语言模型大串烧之变形金刚


本文起笔于2019.8,更新于 2022.8

主要介绍近十年来NLP领域的一些经典的语言模型,包括 Word2vec, ELMo, Transformer, GPT, BERT, XLNet, UniLM, T5, ALBERT, ELECTRA, DeBERTa, ERNIE 等。文中标题标注了各方法大致的年份,多数为论文公开的时间,方便按照时间线对比。从发布年份上可以看出2019年是基于Transformer的NLP研究最热的一年。但本文并未严格按照时间线来依次介绍各个模型。发展脉络主要参考的文章如下,值的一读:


词嵌入

词嵌入目的:表示文本、理解文本。

Embedding是一种典型的利用无监督信息提升监督问题效果的手段。

当词典容量比较大时,对单词进行one-hot encoding或hash编码得到的词向量(word vectors)的特点是:稀疏、高维、硬编码(hard-coded)。而用词嵌入表示,特点与之相反:稠密、低维,并且可从数据中学习得到。

为了了解一个词汇的含义,可以根据它的上下文(context)来得到。
比如两句文本:

  • “小马 520宣誓就职”
  • “阿蔡 520宣誓就职”

由于后文相同,因此可以认为“小马”和“阿蔡B”之间有某种程度的相似性。
那么,怎样通过词嵌入来表达这种相近的关系呢?

词嵌入方式

基于计数的词嵌入(count based)

如果两个词 \(w_i\)\(w_j\) 频繁共同出现,那么对应的词嵌入\(V(w_i), V(w_j)\)应当很接近。令:\(V(w_i)\cdot V(w_j)=N_{ij}\)即可用于优化求解,\(N_{ij}\)\(w_i\)\(w_j\) 在文档中的共现次数。这个概念跟matrix factorozation的概念很类似,这个方法的一个代表性的例子是Glove vector。

基于预测(prediction based)

模型:给定前边的一个或若干个词,预测下一个词(预测词集中每个词是下一次出现的概率)。假定模型是多层感知机模型。

当我们训练得到这样一个预测模型之后,相似的词应当具有相同的输出,在多层感知机模型的第一个隐藏层应具有相近的表示,因此可以用第一个隐藏层当作word embedding。

这种由一个单词的上文,去预测这个单词的模型与Bengio 于2003年提出的神经网络语言模型(NNLM, JMLR2003)非常类似。NNLM的主要任务是要学习一个解决语言模型任务的网络结构,语言模型就是要看到上文预测下文。

模型推广:前面说的模型是由前几个词预测下一个词,可以推广到由上下文预测当前词,即CBOW模型。以及拿中间的词汇预测context,即Skip-gram.

多语言嵌入:Multi-lingual Embedding,比如中英文,如果词汇之间存在一一对应的关系(如“咖啡”与cofee),那么我们如何使得机器能够知道不同语言的词对应同一含义?可以在得到中英文的不同embedding之后,再训练一个模型分别将中英文映射到同一空间内比较接近的位置。

语言模型

首先介绍最基础的N-gram模型,再介绍Word2vec,然后依次介绍现代的基于深度学习的语言模型,如BERT预训练模型。

预训练语言模型发展维度有很多,例如多模态、跨语言、粒度范围、位置编码等。

粒度范围维度 :从粗粒度学习、细粒度学习,向多粒度学习发展

位置编码维度 :从绝对位置编码、相对位置编码,向混合位置编码发展

本文仅介绍部分维度和模型。

N-gram

N元语法是基于n-1阶马尔科夫链的概率语言模型,其中n衡量了计算复杂度和模型准确性。N元语法模型通过马尔科夫假设简化了语言模型的计算,虽然该假设并非一定成立。马尔科夫假设是指一个词的出现只与前面n个词相关,即n阶马尔科夫链(Markov chain of order n),基于n-1阶马尔科夫链,语言模型为:

\[P(w_1 , w_2 , . . . , w_T ) ≈\prod_{t=1}P (w_t | w_{t−(n−1)} , . . . , w_{t−1} )
\]

困惑度perplexity

困惑度(Perplexity, PP)是对交叉熵损失函数做指数运算后得到的值,常用于评价语言模型的好坏,是一个简单、行之有效的评测指标。

设N-gram模型 \(M = P(w_i|w_{i-N+1}…w_{i-1})\) 的交叉熵损失为 \(H(W)=-{1\over N}\log_2 P(w_1w_2…w_N)\)

困惑度定义为:

\[\begin{aligned}
\operatorname{Perplexity}(W) &=2^{H(W)} \\
&=P\left(w_{1} w_{2} \ldots w_{N}\right)^{-\frac{1}{N}} \\
&=\sqrt[N]{\frac{1}{P\left(w_{1} w_{2} \ldots w_{N}\right)}} \\
&=\sqrt[N]{\prod_{i=1}^{N} \frac{1}{P\left(w_{i} \mid w_{1} \ldots w_{i-1}\right)}}
\end{aligned}
\]

句子的概率越大,语言模型越好,困惑度越小。N-gram给的单词序列信息越多,困惑度也越低。当然降低困惑度不一定保证能够提高NLP任务的性能。

参考:Speech and Language Processing

word2vec 2013

  1. Efficient Estimation of Word Representations in Vector Space
  2. Distributed Representations of Words and Phrases and their Compositionality

word2vec(NIPS 2013)可以把对文本内容的处理简化为K维向量空间中的向量运算,而向量空间的相似度可以用来表示文本语义上的相似度。而one-hot表示无法准确表达不同词之间的相似度,比如余弦相似度为0。word2vec将每个词表示成一个定长的向量,比one-hot的维度低很多。把词映射为实数域向量的技术也叫词嵌入。

Word2Vec 是一种浅层的神经网络模型, 它有两种网络结构, 分别是 CBOW(Continues Bag of Words) 和 Skip-gram. 两种网络结构均包含一个隐藏层,通过权重矩阵W将输入的one-hot编码映射到低维词向量。CBOW 的目标是根据上下文出现的词语来预测当前词的生成概率; 而 Skip-gram 是根据当前词来预测上下文中各词的生成概率.

Distributed Representation

word2vec使用的是一种分布式表示,这种表示方式最早由Hinton在1986年提出。其基本思想是通过训练将每个词映射成 K 维实数向量(K 一般为模型中的超参数),通过词之间的距离(比如 cosine 相似度、欧氏距离等)来判断它们之间的语义相似度。

Skip-Gram

Skip-Gram模型假设基于某 个 词 来 生 成 它 在 文 本 序 列 周 围 的 词。 假设存在一个 w1,w2,w3,…,wT 的词组序列,Skip-gram 的目标是最大化似然函数,\(\prod_{t=1}^T\prod_{-c\le j\le c,j\ne 0} p(w_{t+j}|w_t)\),即最小化损失:

\[-{1\over T}\sum_{t=1}^T\sum_{-c\le j\le c,j\ne 0}\log p(w_{t+j}|w_t)
\]

c越大,则需要考虑的 pair 就越多,一般能够带来更精确的结果,但是训练时间也会增加。

假设中心词在词典中索引为i,当它为中心词时向量表示为vi ,而为背景词时向量表示为ui 。设中心词wc 在词典中索引为c,背景词wo 在词典中索引为o,给定中心词生成背景词的条件概率可以通过对向量内积做softmax运算而得到(V为词典索引集):

\[p(w_o|w_c)={\text{exp}(u_o^Tv_c)\over\sum_{i\in V}\text{exp}(u_i^Tv_c)}
\]

若使用随机梯度下降,那么在每一次迭代里我们随机采样一个较短的子序列来计算有关该子序列的损失,然后计算梯度来更新模型参数。对于每个中心词向量,通过梯度进行更新:

\[\frac{\partial \text{log}\, P(w_o \mid w_c)}{\partial \mathbf{v}_c}=\mathbf{u}_o – \sum_{j \in \mathcal{V}} P(w_j \mid w_c) \mathbf{u}_j
\]

训练结束后,对于词典中的任一索引为i的词,我们均得到该词作为中心词和背景词的两组词向量vi 和ui 。在自然语言处理应用中,一般使用跳字模型的中心词向量作为词的表征向量。

CBOW

CBOW 是 Continuous Bag-of-Words Model 的缩写,CBOW 模型是预测 \(P(w_t|w_{t-k},w_{t-(k-1)},…,w_{t-1},w_{t+1},w_{t+2},…,w_{t+k})\)。连续词袋模型假设基于某中心词在文本序列前后的背景词来生成该中心词。因为连续词袋模型的背景词有多个,我们将这些背景词向量取平均,然后使用和跳字模型一样的方法来计算条件概率。

\[P(w_c \mid w_{o_1}, \ldots, w_{o_{2m}}) = \frac{\text{exp}\left(\frac{1}{2m}\mathbf{u}_c^\top (\mathbf{v}_{o_1} + \ldots, + \mathbf{v}_{o_{2m}}) \right)}{ \sum_{i \in \mathcal{V}} \text{exp}\left(\frac{1}{2m}\mathbf{u}_i^\top (\mathbf{v}_{o_1} + \ldots, + \mathbf{v}_{o_{2m}}) \right)}
\]

梯度更新时将平均值的更新量整个应用到每个参与平均的词向量上去。一般使用连续词袋模型的背景词向量作为词的表征向量。

CBOW和Skip-Gram都将\(w_i\)作为条件词(背景词)时的词向量记为\(v_i\),作为目标词词向量时记为\(u_i\)在下游应用中使用作为条件词时的向量

浅层神经网络

可以将Word2vec视作两层的神经网络,包含输入层、隐藏层、输出层。网络参数为输入和输出权重矩阵 \(W_I, W_O\). 背景词向量对应输入矩阵,目标词向量对应输出矩阵,在下游应用中采用输入矩阵作为初始化embedding。

近似训练

Skip-gram 的核心在于使用softmax运算得到给定中心词wc 来生成背景词wo 的条件概率:\(p(w_o|w_c)={\text{exp}(u_o^Tv_c)\over\sum_{i\in V}\text{exp}(u_i^Tv_c)}\),以及该条件概率相应的对数损失。无论Skip-Gram或CBOW的softmax运算的背景词可能是词典V中的任一词,对于含几十万或上百万词的较大词典,每次的梯度计算开销可能过大。为了降低该计算复杂度,本节将介绍两种近似训练方法,即负采样(negative sampling)、层序softmax(hierarchical softmax)。

  • 负采样

    负采样修改了原来的目标函数。给定中心词wc 的一个背景窗口,我们把背景词wo 出现在该背景窗口看作一个事件,并将该事件的概率计算为\(P (D = 1 | w_c , w_o ) = σ(u_o^⊤ v _c )\), σ函数定义为sigmoid激活函数(将softmax替换为了sigmoid简化计算,不依赖整个大词表)。目标是最大化联合概率:\(\prod_{t=1}^T\prod_{-c\le j\le c,j\ne 0}P(D=1|w_t,w_{t+j})\).

    然而,以上模型中包含的事件仅考虑了正类样本。这导致当所有词向量相等且值为无穷大时,以上的联合概率才被最大化为1。很明显,这样的词向量毫无意义。负采样通过采样负类样本使目标函数更有意义。设背景词\(w_o\) 出现在中心词\(w_c\) 的一个背景窗口内为事件\(P\) , 对每一个中心词根据分布\(P (w)\)采样\(K\)个未出现在该背景窗口中的词,即噪声词。条件概率近似为:

    \[P(w^{(t+j)} \mid w^{(t)}) =P(D=1\mid w^{(t)}, w^{(t+j)})\prod_{k=1,\ w_k \sim P(w)}^K P(D=0\mid w^{(t)}, w_k)
    \]

    负采样通过考虑同时含有正类样本和负类样本的相互独立事件来构造损失函数。其训练中每一步的梯度计算开销与采样的噪声词的个数线性相关。论文中将采样概率设置为正比于词的频率的3/4次方(实现中会进行归一化)。

  • 层序softmax

    层序softmax是另一种近似训练法。它使用了二叉树这一数据结构,树的每个叶结点代表词典V中的每个词。通过哈夫曼树的构造方式,将词典根据词频等信息构造成一棵二叉树。对于跳字模型中的条件概率\(P(w_o|w_c)\),将其视为让\(w_c\)从根节点开始走,能够走到\(w_o\)叶节点的概率。对于每一步,向左还是向右走是一个二分类问题。可以用逻辑回归中的sigmoid来得到向左走的概率\(p=\sigma(\theta w_c)\),向右走的概率为\(1-p=1-\sigma(\theta w_c)=\sigma(-\theta w_c)\). 而每个节点保存了逻辑回归的参数\(\theta\).

    假设\(L(w)\)为从二叉树的根结点到词\(w\)的叶结点的路径(包括根结点和叶结点)上的结点数。设\(n(w, j)\)为该路径上第 j 个结点,并设该结点的背景词向量为\(\mathbf{u}_{n(w, j)}\) ,背景词向量充当了\(\theta\)的作用。层序softmax将跳字模型中的条件概率近似表示为

    \[P(w_o|w_c)=\prod_{j=1}^{L(w_o)-1}\sigma(\text{sign}[n(w_o,j+1)=\text{leftChild}(n(w_o,j))]\cdot u^T_n(w_o,j)v_c)
    \]

    式中如果节点\(n(w_o,j+1)\)是节点\(n(w_o,j)\)的左孩子,则sign为1,反之为-1.

    层序softmax使用了二叉树,并根据根结点到叶结点的路径来构造损失函数。其训练中每一步的梯度计算开销与词典大小的对数相关(\(\mathcal O(\log_2 |V|)\))。每一层的节点相当于神经网络隐藏层的神经元。

    层次化的Softmax的思想实质上是将一个全局多分类的问题,转化成为了若干个二元分类问题,从而将计算复杂度从O(V)降到O(logV)。在做Hierarchical Softmax之前,我们需要先利用所有词汇(类别)及其频次构建一棵霍夫曼树。这样,不同词汇(类别)作为输出时,所需要的判断次数实际上是不同的。越频繁出现的词汇,离根结点越近,所需要的判断次数也越少。从而使最终整体的判断效率更高。[1]

对比选择

Mikolov 关于超参数的建议如下:

  1. 模型架构:Skip-gram 更慢一些,但是对低频词效果更好; CBOW 则速度更快一些。为什么?CBOW对context取了平均,计算量较小(减少了softmax的次数),并且生僻词由于与高频词取平均,预测效果降低。
  2. 训练算法:层次 softmax 对低频词效果更好(不存在按频次采样的问题); negative sampling 对高频词效果更好,向量维度较低时效果更好。

Subsampling

在实际应用中需要对过于低频和高频的词汇做处理:

  • 低频词:统一处理成<unk>标记,减少词表的大小

  • 高频词:从句子中随机抹除,词频越高,设置drop out概率越大:

    \[P(w_i) = \max\left(1 – \sqrt{\frac{t}{f(w_i)}}, 0\right)
    \]

    阈值t=1e-4, f(w)为频率,在\(f(w_i) > t\) 时才会进行随机抹除。高频词与很多词的共现频次都很高,通过随机抹除,能够消减高频词对训练的影响。

哈夫曼树构建算法

在word2vec和fastText中的层序softmax均涉及到哈夫曼树的构建,构建过程为迭代查找当前权重最小的两个子树,并将它们合并。不同的实现方式导致不同的时间和空间复杂度:

  • 每次线性查找最小的子树:时间O(n^2), 空间O(1)
  • 使用优先级队列维护堆查找最小值:时间O(nlog n),空间O(n),堆操作较频繁。
  • 使用固定长度为2n的数组存放叶子节点与新合并节点:时间O(nlog n),空间O(n)。

下面介绍word2vec和fastText工具中所使用的第三种方法:

长度为2n的数组(n为叶子节点数)前半部分保存每个叶子节点的词频,降序排列。后半部分随着迭代查找合并的过程依次插入新节点。用两个指针leaf、node分别指向当前迭代过程中剩余未合并的叶子节点、非叶子节点中的最小词频节点。迭代一次,找出leaf、node两者的最小值,若leaf最小,将leaf指针向左移动一位,否则将node指针向右移动一位。继续第二次迭代找到第二小的值(同时左移或右移),将当前找到的两个最小值合并后插入数组右半部分的后边。由于左半部分是降序,右半部分是增序(每次合并,值会不断增加),所以两个指针向相反的方向移动。算法只用了一次排序 + 一次遍历,简洁优雅。

QA

Word2Vec中的条件概率是怎么算出来的?

  1. 两个单词间的相似度:词向量求内积
  2. 一个单词与词典中所有词的相似度通过softmax转概率得到条件概率(该单词出现的条件下词典中每个词是下一个出现的概率)

为什么条件概率的计算采用了向量的内积?

  • 归一化之后的两个向量的内积正是cosine相似度,因此两个向量越相近,计算出的条件概率也越大。

为什么word2vec中的词向量同时用中心词和背景词向量来表示?

  • 数学形式上更简单,如果只用一个向量来表示,那么Softmax计算的概率公式里分母会出现一项平方项\(e^{v_c\cdot v_c}\) 那么再对 \(v_c\) 求导就会比较麻烦。相反如果用两套词向量,求导结果就会很干净。但其实,因为在窗口移动的时候,先前窗口的中心词会变成当前窗口的上下文词,先前窗口的某一个上下文词会变成当前窗口的中心词。所以这两组词向量用来训练的词对其实很相近,训练结果也会很相近。一般做法是取两组向量的平均值作为最后的词向量。参考CS224N
  • 一个词出现在以自己为中心的窗口内的概率很小,向量相乘运算的结果也应当比较小,如果只用一个向量表示,\(v\cdot v\) 计算结果很难保证较小值。

Negative Sampling是主要解决什么问题?

softmax计算量大的问题,也就是解决分类数量过大的问题。

为什么Word2Vec负采样训练中需要对权重开3/4次幂?

在保证高频词容易被抽到的前提下,通过权重 3/4 次幂的方式,适当提升低频词、罕见词被抽到的概率,避免低频词、罕见词很难被抽到,以至于不被更新对应 Embedding 的情况。而选择3/4这个数值是靠经验选择尝试出来的,也可以选择其它小于1的数。可以结合 \(y=x^k\) 的函数图像来看,k越接近0,y越接近1,并且y>=x,这样低频词的权重会被放大,通过轮盘赌被选中的概率也会增加。参考:为什么Word2Vec训练中, 需要对负采样权重开3/4次幂?

函数曲线y=x^k

参考:

GloVe

Word2vec在预估条件概率 \(P(w_j \mid w_i)\) 时采用了Softmax,不仅计算量大,而且在非常见词较多时在损失函数中累加较小的值会导致条件概率计算的不准确。

GloVe[2]从另外的角度来预估 \(P(w_j \mid w_i)\),避免Word2vec中的这两个问题。

\(w_j\) 出现在 \(w_i\) 的上下文窗口中的次数记为 \(x_{ij}\)\(w_i\) 的上下文窗口中的word数累加得到 \(x_i\),定义条件概率 \(p_{ij}=x_{ij}/x_i\).

GloVe 用两个word的预估概率 \(P(w_j \mid w_i)\) 相除,即可去除Softmax函数中共同的分母,并以此来拟合从整体样本中统计出的两个条件概率 \(p_{ij}\) 的比值:

\[f(\mathbf{u}_j, \mathbf{u}_k, {\mathbf{v}}_i) = f\left((\mathbf{u}_j – \mathbf{u}_k)^\top {\mathbf{v}}_i\right) = \frac{\exp\left(\mathbf{u}_j^\top {\mathbf{v}}_i\right)}{\exp\left(\mathbf{u}_k^\top {\mathbf{v}}_i\right)} \approx \frac{p_{ij}}{p_{ik}}
\]

接着,再做一步近似:\(\exp\left(\mathbf{u}_j^\top {\mathbf{v}}_i\right) \approx \alpha p_{ij} = \alpha x_{ij}/x_i\). 其中\(\alpha\)是常量。

