预训练模型的概念在计算机视觉领域并不陌生, 通常我们可以在大规模图像数据集上预先训练出一个通用 模型, 之后再迁移到类似的具体任务上去, 这样在减少对图像样本需求的同时, 也加速了模型的开发速度。计 算机视觉领域采用 ImageNet 对模型进行一次预选训练, 使得模型可以通过海量图像充分学习如何提取特征, 然 后再根据任务目标进行模型精调的范式影响, 自然语言处理领域基于预训练语言模型(Pre-trained Model,PLM ) 的方法也逐渐成为主流。 ImageNet 是一个计算机视觉系统识别项目, 是目前世界上图像识别最大的数据库, 这 个项目始于 CVPR2009。有趣的是, ImageNet 的层级结构, 是从上世纪 90 年代末开始的 WordNet 项目中派生而 来的,其实 NLP 和CV 两个领域一直在不断互相影响,互相促进。 同样, 预训练语言模型就是预训练方法在自然语言处理领域中的应用, 本质上是对自然语言的表示学习, 是 将自然语言转化为让机器可以处理的数据表达形式。预训练语言模型先通过大量的语料(通常是无标注的数据) 进行训练,得到一个通用的语言表征模型,然后再使用面向具体任务的少量语料,就可以完成下游任务的训练。
预训练语言模型的训练范式
以ELMo 为代表的动态词向量模型开启了语言模型预训练的大门,此后以 GPT 和 BERT 为代表的基于 Transformer 模型的大规模预训练语言模型的出现, 使得自然语言处理全面进入了预训练微调范式新时代。将预训练 模型应用于下游任务时, 不需要了解太多的任务细节, 不需要设计特定的神经网络结构, 只需要“微调”预训练 模型,使用具体任务的标注数据在预训练语言模型上进行监督训练,就可以取得显著的性能提升。
针对单词在文章中根据上下文有着不同语义的实际问题, 研究人员提出了“动态词向量”,也就是上下文相 关词向量。 2018 年 ELMo (Embeddings from Language Models) 提出通过首先预训练双向 LSTM 网络, 而不是学 习固定的单词表示,并进行参数微调来捕获上下文信息。 双向语言模型是从两个方向进行语言模型建模: 从左到右前向建模和从右到左后向建模。双向建模带来了 更好的上下文表示,文本中的每个词能同时利用其左右两侧文本的信息,如下图所示。 ELMo 也主要由三层结构组成, 输入层、隐藏层和输出层。其中, 输入层为了减少整词不在词表中的情况, 对输入文本进行了字符级别的编码。之后通过卷积神经网络对字符级的表示进行语义组合, 在每个位置的卷积 输出上使用池化层,再通过 Highway 网络进行进一步转化,得到输入层的. ELMo 使用了两个独立的编码器分别对前向和后向进行语言模型建模。通常认为, 模型低层能捕捉语法等 基础特征, 高层能捕捉语义语境等更深层次的语言特征, 双向的 LSTM 能保证在编码过程中每个位置都能获得该位置过去和未来位置的词信息.
ELMo 语言模型
2017 年 12 月 6 日, Google 发布了论文《Attention is all you need》 提出了 Attention 机制和基于此机制 的 Transformer 架构。该架构首先应用于机器翻译, 目标是从源语言(Source Language) 转换到目标语言(Target Language) 。这种架构的价值在于其是一种完全基于注意力机制的序列转换模型, 而不依赖 RNN 、CNN 或者 LSTM,Transformer 能够一次性知道所有输入, 利用注意力机制将距离不同的单词进行结合, 而不需要逐步递归 来获得全部信息。 Transformer 架构中包括编码器 Encoder 和解码器 Decoder,如下图
Transformer 模型架构
所示, 整个网络结构完全以 Attention 机制 以及前馈神经网络组成:
注意力层: 使用多头注意力(Multi-Head Attention) 机制整合上下文语义, 它使得序列中任意两个单词之 间的依赖关系可以直接被建模而不基于传统的循环结构, 从而更好地解决文本的长程依赖。 Attention 机制 从人类视觉注意力中获得灵感, 目标在于将注意力集中与所处理部分对应的语境信息, 实际实现中则是计 算每一个词与其他词的注意力权重系数。
位置感知前馈层(Position-wise FFN):通过全连接层对输入文本序列中的每个单词表示进行更复杂的变换。
残差连接: 对应图中的 Add 部分。它是一条分别作用在上述两个子层当中的直连通路, 被用于连接它们的 输入与输出。从而使得信息流动更加高效,有利于模型的优化。
层归一化: 对应图中的 Norm 部分。作用于上述两个子层的输出表示序列中, 对表示序列进行层归一化操 作,同样起到稳定优化的作用。
对于输入文本序列, 首先通过输入嵌入层(Input Embedding) 将每个单词转换为其相对应的向量表示。通常 直接对每个单词创建一个向量表示。由于 Transfomer 模型不再使用基于循环的方式建模文本输入, 序列中不再 有任何信息能够提示模型单词之间的相对位置关系。在送入编码器端建模其上下文语义之前, 一个非常重要的 操作是在词嵌入中加入位置编码(Positional Encoding) 这一特征。具体来说, 序列中每一个单词所在的位置都 对应一个向量。这一向量会与单词表示对应相加并送入到后续模块中做进一步处理。在训练的过程当中, 模型 会自动地学习到如何利用这部分位置信息。 为了得到不同位置对应的编码, Transformer 模型使用不同频率的正余弦函数如下所示:
其中, pos 表示单词所在的位置, 2i 和 2i+ 1 表示位置编码向量中的对应维度, d 则对应位置编码的总维度。通过上面这种方式计算位置编码有这样几个好处: 首先, 正余弦函数的范围是在 [- 1,+1],导出的位置编码与原词 嵌入相加不会使得结果偏离过远而破坏原有单词的语义信息。其次, 依据三角函数的基本性质, 可以得知第 pos + k 个位置的编码是第 pos 个位置的编码的线性组合,这就意味着位置编码中蕴含着单词之间的距离信息。 使用 Pytorch 实现的位置编码参考代码如下:
添加图片注释,不超过 140 字(可选)
注意力层
自注意力(Self-Attention) 操作是基于 Transformer 的机器翻译模型的基本操作, 在源语言的编码和目标语言的生成中频繁地被使用以建模源语言、目标语言任意两个单词之间的依赖关系。给定由单词语义嵌入及其位置编码叠加得到的输入表示 xi ∈ Rd i(t)=1 ,为了实现对上下文语义依赖的建模, 进一步引入在自注意力机制中涉 及到的三个元素: 查询 qi (Query), 键 ki (Key), 值 vi (Value)。在编码输入序列中每一个单词的表示的过程中, 这三个元素用于计算上下文单词所对应的权重得分。直观地说, 这些权重反映了在编码当前单词的表示时, 对于上下文不同部分所需要的关注程度。具体来说, 如下图所示, 通过三个线性变换 WQ ∈ Rddq ,WK ∈ Rddk , WV ∈ Rddv 将输入序列中的每一个单词表示 xi 转换为其对应的 qi ∈ Rdq ,ki ∈ Rdk ,vi ∈ Rdv 向量。
自注意力机制中的查询、键、值向量
为了得到编码单词 xi 时所需要关注的上下文信息, 通过位置 i 查询向量与其他位置的键向量做点积得到匹 配分数 qi · k1 , qi · k2 , ..., qi · kt。为了防止过大的匹配分数在后续 Softmax 计算过程中导致的梯度爆炸以及收敛效 率差的问题, 这些得分会除放缩因子^d 以稳定优化。放缩后的得分经过 Softmax 归一化为概率之后, 与其他位 置的值向量相乘来聚合希望关注的上下文信息, 并最小化不相关信息的干扰。上述计算过程可以被形式化地表述如下:
添加图片注释,不超过 140 字(可选)
其中 Q ∈ RL×dq , K ∈ RL×dk ,V ∈ Rd ×dv 分别表示输入序列中的不同单词的 q, k, v 向量拼接组成的矩阵, L 表 示序列长度, Z ∈ RLdv 表示自注意力操作的输出。为了进一步增强自注意力机制聚合上下文信息的能力, 提出了多头自注意力(Multi-head Attention) 的机制, 以关注上下文的不同侧面。具体来说, 上下文中每一个单词的表示 xi 经过多组线性 WjQ WjK W映射到不同的表示子空间中。上面公式会在不同的子空间中分别计算并得 到不同的上下文相关的单词序列表示 Zj 。最终, 线性变换 WO ∈ R(Ndv ) ×d 用于综合不同子空间中的上下文 表示并形成自注意力层最终的输出 xi ∈ Rd i(t)=1。 使用 Pytorch 实现的自注意力层参考代码如下:
添加图片注释,不超过 140 字(可选)
残差连接与层归一化
由 Transformer 结构组成的网络结构通常都是非常庞大。编码器和解码器均由很多层基本的 Transformer 块组成, 每一层当中都包含复杂的非线性映射, 这就导致模型的训练比较困难。因此, 研究者们在 Transformer 块 中进一步引入了残差连接与层归一化技术以进一步提升训练的稳定性。具体来说, 残差连接主要是指使用一条 直连通道直接将对应子层的输入连接到输出上去,从而避免由于网络过深在优化过程中潜在的梯度消失问题:
添加图片注释,不超过 140 字(可选)
其中 xl 表示第 l 层的输入, f (· ) 表示一个映射函数。此外, 为了进一步使得每一层的输入输出范围稳定在一个 合理的范围内,层归一化技术被进一步引入每个 Transformer 块的当中:
添加图片注释,不超过 140 字(可选)
其中 µ 和 σ 分别表示均值和方差, 用于将数据平移缩放到均值为 0,方差为 1 的标准分布, α 和 b 是可学习 的参数。层归一化技术可以有效地缓解优化过程中潜在的不稳定、收敛速度慢等问题。 使用 Pytorch 实现的层归一化参考代码如下:
添加图片注释,不超过 140 字(可选)
目前的预训练语言模型和大语言模型架构基本上都是在 Transformer 模型的基础上构建的。 Transformer 由一 个编码器(encoder)和一个解码器(decoder)组成:
Transformer编码器部分由 N = 6 个相同的编码器组成, 每个编码器由两个子网络。第一个是多头自注意力模块, 第二个是前馈神经网络(FNN)。每个子网络都有残差连接,并跟着层归一化。因此每个自网络的输出是 LayerNorm(x+ Sublayer(x)),其中 Sublayer(x) 是子网络对输入特征进行的具体映射操作。 从最下方的 Inputs 开始, 这里就输入了一个序列a1 , a2 , ..., aN (比如在 NLP 中, 输入了一个句子),然后 获得每一项 ai 的 embedding (嵌入),这里的 embedding 其实是 ai 的特征向量。 使用 Pytorch 实现的编码器参考代码如下:
相比于编码器端, 解码器端要更复杂一些。具体来说, 解码器的每个 Transformer 块的第一个自注意力子层 额外增加了注意力掩码, 即掩码多头注意力 (Masked Multi-Head Attention) 部分。这主要是因为在翻译的过程中, 编码器端主要用于编码源语言序列的信息, 而这个序列是完全已知的, 因而编码器仅需要考虑如何融合上下文 语义信息即可。而解码端则负责生成目标语言序列, 这一生成过程是自回归的, 即对于每一个单词的生成过程, 仅有当前单词之前的目标语言序列是可以被观测的, 因此这一额外增加的掩码是用来掩盖后续的文本信息, 以 防模型在训练阶段直接看到后续的文本序列进而无法得到有效地训练。
此外, 解码器端还额外增加了一个多头注意力 (Multi-Head Attention) 模块, 使用交叉注意力 (Cross-attention) 方法, 同时接收来自编码器端的输出以及当前 Transformer 块的前一个掩码注意力层的输出。查询是通过解码器 前一层的输出进行投影的, 而键和值是使用编码器的输出进行投影的。它的作用是在翻译的过程当中, 为了生 成合理的目标语言序列需要观测待翻译的源语言序列是什么。基于上述的编码器和解码器结构, 待翻译的源语 言文本, 首先经过编码器端的每个 Transformer 块对其上下文语义的层层抽象, 最终输出每一个源语言单词上下 文相关的表示。解码器端以自回归的方式生成目标语言文本, 即在每个时间步 t,根据编码器端输出的源语言文 本表示,以及前 t− 1 个时刻生成的目标语言文本,生成当前时刻的目标语言单词。
Transformer解码器部分也是 N = 6 个相同的解码器组成。与编码器相似, 解码器的每个子网络都有残差连接, 并跟着 层归一化。并且解码器的第一个多头注意力被掩盖(mask),使预测第 i 个单词时只能知道第 i 个单词之前的输 出。 一个注意力机制能将一个查询(query),和一组键(key) -值(value) 投影到输出。该模型中使用的自注意 力是缩放点积注意力。输入包含维度为 dk 的查询和键, 以及维度为 dv 的值。在实际运算中, 输入为查询(Q), 键(K)和值(V)的矩阵。输出矩阵为:
添加图片注释,不超过 140 字(可选)
与传统的点积注意力不同, 为了防止当 dk 过大时会使点积结果变得非常离散, 需要将点击以 1/sqr(d)的比例缩放。 多头注意力则是由多个自注意力组成的。与其使用查询, 键, 值维度为 dmodel 的单一自注意力机制, 分别 线性投影不同在 dk , dk , dv 维度上学习了的线性投影查询, 键, 值 h 次更为有效。对于每个查询, 键, 值的投影 并行使用注意力机制并生成维度为 dv 的输出。这些被集中到一起并再次被投影以得到最终结果。 Transformer 模 型用三种不同的方式使用多头注意力:
在编码器-解码器层, 查询来自于之前的解码器层, 键和值来自于编码器的输出。这使得解码器的每个位置 能够利用输入序列的所有位置。
编码器包含自注意力机制。在其中一个自注意力层中, 所有的查询, 键, 值都来自之前编码器层的输出。 编码器的每个位置能够利用之前一层的所有位置。
相似的, 解码器的自注意力层能够让每个位置利用之前解码器所有位置的信息。为了保留自回归的性质, 需要防止左侧信息涌入解码器。因此在缩放点积注意力中, 需要将 softmax 中所有有违规连接的输入掩盖。
(左)缩放点积注意力(右)多头注意力
除了注意力机制以外, 编码器和解码器的每层还包含了前馈神经网络, 这含有了两个线性变换以及之间的 ReLU 激活函数。尽管在不同位置的线性变换是相同的,参数设置会随着层数变化而更改。
另外, Transformer 使用了学习过的嵌入层来将输入 tokens 和输出 tokens 转化为维度为dmodel 的向量。该模 型也使用了学习过的线性变换和 softmax 函数将解码器的输出转化为下一个 token 的预测可能性。在该模型中, 两个嵌入层和 pre-softmax 线性变换之间共享权重矩阵。 使用 Pytorch 实现的解码器参考代码如下:
最终基于 Transformer 的编码器和解码器结构整体实现参考代码如下:
ps:欢迎扫码关注公众号^-^.