Pytorch 实现情感分析

情感分析

情感分析是 NLP 一种应用场景,模型判断输入语句是积极的还是消极的,实际应用适用于评论、客服等多场景。情感分析通过 transformer 架构中的 encoder 层再加上情感分类层进行实现。

安装依赖

需要安装 Poytorch NLP 相关依赖

pip install torchtext==0.6.0

下载预训练的英文模型

import os
import urllib.request
import zipfile
import tarfile#下载fastText官方英语已学习模型(650MB)。
url = "https://dl.fbaipublicfiles.com/fasttext/vectors-english/wiki-news-300d-1M.vec.zip"
save_path = "./data/wiki-news-300d-1M.vec.zip"
if not os.path.exists(save_path):urllib.request.urlretrieve(url, save_path)#解压缩文件夹“data”中的“/维基-news-300d- 1m .vec.zip”zip = zipfile.ZipFile("./data/wiki-news-300d-1M.vec.zip")
zip.extractall("./data/")  #解压缩ZIP
zip.close()  #关闭ZIP文件

准备数据

准备训练数据、测试数据,去掉空格以及标点符号,由于是英文数据,通过空格进行分词。

##保存为tsv格式的文件
import glob
import os
import io
import string#创建训练数据的tsv文件f = open('./data/IMDb_train.tsv', 'w')path = './data/aclImdb/train/pos/'
for fname in glob.glob(os.path.join(path, '*.txt')):with io.open(fname, 'r', encoding="utf-8") as ff:text = ff.readline()#如果包含制表符就删除text = text.replace('\t', " ")text = text+'\t'+'1'+'\t'+'\n'f.write(text)path = './data/aclImdb/train/neg/'
for fname in glob.glob(os.path.join(path, '*.txt')):with io.open(fname, 'r', encoding="utf-8") as ff:text = ff.readline()#如果包含制表符就删除text = text.replace('\t', " ")text = text+'\t'+'0'+'\t'+'\n'f.write(text)f.close()#创建测试数据f = open('./data/IMDb_test.tsv', 'w')path = './data/aclImdb/test/pos/'
for fname in glob.glob(os.path.join(path, '*.txt')):with io.open(fname, 'r', encoding="utf-8") as ff:text = ff.readline()#如果包含制表符就删除text = text.replace('\t', " ")text = text+'\t'+'1'+'\t'+'\n'f.write(text)path = './data/aclImdb/test/neg/'for fname in glob.glob(os.path.join(path, '*.txt')):with io.open(fname, 'r', encoding="utf-8") as ff:text = ff.readline()#如果包含制表符就删除text = text.replace('\t', " ")text = text+'\t'+'0'+'\t'+'\n'f.write(text)f.close()import string
import re#将下列符号替换成空格符(除了句号和逗号之外)。
print("分隔符:", string.punctuation)
# !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~#预处理def preprocessing_text(text):#预处理text = re.sub('<br />', '', text)#将逗号和句号以外的标点符号替换成空格符for p in string.punctuation:if (p == ".") or (p == ","):continueelse:text = text.replace(p, " ")#在句号和逗号前后插入空格符text = text.replace(".", " . ")text = text.replace(",", " , ")return text#用空格将单词隔开(这里的数据是英文的,用空格进行分隔)def tokenizer_punctuation(text):return text.strip().split()#定义用于预处理和分词处理的函数
def tokenizer_with_preprocessing(text):text = preprocessing_text(text)ret = tokenizer_punctuation(text)return ret#确认执行结果
print(tokenizer_with_preprocessing('I like cats.'))

创建 Dataloader

创建两种类型的数据,TEXT:输入的评论,LABEL:类型标签

