动手学深度学习--文本情感分析之RNN

?本分类是?然语?处理的?个常?任务,它把?段不定?的?本序列变换为?本的类别。它的?个?问题:使??本情感分类来分析?本作者的情绪。这个问题也叫情感分析,并有着?泛的应?。例如,我们可以分析?户对产品的评论并统计?户的满意度,或者分析?户对市场?情的情绪并?以预测接下来的?情。

这里将应?预训练的词向量和含多个隐藏层的双向循环神经?络,来判断?段不定?的?本序列中包含的是正?还是负?的情绪。

1、导入包和模块

 1 import collections
 2 import os
 3 import random
 4 import tarfile
 5 import torch
 6 from torch import nn
 7 import torchtext.vocab as Vocab
 8 import torch.utils.data as Data
 9
10 import sys
11 sys.path.append("..")
12 import d2lzh_pytorch as d2l
13
14 device = torch.device(‘cuda‘ if torch.cuda.is_available() else ‘cpu‘)
15
16 DATA_ROOT = "./Datasets"

2、读入数据

使?斯坦福的IMDb数据集(Stanford‘s Large Movie Review Dataset)作为?本情感分类的数据集。这个数据集分为训练和测试?的两个数据集,分别包含25,000条从IMDb下载的关于电影的评论。在每个数据集中,标签为“正?”和“负?”的评论数量相等。下载数据解压至Datasets中。读取训练数据集和测试数据集。每个样本是?条评论及其对应的标签: 1表示“正?”, 0表示“负?”。

 1 from tqdm import tqdm
 2 def read_imdb(folder=‘train‘, data_root="./Datasets/aclImdb"):
 3     data = []
 4     for label in [‘pos‘, ‘neg‘]:
 5         folder_name = os.path.join(data_root, folder, label)
 6         for file in tqdm(os.listdir(folder_name)):
 7             with open(os.path.join(folder_name, file), ‘rb‘) as f:
 8                 review = f.read().decode(‘utf-8‘).replace(‘\n‘, ‘‘).lower()
 9                 data.append([review, 1 if label == ‘pos‘ else 0])
10     random.shuffle(data)
11     return data
12
13 train_data, test_data = read_imdb(‘train‘), read_imdb(‘test‘)

3、预处理数据

定义的 get_tokenized_imdb 函数使?最简单的?法:基于空格进?分词。

1 def get_tokenized_imdb(data):
2     """
3     data: list of [string, label]
4     """
5     def tokenizer(text):
6         return [tok.lower() for tok in text.split(‘ ‘)]
7     return [tokenizer(review) for review, _ in data]

可以根据分好词的训练数据集来创建词典了。我们在这?过滤掉了出现次数少于5的词。

1 def get_vocab_imdb(data):
2     tokenized_data = get_tokenized_imdb(data)
3     counter = collections.Counter([tk for st in tokenized_data for tk in st])
4     return Vocab.Vocab(counter, min_freq=5)
5
6 vocab = get_vocab_imdb(train_data)
7 ‘# words in vocab:‘, len(vocab)  # (‘# words in vocab:‘, 46151)

因为每条评论?度不?致所以不能直接组合成?批量,我们定义 preprocess_imdb 函数对每条评论进?分词,并通过词典转换成词索引,然后通过截断或者补0来将每条评论?度固定成500。

 1 def preprocess_imdb(data, vocab):
 2     max_l = 500  # 将每条评论通过截断或者补0,使得长度变成500
 3
 4     def pad(x):
 5         return x[:max_l] if len(x) > max_l else x + [0] * (max_l - len(x))
 6
 7     tokenized_data = get_tokenized_imdb(data)
 8     features = torch.tensor([pad([vocab.stoi[word] for word in words]) for words in tokenized_data])
 9     labels = torch.tensor([score for _, score in data])
10     return features, labels

4、创建数据迭代器

我们创建数据迭代器。每次迭代将返回?个?批量的数据。

1 batch_size = 64
2 train_set = Data.TensorDataset(*preprocess_imdb(train_data, vocab))
3 test_set = Data.TensorDataset(*preprocess_imdb(test_data, vocab))
4 train_iter = Data.DataLoader(train_set, batch_size, shuffle=True)
5 test_iter = Data.DataLoader(test_set, batch_size)

5、RNN model

