当前位置: 首页 > news >正文

自然语言处理项目之情感分析(下)

简介


        在当今信息爆炸的时代,海量的文本数据如社交媒体评论、产品评价、新闻留言等不断涌现,这些文本中蕴含着人们丰富的情感态度,无论是对商品的喜爱、对政策的支持,还是对服务的不满。而自然语言处理(NLP)领域中的情感分析技术,正是挖掘这些情感信息的关键工具。情感分析,也常被称为意见挖掘,它通过运用计算机技术对文本数据进行处理、分析和理解,自动识别和提取文本中所包含的情感倾向,如积极、消极、中性,甚至还能进一步细分为喜悦、愤怒、悲伤、惊讶等具体的情感类别,为企业决策、公共舆情监测、个人服务等诸多领域提供有力的支持。

继上一篇我们对数据进行了预处理,今天我们继续来完成项目的后半部分

自然语言处理项目之情感分析(上)

一、项目介绍


1.项目任务
         对微博评论信息的情感分析,建立模型,自动识别评论信息的情绪状态。

评论信息内容

2.问题处理
        1)目标
                将每条评论内容转换为词向量。

        2)输入字词格式
                每个词/字转换为词向量长度(维度)200,使用腾讯训练好的词向量模型有4960个维度,需要这个模型或者文件可私信发送。

        3)每一次传入的词/字的个数是否就是评论的长度
                应该是固定长度,如何固定长度接着看,固定长度每次传入数据与图像相似,例如输入评论长度为32,那么传入的数据为32*200的矩阵,表示这一批词的独热编码,200表示维度

        4)一条评论如果超过32个词/字怎么处理?     
                超出的直接删除后面的内容

        5)一条评论如果没有32个词/字怎么处理?     
                缺少的内容,统一使用一个数字(非词/字的数字)替代,项目中使用<PAD>填充

        6)如果语料库中的词/字太多是否可以压缩?     
                可以,某些词/字出现的频率比较低,可能训练不出特征。因此可以选择频率比较高的词来训练,项目中选择4760个。

        7)被压缩的词/字如何处理?     
                可以统一使用一个数字(非词/字的数字)替代,即选择了评论固定长度的文字后,这段文字内可能有频率低的字,将其用一个数字替代,项目内使用<UNK>替代

二、代码实现

1.定义模型,前向传播函数

        将下列代码写入新创建的文件TextRNN.py。定义了我们的模型结构。

import torch.nn as nnclass Model(nn.Module):  # 定义一个类,继承神经网络的基类,参数管理、模型保存加载...def __init__(self, embedding_pretrained, n_vocab, embed,num_classes):  # 传入参数表示为:预训练的词向量(当前项目导入腾讯训练好的词向量)、词汇表的长度、词向量维度、分类标签的数量super(Model, self).__init__()if embedding_pretrained is not None:  # 如果有预训练模型# 创建一个词嵌入层,用与接收预训练的嵌入层权重作为输入,指定填充词在词汇表中的索引为n_vocab-1,freeze:指定是否冻结embedinq层的权重,False表示可以更新预训练模型的权重参数self.embedding = nn.Embedding.from_pretrained(embedding_pretrained, padding_idx=n_vocab - 1, freeze=False)else:  # 如果没有预训练模型,则初始化一个随机嵌入层,维度为n_vocab*embed   项目内是4762*200self.embedding = nn.Embedding(n_vocab, embed, padding_idx=n_vocab - 1)# 建立LSTM网络层,输入维度为embed,有128个隐藏单元共三层,bidirectional=True表示双向LSTM,所以输出为128*2,batch_first=True表示输入张量第一个维度是批次数,dropout = 0.3表示LSTM层使用的dropout比例self.lstm = nn.LSTM(embed, 128, 3, bidirectional=True, batch_first=True, dropout=0.3)# 128为每一层中每个隐状态中的U、W、V的神经元个数,# 3为隐藏层的层数,batch_first=True表示输入和输出张量将以(batch,seq,feature)而不是(seq,betch,featur)。# bidirectiongl = True: 指定LSTM是双向的。网络会同时从前向后和从后向前处理输入序列,两个方向的# dropout = 0.3: 这指定了在LSTM层中使用的dropout比例。Dropout是一种正则化技术,用于防止网络在训练过程中过拟?self.fc = nn.Linear(128 * 2, num_classes)  # 设置全连接层,在每个时间步的最后一个状态的输出映射到类别数上def forward(self, x):  # 定义前向传播函数,输入的参数x为batch_size批次数以及sequence_length单词样本数x, _ = x  # 返回新的x值为批次数out = self.embedding(x)  # 将批次数传入词嵌入层,将整数索引转换为连续的、密集的词向量out, _ = self.lstm(out)  # 将词向量传入LSTM网络层out = self.fc(out[:, -1, :])  # 只选择LSTM输出序列的最后一个时间步的隐藏状态传递给self.fcreturn out

