目录

  • 说明
  • 配置环境
  • 此节说明
  • 代码

说明

本博客代码来自开源项目:《动手学深度学习》(PyTorch版)
并且在博主学习的理解上对代码进行了大量注释,方便理解各个函数的原理和用途

配置环境

使用环境:python3.8
平台:Windows10
IDE:PyCharm

此节说明

此节对应书本上10.7节
此节功能为:文本情感分类:使用循环神经网络
由于此节相对复杂,代码注释量较多

代码

# 本书链接https://tangshusen.me/Dive-into-DL-PyTorch/#/
# 10.7 文本情感分类:使用循环神经网络
# 注释:黄文俊
# E-mail:hurri_cane@qq.comimport collections
import os
import random
import tarfile
import torch
from torch import nn
import torchtext.vocab as Vocab
import torch.utils.data as Dataimport sys
sys.path.append("..")
import d2lzh_pytorch as d2los.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')DATA_ROOT = "D:/Program/Pytorch/Datasets"from tqdm import tqdm
# 本函数已保存在d2lzh_pytorch包中方便以后使用
def read_imdb(folder='train', data_root="D:/Program/Pytorch/Datasets/aclImdb"):data = []for label in ['pos', 'neg']:folder_name = os.path.join(data_root, folder, label)for file in tqdm(os.listdir(folder_name)):with open(os.path.join(folder_name, file), 'rb') as f:review = f.read().decode('utf-8').replace('\n', '').lower()# .lower()将字符串中的所有大写字母转换为小写字母,并返回一个新字符串data.append([review, 1 if label == 'pos' else 0])random.shuffle(data)return datatrain_data, test_data = read_imdb('train'), read_imdb('test')# 基于空格进行分词
# 本函数已保存在d2lzh_pytorch包中方便以后使用
def get_tokenized_imdb(data):"""data: list of [string, label]"""def tokenizer(text):return [tok.lower() for tok in text.split(' ')]return [tokenizer(review) for review, _ in data]# 过滤掉了出现次数少于5的词
# 本函数已保存在d2lzh_pytorch包中方便以后使用
def get_vocab_imdb(data):tokenized_data = get_tokenized_imdb(data)counter = collections.Counter([tk for st in tokenized_data for tk in st])return Vocab.Vocab(counter, min_freq=5)vocab = get_vocab_imdb(train_data)
print('# words in vocab:', len(vocab))# 通过截断或者补0来将每条评论长度固定成500
# 本函数已保存在d2lzh_torch包中方便以后使用
def preprocess_imdb(data, vocab):max_l = 500  # 将每条评论通过截断或者补0,使得长度变成500def pad(x):return x[:max_l] if len(x) > max_l else x + [0] * (max_l - len(x))tokenized_data = get_tokenized_imdb(data)features = torch.tensor([pad([vocab.stoi[word] for word in words]) for words in tokenized_data])labels = torch.tensor([score for _, score in data])return features, labels# 创建数据迭代器
batch_size = 128
# 此处将原有的64改为了128,因为如果是64的话会报错:
# RuntimeError cuDNN error CUDNN_STATUS_INTERNAL_E
train_set = Data.TensorDataset(*preprocess_imdb(train_data, vocab))
test_set = Data.TensorDataset(*preprocess_imdb(test_data, vocab))
# 训练数据集和测试数据集的尺寸调整为一致,均包含长度为500的字符串以及字符串对应的标签值(0/1)train_iter = Data.DataLoader(train_set, batch_size, shuffle=True)
test_iter = Data.DataLoader(test_set, batch_size)for X, y in train_iter:print('X', X.shape, 'y', y.shape)break
print('#batches:', len(train_iter))
# len(train_iter)表示这个迭代器按照小批量batch_size来取需要多少次能取完所有样本# 10.7.2 使用循环神经网络的模型
class BiRNN(nn.Module):def __init__(self, vocab, embed_size, num_hiddens, num_layers):super(BiRNN, self).__init__()self.embedding = nn.Embedding(len(vocab), embed_size)# bidirectional设为True即得到双向循环神经网络self.encoder = nn.LSTM(input_size=embed_size,hidden_size=num_hiddens,num_layers=num_layers,bidirectional=True)# 初始时间步和最终时间步的隐藏状态作为全连接层输入self.decoder = nn.Linear(4*num_hiddens, 2)def forward(self, inputs):# inputs的形状是(批量大小, 词数),因为LSTM需要将序列长度(seq_len)作为第一维,所以将输入转置后# 再提取词特征,输出形状为(词数, 批量大小, 词向量维度)embeddings = self.embedding(inputs.permute(1, 0))'''embedding运算其实就是根据输入的inputs来索引嵌入层的词向量'''# rnn.LSTM只传入输入embeddings,因此只返回最后一层的隐藏层在各时间步的隐藏状态。# outputs形状是(词数, 批量大小, 2 * 隐藏单元个数)outputs, _ = self.encoder(embeddings)   # output, (h, c)# 连结初始时间步和最终时间步的隐藏状态作为全连接层输入。它的形状为# (批量大小, 4 * 隐藏单元个数)。encoding = torch.cat((outputs[0], outputs[-1]), -1)outs = self.decoder(encoding)return outs# 创建一个含两个隐藏层的双向循环神经网络。
embed_size, num_hiddens, num_layers = 100, 100, 2
net = BiRNN(vocab, embed_size, num_hiddens, num_layers)# 10.7.2.1 加载预训练的词向量
glove_vocab = Vocab.GloVe(name='6B', dim=100, cache=os.path.join(DATA_ROOT, "glove"))# 本函数已保存在d2lzh_torch包中方便以后使用
def load_pretrained_embedding(words, pretrained_vocab):"""从预训练好的vocab中提取出words对应的词向量"""embed = torch.zeros(len(words), pretrained_vocab.vectors[0].shape[0]) # 初始化为0oov_count = 0   # out of vocabularyfor i, word in enumerate(words):try:idx = pretrained_vocab.stoi[word]embed[i, :] = pretrained_vocab.vectors[idx]except KeyError:oov_count += 1if oov_count > 0:print("There are %d oov words." % oov_count)return embednet.embedding.weight.data.copy_(load_pretrained_embedding(vocab.itos, glove_vocab))
net.embedding.weight.requires_grad = False # 直接加载预训练好的, 所以不需要更新它# 10.7.2.2 训练并评价模型
lr, num_epochs = 0.01, 5
# 要过滤掉不计算梯度的embedding参数
optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, net.parameters()), lr=lr)
loss = nn.CrossEntropyLoss()
d2l.train(train_iter, test_iter, net, loss, optimizer, device, num_epochs)# 定义预测函数
# 本函数已保存在d2lzh_pytorch包中方便以后使用
def predict_sentiment(net, vocab, sentence):"""sentence是词语的列表"""device = list(net.parameters())[0].devicesentence = torch.tensor([vocab.stoi[word] for word in sentence], device=device)# a = net(sentence.view((1, -1)))'''通过debug可以发现,通过这个网络计算出来的标签估计值,其实是没有经过归一化的并且会出现某个概率为负数的情况'''label = torch.argmax(net(sentence.view((1, -1))), dim=1)return 'positive' if label.item() == 1 else 'negative'predict1 = predict_sentiment(net, vocab, ['this', 'movie', 'is', 'so', 'great']) # positive
print(predict1)predict2 = predict_sentiment(net, vocab, ['this', 'movie', 'is', 'so', 'bad'])     # negative
print(predict2)predict3 = predict_sentiment(net, vocab, ['As','far','as','I','am','consider','this', 'movie', 'is', 'not', 'bad'])     # negative
print(predict3)
'''
通过自己尝试的例子可以发现,这个算法并没有那么智能
'''
print("*" * 50)