在这个模型中,每个词先通过嵌?层得到特征向量。然后,我们使?双向循环神经?络对特征序列进?步编码得到序列信息。最后,我们将编码的序列信息通过全连接层变换为输出。具体来说,我们可以将双向?短期记忆在最初时间步和最终时间步的隐藏状态连结,作为特征序列的表征传递给输出层分类。在下?实现的 BiRNN 类中, Embedding 实例即嵌?层, LSTM 实例即为序列编码的隐藏层, Linear实例即?成分类结果的输出层。

 1 class BiRNN(nn.Module):
 2     def __init__(self, vocab, embed_size, num_hiddens, num_layers):
 3         super(BiRNN, self).__init__()
 4         self.embedding = nn.Embedding(len(vocab), embed_size)  # 嵌入层
 5
 6         # bidirectional设为True即得到双向循环神经网络
 7         self.encoder = nn.LSTM(input_size=embed_size,
 8                                 hidden_size=num_hiddens,
 9                                 num_layers=num_layers,
10                                 bidirectional=True)  # 隐藏层
11         self.decoder = nn.Linear(4*num_hiddens, 2) # 初始时间步和最终时间步的隐藏状态作为全连接层输入
12
13     def forward(self, inputs):
14         # inputs的形状是(批量大小, 词数),因为LSTM需要将序列长度(seq_len)作为第一维,所以将输入转置后
15         # 再提取词特征,输出形状为(词数, 批量大小, 词向量维度)
16         embeddings = self.embedding(inputs.permute(1, 0))
17         # rnn.LSTM只传入输入embeddings,因此只返回最后一层的隐藏层在各时间步的隐藏状态。
18         # outputs形状是(词数, 批量大小, 2 * 隐藏单元个数)
19         outputs, _ = self.encoder(embeddings) # output, (h, c)
20         # 连结初始时间步和最终时间步的隐藏状态作为全连接层输入。它的形状为
21         # (批量大小, 4 * 隐藏单元个数)。
22         encoding = torch.cat((outputs[0], outputs[-1]), -1)
23         outs = self.decoder(encoding)
24         return outs

创建?个含两个隐藏层的双向循环神经?络。

1 embed_size, num_hiddens, num_layers = 100, 100, 2
2 net = BiRNN(vocab, embed_size, num_hiddens, num_layers)

6、加载预训练的词向量

由于情感分类的训练数据集并不是很?,为应对过拟合,我们将直接使?在更?规模语料上预训练的词向量作为每个词的特征向量。这?,我们为词典 vocab 中的每个词加载100维的GloVe词向量。然后,我们将?这些词向量作为评论中每个词的特征向量。注意,预训练词向量的维度需要与创建的模型中的嵌?层输出?? embed_size ?致。此外,在训练中我们不再更新这些词向量。

 1 glove_vocab = Vocab.GloVe(name=‘6B‘, dim=100, cache=os.path.join(DATA_ROOT, "glove"))
 2 def load_pretrained_embedding(words, pretrained_vocab):
 3     """从预训练好的vocab中提取出words对应的词向量"""
 4     embed = torch.zeros(len(words), pretrained_vocab.vectors[0].shape[0]) # 初始化为0
 5     oov_count = 0 # out of vocabulary
 6     for i, word in enumerate(words):
 7         try:
 8             idx = pretrained_vocab.stoi[word]
 9             embed[i, :] = pretrained_vocab.vectors[idx]
10         except KeyError:
11             oov_count += 0
12     if oov_count > 0:
13         print("There are %d oov words.")
14     return embed
15
16 net.embedding.weight.data.copy_(load_pretrained_embedding(vocab.itos, glove_vocab))
17 net.embedding.weight.requires_grad = False # 直接加载预训练好的, 所以不需要更新它

对于预训练词向量我们使?基于维基百科?集预训练的50维GloVe词向量。第?次 创 建 预 训 练 词 向 量 实 例 时 会 ? 动 下 载 相 应 的 词 向 量 到 cache 指 定 ? 件 夹 ( 默 认为 .vector_cache ),因此需要联?。

cache_dir = "./Datasets/glove"
glove = vocab.GloVe(name=‘6B‘, dim=50, cache=cache_dir)

# ./Datasets/glove/glove.6B.zip: 862MB [40:57, 351kB/s]
# 100%|█████████▉| 399022/400000 [00:30<00:00, 24860.36it/s]

7、训练并评价模型

1 lr, num_epochs = 0.01, 5
2 optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, net.parameters()), lr=lr)
3 loss = nn.CrossEntropyLoss()
4 d2l.train(train_iter, test_iter, net, loss, optimizer, device, num_epochs)

8、定义预测函数

1 def predict_sentiment(net, vocab, sentence):
2     """sentence是词语的列表"""
3     device = list(net.parameters())[0].device
4     sentence = torch.tensor([vocab.stoi[word] for word in sentence], device=device)
5     label = torch.argmax(net(sentence.view((1, -1))), dim=1)
6     return ‘positive‘ if label.item() == 1 else ‘negative‘

实现预测

predict_sentiment(net, vocab, [‘this‘, ‘movie‘, ‘is‘, ‘so‘, ‘great‘])  # positive

原文地址:https://www.cnblogs.com/harbin-ho/p/12003246.html

时间: 2024-11-05 16:24:43

动手学深度学习--文本情感分析之RNN的相关文章

DataWhale 动手学深度学习PyTorch版-task3+4+5:文本预处理;语言模型;循环神经网络基础

课程引用自伯禹平台:https://www.boyuai.com/elites/course/cZu18YmweLv10OeV <动手学深度学习>官方网址:http://zh.gluon.ai/ ——面向中文读者的能运行.可讨论的深度学习教科书. 第二次打卡: Task03: 过拟合.欠拟合及其解决方案:梯度消失.梯度爆炸:循环神经网络进阶 Task04:机器翻译及相关技术:注意力机制与Seq2seq模型:Transformer Task05:卷积神经网络基础:leNet:卷积神经网络进阶 有