##定义在读取数据时,对读取内容所做的处理
import torchtext# #同时准备文章和标签两种字段
max_length = 256
TEXT = torchtext.data.Field(sequential=True, tokenize=tokenizer_with_preprocessing, use_vocab=True,lower=True, include_lengths=True, batch_first=True, fix_length=max_length, init_token="<cls>", eos_token="<eos>")
LABEL = torchtext.data.Field(sequential=False, use_vocab=False)
#从data文件夹中读取各个tsv文件
train_val_ds, test_ds = torchtext.data.TabularDataset.splits(path='./data/', train='IMDb_train.tsv',test='IMDb_test.tsv', format='tsv',fields=[('Text', TEXT), ('Label', LABEL)])#确认执行结果
print('训练和验证数据的数量', len(train_val_ds))
print('第一个训练和验证的数据', vars(train_val_ds[0]))

切分训练数据和验证数据,20000 条训练集、5000 条验证:

import random
#使用torchtext.data.Dataset的split函数将Dataset切分为训练数据和验证数据train_ds, val_ds = train_val_ds.split(split_ratio=0.8, random_state=random.seed(1234))#确认执行结果
print('训练数据的数量', len(train_ds))
print('验证数据的数量', len(val_ds))
print('第一个训练数据', vars(train_ds[0]))

载入已经选练好的 fasttext 模型,并根据模型创建词汇表

#使用torchtext读取作为单词向量from torchtext.vocab import Vectorsenglish_fasttext_vectors = Vectors(name='data/wiki-news-300d-1M.vec')#确认单词向量中的内容
print("1个单词向量的维数:", english_fasttext_vectors.dim)
print("单词数量:", len(english_fasttext_vectors.itos))#单词数量
TEXT.build_vocab(train_ds, vectors=english_fasttext_vectors, min_freq=10)

创建 dataloader

# DataLoaderを作成します(torchtextの文脈では単純にiteraterと呼ばれています)
train_dl = torchtext.data.Iterator(train_ds, batch_size=24, train=True)val_dl = torchtext.data.Iterator(val_ds, batch_size=24, train=False, sort=False)test_dl = torchtext.data.Iterator(test_ds, batch_size=24, train=False, sort=False)# 動作確認 検証データのデータセットで確認
batch = next(iter(val_dl))
print(batch.Text)
print(batch.Label)

创建分类任务

创建 Transformer 模型

