深度学习:LSTM循环神经网络实现评论情感分析
目录
一、任务介绍
1.任务要求
2.信息内容
3.待思考问题
二、问题解决
1.将评论内容转换成语料库
2.获取每条评论的词向量、标签和长度
3.数据打包
4.建立LSTM循环神经网络模型
1.主程序代码
2.模型代码
5.建立训练集函数和测试集函数
一、任务介绍
1.任务要求
- 项目任务:对微博评论信息的情感分析,建立模型,自动识别评论信息的情绪状态。
2.信息内容
- 第一行是标头
- 每一行顶格标着每个评论代表的情绪
-
{0: '喜悦', 1: '愤怒', 2: '厌恶', 3: '低落'}
3.待思考问题
- 思考:向模型中传递数据时,需要提前处理好数据
1、目标:将评论内容转换为词向量。
2、每个词/字转换为词向量长度(维度)200
3、每一次传入的词/字的个数是否就是评论的长度?
应该是固定长度,每次传入数据与图像相似。 例如选择长度为32。则传入的数据为32*200
4、一条评论如果超过80个词/字怎么处理?
直接删除后面的内容
5、一条评论如果没有70个词/字怎么处理?
缺少的内容,统一使用一个数字(非词/字的数字)替代。
6、如果语料库中的词/字太多是否可以压缩?
可以,某些词/字出现的频率比较低,可能训练不出特征。因此可以选择频率比较高的词来训练。例如选择4760个。
7、被压缩的词/字如何处理?
可以统一使用一个数字(非词/字的数字)替代。
二、问题解决
1.将评论内容转换成语料库
- 遍历每一行评论,除去第一行
- 取每行索引2之后的内容
- 然后对每行评论分字
- 获取每个字出现的次数,次数等于1的去掉
- 然后字作为键,出现次数作为值,将其装入字典
- 按照值的大小进行降序排列,只保留前4760个字
- 将值更新为索引,之后将<UNK>和<PAD>添加在字典末尾
- 至此获取了整个文件的语料库以及每个字的独热编码
- 将其以二进制形式保存在pkl文件里
from tqdm import tqdm
import pickle as pklMAX_VOCAB_SIZE = 4760 # 词表长度限制
UNK, PAD = '<UNK>', '<PAD>' # 未知字符号 padding 无含义 unk 识别不出来的字def build_vocab(file_path, max_size, min_freq):'''功能:基于文本内容建立词表vocab,vocab中包含语料库中的字参数:file_path: 需要读取的语料库的路径max_size: 获取词频最高的前max_size个词.min_freq 剔除字频低于min_freq个的词'''tokenizer = lambda x: [y for y in x] # 分字函数vocab_dic = {} # 用于保存词的字典with open(file_path, 'r', encoding='utf8') as f:i = 0for line in tqdm(f): # 用来显示循环的进度条if i == 0:i += 1continuelin = line[2:].strip() # 获取评论内容 剔除标签 不用split分割 因为评论内容中可能存在逗号if not lin:continue # 如果lin中没有内容则 continuefor word in tokenizer(lin):vocab_dic[word] = vocab_dic.get(word, 0) + 1 # 统计每个字出现的次数 .get(key,default) 这个键有值就返回该值 , 没有的话返回默认值vocab_list = sorted([_ for _ in vocab_dic.items() if _[1] > min_freq], key=lambda x: x[1], reverse=True)[:max_size]vocab_dic = {word_count[0]: idx for idx, word_count in enumerate(vocab_list)}vocab_dic.update({UNK: len(vocab_dic), PAD: len(vocab_dic) + 1})print(vocab_dic)pkl.dump(vocab_dic, open('simplifyweibo_4_moods.pkl', 'wb')) # 将字典以二进制形式保存在pkl 统计完所有文字 每个文字都有独热编码print(f"Vocab size:{len(vocab_dic)}") # 将评论的内容根据词表vocab_dic 转换成词向量return vocab_dicif __name__ == '__main__':vocab = build_vocab('simplifyweibo_4_moods.csv', MAX_VOCAB_SIZE, 1) # 获取语料库中每个字的词向量pass# print('vocab')
输出:
- 字典,键是字 值是该字的词向量,整体按照字出现的次数排序
2.获取每条评论的词向量、标签和长度
- 读取评论文件
- 遍历每一行,
- 获取评论标签、评论内容以及评论的真实长度
- 判断评论长度是否大于70
- 若大于,则只取70个字
- 若小于,则在末尾填充<PAD>
- 读取上一步保存的语料库文件
- 判断每条评论中的每个字是否在内,
- 不在内的将其转换成<UNK>
- 在内的获取该字的值
- 一条评论的值装入一个列表,加上该评论的标签和真实长度,将其装入一个元组然后放入另一个列表中
- 至此列表中装着每条评论的词向量、标签和长度
- 取前80%作为训练集,80%-90%作为验证集,90%-100%作为测试集
from tqdm import tqdm
import pickle as pkl
import random
import torchUNK, PAD = '<UNK>', '<PAD>' # 未知字符号def load_dataset(path, pad_size=70):contents = []vocab = pkl.load(open('simplifyweibo_4_moods.pkl', 'rb')) # 读取vocab文件tokenizer = lambda x: [y for y in x]with open(path, 'r', encoding='utf8') as f:i = 0for line in tqdm(f):if i == 0:i += 1continueif not line:continuelabel = int(line[0]) # 获取该行评论标签content = line[2:].strip('\n') # 获取该行评论内容 去掉末尾换行符words_line = []token = tokenizer(content) # 将每一行内容进行分字seq_len = len(token) # 获取每一行评论的字长if pad_size:if len(token) < pad_size: # 如果一行字少于70 则补充<PAD>token.extend([PAD] * (pad_size - len(token)))else:token = token[:pad_size] # 只取当前评论前70个seq_len = pad_size # 将当前评论长度换成70for word in token:words_line.append(vocab.get(word, vocab.get(UNK)))contents.append((words_line, int(label), seq_len))random.shuffle(contents) # 打乱顺序train_data = contents[:int(len(contents) * 0.8)] # 前80%为训练dev_data = contents[int(len(contents) * 0.8):int(len(contents) * 0.9)]test_data = contents[int(len(contents) * 0.9):]return vocab, train_data, dev_data, test_dataif __name__ == '__main__':vocab, train_data, dev_data, test_data = load_dataset('simplifyweibo_4_moods.csv')print(train_data, dev_data, test_data)
输出:
- 每一个元组第一个元素是列表,列表里装着该条评论每个字的独热编码
- 第二个元素是该评论的标签
- 第三个元素使该评论的真实长度
3.数据打包
- 将数据及其标签打包成128条评论一个的包,并将其转换成张量
- 通过if判断,将最后一个不满128的数据打成一个包,同样转换成张量
- 最后得到每条评论的独热编码、标签和长度的张量类型数据
- 将其传入GPU
class DatasetIterater(object):"""将数据batches切分为batch_size的包"""def __init__(self, batches, batch_size, device):self.batches = batchesself.batch_size = batch_sizeself.device = deviceself.n_batches = len(batches) // batch_size # 数据划分batch的数量self.residue = False # 记录划分后的数据是否存在剩余的数据if len(batches) % self.n_batches != 0: # 表示有余数self.residue = Trueself.index = 0def _to_tensor(self, datas):x = torch.LongTensor([_[0] for _ in datas]).to(self.device) # 评论内容y = torch.LongTensor([_[1] for _ in datas]).to(self.device) # 评论情感 最好转换成LongTensor# pad前的长度seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device)return (x, seq_len), ydef __next__(self):if self.residue and self.index == self.n_batches:batches = self.batches[self.index * self.batch_size:len(self.batches)]self.index += 1batches = self._to_tensor(batches)return batcheselif self.index > self.n_batches:self.index = 0raise StopIteration # 停止迭代else:batches = self.batches[self.index * self.batch_size:(self.index + 1) * self.batch_size]self.index += 1batches = self._to_tensor(batches)return batchesdef __iter__(self):return selfdef __len__(self):if self.residue:return self.n_batches + 1else:return self.n_batches
4.建立LSTM循环神经网络模型
1.主程序代码
- 下载腾讯自然语言处理模型嵌入层的参数并将其转换成张量类型
- 嵌入层的输出神经元设置为200
embedding_pretrained = torch.tensor(np.load('embedding_Tencent.npz')['embeddings'].astype('float32'))
# embedding_pretrained = None # 不使用外部训练的词向量
embed = embedding_pretrained.size(1) if embedding_pretrained is not None else 200
class_list = ['喜悦', '愤怒', '厌恶', '低落']
num_classes = len(class_list)
model = demo4TextRNN.Model(embedding_pretrained, len(vocab), embed, num_classes).to(device)
test(model, test_iter, class_list)
2.模型代码
- 告诉模型填充词的独热编码是多少
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:self.embedding = nn.Embedding.from_pretrained(embedding_pretrained, padding_idx=n_vocab - 1, freeze=False)# embedding_pretrained: Tensor,形状为(n_vocab, embed),其中n_vocab是词汇表大小,embed是嵌入维度。# freeze: 是否冻结embedding层的权重else:self.embedding = nn.Embedding(n_vocab, embed, padding_idx=n_vocab - 1)# padding_idx默认None 如果指定 则参数不会对梯度产生影响self.lstm = nn.LSTM(embed, 128, 3, bidirectional=True, batch_first=True, dropout=0.3)# embed: 输入特征的维度或词嵌入的大小。# 128: LSTM 隐藏层的大小,也就是隐藏状态的维度。整数,表示 LSTM 隐藏层输出的特征数量。# 3: LSTM层数(堆叠的LSTM层数量)。# bidirectional = True: 使用双向LSTM,考虑前向和后向序列信息。# batch_first = True: 输入输出形状为(batch_size, seq_length, input_size)。# dropout = 0.3: 在LSTM层之间应用的dropout比率(30% 表示 30% 的神经元会被丢弃)。self.fc = nn.Linear(128 * 2, num_classes) # 因为是双向 所以 *2def forward(self, x):x, _ = x # 只提取评论的独热编码out = self.embedding(x)out, _ = self.lstm(out) # 一个字256个特征 因为是双向的out = self.fc(out[:, -1, :]) #return out
5.建立训练集函数和测试集函数
- 传入模型,训练集数据,验证集数据,测试集数据和分类
- 后面的操作与多分类时函数逻辑一致
import torch.optim
import numpy as np
from sklearn import metrics
import torch.nn.functional as Fdef evaluate(class_list, model, data_iter, test=False):model.eval()loss_total = 0predict_all = np.array([], dtype=int)labels_all = np.array([], dtype=int)with torch.no_grad():for texts, labels in data_iter:outputs = model(texts)loss = F.cross_entropy(outputs, labels)loss_total += losslabels = labels.data.cpu().numpy() # NumPy 操作仅在 CPU 张量上有效predict = torch.max(outputs.data, 1)[1].cpu().numpy()labels_all = np.append(labels_all, labels)predict_all = np.append(predict_all, predict)acc = metrics.accuracy_score(labels_all, predict_all)if test:report = metrics.classification_report(labels_all, predict_all, target_names=class_list, digits=4)return acc, loss_total / len(data_iter), reportreturn acc, loss_total / len(data_iter)def test(model, test_iter, class_list):model.load_state_dict(torch.load('TextRNN.ckpt')) # 使用最优模型model.eval()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)total_batch = 0 # 记录进行到多少batchdev_best_loss = float('inf') # 表示无穷大last_improve = 0 # 记录上次验证集loss下降的batch数flag = False # 记录是否很久没有效果提升epochs = 2for epoch in range(epochs):print("{}/{}".format(epoch + 1, epochs))for i, (trains, labels) in enumerate(train_iter):outputs = model(trains)loss = F.cross_entropy(outputs, labels)model.zero_grad()loss.backward()optimizer.step()if total_batch % 100 == 0:predict = torch.max(outputs.data, 1)[1].cpu() # 第一个参数是要计算的张量,第二个参数是维度。在这里,1 表示按行计算最大值 返回元组 (最大值 对应的索引)train_acc = metrics.accuracy_score(labels.data.cpu(), predict)dev_acc, dev_loss = evaluate(class_list, model, dev_iter)if dev_loss < dev_best_loss:dev_best_loss = dev_loss # 保存最优模型torch.save(model.state_dict(), 'TextRNN.ckpt')last_improve = total_batchmsg = '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()total_batch += 1if total_batch - last_improve > 10000:print('no')flag = Trueif flag:break
最后在主程序使用测试集测试一下
由于样本数据不太均衡,所以有些种类的正确率比较低
相关文章:

深度学习:LSTM循环神经网络实现评论情感分析
目录 一、任务介绍 1.任务要求 2.信息内容 3.待思考问题 二、问题解决 1.将评论内容转换成语料库 2.获取每条评论的词向量、标签和长度 3.数据打包 4.建立LSTM循环神经网络模型 1.主程序代码 2.模型代码 5.建立训练集函数和测试集函数 一、任务介绍 1.任务要求 项…...

基于Arduino的环境监测装置
基于Arduino的环境监测装置 引言痛点功能前期准备软件硬件 项目开发硬件开发软件开发 功能演示更多精彩,欢迎关注 引言 本项目使用机智云Gokit2.0开发板,实现基于Arduino的环境监测装置,解决目前大多数人对环境数据要求逐渐增高的痛点。 痛…...

深度学习:模型攻击(Model Attack)详解
模型攻击(Model Attack)详解 模型攻击通常指在机器学习和人工智能领域中,故意设计的行为或方法,旨在操纵或欺骗机器学习模型的输出。这类攻击可能导致模型做出错误的决策或泄露敏感信息,对于安全性至关重要的应用&…...

CesiumLab介绍
软考鸭小程序 学软考,来软考鸭! 提供软考免费软考讲解视频、题库、软考试题、软考模考、软考查分、软考咨询等服务 CesiumLab是一个围绕Cesium平台设计的完整易用的数据预处理工具集,它旨在最大化提升三维数据可视化效率。本文将详细介绍CesiumLab的安装、主要功能…...