小白学习之pytorch框架(2)-动手学深度学习(begin)

在这向大家推荐一本书-花书-动手学深度学习pytorch版,原书用的深度学习框架是MXNet,这个框架经过Gluon重新再封装,使用风格非常接近pytorch,但是由于pytorch越来越火,个人又比较执着,想学pytorch,好,有个大神来了,把<动手学深度学习>整本书用pytorch代码重现了,其GitHub网址为:https://github.com/ShusenTang/Dive-into-DL-PyTorch   原书GitHub网址为:https://github.com/d2l-

分享《动手学深度学习》高清PDF+视频教程-李沐著

下载:https://pan.baidu.com/s/10EKdEe-vjp9i97xP1FWuGA 更多资料学习:http://blog.51cto.com/14087171 由 MXNet 创始人李沐大神.Aston Zhang 等人所著的交互式书籍<动手学深度学习>推出了在线预览版,面向在校学生.工程师和研究人员,旨在帮助读者从入门到深入.动手学习深度学习,即使是零基础的读者也完全适用. 在本书上线之前,李沐等人还推出了<动手学深度学习>系列视频,这门课程的第一季已经于今年

分享《动手学深度学习(李沐等著)》PDF+源代码+《神经网络与深度学习(吴岸城)著》PDF

下载:https://pan.baidu.com/s/11O2m_uxSWJGbkXHF2Zh94w 更多资料:https://pan.baidu.com/s/1g4hv05UZ_w92uh9NNNkCaA <动手学深度学习(李沐等著)> 中文PDF,530页,带书签目录,文字可以复制粘贴.配套源代码. <神经网络与深度学习 (吴岸城)著>中文PDF,233页,带书签目录. 如图: 原文地址:https://www.cnblogs.com/limujun/p/10054478.ht

对比《动手学深度学习》 PDF代码+《神经网络与深度学习 》PDF

随着AlphaGo与李世石大战的落幕,人工智能成为话题焦点.AlphaGo背后的工作原理"深度学习"也跳入大众的视野.什么是深度学习,什么是神经网络,为何一段程序在精密的围棋大赛中可以大获全胜?人工智终将会取代人类智慧吗? <神经网络与深度学习>是一本介绍神经网络和深度学习算法基本原理及相关实例的书籍,它不是教科书,作者已尽量把公式减少到最少,以适应绝大部分人的阅读基础和知识储备.<神经网络与深度学习>涵盖了神经网络的研究历史.基础原理.深度学习中的自编码器.深

【动手学深度学习】Jupyter notebook中 import mxnet出错

问题描述 打开d2l-zh目录,使用jupyter notebook打开文件运行,import mxnet 出现无法导入mxnet模块的问题, 但是命令行运行是可以导入mxnet模块的. 原因: 激活环境是能够运行代码的前提. 解决方法: 在d2l-zh目录运行conda activate gluon命令,然后再打开jupyter notebook,则可以正常导入mxnet模块. 参考 1. d2l-zh-doc; 2. [动手学深度学习]中Jupyter notebook中 import mx

动手学深度学习第一课:从上手到多类分类-Autograd

使用autograd来自动求导 在机器学习中,我们通常使用梯度下降来更新模型参数从而求解.损失函数关于模型参数的梯度指向一个可以降低损失函数值的方向,我们不断地沿着梯度的方向更新模型从而最小化损失函数.虽然梯度计算比较直观,但对于复杂的模型,例如多达数十层的神经网络,手动计算梯度非常困难. 为此MXNet提供autograd包来自动化求导过程.虽然大部分的深度学习框架要求编译计算图来自动求导,mxnet.autograd可以对正常的命令式程序进行求导,它每次在后端实时创建计算图从而可以立即得到梯

动手学深度学习 3-5 Others

其他问题 1. 模型选择.欠拟合和过拟合 1.1 训练误差和泛化误差 1.2 模型选择 1.2.1 验证数据集 1.2.2 \(K\) 折交叉验证 由于验证数据集不参与模型训练,当训练数据不够用时,预留大量的验证数据显得太奢侈.一种改善的方法是\(K\)折交叉验证(\(K\)-fold cross-validation).在\(K\)折交叉验证中,我们把原始训练数据集分割成\(K\)个不重合的子数据集,然后我们做\(K\)次模型训练和验证.每一次,我们使用一个子数据集验证模型,并使用其他\(K-

动手学深度学习 4 Deep-learning-computation

4. deep-learning-computaion 4.1 模型构造 4.1.1 继承Block来构造模型 Block类是nn模块里提供的一个模型构造类,我们可以继承它来定义我们想要的模型也可以继承它来构造层. 事实上,Sequential类继承自Block类.当模型的前向计算为简单串联各个层的计算时,可以通过更加简单的方式定义模型.这正是Sequential类的目的:它提供add函数来逐一添加串联的Block子类实例,而模型的前向计算就是将这些实例按添加的顺序逐一计算,且无需定义forwa