首页 > 其他分享 >情感分词新手实践

情感分词新手实践

时间:2024-05-06 20:22:42浏览次数:32  
标签:dim self batch ids 情感 新手 hidden 分词 size

Amazon Full Review 情感分析任务

input: Remark Text

output: Sentiment(\(\{-1, 0, 1\}\)) convert to \(\{0, 1, 2\}\) for calculating accuracy

Mark: 之前没有用 torch 做过 NLP,因此相当于一个 tutorial

数据准备工作

  1. 文本分词

NLP 需要将文本数据分词并转换为词汇表中的 id,这里使用transformers库中的BertTokenizer进行处理。

  1. 创建词汇表

需要完成的工作为

  • 创建词汇表 Vocabulary, 用于将文本转换为数字,由于词汇数量巨大,并且测试集可能出现未知词汇,因此设置一个阈值,设置两个标记符号,一个是未知词汇,一个是填充符号。
  • 同时在之后的 Embedding 中,词嵌入的输入是固定的,因此可以尝试将所有的句子 ids 的长度设置为相同的长度,不足的部分用填充符号填充。
  1. 创建 DataSet

主要是将文件读取入字典中,并在 getitem 方法中将文本数据转换为数字,同时将标签转换为数字。

模板如下


class MyDataset(Dataset):
        def __init__(self, path, tokenizer=None, max_length=512, device="gpu"):
        self.data = self.load_csv(path)
        self.tokenizer = tokenizer
        self.max_length = max_length
        print(f"Loaded {len(self.data)} data from {path}")

    def load_csv(self, path):
        Data = {}
        index = 0
        try:
            with open(path, "rt", encoding="utf-8") as f:
                for line in f:
                    items = line.strip().split(",")
                    # convert labels
                        Data[index] = {
                            "subject": items[1],
                            "review": items[2],
                            "label": label,
                        }
                        index += 1
                    else:
                        continue
        except IOError as e:
            print(f"Error opening or reading the file: {path}. Error: {e}")
        return Data

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        # 在这里进行数据处理
        if idx < len(self.data) and idx >= 0:
            item = self.data[idx]
            # 编码处理
            encoded_review = self.tokenizer.encode_plus(
                item['review'],
                add_special_tokens=True,
                max_length=self.max_length,
                return_token_type_ids=False,
                padding="max_length",
                truncation=True,
                return_attention_mask=True,
                return_tensors='pt',
            )
            item["ids"] = encoded_review["input_ids"].squeeze()
            return item

  1. 划分数据集

可以直接在 dataset 中使用 subset 划分,但在创建 dataloader 时会存在索引问题,因此排列在预处理之前,出现问题的代码如下:

indices = list(range(len(train_data)))
np.random.shuffle(indices)
split = int(np.floor(0.8 * len(train_data)))
train_indices = indices[:split]
valid_indices = indices[split:]

train_data = Subset(train_data, train_indices)
valid_data = Subset(train_data, valid_indices)
  1. 创建 DataLoader

需要注意的几个参数为batch_size, shuffle, drop_last, 其中shuffle表示是否打乱数据,drop_last表示是否丢弃最后一个 batch。

模型构建

1. Embedding + Pooling + Linear

  • Embedding 层将输入的词汇 id 转换为词嵌入
  • 然后使用 Pooling 层将词嵌入转换为句子向量
  • 最后使用 Linear 层将句子向量转换为输出