PyQt 入门教程(3)基础知识 | 3.2、加载资源文件
文章目录 一、加载资源文件1、PyQt5加载资源文件2、PyQt6加载资源文件 一、加载资源文件 常见的资源文件有图像与图标,下面分别介绍下加载资源文件的常用方法 1、PyQt5加载资源文件 2、PyQt6加载资源文件 PyQt6版本暂时没有提供pyrcc工具,下面介绍下在不…...

老照片修复工作流教程:用 ComfyUI 轻松还原历史记忆
你是否有过这样的遗憾? 那些珍贵的老照片因为时间的流逝,早已失去了当年的色彩,变得模糊、褪色,甚至破损? 今天带你了解如何使用 ComfyUI 的老照片修复工作流,通过简单的几步操作,在短短十几秒…...

ESP-IDF Blink实例学习
文章目录 一、引言二、工程创建1、打开vscode点击ESP-IDF资源管理器2、选择ESP-IDF框架3、选择Show Examples4、选择blink5、点击Create project using example blink ,选择创建目录6、创建完成 三、硬件电路LED管脚分配四、修改menuconfig五、编译和下载运行 一、引言 Blink实…...

QT QML 练习8-Simple Transformations
简单的转换(Simple Transformations) 转换操作改变了一个对象的几何状态。QML元素对象通常能够被平移,旋转,缩放。下面我们将讲解这些简单的操作和一些更高级的用法。 我们先从一个简单的转换开始。用下面的场景作为我们学习的开始…...