两边取log:\(\mathbf{u}_j^\top {\mathbf{v}}_i \approx \log\,x_{ij} + \log\,\alpha – \log\,x_i\)

用两个word的bias之和来代替 \(- \log\, \alpha + \log\, x_i\). 得到\(\mathbf{u}_j^\top \mathbf{v}_i + b_i + c_j \approx \log(x_{ij})\).

采用平方误差作为损失,并添加每一项的权重 \(h(x)\),最终损失函数定义为:

\[\sum_{i\in\mathcal{V}} \sum_{j\in\mathcal{V}} h(x_{ij}) \left(\mathbf{u}_j^\top \mathbf{v}_i + b_i + c_j – \log\,x_{ij}\right)^2
\]

\(h(x)\) 设置为单调递增的函数: 当 x<c (e.g c=100)时 \(h(x)=(x/c)^α\) (e.g α=0.75), 否则 h(x)=1.

在每次SGD中随机采样一个 \(x_{ij}\) 作为minibatch。这些非零值 \(x_{ij}\) 提前在整个数据集上计算好,由于包含数据集的全局统计信息,因此该方法取名“Global Vectors”.

在GloVe中单词作为中心词和作为背景词的向量是相同的,采用了相同的学习方式。但是由于随机初始化时初始值的不同导致最后学习出来的向量不相同,在下游应用中使用时采用两者之和(一些经验表明训练同一个神经网络多次,并组合最终的结果能一定程度上提高效果,减少过拟合和噪声)。

在从样本中统计 \(p_{ij}\) 时还可以考虑两个word的间距,对距离较远的两个word,虽然出现在设定的固定大小的窗口内,但是相关性会差一些。论文中将两个word之间的间隔数 d 的倒数 1/d 作为 \(p_{ij}\) 的权重。

Glove这种训练词向量的方法的核心思想是通过对“词-词”共现矩阵进行分解从而得到词表示的方法。

\(N_{ij}\)\(w_i\)\(w_j\) 在文档中的共现次数,令:\(V(w_i)\cdot V(w_j)=N_{ij}\) 即可用于优化求解。这个概念跟matrix factorozation很类似。

Q:glove 与 word2vec 性能比较?

GloVe 的训练速度更快,然而词向量的性能在通用性上弱一些,仅在少量任务上表现优于 Word2Vec,在多数任务上比 Word2Vec 差。

参考:

子词嵌入

在word2vec中,我们并没有直接利用构词学(morphology)中的信息。构词学作为语言学的一个重要分支,研究的正是词的内部结构和形成方式。比如单复数cat,cats在word2vec中使用了不同的向量表示,而模型中并未直接表达这两个向量之间的关系。鉴于此,Facebook的论文Enriching Word Vectors with Subword Information[3]提出了子词嵌入(subword embedding)的方法,从而试图将构词信息引入word2vec中的skip-gram跳字模型中。在该方法中,每个中心词被表示成子词的集合,将中心词向量表示成单词的子词向量之和。子词嵌入利用构词上的规律,通常可以提升生僻词表示的质量。较生僻的复杂单词,甚至是词典中没有的单词(未登录词),可能会从同它结构类似的其他词那里获取更好的词向量表示。

论文提出了一种方法学习字符级的n-grams表征向量,用子字符n-grams表征向量的和来表示原词,这样具有相同词根的词有较高的相似度。字符级的n-grams示例如下:对于单词“where”,在两端添加特殊字符“<”和“>”以区分作为前后缀的子词。当n=3时,我们得到所有长度为3的子词:“<wh”,“whe”,“her”,“ere”,“re>”以及特殊子词“<where>”。

对于一个词w,我们将它所有长度在3∼6的子词和特殊子词的并集记为\(\mathcal{G}_w\)。那么词典则是所有词的子词集合的并集。假设词典中子词g的向量为\(\boldsymbol{z}_g\),那么跳字模型中词w的作为中心词的向量\(\boldsymbol{v}_w\)则表示成

\[\boldsymbol{v}_w = \sum_{g\in\mathcal{G}_w} \boldsymbol{z}_g
\]

子词数量过多带来的问题

子词数量过多导致内存需求较大,为了应对这一问题,论文提出采用哈希函数将所有子词映射到一个固定大小为K的列表中,用下标来表示子词。哈希函数采用Fowler-Noll-Vo hash(FNV-1a变体),需要考虑哈希冲突带来的性能影响。

Subword算法与传统空格分隔tokenization技术的对比优势:

  • 传统词表示方法无法很好的处理未知或罕见的词汇(OOV问题)
  • 传统词tokenization方法不利于模型学习词缀之前的关系

子词嵌入应用

子词嵌入的方法除了用于skip-gram同样可以用于CBOW,并能使用负采样或层序softmax来加速训练。但是在原word2vec基础上添加子词嵌入导致词典规模更大,模型参数更多,同时一个词的向量需要对所有子词向量求和,继而导致计算复杂度更高。

fastText工具采用了子词嵌入的方法。

byte pair encoding (BPE)

采用了子词嵌入之后n-gram字典的大小不能预先定义,为了在固定字典大小的情况下支持变长的子词,可以应用byte pair encoding (BPE)[4]方法来提取子词。BPE及其变体已经在GPT-2、RoBERTa等较现代的NLP模型中有所应用。

BPE的基本思想为:设定子词字典的容量m,初始统计单个字符[a-z]的频次,加入字典。开始迭代:选择频次最高的两个子词组合后统计频次,加入字典。迭代过程同哈夫曼编码的贪心过程,直至字典满为止。生成字典之后从长到短排序得到vocab词表。

在用一份预料得到BPE字典之后,对一个词(可以是不同的预料、数据集中的词)进行划分子词的过程为:从前往后依次贪心匹配字典中最长的子词。

注:在处理子词时对结尾子词添加一个特征的后缀,如</w>来区分后缀与开头或中间出现的相同的子词,因为通常会有不同的意义。

Wordpiece

BERT源码中采用的WordpieceTokenizer来对文本进行分割,转换为token id。使用 贪婪最长匹配优先算法(greedy longest-match-first algorithm) 从左往右不重叠地将一段文本进行 tokenization ,变成相应的 wordpiece,主要针对英文

在BERT中将汉字当做unicode单字字符处理的,因此WordpieceTokenizer不起作用,只在英文单词上产生作用。如 “unaffable” → [“un”, “##aff”, “##able”]。其中前缀##表示子词间的连接符。

如果要用这种思想来处理中文,我理解的应该是将中文文本分词当做word,将单字或偏旁部首分形作为piece处理,分词粒度通常包括短语粒度与基础粒度。在ERNIE 1.0中则对中文做了处理,分词作为word(分词方式不限于简单的贪婪最长匹配或专业的汉语分词工具),并在vocab.txt中包含##前缀的汉字单字piece,在WordpieceTokenizer中与英文处理方式一致。

BERT所采用的Wordpiece算法与BPE算法很相似,仅仅是合并token时选择的属性不同。BPE选择用频率,Wordpiece选择用概率(互信息)。即BPE 选择频数最高的相邻子词合并,而 WordPiece 选择能够提升语言模型概率最大的相邻子词加入词表。

Wordpiece及后来提出的Unigram Language Model都利用语言模型建立subword词表。

注:生成词表(vocab.txt)的代码未包含在BERT WordpieceTokenizer中,我们可直接使用开源项目中生成好的各语言的vocab.txt词表或者根据自己的具体任务的语料来生成。

参考:

fastText 文本分类模型

论文Bag of Tricks for Efficient Text Classification提出了用于文本分类的fastText方法,开源代码见 githubfasttext网站(包含多种语言的预训练词向量)。fastText开源、免费、轻量级,适用于文本分类和文本向量化表示场景,运行于标准硬件环境。裁剪压缩过的模型甚至可以轻松跑在移动设备上。值的注意的是fastText相关的三篇论文的作者均包括word2vec论文的作者 Tomas Mikolov。

fastText做文本分类的思想非常简单,对文本分类的baseline方法( 使用bag of words (BoW) 训练一个线性分类器)稍加改进:

  • BoW没有保留次序信息,采用n-gram来保留局部的次序信息(这里指的是单词word级别的n-gram,而非字符char级别的)。该论文并未提及和引用前作Enriching word vectors with subword information中的子词嵌入思想(字符级n-gram),但fastText工具中可以使用子词嵌入,在预测时可以得到未登录词的向量。
  • 对一个句子的词级 n-gram在lookup table中的低秩向量加和平均作为线性分类模型的输入特征。这里的lookup table与word2vec一样都是随机初始化并可学习。

分类器部分采用线性模型:f(Wx),并采用层次 softmax 来计算类别概率、计算损失。

论文和char-CNN等基于GPU的深度模型在Sogou等数据集上做了性能和速度的对比实验,表现不俗。

论文主要提出了文本分类模型,词向量只是其中的副产物。但是fastText工具的实现中除了分类模型,还提供了专用于词向量表示的CBOW、skip-gram模型,并且共用了一套接口。代码相比word2vec原始版本更具可读性,模块化程度较好。

由于单词级别 n-gram 的数量远大于 word 的数量,完全存储不现实,为了节省空间,fastText工具对n-gram做了hash分桶,hash到同一个位置的多个n-gram会共享同一个embedding,潜在的问题是存在哈希冲突。此外,该工具还支持模型压缩,以便在移动设备上运行。

实践经验表明,fastText更适用于样本数量大、类别标签多的任务,一般能够得到很好的效果,大多数情况下强于传统的BOW + LR/SVM分类器。

fastText在多个方面体现它的fast:

fastText与word2vec训练目标不一致:

  • fastText 预测目标为文档的类别,属于分类模型,词向量属于附属产物。而word2vec的训练目的仅为得到词向量。
  • word2vec的叶子节点是词和词频,fastText叶子节点是类标和类标的频数。

为什么有时候层序softmax比原始full softmax的性能指标差?

  • 层序softmax对原softmax做了近似,使得执行效率更高,但往往会损失一定的性能,尤其在类别不平衡时。如果类别较平衡的话可以尝试负采样,但测试时需要使用full softmax会相对慢一些。

没考虑词序信息?

  • cbow,skipgram,以及fasttext分类模型,都放弃了词序信息(fastText通过单词级的n-gram考虑了局部词序信息)。如果考虑词序信息,短文本可以考虑用一维卷积来捕捉,稍微长一点的文本,可以用lstm.

层序softmax预测时为什么采用深度优先遍历?

  • 在训练fastText时采用Hierarchical softmax,在测试时也需要采用树形结构得到每个类别的概率值。当类别数较大时,线性查找最大概率的值时间复杂度O(k),而采用深度优先遍历来找到概率值最大的类别时间复杂度可以是O(log k)。

    树的每个叶子节点是不同的类别,设类别数为k,则树的深度为log k。从根节点走到叶子节点将每个节点的二分类概率值累乘后得到叶子节点的类别概率,因此走到每个节点时累积概率值总是小于其父节点的累积概率值。在dfs走的过程记录当前已经走过的叶子节点里边的最大值,在继续走时发现当前节点的累积概率值小于已经发现的最大值,则停止向前,直接回溯。因此预测时的时间复杂度从softmax的O(k)变成层次softmax的O(log k). 如果要给出概率值最大的top T个类别,则采用优先级队列(小顶堆),时间复杂度O(log T).

参考:

Skip-Thought Vectors

Skip-Thought Vectors(NIPS 2015)借助于 skip-gram 的思想实现了 Sentence2vector,即句子的表示向量,可以更方便地用于文本相似性判断、文本分类等任务。

在skip-thought中利用中心句子来预测上下文的句子,输入 \(s_t\) ,输出 \((s_{t−1},s_{t+1})\) ,模型结构采用在机器翻译中最常用的 Encoder-Decoder 架构(具体实现采用GRU、LSTM),用Encoder的输出作为最终句子的表示向量。

数据集采用BookCorpus小说书籍中连续的句子,BookCorpus包含一万多本书,七千多万个句子,平均每个句子包含13个单词,131w个单词。示例如下:

连续的三个句子:“I got back home. I could see the cat on the steps. This was strange.”

对中间句子送入Encoder,相邻句子送入两个不同的Decoder。

Skip-Thought Vectors

词汇扩展

论文在对BookCorpus做预处理后仅用了2w单词,因此训练后模型存在的一个问题是单词数量较少,而英文词汇常用词也有三四万,加上不常用词、淘汰词后可达百万。因此未登录词的问题比较严重。

在训练完成后通过词汇扩展将词汇量扩展到百万级别,使得对于训练时未见过的多数词能通过词汇扩展找到近似的向量。具体的做法是:

  1)用 Vw2v 表示训练的Word2vec词向量空间,用Vrnn 表示Skip-Thought模型中的词向量空间,在这里 Vw2v 数量远大于 Vrnn 。

  2)引入一个矩阵 W 来构建一个线性映射函数:f: Vw2v−>Vrnn 。使得有v′=Wv ,其中 v∈Vw2v,v′∈Vrnn 。

  3)通过映射函数就可以将任何在 Vw2v 中的词映射到 Vrnn 中。

其中第2点是受论文 “Tomas Mikolov, Quoc V Le, and Ilya Sutskever. Exploiting similarities among languages for machine translation. arXiv preprint arXiv:1309.4168, 2013.” (对不同的语言空间通过线性映射得到word embedding)的启发,权重 W 通过不加正则化的线性回归训练得到。

这个线性映射的思想还可用于Image caption任务,给定图片做文本分类或者通过文本检索图片,分别对图片和文本的模型向量进行映射,在同一向量空间中计算相似度。

NLP研究与应用模式

研究方向:发展更强的特征抽取器;如何优雅地引入大量无监督数据中包含的语言学知识。

应用模式:超大规模预训练+具体任务Finetuing、具体任务特征补充。

词向量的应用

  • 在大规模语料上预训练的词向量常常可以应用于下游自然语言处理任务中。
  • 可以应用预训练的词向量求近义词和类比词。(比如运用KNN)

下游任务模型预训练

Word Embedding 等价于把Onehot层到embedding层的网络用预训练好的参数矩阵Q初始化了。句子中每个单词以Onehot形式作为输入,然后乘以学好的Word Embedding矩阵Q,就得到单词对应的Word Embedding了,这类似于查表的操作。下游NLP任务在使用Word Embedding的时候也类似CV领域有两种做法,一种是Frozen,就是Word Embedding那层网络参数固定不动;另外一种是Fine-Tuning,就是Word Embedding这层参数使用新的训练集合训练也需要跟着训练过程更新掉。

Word Embedding对于很多下游NLP任务是有帮助的,但是帮助没有特别明显。Word Embedding存在一个缺点:多义词的问题。一个词的多种语义都被编码到同一个embedding空间,这样embedding混合了不同上下文中的语义,是静态的,不能随着上下文的改变而改变。一种相对简洁优雅的解决方案是ELMo。

ELMo 2018

ELMo是“Embedding from Language Models”的简称,出自论文 Deep contextualized word representations(NAACL2018 最佳论文)。ELMo可以根据当前上下文对Word Embedding动态调整,ELMo 是第一个基于上下文的现代的语义理解模型。ELMo 使用了两层双向的LSTM,采用上下文语言模型进行预训练。ELMo 的模型结构和下游任务的使用方法如下图所示:

ELMo structure

下游任务使用ELMo的方式为:将输入数据送入ELMo得到三种特征(单词、句法、语义特征),并将三种特征按权相加(权重可以学习,并通过softmax层归一化)并进行一定的scaling作为下游任务的输入(scaling参数还是比较重要的,调整到合适的方差以更好的适应下游任务)。embedding输出即:

\[\text{ELMo}_k^{task}= \gamma^{task}\sum_{j=0}^L s_j^{task} h_{k,j}^{LM}
\]

其源码实现上也支持用Highway Net或者CNN来额外引入char-level encoding。

训练采用语言模型标准的最大化似然函数,即

\[\max \sum_{k=1}^N\left(\log p(t_k|t_1,\cdots,t_{k-1};\Theta_x,\overrightarrow\Theta_{LSTM},\Theta_s)
+\log p(t_k|t_{k+1},\cdots,t_N;\Theta_x,\overleftarrow\Theta_{LSTM},\Theta_s) \right)
\]

双向的LSTM有各自的参数\(\overrightarrow\Theta_{LSTM},\overleftarrow\Theta_{LSTM}\),但是word embedding参数 \(\Theta_x\) 和softmax参数 \(\Theta_s\) 是共享的。

由于ELMO给下游提供的是每个单词的特征形式,所以这一类预训练的方法被称为 “Feature-based Pre-Training”。

ELMo可改进之处(反观历史):

  1. LSTM抽取特征的能力远弱于Transformer。

  2. 上下文编码的方式可继续改进,双向融合特征的拼接方式的融合能力偏弱。

    ELMo的“双向”不够充分,因为bi-LSTM训练时是采用的两套参数,仅共享输入,并对输出拼接后反向传播更新参数。而后来的BERT的双向是用一套参数(共享)。ELMo这种“伪双向”有一点好处是不会存在深度双向语言模型中自己预测自己的问题,BERT论文作者 Jacob 在 reddit 帖子里提到:It’s unfortunately impossible to train a deep bidirectional model like a normal LM, because that would create cycles where words can indirectly “see themselves,” and the predictions become trivial.

    即当前待预测词的信息在前边层中会被包含,而BERT在做上下文编码时为了避免这个问题,在 Transformer 输入数据时使用mask将当前待预测词抹去,这样每层的全局 self-attention 都不会看到当前词。但mask的方式也带来了其它问题(见XLNet的分析及GPT坚持采用单向语言模型的原因)。参考:从语言模型看Bert的善变与GPT的坚守

Seq2Seq

Encoder-Decoder模型

通常来说,Seq2Seq任务最常见的是使用Encoder+Decoder的模式,先将一个固定长度的序列编码成一个上下文矩阵,再使用Decoder来解码。当然,我们仅仅把context vector作为编码器到解码器的输入。编码器要将整个序列的信息压缩成一个固定长度的向量。它存在三个弊端:[5]

(1)对于编码器来说,语义向量context vector可能无法完全表示整个序列的信息。

(2)对于编码器来说,先输入到网络的序列携带的信息可能会被后输入的序列覆盖掉,输入的序列越长,这种现象就越严重。

(3)对于解码器来说,在解码的时候,对于输入的每个单词的权重是不一致的。

以上三个弊端使得在解码的时候解码器一开始可能就没有获得输入序列足够多的信息,自然解码的准确率也就不高。所以,在NMT(Neural Machine Translation,神经机器翻译)任务上,还添加了attention的机制。

在transformer之前的seq2seq任务主要方案是由RNN/LSTM这类循环网络或者是CNN构成的 encoder+decoder的框架。还有在此基础上应用Attention机制也取得了非常大的成功,但依然存在很多痛点,比如RNN无法并行、速度慢。

Google 提出的 Transformer 正是基于 encoder-decoder 结构,但是通过特别的attention来试图改善传统encoder-decoder 结构的这三个弊端。可以并行计算,并能更好的解决长距离依赖问题。Transformer的 encoder-decoder 连接结构如下:

The_transformer_encoder_decoder_stack
(source://jalammar.github.io/images/t/The_transformer_encoder_decoder_stack.png)

Encoder-Decoder的内部连接结构如下图:

Transformer_encoder_decoder_stack

Q:decoder和encoder的区别?

结构类似,但是block内多了一个 soft attention 的 sub-layer,而非self attention。 K,V 来自 encoder,Q 来自上一位置 decoder 的输出解码。而在self attention输入时将当前位置及之后的词mask掉,与输入右移实现并行化有关。

Q:Decoder的输入为什么要右移一位?

因为语言模型是根据第i个位置之前的input token来预测第i个target token,通过将decoder的input token右移一位就可以实现这个目的。

在一般的Seq2seq模型中,Decoder是迭代对每一个输出位置进行解码,并用前一个的输出作为后一个的输入,与普通的RNN类似,执行效率较低。Transformer则没有按照旧方式来做,而是将解码器也同编码器一样,一次接收解码时所有时刻的输入进行计算。这样做的好处,一是通过多样本并行计算能够加快网络的训练速度;二是在训练过程中直接喂入解码器正确的结果而不是上一时刻的预测值能够更好的训练网络。[6]

Decoder 的并行化仅在训练阶段,在测试阶段,因为我们没有正确的目标语句,t 时刻的输入必然依赖 t-1 时刻的输出,这时跟之前的 seq2seq 就没什么区别了。

Seq2seq的decoder输出需要选择输出最可能的序列,通常采用beam search的方式。贪心选择与穷举方式都可以看作是beam search的特例。

集束搜索是一种启发式算法,会保存 beam size 个当前的较佳选择,然后解码时每一步根据保存的选择进行下一步扩展和排序,接着选择前beam size个进行保存,循环迭代,直到结束时选择最佳的一个序列作为解码的结果输出。

计算复杂度为 \(\text{beam_size * |vocabulary| * out_seq_len} = \mathcal{O}(k\left|\mathcal{Y}\right|T’)\)

参考 //d2l.ai/chapter_recurrent-modern/beam-search.html

Attention机制

基本思想:Attention is a generalized pooling method with bias alignment over inputs.

主要包括Soft Attention与Hard Attention两种:机器学习中 soft 常常表示可微分,比如sigmoid和softmax机制;而hard常常表示不可微分。

Encoder-Decoder加Attention架构由于其卓越的实际效果,目前在深度学习领域里得到了广泛的使用。

Soft Attention

将Source中的构成元素想象成是由一系列的<Key,Value>数据对构成,此时给定Target中的某个元素Query,通过计算Query和各个Key的相似性或者相关性,得到每个Key对应Value的权重系数,然后对Value进行加权求和,即得到了最终的Attention数值。所以本质上Soft Attention机制是对Source中元素的Value值进行加权求和,而Query和Key用来计算对应Value的权重系数。即可以将其本质思想改写为如下公式:

\[\text{Attention}(Query, Source)=\sum_{i=1}^{L_x}\text{Similarity}(Query, Key_i) * Value_i
\]

其中,\(L_x=\|Source\|\)代表Source的长度。根据Query和Key的相似性进行取值的过程也可以看作一种软寻址(Soft Addressing)。计算两者的相似性或者相关性,最常见的方法包括:求两者的向量点积、求两者的向量Cosine相似性或者通过再引入额外的神经网络来求值。再计算相似度之后通常使用softmax来进行归一化和突出重要元素的权重。

对于向量维度相同的query和key的相似度可以采用内积,并对所有的keys进行softmax得到归一化的值。

Dot Product Attention

\[\alpha(\mathbf q, \mathbf k) = \langle \mathbf q, \mathbf k \rangle /\sqrt{d} \\
\mathbf b =\rm{softmax}(\alpha) \\
\mathbf o = \sum_{i=1}^n b_i \mathbf v_i.
\]

计算分数时除以 \(\sqrt{d}\) 来消除维度 \(d\) 对分数计算的不相关影响。Transformer论文中称之为 Scaled Dot-Product Attention

为什么除以d的开方?

假设两个 d 维向量每个分量都是一个相互独立的服从标准正态分布的随机变量,那么他们的点乘结果会变得很大,并且服从均值为0,方差为d的分布。方差越大,正态分布越扁平,softmax输出的最大值的梯度也越小。对点乘结果除以 sqrt(d) 可以让点乘的方差变成 1,避免出现梯度消失。

(概率论知识:方差等于每个变量取值减均值后的平方和再除以变量个数或者个数减1)

至于是否可以除以d而不用d的开方,肯定也是可以的,计算开销更低一点,但是方差有所不同,最终效果可能也有些许差异。

Scaled Dot-Product Attention只是注意力的一种形式,还有一些其他选择,比如 query 跟 key 的运算方式不一定是点乘(还可以是拼接后再内积一个参数向量),甚至权重都不一定要归一化,等等。

对于向量维度不同的query和key的相似度,不能直接采用点积计算,需要转换为维度相同的向量后再做点积。

Multilayer Perceptron Attention

通过可学习的参数将query和keys映射到相同维度空间 \(\mathbb R^{h}\) :

\[\alpha(\mathbf k, \mathbf q) = \mathbf v^\top \text{tanh}(\mathbf W_k \mathbf k + \mathbf W_q\mathbf q)
\]

三个可学习参数通过Dense层(全连接层)即可实现。

Soft Attention 应用示例:

soft-attention

机器翻译加Soft Attention如上图所示,A网络的每个输入词的输出向量为 \(\mathbf s_j\),B网络的隐藏状态 \(\mathbf h_i\),那么Similarity可以是如下的形式:

  1. 乘法Attention,参数较少

    \[f_{att}(\mathbf h_i,\mathbf s_j)=\mathbf h_i^\mathsf{T} \mathbf W_a \mathbf s_j
    \]

  2. 加法-拼接 \(\mathbf s_j\)\(\mathbf h_i\)

    \[f_{att}(\mathbf h_i,\mathbf s_j)=\mathbf v_a^\mathsf{T} \tanh(\mathbf W_a [\mathbf h_i;\mathbf s_j])
    \]

  3. 加法-独立

    \[f_{att}(\mathbf h_i,\mathbf s_j)=\mathbf v_a^\mathsf{T} \tanh(\mathbf W_1 \mathbf h_i + \mathbf W_2\mathbf s_j)
    \]

Self Attention

自注意力机制是注意力机制的变体,其减少了对外部信息的依赖,更擅长捕捉数据或特征的内部相关性。

Self Attention也经常被称为intra Attention(内部Attention),指的不是Target和Source之间的Attention机制,而是Source内部元素之间或者Target内部元素之间发生的Attention机制,也可以理解为Target=Source这种特殊情况下的注意力计算机制。Self Attention在机器翻译中可以捕获同一个句子中单词之间的一些句法特征(比如短语结构)或者语义特征(比如it/its与指代对象具有相关性)。

引入Self Attention后会更容易捕获句子中长距离的相互依赖的特征,而RNN或LSTM,需要依次序序列计算,对于远距离的相互依赖的特征,要经过若干时间步步骤的信息累积才能将两者联系起来,而距离越远,有效捕获的可能性越小。因此Self Attention也有利用计算的并行性。

为什么self attention有效?是怎样学习的?通过人工强制加入self attention,迫使网络将相关的元素找出来,并且使得相关的元素的embedding比较相近。

Attention在Transformer中的应用

Transformer在三个地方使用了multi-head attention。

  1. 在encoder中包含self-attention层,在每个self-attention层所有的key, value, query都是由上一层而来,因为每个位置都含有之前层的信息。
  2. 在decoder中也包含了一个类似encoder中的self-attention层,避免看见未来的词,在decoder中加入了mask。key, value, query都是由上一层而来。
  3. 在encoder-decoder层,query是上一个decoder层产生,key, value来自于encoder,这可以让decoder中每一个位置都可以学习到输入序列中的信息。不属于Self Attention而属于Soft Attention。

Transformer 2017

Transformer源自谷歌论文 Attention Is All You Need NIPS 2017,本质是个self attention叠加结构,其提取特征的能力要远强于LSTM。优点是易于并行,捕获长距离特征能力强。

RNN的明显缺点之一就是无法并行,速度较慢,这是递归的天然缺陷。RNN递归的过程无法很好地学习到全局的结构信息,因为它本质是一个马尔科夫决策过程。RNN一般要双向才比较好。CNN只能获取局部信息,需要通过层叠来增大感受野。Attention的思路最为直接,它一步到位获取了全局信息。

Transformer的结构图见上文Seq2Seq,包含Encoder、Decoder两部分,每部分均包含N个block,每个block中包括multi-head attention、FFN、add&norm等操作。add&norm中采用了Layer Normalization而不是Batch Normalization。

Transformer将单个attention用在整个句子中。句子长度适用于多长?文章级别需要分段吗?不适宜过长的文章级别的文本,因为self Attention的计算复杂度为长度的平方级,Longformer论文提出了新的Attention机制来解决文章级别的文本任务,使Attention的计算复杂度与长度呈线性关系。而如果对文章进行分段处理,势必会丢失信息。

multi-head attention 和 FFN都是在sequence的每个单词位置进行变换,没有采用RNN中的循环结构或者CNN中的卷积,不涉及词的先后顺序,因此可以并行计算。但是单词的先后位置信息没有被利用到,可以将位置信息提前编码加入原始输入特征X再经过multi-head attention 和 FFN。

输入编码表示:输入文本经过 Token Embeddings 再与 position embedding 相加。

Multi-Head Attention

Multi-Head Attention

通过三个可学习的权重矩阵:\(\mathbf W_q^{(i)}\in\mathbb R^{p_q\times d_q},\ \mathbf W_k^{(i)}\in\mathbb R^{p_k\times d_k},\ \mathbf W_v^{(i)}\in\mathbb R^{p_v\times d_v}\) 对query, key, value 进行转换。然后可以使用上边提到的 Scaled Dot-Product Attention 或 Multilayer Perceptron Attention。

\[\mathbf o^{(i)} = \mathrm{attention}(\mathbf W_q^{(i)}\mathbf q, \mathbf W_k^{(i)}\mathbf k,\mathbf W_v^{(i)}\mathbf v)
\]

然后通过h个参数独立的attention得到h个输出,拼接后经过额外的权重矩阵转换(全连接dense层)得到Multi-Head Attention输出:

\[\mathbf o = \mathbf W_o \begin{bmatrix}\mathbf o^{(1)}\\\vdots\\\mathbf o^{(h)}\end{bmatrix}
\]

Transformer论文中实验设置为 \(h=8,\ d_k=d_v=d_{\rm{model}}/h=64\).

Multi-Head Attention 结构示意图如下:

Multi-Head Attention

并行计算:h个header可以并行计算,但代码中可以通过reshape的方式将h个矩阵乘法合并成一次,而将矩阵乘法交给底层来加速。[7]

使用多头的原因

多次 attention 综合的结果能够起到增强模型的作用,可以类比 CNN 中同时使用多个卷积核的作用。直观上讲,多头的注意力有助于网络捕捉到更丰富的特征/信息。

位置编码

position embedding位置编码有很多种选择,有固定参数的和可学习的,参考文献[8].

Transformer的位置编码采用了固定参数的包含正余弦的函数形式,为什么设计的那么奇葩?直接采用位置编号(0、1、2…)不行吗?

不行,因为绝对位置在不同长度的句子中意义不同。比如长度分别为5、20的句子中位置3的意义相差可能较大。在长度较长时,数值会比较大。并且训练样本的最长长度固定,当测试时文本长度超过之后,无法准确预测,导致模型泛化能力较差。如果将位置编号换成[0, 1]之间的浮点数,将丧失字符个数信息,且在不同长度的句子中尾号编码的意义也不同。

位置编码函数期望:[9]

  • 句子中每个词应对应一个唯一的编码
  • 在不同长度的句子中两个点之间的编码距离应该一致
  • 值有界,且适用于较长的句子
  • 位置编码函数具有确定性的值输出

采用具有周期性的sin、cos函数能够表示相对位置信息,且适用于不定长度的句子。

sin(wx)的周期/波长为:2π/w,因此位置编码函数的波长为: \(2π \cdot 10000^{2j/d}\) 范围为 2π ~ 10000⋅2π.

  • 论文的位置编码是使用三角函数去生成一个编码向量,而不是标量:

    • 值域只有[-1,1]
    • 容易计算相对位置。
\[\begin{align}
P_{i, 2j} &= \sin(i/10000^{2j/d}), \\
\quad P_{i, 2j+1} &= \cos(i/10000^{2j/d})
\end{align}
\]

\(P_{pos+k}\) 可以表示为 \(P_{pos}\) 的线性函数。why?正余弦公式:参考 addition theorem

\[\begin{array}{l} \sin \left( {\alpha + \beta } \right) = \sin \alpha \cos \beta + \cos \alpha \sin \beta \\ \sin \left( {\alpha – \beta } \right) = \sin \alpha \cos \beta – \cos \alpha \sin \beta \\ \cos \left( {\alpha + \beta } \right) = \cos \alpha \cos \beta – \sin \alpha \sin \beta \\ \cos \left( {\alpha – \beta } \right) = \cos \alpha \cos \beta + \sin \alpha \sin \beta \end{array}
\]

为什么设计成sin、cos组合的形式来生成编码向量,并且向量的各个维度具有不同的频率?

让我们观察二进制数字表示形式:

\[\begin{align}
0: \ \ \ \ \color{orange}{\texttt{0}} \ \ \color{green}{\texttt{0}} \ \ \color{blue}{\texttt{0}} \ \ \color{red}{\texttt{0}} & &
8: \ \ \ \ \color{orange}{\texttt{1}} \ \ \color{green}{\texttt{0}} \ \ \color{blue}{\texttt{0}} \ \ \color{red}{\texttt{0}} \\
1: \ \ \ \ \color{orange}{\texttt{0}} \ \ \color{green}{\texttt{0}} \ \ \color{blue}{\texttt{0}} \ \ \color{red}{\texttt{1}} & &
9: \ \ \ \ \color{orange}{\texttt{1}} \ \ \color{green}{\texttt{0}} \ \ \color{blue}{\texttt{0}} \ \ \color{red}{\texttt{1}} \\
2: \ \ \ \ \color{orange}{\texttt{0}} \ \ \color{green}{\texttt{0}} \ \ \color{blue}{\texttt{1}} \ \ \color{red}{\texttt{0}} & &
10: \ \ \ \ \color{orange}{\texttt{1}} \ \ \color{green}{\texttt{0}} \ \ \color{blue}{\texttt{1}} \ \ \color{red}{\texttt{0}} \\
3: \ \ \ \ \color{orange}{\texttt{0}} \ \ \color{green}{\texttt{0}} \ \ \color{blue}{\texttt{1}} \ \ \color{red}{\texttt{1}} & &
11: \ \ \ \ \color{orange}{\texttt{1}} \ \ \color{green}{\texttt{0}} \ \ \color{blue}{\texttt{1}} \ \ \color{red}{\texttt{1}} \\
4: \ \ \ \ \color{orange}{\texttt{0}} \ \ \color{green}{\texttt{1}} \ \ \color{blue}{\texttt{0}} \ \ \color{red}{\texttt{0}} & &
12: \ \ \ \ \color{orange}{\texttt{1}} \ \ \color{green}{\texttt{1}} \ \ \color{blue}{\texttt{0}} \ \ \color{red}{\texttt{0}} \\
5: \ \ \ \ \color{orange}{\texttt{0}} \ \ \color{green}{\texttt{1}} \ \ \color{blue}{\texttt{0}} \ \ \color{red}{\texttt{1}} & &
13: \ \ \ \ \color{orange}{\texttt{1}} \ \ \color{green}{\texttt{1}} \ \ \color{blue}{\texttt{0}} \ \ \color{red}{\texttt{1}} \\
6: \ \ \ \ \color{orange}{\texttt{0}} \ \ \color{green}{\texttt{1}} \ \ \color{blue}{\texttt{1}} \ \ \color{red}{\texttt{0}} & &
14: \ \ \ \ \color{orange}{\texttt{1}} \ \ \color{green}{\texttt{1}} \ \ \color{blue}{\texttt{1}} \ \ \color{red}{\texttt{0}} \\
7: \ \ \ \ \color{orange}{\texttt{0}} \ \ \color{green}{\texttt{1}} \ \ \color{blue}{\texttt{1}} \ \ \color{red}{\texttt{1}} & &
15: \ \ \ \ \color{orange}{\texttt{1}} \ \ \color{green}{\texttt{1}} \ \ \color{blue}{\texttt{1}} \ \ \color{red}{\texttt{1}} \\
\end{align}
\]

可以看出:不同的比特位具有不同的变化频率,LSB(Least Significant Bit,最低有效位)变化最频繁,MSB(最高有效位)变化周期最长。然而直接用二进制表示位置编码,在浮点型环境下会比较浪费空间。采用正余弦函数取得[-1,1]之间平滑的取值, 能够节省空间。

为什么同时使用sin、cos,只用一个函数不行吗?[sin(x+k), cos(x+k)] 可以通过 [sin(x), cos(x)] 线性变化得到(通过旋转矩阵 rotation matrix),但是只用一个sin(或cos),无法仅用sin(或cos)来实现线性变换。

\[M_{k} = \begin{bmatrix}
\cos(k) & \sin(k) \\
– \sin(k) & \cos(k)
\end{bmatrix} \\
\begin{bmatrix}
\sin(x+k) \\
\cos(x+k)
\end{bmatrix}
= M_k
\begin{bmatrix}
\sin(x) \\
\cos(x)
\end{bmatrix}
\]

对该位置编码函数的更形象的理解:将每对(sin, cos)看作时钟上的一个指针(时针、分针、秒针、毫秒、微秒、纳秒…),位置改变的过程就是钟表指针旋转的过程。因此,可以想到位置变化可以用旋转矩阵来得到。

相对位置可以通过线性变换有什么意义?论文提到可以使模型更容易学习attention。给定一个位置pos的编码,想要将attention聚焦于pos+k的位置,只需要让网络学习一个Mk的权重,与起始位置pos无关。

下面图一位置编码函数图像,可以反映出不同维度随着位置改变的变化频率。图二的编码距离可以看出具有对称性,位置距离越远,编码距离也越大。

图一:位置编码函数,x轴:embedding维度,y轴:位置

位置编码函数

图二:不同位置编码的欧式距离,x,y轴:位置

位置编码的欧式距离

Position Embedding本身是一个绝对位置的信息,但在自然语言中,相对位置也很重要,Google选择前述的位置向量公式的一个重要原因是:由于 \(\sin(α+β)=\sinα\cosβ+\cosα\sinβ\) 以及 \(\cos(α+β)=\cosα\cosβ−\sinα\sinβ\),这表明位置p+k的向量可以表示成位置p的向量的线性变换,这提供了表达相对位置信息的可能性,在遇到比训练集中更长的句子时泛化能力可能更强。尽管论文给出的Position Embedding是 sin,cos 交错的形式,但其实这个交错形式没有特别的意义,你可以按照任意的方式重排它(比如前sin后cos拼接)[10]

位置编码方式选择

论文也指出,通过自动学习的位置编码和人为选择的固定的编码在实验效果上差距不大。自动学习的位置编码可解释性肯定就比较差了,而人为选择的编码满足我们对距离的理解,相比于训练出来的向量,三角函数的公式可以处理比训练样本更长的文本序列。

对于机器翻译任务,encoder 的核心是提取完整句子的语义信息,它并不关注某个词的具体位置是什么,只需要将每个位置区分开(三角函数对相对位置有帮助); 而对于序列标注类的下游任务 ,是要给出每个位置的预测结果的。 Bert 模型采用了自动学习位置编码的方式,并非是因为自动学习的方式有显著的提升,而是基于神经网络能模拟任意函数的思路,统一采用网络自动学习的方式可能会表现更好。

对于位置编码的使用方式:通过与原输入做拼接(concat)能很好地满足正交性,但是通常embedding的维度比较大,拼接的方式导致需要学习更多的参数。通过与原输入直接相加的方式能够得到近似的正交性,而且也不需要获取绝对精确的位置信息。参考1[11],参考2[12].相加的方式要求位置编码与单词embedding具有相同的维度(论文中是512)。

位置信息前向传播经过许多层之后不会变质或者消失吗?由于采用了残差结构,能够直接传播过去。

OpenAI 的实现的位置编码如下:参考stackexchange

\[\begin{align}
P_{i, 2j} &= \sin(i\cdot \exp(2j\cdot -\log 10000/d)), \\
\quad P_{i, 2j+1} &= \cos(i\cdot \exp(2j\cdot -\log 10000/d))
\end{align}
\]

Multi-head可以让模型在不同的位置从不同的视角进行学习,与单attention head相比学习到信息更丰富,每一个head可以并行。

位置编码的应用方式:与输入直接相加再进行Attention和FFN,有些实现中在添加位置编码之前对输入的embedding乘上\(\sqrt d\) 来防止值太小(d是embedding的维度)。

FFN

Position-wise Feed-Forward Networks

对于三维特征输入:(batch size, sequence length, feature size) ,使用两个dense层(全连接层)对最后一个维度进行变换,保持输出维度不变。等价于使用两个1×1的一维卷积(为什么?一维卷积在sequence length维度上滑动,kernel_size=1则在每个位置上(position-wise)进行feature size维度上的变化)。

可调参数

可调整的参数:训练数据集中最长句子的长度,beam_size(候选集的个数) 和 max_out_len(最大输出的句子长度)。

Transformer优缺点[13]

  1. 优点
  • 模型的设计主要是矩阵乘法,可以高度并行化,计算复杂度大大降低。
  • 计算不同step之间的相关性,self attention不需要进行序列计算,直接进行point-wise计算。
  • 在Encoder中,若想要获得最终的hidden state结果,RNN需要从前往后逐个沿着序列计算,CNN需要堆叠多层的卷积层来扩展视野,而Transformer只需要多层的矩阵计算即可。
  1. 缺点-序列长度限制
  • Transformer使用了position embedding加入了序列的信息,但是在训练的时候设定了max_length,如果在预测中遇到超过max_length的case,可能不能得到很好的结果。
  • 无法借助while op来处理变长序列的输入,而只能通过pad或者截断来预处理数据。
  • 对于长输入的任务,典型的比如篇章级别的任务(例如文本摘要),因为任务的输入太长,Transformer会有巨大的计算复杂度,导致速度会急剧变慢。但是可以通过文本切分,用层级的Transformer来提取特征,比如Transforme-XL采用了类似的思路。而Longformer则从Attention的角度进行了优化。

Transformers-hub

开源huggingface库集成了众多基于Transformer的模型,开箱即用。

利用Transformer结构思想的后续模型很多仅采用了encoder或decoder两者之一,如GPT decoder, BERT encoder。

NLP任务大体可分为自然语言理解(NLU,Natural Language Understanding)和自然语言生成(NLG,Natural Language Generation)两种类型。仅含Encoder的模型主要做NLU,仅含Decoder的模型主要做NLG,而两部分都包含的模型两者皆可做。

可以将Transformers宽泛地分为三类:

  • GPT-like (auto-regressive Transformer models)
  • BERT-like (auto-encoding Transformer models)
  • BART/T5-like (sequence-to-sequence Transformer models)

Q:什么情况下用encoder,什么情况下用decoder?

如何选择语言模型(language models)取决于任务类型:

  • Decoder:GPT系列(GPT-2、GPT-3)、XLNet,擅长自由创作等文本生成应用场景。在传统的单向 language models (LMs) 中, 每个 token 基于前边的 tokens 进行预测,因此仅需要decoder.
  • Encoder:BERT、RoBERTa、ALBERT等输入内容理解(NLU)模型,适合分类问题(如句子分类、命名实体识别)。在BERT的masked LMs中,每个 token 基于两边的 tokens 进行预测,在encoder中就可完成,因此仅需要encoder。在其他的 masked LM 架构中有用encoder-decoder实现的, 比如 MASS
  • Encoder-Decoder:T5。对生成式、判别式模型均适用。擅长给定输入,产生对应的输出的应用:比如翻译,知识问答、文章摘要等。在机器翻译 Neural Machine Translation (NMT) 模型中, 每个 token 基于前边的已预测tokens (decoder)和源语言文本(encoder)进行预测,因此是encoder-decoder结构。当然也有一些仅用 decoder 的模型,如 this one.

参考:nlp – Why is the decoder not a part of BERT architecture? – Data Science Stack Exchange

Transformers 模型时间线,from BERT 101 – State Of The Art NLP Model Explained

Transformer model timeline

参数量 from How do Transformers work? – Hugging Face Course

Number of parameters of recent Transformers models

Longformer 2020

Longformer 通过简化Attention的计算来减少长输入的计算复杂度。Attention的设计思想为Global+Local(sliding window ) Attention。

sliding window attention 是对每个token在长度为W的窗口内进行softmax attention的计算,计算复杂度为O(WL).

对于不同的下游任务设置不同的Global attention:

  • 在分类任务上,这个global attention就落在[CLS]标签上。
  • 在QA任务上,就在整个问句上计算global attention。

可以看出,global attention是视具体任务而定的,换个任务可能之前的做法就不适用了,但作者认为,这仍然比现有的trunk或者shorten的做法要简单很多。

Longformer

GPT 2018~2020

GPT:Improving Language Understandingby Generative Pre-Training(OpenAI,2018)

GPT是“Generative Pre-Training”的简称,从名字看其含义是指的通用的预训练,核心在通用上。

GPT也采用两阶段过程,第一个阶段是利用语言模型进行预训练,第二阶段通过Fine-tuning的模式解决下游任务。

GPT采用Transformer作为特征抽取器,预训练虽然仍然是以语言模型作为目标任务,但是采用的是单向的语言模型,即仅靠上文来进行预测。相比于ELMo的采用上下文来做预测,GPT在某些应用场景下会受限,比如阅读理解任务(可以充分利用下文)。

为了下游任务能够fine-tuning,下游任务不能再任意设计自己的网络结构,需要和GPT保持一致。那么如何改造下游任务使之接近GPT的网络模型呢?

  • 分类问题,不用怎么动,加上一个起始和终结符号即可;
  • 句子关系判断问题,比如Entailment,两个句子中间再加个分隔符即可;
  • 文本相似性判断问题,把两个句子顺序颠倒下做出两个输入即可,这是为了告诉模型句子顺序不重要;
  • 多项选择问题,则多路输入,每一路把文章和答案选项拼接作为输入即可。

GPT-2 : Language Models Are Unsupervised Multitask Learners (2019)

GPT-2 相比GPT-1,在结构框架上没有大的差异(依然仅使用Decoder),而是扩大的模型容量:更大的模型、更大的训练语料。GPT-2将Transformer层数增加到48层,参数规模15亿。采用包含800万互联网网页的数据作为语言模型的训练数据,称为WebText(40GB)。互联网网页的优点是覆盖的主题范围非常广,这样训练出来的语言模型,通用性好,能广泛适用于任意领域的下游任务。WebText采用的reddit中获得高投票的网页链接,并在数据质量方面下了很大的功夫。

GPT-2 通过无监督大模型验证了只要模型够大、数据够多,通过Transformer就可以学到很多通用的包含各个领域的知识,这样下游任务几乎不需要再微调了。当然如果在下游数据上微调可能还能获得更好的结果。

Zero-Shot Learning:在没有采用监督数据训练的情况下尝试完成下游任务。GPT-2 通过给模型一个提示(prompt)让模型按生成模型的方式来生成答案。比如做文本摘要,在输入时候加入“TL:DR”引导字符串。

GPT-3 : Language Models are Few-Shot Learners(2020)

GPT-3 再次提升了模型的规模,使用了45TB的训练数据,拥有175B的参数量。

One-shot/Few-shot learning:对某些类别只提供一个或者少量的训练样本。

GPT-3 对于下游任务的预测,仿照人类出题答题的方式:给一个问题说明,并举一个或多个例子来说明问题。

对比:

与Transformer的区别:仅用了decoder部分,采用无监督数据做预训练,而Transformer是直接用模型做的机器翻译等任务,没有预训练过程。

与BERT的区别:GPT是基于自回归模型,可以应用在NLU和NLG两大任务,而原生的BERT采用的基于自编码模型,只能完成NLU任务,无法直接应用在文本生成上面。

GPT的可改进之处:单向语言模型的问题 => 改成双向(结合BERT的MLM 掩码方式、结合Encoder:MASS/BART/UniLM)。

GPT系列均采用单向语言模型的原因:可能主要为完成生成式的任务,在生成式相关任务场景下一般只能看到上文,因此传统的单向语言模型更方便。但是不排除有更好的双向模型出现的可能,比如后文的MASS通过seq2seq既能够利用双向又能够实现生成式。

BERT 2018

Bert(Pre-training of Deep Bidirectional Transformers for Language Understanding)采用和GPT完全相同的两阶段模型,首先是语言模型预训练;其次是使用Fine-Tuning模式解决下游任务。和GPT的最主要不同在于在预训练阶段采用了类似ELMo的双向语言模型,当然另外一点是语言模型的数据规模要比GPT大。

Bert在模型和方法上的创新表现在Masked 语言模型Next Sentence Prediction。而Masked语言模型的本质思想和CBOW类似,但是细节方面有改进。

  1. Masked双向语言模型:类似CBOW,用一个词周围的词,去预测其本身。随机选择语料中15%的单词,把它抠掉,也就是用[Mask]掩码代替原始单词,然后要求模型去正确预测被抠掉的单词。但是这里存在一个问题:训练过程大量看到[mask]标记,但是真正后面用的时候是不会有这个标记的,这会引导模型认为输出是针对[mask]这个标记的,但是实际使用又见不到这个标记。为了缓解这个问题,Bert对15%的被选中要替换成[mask]的单词进行如下的随机操作:
    • 80%真正被替换成[mask]标记;
    • 10%被随机替换成另外一个单词;
    • 10%不做替换。
  2. Next Sentence Prediction:为了训练一个可以理解句子关系(句子B是否是A的下一句)的模型,可以训练一个二值化的Next Sentence Prediction任务。训练样本可以从任何的单语言语料库中简单地生成(50%的概率选择一个句子的实际的下一句,50%的概率从语料库中随机选择一个句子)。考虑到很多NLP任务是句子关系判断任务,单词预测粒度的训练到不了句子关系这个层级,增加这个任务有助于下游句子关系判断任务。值得注意的是这里的句子级负采样与word2vec的词级负采样做法类似。

Bert的预训练是个多任务过程,即同时训练这两个任务 MLM (50%) + NSP (50%),采用多目标损失函数。

MLM任务仅用于预训练,这也带来一个缺点:[mask] 使pre-training和fine-tuning不匹配。

Bert使用了Transformer的encoder结构,但是在位置编码上没有采用Transformer论文(Attention is all you need)中的sin、cos编码方式,而是直接简单训练一个位置编码,与word embedding直接相加。

输入预处理:添加特殊token,将输入的pair变为[cls] text_a [sep] text_b [sep],如果仅用单句,则只需要[cls]

  • [cls] 汇聚句子的表示
  • [sep] 区分句子

这两个特殊token同时用于预训练和微调,而GPT中仅用于微调。

开源代码://github.com/google-research/bert

论文中的 BERT-base 与 BERT-large 对比:

Model Transformer Layers Hidden Size Attention Heads Parameters Processing Length of Training
BERTbase 12 768 12 110M 4 TPUs 4 days
BERTlarge 24 1024 16 340M 16 TPUs 4 days

注:BERT-base的参数设计是为了和OpenAI GPT保持相同的参数量,用于模型比较。

Hidden Size是指Multi-head Attention的输出维度及feed-forward的输出维度,两个模型中feed-forward/filter size = 4H,filter size是指用卷积或全连接实现的feed-forward。即feed-forward中间隐藏层维度分别为4×768,4×1024,先升维再降维。

Q:为什么bert是双向的?

因为语言模型训练方式的缘故,GPT根据上文预测下文,因此是单向的,而bert采用了MLM预训练任务根据上下文预测mask位置,因此是双向的。参考 how the model reflect ‘bidirectional’?

Q: bert这种masked language model 预训练的收敛速度相比left-to-right language model快还是慢?

慢,自己猜测的原因:因为15%的token被随机mask,需要随机很多次才能遍历完,需要更充分的迭代。

Q:为什么用[CLS] token作为整个句子的表示参与最终的分类?

[CLS] token是给任意的句子添加在句首的dummy token,与位置无关。最主要的是经过了多层attention之后,融合了句子的上下文信息。如果选用n-th token则与位置有关,并且需要考虑句子长度是否小于n的问题。

Q:BERT与Transformer的区别 [14]

  • BERT 是个语言模型,无监督预训练+有监督微调下游任务;Transformer则直接用于具体任务。

  • BERT 仅采用了 encoder 部分,没有Transformer decoder中的循环连接。原因:预训练采用masked language model,是一个用上下文去推测中心词[MASK]的任务,和Encoder-Decoder架构无关,只需要Encoder做特征提取器,不需要Decoder解析序列输出结果。而在微调任务中采用了encoder的编码表示来做分类等下游任务,对于机器翻译等下游任务,可以继续添加decoder来微调训练。

  • 输入编码:原始 transformer 仅采用 word embeddings 和 positional encodings. BERT 额外采用了 segment embeddings,并且设置输入的三种embedding均可学习更新。为什么用[SEP]分隔句子了还要用segment embeddings,并且还是可学习的?用于区分token是属于哪个句子,主要用于NSP任务(这个任务是否有必要存在争议,这个embedding可能作用不是很大)。1)[sep]没有直接被用到可能比segment embeddings作用弱。2)与位置编码类似,设置成可学习的不影响效果,统一学习有可能取得更好的结果。 segment embeddings限制只有0、1两种取值,而其它可以是浮点数,这三个embedding lookup table分别更新。[15][16]