2、定义训练、测试函数

 创建一个文件train_eval_test.py,将下列代码写入其中

import torch
import torch.nn.functional as F
import numpy as np
from sklearn import metrics
import timedef evaluate(class_list, model, data_iter, test=False):  # 传入参数:种类名称列表、训练好的模型、验证集数据,test表示是否进行测试模式model.eval()  # 模型开始测试loss_total = 0  # 初始化总损失值为0predict_all = np.array([], dtype=int)  # 定义一个数组用于存放预测结果的标签labels_all = np.array([], dtype=int)  # 存放所有样本的真实标签with torch.no_grad():  # 一个上下文管理器,关闭梯度计算for texts, labels in data_iter:  # 遍历出来 每128条评价的包 的独热编码及长度 和标签outputs = model(texts)  # 输出模型进行测试,返回每个包中每条评论的测试结果loss = F.cross_entropy(outputs, labels)  # 计算交叉熵损失值loss_total += loss  # 损失值叠加labels = labels.data.cpu().numpy()  # 将真实标签转化为numpy数组predic = torch.max(outputs.data, 1)[1].cpu().numpy()  # 计算预测值的标签并转化为numpy数组labels_all = np.append(labels_all, labels)  # 将真实标签增加到labels_all数组predict_all = np.append(predict_all, predic)acc = metrics.accuracy_score(labels_all, predict_all)  # 计算模型在所有样本上的准确率# 返回结果if test:  #report = metrics.classification_report(labels_all, predict_all, target_names=class_list,digits=4)  # 如果不是测试模式,那么打印分类报告,target_names用于识别每个类别的名称class_list,digits表示打印报告中浮点数的位数return acc, loss_total / len(data_iter), report  # 返回准确率、平均损失值、分类报告return acc, loss_total / len(data_iter)  # 返回准确率、平均损失值def test(model, test_iter, class_list):model.load_state_dict(torch.load('TextRNN.ckpt'))model.eval()start_time = time.time()test_acc, test_loss, test_report = evaluate(class_list, model, test_iter, test=True)msg = "Test Loss:{0:>5.2},Test Acc:{1:6.2%}"print(msg.format(test_loss, test_acc))print(test_report)def train(model, train_iter, dev_iter, test_iter, class_list):  # 传入模型结构、训练集、验证集、测试集、标签类别model.train()  # 开始训练optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)  # 优化器,用于更新模型权重,学习率为0.001total_batch = 0dev_best_loss = float('inf')  # 初始化设置最大损失值为正无穷大last_improve = 0flag = Falseepochs = 10  # 设置训练次数for epoch in range(epochs):print('Epoch [{}/{}]'.format(epoch + 1, epochs))  # 第一轮[1/2],第二轮[2/2]for i, (trains, labels) in enumerate(train_iter):  # 遍历训练集的索引和数据,数据存放的是 每128条评价的包 的字在词表中的索引信息、标签信息、评价长度# 经过DatasetIterater中的 to_tensor 返回的数据格式为:(x,seq_len),y,即独热编码、长度、标签outputs = model(trains)  # 将数据放入模型进行训练,得到预测输出值,这里的forward没有展示,即传入模型进行前向传播,返回预测结果格式为128*4loss = F.cross_entropy(outputs, labels)  # 将输出值与标签放入交叉熵损失计算损失值,多分类计算损失值model.zero_grad()  # 对模型进行梯度清0,为下一轮训练做准备loss.backward()  # 根据损失计算梯度optimizer.step()  # 根据梯度更新模型参数if total_batch % 100 == 0:  # 每100轮 输出 在训练集和验证集上的效果,每一百个批次的包打印出来一次predic = torch.max(outputs.data, 1)[1].cpu()  # outputs.data为 每128条评价的包 的预测大小状态128*4,因为都在GPU中,所以为Tensor类型,torch.max返回第二个维度的最大值及索引,1表示第二个维度,[1]表示取索引的值当做预测结果,然后将预测结果传入cputrain_acc = metrics.accuracy_score(labels.data.cpu(), predic)  # 将真实值的标签结果与预测结果输入函数计算准确率dev_acc, dev_loss = evaluate(class_list, model, dev_iter)  # 将种类名、模型、验证集数据传入evaluate函数,获得验证结果,返回准确率和损失值if dev_loss < dev_best_loss:  # 判断当前损失值是否小于历史损失值dev_best_loss = dev_loss  # 如果损失值比前面的小,那么更新之前的损失值,然后保存这个模型的权重信息torch.save(model.state_dict(), 'TextRNN.ckpt')  # 保存最优模型last_improve = total_batch  # 保存最优模型的batch值,整数赋值给last_improve# 打印模型的轮数右对齐字符宽为6、训练集的损失值长度为5保留2个小数、训练集的准确率、验证集的损失值和准确率,其中的0,1,2,3,4表示序号第一个参数第二个参数...msg = 'Iter:{0:>6},Train Loss:{1:>5.2},Train Acc:{2:>6.2%},Val Loss:{3:>5.2},Val Acc:{4:>6.2%}'print(msg.format(total_batch, loss.item(), train_acc, dev_loss, dev_acc))model.train()  # 因为上述使用了evaluate将模型设置了测试模式,所以此处再次设置为训练模式total_batch += 1  # 每运行一次训练了一个包的文件,对数值加1if total_batch - last_improve > 10000:print("No optimization for a long time,auto-stopping...")flag = Trueif flag:breaktest(model, test_iter, class_list)  # 调用test函数进行测试

