循环神经网络LSTM实现电影情感分类
循环神经网络LSTM实现电影情感分类
一.数据集:
为了对word embedding这种常用的文本向量化的方法进行巩固,这里我们会完成一个文本情感分类的案例
现在我们有一个经典的数据集IMDB
数据集,地址:http://ai.stanford.edu/~amaas/data/sentiment/
,这是一份包含了5万条流行电影的评论数据,其中训练集25000条,测试集25000条。数据格式如下:
下图左边为名称,其中名称包含两部分,分别是序号和情感评分,(1-4为neg,5-10为pos),右边为评论内容
但本次实验从简设计只实现二分类,即实现积极
和消极
的预测
二.实现流程
三.数据集准备
数据集DataSet构建
import pickleimport torch
from torch.utils.data import DataLoader, Dataset
import os
import re'''
data: 电影评论数据
数据集准备
使用W2S模型将文本序列化
'''
data_base_path = r"./aclImdb"# 加载-词典(Word2Sequence中保存的模型,事先生成使用w2s_save保存的模型)-用于文本序列化
ws = pickle.load(open("./models/ws.pkl", "rb"))
Max_Len = 40
train_batch_size = 512
test_batch_size = 1024# 定义tokenize的方法
def tokenize(text):# fileters = '!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n'fileters = ['!', '"', '#', '$', '%', '&', '\(', '\)', '\*', '\+', ',', '-', '\.', '/', ':', ';', '<', '=', '>','\?', '@', '\[', '\\', '\]', '^', '_', '`', '\{', '\|', '\}', '~', '\t', '\n', '\x97', '\x96', '”','“', ]text = re.sub("<.*?>", " ", text)text = re.sub("|".join(fileters), " ", text)return [i.strip().lower() for i in text.split()]# 准备dataset
class ImdbDataset(Dataset):def __init__(self, train=True):super(ImdbDataset, self).__init__()self.train_data_path = data_base_path + r'\train'self.test_data_path = data_base_path + r'\test'self.data_path = self.train_data_path if train else self.test_data_path# 把所有文件名放入列表self.temp_data_path = [os.path.join(self.data_path, 'pos'), os.path.join(self.data_path, 'neg')]self.total_file_path_list = [] # 所有评论文件的pathfor path in self.temp_data_path:self.total_file_path_list.extend([os.path.join(path, j) for j in os.listdir(path) if j.endswith('.txt')])def __getitem__(self, index):# 获取评论路径path = self.total_file_path_list[index]# 获取标签label_str = path.split('\\')[-2]label = 0 if label_str == 'neg' else 1content = tokenize(open(path,encoding='utf-8').read())return content, labeldef __len__(self):return len(self.total_file_path_list)def collate_fn(batch):# batch是list,其中是一个一个元组,每个元组是dataset中__getitem__的结果# print(batch)content, labels = list(zip(*batch))content = torch.LongTensor([ws.transform(i,max_len=Max_Len) for i in content])labels = torch.LongTensor(labels)print(content, labels)return content, labelsdef get_dataloader(train=True,batch_size=train_batch_size):# 2. 实例化,准备dataloaderdataset = ImdbDataset(train)dataloader = DataLoader(dataset=dataset, batch_size=batch_size, shuffle=True, collate_fn=collate_fn)return dataloaderif __name__ == '__main__':# 3. 观察数据输出结果for idx, (sentence, label) in enumerate(get_dataloader()):print("idx:", idx)print("sentence:", sentence)print("label:", label)break
- 文本序列化
import numpy as np
'''
文本序列化,序列化文本类
'''
class Word2Sequence():UNK_TAG = "UNK"PAD_TAG = "PAD"UNK = 0PAD = 1def __init__(self):self.dict = {self.UNK_TAG :self.UNK,self.PAD_TAG :self.PAD}# 是否进行fit 操作self.fited = False# 是否构建词典操作self.build_vocabd = False# 词频统计self.count = {}def to_index(self,word):"""word -> index"""assert self.fited == True,"必须先进行fit操作"return self.dict.get(word,self.UNK)def to_word(self,index):"""index -> word"""assert self.fited , "必须先进行fit操作"if index in self.inversed_dict:return self.inversed_dict[index]return self.UNK_TAGdef __len__(self):return len(self.dict)def fit(self,sentence):for word in sentence:self.count[word] = self.count.get(word, 0) + 1self.fited = Truedef build_vocab(self, min_count=5, max_count=None, max_features=None):'''生成词典:param sentence: [word1.word2,word3 .....]:param min_count: 最小出现的次数:param max_count: 最大出现的次数:param max_features: 一共保留多少个特征(word):return:'''# 删除词频中count 最小的wordif min_count is not None:self.count = {k: v for k, v in self.count.items() if v >= min_count}# 删除词频超过限制的wordif max_count is not None:self.count = {k: v for k, v in self.count.items() if v <= max_count}if max_features is not None:# 对词频字典排序取前max_features个词语temp = sorted(self.count.items(),key=lambda x: x[-1],reverse=True)[:max_features]self.count = dict(temp)# 给处理好的word编号for word in self.count:self.dict[word] = len(self.dict)# 得到一个翻转的字典(编号:词)self.inversed_dict = dict(zip(self.dict.values(), self.dict.keys()))self.build_vocabd = Truedef transform(self, sentence, max_len=None):"""实现把句子转化为数组(向量):param sentence: [word1,word2,word3 ....]:param max_len: 向量的限制长度:return:"""assert self.fited, "必须先进行fit操作"assert self.build_vocabd,"必须先进行build_vocab操作"if max_len is not None:if max_len > len(sentence):sentence = sentence + [self.PAD_TAG] * (max_len-len(sentence)) # 填充else:sentence = sentence[:max_len] # 裁剪return [self.dict.get(word,self.UNK) for word in sentence]def inverse_transform(self,indices):"""实现从数组转化为文字:param indices: [1,2,3....]:return:[word1,word2.....]"""assert self.fited, "必须先进行fit操作"assert self.build_vocabd,"必须先进行build_vocab操作"return [self.inversed_dict.get(idx) for idx in indices]if __name__ == '__main__':w2s = Word2Sequence()w2s.fit(["你", "好", "么"])w2s.fit(["你", "好", "哦"])w2s.build_vocab(min_count=1)print(w2s.dict)print(w2s.fited)print(w2s.transform(["你","好","嘛"]))print(w2s.transform(["你好嘛"],max_len=10))print(w2s.inverse_transform([5,2,4]))print(len(w2s))
- 生成序列化模型
略
四.模型构建
import os
import torch
import numpy as np
from torch import nn, optim
from DataSet import get_dataloader, ws, Max_Len, test_batch_size
import torch.nn.functional as F
from tqdm import tqdm'''
IMDB电影评论情感分析(pos,neg)积极和消极-改进版
使用LSTM双向循环神经网络,抽取最后一个时间步的特征用作全连接层特征输入
即:文本 -> num -> vector -> LSTM[last TimeStep] -> 2层全连接 -> softmax
'''class IMDBLstmmodel(nn.Module):def __init__(self):super(IMDBLstmmodel,self).__init__()# 以下部分为超参数,可以自行修改self.hidden_size = 64 # 每一层的LSTM单元数self.embedding_dim = 200 # 每个词的向量长度self.num_layer = 2 # 隐藏层数self.bidriectional = True # 是否使用双向的LSTMself.bi_num = 2 if self.bidriectional else 1 # 是否是双向的LSTMself.dropout = 0.5self.embedding = nn.Embedding(len(ws),self.embedding_dim, padding_idx=ws.PAD)self.lstm = nn.LSTM(input_size=self.embedding_dim, hidden_size=self.hidden_size, num_layers=self.num_layer,bidirectional=self.bidriectional, dropout=self.dropout)# 使用两个全连接层,中间使用relu激活函数self.fc = nn.Linear(self.hidden_size*self.bi_num, 20)self.fc2 = nn.Linear(20, 2)def forward(self, x): # 输入的x的形状[batch_size, sequence_len]# x 经过embedding 之后的形状 [batch_size, sequence_len, embedding_dim]x = self.embedding(x)# 进行轴交换 x的形状变为[sequence_len, batch_size, embdedding_dim]x = x.permute(1, 0, 2)# x的形状[sequence_len, batch_size, hidden_size] , h_n的形状[num_layer*bi_num, batch, hidden_size], c_n同h_nx, (h_n, c_n) = self.lstm(x)# 只要最后一个lstm单元处理的结果,即正向的最后一个lstm 和 反向的最后一个处理结果合并,形状为[batch_szie, hidden_size*bi_num]out = torch.cat([h_n[-2, :, :], h_n[-1, :, :]], dim=-1)out = self.fc(out)out = F.relu(out)out = self.fc2(out)return F.log_softmax(out,dim=-1)
五. 模型训练
# 实例化模型
model = IMDBLstmmodel()
# 实例化优化器
optimizer = optim.Adam(model.parameters(), lr=0.001)
if os.path.exists('./models/lstm_model.pkl'): # 是否有已训练的模型,方便快速训练model.load_state_dict(torch.load('./models/lstm_model.pkl'))optimizer.load_state_dict(torch.load('./models/lstm_optimizer.pkl'))# 定义训练函数
def train(epoch):data_loader = get_dataloader()for idx, (input, label) in tqdm(enumerate(data_loader),total=len(data_loader),ascii=True,desc='第%d轮训练'%epoch):# 梯度清零optimizer.zero_grad()# 使用模型进行预测ouput = model(input)# 计算损失loss = F.nll_loss(ouput, label)# 误差反向传播loss.backward()# 梯度更新optimizer.step()if idx == len(data_loader)-1:print('result: 第%d轮次训练,损失%f'%(epoch,loss.item()))torch.save(model.state_dict(), "./models/lstm_model.pkl") # 模型保存torch.save(optimizer.state_dict(), './models/lstm_optimizer.pkl') # 优化器保存
训练效果(这里我已经提前训练了,所以损失已经很低了)
六.模型评估
# 模型评估
def test():model.eval()loss_ = []acc_ = []with torch.no_grad():data_loader = get_dataloader(train=False,batch_size=test_batch_size)for idx, (input, label) in tqdm(enumerate(data_loader),total=len(data_loader),ascii=True,desc='模型评估'):ouput = model(input)loss = F.nll_loss(ouput,label,reduction="mean")loss_.append(loss.item())pred = ouput.max(dim=1)[1] # [batch_size, 1]acc_.append(pred.eq(pred).float().mean()) # 每个批次的平均准确率print('模型损失%f,平均准确率%f' % (np.mean(loss_), np.mean(acc_)))
准确率在99% 以上
循环神经网络LSTM实现电影情感分类相关推荐
- 使用循环神经网络(RNN)实现影评情感分类
最近由于做论文的补充实验,需要在rnn上做一下算法验证.找了一下这个博客写的挺好的,但是也有一些bug,暂时先记录一下. 使用循环神经网络(RNN)实现影评情感分类 作为对循环神经网络的实践,我用循环 ...
- Python实现PSO粒子群优化循环神经网络LSTM分类模型项目实战
说明:这是一个机器学习实战项目(附带数据+代码+文档+视频讲解),如需数据+代码+文档+视频讲解可以直接到文章最后获取. 1.项目背景 PSO是粒子群优化算法(Particle Swarm Optim ...
- 循环神经网络实现文本情感分类之使用LSTM完成文本情感分类
循环神经网络实现文本情感分类之使用LSTM完成文本情感分类 1. 使用LSTM完成文本情感分类 在前面,使用了word embedding去实现了toy级别的文本情感分类,那么现在在这个模型中添加上L ...
- PyTorch-09 循环神经网络RNNLSTM (时间序列表示、RNN循环神经网络、RNN Layer使用、时间序列预测案例、RNN训练难题、解决梯度离散LSTM、LSTM使用、情感分类问题实战)
PyTorch-09 循环神经网络RNN&LSTM (时间序列表示.RNN循环神经网络.RNN Layer使用.时间序列预测案例(一层的预测点的案例).RNN训练难题(梯度爆炸和梯度离散)和解 ...
- 循环神经网络LSTM RNN回归:sin曲线预测
摘要:本篇文章将分享循环神经网络LSTM RNN如何实现回归预测. 本文分享自华为云社区<[Python人工智能] 十四.循环神经网络LSTM RNN回归案例之sin曲线预测 丨[百变AI秀]& ...
- [译] RNN 循环神经网络系列 2:文本分类
原文地址:RECURRENT NEURAL NETWORKS (RNN) – PART 2: TEXT CLASSIFICATION 原文作者:GokuMohandas 译文出自:掘金翻译计划 本文永 ...
- 深度学习中的循环神经网络LSTM详解
(一).什么是循环神经网络LSTM? LSTM指的是长短期记忆网络(Long Short Term Memory),它是循环神经网络中最知名和成功的扩展.由于循环神经网络有梯度消失和梯度爆炸的问题,学 ...
- 基于RNN循环神经网络lstm的藏头诗制作
基于RNN循环神经网络lstm的藏头诗制作 简单介绍 在一次偶然中接触到藏头诗,觉得十分有意思.但是好像都是利用古代本就有的诗句重新组合而成.比如输入清风袭来,结果如下图所示. 之后想到不如利用深度学 ...
- LSTM+word2vec电影情感分析
LSTM+word2vec电影情感分析 import numpy as np import matplotlib.pyplot as plt import pandas as pd from skle ...
最新文章
- 桌面应用程序 azure_如何开始使用Microsoft Azure-功能应用程序,HTTP触发器和事件队列...
- operate XML file (Open,Insert)
- 一日千里 云计算普及势不可挡
- FFmpeg在Linux下编译使用
- 2pin接口耳机_拆解报告:雷柏首款真无线耳机XS200
- mysql union_Mysql union和union all用法
- 牛客网编程题04--字符串处理
- React 事件总结
- 查看unix和linux的HBA卡的WWN地址
- 使用cross-env解决跨平台设置NODE_ENV的问题
- 【图像修复】基于matlab GUI Lucy_Richardson迭代法图像修复【含Matlab源码 846期】
- 微信聊天小程序——(五、添加好友)
- 7-59 二元一次方程的解
- linux文件重定向 dup,linux之dup和dup2函数解析
- 各种类型的电脑进入bios界面
- 笔记本双无线网卡内外网配置路由
- 什么是稳压电源(Regulated Power Supply)?
- 推广都需要哪些工具?这几款工具可以轻松提高推广效率
- Fiddler使用 抓取手机数据包及中文乱码解决方案
- 【数据结构和算法】 八大排序算法详解