低空产业园搭建技术详解
低空产业园的搭建技术是一个复杂而系统的工程,涉及多个方面的技术和策略。以下是对低空产业园搭建技术的详细解析: 一、规划与设计 1. 总体规划:低空产业园的规划需要结合地方经济发展、产业基础、政策导向等因素,制定科学合理的…...

Python网络爬虫从入门到实战
目录 引言 一、网络爬虫的概念 二、 网络爬虫的基本工作流程 (一)过程: (二)安装requests模块和beautifulsoup4模块 (三)requests库的使用 1、requests库的基本介绍 2、导入requests库的…...

探索Theine:Python中的AI缓存新贵
文章目录 探索Theine:Python中的AI缓存新贵背景:为何选择Theine?Theine是什么?如何安装Theine?简单的库函数使用方法场景应用场景一:Web应用缓存场景二:分布式系统中的数据共享场景三࿱…...

js拼图(神鹰黑手哥)
直接上代码 再解释 这是最终效果图 css代码如下 * {margin: 0;padding: 0;}body {height: 800px;width: 100%;background-color: blanchedalmond;display: flex;justify-content: space-around;align-items: center;position: relative;}.img-box {display: flex;flex-wrap: w…...

值得推荐的五款数据恢复工具!!
当谈及我们日常工作生活中无法避免的数据丢失情况时,很多小伙伴一定急得如热锅上的蚂蚁,无助与忐忑。特别是现在社会,信息量庞大,一旦电脑上的重要数据不慎丢失,无论是工作文件、生活照片还是珍贵的视频,都…...

股票金融市场中的tick,分钟,日线数据
在金融市场中,股票数据的分析对于投资者来说至关重要。股票数据可以根据时间粒度的不同,分为几种不同的类型,包括Tick数据、分钟数据和日线数据。下面将详细介绍这些数据类型,并对比它们之间的差别。 Tick数据 Tick数据…...

OKG Research:如何衡量链上数据的开放价值?
在新加坡Token2049期间,欧科云链研究院受邀参加Bloomberg主办的企业另类资产投资峰会2024,与多位专家围绕未来数据形态与前景进行了深入交流。 活动后,欧科云链研究院负责人Lola Wang与资深研究员Jason Jiang在大公网发表署名文章《如何衡量…...

向日葵下载教程以及三款远程控制工具推荐!!!
向日葵远程控制下载教程!! 亲爱的朋友们,如果你对远程控制软件有所需求,那么向日葵绝对是一个不错的选择。现在我将带你走一遍向日葵的下载流程。 1. 打开你的浏览器,输入“向日葵官方网站”,进入官方网站…...

Studio One 6中文版及最新功能介绍 Studio One 6音乐软件安装包
Studio One 6是一款功能强大的数字音频工作站(DAW),专为音乐制作和录音而设计。它提供了从初学者到专业人士的所有需求,无论是创作、录音、混音还是母带处理。 Studio One 6拥有直观的界面和强大的虚拟乐器、插件和音频处理工具&a…...

【数据结构】栈和队列 + 经典算法题
目录 前言 一、栈 二、栈的实现 三、栈的循环遍历演示 四、栈的算法题 // 一、队列 二、队列的实现 三、使用演示 四、队列的算法题 总结 前言 本文完整实现了栈和队列的数据结构,以及栈和队列的一些经典算法题,让我们更加清楚了解这两种数据…...

C# 基于winform 使用NI-VISA USB口远程控制电源 万用表
1.下载完整版本NI-VISA NI-VISA Download - NI *注意支持的操作系统,以便后期编译 安装完成之后,打开NI MAX,插上usb口,打开测试面板进行通信 2.编程示例 见本地文件夹C:\Users\Public\Documents\National Instruments\NI-VIS…...

Python设计方差分析实验
前言 方差分析(ANOVA)是一种用于检测多个样本均值之间差异的统计方法,广泛应用于实验设计与数据分析中。通过分析不同因素对实验结果的影响,方差分析能够帮助评估哪些因素显著影响了实验结果,并且可以提供各因素交互作用的深入理解。在多因子实验设计中,随机化、重复和平…...

【Oracle DB故障分享】分享一次由于SGA设置太小导致的DP备份失败
List item 今天给客户做Oracle例行数据库健康巡检,过程中检出一些备份异常,分享如下。 排查问题: 打开DP备份软件,随即弹出如下提示: 登录DP,查看备份情况:发现从10/6开始,DP备份…...

Yocto构建教程:在SDK中添加Qt5并生成带有Qt5的SDK
下载meta-qt5 复位环境 确认下版本是否匹配 添加meta-qt5进bblayers.bb 先编译起来 研究meta-qt5 构建带有Qt5的toolchain SDK meta-toolchain如何编译带Qt5的软件包? 文件系统中如何添加Qt5软件包 如何同时编译目标镜像和SDK Yocto Project是一个开源的嵌…...

操作系统——位示图
这里写目录标题 前言基础说明相关计算题目一题目二题目三 前言 基础说明 位示图是一种用来表示文件和目录在磁盘上存储位置的图形化表示方法。它通过使用一系列的位来表示文件或目录所占用的磁盘块,从而显示出磁盘上的存储情况。 位示图通常是一个位向量…...

【STM32 Blue Pill编程实例】-矩阵键盘
矩阵键盘 文章目录 矩阵键盘1、矩阵键盘介绍2、硬件准备与接线3、模块配置3.1 矩阵键盘列引脚配置3.2 矩阵键盘列引脚配置3.3 LED配置4、代码实现在本文中,我们将介绍如何把 43 键盘与 STM32 Blue Pill 连接,并使用 HAL 库在 STM32CubeIDE 中对其进行编程。 键盘是一种输入设…...

基于SSM的药品商城系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...

南京邮电大学电工电子A实验十一(数据选择器及逻辑电路的动态测试)
文章目录 一、实验报告预览二、Word版本报告下载 一、实验报告预览 二、Word版本报告下载 点我...

算法.图论-BFS及其拓展
文章目录 广度优先搜索简介经典bfs习题地图分析贴纸拼词 01bfs解析基本过程相关习题 广度优先搜索简介 bfs的特点是逐层扩散, 从源头到目标点扩散了几层, 最短路就是多少 bfs的使用特征是任意两个节点的距离(权值)是相同的(无向图, 矩阵天然满足这一特点) bfs开始的时候可以是…...

mongodb的相关关键字说明
以下是MongoDB中一些数据库相关的关键字说明: 1. 数据库(Database) 概念 数据库是MongoDB中数据存储的最高层级容器,类似于关系型数据库中的数据库概念。一个MongoDB服务器实例可以包含多个数据库,每个数据库可以有自…...

强化学习之DDPG算法
前言: 在正文开始之前,首先给大家介绍一个不错的人工智能学习教程:https://www.captainbed.cn/bbs。其中包含了机器学习、深度学习、强化学习等系列教程,感兴趣的读者可以自行查阅。 一、算法介绍 深度确定性策略梯度 ࿰…...

【进阶OpenCV】 (16)-- 人脸识别 -- FisherFaces算法
文章目录 FisherFaces算法一、算法原理二、算法优势与局限三、算法实现1. 图像预处理2. 创建FisherFace人脸特征识别器3. 训练模型4. 测试图像 总结 FisherFaces算法 PCA方法是EigenFaces人脸识别的核心,但是其具有明显的缺点,在操作过程中会损失许多人…...