不重要的区别包括

  • 超参数,如multi head数量,bert:12、16 ,Transformer 8;Hidden Size 768 feedforward networks的单元数量。

Q:为什么对三个输入向量直接相加而不是concat方式

首先,相加是对同一token的三个embedding相加,这其实等价于三个one-hot concat之后乘以lookup table得到的向量。本质可以看作一个特征的融合,随着模型越来越深,相加后的向量在高维空间中又变成了可分的。

在实际场景中,叠加是一个更为常态的操作。比如声音、图像等信号。一个时序的波可以用多个不同频率的正弦波叠加来表示。只要叠加的波的频率不同,我们就可以通过傅里叶变换进行逆向转换。

一串文本也可以看作是一些时序信号,也可以有很多信号进行叠加,只要频率不同,都可以在后面的复杂神经网络中得到解耦(但也不一定真的要得到解耦)。在BERT这个设定中,token,segment,position明显可以对应三种非常不同的频率。

参考:为什么 Bert 的三个 Embedding 可以进行相加? – 知乎

Q:为什么在inference阶段调换两个句子的顺序作为输入时会得到不同的输出?

因为inference时每个位置的segment embedding、position embedding是固定不变的,但是调换两个句子的位置之后 token embedding发生变化,三个向量之和发生了变化。

Q:BERT 计算文本相似度的方法,及效果不好有什么改进方法

Bert 模型的做句向量的缺陷及解决办法

获取句向量,计算cosine距离,BERT 句向量的获取方式有:

  • 取最后一两层的 embedding 的各单词的平均
  • 直接用[CLS]对应的 embedding

效果不好原因:

简单来说,直接使用 Bert 做句向量的输出,会发现所有的句向量两两相似度都很高。

1、因为对于句子来说,大多数的句子都是使用常见的词组成的。
2、Bert 的词向量空间是非凸的,大量的常见的词向量都是在 0 点附近,从而计算出的句子向量,都很相似。

对于词向量平均法而言,语句越长分出的词多,信息量越杂,重要的词的信息会在平均的过程中极大的被消弱, 从而分类效果差。

更深层次的说法:

一、BERT 句向量的空间分布是不均匀的,受到词频的影响。因为词向量在训练的过程中起到连接上 下文的作用,词向量分布受到了词频的影响,导致了上下文句向量中包含的语义信息也受到了破坏。

二、BERT 句向量空间是各向异性的,高频词分布较密集且整体上更靠近原点,低频词分布较稀疏且 整体分布离原点相对较远。因为高词频的词和低频词的空间分布特性,导致了相似度计算时,相似度过高 或过低的问题。在句子级:如果两个句子都是由高频词组成,那么它们存在共现词时,相似度可能会很高 ,而如果都是由低频词组成时,得到的相似度则可能会相对较低;在单词级:假设两个词在语义上是等价的,但是它们的词频差异导致了它们空间上的距离偏差,这时词向量的距离就不能很好的表征语义相关度 。

解决办法:

  1. 使用双塔的形式,将两个句子传入两个参数共享的 Bert 模型,将两个句向量做拼接,进行有监督的学习,从而调整 Bert 参数。此方法叫 Sentence-Bert:在微调的时候直接把损失函数改写为余弦相似度,然后采用平方损失函数(MSE)。关于余弦相似度该配合使用什么损失函数没有定论,可以用CE、MSE、1-cosine值等。

  2. 线性变换进行句向量校正:BERT-flow、BERT-Whitening。这两者更像是后处理,通过对 BERT 提取的句向量进行某些变换,从而缓解各向异性问题。

    BERT-Flow:利用标准化流(Normalizing Flows)将 BERT 句向量分布变换为一个光滑的、各向同性的标准高斯分布。

    苏剑林提出:简单的BERT-whitening线性变换直接校正句向量的协方差矩阵就能取得跟BERT-flow媲美的结果。同时,BERT-whitening还支持降维操作,能达到提速又提效的效果。参考 你可能不需要BERT-flow:一个线性变换媲美BERT-flow

  3. 对比学习:SimCSE。 对比学习的思想是拉近相似的样本,推开不相似的样本,从而提升模型的句子表示能力。无监督SimCSE的方法:将同一个句子两次传入同一个带dropout的 bert(dropout = 0.3)得到句子对(同一个句子的不同表示),设置标签为正例;不同句子设置标签为负。 通过这种训练样本对 Bert 微调。其本质是利用 Dropout 进行数据增广。refer 2021 NLP 比较火的论文 《SimCSE: Simple Contrastive Learning of Sentence Embeddings》

Q:如何处理长文本预料?

对于长文本,常见的处理方式有:截断和切分。
截断:一般来说文本中最重要的信息是开始和结尾,因此文中对于长文本做了截断处理。

head-only:保留前 510 个字符

tail-only:保留后 510 个字符

head+tail:保留前 128 个和后 382 个字符

切分: 用sliding window将文本切片,独立放进去BERT得到[CLS]的表示,所有[CLS]再进行融合。融合方式有:

Max-pooling, Average pooling 和 self-attention,以及复杂点的叠加Transformer。

模型层面的改进处理长文本:Transformer-XL, sparse Transformer, Longformer, Reformer等。

参考:Bert 如何解决长文本问题?

Q:如何加速Bert模型的训练。

BERT 基线模型的训练使用 AdamW(Adam with weight decay,Adam优化器的变体)作为优化器。

可用LAMB优化器来提高并行训练能力,LAMB 是一款通用优化器,它适用于小批量和大批量,且除了学习率以外其他超参数均无需调整。LAMB 优化器支持自适应元素级更新(adaptive element-wise updating)和准确的逐层修正(layer-wise correction)。LAMB 可将 BERT 预训练的批量大小扩展到 64K,且不会造成准确率损失,76分钟就可以完成BERT的训练。

下游任务

Q:微调的方式

在预训练模型的最后添加一层额外的输出层(分类层,一般为全连接层+softxax层),对于不同的任务采用不同的设计。在预训练完成之后对于子任务仅需要少量的参数进行学习。

BERT在11项NLU任务上取得更优的结果,这些任务可归类为四大类NLP下游任务,分别是 句子对分类任务、单句子分类任务、问答任务、单句子标注 任务,如下图所示:

BERT下游任务

  • 对于单、双句句子分类任务,在[CLS]token位置的输出进行分类。

  • 对于问答任务,属于token级任务。将答案段落(text_b)对应的所有token向量接全连接层,每个token输出维度为2(表示答案的起止位置start, end)。根据每个token预测起止位置与真实答案起止位置之间的平均差值计算loss。通过取所有token中softmax概率最大的作为最终预测的起止位置。

  • 单句标注任务,同属于token级任务,与问答任务类似,也用全连接+softmax作为输出层,每个token进行多分类(BIOX,B表示实体开头,I表示在实体内部,O表示非实体,X用于标注英文单词分词之后的非首单词)。

  • 注:未用于机器翻译等NLG任务,仅用encoder不容易取得显著效果。

