最近被 Google 的 BERT (Bidirectional Encoder Representations from Transfoemers)模型给刷屏了。第一作者还在 Reddit 上进行了解答说明,具体可以戳:这里 ,本文为了便于学习,翻译了第一作者的解读说明,不妥则删。
解读说明正文开始:
基本的想法是非常简单的。最近几年,人们在将预训练 DNNs 模型作为一个语言模型并采用微调(fine-tuning)在一些下游 NLP 任务(如,问题回答,自然语言推断,情感分析等等)上已经取得了非常好的结果。
语言模型通常是从左到右的,例如:
"the man went to a store"
P(the | <s>)*P(man|<s> the)*P(went|<s> the man)*...
问题是对于下游任务来说,你通常不需要一个语言模型,需要的是:对于每个单词来说,尽可能有最好的上下文表示。如果每个单词,只能知道左边的情况,很明显这是有遗失的。所以,人们发现的一个技巧是从右到左训练一个模型,例如:
P(store|</s>)*P(a|store </s>)*...
目前为止,我们有了每个单词的两种表达方式。一个是从左到右,一个是从右到左。可以将它们结合在一起来解决下游任务。
直观上来说,如果我们训练一个深度的双向模型的话结果可能会好得多。但是不幸的是,不可能像训练普通的 LM 模型一样去训练深度双向模型。因为这会产生一些循环,在这些循环中,单词可以间接地“看到它们自己”,并且预测会变得微不足道。
可以取而代之的是一个非常简单的技巧被用于降噪自动编码器中(de-noise auto-encoders),即从输入中掩盖一定比例的单词并从上下文中重构这些单词。我们称之为 “masked LM”,但是经常也被称为完形填空任务(Cloze task)
任务 1: Masked LM(Language Model)
Input:
the man [MASK1] to [MASK2] store
Label:
[MASK1] = went; [MASK2] = a
特别地,我们通过一个深度转换编码器来提供输入,然后用被掩盖位置的最终隐藏状态来预测被掩盖的单词,就像我们训练语言模型一样。LM 模型缺失的另一样东西是它不能理解句子之间的关系,这个关系在很多的 NLP 任务中都是非常重要的。为了预训练一个句子关系模型,我们使用一个非常简单的二元分类任务,即连接两个句子 A 和 B 并预测 B 是否实际处于原始文本中的 A 之后。
任务 2:Next Sentence Prediction
Input:
the man went to the store [SEP] he bought a gallon of milk
Label:
IsNext
Input:
the man went to the store [SEP] penguins are flightless birds
Label:
NotNext
然后,我们只需要在很大的文本上(我们使用了维基百科 + 一些免费电子书的集合,是一些 NLP 研究人员去年公开发布的)为很多步骤(steps)训练一个非常大的模型。为了适应某些下游任务,你只需对该任务模型的标签微调几个 epoch。
通过这样做,我们在我们尝试的每个 NLP 任务上都获得了相对于 SOTA 的巨大改进,几乎不需要任何特定任务就可以对我们的模型进行任何更改。
但对我们来说,真正令人惊讶和意想不到的是,当我们从一个大型模型(12 个转换区块,768 个隐藏层,110M 参数)变成一个非常大的模型(24 个转换区块,1024 个隐藏层,340M 参数)时,我们得到了即使在非常小的数据集上也有巨大的改进(小 == 少于5,000个标记的例子)的结果。
我们也百分百愿意在接下来的 2-3 周内发布预训练的模型和用于主要结果的自动化复现代码。(在单个 GPU 上复现微调最多需要几个小时)。
以上是正文的全部。
最后,作者还在评论里提到使用 Google 的 TPU 的话,训练效率将比一般的要高。16 个 TPU 就有很强的运算能力。以及由于预训练的复现对于 Google 之外的几乎所有人来说都不可行,并且预训练数据处理是使用 Google 的并行计算框架和 C++ 编写的,他们无法重新发布数据(即使它是公开的,他们也不会在可预见的未来发布预训练复现的代码。)但实际的 TensorFlow 方面对于预训练和微调是 99% 相同。
网友评论