pytorch教程 聊天机器人(详细注释&attention&rnn输入输出shape等知识点...
最近可能要用到seq2seq模型去解决一些轨迹预测的问题,拿pytorch教程的聊天机器人练了练手。原文中教程已经写的比较详尽了,在此对原文教程进行一些补充说明,可能更加方便向我这样的小白入门学习。本文是对教程的补充说明,并没有照搬所有教程中的代码,中文教程写的很不错啦,链接在下面。pytorch中文教程:http://www.pytorch123.com/FifthSection/Chatbot
最近可能要用到seq2seq模型去解决一些轨迹预测的问题,拿pytorch教程的聊天机器人练了练手。
原文中教程已经写的比较详尽了,在此对原文教程进行一些补充说明,可能更加方便向我这样的小白入门学习。
本文是对教程的补充说明,并没有照搬所有教程中的代码,中文教程写的很不错啦,链接在下面。
pytorch中文教程:http://www.pytorch123.com/FifthSection/Chatbot/
我的git地址:https://github.com/jamjar102/pytorch_chatbot_2 这里面代码写了一些注释方便像我这样的小白follow作者的思想,并且带有数据集
数据集:我给一个网盘吧,不方便科学学习的小伙伴可以快速下载:
链接:https://pan.baidu.com/s/1XWESTyoPYv_0j-gk21Skpg
提取码:f8r6
(觉得百度云更慢的可以按照教程提供的地址下载
一)在教程->2.2 加载和清洗数据中
这块调用了normalizeString()函数,这个函数其实并不是库函数,但是原文中并没有提供
需要自己实现一下,代码如下:
import re
def normalizeString(string):
string=re.sub("([?,;.!<>])",repl=r" \1",string=string)
string=re.sub("[^a-zA-Z.?!]+",repl=" ",string=string)
string=re.sub("\s+",repl=' ',string=string)
return string.strip()
这个函数主要是进行大小写转换,去除非法字符的,就是normalize一下
二) 在教程->3.为模型准备数据中
在outputVar()函数中,声明的mask变量应该转成bool型,教程中写的是mask=torch.ByteTensor(mask),如果这么写会报warning,(在pycharm中运行训练时间大幅增长):
received a mask with dtype torch.uint8, this behavior is now deprecated,please use a mask with dtype torch.bool instead.
代码修改成如下即可:
def outputVar(l, voc):
indexes_batch = [indexesFromSentence(voc, sentence) for sentence in l]
max_target_len = max([len(indexes) for indexes in indexes_batch])
padList = zeroPadding(indexes_batch)
mask = binaryMatrix(padList)
mask = torch.BoolTensor(mask)
padVar = torch.LongTensor(padList)
return padVar, mask, max_target_len
三)GRU 组件输入输出shape
在CNN中,batch的position=0,RNN中position=1
输入数据input的shape为(sentence_max_length,batch_size,1)其中1的含义是:由于每个词都是做了word2index,所以在准备数据的时候这块的维度就是1
在model encoderRNN定义中,forward前向函数中,进行了如下操作
embedded = self.embedding(input_seq)
此时shape变成了,(sentence_max_length,batch_size,hidden_size), 因为原文中作者设定了embedding后的维度为hidden_size
RNN的输出OUT的shape =(max_length,batch_size,hidden_size * num_directions) 这块原文写错了,最后一项的维度应该是hidden_size * num_directions
由于在encoder中,定义的RNN是bidirectional的,所以第三维由两个GRU的隐层输出拼接而成。[:hidden_size]为正向的隐层输出,[hidden_size:]为反向的隐层输出
def forward(self, input_seq, input_lengths, hidden=None):
# 将单词索引转换为词向量
embedded = self.embedding(input_seq) #embedding
# 为RNN模块打包填充batch序列
packed = nn.utils.rnn.pack_padded_sequence(embedded, input_lengths) # todo batch 需要进行pack_padded_sequence 和 nn.utils.rnn.pad_packed_sequence
# 正向通过GRU
outputs, hidden = self.gru(packed, hidden)
# 打开填充
outputs, _ = nn.utils.rnn.pad_packed_sequence(outputs)
# 总和双向GRU输出
outputs = outputs[:, :, :self.hidden_size] + outputs[:, : ,self.hidden_size:] # todo 双向RNN,output 维度为[seq_len, batch, hidden_size*bidirectional]
# 返回输出和最终隐藏状态 todo 对位相加(把双向的同一个位置的两个GRU单元hidden输出 相加)
return outputs, hidden
RNN的隐层输出的shape=(n_layers x num_directions,batch_size,hidden_size)
隐层输出就是最后GRU单元的hidden输出,所以只和RNN模型的层数、方向 ,batch_size,以及一个hidden的位数有关
四)Luong attention机制
快速了解attention机制看这个视频可以,https://blog.csdn.net/qq_43409114/article/details/105889114 ,随手b站上找了一个视频,看了看可以讲清楚
简而言之就是如果不使用attention 机制,decoder的 input会吃encoder最后的hidden输出,如果只用这一个输出表示前面所有信息,想想就很不靠谱
所以采用了attention机制,decoder的一个GRU单元的hidden输出会和前面encoder的每一个hidden输出进行运算,得到权重,从而找到“更应该关注的那个词”
利用这个attention权重和docoder这个GRU单元的hidden输出共同作用得到target词汇
关于BahdanauAttention和Luong attention机制可以看这篇 https://blog.csdn.net/qq_43409114/article/details/105889114
对论文的解读还是写的十分清楚的
五)train函数中有个小bug,decoder前面+self.即可
虽然我跟我机器人对话过程十分尴尬
但是最起码可以跑了嘛
能跑就行 能跑就行,哈哈哈哈哈哈
如果有什么问题困扰你,请留言,让那个问题来困扰我们所有人
如果本文中有什么写错的地方,欢迎各位指正

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)