Q:Bert 模型适合做什么任务,不适合做什么任务?

  1. 适合:Bert 模型是 Transformer 的 encoder,适合做情感分类、文本分类、意图识别、命名实体识别、句子是否相似、句子是否有被包含、半指针半标注的 SPO 三元组抽取、问答等任务。

  2. 不适合:Bert 未包含 decoder,不能做任何生成式的任务。比如翻译、文本摘要、问题生成等 seq2seq 任务。当然有些后续工作已经在尝试用于机器翻译等任务,但可能还没取得显著成效。参考 如何使用BERT模型应用到机器翻译任务中?

Q:如何做文本摘要?

自动文本摘要的一种简单形式是抽取式摘要:从一篇文章中抽取几个句子(段落),将每个句子做二分类判断是否用作摘要。

论文 Fine-tune BERT for Extractive Summarization 给出了一种模型结构方法,将多个句子同时输入模型,在输出上接二分类的线性层预测每个句子。对于BERT输入的改造方式比较简单:

  • 每个句子开头加[CLS]用于每个句子的分类。
  • segment embedding采用A、B交替式:ABABA…。

由于BERT对超长文本不易训练,采用XLNet会更好一些,参考XLNet。

激活函数-GELU

在FFN中采用gelu,与GPT一致。gelu的函数形式,参考我的博客-激活函数

RELU及其变种与Dropout从两个独立的方面来决定网络的输出,有没有什么比较中庸的方法把两者合二为一呢?在网络正则化方面,Dropout将神经单元输出随机置0(乘0),Zoneout将RNN的单元随机跳过(乘1)。两者均是将输出乘上了服从伯努利分布的随机变量m ~ Bernoulli(p),其中p是指定的确定的参数,表示取1的概率。

然而激活函数由于在训练和测试时使用方式完全相同,所以是需要有确定性的输出,不能直接对输入x乘随机变量m,这点与Dropout不同(Dropout在测试时并不随机置0)。由于概率分布的数学期望是确定值,因此可以改为求输出的期望:\(E[mx]=xE[m]\),即对输入乘上伯努利分布的期望值\(p=E[m]\)

论文中希望p能够随着输入x的不同而不同,在x较小时以较大概率将其置0。 由于神经元的输入通常服从正态分布,尤其是在加入了Batch Normalization的网络中,因此令p等于正态分布的累积分布函数即可满足。

正态分布的概率密度函数:\(f(x)={\frac {1}{\sigma {\sqrt {2\pi }}}}\;e^{-{\frac {\left(x-\mu \right)^{2}}{2\sigma ^{2}}}}\),累积分布函数:\(F(x) = \frac{1}{\sigma\sqrt{2\pi}} \int_{-\infty}^x \exp \left( -\frac{(t – \mu)^2}{2\sigma^2} \ \right)\, dt\). 正态分布的累积分布函数曲线与sigmoid曲线相似。

标准正态分布:\(X\sim \mathcal N(0,1)\),标准正态分布的累积分布函数习惯上记为\(\Phi\)\(\Phi(x)=P(X\le x)\).

因此GELU采用的激活函数为 \(g(x)=x\cdot p=x\Phi(x)\)

RoBERTa 2019

RoBERTa: A Robustly optimized BERT Pretraining approach,由Facebook团队 2019发布(同作者在同期还发布了另一篇论文SpanBERT,有很多相通的思想),发布时间晚于XLNet。

核心思想:通过改进bert的细节,更好地训练。在不大改网络结构的前提下实现了比BERT的后起之秀更好或接近的表现。

改动点:

(1)语料训练=>更多

  • 采用更大的预训练语料(BERT 16GB -> 160GB),但这导致不好公平比较各模型。
  • 更大的batch size:256 -> 8K,512 -> 32k
  • 更多的迭代次数:100K -> 300K -> 500K.
  • BPE词表扩展:由30k字符级 -> 50K 字节级subword units. 对于汉字等多字节的unicode字符可能会有优势,并且不会存在任何UNKNOWN token的问题。

(2)预训练模型=>精简、改进

  • Dynamic Masking,动态改变训练数据的掩码模式,不像bert那样预先对训练集生成固定mask。原始BERT实现方式是预先增加了随机掩码的模式,如对每条训练样本复制10次,创建10种不同的随机掩码,迭代40个epoch,平均每个模式被4个epoch共用。而RoBERTa的Dynamic Masking是完全的随机(动态,每次迭代时不同)。但是并没有带来特别显著的提升,我觉得原始BERT可能就是为了实现简单、方便复现,没有采用每次随机的方式。
  • 去掉NSP任务,因为之前就被指出NSP带来的提升不显著,作者通过对比实验发现去掉NSP效果还能更好,并指出BERT原论文中写的去掉NSP指标大幅下降的可能原因是输入数据格式的问题,没有将SEGMENT-PAIR格式改为DOC-SENTENCES
  • 文本长度设置:取消 BERT中前90%次迭代采用128长度的短文本,后10%采用512长文本的设置,统一用512长文本。
参数\模型 Bert RoBerta
Batch_size 256 2K、8K或更高(受内存/显存限制)
训练数据 13G(Bert Large) 16G、160G
训练步数 1M 125K、31K
是否有 NSP
Mask 方式 static mask(静态 mask) dynamic(动态 mask)
text Encoding 基于 char-level 的 BPE 基于 bytes-level 的 BPE

Transformer-XL 2018

Transformer的Attention机制虽然理论上可以适用于任意长度的文本,但是受限于内存和计算资源限制,往往只能采用较小的长度值,比如512。传统的长文本处理方式可能有:

  • 对于长文本进行分段处理,但是很难准确的分句和分段。本来具有上下文联系的文本可能被分到两段,导致上下文信息不能接续。
  • 滑动窗口,采用固定长度的左侧窗口文本预测当前token,这种方式比分段方式好在可以维持固定长度的上下文信息。但由于窗口文本随时刻变化,每个时刻都需要用Transformer计算一次,计算性能很差。

Transformer-XL 设计了一种片段循环机制结合了上边的两点,对每个片段的计算结果进行cache,在计算当前片段时利用前边窗口内cache的结果与当前片段拼接起来计算Attention。对于cache的部分不会重复计算,在反向传播时,cache里的内容也不参与梯度的计算。

相对位置编码

由于Transformer-XL对长文本进行了分段,这样不能采用Transformer(三角函数固定初始化)或BERT(可学习位置编码)中的“绝对“位置编码方式,因为无法从编码上区分出文本属于哪一段。

为了解决这个问题,Transformer-XL引入了”真正”的相对位置编码方法。它不是把位置信息提前编码在输入的Embedding里,而是在计算attention的时候根据当前的位置和要attend to的位置的相对距离来”实时”告诉attention head。采用了和Transformer中的三角函数式编码,不可学习。详情见后文“相对位置编码”对比部分。

XLNet 2019

XLNet: Generalized Autoregressive Pretraining for Language Understanding(NeurlPS 2019)

关键点:

  • Permutation Language Model:和语言模型相比,XLNet最大的优势就是通过输入序列的各种排列,同时学习到上下文的信息。
  • Transformer-XL,解决长文本的问题

核心与借鉴思想:

(1)XLNet核心思想

仍使用语言模型,但是为了解决双向上下文的问题,引入了排列语言模型。

排列语言模型在预测时需要target的位置信息,因此通过引入Two-Stream,Content流编码到当前时刻的所有内容,而Query流只能参考之前的历史以及当前要预测的位置。

最后为了解决计算量过大的问题,对于一个句子,我们只预测后面的1/K的词。

(2)Transformer XL 借鉴思想

XLNet借鉴了Transformer XL的主要思想来处理长文本:

  • Transoformer-XL的分段cache隐状态的思想。
  • Transoformer-XL的相对位置编码。

参数设置:

XLNet-Large采用了和BERT-Large一样的超参数,从而得到类似大小的模型。序列长度和cache分别设置为512和384。

AR与AE语言模型

目前主流的nlp预训练模型包括两类 autoregressive (AR) language model 与autoencoding (AE) language model。

  • AR是常规的单向语言模型,比如open AI提出的GPT、GPT2.0就是采用的AR模式。
  • AE模型采用的是以上下文的方式,最典型的成功案例就是bert,通过Masked Language Model实现上下文编码。

但 Masked Language Model 存在预训练和微调数据不统一的问题,并且其条件独立的假设——那些被MASK的词在给定非MASK的词的条件下是独立的并不总是成立。比如“New York”两个token经常连续出现,只mask掉其中一个不满足条件独立假设(ERNIE通过将词扩大到实体和短语来解决这个问题)。

XLNet从其它角度来引入上下文,依然采用AR模式。XLNet 设计了 Permutation Language Model 来利用上下文,同时避免mask的问题。其思想受NADE(一种生成模型)的启发。

Permutation LM

思想:对原序列打乱顺序生成多种乱序序列(设序列长度为T,一共有 \(T!\) 种可能)再按单向语言模型的方式训练,这样语言模型能够学习各种排列顺序下通过上文预测下文的方法,而“上文”实际可能是原序列里的下文,因此能够学习到各种上下文。排列语言模型的目标是调整模型参数使得下面的似然概率最大:

\[\underset{\theta}{max} \mathbb{E}_{z \sim \mathcal{Z}_T}[\sum_{t=1}^Tlog p_\theta(x_{z_t}|\mathbf{x}_{z_{<t}})]
\]

因为 finetuning 的时候只能按原本的自然顺序,所以在预训练时未真正打乱原序列输入,而是采用Attention mask来实现(对每种排列生成一个mask方阵,在计算Attention时使用,可参考后文UniLM中Attention mask的设计思路,这里先忽略),位置编码仍按原序列顺序。

Permutation LM 存在没有目标(target)位置信息的问题

由于将原序列打乱顺序,在预测乱序序列中由上文预测当前词时无法得到当前待预测词是原序列中哪个位置的词。虽然在输入时添加了位置编码,但传统LM不使用当前待预测词的位置编码。而在原始LM中是按顺序的,能够推断出当前词的位置。而缺失位置信息会怎样?导致不同的序列可能有相同的预测。比如两个原始序列ABCD与ABDC,其排列组合构成的集合是相等的,如果打乱顺序后均采用了ABCD这个顺序进行预测,那么C、D将得到相同的预测概率值,但在原始序列中应当有不同的概率值。这样导致模型无法学到有效的表示。

既然由于打乱顺序导致位置信息丢失,那么可以显式将当前待预测词在原序列中的位置告诉网络(好比是给原本的位置信息打补丁)。论文中提出来新的分布计算方法,来实现目标位置感知:

\[p_{\theta} (X_{z_t}=x | x_{z_{<t}}) = \frac{\exp(e(x)^Tg_{\theta}(x_{z_{<t}},z_t))}{\sum_{x’} \exp(e(x’)^Tg_{\theta}(x_{z_{<t}},z_t))}
\]

其中e(x)是x 的embedding,\(g_{\theta}(x_{z_{<t}},z_t)\) 是上文的表示embedding,并且把位置信息 \(z_t\) 作为了其输入。

论文对于\(g_{\theta}(x_{z_{<t}},z_t)\)的实现采用了masked attention,提出了 Two-Stream Self-Attention 双流自注意力方法。在位置\(z_t\)来从context \(x_{z<t}\)里通过Attention机制提取需要的信息来预测这个位置的词。那么它需要满足如下两点要求:

  • 为了预测 \(\mathbb x_{z_t}\)\(g_θ(x_{z<t},z_t)\)只能使用位置信息\(z_t\)而不能使用内容信息 \(\mathbb x_{z_t}\)
  • 为了预测\(z_t\)之后的词,\(g_{\theta}(x_{z_{<t}},z_t)\) 必须编码 \(\mathbb x_{z_t}\)的信息(语义)。

但是上面两点要求是矛盾的,不能用一种\(g_{\theta}(x_{z_{<t}},z_t)\) 来实现,对于普通的Transformer来说是无法满足的。

论文在标准的Transformer Decoder之上采用两种Attention,分别编码两个隐状态:

  • 内容隐状态\(h_θ(x_{z<t})\),简写为\(h_{z_t}\),既编码上下文(context)也编码 \(\mathbb x_{z_t}\)的内容。初始化为词的Embedding \(e(x_i)\)
  • 查询隐状态\(g_{\theta}(x_{z_{<t}},z_t)\),简写为\(g_{z_t}\),它只编码上下文和要预测的位置\(z_t\),但是不包含 \(\mathbb x_{z_t}\)。初始值随机初始化。

从m=1到第M层,逐层计算:

\(g_{z_{t}}^{(m)} \leftarrow\) Attention \(\left(Q=g_{z_{t}}^{(m-1)}, K V=h_{z_{<t}}^{(m-1)} ; \theta\right)\) Query流, 可以使用 \(z_{t}\) 但不能用其内容

\(h_{z_{t}}^{(m)} \leftarrow\) Attention \(\left(Q=h_{z_{t}}^{(m-1)}, K V=h_{z_{\leq t}}^{(m-1)} ; \theta\right)\) Content流, 同时使用 \(z_{t}\)\(x_{z_{t}}\)

训练时两个流的网络权重共享。在最终预测 \(p_{\theta} (X_{z_t}=x | x_{z_{<t}})\) 时采用最后一层的query表示:\(g_{z_{t}}^{(m)}\)

当将这种双流自注意力Permutation LM 预训练模型用在finetune阶段时,只采用content stream即可,不需要计算query stream。

双流自注意力模型的计算过程示意图如下:

双流自注意力

Partial Prediction 加速计算:Permutation LM的排列组合太多,为了提高计算速度,XLNet选择仅预测靠后位置的token,而忽略对靠前位置的token的预测。因为前面的词的上下文信息相对较少,很难让模型学习到很有效的模式。对于前面不用预测的token,不需要计算其Query流,从而能够减少计算,同时节省内存。

预训练时仅采用了Permutation LM,而去除了Next Sentence Prediction,作者发现该任务对结果的提升并没有太大的影响。虽未采用NSP任务,但是采用类似的输入格式:A [SEP] B [SEP] [CLS],将CLS放在最后是Partial Prediction只预测靠后位置的token的原因。NSP的格式可以处理QA问答等类型的数据,在下游任务中常常被使用。

相对Segment编码

在BERT的NSP格式数据输入时采用了segment编码来区分句子(属于A还是B),但如果调换句子顺序,编码发生改变会导致预测结果发生变化。为避免这个问题,XLNet采用相对Segment编码,与相对位置编码类似,将编码移到了计算Attention的时候而不是提前在输入的时候。对于两个token的segment编码,只需关心它们是否属于同一个句子,而不关心绝对值(属于哪个句子)。设在同一个句子时采用编码 \(s_{ij}=s_+\),否则 \(s_{ij}=s_−\)。计算一个新的attention score:\(a_{ij}=(q_i+b)^Ts_{ij}\)。这里的 \(q_i\) 是第i个位置的Query向量,b是一个可以学习的bias。最后把这个attention score加到原本的Attention score里。

参考:XLNet原理 – 李理的博客


SpanBERT 2019

SpanBERT: Improving Pre-training by Representing and Predicting Spans(TACL 2020.)

这篇Facebook AI Research 2019的论文对 Span Mask 方案 进行了很细节地探索,主要包含两点改进:

  • 随机mask一段连续文本,展示了随机遮盖连续一段字要比随机遮盖掉分散的字效果好。

  • 加入 Span Boundary Objective (SBO) 训练目标,更好地预测被遮盖的文本,增强了 BERT 的性能。

遮盖(span)的设置方式:从几何分布\(\ell \sim \operatorname{Geo}(p=0.2)\) s.t. \(\ell_{\max }=10\))中采样1~10作为span长度(拒绝采样法拒绝超过10的数字,实现时采用迭代随机采样,每次有p=0.2 的几率继续扩展Span, 1−p=0.8 的几率停止扩展Span);从均匀分布采样起始位置。并确保总是遮盖完整的词,即避免出现子词(subwords)被切割到两部分的情况。

几何分布,是一种长尾分布。参考:几何分布 – 维基百科

几何分布(Geometric distribution)指的是以下两种离散型概率分布中的一种:

  • 伯努利试验中,得到一次成功所需要的试验次数XX的值域是{ 1, 2, 3, … }
  • 在得到第一次成功之前所经历的失败次数Y = X − 1。Y的值域是{ 0, 1, 2, 3, … }

实际使用中指的是哪一个取决于惯例和使用方便。在这里我们用从1开始的形式,每次试验的成功概率是p,第k次才得到成功的概率是:

\(P(X=k)=(1-p)^{k-1}p\), k取无穷极限时数学期望是 1/p

由于SpanBERT中采用了拒绝采样法采样1~10,span长度的期望并非 1/p = 5,而是需要考虑排除超过10的概率 \((1-p)^{10}\). 设 \(q=1-p\),那么拒绝采样取到长度为k的概率是:\(P(X=k)={q^{k-1}p \over 1-q^{10}}\).

即 span 长度为 1 的概率是 \(p/(1-q^{10})=0.224\),span 长度的期望是 \(p(1+2q+3q^2+…10q^9)/(1-q^{10}) = 3.797\)

实现:仿照原BERT中的参数设置对随机的15%的token进行mask(在其中80%用[M]替换,10%用随机词替换,10%不变)。SpanBERT与之类似,只是在随机生成span mask的时候需要控制下token的总数量,对每个span中的连续token替换成[M]或采样的随机词。

实验表现:随机的span方式略胜出于WWM或ERNIE中引入命名实体外部知识masking方法,或许可以说明引入类似词边界信息不是特别需要。当然由于不太好公平地对比模型,说服力不足。

论文继续设计了一个利用边界和位置编码来对mask进行预测的任务损失函数,能够提升指代消解等任务的表现。

具体做法是,在训练时取 Span 前后边界之外的两个词的向量加上 Span 中被遮盖掉词的位置向量,来预测原词:\(\mathbf{y}_i =f \left(\mathbf{x}_{s-1} , \mathbf{x}_{e+1} , \mathbf{p}_{i-s+1}\right)\), 其中位置编码采用的第i个待预测词\(x_i\)相对于左边界\(x_{s−1}\)偏移位置编码,即第 $ i-(s-1)$ 个位置对应的位置编码。应该还是采用的原BERT或Transformer的绝对位置编码,而不是XLNet等模型中采用的相对位置编码实现方式。

\(f(\cdot)\) 函数具体用的是BERT的FFN结构来实现:

\[\begin{aligned}
\mathbf{h}_{0} &=\left[\mathbf{x}_{s-1} ; \mathbf{x}_{e+1} ; \mathbf{p}_{i-s+1}\right] \\
\mathbf{h}_{1} &=\operatorname{Layer} \operatorname{Norm}\left(\operatorname{GeLU}\left(\mathbf{W}_{1} \mathbf{h}_{0}\right)\right) \\
\mathbf{y}_{i} &=\operatorname{Layer} \operatorname{Norm}\left(\operatorname{GeLU}\left(\mathbf{W}_{2} \mathbf{h}_{1}\right)\right)
\end{aligned}
\]

然后这个SBO任务和MLM一样通过交叉熵计算损失并求和:

\[\begin{aligned}
\mathcal{L}\left(x_{i}\right) &=\mathcal{L}_{\mathrm{MLM}}\left(x_{i}\right)+\mathcal{L}_{\mathrm{SBO}}\left(x_{i}\right) \\
&=-\log P\left(x_{i} \mid \mathbf{x}_{i}\right)-\log P\left(x_{i} \mid \mathbf{y}_{i}\right)
\end{aligned}
\]

SpanBERT 预训练任务的示意图:

SpanBERT

