python-pytorch seq2seq+attention笔记1.0.0
- 1. LSTM模型的数据size
- 2. 关于LSTM的输入数据包含hn和cn时,hn和cn的size
- 3. LSTM参数中默认batch_first
- 4. Attention机制的三种算法
- 5. 模型的编码器
- 6. 模型的解码器
- 7. 最终模型
- 8. 数据的准备
- 9. 遇到的问题
- 10. 完整代码
- 11. 参考链接
记录
- 2024年5月14日09:27:39----0.5.10
- 2024年5月14日11:32:47----0.5.12
- 2024年5月14日11:51:03----1.0.0
1. LSTM模型的数据size
一定是按这个来:维度(batch_size, seq_length, embedding_dim) 是一个三维的tensor;其中,batch_size指每次输入的文本数量;seq_length指每个文本的词语数或者单字数;embedding_dim指每个词语或者每个字的向量长度。
2. 关于LSTM的输入数据包含hn和cn时,hn和cn的size
LSTM的输入数据是上个时间窗的hn和cn时,hn和cn的size要求一定是和LSTM模型参数吻合。公式是(laynum,batchsize,hidden or embeding size)或者(batchsize,hidden or embeding size)。
3. LSTM参数中默认batch_first
其实改变的是模型的hn和cn的size,不改变output的size。因为,cn和hn的size是和batch_size有关系的,是layernum、batch_size、hidden_size
4. Attention机制的三种算法
dot 、general、concat三种,常见使用general算法。
general大概思路是:
计算分数:decoder中LSTM的output和encoder的output做bmm计算
计算权重:将计算出来的分数做softmax,得到行上的概率分布或者权重
计算新向量:将权重和encoder的outpu再做bmm计算
拼接decoder的output和新向量
对新的拼接结果做tanh计算
最后全连接到vocab_size
concat算法思路是:
tang计算:encoder的hn和输出encoder_output相加
计算分数:对相加做tanh计算得到对其分数
计算权重:对其分数做行上做softmax计算得到权重
计算新向量:权重和encoder_output做bmm计算得到新向量
拼接decoder输入的ebeded和新向量作为decoder中LSTM或者GRU的输入
最后返回LSTM或者GRU等的out
5. 模型的编码器
思路很简单,就是将word2index后,通过embedding,将数据给LSTM模型就可以了,返回的是 LSTM的output、hn、cn。
当前你可以根据自己的习惯,在使用LSTM时候增加参数batch_fist或者bidirectional。
此时inputx的是word2index后的数据。
class encoder(nn.Module):def __init__(self):super(encoder, self).__init__()self.embedding=nn.Embedding(vocab_size,n_hidden)self.lstm=nn.LSTM(n_hidden,n_hidden*2,batch_first=False)def forward(self, inputx):embeded=self.embedding(inputx.long())output,(encoder_h_n, encoder_c_n)=self.lstm(embeded.permute(1,0,2))return output,(encoder_h_n,encoder_c_n)
6. 模型的解码器
将解码器的输入embedding后,加上编码器的outout、hn、cn,给LSTM模型输出ouput、hn、cn,做general的attention,最终返回新的LSTM的output、hn、cn。
class lstm_decoder(nn.Module):def __init__(self):super(lstm_decoder, self).__init__()self.embedding=nn.Embedding(vocab_size,embedding_size)self.decoder = nn.LSTM(embedding_size, n_hidden * 2, 1,batch_first=False)self.fc = nn.Linear(n_hidden * 2, num_classes)def forward(self, input_x, encoder_output, hn, cn):embeded=self.embedding(input_x)decoder_output, (decoder_h_n, decoder_c_n) = self.decoder(embeded.float().permute(1,0,2), (hn, cn))decoder_output = decoder_output.permute(1, 0, 2)encoder_output = encoder_output.permute(1, 0, 2)# 下面是实现attention编码# 计算分数scoredecoder_output_score = decoder_output.bmm(encoder_output.permute(0,2,1))# 计算权重atat = nn.functional.softmax(decoder_output_score, dim=2)# 计算新的context向量ctct = at.bmm(encoder_output)# 拼接ct和decoder_htht_joint = torch.cat((ct, decoder_output), dim=2)fc_joint = torch.tanh(self.att_joint(ht_joint))# 实现attention编码结束fc_out = self.fc(fc_joint)return fc_out, decoder_h_n, decoder_c_n
7. 最终模型
在训练时候,encoder的output、hn、cn作为decoder的的输入一部分。最终模型的输出和target数据(view(-1