本文参考https://lena-voita.github.io/nlp_course/transfer_learning.html
目前不论是在学术界还是工业界,迁移学习可能都是最流行的NLP领域。很可能你已经听说过了ELMo,BERT,和其他一些名字----在这篇文章后,希望你能有一个大致的了解。
一般的迁移学习的思想是将知识从一个任务/模型迁移到另外一个。例如:对于目前你感兴趣的任务没有大量的数据,如:分类。用你目前仅有的数据得到一个好的模型是很困难的。相反,在其他任务中你可以有更加容易得到的数据,如:语言模型,在语言模型任务中不需要带标签的数据----纯文本就足够了。
在这种情况下,我们就可以将知识从你不感兴趣的任务,我们叫他源任务“迁移”到你关心的任务中,也就是目标任务。
在Sebastian Ruder’s blog post
中很好的将迁移学习进行了分类。两大类是transductive与inductive。这两大类将所有的方法分为任务相同,只在源任务中有标签(transductive)以及任务不同,只在目标任务中有标签(inductive)。
在本篇文章中,我们最感兴趣的是辅助模型看起来是怎样的以及迁移在模型角度看是怎样的?
在谈论文本分类时,我们已经知道使用语训练得词向量会很有帮助,关于这部分让我们再回想一下。
文本分类中的词嵌入
网络中的输入是由词嵌入代表的。有三个选择可以得到这些词嵌入:
1.做为模型的一部分,从头开始训练
2.使用预训练的词嵌入并固定他们如:Word2Vec,GloVe等,将他们做为静态的向量使用
3.使用预训练的向量做初始化在网络中训练他们(“微调”)
让我们通过观察模型可以使用的数据来观察这些模型。训练数据进行文本分类需要带标签的固定于具体任务的数据,但是带标签的数据往往不容易得到。因此,这个语料就不会很大,或者不会很全面多样。相反,训练词向量并不需要带标签的数据----纯文本就足够了。因此。这些数据可以是大量的,多样的,可以从中学到很多。
现在让我们考虑一个模型,这个模型知道的多少取决于我们对词嵌入所做的处理。如果词嵌入是从头开始训练的,模型掌握的仅仅是用于分类的数据----这些数据可能并不足够将词间的关系学习好。但是,如果我们使用预训练的词向量,这些词向量(也就是说,整个模型)将会掌握一个很大的语料库,他们会学习到关于词的很多知识。为了适应这些词向量到你具体任务的数据,你可以通过将这些词向量在整个网络中进行训练来微调这些词向量----这可以带来模型表现上的提升(尽管不会是太大的提升)
当我们使用预训练的词向量时,这就是迁移学习的一个例子:通过词向量,我们将知识从训练词向量的数据迁移到了我们的具体任务的模型中。
我们刚刚介绍了在具体任务中使用预训练词向量的主要思想:
通过词向量,将知识从训练数据中迁移到具体任务的模型中
在模型中,这种迁移学习是通过将随机初始化的向量替换为预训练的词向量实现的(还有复制权重从预训练的词向量中)
注意我们并没有改变模型:模型和以前保持一致。
在之后的介绍中,情况可能会有些不同。
我们在讲词嵌入实现的知识迁移中的思想是一般性的。当将词嵌入变为预训练模型时思想是保持不变的。也就是:可以将"词向量"替换为模型的名字
通过“某个模型”我们将知识从训练数据中迁移到具体任务的模型中
两个好主意 :)
这部分我们将看到四个模型:CoVe,ELMo,GPT,BERT。注意现在有很多这些模型的变种:从非常小的改变(如:训练数据或设定)到很突出的改变(如:不同的训练目标)。
然而,大体上讲,从词嵌入到目前最先进的模型的过渡可以用两个想法来解释。
两个想法:
1.什么被编码:从词到上下文语境中的词
2.下游任务的用法:从仅替换特定任务中的词向量到替换整个模型
现在,我将解释这些想法以及相应的模型
就像我们刚刚看到的,通过向量表示进行知识迁移已经在预训练模型出现之前存在很长时间了:最简单的情况下,通过词的向量表示实现。是迁移更有效率(因此更加流行)的是一个很简单的思想:
相反于单独对词进行表示,我们可以学习将单词与其上下文一起进行表示。
好的,那么,但是我们要如何实现呢?
记得我们曾训练过神经语言模型?训练一个语言模型我们需要的数据与训练词向量需要的数据是相同的:纯文本就行了(如:维基百科中的文本或者任何你想要的文本)。你不需要任何的标签。
现在想象一下我们有一些自然语言的文本。我们可以使用这些文本训练词向量(Word2Vec,GloVe等)或者一个神经语言模型。但是训练一个语言模型我们会比训练一个词嵌入得到的多的多:语言模型处理的不仅仅是单个的词还有句子,短语等。语言模型也会为每一个词建立表示向量,但是这些向量表示不仅仅是词,还表示了词中的上下文语境。
举例说明:如句子“ I saw a cat on a mat ”中的cat。如果我们使用的是词向量,cat的向量会包含关于cat的一般性信息。它可以是我们能想到的任何种的cat。但是如果我们得到的是从语言模型中的向量cat,这个cat就不是其他的cat了。因为语言模型读了上下文语境,这个向量代表的cat是“i saw”的这只猫,是“sat on the mat.”的这只猫。
迁移:将表示输入而不是词向量
首先实现了编码带有上下文词语的模型是CoVe和ELMo。他们的下游任务使用的方式与词向量相同:通常情况下,只需要将模型表示取代词向量即可。
注意现在对每一个模型你仍然有一个具体的任务模型。这些具体任务的模型可以是非常不同的。我们改变的是只我们编码词语的方式。
CoVe表示的是“Context Vectors”。它在NeurIPS 2017论文
Learned in Translation: Contextualized Word Vectors中被提出。作者首次提出来如何将不仅仅是单独的词而是将词与他的上下文词一起进行编码。
模型训练:神经机器翻译(LSTMs 和 Attention)
为了在句子/段落的上下文中对单词进行编码,CoVe训练了一个NMT系统使用了系统中的encoder部分。主要的假设是为了翻译一个句子,NMT编码器部分学习“理解”源句子。因
此编码器中的向量表示包含了词的上下文信息。
作者训练了一个带有注意力机制的LSTM模型(如我们在seq2seq 和Attention中提到过的:Bahdanau model we saw in the previous lecture)。因为最后我们需要使用训练好的编码器处理英文句子(不是因为我们只关注英文。是因为大多数下载的数据集是英文的)所以NMT系统需要将英语翻译为其他语言。
注意在这个NMT模型中,编码器是双向的:它连接了前向LSTM和后向LSTM的输出。因此,编码器的输出包含了左边和右边的上下文信息。
训练完一个NMT系统,我们需要的是他的编码器部分。对于一个给定的文本,CoVe向量是编码器的输出。对于下游任务,作者提出使用Glove(代表单独的词)与CoVe(在上下文中编码的词)的联合向量。这是因为这些向量代表了不同种的信息。将他们联合起来可能会有帮助。
仅通过将CoVe与GloVe结合使用,作者在很多下游任务中:文本分类。自然语言推理,问答方面取得了显著的提升。
ELMo模型在论文Deep contextualized word representations中被提出。不同于CoVe,ELMo使用的表示不是来自于NMT模型而是来自于一个语言模型。仅仅通过将GloVe词向量替换为从LM中得到的向量就在很多问题上得到了一个大的提升:问答,情感分析,命名实体识别和一些其他工作上。同时这篇论文得到了2018年NAACL的最佳论文奖。
现在让我们来仔细的了解一下ELMo。
模型训练:在char-CNN基础之上的前向后向LSTM-LM
模型很简单,由两层LSTM语言模型组成:前向的和后向的。使用了这两层可以让每一个词知道全部的上下文:左边的和右边的。
有趣的是作者得到初始化词嵌入的方法(得到初始化词嵌入将其喂入到LSTMs中)。我们知道,在标准的词嵌入层,,对于每一个词汇表中的词,我们训练一个独一无二的向量。这种情况下:
1.词向量不知道词的字符组成情况(如,他们不知道词represent,represents,represented,和repersentation在书写上是相近的)
2.无法表示词汇表外的词(out-of-vocabulary,OOV)
为了解决这个问题,作者使用字符级别的网络输出做为词的表示。就像我们在上图中看到的,这个CNN很简单,组成部分也是我们早就知道的:卷积,全局池化,highway连接以及全链接层。这种情况下,单词的表示形式知道他们的字符组成。并且可以表示我们在训练数据中没有遇到的词。
得到表示:不同层的权重表示
模型训练好后,就可以使用它来得到词的表示形式。对于ELMo,每一个词的表示是结合了响应层的前向和后向的LSTM得到的。通过将前向和后向的向量结合,我们得到了一个表示“知道”左边和右边的上下文。
总体来说,ELMo有层得到表示:
layer0:(embeddings)字符级别的CNN的输出
layer1:结合来自于layer1层的前向和后向LSTM的表示
layer2:结合来自于layer2层的前向和后向LSTM的表示
每一层都编码了不同的信息:layer0:词级别的信息,layer1和layer2:带有语境的词。对layer1和layer2左比较:layer2更倾向于包含了高层次的信息。
由于不同的下游任务需要不同类型的信息,因此ELMo使用特定于任务的权重来组合来自三层的表示形式。这些权重常量从每一个下游任务中学习得到。最后的结果向量,是用各个层的权重组合表示一个词。
接下来我们看到的两个(两类)模型是CPT和BERT。他们的对于下游方法的使用和我们之前看到的方法有很大的不同。
CoVe和ELMo替换了词向量,GPT和BERT替换了整个模型
注意到ELMo和CoVe的表示主要用于替换embedding层,几乎完整的保留了具体任务的模型架构。这意味着,对于共指消歧,需要使用一个具体的为这个任务设定的模型。对于词性标注–另一个模型,问答问题—可能是一个非常不同的模型。对于这些任务,研究人员需要研究提升具体模型结构的方法。
与之前的模型相反,GPT/BERT不是替换词向量层,而是替换了整个具体任务的模型。在这个新想法下,末次那个首先经过一个大量的没有标签的数据(纯文本)的预训练。然后,对于每一个下游任务进行微调。重要的是,在微调期间,你唯一需要做的事情就是使用任务可感知的输入也就是说将数据以某种特定的方式输入而不是要调整模型结构。
GPT是一个基于transformer的从左到右的语言模型。结构是12层的Transformer解码器(不包括decoder-encoder attention)。
正常情况下,如果y1,…,yn是一个训练序列,在时间t,模型预测可能的分布:
模型训练过程中使用的是标准的交叉熵损失,对于整个序列损失是:
微调损失包括了具体任务损失和语言模型损失:
在微调这部分,模型结构除了最后的线性层保持不变。
改变的是每一个任务的输入形式:如下边的插图所示:
单句分类:
为了将单个句子进行分类,只要将训练数据喂入到模型中,然后从最后的输入表示总得到预测。
任务举例:
SST-2:二元情绪分类
CoLA(Corpus of Linguistic Acceptability):判断一个句子是否是语言可接受的
句子对分类
要对句子对进行分类,将两个片段用特殊的分割token如(delim),然后根据输入的最后词的表示进行预测。
任务举例:
SNLI:含义分类,给定一对句子,判断第二个句子是蕴含的,对立的还是中立的
QQP(Quora Question Pairs):给定两个问题,判断他们是否在语义上是相等的。
STS-B:给定两个句子返回相似度评分1-5
问题回答和常识推理
这些任务中,会给定一个文本文档z和一个问题q,以及一些可能的答案ak。连接文档和问题,并在delim标记后添加可能的答案。对于每一个可能的答案,单独用GPT模型进行处理,然后通过softmax层产生可能答案的一个归一化分布。
任务举例:
RACE:阅读理解。给定一个文章,一个问题和几个答案,挑选正确的一个
Story Cloze:故事理解和剧本学习。给定一个四句故事和两个可能的结尾,选择故事的正确结尾。
以及:GPT-1-2-3
目前有三个GPT模型
GPT1: Improving Language Understanding by Generative Pre-Training
CPT-2:Language Models are Unsupervised Multitask Learners
GPT-3:Language Models are Few-Shot Learners
这些模型的主要区别在于训练数据的数量和参数的数量。因为这些模型是如此之大,以至于只有大公司才能负担得起训练一个。这导致了很多有关使用此类巨大模型道德,环境等的问题的讨论。如果对此感兴趣,可以轻松地在Internet上找到很多信息。
BERT在论文 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding中被提出。上边说过ELMo论文获得了2018年的NAACL的最佳论文奖,BERT获得了NAACL2019的最佳论文奖。
BERT的模型结构很简单,并且我们已经知道这个结构是如何进行工作的:它就是trasformer中的encoder部分。不一样的是,训练的目标和用于下游任务的方式。
怎样才能使用纯文本训练一个(双向)编码器呢?我们现在所知道的就是从左到右的语言模型可以使用纯文本进行训练。但这样的文本也仅仅decoder部分可以使用,并且只能看到每个token的之前的字不能看到未来的字。BERT的作者想出了对于没有标签的数据的另一个训练目标。在介绍这个之前,我们先看一下BERT是将什么做为Transformer的encoder的输入的。
训练输入:带有特殊token的句子对
在训练中,BERT看到的是一对用特殊token[SEP]进行分割的句子。为了使模型更容易区分这些句子,除了token和位置嵌入还使用了分词嵌入。
另外一个特殊的token是[CLS],训练过程中,它将用于NSP目标之后会介绍。模型被训练好后,就可以用于下游任务。
预训练目标:Next Sentence Prediction (NSP) Objective
The Next Sentence Prediction (NSP) 是一个二分类任务。根据最后一层的特殊token [CLS],模型预测两个句子是否是连续的句子。训练数据中,有一半的数据是从训练文本中抽取的连续的句子。另外一半则是随机组合的句子。下面的例子是初始论文中的例子。
这个任务会教模型学习理解句子之间的关系。像我们在之后看到的,这使得可以将BERT用于某些复杂的需要一些推理的任务。
预训练目标:Masked Language Modeling (MLM) Objective
BERT有两个训练目标。其中最重要的是Masked Language Modeling (MLM)。使用MLM,以下步骤会发生。
1.选择一些token:
每一个token都有15%的可能性被选中
2.将选中的token进行替换
有80%的可能替换为[MASK],有10%可能替换为一个随机token,10%可能是原token即保持不变。
3.预测原始token(计算损失)
MLM仍然是语言模型:目标是根据文本中的某一部分预测一个句子或者文本中的一些token。为了说的更清晰一些,将MLM和标准的从左到右的语言模型做一个比较。
每一步中,标准的从左到右的LM基于之前出现的词预测下一个token。这意味着,最后的从最后一层得到的用于预测的表示只编码了前文的信息,也就是说没有看到之后的信息。
不同的是,MLM一次性的看到了整个文本,但是一些tokens被屏蔽了:这就是为什么BERT是双向的。记得为了让ELMo知道左边和右边的上下文,作者需要训练两个不同的单向LM然后将他们的表示结合起来。在BERT中,就不需要这样做了,一个model就足够了。
微调:在下游任务中使用BERT
现在来看一下如何将BERT应用于不同任务。目前,我们只很简单的看一下BERT是如何在不同的下游任务中进行微调的。之后,会看到其他的为不同的任务调整模型的方法。
这部分中,只提到了一些任务。对于更多的评价数据集,可以在这里看到,
要将单个句子进行分类,将数据集以图示的形式输入,并从最后的[CLS]标签表示总预测得到标签。
任务举例:
SST-2:二元情绪分类
CoLA(Corpus of Linguistic Acceptability):判断一个句子是否是语言可接受的
想要将句子对进行分类,将数据像训练一样进行输入。和单句分类相似,从最后的[CLS]表示中预测标签。
任务举例:
SNLI:含义分类,给定一对句子,判断第二个句子是蕴含的,对立的还是中立的
QQP(Quora Question Pairs):给定两个问题,判断他们是否在语义上是相等的。
STS-B:给定两个句子返回相似度评分1-5
对于QA,BERT的作者只使用了一个数据集:SQuAD v1.1。在这个任务中,会有一个给定的文本和一个问题。问题的答案通常是文章中的一部分。任务就是找到正确的文章中的部分。
在这个问题中使用BERT,将问题和文章以图中展示的样子进行输入。之后,将文章中的每一个token使用BERT表示预测这个token是不是正确片段的开始或结束。
在标注任务中,需要为每一个token预测标签。如命名实体识别(NER),就需要预测每一个词是否是命名实体以及实体类别。