MLM的损失函数是怎样的?和CBOW类似,对每一个被mask的token通过输出embedding与输入的lookup embedding相乘取softmax求损失,然后计算所有mask token的平均值。参考BERT源码run_pretraining.py中的 get_masked_lm_output 函数。

SpanBERT具体实现的一些细节同作者同时期发布的另一篇RoBerta论文:

  • 采用动态mask(Dynamic Masking
  • 取消 BERT 中随机采样短句的策略:取消 BERT中前90%次迭代采用128长度的短文本,后10%采用512长文本的设置,统一用512长文本。
  • 去除NSP任务,1)句子对的引入限制了单句最长文本长度. 使用单句训练, 最长文本长度可以直接翻倍. 2)句子对上下不相关时, 会引入非常大的噪声.

参考:SpanBert:对 Bert 预训练的一次深度探索 – 知乎

StructBERT 2019

StructBERT: Incorporating Language Structures into Pre-training for Deep Language Understanding(ICLR 2020. 阿里2019.9)

之前的BERT、RoBERTa等模型虽然主要集中解决自然语言理解(NLU)问题,但仍然没有把语言结构信息集成进去。

StructBERT对原始BERT进行了扩展,在单词和句子级别应用语言结构,新增两个辅助任务: word-level ordering and sentence-level ordering ,使其能够注意到句子中的结构信息的变化。具体方式为通过打乱单词和句子的顺序,让模型学习单词和句子的原始顺序(较流利的表达方式)。这两个辅助任务分别体现在MLM、NSP任务上:

  • Word Structural Objective:随机选择一些长度为K的子序列打乱单词顺序,通过Transformer的编码表示预测对应位置原本的单词,通过极大似然估计:\(\arg \max _{\theta} \sum \log P\left(\operatorname{pos}_{1}=t_{1}, \operatorname{pos}_{2}=t_{2}, \ldots, \operatorname{pos}_{K}=t_{K} \mid t_{1}, t_{2}, \ldots, t_{K}, \theta\right)\)。为达到模型鲁棒性和模型重建能力的平衡,论文设定K=3,采样5%的三元组做随机打乱。该任务与原始MLM进行联合训练
  • Sentence Structural Objective:原始BERT的NSP任务过于简单,能够很轻易达到 98% 左右,在RoBERTa等方法中未被使用。而通过增加该任务的难度还是能够对于预训练模型有帮助的,具体方式为将NSP改为三分类:下一句、上一句、负例(其他文档的随机一句),等概率抽样三部分的样本。相当于将NSP任务与“PSP”任务结合起来。这个思路比ALBERT的段落连续性任务(调换顺序作为负例)更高级一些,比ERNIE2.0的Sentence Reordering Task低级。

这两个辅助任务都属于排序任务,但在实现方式上做了简化,两类任务的图示如下:

StructBERT

MASS/BART 2019

MASS: Masked Sequence to Sequence Pre-training for Language Generation (ICML 2019,微软)

前面提到的GPT、BERT各有特点,但是应用受限:

  • GPT采用decoder、单向、生成式;
  • BERT采用encoder、双向、判别式。

微软的 MASS 用seq2seq框架结合了BERT与GPT的思想,能够应用于机器翻译、对话等 seq2seq 任务。在encoder中对部分子序列片段进行mask,在decoder中利用encoder的输出对被mask的子序列进行解码预测。

不同于传统seq2seq的是,Decoder的目标为重构被mask(加噪)的文本。训练时Decoder的输入为对Encoder输入反mask之后右移一位(Teacher Forcing)的结果。至于为什么在Decoder中对于不需要预测的部分用mask来替换,作者的解释是这样能更充分利用Encoder的编码,而BART模型则未设置为mask。

MASS 结构示意图如下:

MASS

Mask策略:随机选一个位置开始(纯随机,不考虑被切割后两个子词subword分离的问题),连续mask掉句子长度50%的token(阈值是通过实验对比选定的较优值)。并且参考BERT的策略,80%的时间用[M],10%用随机的token,10%保留原token。

连续mask的长度k在两个极值情况下对应两个特例:BERT、GPT,因此MASS可以看作是对BERT、GPT的统一框架。

MASS特点:

  • Encoder和Decoder联合训练. 统一了BERT、GPT这两类单独训练Encoder或Decoder的模型。用于生成模型时相比GPT,能使Decoder从Encoder获取更多的信息。
  • 连续mask获得更好的性能(相对于原始BERT单个token级别的掩码)

MASS主要应用于机器翻译任务,相比分开预训练encoder和decoder(BERT+LM),联合训练效果要好一些。但是MASS的提升不是很显著,可能还有更好的联合训练方式。


BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension(2019.10 略晚于MASS,Facebook)

BART(Bidirectional and Auto – Regressive Transformers) 是一个和MASS类似的思想,同样采用Transformer,让Decoder解码噪声。

特点:

  • 没有采用BERT的FFN,这使得BART只比同级别的BERT多了10%的参数。
  • Encoder 添加噪声扰动的方式不受限制,容许任意的方式。

异同:

  • BERT、MASS和BART都是去噪自编码器(Denoising AutoEncoder),随机mask便是一种噪声,使用自编码器进行自学习,目标为去除噪声还原输入。
  • BART给出了除mask外的更多的噪声种类:随机删除、重排列打乱顺序、旋转字符数组、连续文本替换成一个[Mask] token,组合这些方式使得模型的学习难度可大大增加。
  • MASS对Decoder的设计比较特别,对于不需要预测的部分用mask来替换,更充分利用Encoder的编码。但是由于Encoder/Decoder采用不相交的文本集合作为输入,不利于判别式任务。而BART模型未设置为mask,给的说法是减少预训练与下游生成式任务之间的mismatch,都用不加噪声的文本作为输入。

其中连续文本替换成一个[Mask] token的方式,论文称之为 Text Infilling ,受SpanBERT的启发。但相比SpanBERT的替换为mask序列,BART仅替换成一个mask,带来的好处是能让模型学习缺失的token个数(增加学习难度)。

BART效果比MASS显著,并能取得与RoBERTa相近的结果。

下游任务:

  • 分类任务:让Encoder和Decoder以相同的数据输入, 利用Decoder的最后一次输出作为tokens或句子的表示进行分类。
  • 机器翻译:额外训练一个外语映射的Encoder,将源语言与目标语言进行语义空间对齐,替代掉原来的Word Embedding,示意图如下。训练方式为:1. 固定住BART的大部分预训练参数,仅学习额外的编码器+BART的位置编码+BART Encoder的第一层Self Attention投影矩阵。2. 原BART+额外Encoder整体训练,做少量次数的迭代。mBART多语言版的机器翻译模型。

BART机器翻译

UniLM 2019

UniLM 是与MASS同时期的微软研究院出的另一篇论文 Unified Language Model Pre-training for Natural Language Understanding and Generation(NeurIPS 2019,MSRA),自然语言理解与生成的统一预训练语言模型。代码地址:代码:unilm中文Unilm

UniLM出发点和MASS类似,也是因为BERT的MLM的双向性使得它很难应用于自然语言生成任务。但是UniLM与MASS的实现方法却截然相反,MASS将BERT MLM引入传统seq2seq,而UniLM将seq2seq的思想引入到BERT。UniLM通过修改训练时额外添加的Mask矩阵控制预测时依赖的上下文,既可以应用于自然语言理解(NLU)任务,又可以应用于自然语言生成(NLG)任务。

UniLM 在 Transformer 每层中的自注意力头输出 \(\mathbf A_l\) 表示中添加了Mask矩阵 M 来控制Attention的范围,从而能够灵活地改变模型的运行模式(单向、双向、seq2seq):

\[\begin{aligned}
\mathbf{Q} &=\mathbf{H}^{l-1} \mathbf{W}_{l}^{Q}, \quad \mathbf{K}=\mathbf{H}^{l-1} \mathbf{W}_{l}^{K}, \quad \mathbf{V}=\mathbf{H}^{l-1} \mathbf{W}_{l}^{V} \\
\mathbf{M}_{i j} &=\left\{\begin{array}{ll}
0, & \text { allow to attend } \\
-\infty, & \text { prevent from attending }
\end{array}\right. (M\in \mathbb R^{|x|×|x|}) \\
\mathbf{A}_{l} &=\operatorname{softmax}\left(\frac{\mathbf{Q} \mathbf{K}^{\top}}{\sqrt{d_{k}}}+\mathbf{M}\right) \mathbf{V}_{l}
\end{aligned}
\]

unilm

输入表示:为统一NLU、NLG,在输入表示上对文本段添加起始和结束token标志:[SOS]、[EOS]. 在NLU任务上对应BERT的 [CLS]、[SEP],其中[EOS]作为NLU任务的边界标记,NLG任务的生成结束标记。

模型结构:UniLM的巧妙之处在于使Encoder和Decoder共享权重,实际上合并成一个Encoder或Decoder(姑且称这个掩码矩阵控制的编解码器为”X-coder”吧,相比Transformer去除了Encoder-Decoder间的跨层Attention连接),这样与BERT(Encoder)的结构完全兼容,能够使用BERT的预训练权重做初始化(论文从BERT-large初始化)。

预训练:包括unidirectional, bidirectional, sequence-to-sequence prediction三种,均采用BERT的MLM训练方式,对于bidirectional单独再添加了NSP任务。对于单向LM而言仅能用左边/右边的tokens预测被mask的词,seq2seq模式则是双向LM(对应 \(S_1\) encoder部分)与单向LM(对应 \(S_2\) decoder部分)的组合。

具体地,在一个训练batch中,(1)使用1/3的数据进行双向语言模型优化,(2)1/3的数据进行序列到序列语言模型优化,(3)1/6的数据进行从左向右的单向语言模型优化,1/6的数据进行从右向左的单向语言模型优化。这种multi-task learning方式与常规的方式(batch所有数据计算所有任务的loss按权相加)应该没有本质的不同。

模型对比:

  • 统一方式:UniLM具有和BERT相同的结构,这种统一方式相比MASS/BART更为简介,在做下游任务时不需要考虑丢弃Encoder/Decoder的问题。当然这种“权重共享”的方式相比非共享的Encoder-Decoder,在机器翻译等任务上可能表现较差。
  • 预训练任务:UniLM利用了多种任务联合训练,而MASS仅有MLM一种。

UniLM-v2 论文 UniLMv2: Pseudo-Masked Language Models for Unified Language Model Pre-Training(ICML 2020),译为伪掩码语言模型预训练的统一语言模型,是MSRA对前作UniLM的改进。UniLM通过Self Attention Masks将AE、AR、Seq2seq统一到一个模型结构中进行联合训练,但每个任务(加上NSP是4个任务)的输入数据格式不同(有无mask、单双多句),均需要经过encode,整体预训练耗时较高。UniLMv2将预训练任务数缩减为两个(AE、PAR),并统一为相同的输入,实现了encode的重复利用。

  • 自编码任务(autoencoding, AE):普通的MLM,预测每个mask掩码时是互相独立的。

  • 自回归任务(autoregressive, AR):在XLNet部分介绍过自回归(AR)任务,前一个预测结果会被用于预测下一个结果。UniLMv2为了统一AE与AR的输入数据格式,(1)借鉴了XLNet的Permutation LM的思想通过打乱AR的预测顺序实现双向的编码;(2)加入了[Mask]使其与MLM格式兼容,并且修改了预测目标,仅预测被mask的token,而不像传统LM那样预测连续的每一个token。极大似然估计也改为基于所有非mask文本预测按指定顺序自回归预测被mask的tokens。和XLNet不同的是,PAR只对mask打乱顺序,而非mask token保持原顺序;而XLNet则没有采用mask做训练,全部token打乱顺序。(3)对AR引入mask后带来的一个问题是当某个mask token在某一步被预测之后需要替换成预测值再被用于预测后续的mask token,这个替换过程不易实现,可能会影响训练速度。为解决这一问题,作者巧妙地设计了一个伪掩码语言模型(PMLM),在做数据预处理时并不直接将原token替换为[Mask],而是改成在原token之后(或之前)插入[Mask]、[Pseudo]这两个token,并且使其与原token共享同一个位置编码,称这两个掩码token为伪掩码。因此该论文所述的AR任务与传统的单向LM有了较大的区别。

  • 部分自回归任务(partially autoregressive, PAR):部分自回归任务是在上述修改后的AR任务上像SpanBERT那样对连续的token span进行掩码后预测,对于一个span内的多个token可以做独立并行预测,因此称为部分自回归。

    参数设置:在掩码中设置40%的比例采用n-gram的span mask(\(n\sim U[2, 6]\))。

为了统一AE、PAR任务的输入,论文设计了如下的伪掩码语言模型(PMLM):

PMLM

图中待预测的排列组合顺序为 4, 5 → 2,其中4,5处于同一个span mask。在输入编码上AE、AR表现为先后的关系,左半部分(浅蓝色部分)即常规的MLM,右半部分为随机的待预测掩码[P]及目标token拼接在了MLM的末尾,PAR任务作用在整个的输入上,conditioned on left 从左向右进行自回归预测。其中[P]仅用于PAR任务,conditioned on 左侧的原始token及[M].

和XLNet类似,在实现上图所示的模型时并不真正地在预处理数据时打乱顺序,而是通过Attention Mask来设置顺序。

Attention Mask

共享位置编码的设计使得PAR任务中的[M]、[P]与MLM任务中的[M]无异,通过Attention Mask来控制条件,使得[M]、[P]容易被替换为原token。

UniLMv2

模型对比:UniLMv2相比v1,

  • 缩减任务数量为AE+AR,通过伪掩码统一了输入格式,使得两个任务共享前向计算。模型结构更加统一、训练更加高效。
  • 通过span mask,鼓励学习长距离的依赖关系。

实验结果表明,PMLM提高了多种语言理解和生成基准的最终结果。在问题生成和文章摘要抽取等任务上,\(\text{UniLMv2}_{BASE}\) 取得了比 \(\text{UniLM}_{LARGE}\) (参数量大三倍)更好的结果。此外,与BERT兼容,可以直接采用BERT预训练权重进行初始化,即便不继续做预训练调整直接在下游的生成任务上做finetune,也能取得不错的效果。

参考:

T5 2019

Text-to-Text Transfer Transformer (T5)Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer (JMLR2020)

Google 出品的预训练模型,提出了NLP迁移学习的新思路:将每个NLP 问题看作 text-to-text 任务。其理念为“万事皆可Seq2Seq”。

  • 对于监督任务通过在原始输入文本添加前缀来区分任务,如:“translate English to German:”, “summarize:”。这种转化跟 GPT-2、GPT-3、PET 的思想一致,用文字把要做的任务表达出来,然后都转化为对文字的预测,即通过给模型一个提示(prompt)让模型按生成模型的方式来生成答案。

  • 对于无监督任务,如MLM的Seq2Seq模式可以是下面这样,和MASS模型的输入格式也类似,mask后的文本是encoder的输入,decoder 输出重建文本。

    输入:明月几时有,[M0] 问青天,不知 [M1],今夕是何年。我欲[M2]归去,唯恐琼楼玉宇,高处 [M3];起舞 [M4] 清影,何似在人间。

    输出:[M0] 把酒 [M1] 天上宫阙 [M2] 乘风 [M3] 不胜寒 [M4] 弄 [END]

模型:Text-to-Text Transfer Transformer (T5),大模型11B( 110 亿)参数。 和Transformer一样同时采用了encoder和decoder,即标准的 Seq2Seq 模式。GPT-2 则仅用了decoder。

数据:采用了比GPT-2 WebText(40GB)更大的清洗过的网页数据集 Colossal Clean Crawled Corpus (C4) (超大型干净爬取数据,750GB,在TensorFlow Datasets开放),数据与代码链接:GitHub。数据源于 Common Crawl(一个公开的网页存档数据集,每个月大概抓取 20TB 文本数据),经过多种策略清洗:只保留结尾是正常符号的行;去掉包含 Javascript 、各类编程语言的行,等等。

多国语言版 mT5: A massively multilingual pre-trained text-to-text transformer,数据集 mC4,与T5结构一致,仅数据集不同。参考:那个屠榜的T5模型,现在可以在中文上玩玩了

预训练

  • 参考SpanBERT,mask掉15%的span(固定span len=3)。ALBERT也是类似做法,但设置了不同的1-3 gram的采样概率。
  • 学习率 \(\eta =1 / \sqrt{\max(t, k_\text{warmup})}\), 前1w步warm-up设置固定学习率0.01,后边步骤按逆平方根衰减。也尝试了consine学习率,在确定最大迭代次数的前提下能得到比较好的学习结果,但因为需要频繁实验,没有都采用cosine。
  • 模型架构:Prefix LM。

Transformers 预训练模型中的三种模型架构对比:

LM架构对比

灰线表示常规语言模型中只对上文的依赖,即包含前缀mask的Attention,实线表示全连接,完全的Attention。句点.表示输出的终结符。

  1. Encoder-Decoder,原始的Transformer正是属于这种,Encoder中采用完全Attention,而Decoder中mask掉待预测的部分。
  2. Decoder,如GPT,仅用了Transformer的Decoder部分。对于text-to-text任务,将input和target拼起来作为语言模型的输入。
  3. Prefix LM,对于text-to-text任务,第2种Decoder的方式按序列预测input的部分显然没必要,增加了多余的约束。可将input和target分两部分看待,input部分采用full attention,target部分采用原Decoder 方式只看过去的信息。UniLM 模型 便是此结构。

Attention Mask的区别:

Attention Mask

Prefix LM架构,可以类比BERT(采用Encoder完全Attention)做分类的方式,BERT添加了[CLS] token来做分类,而Prefix LM可以看作是用input来预测target标签类别,只不过这里的target是纯文本,而不是one-hot编码。

相比于原始的Transformer, Prefix LM可以看作encoder和decoder共享参数,而两者之间联系的encoder-decoder attention被换成target和input之间的full attention。

This architecture is similar to an encoder-decoder model with parameters shared across the encoder and decoder and with the encoder-decoder attention replaced with full attention across the input and target sequence.

T5通过实验对比了不同的架构的表现,发现还是原始的Transformer结构表现最好,并且如果用shared方式共享encoder和decoder的参数不会使效果差太多。而Prefix LM架构会稍差一些。

T5在解码时大部分任务使用Greedy decoding,对于输出句子较长的任务使用beam search。对于 WMT translation 和 CNN/Daily Mail summarization tasks 设置 beam width = 4 ,length penalty α = 0.6 .

相对位置编码 Relative position embeddings (PE)

T5使用了简化的相对位置编码,用一个数值标量\(b_{j-i}\)而不是向量来表示相对位置信息,将数值加在attention的softmax计算公式中的logits之上,不过对mult-head的每个head设置了不同的PE,所有的层共享一套PE。在BERT中,attention公式中的(Qc + Qp) x (Kc + Kp) 包含了内容-内容、内容-位置、位置-内容、位置-位置四项组合。T5的设计思路为假设内容信息与位置信息是独立的,它们之间不应该有交互,仅利用位置-位置的交互。而后起之秀DeBERTa的相对位置编码设计思路与之恰恰相反。

不同于常规的相对位置编码的j-i截断方式,T5设置了一种分桶截断方法,128以内距离的位置越远共用编码的桶越大。

激活函数

T5在论文放出之后的代码实现中做过一次升级(版本T5.1.1,参考 released_checkpoints.md 这里的说明):

  • 预训练时关闭Dropout,而微调时开启。

  • 将Transformer的FFN中的激活函数由 ReLU 替换成 GEGLU,而BERT则是采用GELU,两个G的含义不同 门控 vs 高斯。

GEGLUGLUGated Linear Unit)激活函数的变体,源自 GLU Variants Improve Transformer (Google, 2020),将GLU中的sigmoid替换为GELU,函数形式如下(忽略bias项的书写):