import math
import numpy as np
import randomimport torch
import torch.nn as nn
import torch.nn.functional as F 
import torchtext# Setup seeds
torch.manual_seed(1234)
np.random.seed(1234)
random.seed(1234)class Embedder(nn.Module):'''将id代表的单词转换为向量'''def __init__(self, text_embedding_vectors):super(Embedder, self).__init__()self.embeddings = nn.Embedding.from_pretrained(embeddings=text_embedding_vectors, freeze=True)#指定freeze=True,可以防止反向传播造成的更新,保证数据不发生变化def forward(self, x):x_vec = self.embeddings(x)return x_vec#确认代码的执行结果#确认代码的执行结果
from utils.dataloader import get_IMDb_DataLoaders_and_TEXT
train_dl, val_dl, test_dl, TEXT = get_IMDb_DataLoaders_and_TEXT(max_length=256, batch_size=24)#准备小批次
batch = next(iter(train_dl))#构建模型
net1 = Embedder(TEXT.vocab.vectors)#输入和输出
x = batch.Text[0]
x1 = net1(x) #将单词转换为向量print("输入的张量尺寸:", x.shape)
print("输出的张量尺寸:", x1.shape)## 定义 positionencoder
class PositionalEncoder(nn.Module):'''添加用于表示输入单词的位置的向量信息'''def __init__(self, d_model=300, max_seq_len=256):super().__init__()self.d_model = d_model   #单词向量的维度#创建根据单词的顺序(pos)和填入向量的维度的位置(i)确定的值的表pepe = torch.zeros(max_seq_len, d_model)#如果GPU可用,则发送到GPU中,这里暂且省略此操作。在实际进行学习时可以使用# device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# pe = pe.to(device)for pos in range(max_seq_len):for i in range(0, d_model, 2):pe[pos, i] = math.sin(pos / (10000 ** ((2 * i)/d_model)))pe[pos, i + 1] = math.cos(pos /(10000 ** ((2 * (i + 1))/d_model)))#将作为小批量维度的维度添加到pe的开头self.pe = pe.unsqueeze(0)#关闭梯度的计算self.pe.requires_grad = Falsedef forward(self, x):#将输入x与Positonal Encoding相加#x比pe要小,因此需要将其放大ret = math.sqrt(self.d_model)*x + self.pereturn ret#创建Attention
class Attention(nn.Module):'''实际上,Transformer中使用的是多头Attention这里为了便于读者理解,采用的是单一Attention结构'''def __init__(self, d_model=300):super().__init__()#在Self-Attention GAN中使用的是1dConv,这次在全连接层中对特征量进行变换self.q_linear = nn.Linear(d_model, d_model)self.v_linear = nn.Linear(d_model, d_model)self.k_linear = nn.Linear(d_model, d_model)#输出时使用的全连接层self.out = nn.Linear(d_model, d_model)#用于调整Attention大小的变量self.d_k = d_modeldef forward(self, q, k, v, mask):#在全连接层中进行特征量变换k = self.k_linear(k)q = self.q_linear(q)v = self.v_linear(v)#计算Attention的值#直接与各个值相加得到的结果太大,因此除以root(d_k)来调整weights = torch.matmul(q, k.transpose(1, 2)) / math.sqrt(self.d_k)#在这里计算maskmask = mask.unsqueeze(1)weights = weights.masked_fill(mask == 0, -1e9)#使用softmax进行归一化处理normlized_weights = F.softmax(weights, dim=-1)#将Attention与Value相乘output = torch.matmul(normlized_weights, v)#使用全连接层进行特征量变换output = self.out(output)return output, normlized_weights#创建feedforward 网络
class FeedForward(nn.Module):def __init__(self, d_model, d_ff=1024, dropout=0.1):'''负责将来自Attention层的输出通过两个全连接层进行特征量变换的组件'''super().__init__()self.linear_1 = nn.Linear(d_model, d_ff)self.dropout = nn.Dropout(dropout)self.linear_2 = nn.Linear(d_ff, d_model)def forward(self, x):x = self.linear_1(x)x = self.dropout(F.relu(x))x = self.linear_2(x)return x#创建 Transformer
class TransformerBlock(nn.Module):def __init__(self, d_model, dropout=0.1):super().__init__()# LayerNormalization層层# https://pytorch.org/docs/stable/nn.html?highlight=layernormself.norm_1 = nn.LayerNorm(d_model)self.norm_2 = nn.LayerNorm(d_model)# Attention层self.attn = Attention(d_model)#Attention后面的两个全连接层self.ff = FeedForward(d_model)# Dropoutself.dropout_1 = nn.Dropout(dropout)self.dropout_2 = nn.Dropout(dropout)def forward(self, x, mask):#归一化与Attentionx_normlized = self.norm_1(x)output, normlized_weights = self.attn(x_normlized, x_normlized, x_normlized, mask)x2 = x + self.dropout_1(output)#归一化与全连接层x_normlized2 = self.norm_2(x2)output = x2 + self.dropout_2(self.ff(x_normlized2))return output, normlized_weights## 创建分类
class ClassificationHead(nn.Module):'''使用Transformer_Block的输出结果,最终实现分类处理'''def __init__(self, d_model=300, output_dim=2):super().__init__()#使用Transformer_Block的输出结果,最终实现分类处理self.linear = nn.Linear(d_model, output_dim)  #output_dim是正面/负面这两个维度#权重的初始化处理nn.init.normal_(self.linear.weight, std=0.02)nn.init.normal_(self.linear.bias, 0)def forward(self, x):x0 = x[:, 0, :]  #取出每个小批次的每个文章的开头的单词的特征量(300 维)out = self.linear(x0)return out
## 整合代码放到 TransformerClassificationclass TransformerClassification(nn.Module):'''#最终的Transformer模型的类'''def __init__(self, text_embedding_vectors, d_model=300, max_seq_len=256, output_dim=2):super().__init__()#构建模型self.net1 = Embedder(text_embedding_vectors)self.net2 = PositionalEncoder(d_model=d_model, max_seq_len=max_seq_len)self.net3_1 = TransformerBlock(d_model=d_model)self.net3_2 = TransformerBlock(d_model=d_model)self.net4 = ClassificationHead(output_dim=output_dim, d_model=d_model)def forward(self, x, mask):x1 = self.net1(x)  #将单词转换为向量x2 = self.net2(x1)  #对Positon信息进行加法运算x3_1, normlized_weights_1 = self.net3_1(x2, mask) #使用Self−Attention进行特征量变换x3_2, normlized_weights_2 = self.net3_2(x3_1, mask)  #使用Self−Attention进行特征量变换x4 = self.net4(x3_2)  #使用最终输出的第0个单词,输出分类0~1的标量return x4, normlized_weights_1, normlized_weights_2

