先从我的理解概括Attention机制:在面对一句话时,人们一般不会整句都看完再去理解其意义(如果这个句子较长)。在seq2seq模型中,一整个句子当作输入会给网络带来困扰,并且很有可能丢失序列中靠前的信息。而在decoder模型的输入时,我们同样利用context替换原本的输入。context则是利用这句话学习得到的权重乘以这句话,得到一个新的context。将contex与这句话相拼接,输入网络中。这样做使得seq2seq的效果大大提升。因为输入不仅包含了原本的输入序列,还利用context让网络只注意这句话中的某几个单词,而不是整个句子。最关键的利用编码器(encoder)的信息得到contex替换掉原来的输入,让网络只关心某几个单词。下面开始详细介绍,部分图选自网络,如有侵权,请联系我。
先介绍encoer_decoder架构。seq2seq 就是一个Encoder–Decoder 结构的网络。它的输入是一个序列,通过GRU或者LSTM网络得到一个向量,即encoder_output。这个encoder_output实际上代表了输入序列的信息。输出也是一个序列,通过decoder网络(GRU或者LSTM网)将encoder_output作为输入,得到一个序列。
Encoder 中将一个可变长度的信号序列变为固定长度的向量表达,Decoder 将这个固定长度的向量变成可变长度的目标的信号序列。--简书
模型框架:
假设一下这个输入序列是中文,输出序列是英文。
一般来说,这个是encoder网络采用GRU或者LSTM。以GRU举例,如果输入的维度是[seq_len, batch],那么就得到了[seq_len, batch, hidden_size]的encoder_output。pack_padded_sequence解释在这里:https://mp.youkuaiyun.com/postedit/102626466。
Encoder代码如下(采用pytorch):
import torch
import torch.nn as nn
import torch.nn.functional as F
class Encoder(nn.Module):
def __init__(self, input_size, hidden_size, n_layer=1, drop_out=0):
# input_size是指单词数量,hidden_size为gru的hidden的feature
super(Encoder, self).__init__()
self.hidden_size = hidden_size
self.embeddding = nn.Embedding(input_size, self.hidden_size)
self.gru = nn.GRU(self.hidden_size, self.hidden_size, bidirectional=True,
num_layers=n_layer, dropout=(0 if n_layer == 1 else drop_out))
def forward(self, input_seq