模型来自论文 Google 最近公布的论文 《ALBERT: A LITE BERT FOR SELF-SUPERVISED LEARNING OF LANGUAGE REPRESENTATIONS》[1],该论文现在已送审 ICIR 2020。
从名字就可以看出 ALBERT 是 BERT 的“改进版”,其进步的地方,一言以蔽之,就是 用更少的参数,取得了更好的效果。
1. 模型大小与模型性能之间的关系
这是作者开篇讨论的问题。近一两年,预训练语言模型给自然语言处理领域带来了巨大的突破。从 ELMO,GPT,到 Bert,XLNet 和 RoBerta,我们不难看出,性能越强的模型,参数量也越大。既然模型的参数量如此重要,我们就会有一个很直接的假设:参数量越大,模型的性能就会越高。
先不考虑硬件资源和训练时间(还是要考虑,如此大的开销已经将很多参与者挤出门外了),如果上述假设成立,那么我们只需要想方设法地扩展模型规模就可以了。作者为验证假设,将 Bert-large 模型的隐藏层 size 扩展了一倍,构建了 Bert-xlarge模型。该模型的参数量较 Bert-large 提升了一倍,然而遗憾的是,如图1所示,Bert-xlarge 出现了模型退化(model degradation)现象,性能不升反降。因此,简单地推高参数量,不仅会面临更加严峻的硬件资源不足以及训练时间过长问题,且无法获得更好的效果的。
其实这也比较好理解,参数量越大性能越好,我认为这本身是没有正确的,但前提是对模型中参数的运用没有退化,或者说模型内单位参数所发挥的作用没有退化。举个例子,鲸鱼大脑的绝对体积和重量都要超过人类,但其大脑很大一部分精力用在控制其“臃肿”的体积上,而不是用来思考和记忆,因此远不如人类聪明。
因此为了提升模型性能,我们既可以“做加法”,在模型结构合理有效的前提下,增大模型的规模(e.g. Bert --> Bert-large, Bert --> XLNet);也可以“做减法”,降低参数量,但提升参数的利用效率、更大地发挥参数的效果。本篇论文中所设计的 ALBERT,就是在“做减法”的基础上,在性能上全面超越 Bert。
2. 为模型“做减法”
ALBERT 在模型上“做减法”,最大的体现就是减少了参数量,同时带来了以下提升:
- 提升了训练速度,注意是训练速度,测试速度还是很慢
- 减少了硬件资源的要求??
- 最后但是最重要的,提升了性能
铺垫了这么久,让我们看看 ALBERT 是如何在降低参数量的同时,提升训练速度和性能的吧(在结果上,近乎完美的提升啊)。在整体上,ALBERT 继承了 Bert 的骨干架构,也就是使用 transformer encoder 和 GELU 非线性激活函数。不同的是,作者引入了两个参数削减机制和一个全新的loss函数设计,让 BERT 焕然一新。
I. 嵌入层参数因式分解(Factorized embedding parameterization)
width
不论是 Bert,还是随后的 XLNet 和 RoBERTa,模型中的词嵌入(WordPiece Embedding)大小都是与隐藏层输出大小(Hidden-layer Embedding)相捆绑的,譬如 ,然而这种捆绑策略不论是从建模层面还是实际层面来看,都是欠佳的。
从建模层面讲,词嵌入的目标是学习上下文无关的表示(context-independent representations),而隐藏层的目标是学习上下文相关表示(context-dependent),而 Bert 表示的强大之处正是在于学习这种上下文相关的表示。解开 词嵌入 与 隐藏层表示 的直接捆绑关系,譬如使得 H 远大于 E,能够更加高效地利用模型的整体参数。
从实际层面讲,自然语言词表(V, vocabulary)长度达到 2w~3w。如果 E 恒等于 H,那么想要增加隐藏层大小 H,意味着需要同时增加嵌入矩阵 的大小,由于V非常大,少量地增加 E,都会使得模型的参数达到数十亿的量级,显得十分臃肿;同时,直观上我们知道 上下文无关表示(单词级别) 所蕴含的信息要远远少于 上下文相关表示(句子级别) 所蕴含的信息,然而他们却被赋予了相同的 size,可以想见词嵌入 E 的多数维度在训练过程中都只是稀疏更新,显得十分低效。
因此,作者在 ALBERT 中尝试打破这种 词嵌入 与 隐藏层 维度的捆绑关系。模型中,不再直接将独热码向量映射到隐藏空间(hidden space)中(这样会带来 的参数矩阵),而是先将 独热码向量 映射到一个低维嵌入空间中,再将它们映射到 隐藏空间中,也就是将原本的大矩阵 分解成两个小矩阵 ,当 H 远大于 E 的时候,这种分解能大大减少参数量。
疑问:Bert中的隐藏层参数E多少? 隐藏层向量又是多少?得到词向量的过程究竟是怎么样的
II. 跨层参数共享机制(Cross-layer parameter sharing)- depth
为了进一步提升参数的效率,作者尝试了不同的参数共享方式,包括全参数共享、注意力参数共享和前馈神经网络参数共享。虽然这些参数共享方式在不同程度上造成了性能的一些下降,但是它显著地降低了参数量。从下表的试验结果可以看出,当设置 E = 128 的时候,性能下降的程度是比较小的;同时通过对比试验,性能下降主要是 前馈神经网络参数共享所带来的,当只共享 attention 参数且 E 设置为 128 的时候,性能不降反升。不过最终作者选择的策略是所有层共享所有参数。
疑问:这个跨层共享参数的*跨层*究竟是怎么跨的
III. 句间连续性损失函数(Inter-sentence coherence loss)
我们知道 Bert 设计了两个任务在无监督数据上实现预训练,分别是 掩码双向语言模型(MLM, masked language modeling)和 下句预测任务(NSP, next-sentence prediction)。MLM 类似于我们熟悉的完形填空任务,在 ALBERT 中被保留了下来,这里不再赘述。NSP 是一个简单的二分类任务,即判断两个句子是否是一篇文章中的两个连续的句子,正例的构造就是从一个 text 中摘取位置上连续的两个句子,而负例的构造却是从两篇不同的文章中选取两个句子(我原本以为是从一篇文章中不连续地抽取两个句子呢)。我们知道设计 MLM 任务是为了捕捉句内不同单词之间的关系的,适用于序列标记等任务;而 NSP 是用于获取句子间关系的,以此提升类似于语言推理这样的下游任务性能,然而该任务存在明显的缺陷:它太简单了,以至于模型从这个任务中学不到充分的句子间关系。NSP 任务试图将 主题预测(topic prediction)和 句子连贯性预测(coherence prediction)糅合成一个任务;然而比起句子连贯性,主题预测是个简单得多的任务(只要预测出来两句话的主题不一致,就判负例,否则为正例),因此在 NSP 任务中,模型更倾向于预测主题,造成的后果就是:不仅忽略了句间连贯性预测,把握不到句间关系,也使得 NSP 任务与 MLM 任务产生了重合(主题预测本质上也是探索一个句子中的内在联系)。
这不禁让我想到了之前做的一个实体抽取任务,由于赛方不仅提供了目标text文本,还提供了目标实体所参与的事件类型type(e.g. text: 小明做了S1类型的事件,小丽做了S2类型的事件 type: S1 则目标实体是小明,而不是小丽),我们既可以把 type 和 text 拼接起来当成一个句子,也可以把 type 和 text 看成一个句子对,然而后者做法的效果明显比前者要查,也能就是 MLM 的设计要优于 NSP ,使得 BERT 在处理单个句子的时候更有优势。
针对 NSP 任务的两大缺点:1)过于简单,与 MLM 任务有重合 2)无法很好地捕捉句间关系,作者对 NSP 任务进行了改进。还是针对一个句子对做二分类,正例的构造也和 NSP一致,即从一篇文章中选取连续的两个句子,用 来表示(其中下标 i 表示文章中的第i个句子);而负例的构造就有很大的不同了,不再是从不同文章中选取句子,而是调换同一篇文章中两个连续句子的顺序,即。为何这么设计?首先我们可以看到,两个句子由于来自同一篇文章,因此其主题是一致的,模型无法通过主题预测判断是正例还是负例,因此增加了任务的难度。其次,由于正负例之间最大的区别就是顺序的调换,因此该任务能够强制模型去关注话语级别的句子连贯性属性,从而更好地把握句子间关系。所以一开始提到的 NSP 任务缺陷在这里都解决了,作者把这个任务称作 句子顺序预测任务(SOP, sentence-order prediction),对应的 loss 称为 句间连贯性损失。同时作者把任务中的句子(sentence)换成了句段,一个句段通常由多个句子组成,经验证,在模型训练中,以句段为单位较句子更加有效。[2]
# --------------------------------------------------------- 我也可以设计实验去搞一搞啊
# --------------------------------------------------------- 设计一个更好的预训练任务啊
作者通过对比实验发现,用 NSP 任务预训练过的模型,在 SOP 任务上测试,性能只比抛硬币好一点;而在 SOP 任务上预训练过的模型,在 NSP 任务上却达到了非常不错的性能。这也印证了 SOP 任务比 NSP 任务更难,能够让模型学到更佳的句子间信息。
3. 预训练实验设置 & 代码分析
为了控制变量、方便实验对比,ALBERT 的实验设置与 BERT 基本保持一致,包括:
- 预训练数据采用 BOOKCORPUS 和 English Wikipedia,包含约 16G 未压缩的文字;
- 构造 input 的方式: “[CLS] x1 [SEP] x2 [SEP]”,其中 x1 和 x2 都是句段,包含一个或多个句子
- n-gram masking 任务(n = 1, 2, 3)
一大不同是不再使用 权重衰减的Adam 优化器,而是使用 2019 年新提出的一种 LAMB 优化器,学习率设置为 0.00176,batch size 设置为 4096。用到的 TPU 数量根据模型大小,从 64 到 1024 块不等。
4. 模型性能
通过图4的表格我们可以看到,由于采取了上述的策略,ALBERT 在参数量上要远远小于 Bert。譬如,ALBERT-large 的参数量仅有 18M,仅为 Bert-large 的 1/18;将 Bert 的隐藏层扩展到 2048 维,参数量会飙升到 1.27G 且性能下降,而 H = 2048 的 ALBERT-xlarge 模型只有 59M 的参数,更大的模型 ALBERT-xxlarge(H=4096)参数量也仅有 233M。另外作者在 ALBERT-xxlarge 中设定了 12 层的网络,之所以不设置为 24 层,是因为通过实验作者验证了二者在性能上相近,而后者的计算成本更高。
整体性能上可以看到,ALBERT 在几乎所有任务上都超越了 Bert-large 模型,同时兼具 参数量小 和 训练速度快 的优势。然而我测试了 github 上公开的一个实现版本,发现测试的速度并没有提升。
5. 其他思考
可以看到,本篇论文并没有对预训练模型的结构进行大刀阔斧的创新,但这仍不妨碍它为预训练模型发展方向所做出的巨大指导:虽然参数量是提升模型性能的重要因素,但为了提升参数量而提升参数量只会导致模型退化等负面情况,还要考虑模型对参数的运用效率。如果把小模型比作“人”,那么在规模上变大了的模型仍然应当是个“巨人”,而不应该是一个“大象”。
同时,论文中个通过丰富的 ALBERT 对比实验(啊,硬件资源不要钱啊)探讨了一些我们经常会遇到的疑惑:
a. 模型深度和宽度之于模型性能有何影响
模型深度指的是 层数(number of layer),模型宽度指的是 隐藏层大小(hidden size)。作者首先进行了深度的探索,由于所有层共享所有参数,所以参数量并不会因为深度的增加而改变(一直都是 18M)。可以从图 5 看到,虽然参数量没变,但随着深度的增加,模型在下游任务上的性能逐步提升;在 12 层的之后,性能变化很小,并且在48层的时候出现了性能下降。注意作者在这个实验中使用了 热启动(warm-start)技术,也即深层模型是由浅层模型 finetune 而得到的,这能帮助深层模型达到收敛。
性能先增后降的现象同样出现在 宽度实验 中,如图 6 所示。不论是在训练还是在验证的过程中,没有模型出现了过拟合现象,但比起 ALBERT 的最佳参数配置,它们都有更高的 loss。
b. 训练时间对模型性能的影响
如下图,训练几乎相同的时间,ALBERT-xxlarge 的性能是高于 Bert-large 的,不过前者的数据吞吐量(data-throughput)确实是比后者慢三倍有余。
c. 更宽的 ALBERT 模型也需要变得更深吗?
在图 5 中我们看到,12 层模型和 24 层模型的结果差距很小,那么造成这个现象的原因,是模型宽度没有跟着深度的增加而增加吗,作者通过图 8 的实验给出了否定的回答:第一行模型的参数是 12-layer 和 1024-H,第二行模型的参数是 24-layer 和 4096-H,然而性能几乎没有改变。这就说明简单地加深模型、加宽模型抑或是同时加宽加深模型,都无法带来性能的提升,参数量的增加还是需要基于模型基础结构复杂度、合理性的提升。
d. 增加额外的训练数据以及引入 Dropout 机制
前面说到作者为了方便与 Bert 对比,只是用了 English Wikipedia 和 BOOKCORPUS 数据集,在本部分的实验中,作者扩充了训练集,加入了 XLNet 和 RoBERTa 训练过程中所使用的数据。从图 9(a) 中可以看出,增加训练数据后,不论是在预训练还是下游任务上,模型都有了进一步的提升。
而由于 ALBERT-xxlarge 即使在训练了 1M steps 后,仍然没有在训练集上过拟合,因此如图 12 所示,作者在移除 dropout 机制后,发现性能提升了。这第一次印证了 dropout 可能对基于 transformer 的大型模型产生负面效果,其原因很有可能是当 batch normalization 和 dropout 同时应用与模型上时,会损害模型性能。
e. 当前 NLU 任务上最好的模型
最后作者又总结了一遍论文中提出的模型——ALBERT-xxlarge 的强大性能(使用了 Bert、XLNet 和 RoBERTa 的训练数据):在 13 项 NLP 任务上都取得了最佳,包括 GLUE 上的 9 个任务 和 SQuAD、RACE等 4 个数据集。
6. 我的思考
1) 更好的预训练任务设计
[1] Lan Z, Chen M, Goodman S, et al. ALBERT: A Lite BERT for Self-supervised Learning of Language Representations[J]. arXiv preprint arXiv:1909.11942, 2019.
[2] Yinhan Liu, Myle Ott, Naman Goyal, Jingfei Du, Mandar Joshi, Danqi Chen, Omer Levy, Mike Lewis, Luke Zettlemoyer, and Veselin Stoyanov. RoBERTa: A robustly optimized BERT pretraining approach. arXiv preprint arXiv:1907.11692, 2019.