🐬序列到序列学习 seq2seq
2021-12-4
| 2023-8-7
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property

 
机器翻译中的输入序列和输出序列都是长度可变的。 为了解决这类问题,设计了一个通用的”编码器-解码器“架构。 这里将使用两个循环神经网络的编码器和解码器, 并将其应用于序列到序列(sequence to sequence,seq2seq)类的学习任务。
遵循编码器-解码器架构的设计原则, 循环神经网络编码器使用长度可变的序列作为输入, 将其转换为固定形状的隐状态。 换言之,输入序列的信息被编码到循环神经网络编码器的隐状态中。 为了连续生成输出序列的词元, 独立的循环神经网络解码器是基于输入序列的编码信息和输出序列已经看见的或者生成的词元来预测下一个词元。
 
下图演示了如何在机器翻译中使用两个循环神经网络进行序列到序列学习:
notion image
特定的“<eos>”表示序列结束词元。 一旦输出序列生成此词元,模型就会停止预测。 在循环神经网络解码器的初始化时间步,有两个特定的设计决定: 首先,特定的“<bos>”表示序列开始词元,它是解码器的输入序列的第一个词元。 其次,使用循环神经网络编码器最终的隐状态来初始化解码器的隐状态。 例如,在[Sutskever et al., 2014]的设计中, 正是基于这种设计将输入序列的编码信息送入到解码器中来生成输出序列的。 在其他一些设计中[Cho et al., 2014b], 如图所示, 编码器最终的隐状态在每一个时间步都作为解码器的输入序列的一部分。类似于语言模型的训练,可以允许标签成为原始的输出序列,从源序列词元“<bos>”、“Ils”、“regardent”、“.” 到新序列词元 “Ils”、“regardent”、“.”、“<eos>”来移动预测的位置。
notion image

编码器

从技术上讲,编码器将长度可变的输入序列转换成 形状固定的上下文变量, 并且将输入序列的信息在该上下文变量中进行编码,可以使用循环神经网络来设计编码器。
考虑由一个序列组成的样本(批量大小是 )。 假设输入序列是 , 其中 是输入文本序列中的第 个词元。 在时间步,循环神经网络将词元 的输入特征向量(即上一时间步的隐状态) 转换为(即当前步的隐状态)。 使用一个函数来描述循环神经网络的循环层所做的变换:
总之,编码器通过选定的函数, 将所有时间步的隐状态转换为上下文变量:
比如,当选择 时, 上下文变量仅仅是输入序列在最后时间步的隐状态
到目前为止,使用的是一个单向循环神经网络来设计编码器, 其中隐状态只依赖于输入子序列, 这个子序列是由输入序列的开始位置到隐状态所在的时间步的位置 (包括隐状态所在的时间步)组成。
也可以使用双向循环神经网络构造编码器, 其中隐状态依赖于两个输入子序列, 两个子序列是由隐状态所在的时间步的位置之前的序列和之后的序列 (包括隐状态所在的时间步), 因此隐状态对整个序列的信息都进行了编码。
 
实现循环神经网络编码器:
使用嵌入层embedding layer 来获得输入序列中每个词元的特征向量。嵌入层的权重是一个矩阵, 行数等于输入词表的大小vocab_size, 列数等于特征向量的维度embed_size。 对于任意输入词元的索引 , 嵌入层获取权重矩阵的第 行(从 开始)以返回其特征向量。
这里选择了一个多层门控循环单元来实现编码器。
实例化上述编码器的实现: 使用一个两层门控循环单元编码器,其隐藏单元数为。 给定一小批量的输入序列X(批量大小为 ,时间步为 )。 在完成所有时间步后, 最后一层的隐状态的输出是一个张量(output由编码器的循环层返回), 其形状为(时间步数,批量大小,隐藏单元数)
由于这里使用的是门控循环单元, 所以在最后一个时间步的多层隐状态的形状是 (隐藏层的数量,批量大小,隐藏单元的数量)。 如果使用长短期记忆网络,state中还将包含记忆单元信息
 

解码器