训练并验证

#导入软件包
import numpy as np
import randomimport torch
import torch.nn as nn
import torch.optim as optimimport torchtext# 设定随机数的种子,
torch.manual_seed(1234)
np.random.seed(1234)
random.seed(1234)from utils.dataloader import get_IMDb_DataLoaders_and_TEXT#载入数据
train_dl, val_dl, test_dl, TEXT = get_IMDb_DataLoaders_and_TEXT(max_length=256, batch_size=64)#集中保存到字典对象中
dataloaders_dict = {"train": train_dl, "val": val_dl}from utils.transformer import TransformerClassification#构建模型
net = TransformerClassification(text_embedding_vectors=TEXT.vocab.vectors, d_model=300, max_seq_len=256, output_dim=2)#定义网络的初始化操作def weights_init(m):classname = m.__class__.__name__if classname.find('Linear') != -1:#Liner层的初始化nn.init.kaiming_normal_(m.weight)if m.bias is not None:nn.init.constant_(m.bias, 0.0)#设置为训练模式
net.train()#执行TransformerBlock模块的初始化操作
net.net3_1.apply(weights_init)
net.net3_2.apply(weights_init)print('网络设置完毕')#设置损失函数
criterion = nn.CrossEntropyLoss()#设置最优化算法
learning_rate = 2e-5
optimizer = optim.Adam(net.parameters(), lr=learning_rate)#创建用于训练模型的函数def train_model(net, dataloaders_dict, criterion, optimizer, num_epochs):#确认是否能够使用GPUdevice = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")print("使用的设备:", device)print('-----start-------')#将网络载入GPU中net.to(device)#如果网络结构比较固定,则开启硬件加速torch.backends.cudnn.benchmark = True#epoch循环for epoch in range(num_epochs):#以epoch为单位进行训练和验证的循环for phase in ['train', 'val']:if phase == 'train':net.train()  #将模型设为训练模式else:net.eval()   #将模型设为训练模式epoch_loss = 0.0  #epoch的损失和epoch_corrects = 0  #epoch的准确率#从数据加载器中读取小批次数据的循环for batch in (dataloaders_dict[phase]):#batch是Text和Lable的字典对象#如果GPU可以使用,则将数据输送到GPU中inputs = batch.Text[0].to(device)  # 文章labels = batch.Label.to(device)  # 标签#初始化optimizeroptimizer.zero_grad()#初始化optimizerwith torch.set_grad_enabled(phase == 'train'):# mask作成input_pad = 1 #在单词ID中'<pad>': 1input_mask = (inputs != input_pad)#输入Transformer中outputs, _, _ = net(inputs, input_mask)loss = criterion(outputs, labels)  #计算损失值_, preds = torch.max(outputs, 1)  #对标签进行预测#训练时进行反向传播if phase == 'train':loss.backward()optimizer.step()#计算结果epoch_loss += loss.item() * inputs.size(0)  # lossの合計を更新#更新正确答案的合计数量epoch_corrects += torch.sum(preds == labels.data)#每轮epoch的loss和准确率epoch_loss = epoch_loss / len(dataloaders_dict[phase].dataset)epoch_acc = epoch_corrects.double() / len(dataloaders_dict[phase].dataset)print('Epoch {}/{} | {:^5} |  Loss: {:.4f} Acc: {:.4f}'.format(epoch+1, num_epochs,phase, epoch_loss, epoch_acc))return net#执行学习和验证
num_epochs = 10
net_trained = train_model(net, dataloaders_dict,criterion, optimizer, num_epochs=num_epochs)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/7982.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JVM学习笔记【基础篇:垃圾回收】