《动手学深度学习》(PyTorch版)代码注释 - 54 【Text_sentiment_classification(RNN)】相关推荐

  1. 伯禹公益AI《动手学深度学习PyTorch版》Task 04 学习笔记

    伯禹公益AI<动手学深度学习PyTorch版>Task 04 学习笔记 Task 04:机器翻译及相关技术:注意力机制与Seq2seq模型:Transformer 微信昵称:WarmIce ...

  2. 伯禹公益AI《动手学深度学习PyTorch版》Task 07 学习笔记

    伯禹公益AI<动手学深度学习PyTorch版>Task 07 学习笔记 Task 07:优化算法进阶:word2vec:词嵌入进阶 微信昵称:WarmIce 优化算法进阶 emmmm,讲实 ...

  3. 伯禹公益AI《动手学深度学习PyTorch版》Task 03 学习笔记

    伯禹公益AI<动手学深度学习PyTorch版>Task 03 学习笔记 Task 03:过拟合.欠拟合及其解决方案:梯度消失.梯度爆炸:循环神经网络进阶 微信昵称:WarmIce 过拟合. ...

  4. 【动手学深度学习PyTorch版】6 权重衰退

    上一篇移步[动手学深度学习PyTorch版]5 模型选择 + 过拟合和欠拟合_水w的博客-CSDN博客 目录 一.权重衰退 1.1 权重衰退 weight decay:处理过拟合的最常见方法(L2_p ...

  5. 【动手学深度学习PyTorch版】12 卷积层

    上一篇移步[动手学深度学习PyTorch版]11 使用GPU_水w的博客-CSDN博客 目录 一.卷积层 1.1从全连接到卷积 ◼ 回顾单隐藏层MLP ◼ Waldo在哪里? ◼ 原则1-平移不变性 ...

  6. 【动手学深度学习PyTorch版】27 数据增强

    上一篇请移步[动手学深度学习PyTorch版]23 深度学习硬件CPU 和 GPU_水w的博客-CSDN博客 目录 一.数据增强 1.1 数据增强(主要是关于图像增强) ◼ CES上的真实的故事 ◼ ...

  7. 【动手学深度学习PyTorch版】13 卷积层的填充和步幅

    上一篇移步[动手学深度学习PyTorch版]12 卷积层_水w的博客-CSDN博客 目录 一.卷积层的填充和步幅 1.1 填充 1.2 步幅 1.3 总结 二.代码实现填充和步幅(使用框架) 一.卷积 ...

  8. 【动手学深度学习PyTorch版】23 深度学习硬件CPU 和 GPU

    上一篇请移步[动手学深度学习PyTorch版]22续 ResNet为什么能训练出1000层的模型_水w的博客-CSDN博客 目录 一.深度学习硬件CPU 和 GPU 1.1 深度学习硬件 ◼ 计算机构 ...

  9. 【动手学深度学习PyTorch版】15 池化层

    上一篇请移步[动手学深度学习PyTorch版]14 卷积层里的多输入多输出通道_水w的博客-CSDN博客 目录 一.池化层 1.1 池化层 ◼池化层原因 ◼ 二维最大池化 1.2 填充.步幅与多个通道 ...

  10. 伯禹公益AI《动手学深度学习PyTorch版》Task 05 学习笔记

    伯禹公益AI<动手学深度学习PyTorch版>Task 05 学习笔记 Task 05:卷积神经网络基础:LeNet:卷积神经网络进阶 微信昵称:WarmIce 昨天打了一天的<大革 ...

最新文章

  1. 信息系统项目管理师:第9章:项目人力资源管理-章节重点
  2. STM32开发 -- YModem详解
  3. 做为产品经理如何判断一个创业项目是否靠谱?
  4. Postman调用阿里云HTTPS动态注册接口(一型一密)
  5. MySQL中的读锁和写锁
  6. websocket底层处理粘包_Socket解决粘包问题1
  7. Qt工作笔记-pro文件中QMAKE_POST_LINK的使用
  8. jersey tomcat MySQL_使用 Jersey 和 Apache Tomcat 7 构建 JAX-RS 环境
  9. gitHub上传项目
  10. Java字符串截取(substring)
  11. 可变对象 vs 不可变对象(Python)
  12. BOM 定时器+回调函数
  13. 华为RH2288 V3安装 linux 龙蜥anolis系统安装
  14. 中国皇帝顺序(全)---
  15. 进制转换——36进制
  16. idea 2020.3更新后如何实现run parallel
  17. MySQL系列——MySQL实现序列(Sequence)效果
  18. 3dsmax-拓扑插件Wrapit使用
  19. 区块链进化论:极客与开源 - 区块链大航海时代
  20. 互联网日报 | 7月1日 星期四 | 滴滴正式登陆纽交所;奈雪的茶上市首日破发;2021年铁路暑运今日正式启动...

热门文章

  1. oracle.exe占用cpu太高,360tray.exe占用CPU过高,怎么办
  2. 用Python来合并图片(SoEasy)
  3. 5款伊思儷超媒體繁体游戏 简体中文补丁
  4. 东北大学oj平台python答案_你觉得东北大学的Python考试怎么样?
  5. 2021年登高架设免费试题及登高架设找解析
  6. nginx压缩静态文件
  7. 第29章基于锁的并发数据结构
  8. java apm_APM 追踪 Java 应用性能
  9. 手机中的劳力士:HTC是执迷不悟还是不悔?
  10. 钢铁侠java_现代版“钢铁侠”,无所不能的程序员,java工程师实现人造器官!...