\[\begin{align}
\text{GLU}(x,W,V) &= \sigma(xW) \odot xV \tag{$\text{GLU}\left(a, b\right) = a\odot \sigma\left(b\right)$} \\
\text{GELU}(x) &= x\cdot \Phi(x)=x\cdot {1\over 2}\left(1+\rm{erf}\left({x\over \sqrt 2}\right)\right) \\
\text{GEGLU}\left(x, W, V\right) &= \text{GELU}\left(xW\right) \odot xV
\end{align}
\]

GLU通过门控机制对输出进行把控,像Attention一样可看作是对重要特征的选择。其优势是不仅具有通用激活函数的非线性,而且反向传播梯度时具有线性通道,类似ResNet残差网络中的加和操作传递梯度,能够缓解梯度消失问题。

为什么?对比下sigmoid 及 LSTM中使用的 gated tanh unit (GTU) 的梯度:

\[\begin{align}
\nabla[\tanh (\mathbf{X}) \odot \sigma(\mathbf{X})] &=\tanh ^{\prime}(\mathbf{X}) \nabla \mathbf{X} \odot \sigma(\mathbf{X})
+\sigma^{\prime}(\mathbf{X}) \nabla \mathbf{X} \odot \tanh (\mathbf{X}) \tag{LSTM} \\
∇[σ(X)] &= ∇X \odot σ'(X) = ∇X \odot σ(X)(1-σ(X)) \tag{sigmoid} \\
∇[X \odot σ(X)] &= ∇X \odot σ(X) + X \odot σ'(X) \tag{GLU} \\
\end{align}
\]

由于 sigmoid和tanh的导数会downscaling,导致梯度消失问题。而GLU相比sigmoid多出一个线性乘积项,梯度中的\(∇X \odot σ(X)\) 不会对 σ(X) downscaling,因此能够加速收敛。

注:T5 没用 bias,使用的简化版的 Layer Normalization 去掉了bias,仅用缩放。因为输入归一化到0,因此后边的FFN也不再需要bias。 而Transformer、BERT中都是采用 Bias 的。采用GEGLU的FFN公式演变为:

\[\begin{align}
\operatorname{FFN}(x) &=\operatorname{relu}\left(x W_{1}\right) W_{2} \\
& \Downarrow \\
\operatorname{FFN}_{\text {GEGLU }}(x) &=\left(\operatorname{gelu}\left(x W_{1}\right) \otimes x W_{2}\right) W_{3}
\end{align}
\]

可以看出增加了一个W3的参数,参数量增加50%,但是性能提升比较显著。

除了用GELU替代GLU中的sigmoid外,还可用ReLU、Swish等,甚至取消其中的激活函数(Bilinear(x, W, V) = xW · xV),但是这些变体相比GLU差异不是很显著。

ALBERT 2019

ALBERT: A Lite BERT for Self-supervised Learning of Language Representations(ICLR 2020)

论文提出了参数更少的 BERT,可以看作是谷歌对先前提出的BERT的训练方法的bag of tricks。

