Seq2seq and Attention
Learn from these blog:
- Sequence to Sequence (seq2seq) and Attention
- H_M. Seq2seq and attention - Pytorch Implementation - EN
Seq2seq
1 什么是Seq2seq
Seq2seq,全称为sequence to sequence
,即序列到序列,是序列到序列任务的统称。
序列到序列任务,简单地说,有2种具有某种对应关系的相互对应的序列,一个序列根绝这种对应关系得到与之对应的另一个序列的任务就是Seq2seq
任务。
例如,最典型的Seq2seq任务:翻译任务,以中英翻译为例-中文句子和与其含义相同的英文句子相互对应,一个中文句子根据中英文语言之间的对应关系,得到与之对应的含义相同的英文句子。
序列到序列任务可以理解为,一种用来学习2种序列之间对应关系,以实现从一种序列转换到对应的另一种序列的任务。
翻译任务中,实际上学习的对应关系是一种语言与另一种语言之间的映射关系。
序列到序列任务中的2种序列可以是任何2种具有某种映射关系的序列,这个任务主要解决的问题就是得到2种序列之间的映射关系。
2 Seq2seq基础-如何思考用机器解决seq2seq任务
以翻译任务为例。
形式上,该任务有一个输入序列$ x_1, x_2, ..., x_m $,和一个对应的输出序列$ y_1, y_2, ..., y_n $,而该任务是要根据输入序列,找到最有可能的与之对应的目标序列。
因此,形式上目标序列就是最大化条件概率:
为什么是概率形式:理解为与输入序列对应的序列有很多,即是不确定的,目标序列在形式上是其中概率最大的。简单的理解就是输入序列与输出序列之间不是一种一一对应、唯一确定的关系。
人类做的翻译任务,就是根据$ x $,翻译出最可能的$ y $,就对应于该公式:
机器做该翻译任务,是根据$ x $,和经过训练得到的针对翻译任务的模型的参数集合$ \theta $,翻译出最可能的$ y $,对应于该公式:
$ \theta $理解为训练后的能做翻译任务的模型。
由此可得,为了定义一个机器翻译系统,我们需要回答以下3个问题:
- 建模modeling:$ p(y|x, \theta) $的模型是什么样的?
回答该问题等同于设计出一个能做该任务的模型,$ \theta $为该模型种带的参数。 - 学习learning:如何找到$ \theta $?
回答该问题等同于设计出该模型对应的损失函数。
模型根据损失函数训练,使得自己从一个能做该任务进化到会做该任务。 - 推理inference:如何找到最好的y?
由于模型输出的是$ p(y|x, \theta) $,回答该问题等同于设计一个策略根据模型的输出得到目标序列,即。
回答了以上三个问题,一个机器翻译系统就定义好了。
由此也可以看到,模型往往是一个系统中的一大部分,并不等同于一个系统,往往还有推理(可以理解为对模型输出的解码)这么个部分。
3 Seq2seq基础-Seq2seq的典型模型框架:Encoder-Decoder框架
Encoder-decoder
是seq2seq
任务的标准建模范式。这个框架由两部分组成:
- Encoder: 接收source序列,并且生成对应的表示。
- Decoder: 使用source表示,生成target序列。
4 Seq2seq基础-Seq2seq的模型:条件语言模型
回答$ p(y|x, \theta) $是什么样的模型,对应建模问题。
语言模型是估计tokens序列$ y = (y_1, y_2, ..., y_n) $的概率$ p(y) $,是序列$ y $的无条件概率。
语言模型可以理解为做的任务是在没有任何条件下得到序列$ y $。
Seq2seq模型是在给定条件序列$ x $下,估计序列$ y $的概率$ p(y|x) $,换句话说序列$ y $是基于序列& x &得到的,因此是序列$ y $的条件概率。
Seq2seq模型类似于语言模型,只是多了一个给定条件:序列$ x $。
因此根据语言模型,seq2seq任务可以被建模为条件语言模型:
注意,条件语言建模不仅可以用来解决seq2seq任务,一般来说,条件语言建模中的$ x $可以是tokens序列外的其他东西。例如,在图像字幕捕获任务中,$ x $就是一个图像,而$ y $是该图像的描述。
条件语言模型与语言模型唯一的区别是$ x $的存在,因此条件语言建模和训练与语言模型类似,具体地:
- 将source和之前生成的tokens喂入网络;
- 通过decoder得到对应的上下文向量表示;
- 根据该表示,预测下一个token的概率分布。
通常以一种简单的方式根据一个向量表示来得到一个token的概率分布:用一个线性层后接softmax作为分类部分。
- 线性层用于将$ d $维向量表示转换为对应于token预测的$ |V| $维的向量表示;
- softmax操作用于将表示预测的向量表示中的标量转换为概率值,即一个向量的每个维度的值都为0到1之间的值,并且所有维度的值之和为1。
5 最简单的模型:2个RNNs分别作为Encoder和Decoder
Encoder RNN接收source,整个Encoder RNN的最后一个(隐层)状态作为source的表示,用于初始化Decoder RNN。
这个模型有不同的改进版,例如,encoder和decoder可以有好几层,不同层学习到的信息不同,这样学习到的表示包含的信息更丰富。
6 训练:交叉熵损失
类似于语言模型,seq2seq模型是训练来根据之前的预测tokens和给定的$ x $,来预测下一个token。
因此,训练就要使模型在预测每个token,即在每一步,最大化其分配给正确token的概率(最大概率为1)。
损失函数推理过程如下:
7 推理:贪婪解码Greedy Decoding和束搜索Beam Search
到目前为止,已经有了一个能做好根据序列$ x $预测可能的(即还无法完全确定为一个的)对应序列$ y $的模型,即模型能够完成$ p(y|x, \theta) $,但目标是得到与$ x $最匹配的那个$ y $。因此,该部分对应实现
需要注意的是,条件概率公式的计算:$ P(A|B) = P(AB)P(B) $,也就是说:
模型能做的是预测每一步所有可能的tokens的概率,要确定目标$ y^' $就要从$ |V|^n $个可能中确定,在实际中是不可行的。因此,只能确定一个近似解。
根据模型的特定:只能预测每一步所有可能的tokens的概率,有两种确定近似解的策略:
- 贪婪解码:每一步选择概率最大的token。
这是最直接和简单的方式,它可能是很好的一个基线,但存在一个问题:当前步最可能的token不一定是那个组成到当前步为止的最可能的序列的token,即 - 束搜索:追踪几个最可能的假设。
贪婪解码是按照贪婪策略直接确定一个假设为目标$ y^' $。
而束搜索是每一步在当前假设的基础上,保留几个最可能的假设,如图,通常beam size设置为4到10,beam size越大,计算效率越低,并且往往句子质量也会越差。
Attention
1 引入注意力的原因:固定的Encoder表示
Encoder产生的固定的source表示是次优的(suboptimal):
- 对于encoder,将source的所有信息压缩为一个向量,一定程度上限制了source的长度。
因为,如果source太长,encoder将所有信息压缩为一个向量,很可能会“忘掉”某些信息。 - 对于decoder,生成token的每一步都是基于表示source的相同不变的表示,一定程度上限制了decoder生成token的性能。
因为,生成token的每步与source中相关联的信息部分可能是不同的,每个生成步对应不同的source表示或许更有用。
2 注意力机制
注意力机制是神经网络的一部分,它能够使decoder中的每个生成步得到包含与自己最相关信息的代表source的表示。
换句话说,注意力机制使得encoder不再将source所有信息压缩为一个向量给所有decoder的生成步使用,而是encode出source中每个token的表示。
根据注意力机制的作用,decoder中每个生成步都有一个与之对应的source表示,因此每个生成步对应的source表示的生成需要每个生成步自己的信息与source中所有信息参与,这样每个生成步才能得到包含与自己最相关的信息的source表示,这也称为每个生成步的attention。
decoder每个生成步对应的attention的计算步骤:
attention的大体计算策略如下:
3 注意力分数的计算方式
注意力分数是计算attention的其中一个步骤,其计算方式并不是固定的,理论上可以应用任何你想用的函数来计算。
通常都会应用以下三种流行的、表现较好的计算注意力分数的方式:
- 点乘:最简单的方式,公式如下:
- 双线性函数:用在
Luong attention
中,公式如下: - 多层感知机:用在
Bahdanau attention
中,公式如下:
双线性函数代码实现体现为:decoder的表示通过一个线性层引入一个权重矩阵,后再与encoder表示点乘。
多层感知机代码实现体现为:decoder的表示与encoder的表示求和,通过一个线性层引入一个权重矩阵,再套上tanh,最后再与一个权重矩阵点乘。
4 注意力机制模型:Bahdanau和Luong
1) Bahdanau Model (or Bahdanau Attention)
- encoder: 双向RNN,前向和后向
source中每个token经过encoder后的表示等于对应前向和后向状态的拼接。 - attention score(注意力分数的计算方式): 多层感知机。
这里给出这种注意力分数的计算方式和示意图,与前面略有不同的是,这里代表decoder每步的表示与代表encoder各token的表示,有各自的线性层即各自的可训练权重,前面展示的是共有一个,但本质方式相同。 attention的应用: 用于decoder每2步之间
对于decoder的第t步,首先用前一步生成的$ h_{t-1} $与encoder的各token表示生成attention,然后将$ h_{t-1} $、上一步生成的output及由$ h_{t-1} $生成的attention用于第t步token的生成,具体地:- $ h_{t-1} $作为输入到第t步的上一层的隐层状态;
- attention和output拼接作为第t步的输入。
2) Luong Model (or Luong Attention)
- encoder: 单向RNN
- attention score(注意力分数的计算方式): 双线性函数
在原文中展示了前面提到的3种注意力分数的计算方式,其对应公式和代码分别如下: - attention的应用:用在decoder每步生成状态t和预测这步的output之间。
对于decoder的第t步,首先利用上一步的$ h_{t-1} $和上一步的output得到当前步对应的$ h_t $,再将$ h_t $与encoder各token表示生成对应的attention,再将attention与$ h_t $进行拼接预测这一步的output,最后将这一步的$ h_t $和output传给下一步。
Transformer
Transformer是seq2seq任务建模的新范式:之前的模型在encoder和decoder中的处理是通过循环或卷积网络完成的,Transformer仅使用了注意力机制。
Transformer的形象描述:
在之前,要理解(得到对应表示)source中的一个token,必须先理解完这个token之前的所有token。这就对应之前的RNN Encoder工作的机制。
而在Transformer中的Encoder中,所有token都是同时与其他所有token交互。
并且Transformer的Decoder中,所有token也都是与之前token交互并与encoder的各token交互。
其他关于更多Transformer细节,查阅原blog:Sequence to Sequence (seq2seq) and Attention