自动垃圾回收 C/C的内存管理 ⚫ 在C/C这类没有自动垃圾回收机制的语言中&#xff0c;一个对象如果不再使用&#xff0c;需要手动释放&#xff0c;否则就会出现 内存泄漏。我们称这种释放对象的过程为垃圾回收&#xff0c;而需要程序员编写代码进行回收的方式为手动回收。 ⚫ …

RTT潘多拉开发板上实现电源管理

简介 随着物联网(IoT)的兴起&#xff0c;产品对功耗的需求越来越强烈。作为数据采集的传感器节点通常需要在电池供电时长期工作&#xff0c;而作为联网的SOC也需要有快速的响应功能和较低的功耗。 在产品开发的起始阶段&#xff0c;首先考虑是尽快完成产品的功能开发。在产品…

数仓开发中期:理论巩固

一、数仓以及商业智能&#xff08;Data Warehousing and Business Intelligence, DW/BI&#xff09;系统 1.1数据操作和数据获取的区别 对所有组织来说&#xff0c;信息都是其最重要的财富之一。信息几乎总是用作两个目的:操作型记录的保存和分析型决策的制定。简单来说&…

Stack数据结构设计模板

第三章 栈、队列、数组 1.栈 1.1 顺序栈 #define MaxSize 20 typedef int ElemType; //顺序栈的定义 typedef struct {ElemType data[MaxSize];int top; }SqStack; // 初始化顺序栈 void InitSqStack(SqStack &S){S.top -1; }; // 入栈(增) bool Push(SqStack &S,El…

WIFI模块UDP电脑端调试

一&#xff0c;两端都是电脑端 1&#xff0c;电脑本机的IP地址 192.168.137.1 2&#xff0c;新建两个不同的连接&#xff0c;注意端口 二&#xff0c;WIFI 模块和电脑端连接 1&#xff0c;设置模块端目标IP和端口&#xff0c;电脑端只接收数据的话&#xff0c;IP、端口可随…

【从零开始学架构 架构基础】架构设计的本质、历史背景和目的

本文是《从零开始学架构》的第一篇学习笔记&#xff0c;主要理解架构的设计的本质定义、历史背景以及目的。 架构设计的本质 分别从三组概念的区别来理解架构设计。 系统与子系统 什么是系统&#xff0c;系统泛指由一群有关联的个体组成&#xff0c;根据某种规则运作&#…

企业终端安全管理软件有哪些?终端安全管理软件哪个好?

终端安全的重要性大家众所周知&#xff0c;关系到生死存亡的东西。 各类终端安全管理软件应运而生&#xff0c;为企业提供全方位、多层次的终端防护。 有哪些企业终端安全管理软件&#xff1f; 一、主流企业终端安全管理软件 1. 域智盾 域智盾是一款专为企业打造的全面终端…

奥威-金蝶BI现金流量表模板,可借鉴、可套用

企业现金流一旦出了问题都是大问题&#xff0c;会直接影响到企业的日常运作&#xff0c;甚至直接关系到企业能不能继续存活&#xff0c;因此现金流量表是企业财务分析中重要报表之一&#xff0c;也是企业监控财务监控情况的重要手段之一。那么这么重要的一份现金流量表该怎么做…

[Linux] GDB使用指南----包含CentOS7下安装以及使用