ALBERT 采用了两种方式来缩减参数:

  • 嵌入矩阵分解 (factorized embedding parameterization

  • 参数共享(cross-layer parameter sharing):共享层与层之间的参数,减少模型参数。

(1)嵌入矩阵分解:缩减输入的嵌入向量(lookup table)的维度,BERT中为了简便利用ResNet那种短路连接将嵌入向量维度和后续的隐藏层维度设置成相同值便于后续的Add&Norm。但实际嵌入向量只需要能够区分每个不同的输入即可,不需要太大的向量空间。lookup table的大小为词表大小Vx向量维度E,对于BERT-base是3w x 768. ALBERT通过矩阵分解的思想,将嵌入向量维度设置为较小值(如128)再通过矩阵变换到原维度H=768(通过全连接层实现)。参数量级变化:\(O(V\times H) \rightarrow O(V \times E + E \times H)\)。量级变化显著,指标也会有一定的损失。

(2)多层参数共享:对每个encoder block(多头注意力和 FFN)共享参数,注意力层的参数对效果的减弱影响小一点。如BERT-base 12层,通过多层参数共享降低为1层的的参数量,降为原来的1/12,但不改变计算量.

其它提分点

  • 预训练用长句:BERT 在预训练的时候,为了加速,前 90% 的 steps 用长度为 128 的句子,而后 10% 的 steps 用长度为 512 的句子,来训练位置编码。ALBERT 则是反过来,90%-512,10%-128。
  • MLM 任务改进-遮挡连续词:借鉴 SpanBERT 中的方法,对 MLM 任务,每次不随机遮一个词,而是随机遮连续的多个词(n-gram 片段,n最大取3),包含更完整的语义信息。随机选用 1-gram 、2-gram、3-gram 的概率分别为 6/11,3/11,2/11。越长概率越小:\(p(n)=\frac{1 / n}{\sum_{k=1}^{N} 1 / k}\)
  • 增加预训练数据:像XLNet 和 RoBERTa 那样使用额外的预训练数据集。
  • 去掉 Dropout 层:因为共享参数降低了参数量,再使用Dropout会正则化过度。论文提到在训练到一定步数时仍未收敛,停掉了dropout。也许一开始就可以不使用?
  • 段落连续性任务修改:用 Sentence-Order prediction (SOP) 任务替代NSP任务。正例和原BERT一致,使用从一个文档中连续的两个文本段落;负例,使用从一个文档中连续的两个文本段落,但调换位置(self-supervised loss)。NSP任务的负例则是随机选的不同的文档中的段落(肯定能保证是不连续的),但是这会导致这个任务隐含”topic prediction”,任务变得简单,不利用预训练的效果。ALBERT 提出的 SOP 则是单纯地学习文本的连贯性,相比NSP在实现上也更加简单。在百度 ERNIE 2.0 里提出了更强的 Sentence Reordering Task (SRT) ,预测更多种句子片段顺序排列(相应地代码实现变复杂)。
  • 采用LAMB优化器以适应特别大的batch size,加快训练速度。

ALBERT-large相比原始BERT-large缩减了 18倍的参数量,提高1.7倍的训练速度, 取得接近的指标表现。整体来看ALBERT 只减参数(显存)不减计算量

参考:

ALBERT 详细解读

brightmart/albert_zh: 中文预训练ALBERT模型

ELECTRA 2020

ELECTRA: Pre-training Text Encoders as Discriminators Rather Than Generators(ICLR 2020,Stanford University & Google Brain,2019年最佳NLP预训练模型)

ELECTRA 是 Efficiently Learning an Encoder that Classifies Token Replacements Accurately 的缩写,论文题目和这个缩写的句子点明了论文的核心思想:MLM模型需要大量的样本采样进行训练,效率并不高(每步仅将一小部分token作为预测目标,如15%),ELECTRA提出了一种效率更高地采样方法,称为Replaced token detection(RTD)。其借鉴了GAN的思想,将本来需mask的token替换为由一个较小的生成式语言模型生成的token,然后将预训练模型当做判别模型去预测每一个token是原始值还是被替换的值(序列标注,二分类)。

相比于MLM仅预测掩码token,ELECTRA预测全部token,学习效率更高,同时也避免了下游任务与MLM训练数据格式不一致的问题(下游任务不用Mask)。MLM模型是用其它位置的文本信息预测当前位置的文本,而ELECTRA可认为是第一个有效学到用当前位置提取的信息预测当前位置的输出的模型(在BERT中被mask的token中设置了10%并不真正替换为[M],用来缓解与下游任务的不一致问题,然而会导致信息泄露)。此外,相比于MLM和GPT的AR任务这种生成式,ELECTRA预训练模型属于判别式。

模型结构

直接采用随机替换的方式让判别模型去判别会比较简单,效果不佳。可以用一个小型的MLM(如BERT-small)来对mask位置生成token,生成模型与判别模型做联合训练,通过这种方式将生成对抗网络的部分思想应用到了BERT之中,然而不是真正的对抗模型(ELECTRA≠BERT+GAN),因为对于文本这种离散型数据,不能通过轻微扰动来改变生成器,即判别器的梯度无法回传到生成模型(应用GAN到文本上比较难,参考Language GANs falling short. arXiv:1811.02549, 2018. 快速理解可参考为什么GANs不适合做NLP?)。生成器的损失函数继续用极大似然估计,而不是GAN的迭代对抗训练。这种预训练方式和CV中的Faster R-CNN目标检测网络非常像,都是two-stage,第二个stage利用到第一个stage的结果,并且交替训练两个子网络(而Faster R-CNN存在两种训练方式,一种是交替式,一种是同时联合训练。我理解的在权重共享比较少的情况下用交替式更合适)。在预训练完成之后仅用判别器做下游任务的finetune。

示意图如下:

ELECTRA

损失函数为两部分的组合,其中判别器相对较易学习,增加其权重:

\[\mathcal{L} = \min _{\theta_{G}, \theta_{D}} \sum_{\boldsymbol{x} \in \mathcal{X}} \mathcal{L}_{\mathrm{MLM}}\left(\boldsymbol{x}, \theta_{G}\right)+\lambda \mathcal{L}_{\text {Disc }}\left(\boldsymbol{x}, \theta_{D}\right)
\]

除了梯度的反向传播,还有以下几点和GAN的区别:

对比 ELECTRA GAN
输入数据 真实文本 随机噪声
训练目标 生成器学习语言模型,
判别器学习区分真假文本
生成器学习欺骗判别器,
判别器学习区分真假数据(图像)
反向传播 梯度无法从判别器传到生成器 梯度可以从判别器传到生成器
特殊情况 生成器生成真实文本时标记为判别器的正例 生成器的结果全部作为负例

接下来看下生成器怎样设计,如何训练。容易想到两种方式:

  1. 单独接一个额外的MLM到判别器之前(参数不共享),这种方式比较灵活,可选择任意大小、结构的BERT类模型。

  2. 共享同一个结构参数(参数共享),仅输入和学习目标不同。

在方式1中还可利用常见的输入embedding共享的方式,在BERT中指token embedding和位置编码。作者通过实验表明,共享输入embedding能够获得较大的提升,因为MLM会通过softmax更新整个词表,而判别器仅更新在输入中见过的token。共享完整的结构参数相比只共享输入embedding,提升不显著。因此为了灵活性,选择仅共享输入embedding的额外的生成器。

作者实验了最简单的unigram LM作为生成器(根据预料中词频的统计进行生成,无须训练),也能取得不算很差的结果。而更大型的生成器对效果反而并不好,因为当生成器预测准确的时候会作为判别器的正例,这样生成器走向两个极端,太弱或太强,都不利于判别器的训练。当生成器Transformer的层数是判别器的1/4-1/2之间时效果最好。

实验效果

能够以原1/4的算力达到和 RoBERTa、XLNet 接近的效果,在训练充分时效果更佳。效果对比:

DeBERTa 2020

DeBERTa: Decoding-enhanced BERT with Disentangled Attention(ICLR 2021,MSRA 2020.6,与UniLM有相同的作者团队)

DeBERTa 是使用了“解绑注意力”的“解码增强”的BERT。

核心点:注意力解耦(disentangled attention) 、 enhanced mask decoder

一、Disentangled attention

作者认为两个token之间的依赖关系程度不仅与字面含义有关,还与表达形式有关,表现为相对位置、顺序。如deep learning两个单词相邻与不相邻的含义可能大不相同。

在Self-Attention with Relative Position Representations中提出的相对位置编码只包含content-to-content, content-to-position两部分,作者认为引入position-to-content self-attention可使得相对位置的建模更完整。

用 Qc、Kc、Vc 表示内容向量,Qp、Kp、Vp 表示绝对位置编码,Qr、Kr、Vr 表示相对位置编码。

在原始BERT中采用(token 内容embedding+绝对位置编码)送入self-attention网络。那么attention矩阵就是通过 (Qc + Qp) x (Kc + Kp) 参与计算得到,可分离成四部分:content-to-content, content-to-position, position-to-content, position-to-position,完整包含了对称的content-to-position、position-to-content。而position-to-position由于不包含额外的内容信息,作者认为不应被使用(在T5中恰恰相反,丢掉了c2p,p2c,仅用c2c+p2p)。

延续这种思路,用相对位置编码替换绝对位置编码,但并不真正像BERT那样直接耦合相加,而是解耦成用一个单独的向量表示相对位置信息 \(P\in R^{2k\times d}\),并采用不同的投射矩阵\(W_{q,r}\)(而BERT中内容和位置共享了投射矩阵),参与和content之间的attention计算,并在所有的Transformer attention层中共享。将attention计算分离成三项,公式如下:

\[\begin{align}
Q_{c} &=H W_{q, c}, K_{c}=H W_{k, c}, V_{c}=H W_{v, c}, Q_{r}=P W_{q, r}, K_{r}=P W_{k, r} \\
\tilde{A}_{i, j} &=
\underbrace{Q_{i}^{c} K_{j}^{c \top}}_{(\mathrm{a}) \text { content-to-content }} +
\underbrace{Q_{i}^{c} K_{\delta(i, j)}^{r \top}}_{(\mathrm{b}) \text { content-to-position }} +
\underbrace{K_{j}^{c} Q_{\delta(j, i)}^{r \top}}_{(\mathrm{c}) \text { position-to-content }}
\\
\boldsymbol{H}_{o} &=\operatorname{softmax}\left(\frac{\tilde{\boldsymbol{A}}}{\sqrt{3 d}}\right) \boldsymbol{V}_{c}
\end{align}
\]

DeBERTa 将相对位置偏移编码 \(\delta\) 定义为:

\[\delta(i, j)=\left\{\begin{array}{rcc}
0 & \text { for } & i-j \leqslant-k \\
2 k-1 & \text { for } & i-j \geqslant k \\
i-j+k & \text { others }
\end{array}\right.
\]

最大相对距离设置k=512。

二、Enhanced mask decoder

用增强的 mask decoder替换原始输出的 softmax层,以预测模型预训练时候被 mask 掉的token。以此解决BERT的预训练和微调阶段的不一致问题。其包括两点改动:

  1. 在softmax层之前用绝对位置信息替代那些本该被mask但实际未mask的tokens,因为那些token以本身为条件进行预测导致信息泄露,而绝对位置信息对于区分单词、理解句子的重点有帮助。例如“a new [store] opened beside the new [mall]”,其中store和mall被mask用于预测,主题是store,显然只用上下文内容和相对位置编码是难以区分store和mall的,需要将绝对位置编码作为补充。作者实验对比了BERT式的早期添加绝对编码的方式和末期添加绝对位置编码的方式,发现后者更好一些。(关于绝对位置编码的添加位置这一块的理论分析和实验可能不太充分)
  2. 增加decoder的层数。可以将BERT最后一层Transformer block+softmax看作decoder,前边层看作encoder。DeBERTa增加了decoder的层数,并类似ALBERT进行参数共享。DeBERTa-base相对于BERT-base而言,前11层看作encoder,对最后一层复制一层作为decoder,参数量保持一致,计算量增加一层。在对DeBERTa模型进行预训练后,对11层encoder和1层decoder进行叠加,以恢复出标准的BERT-base结构进行微调。

我理解第二点改动是为了配合第一点改动,第一点可看作是将绝对位置编码插入到了最后倒数n层中,为了提升效果继续增加decoder的层数,但又需要跟其他论文同等参数量的模型做对比,采用了ALBERT参数共享的方式保持参数量不变。

Enhanced mask decoder结构示意图如下图(b)所示,将decoder中每一层的Q替换为绝对位置编码。

Enhanced mask decoder

当I=H,而且n=1时,Enhanced mask decoder就和bert decoder layer完全一样了。但I还可以是H与绝对位置编码的组合,这使得模型结构更灵活。

三、Scale-invariant fine-tuning 虚拟对抗学习

论文还提出了一个虚拟对抗学习的方法,用于微调下游任务。借鉴了CV中对抗样本学习的思想,对输入添加轻微的噪声扰动。相当于添加正则项(regularization),能够提高模型的泛化能力。

对于图像,添加随机的像素点即可。对于文本,由于是离散型数据,不便于直接扰动,但可以转而在word embedding空间中添加噪声。

然而不同word和模型的embedding向量的方差差异较大,并且模型越大方差也越大,需要添加的噪声的方差也需要加大,这导致对抗学习不稳定。容易想到的解决思路是对方差标准化(normalization),对 word embedding 进行LayerNorm使其Scale-invariant,然后再添加噪声,会稳定一些。

巧的是,这个方法的缩写SiFT恰好与CV中的SIFT(Scale-invariant feature transform)特征重名了。

在论文中SiFT仅被用在1.5B大模型上面,用于测试SuperGLUE任务,并且取得显著的提升,在未来会被继续研究。

效果

相比于RoBERTa,Disentangled attention增加了参数量(及计算量),Enhanced mask decoder增加了计算量,但DeBERTa 收敛速度更快,仅用一半预训练数据即可在众多NLP任务中超越RoBERTa-Large。通过48层1.5B参数量的模型,在SuperGLUE榜单上更是超越人类基准(89.9 vs. 89.8),2021年初取得榜首地位。

DeBERTa-Large的参数量是390M,其他的BERT、RoBERTa、XLNet模型Large版在335~355M左右。

强强联合 DeBERTa 🤝 ELECTRA

DeBERTa原版在多个任务上能够取得与ELECTRA接近或微胜的结果,在用ELECTRA提出的 Replaced token detection (RTD) 学习方式替换MLM之后可以取得更强的结果,在MNLI、SQuAD v2.0任务上base版提高2个点,large版也能提高将近1个点。这再次验证了ELECTRA方法的有效性。

参考:[细读经典]DeBERTa-使用解绑注意力的解码增强BERT

ERNIE 2019~2021

百度文心 ERNIE: Enhanced Representation through Knowledge Integration(2019.4)

通过知识集成的增强表示(ERNIE),包括以下三点:

  • 预训练数据:包括中文Wiki、百度百科、百度新闻和百度贴吧数据
  • 采用多层级Mask训练任务:基本(英文word或中文单字)、entity和phrase。思想和Whole Word Masking类似,只是把Masking的整体从词扩大到实体(entity)和短语(phrase)。对中文通过命名实体识别和分词得到实体和短语。
  • 用对话数据(贴吧)训练对话语言模型(Dialogue LM),相比NSP任务,只是变成三个句子,顺序不固定。Query和Response构成三元组数据:QRQ、QRR、QQR。这个任务与NSP任务一样有争议。

这个版本通常称为ERNIE 1.0,与BERT-wwm、RoBERTa类似未做模型结构上的根本性改变。同年清华团队也发布了一篇命名撞车的论文:ERNIE: Enhanced language representation with informative entities,同样引入了外部信息。本文暂不做介绍。

ERNIE 1.0仅从mask这一点上实现“知识融合”,还是比较浅显的。

ERNIE 2.0

ERNIE 2.0(ERNIE 2.0: A Continual Pre-training Framework for Language Understanding)(2019.7,AAAI 2020.)可以看作是一个模型框架,通过增量训练的方式集成多种预训练任务。希望利用多种无监督(弱监督)的任务来学习词法(lexical)、句法(syntactic)和语义(semantic)的信息。

增量训练(Continual Pre-training)或者称为持续学习,特点是能够在学习新任务的同时保证老任务的准确率不会变,避免串行任务学习存在的遗忘问题。具体方式为:先训练一个task;然后增加一个新的Task一起来multi-task Learning;然后再依次增加到n个task的multi-task Learning,这可能比直接开始多任务联合训练更稳定一些。联想到了Faster R-CNN的交替训练方式,在NLP的大预料情况下耗时会不可接受。

ERNIE 2.0 的预训练任务包括:

  • Word-aware Tasks

    • Knowledge Masking Task

      ERNIE 1.0版本的任务,包括word、phrase和entity级别的mask得到的任务。

    • Capitalization Prediction Task

      预测一个词是否首字母大小的任务。对于英文来说,首字符大小的词往往是命名实体,所以这个任务可以学习到一些entity的知识。

    • Token-Document Relation Task

      预测当前词是否出现在其它的Document里,一个词如果出现在多个Document里,要么它是常见的词,要么它是这两个Document共享的主题的词。这个任务能够让它学习多个Document的共同主题。

  • Structure-aware Tasks

    • Sentence Reordering Task

      给定一个段落(paragraph),首先把它随机的切分成1到m个segment。然后把segment随机打散(segment内部的词并不打散),让模型来恢复。是一种句子重排序任务,实现方式采用了一种最简单粗暴的分类的方法,总共有 $$k=\sum_{s=1}^m s!$$ 种分类。SRT任务可以让模型学习段落的篇章结构信息,其复杂度比NSP任务高出许多(阶乘类似指数级)。

    • Sentence Distance Task

      两个句子的”距离”的任务,对于两个句子有3种关系(3分类任务):它们是前后相邻的句子;它们不相邻但是属于同一个Document;它们属于不同的Document。

  • Semantic-aware Tasks

    • Discourse Relation Task

      让模型来预测两个句子的语义或者修辞(rhetorical)关系,参考:Mining discourse markers for unsuper- vised sentence representation learning](//arxiv.org/pdf/1903.11850.pdf)。

    • IR Relevance Task

      这是利用搜索引擎的数据,给定Query和搜索结果,分为3类:强相关、弱相关和完全不相关。

ERNIE 3.0

ERNIE 3.0: Large-scale Knowledge Enhanced Pre-training for Language Understanding and Generation(2021.7)

ERNIE 3.0 是基于知识增强的多范式统一预训练框架。在 ERNIE 3.0 中,自回归和自编码网络被创新型地融合在一起进行预训练,其中自编码网络采用 ERNIE 2.0 的多任务学习增量式构建预训练任务,持续的进行语义理解学习。 通过新增的实体预测、句子因果关系判断、文章句子结构重建等语义任务。同时,自编码网络创新性地增加了知识增强的预训练任务。自回归网络基于 Tranformer-XL 结构,支持长文本语言模型建模。多范式的统一预训练模式使得 ERNIE 3.0 能够在理解任务、生成任务和零样本学习任务上获取 SOTA 的表现。

文心ERNIE结合paddlepaddle深度学习框架,已集成到百度的商业应用平台,参考 文心大模型-产业级知识增强大模型

核心点:对标GPT-3的zero-shot/few-shot learning,(1)AE + AR 融合;(2)AE增加知识图谱增强的预训练任务。

ERNIE 3.0模型结构如下:

ERNIE 3.0

AE、AR任务的融合方式为:

  • 灰色部分,通用的transformer-XL encoder blocks(主要为了支持NLG的长文本,且仅在NLG任务上启用记忆循环机制),通过continual learning训练(主要用于NLU任务);

  • 蓝色部分,专为NLU设计,针对语义理解分类任务;

  • 绿色部分,专为NLG设计,针对生成任务。采用了ERNIE-Doc中提出的记忆循环机制,以建模更长的序列依赖。

这么做的好处有:

  • ERNIE 3.0和MASS/UniLM/T5统一AE、AR任务的方式不同的是,前者重在设计巧妙,后者重在扩展性,适合大量任务的共同学习(大模型应用新范式)。

  • 不同任务共享大部分的底层模型参数,但采用少量独立层适配更合适的网络,相比于BERT(各任务仅仅输出层不同),能够提高模型在相应任务上的表现。

  • 底层模型参数被多任务训练后具有较强的通用性(底层抽象语义信息,例如词汇和语法信息),可以像CV中采用ImageNet预训练的图像分类模型微调下游任务(如目标检测)时固定底层参数那样,在finetune下游任务时仅更新任务相关的子网络层,提高训练效率

Knowledge-aware Pre-training Tasks 通用知识文本预测

通用知识文本预测是基于知识的 MLM 任务的扩展,输入数据格式为知识图谱数据三元组(head, relation, tail)与这个知识所在的具体的文本(来自百科全书,如百度百科)进行拼接,随机选择(1)mask文本中的单词,或者(2)基于这条知识 mask 实体与实体之间的关系。实体关系有助于预测句子中的单词,而通过句子表示来预测关系强化了模型对句子的理解能力。

数据采样方式比较简单,先确定百科全书doc title中的实体作为head或tail,再从这个doc中抽取同时包含图谱三元组中的head与tail的句子。

通用知识文本预测任务如下图所示:

通用知识文本预测

效果:百亿级参数量(10B,vs GPT-3 175B),在五十多种NLU、NLG任务上取得SOTA结果。在SuperGLUE榜单上相比人类基准+0.8% (90.6% vs. 89.8%),超越了DeBERTa。

发展维度-位置编码

由于自然语言一般更依赖于相对位置,因此一些论文提出了表现更优异的相对位置编码。相对位置编码是在算Attention的时候考虑当前位置与被Attention的位置的相对距离,而不考虑绝对距离。

相对位置编码矩阵定义为:\(A_{ij}=a_{j-i}\),在线性代数中称为常对角矩阵(又称特普利茨矩阵 Toeplitz matrix),对每条对角线平行线上具有相同的值。

与绝对位置编码的区别:

  • 在Transformer中提出的三角函数形式的绝对位置编码具有一定的相对位置表达能力(位置α+β的向量可以表示成位置α和位置β的向量组合),但可能没有可学习的相对位置编码灵活,在深层网络中可能逐渐消失。三角式在后续网络中也很少被使用了。
  • Transformer的三角函数位置编码或BERT中可学习的绝对位置编码都是加在模型开头的输入部分,而相对位置编码是每一层都显式加一次,让模型对位置更加敏感。

再次附上三角函数式 位置编码公式:

\[\begin{aligned}&\boldsymbol{p}_{k,2i} &=\sin\Big(k/10000^{2i/d}\Big) \\
&\boldsymbol{p}_{k, 2i+1} &=\cos\Big(k/10000^{2i/d}\Big)
\end{aligned}
\]

下面介绍几种可学习的绝对/相对位置编码形式:包括 BERT、T5、DeBERTa、XLNet、TUPU 等。

这些不同的方法是基于各自不同的出发点,甚至有着相反的观点,算是一个仍然值的继续研究的方向。

BERT-绝对位置编码

\[\begin{aligned}
\alpha_{i j}^{Abs} &= \frac{1}{\sqrt{d}} \left( \left(x_{i}+p_{i}\right) W^{Q}\right)\left(\left(x_{j}+p_{j}\right) W^{K}\right)^{T} \\
&= \frac{1}{\sqrt{d}} \left[ \left(x_{i} W^{Q}\right)\left(x_{j} W^{K}\right)^{T} \right] &(\text{content-to-content}) \\
&+ \frac{1}{\sqrt{d}} \left[ \left(x_{i} W^{Q}\right) \left(p_{j} W^{K}\right)^{T}\right. + \left.\left(p_{i} W^{Q}\right)\left(x_{j} W^{K}\right)^{T} \right] &(\text{content-to-position, position-to-content}) \\
&+ \frac{1}{\sqrt{d}} \left[ \left(p_{i} W^{Q}\right)\left(p_{j} W^{K}\right)^{T}\right] &(\text{position-to-position})
\end{aligned}
\]

经典版-相对位置编码

Self-Attention with Relative Position Representations (NAACL 2018,Google) 首次提出了相对位置编码,影响了后来的多种模型,姑且称之为谷歌经典式。

相对位置编码是在计算Attention权重时添加相对位置编码矩阵 \(a^K、a^V\) 作为bias:

\[\begin{aligned}
e_{i j} &=\frac{x_{i} W^{Q}\left(x_{j} W^{K}+a_{i j}^{K}\right)^{T}}{\sqrt{d_{z}}} \\
\alpha_{i j} &=\frac{\exp e_{i j}}{\sum_{k=1}^{n} \exp e_{i k}} \\
z_{i} &=\sum_{j=1}^{n} \alpha_{i j}\left(x_{j} W^{V}+a_{i j}^{V}\right)
\end{aligned}
\]

式中相对位置编码 \(a_{ij}\) 的取值需要对偏移量 \(j-i\) 裁剪到区间[-k, k]以应对未知的任意长度的序列,然后从矩阵 \(\delta\) 中按偏移量查询:

\[\begin{aligned}
a_{i j}^{K} &=\delta_{\operatorname{clip}(j-i, k)}^{K} \\
a_{i j}^{V} &=\delta_{\operatorname{clip}(j-i, k)}^{V} \\
\operatorname{clip}(x, k) &=\max (-k, \min (k, x))
\end{aligned}
\]

这个相对位置编码不仅加在了Query-Key之间,还加到了Attention weight-Value之间,而后者的作用并不明显,因此在后续的XLNet、T5、TUPE等模型中均未使用。

值的注意的是,相对位置编码公式中的\(x\)未融合绝对位置编码,但绝对位置有时候也是有用的,也是可以融合进去的,如按照TUPE的方式。

XLNet-相对位置编码

XLNet/Transformer-XL 融合了三角函数式与谷歌经典式相对位置编码。Transformer-XL对长文本的分段处理方式导致绝对位置编码不可用,需要采用纯粹的相对位置编码。

考虑将BERT绝对位置编码分解式中两个token的绝对位置编码 \((p_i,p_j)\) 转换为相对位置编码:

  • content-to-position:\(R_{i-j}\),不可学习,通过三角函数构造相对编码。

  • position-to-content:\(u\),和经典式相对位置编码类似,不引入这种相对位置,而用一个可学习的base vector来替代原绝对位置编码。

  • position-to-position:\((v, R_{i-j})\),引入相对位置和base vector。

\[\begin{align}
\boldsymbol{q}_i \boldsymbol{k}_j^{\top}
& = \boldsymbol{x}_i \boldsymbol{W}_Q \boldsymbol{W}_K^{\top}\boldsymbol{x}_j^{\top} + \boldsymbol{x}_i \boldsymbol{W}_Q \boldsymbol{W}_K^{\top}\boldsymbol{p}_j^{\top} + \boldsymbol{p}_i \boldsymbol{W}_Q \boldsymbol{W}_K^{\top}\boldsymbol{x}_j^{\top} + \boldsymbol{p}_i \boldsymbol{W}_Q \boldsymbol{W}_K^{\top}\boldsymbol{p}_j^{\top}
\\
& \Rightarrow
\boldsymbol{x}_i \boldsymbol{W}_Q \boldsymbol{W}_K^{\top}\boldsymbol{x}_j^{\top} + \boldsymbol{x}_i \boldsymbol{W}_Q \boldsymbol{W}_K^{\top}\color{green}{\boldsymbol{R}_{i-j}^{\top}} + \color{red}{\boldsymbol{u}}\boldsymbol{W}_Q \boldsymbol{W}_K^{\top}\boldsymbol{x}_j^{\top} + \color{red}{\boldsymbol{v}} \boldsymbol{W}_Q \boldsymbol{W}_K^{\top}\color{green}{\boldsymbol{R}_{i-j}^{\top}}
\end{align}
\]

参考:

TUPE-混合编码

[2006.15595] Rethinking Positional Encoding in Language Pre-training(ICLR 2021,MSRA)提出的TUPU是混合式的。

提出了一种位置编码方式:Transformer with Untied Positional Encoding (TUPE),将内容与位置解耦,独立应用投射矩阵再相加。此外,还引入了T5中新增的bias项 \(b_{j-i}\)。舍弃了word-to-position, position-to-word依赖性的计算,可视化分析训练好的模型的相关矩阵发现位置信息和语义信息之间并不存在较强的关联性,引入这两个矩阵可能只是引入了噪声。并且由于NSP这种改变词序、语序的任务的存在,单词本身与其位置信息之间的关联被进一步削弱了。

Attention weight计算方式如下,上标 \(l\) 表示第几层,而位置编码的投射矩阵 \(U^Q, U^K ∈ \mathbb R^{d×d}\) 在所有层参数共享。

\[\alpha_{i j}=\frac{1}{\sqrt{2 d}} \underline{ \left[ \left(x_{i}^{l} W^{Q, l}\right)\left(x_{j}^{l} W^{K, l}\right)^{T}
+ \left(p_{i} U^{Q}\right)\left(p_{j} U^{K}\right)^{T} \right] }_{绝对位置}
+ \underline{ b_{j-i} }_{相对位置}
\]

TUPE同BERT那样在multi-head中各个head间共享位置编码,这仅增加了少量参数,但可以将 \(U^Q, U^K\) 扩展为每个head独立编码来进一步增加模型复杂度(DeBERTa正是这么做的)。

另外,TUPE 还将 [CLS] 标记与其它token独立区分开,以避免在相对位置编码的设计中 [CLS] 与其它token具有相同的位置编码(而在绝对位置编码中每个位置的编码是独立学习或者独一无二的,因此没有这个担忧)。单词通常具有较强的局部依赖性,而[CLS]的作用是汇聚所有token的信息,不应该强烈依赖相邻的token。对于BERT而言[CLS]放在开头,那么[CLS]可能强依赖于前几个单词,虽然很多句子中重心是在前边,但是越完整对理解句子越有利。而XLNet由于是自回归的方式,将[CLS]放在了末尾。

位置编码独立的方式也比较简单,修改位置编码矩阵(绝对+相对)中[CLS]所在的行和列分别为相同值 \(\theta_1^{\to},\theta_2^{\leftarrow}\),这两个值与其它位置编码一样可学习。

\[\operatorname{reset}_{\theta}(v, i, j)=
\begin{cases}
v_{i j} & i \neq 1, j \neq 1, &(\text { not related to }[\mathrm{CLS}]) \\
\theta_{1} & i=1, &([\mathrm{CLS}] \to\text {others }) \\
\theta_{2} & i \neq 1, j=1, &(\text { others}\to [\mathrm{CLS}])
\end{cases} \\
v_{i j} =\frac{1}{\sqrt{2 d}}\left(p_{i} U^{Q}\right)\left(p_{j} U^{K}\right)^{T}+b_{j-i}
\]

论文还讨论了混合绝对+相对位置编码的必要性,

  1. 考虑 \(\mathbb R^{n×n}\) 空间,相对位置编码常对角矩阵是只有2n-1自由度的线性子空间,而 \((P U^Q)(P U^K)^T\)\(\mathbb R^{n×n}\) 空间内的低秩矩阵,因此两者在空间上有差别。
  2. 在相对位置编码中通常会对过长的偏移量进行裁剪,这样无法区分较远的那些单词。而绝对位置编码没有这个问题。

其它-位置编码

T5采用了最简单形式的相对位置编码在QK相乘之后再加bias项 \(b_{j-i}\)

DeBERTa在末尾几层添加了绝对位置编码,而每层均采用了相对位置编码,暂且归属于半混合式吧。

详情参考T5、DeBERTa部分的介绍。

参考:让研究人员绞尽脑汁的Transformer位置编码 – 科学空间|Scientific Spaces

发展维度-masking 改进

对BERT预训练改进的出发点之一:masking。前文分模型部分已有所介绍,这里再做汇总与补充。

  • 细节地改动:沿用挖孔mask的方式,代表性的工作包括BERT-wwm、SpanBERT、ERNIE、RoBERTa。

  • 大刀阔斧地改动:XLNet的Permutation LM,为了消除预训练与下游finetune任务的隔阂,用打乱顺序+单向的模式替代中间挖孔的方式,达到双向上下文感知的效果。

对于Mask的改进属于预训练阶段的改进,因此对于不需要Pretraining的用户来说只要把Google提供的初始模型替换成这些模型就可以直接享受其改进了,即Fine-tuning时代码不需要做任何修改,只需要更换预训练模型。

Facebook的RoBERTa: A Robustly Optimized BERT Pretraining Approach 提出的动态mask,思路比较简单,仅仅是增加同一样本在多次迭代时masking随机的模式。它并没做任何模型结构的改变,只是改进了pretraining的方法就在某些数据集上比XLNet的效果要好。

Whole Word Masking

基本思想

Whold Word Mask 由原BERT的作者提出,是一个很简单的思想:随机mask掉整个单词,而不是英文的WordPiece或者中文的单字。比如“琵琶”这个词仅mask掉一个字,模型也很容易通过概率统计知道这两个字是强关联的,不需要通过上下文去预测,这会降低模型的学习能力,英文单词的WordPiece也会有同样的问题。但是原BERT开放的Whole Word Masking 预训练模型仅包含英文的。

哈工大与科大讯飞的TASLP 2021论文Pre-Training with Whole Word Masking for Chinese BERT 专门对这个思想做了验证,并开放了中文版的Pretraining Whole Word Masking 预训练模型Chinese-BERT-wwm,可以在这里下载。

预训练时做了一点修改:

  • 优化器用LAMB,因为它对于长文本效果更好。BERT原始代码使用的是AdamWeightDecayOptimizer。
  • 采用Google发布的原始中文模型做初始化,起点高一些。

ERNIE实体与短语mask

在 ERNIE 1.0: Enhanced Representation through Knowledge Integration 中(包括后续版本2.0、3.0),在Whole Word Masking之上更进一步,引入命名实体识别和分词,将Masking的范围从词扩大到实体(entity)和短语(phrase)。并采用多层级Mask训练任务:基本(英文word或中文单字)、entity和phrase。

相比SpanBERT这种纯随机的方式,ERNIE属于应用人工先验知识来确定mask span长度,可解释性强一些,虽然效果不见得一定比SpanBERT随机的方式强。

参考:对BERT的pretraining改进的几篇文章 – 李理的博客

MLM 扩展延伸

BERT 的 MLM 模型的一个应用:配合特定的描述将任务转化为完形填空,利用 MLM 模型做零样本学习、小样本学习和半监督学习。

如何用MLM做文本分类问题?

采用 Pattern-Exploiting Training(PET) 训练模式,它首先出现在论文 Exploiting Cloze Questions for Few Shot Text Classification and Natural Language Inference

给输入的文本增加一个前缀或者后缀描述,并且 Mask 掉某些 Token,转换为完形填空问题,这样的转换在原论文中称为 Pattern,这个转换要尽可能与原来的句子组成一句自然的话,不能过于生硬,因为预训练的 MLM 模型就是在自然语言上进行的。例如:“这趟旅行我感觉很不错。____满意。”,空白处填“很/不”甚至多个字符,需要枚举建立 Token 到实际类别的映射。用MLM输出概率最高的token作为分类结果。

参考:必须要GPT-3吗?不,BERT的MLM模型也能小样本学习


  1. fastText,智慧与美貌并重的文本分类及向量化工具 ↩︎

  2. Pennington, J., Socher, R., & Manning, C. (2014). Glove: global vectors for word representation. Proceedings of the 2014 conference on empirical methods in natural language processing (EMNLP) (pp. 1532–1543). ↩︎

  3. Bojanowski, P., Grave, E., Joulin, A., & Mikolov, T. (2016). Enriching word vectors with subword information. arXiv preprint arXiv:1607.04606. ↩︎

  4. Sennrich, R., Haddow, B., & Birch, A. (2015). Neural machine translation of rare words with subword units. arXiv preprint arXiv:1508.07909. ↩︎

  5. Self-Attention与Transformer ↩︎

  6. 位置编码与编码解码过程 ↩︎

  7. 在NLP中广泛应用的transformer(Self-Attention)剖析笔记 ↩︎

  8. Jonas Gehring, Michael Auli, David Grangier, Denis Yarats, and Yann N. Dauphin. Convolutional sequence to sequence learning. arXiv preprint arXiv:1705.03122v2, 2017. ↩︎

  9. 强烈推荐阅读 //kazemnejad.com/blog/transformer_architecture_positional_encoding/ ↩︎

  10. 《Attention is All You Need》浅读(简介+代码) ↩︎

  11. Positional Encoding in Transformer ↩︎

  12. //d2l.ai/chapter_attention-mechanisms/transformer.html ↩︎

  13. Transformer(模型和代码解析) ↩︎

  14. How is BERT different from the original transformer architecture? ↩︎

  15. BERT pretraining: [SEP] vs. Segment Embeddings? · Issue #11925 · huggingface/transformers ↩︎

  16. nlp – BERT embedding layer – Data Science Stack Exchange ↩︎