正如上文提到的,编码器输出的上下文变量 对整个输入序列 进行编码。 来自训练数据集的输出序列 , 对于每个时间步 (与输入序列或编码器的时间步 不同), 解码器输出 的概率取决于先前的输出子序列 和上下文变量 , 即
为了在序列上模型化这种条件概率, 可以使用另一个循环神经网络作为解码器。 在输出序列上的任意时间步 , 循环神经网络将来自上一时间步的输出 和上下文变量 作为其输入, 然后在当前时间步将它们和上一隐状态 转换为 隐状态 。 因此,可以使用函数 来表示解码器的隐藏层的变换:
在获得解码器的隐状态之后, 可以使用输出层和softmax操作来计算在时间步 时输出 的条件概率分布
当实现解码器时, 直接使用编码器最后一个时间步的隐状态来初始化解码器的隐状态。 这就要求使用循环神经网络实现的编码器和解码器具有相同数量的层和隐藏单元。 为了进一步包含经过编码的输入序列的信息, 上下文变量在所有的时间步与解码器的输入进行拼接(concatenate)。 为了预测输出词元的概率分布, 在循环神经网络解码器的最后一层使用全连接层来变换隐状态。
下面用与前面提到的编码器中相同的超参数来实例化解码器,解码器的输出形状变为(批量大小,时间步数,词表大小), 其中张量的最后一个维度存储预测的词元分布。
总之,上述循环神经网络“编码器-解码器”模型中的各层如图所示。
notion image
 
 

损失函数

在每个时间步,解码器预测了输出词元的概率分布。 类似于语言模型,可以使用softmax来获得分布, 并通过计算交叉熵损失函数来进行优化。特定的填充词元被添加到序列的末尾, 因此不同长度的序列可以以相同形状的小批量加载。 但是,应该将填充词元的预测排除在损失函数的计算之外
为此,可以使用下面的sequence_mask函数 通过零值化屏蔽不相关的项, 以便后面任何不相关预测的计算都是与零的乘积,结果都等于零。 例如,如果两个序列的有效长度(不包括填充词元)分别为 , 则第一个序列的第一项和第二个序列的前两项之后的剩余项将被清除为零。
 
还可以使用此函数屏蔽最后几个轴上的所有项。如果愿意,也可以使用指定的非零值来替换这些项
现在可以通过扩展softmax交叉熵损失函数来遮蔽不相关的预测。 最初,所有预测词元的掩码都设置为1。 一旦给定了有效长度,与填充词元对应的掩码将被设置为0。 最后,将所有词元的损失乘以掩码,以过滤掉损失中填充词元产生的不相关预测
可以创建三个相同的序列来进行代码健全性检查, 然后分别指定这些序列的有效长度为4、2和0。 结果就是,第一个序列的损失应为第二个序列的两倍,而第三个序列的损失应为零
 

训练

在下面的循环训练过程中, 特定的序列开始词元(“<bos>”)和 原始的输出序列(不包括序列结束词元“<eos>”) 拼接在一起作为解码器的输入。 这被称为强制教学(teacher forcing), 因为原始的输出序列(词元的标签)被送入解码器。 或者,将来自上一个时间步的预测得到的词元作为解码器的当前输入。
现在,在机器翻译数据集上,可以创建和训练一个循环神经网络“编码器-解码器”模型用于序列到序列的学习。
 
notion image
 

预测

为了采用一个接着一个词元的方式预测输出序列, 每个解码器当前时间步的输入都将来自于前一时间步的预测词元。 与训练类似,序列开始词元(“<bos>”) 在初始时间步被输入到解码器中。 该预测过程如图所示, 当输出序列的预测遇到序列结束词元(“<eos>”)时,预测就结束了。
notion image
 

预测序列的评估

可以通过与真实的标签序列进行比较来评估预测序列。 虽然[Papineni et al., 2002]提出的BLEU(bilingual evaluation understudy) 最先是用于评估机器翻译的结果, 但现在它已经被广泛用于测量许多应用的输出序列的质量。 原则上说,对于预测序列中的任意元语法(n-grams), BLEU的评估都是这个元语法是否出现在标签序列中。
将BLEU定义为:
其中 示标签序列中的词元数和表示预测序列中的词元数, 是用于匹配的最长的 元语法。 另外,用 表示 元语法的精确度,它是两个数量的比值: 第一个是预测序列与标签序列中匹配的 元语法的数量, 第二个是预测序列中 元语法的数量的比率。 具体地说,给定标签序列 和预测序列 , 有
根据BLEU的定义, 当预测序列与标签序列完全相同时,BLEU。 此外,由于 元语法越长则匹配难度越大, 所以BLEU为更长的 元语法的精确度分配更大的权重。 具体来说,当 固定时, 会随着 的增长而增加(原始论文用 )。 而且,由于预测的序列越短获得的 值越高, 所以乘法项之前的系数用于惩罚较短的预测序列。 例如,当 时,给定标签序列 和预测序列 ,尽管 , 惩罚因子 会降低BLEU。
 
利用训练好的循环神经网络“编码器-解码器”模型, 将几个英语句子翻译成法语,并计算BLEU的最终结果
 

代码

 
 
 
 
 
 
 
 
 
  • PyTorch
  • 编码器-解码器架构束搜索
    目录