什么是GDB&#xff1f; GDB 是由 GUN 软件系统社区提供的调试工具&#xff0c;同 GCC 配套组成了一套完整的开发环境&#xff0c;GDB 是 Linux 和许多 类Unix系统的标准开发环境。可以用来调试C、C、Go、java、 objective-c、PHP等语言。 GDB的作用 程序启动时&#xff0c;可…

73. 矩阵置零/54. 螺旋矩阵

73. 矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 思路&#x…

小程序搜索排名优化 三步操作提升

搜索排名优化最直接的一个目的就是为了提升小程序的排名和流量&#xff0c;获取用户的信任度。当用户在搜索关键词的时候&#xff0c;能让用户看到小程序&#xff0c;增加被发现和点击的机会。 一、关键词优化&#xff1a; 1.选择合适的关键词&#xff1a;选择与小程序内容高…

代码训练LeetCode(17)存在重复元素

代码训练(17)LeetCode之存在重复元素 Author: Once Day Date: 2024年5月7日 漫漫长路&#xff0c;才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 219. 存在重复元素 II - 力扣&#xff08;LeetCode&#xff09;力扣 (LeetCode) 全球…

fero - yolo - mamba:基于选择性状态空间的面部表情检测与分类

fero - yolo - mamba:基于选择性状态空间的面部表情检测与分类 摘要IntroductionRelated work FER-YOLO-Mamba: Facial Expression Detection and Classification Based on Selective State Space 摘要 面部表情识别&#xff08;FER&#xff09;在理解人类情绪线索方面起着关键…

零资源跑大模型:Hugging Face API + LiteLLM + Flask

前言 HuggingFace 是自然语言处理领域的开源软件库和平台&#xff0c;其收纳了众多最前沿的模型和数据集&#xff0c;并提供了 Serverless Inference API&#xff0c;用户可以轻松调用这些模型&#xff0c;甚至用于运行自己的私人模型。本教程将指导用户如何利用 Hugging Face…

RabbitMQ之消费者并发消费

为什么要引入消费者的并发消费&#xff1f; 当生产者的推送速度是远远超过消费者的能力的&#xff0c;可以提高消费者的消费速度。比如在java中我们可以启动多个 JVM 进程&#xff0c;实现多进程的并发消费&#xff0c;从而加速消费的速度&#xff0c;在mq中也可以通过设置配置…

鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽

进程间为何要通讯 ? 鸿蒙内核默认支持 64个进程和128个任务&#xff0c;由进程池和任务池统一管理.内核设计尽量不去打扰它们&#xff0c;让各自过好各自的日子&#xff0c; 但大家毕竟在一口锅里吃饭&#xff0c; 不可能不与外界联系&#xff0c; 联系就得有渠道&#xff0c…

Go微服务精讲:Go-Zero全流程实战即时通讯(超清)

go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性&#xff0c;经受了充分的实战检验。 Go微服务精讲&#xff1a;Go-Zero全流程实战即时通讯(超清) go-zero 中的 api&#xff0c;rpc&#xff0c;数据库等涉及的代码&#xff0c;…

C#标签设计打印软件开发

1、新建自定义C#控件项目Custom using System; using System.Collections.Generic; using System.Text;namespace CustomControls {public class CommonSettings{/// <summary>/// 把像素换算成毫米/// </summary>/// <param name"Pixel">多少像素…

Springboot 集成 Consul 实现服务注册中心-05

因为后续很多模块都要用到注册中心&#xff0c;所以此处先实现此模块。 Consul简介 Consul是一个开源的服务发现和配置管理工具&#xff0c;具有跨平台、运行高效等特点。它由HashiCorp公司开发&#xff0c;并使用Go语言编写。Consul主要用于实现分布式系统中的服务发现、健康…

解决Node.js mysql客户端不支持认证协议引发的“ER_NOT_SUPPORTED_AUTH_MODE”问题

这是一个版本问题 我用koa2和mysql2链接就没有问题 不知道这个老项目运行为啥有这个问题 解决方案 打开mysql运行这个两个命令&#xff1a; ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123321; FLUSH PRIVILEGES; 须知(给小白看的&#xff01;) …