3.定义主函数

创建一个文件命名为main.py,将下列代码写入文件

import torch
import numpy as np
import load_dataset
import TextRNN
from train_eval_test import traindevice = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
np.random.seed(1)
torch.manual_seed(1)
torch.cuda.manual_seed(1)
torch.backends.cudnn.deterministic = True
vocab, train_data, dev_data, test_data = load_dataset.load_dataset('simplifyweibo_4_moods.csv')
train_iter = load_dataset.DatasetIterater(train_data, 128, device)
dev_iter = load_dataset.DatasetIterater(dev_data, 128, device)
test_iter = load_dataset.DatasetIterater(test_data, 128, device)embedding_pretrained = torch.tensor(np.load("embedding_Tencent.npz")['embeddings'].astype('float32'))embed = embedding_pretrained.size(1) if embedding_pretrained is None else 200
class_list =['', ' ', '', '']
num_classes = len(class_list)
model = TextRNN.Model(embedding_pretrained, len(vocab), embed, num_classes).to(device)
train(model, train_iter, dev_iter, test_iter, class_list)

4.代码文件

最后加上上篇博客的代码,一共有上图代码文件、加上腾讯的词库。

最后实现结果

这样我们就实现了完整代码的训练以及测试。

http://www.dtcms.com/a/420451.html

相关文章:

  • 简墨博客系统测试报告
  • 数码港 太原网站开发公司小程序自己制作流程
  • 长春做网站长春网站设计如何开展网络营销推广
  • 界面设计好看的网站网页设计与制作步骤流程
  • 电商数据分析之自动获取数据的技术手段分享
  • 怎样用ps做企业网站wordpress配置qq邮件
  • 沈阳世纪兴网站制作公司电子书店网站开发
  • *Linux磁盘管理全攻略:LVM+RAID+文件系统指南
  • 【复习】计网每日一题--零窗口要启动的计时器
  • 基于python的校园舆情管理系统设计与实现
  • count down 82 days
  • 找一家秦皇岛市做网站的公司白云区建材网站建设
  • 如何做网站的线下推广手机app一般用什么开发
  • 英语四级资源合集
  • 网站制作全过程个人网站有哪些平台
  • istio集群服务治理
  • 网站上传空间下一步东莞网站制作模板
  • 益阳网站建设公司电话网站设计存在的不足
  • 12. C++ 类作用域
  • 【C++】vector 使用和实现
  • c语言基础之函数
  • 成品ppt网站最近国际新闻大事20条
  • 阿里巴巴官方网站微信小程序制作文档
  • php网站开发工程师月薪怎么样在公司配置服务器做网站
  • QML学习笔记(十九)QML的附加信号处理器
  • 免费浏览的网站广告代理公司排名
  • 为女人网上量体做衣网站轻淘客一键做网站
  • 旗讯OCR表格识别精准还原复杂表格,识别还原准确率95%+,还能结构化
  • 天津建站软件网站制作功能多少钱
  • Java入门级教程21——Java 缓存技术、RMI远程方法调用、多线程分割大文件