class NBoW(nn.Module):
    def __init__(self, vocab_size, embedding_dim, num_class):
        super(NBoW, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.fc = nn.Linear(embedding_dim, num_class)

    def forward(self, ids):
        # ids = [batch size, seq len]
        embedded = self.embedding(ids)
        # embedded = [batch size, seq len, embedding dim]
        pooled = torch.mean(embedded, dim=1)
        # pooled = [batch size, embedding dim]
        pred = self.fc(pooled)
        # pred = [batch size, output dim], 输出由于loss是CE, 不需要softmax
        return pred

img

2. LSTM

模型结构如下:

  • Embedding 层将输入的词汇 id 转换为词嵌入
  • LSTM 层将词嵌入转换为句子向量
  • Linear 层将句子向量转换为输出

同时防止过拟合,使用了 Dropout 层。以dropout_rate的概率,在训练时将输入的某些元素置为 0,以防止过拟合。

class LSTM(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim,
                 n_layers, bidirectional, dropout_rate) -> None:
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        self.lstm = nn.LSTM(
            embedding_dim,
            hidden_dim,
            n_layers,
            bidirectional=bidirectional,
            dropout=dropout_rate,
            batch_first=True,
        )
        self.fc = nn.Linear(hidden_dim * 2 if bidirectional else hidden_dim, output_dim)
        self.dropout = nn.Dropout(dropout_rate)

    def forward(self, ids):
        # ids = [batch size, seq len]
        # length = [batch size]
        embedded = self.dropout(self.embedding(ids))
        # embedded = [batch size, seq len, embedding dim]
        output, (hidden, cell) = self.lstm(embedded)
        # hidden = [n layers * n directions, batch size, hidden dim]
        # cell = [n layers * n directions, batch size, hidden dim]
        # output = [batch size, seq len, hidden dim * n directions]
        if self.lstm.bidirectional:
            hidden = self.dropout(torch.cat([hidden[-1], hidden[-2]], dim=-1))
            # hidden = [batch size, hidden dim * 2]
        else:
            hidden = self.dropout(hidden[-1])
            # hidden = [batch size, hidden dim]
        prediction = self.fc(hidden)
        # prediction = [batch size, output dim]
        return prediction

模型训练

使用(torch.argmax(predict, dim=1) == label).float().mean().item()计算准确率。

在第一种模型中,batch_size=512, epoch=3,在第二种模型中,batch_size=128, epoch=3

训练过程中使用,Adam优化器,CrossEntropyLoss损失函数。

然而由于没有考虑到数据平衡性问题,因此在训练过程中,准确率并不高,可以考虑使用WeightedRandomSampler解决数据不平衡问题。

Embedding LSTM
img img

模型接口

要注意的是最终结果的计算,由于预处理时已经将 label 转换为 idx,因此获得结果时只需套torch.argmax获取 idx 即可。

def predict_sentiment(text, model, tokenizer, device):
    model.eval()
    encoded_review = tokenizer.encode_plus(
        text,
        add_special_tokens=True,
        max_length=512,
        return_token_type_ids=False,
        padding="max_length",
        truncation=True,
        return_attention_mask=True,
        return_tensors='pt',
    )
    ids = encoded_review["input_ids"].to(device)
    prediction = model(ids)
    return torch.argmax(prediction).item()

参考

  1. 快速入门 Transformer

  2. Pytorch Sentiment Analysis

标签:dim,self,batch,ids,情感,新手,hidden,分词,size
From: https://www.cnblogs.com/Blackteaxx/p/18175813

相关文章

  • Git 使用教程(新手学习)
    Git是一种分布式版本控制系统,用于管理软件项目的源代码。它是由Linux之父LinusTorvalds开发的,并已经成为了现代软件开发领域中最流行的版本控制系统之一。使用Git可以追踪代码的历史修改记录,方便团队协作、代码共享和代码重构。Git的基本工作流程如下:在开始编写代码之......
  • 3d软件哪个适合新手学?3D动画渲染怎么好
    在不同的行业领域,3D建模和动画的需求各异,因此所需的3D软件工具也会有所不同。对于刚开始接触3D设计的新手来说,软件的易操作性、丰富的学习资源以及与自己专业领域相关的功能是选择时的重要考虑因素。以下是几款适合初学者入门的3D软件推荐。工业设计师:犀牛、Alias犀牛和Alias......
  • 新手也能学会的甘特图制作教程
    ##甘特图是什么?甘特图(GanttChart)是一种以图表形式直观展示项目计划的工具,由20世纪初的管理学家亨利·甘特(HenryGantt)发明并命名。它具有以下几个主要特点:1.水平时间轴甘特图的横轴是一条时间轴,通常按天、周或月来刻度,直观展示了项目从开始到结束的整个时间跨度。2.任......
  • 新手下载python和anaconda3注意事项
    新手下载python和anaconda3要注意哪些1、python关于python下载其实很简单,直接在官网下载就行。官网:WelcometoPython.org当然,到了官网下载是默认最新版本,如果你需要旧版本,那就需要找一下了,这里提供一下windows的各版本的官网链接:PythonReleasesforWindows|Python.org......
  • Elasticsearch N-gram分词器介绍 (7)
    一.概述Ngram是一种基于统计语言模型的算法。Ngram基本思想是将文本里面的内容按照字节大小进行滑动窗口操作,形成长度是N的字节片段序列。此时每一个字节片段称为gram。对所有gram的出现频度进行统计,并且按照事先设定好的阈值进行过滤,形成关键gram列表,也就是这个文本的向量特......
  • VS Code如何创建HTML文件并运行(新手友好)
    一、下载VSCode首先从官网https://code.visualstudio.com/下载VSCode。二、在VSCode中下载相关的插件1、首先打开VisualStudioCode 2、点击左侧工具栏中“扩展”栏,也可使用扩展快捷键打开(Ctrl+Shift+X),打开扩展下载以下三个插件。(三个插件安装完成后都需要重启VSCod......
  • Elasticsearch 所有内置分词器介绍(6)
    一.概述Tokenizer分词器接收字符流(es的text类型),将其分解为单个term(通常是单个单词),然后输出标记流。分词器除了分解,还负责记录以下内容:1)记录每个单词(term)的顺序或位置(用于”phrase短语“和单词邻近性查询)2)term原始单词的开始和结束字符偏移量(使用......
  • 新手大白话 [SWPU 2018]SimplePHP Phar反序列化
    今天再做个Phar反序列化巩固下。进入题目发现了查看文件与上传文件,与自己的IP。利用burp抓包进行查看,先尝试index.php,发现base.php,查看base.php发现flag所在文件,再查看file.php,发现function.phpclass.php点击查看代码class.php<?phpclassC1e4r{public$t......
  • 新手学习记录丨Excel VBA(1)
    准备工作:开启ExcelVBA工作环境在MicrosoftExcel中,按键Alt+F11(或者Alt+Fn+F11)即可打开VBA编辑器。如下图所示,右键插入“模块”,即可开始在右侧的编辑器中编辑代码。实现最基本的任务:打印Helloworld在ExcelVBA中,字符串用双引号包围。我们可以使用MsgBox函数输出文......
  • 新手大白话 [HNCTF 2022 Week1]Challenge__rce RCE自增绕过
    今天遇到个RCE难题,挺另类的,这里做个复盘。进入题目直接给出了源码,可以发现就是个无字母RCE,且有长度限制不能使用url取反绕过,到这想到了以前的一个rce自增绕过方式,但是以前的没有长度限制。点击查看代码<?phperror_reporting(0);if(isset($_GET['hint'])){highlight_f......