预训练语言模型的前世此生 - 从Word Embedding到BERT

本文的主题是预训练语言模型的前世此生,会大体说下 NLP 中的预训练技术是一步一步如何发展到 Bert 模型的,从中能够很天然地看到 Bert 的思路是如何逐渐造成的,Bert 的历史沿革是什么,继承了什么,创新了什么,为何效果那么好,主要缘由是什么,以及为什么说模型创新不算太大,为什么说 Bert 是近年来 NLP 重大进展的集大成者。 预训练语言模型的发展并非一蹴而就的,而是伴随着诸如词嵌入、序列到序列模型及 Attention 的发展而产生的。
预训练语言模型的前世此生 - 从Word Embedding到BERT

本篇文章共 24619 个词,一个字一个字手码的不容易,转载请标明出处:
预训练语言模型的前世此生 - 从Word Embedding到BERT - 二十三岁的有德git

 

目录

 

Bert 最近很火,应该是最近最火爆的 AI 进展,网上的评价很高,从模型创新角度看通常,创新不算大。可是架不住效果太好了,基本刷新了不少 NLP 的任务的最好性能,有些任务还被刷爆了,这个才是关键。另一点是 Bert 具有普遍的通用性,就是说绝大部分 NLP 任务均可以采用相似的两阶段模式直接去提高效果,这个第二关键。客观的说,把 Bert 当作最近两年 NLP 重大进展的集大成者更符合事实。github

本文的主题是预训练语言模型的前世此生,会大体说下 NLP 中的预训练技术是一步一步如何发展到 Bert 模型的,从中能够很天然地看到 Bert 的思路是如何逐渐造成的,Bert 的历史沿革是什么,继承了什么,创新了什么,为何效果那么好,主要缘由是什么,以及为什么说模型创新不算太大,为什么说 Bert 是近年来 NLP 重大进展的集大成者。api

预训练语言模型的发展并非一蹴而就的,而是伴随着诸如词嵌入、序列到序列模型及 Attention 的发展而产生的。网络

DeepMind 的计算机科学家 Sebastian Ruder 给出了 21 世纪以来,从神经网络技术的角度分析,天然语言处理的里程碑式进展,以下表所示:架构

年份 2013 年 2014 年 2015 年 2016 年 2017 年
技术 word2vec GloVe LSTM/Attention Self-Attention Transformer
年份 2018 年 2019 年 2020 年
技术 GPT/ELMo/BERT/GNN XLNet/BoBERTa/GPT-2/ERNIE/T5 GPT-3/ELECTRA/ALBERT

本篇文章将会经过上表显示的 NLP 中技术的发展史一一叙述,因为 19 年后的技术大都是 BERT 的变体,在这里不会多加叙述,读者能够自行加以了解。app

1、预训练

1.1 图像领域的预训练

在介绍图像领域的预训练以前,咱们首先介绍下卷积神经网络(CNN),CNN 通常用于图片分类任务,而且CNN 由多个层级结构组成,不一样层学到的图像特征也不一样,越浅的层学到的特征越通用(横竖撇捺),越深的层学到的特征和具体任务的关联性越强(人脸-人脸轮廓、汽车-汽车轮廓),以下图所示:框架

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

由此,当领导给咱们一个任务:阿猫、阿狗、阿虎的图片各十张,而后让咱们设计一个深度神经网络,经过该网络把它们三者的图片进行分类。机器学习

对于上述任务,若是咱们亲手设计一个深度神经网络基本是不可能的,由于深度学习一个弱项就是在训练阶段对于数据量的需求特别大,而领导只给咱们合计三十张图片,显然这是不够的。ide

虽然领导给咱们的数据量不多,可是咱们是否能够利用网上现有的大量已作好分类标注的图片。好比 ImageNet 中有 1400 万张图片,而且这些图片都已经作好了分类标注。函数

上述利用网络上现有图片的思想就是预训练的思想,具体作法就是:

  1. 经过 ImageNet 数据集咱们训练出一个模型 A
  2. 因为上面提到 CNN 的浅层学到的特征通用性特别强,咱们能够对模型 A 作出一部分改进获得模型 B(两种方法):
    1. 冻结:浅层参数使用模型 A 的参数,高层参数随机初始化,浅层参数一直不变,而后利用领导给出的 30 张图片训练参数
    2. 微调:浅层参数使用模型 A 的参数,高层参数随机初始化,而后利用领导给出的 30 张图片训练参数,可是在这里浅层参数会随着任务的训练不断发生变化
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

经过上述的讲解,对图像预训练作个总结(可参照上图):对于一个具备少许数据的任务 A,首先经过一个现有的大量数据搭建一个 CNN 模型 A,因为 CNN的浅层学到的特征通用性特别强,所以在搭建一个 CNN 模型 B,其中模型 B 的浅层参数使用模型 A 的浅层参数,模型 B 的高层参数随机初始化,而后经过冻结或微调的方式利用任务 A 的数据训练模型 B,模型 B 就是对应任务 A 的模型。

1.2 预训练的思想

有了图像领域预训练的引入,咱们在此给出预训练的思想:任务 A 对应的模型 A 的参数再也不是随机初始化的,而是经过任务 B 进行预先训练获得模型 B,而后利用模型 B 的参数对模型 A 进行初始化,再经过任务 A 的数据对模型 A 进行训练。注:模型 B 的参数是随机初始化的。

2、语言模型

想了解预训练语言模型,首先得了解什么是语言模型。

语言模型通俗点讲就是计算一个句子的几率。也就是说,对于语言序列 \(w_1,w_2,\cdots,w_n\),语言模型就是计算该序列的几率,即 \(P(w_1,w_2,\cdots,w_n)\)。

下面经过两个实例具体了解上述所描述的意思:

  1. 假设给定两句话 “判断这个词的磁性” 和 “判断这个词的词性”,语言模型会认为后者更天然。转化成数学语言也就是:\(P(判断,这个,词,的,词性) \gt P(判断,这个,词,的,磁性)\)
  2. 假设给定一句话作填空 “判断这个词的____”,则问题就变成了给定前面的词,找出后面的一个词是什么,转化成数学语言就是:\(P(词性|判断,这个,词,的) \gt P(磁性|判断,这个,词,的)\)

经过上述两个实例,能够给出语言模型更加具体的描述:给定一句由 \(n\) 个词组成的句子 \(W=w_1,w_2,\cdots,w_n\),计算这个句子的几率 \(P(w_1,w_2,\cdots,w_n)\),或者计算根据上文计算下一个词的几率 \(P(w_n|w_1,w_2,\cdots,w_{n-1})\)。

下面将介绍语言模型的两个分支,统计语言模型和神经网络语言模型。

2.1 统计语言模型

统计语言模型的基本思想就是计算条件几率。

给定一句由 \(n\) 个词组成的句子 \(W=w_1,w_2,\cdots,w_n\),计算这个句子的几率 \(P(w_1,w_2,\cdots,w_n)\) 的公式以下(条件几率乘法公式的推广,链式法则):

 

\[\begin{align*} P(w_1,w_2,\cdots,w_n) & = P(w_1)P(w_2|w_1)P(w_3|w_1,w_2)\cdots p(w_n|w_1,w_2,\cdots,w_{n-1}) \\ & = \prod_i P(w_i|w1,w_2,\cdots,w_{i-1}) \end{align*} \]

 

对于上一节提到的 “判断这个词的词性” 这句话,利用上述的公式,能够获得:

 

\[\begin{align*} & P(判断,这个,词,的,词性) = \\ & P(判断)P(这个|判断)P(词|判断,这个) \\ & P(的|判断,这个,词)P(词性|判断,这个,词,的)P(判断,这个,词,的,词性) \end{align*} \]

 

对于上一节提到的另一个问题,当给定前面词的序列 “判断,这个,词,的” 时,想要知道下一个词是什么,能够直接计算以下几率:

 

\[P(w_{next}|判断,这个,词,的)\quad\text{公式(1)} \]

 

其中,\(w_{next} \in V\) 表示词序列的下一个词,\(V\) 是一个具备 \(|V|\) 个词的词典(词集合)。

对于公式(1),能够展开成以下形式:

 

\[P(w_{next}|判断,这个,词,的) = \frac{count(w_{next},判断,这个,词,的)}{count(判断,这个,词,的)} \quad\text{公式(2)} \]

 

对于公式(2),能够把字典 \(V\) 中的多有单词,逐一做为 \(w_{next}\),带入计算,最后取最大几率的词做为 \(w_{next}\) 的候选词。

若是 \(|V|\) 特别大,公式(2)的计算将会很是困难,可是咱们能够引入马尔科夫链的概念(固然,在这里只是简单讲讲如何作,关于马尔科夫链的数学理论知识能够自行查看其余参考资料)。

假设字典 \(V\) 中有 “火星” 一词,能够明显发现 “火星” 不可能出如今 “判断这个词的” 后面,所以(火星,判断,这个,词,的)这个组合是不存在的,而且词典中会存在不少相似于 “火星” 这样的词。

进一步,能够发现咱们把(火星,判断,这个,词,的)这个组合判断为不存在,是由于 “火星” 不可能出如今 “词的” 后面,也就是说咱们能够考虑是否把公式(1)转化为

 

\[P(w_{next}|判断,这个,词,的) \approx P(w_{next}|词,的)\quad\text{公式(3)} \]

 

公式(3)就是马尔科夫链的思想:假设 \(w_{next}\) 只和它以前的 \(k\) 个词有相关性,\(k=1\) 时称做一个单元语言模型,\(k=2\) 时称为二元语言模型。

能够发现经过马尔科夫链后改写的公式计算起来将会简单不少,下面咱们举个简单的例子介绍下如何计算一个二元语言模型的几率。

其中二元语言模型的公式为:

 

\[P(w_i|w_{i-1})=\frac{count(w_{i-1},w_i)}{count(w_{i-1})}\quad\text{公式(4)} \]

 

假设有一个文本集合:

“词性是动词”
“判断单词的词性”
“磁性很强的磁铁”
“北京的词性是名词”

对于上述文本,若是要计算 \(P(词性|的)\) 的几率,经过公式(4),须要统计 “的,词性” 同时按序出现的次数,再除以 “的” 出现的次数:

 

\[P(词性|的) = \frac{count(的,词性)}{count(的)} = \frac{2}{3}\quad\text{公式(5)} \]

 

上述文本集合是咱们自定制的,然而对于绝大多数具备现实意义的文本,会出现数据稀疏的状况,例如训练时未出现,测试时出现了的未登陆单词。

因为数据稀疏问题,则会出现几率值为 0 的状况(填空题将没法从词典中选择一个词填入),为了不 0 值的出现,会使用一种平滑的策略——分子和分母都加入一个非 0 正数,例如能够把公式(4)改成:

 

\[P(w_i|w_{i-1}) = \frac{count(w_{i-1},w_i)+1}{count(w_{i-1})+|V|}\quad\text{公式(6)} \]

 

神经网络语言模型

上一节简单的介绍了统计语言模型,而且在结尾处讲到统计语言模型存在数据稀疏问题,针对该问题,咱们也提出了平滑方法来应对这个问题。

神经网络语言模型则引入神经网络架构来估计单词的分布,而且经过词向量的距离衡量单词之间的类似度,所以,对于未登陆单词,也能够经过类似词进行估计,进而避免出现数据稀疏问题。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上图为神经网络语言模型结构图,它的学习任务是输入某个句中单词 \(w_t = bert\) 前的 \(t-1\) 个单词,要求网络正确预测单词 “bert”,即最大化:

 

\[P(w_t=bert|w_1,w_2,\cdots,w_{t-1};\theta)\quad\text{公式(7)} \]

 

上图所示的神经网络语言模型分为三层,接下来咱们详细讲解这三层的做用:

  1. 神经网络语言模型的第一层,为输入层。首先将前 \(n-1\) 个单词用 Onehot 编码(例如:0001000)做为原始单词输入,以后乘以一个随机初始化的矩阵 Q 后得到词向量 \(C(w_i)\),对这 \(n-1\) 个词向量处理后获得输入 \(x\),记做 \(x=(C(w_1),C(w_2),\cdots,C(w_{t-1}))\)
  2. 神经网络语言模型的第二层,为隐层,包含 \(h\) 个隐变量,\(H\) 表明权重矩阵,所以隐层的输出为 \(Hx+d\),其中 \(d\) 为偏置项。而且在此以后使用 \(tanh\) 做为激活函数。
  3. 神经网络语言模型的第三层,为输出层,一共有 \(|V|\) 个输出节点(字典大小),直观上讲,每一个输出节点 \(y_i\) 是词典中每个单词几率值。最终获得的计算公式为:\(y = softmax(b+Wx+U\tanh(d+Hx))\),其中 \(W\) 是直接从输入层到输出层的权重矩阵,\(U\) 是隐层到输出层的参数矩阵。
3、词向量

在描述神经网络语言模型的时候,提到 Onehot 编码和词向量 \(C(w_i)\),可是并无具体说起他们究竟是什么玩意。

因为他们对于将来 BERT 的讲解很是重要,因此在这里重开一章来描述词向量究竟是什么,如何表示。

3.1 独热(Onehot)编码

把单词用向量表示,是把深度神经网络语言模型引入天然语言处理领域的一个核心技术。

在天然语言处理任务中,训练集大多为一个字或者一个词,把他们转化为计算机适合处理的数值类数据很是重要。

早期,人们想到的方法是使用独热(Onehot)编码,以下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

对于上图的解释,假设有一个包含 8 个次的字典 \(V\),“time” 位于字典的第 1 个位置,“banana” 位于字典的第 8 个位置,所以,采用独热表示方法,对于 “time” 的向量来讲,除了第 1 个位置为 1,其他位置为 0;对于 “banana” 的向量来讲,除了第 8 个位置为 1,其他位置为 0。

可是,对于独热表示的向量,若是采用余弦类似度计算向量间的类似度,能够明显的发现任意二者向量的类似度结果都为 0,即任意两者都不相关,也就是说独热表示没法解决词之间的类似性问题。

3.2 Word Embedding

因为独热表示没法解决词之间类似性问题,这种表示很快就被词向量表示给替代了,这个时候聪明的你可能想到了在神经网络语言模型中出现的一个词向量 \(C(w_i)\),对的,这个 \(C(w_i)\) 其实就是单词对应的 Word Embedding 值,也就是咱们这节的核心——词向量。

在神经网络语言模型中,咱们并无详细解释词向量是如何计算的,如今让咱们重看神经网络语言模型的架构图:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上图所示有一个 \(V×m\) 的矩阵 \(Q\),这个矩阵 \(Q\) 包含 \(V\) 行,\(V\) 表明词典大小,每一行的内容表明对应单词的 Word Embedding 值。

只不过 \(Q\) 的内容也是网络参数,须要学习得到,训练刚开始用随机值初始化矩阵 \(Q\),当这个网络训练好以后,矩阵 \(Q\) 的内容被正确赋值,每一行表明一个单词对应的 Word embedding 值。

可是这个词向量有没有解决词之间的类似度问题呢?为了回答这个问题,咱们能够看看词向量的计算过程:

 

\[\begin{bmatrix} 0&0&0&1&0 \end{bmatrix} \begin{bmatrix} 17&24&1\\ 23&5&7\\ 4&6&13\\ 10&12&19\\ 11&18&25 \end{bmatrix} = \begin{bmatrix} 10&12&19 \end{bmatrix} \quad\text{公式(8)} \]

 

经过上述词向量的计算,能够发现第 4 个词的词向量表示为 \([10\,12\,19]\)。

若是再次采用余弦类似度计算两个词之间的类似度,结果再也不是 0 ,既能够必定程度上描述两个词之间的类似度。

下图给了网上找的几个例子,能够看出有些例子效果仍是很不错的,一个单词表达成 Word Embedding 后,很容易找出语义相近的其它词汇。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=4、Word2Vec 模型

2013 年最火的用语言模型作 Word Embedding 的工具是 Word2Vec ,后来又出了Glove(因为 Glove 和 Word2Vec 的做用相似,并对 BERT 的讲解没有什么帮助,以后再也不多加叙述),Word2Vec是怎么工做的呢?看下图:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

Word2Vec 的网络结构其实和神经网络语言模型(NNLM)是基本相似的,只是这个图长得清晰度差了点,看上去不像,其实它们是亲兄弟。不过这里须要指出:尽管网络结构相近,并且都是作语言模型任务,可是他们训练方法不太同样。

Word2Vec 有两种训练方法:

  1. 第一种叫 CBOW,核心思想是从一个句子里面把一个词抠掉,用这个词的上文和下文去预测被抠掉的这个词;
  2. 第二种叫作 Skip-gram,和 CBOW 正好反过来,输入某个单词,要求网络预测它的上下文单词。

而你回头看看,NNLM 是怎么训练的?是输入一个单词的上文,去预测这个单词。这是有显著差别的。

为何 Word2Vec 这么处理?缘由很简单,由于 Word2Vec 和 NNLM 不同,NNLM 的主要任务是要学习一个解决语言模型任务的网络结构,语言模型就是要看到上文预测下文,而 Word Embedding只是 NNLM 无意插柳的一个副产品;可是 Word2Vec 目标不同,它单纯就是要 Word Embedding 的,这是主产品,因此它彻底能够随性地这么去训练网络。

为何要讲 Word2Vec 呢?这里主要是要引出 CBOW 的训练方法,BERT 其实跟它有关系,后面会讲解它们之间的关系,固然它们的关系 BERT 做者没说,是我猜的,至于我猜的对不对,你看完这篇文章以后能够自行判断。

5、天然语言处理的预训练模型

忽然在文章中插入这一段,其实就是给出一个问题:Word Embedding 这种作法能算是预训练吗?这其实就是标准的预训练过程。要理解这一点要看看学会 Word Embedding 后下游任务是怎么使用它的。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

假设如上图所示,咱们有个NLP的下游任务,好比 QA,就是问答问题,所谓问答问题,指的是给定一个问题 X,给定另一个句子 Y,要判断句子 Y 是不是问题 X 的正确答案。

问答问题假设设计的网络结构如上图所示,这里不展开讲了,懂得天然懂,不懂的也不要紧,由于这点对于本文主旨来讲不关键,关键是网络如何使用训练好的 Word Embedding 的。

它的使用方法其实和前面讲的 NNLM 是同样的,句子中每一个单词以 Onehot 形式做为输入,而后乘上学好的 Word Embedding 矩阵 Q,就直接取出单词对应的 Word Embedding 了。

这乍看上去好像是个查表操做,不像是预训练的作法是吧?其实否则,那个Word Embedding矩阵Q其实就是网络 Onehot 层到 embedding 层映射的网络参数矩阵。

因此你看到了,使用 Word Embedding 等价于什么?等价于把 Onehot 层到 embedding 层的网络用预训练好的参数矩阵 Q 初始化了。这跟前面讲的图像领域的低层预训练过程实际上是同样的,区别无非 Word Embedding 只能初始化第一层网络参数,再高层的参数就无能为力了。

下游NLP任务在使用 Word Embedding 的时候也相似图像有两种作法,一种是 Frozen,就是 Word Embedding 那层网络参数固定不动;另一种是 Fine-Tuning,就是 Word Embedding 这层参数使用新的训练集合训练也须要跟着训练过程更新掉。

上面这种作法就是18年以前NLP领域里面采用预训练的典型作法,而且 Word Embedding 其实对于不少下游 NLP 任务是有帮助的,只是帮助没有大到闪瞎忘记戴墨镜的围观群众的双眼而已。

6、RNN 和 LSTM

为何要在这里穿插一个 RNN(Recurrent Neural Network) 和 LSTM(Long Short-Term Memory) 呢?

由于接下来要介绍的 ELMo(Embeddings from Language Models) 模型在训练过程当中使用了双向长短时间记忆网络(Bi-LSTM)。

固然,这里只是简单地介绍,想要详细了解的能够去查看网上铺天盖地的参考资料。

6.1 RNN

传统的神经网络没法获取时序信息,然而时序信息在天然语言处理任务中很是重要。

例如对于这一句话 “我吃了一个苹果”,“苹果” 的词性和意思,在这里取决于前面词的信息,若是没有 “我吃了一个” 这些词,“苹果” 也能够翻译为乔布斯搞出来的那个被咬了一口的苹果。

也就是说,RNN 的出现,让处理时序信息变为可能。

RNN 的基本单元结构以下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上图左边部分称做 RNN 的一个 timestep,在这个 timestep 中能够看到,在 \(t\) 时刻,输入变量 \(x_t\),经过 RNN 的一个基础模块 A,输出变量 \(h_t\),而 \(t\) 时刻的信息,将会传递到下一个时刻 \(t+1\)。

若是把模块按照时序展开,则会如上图右边部分所示,由此能够看到 RNN 为多个基础模块 A 的互连,每个模块都会把当前信息传递给下一个模块。

RNN 解决了时序依赖问题,但这里的时序通常指的是短距离的,首先咱们先介绍下短距离依赖和长距离依赖的区别:

  • 短距离依赖:对于这个填空题 “我想看一场篮球____”,咱们很容易就判断出 “篮球” 后面跟的是 “比赛”,这种短距离依赖问题很是适合 RNN。
  • 长距离依赖:对于这个填空题 “我出生在中国的瓷都景德镇,小学和中学离家都很近,……,个人母语是____”,对于短距离依赖,“个人母语是” 后面能够紧跟着 “汉语”、“英语”、“法语”,可是若是咱们想精确答案,则必须回到上文中很长距离以前的表述 “我出生在中国的瓷都景德镇”,进而判断答案为 “汉语”,而 RNN 是很难学习到这些信息的。

6.2 RNN 的梯度消失问题

在这里我简单讲解下 RNN 为何不适合长距离依赖问题。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

如上图所示,为RNN模型结构,前向传播过程包括:

  • 隐藏状态:\(h^{(t)} = \sigma (z^{(t)}) = \sigma(Ux^{(t)} + Wh^{(t-1)} + b)\) ,此处激活函数通常为 \(tanh\) 。
  • 模型输出:\(o^{(t)} = Vh^{(t)} + c\)
  • 预测输出:\(\hat{y}^{(t)} = \sigma(o^{(t)})\) ,此处激活函数通常为softmax。
  • 模型损失:\(L = \sum_{t = 1}^{T} L^{(t)}\)

RNN 全部的 timestep 共享一套参数 \(U,V,W\),在 RNN 反向传播过程当中,须要计算 \(U,V,W\) 等参数的梯度,以 \(W\) 的梯度表达式为例(假设 RNN 模型的损失函数为 \(L\)):

 

\[\frac{\partial L}{\partial W} = \sum_{t = 1}^{T} \frac{\partial L}{\partial y^{(T)}} \frac{\partial y^{(T)}}{\partial o^{(T)}} \frac{\partial o^{(T)}}{\partial h^{(T)}} \left( \prod_{k=t + 1}^{T} \frac{\partial h^{(k)}}{\partial h^{(k - 1)}} \right) \frac{\partial h^{(t)}}{\partial W} \ \\ = \sum_{t = 1}^{T} \frac{\partial L}{\partial y^{(T)}} \frac{\partial y^{(T)}}{\partial o^{(T)}} \frac{\partial o^{(T)}}{\partial h^{(T)}} \left( \prod_{k=t+1}^{T} tanh^{'}(z^{(k)}) W \right) \frac{\partial h^{(t)}}{\partial W} \ \\ \quad\text{公式(9)} \]

 

对于公式(9)中的 \(\left( \prod_{k=t + 1}^{T} \frac{\partial h^{(k)}}{\partial h^{(k - 1)}} \right) = \left( \prod_{k=t+1}^{T} tanh^{'}(z^{(k)}) W \right)\),\(\tanh\) 的导数老是小于 1 的,因为是 \(T-(t+1)\) 个 timestep 参数的连乘,若是 \(W\) 的主特征值小于 1,梯度便会消失;若是 \(W\) 的特征值大于 1,梯度便会爆炸。

须要注意的是,RNN和DNN梯度消失和梯度爆炸含义并不相同。

RNN中权重在各时间步内共享,最终的梯度是各个时间步的梯度和,梯度和会愈来愈大。所以,RNN中总的梯度是不会消失的,即便梯度越传越弱,也只是远距离的梯度消失。 从公式(9)中的 \(\left( \prod_{k=t+1}^{T} tanh^{'}(z^{(k)}) W \right)\) 能够看到,RNN所谓梯度消失的真正含义是,梯度被近距离(\(t+1 趋向于 T\))梯度主导,远距离(\(t+1 远离 T\))梯度很小,致使模型难以学到远距离的信息。

6.3 LSTM

为了解决 RNN 缺少的序列长距离依赖问题,LSTM 被提了出来,首先咱们来看看 LSTM 相对于 RNN 作了哪些改进:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

如上图所示,为 LSTM 的 RNN 门控结构(LSTM 的 timestep),LSTM 前向传播过程包括:

  • 遗忘门:决定了丢弃哪些信息,遗忘门接收 \(t-1\) 时刻的状态 \(h_{t-1}\),以及当前的输入 \(x_t\),通过 Sigmoid 函数后输出一个 0 到 1 之间的值 \(f_t\)
    • 输出: \(f_{t} = \sigma(W_fh_{t-1} + U_fx_{t} + b_f)\)
  • 输入门:决定了哪些新信息被保留,并更新细胞状态,输入们的取值由 \(h_{t-1}\) 和 \(x_t\) 决定,经过 Sigmoid 函数获得一个 0 到 1 之间的值 \(i_t\),而 \(\tanh\) 函数则创造了一个当前细胞状态的候选 \(a_t\)
    • 输出:\(i_{t} = \sigma(W_ih_{t-1} + U_ix_{t} + b_i)\) , \(\tilde{C_{t} }= tanhW_ah_{t-1} + U_ax_{t} + b_a\)
  • 细胞状态:旧细胞状态 \(C_{t-1}\) 被更新到新的细胞状态 \(C_t\) 上,
    • 输出:\(C_{t} = C_{t-1}\odot f_{t} + i_{t}\odot \tilde{C_{t} }\)
  • 输出门:决定了最后输出的信息,输出门取值由 \(h_{t-1}\) 和 \(x_t\) 决定,经过 Sigmoid 函数获得一个 0 到 1 之间的值 \(o_t\),最后经过 \(\tanh\) 函数决定最后输出的信息
    • 输出:\(o_{t} = \sigma(W_oh_{t-1} + U_ox_{t} + b_o)\) , \(h_{t} = o_{t}\odot tanhC_{t}\)
  • 预测输出:\(\hat{y}_{t} = \sigma(Vh_{t}+c)\)

6.4 LSTM 解决 RNN 的梯度消失问题

明白了 RNN 梯度消失的缘由以后,咱们看 LSTM 如何解决问题的呢?

RNN 梯度消失的缘由是,随着梯度的传导,梯度被近距离梯度主导,模型难以学习到远距离的信息。具体缘由也就是 \(\prod_{k=t+1}^{T}\frac{\partial h_{k}}{\partial h_{k - 1}}\) 部分,在迭代过程当中,每一步 \(\frac{\partial h_{k}}{\partial h_{k - 1}}\) 始终在 [0,1) 之间或者始终大于 1。

而对于 LSTM 模型而言,针对 \(\prod _{k=t+1}^{T} \frac{\partial C_{k}}{\partial C_{k-1}}\) 求得:

 

\[\begin{align} & \frac{\partial C_{k}}{\partial C_{k-1}} = f_k + other \\ & \prod _{k=t+1}^{T} \frac{\partial C_{k}}{\partial C_{k-1}} = f_{k}f_{k+1}...f_{T} + other \\ \end{align} \]

 

在 LSTM 迭代过程当中,针对 \(\prod_{k=t+1}^{T} \frac{\partial C_{k}}{\partial C_{k-1}}\) 而言,每一步\(\frac{\partial C_{k}}{\partial C_{k-1}}\) 能够自主的选择在 [0,1] 之间,或者大于1,由于 \(f_{k}\) 是可训练学习的。那么总体 \(\prod _{k=t+1}^{T} \frac{\partial C_{k}}{\partial C_{k-1}}\) 也就不会一直减少,远距离梯度不至于彻底消失,也就可以解决 RNN 中存在的梯度消失问题。

LSTM 遗忘门值 \(f_t\) 能够选择在 [0,1] 之间,让 LSTM 来改善梯度消失的状况。也能够选择接近 1,让遗忘门饱和,此时远距离信息梯度不消失;也能够选择接近 0,此时模型是故意阻断梯度流,遗忘以前信息。

另外须要强调的是LSTM搞的这么复杂,除了在结构上自然地克服了梯度消失的问题,更重要的是具备更多的参数来控制模型;经过四倍于RNN的参数量,能够更加精细地预测时间序列变量。

此外,我记得有一篇文章讲到,LSTM 在 200左右长度的文本上,就已经捉襟见肘了。

7、ELMo 模型

7.1 ELMo 的预训练

在讲解 Word Embedding 时,细心地读者必定已经发现,这些词表示方法本质上是静态的,每个词都有一个惟一肯定的词向量,不能根据句子的不一样而改变,没法处理天然语言处理任务中的多义词问题。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

如上图所示,例如多义词 Bank,有两个经常使用含义,可是 Word Embedding 在对 bank 这个单词进行编码的时候,是区分不开这两个含义的。

由于尽管这两句含有 bank 的句子中 bank 上下文环境中出现的单词不一样,可是在用语言模型训练的时候,不论什么上下文的句子通过 Word2Vec,都是预测相同的单词 bank,而同一个单词占用的是同一行的参数空间,这会致使两种不一样的上下文信息都会编码到相同的 Word Embedding 空间里,进而致使Word Embedding 没法区分多义词的不一样语义。

因此对于好比 Bank 这个词,它事先学好的 Word Embedding 中混合了几种语义 ,在应用中来了个新句子,即便从上下文中(好比句子包含 money 等词)明显能够看出它表明的是 “银行” 的含义,可是对应的 Word Embedding 内容也不会变,它仍是混合了多种语义。

针对 Word Embedding 中出现的多义词问题,ELMo 提供了一个简洁优雅的解决方案。

ELMo 的本质思想是:我事先用语言模型学好一个单词的 Word Embedding,此时多义词没法区分,不过这不要紧。在我实际使用 Word Embedding 的时候,单词已经具有了特定的上下文了,这个时候我能够根据上下文单词的语义再去调整单词的 Word Embedding 表示,这样通过调整后的 Word Embedding 更能表达在这个上下文中的具体含义,天然也就解决了多义词的问题了。因此 ELMo 自己是个根据当前上下文对 Word Embedding 动态调整的思路。

ELMo 采用了典型的两阶段过程:

  1. 第一个阶段是利用语言模型进行预训练;
  2. 第二个阶段是在作下游任务时,从预训练网络中提取对应单词的网络各层的 Word Embedding 做为新特征补充到下游任务中。
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上图展现的是其第一阶段预训练过程,它的网络结构采用了双层双向 LSTM,目前语言模型训练的任务目标是根据单词 \(w_i\) 的上下文去正确预测单词 \(w_i\),\(w_i\) 以前的单词序列 Context-before 称为上文,以后的单词序列 Context-after 称为下文。

图中左端的前向双层 LSTM 表明正方向编码器,输入的是从左到右顺序的除了预测单词外 \(W_i\) 的上文 Context-before;右端的逆向双层 LSTM 表明反方向编码器,输入的是从右到左的逆序的句子下文Context-after;每一个编码器的深度都是两层 LSTM 叠加。

这个网络结构其实在 NLP 中是很经常使用的。使用这个网络结构利用大量语料作语言模型任务就能预先训练好这个网络,若是训练好这个网络后,输入一个新句子 \(s_{new}\) ,句子中每一个单词都能获得对应的三个 Embedding:

  • 最底层是单词的 Word Embedding;
  • 往上走是第一层双向 LSTM 中对应单词位置的 Embedding,这层编码单词的句法信息更多一些;
  • 再往上走是第二层 LSTM 中对应单词位置的 Embedding,这层编码单词的语义信息更多一些。

也就是说,ELMo 的预训练过程不只仅学会单词的 Word Embedding,还学会了一个双层双向的 LSTM 网络结构,而这二者后面都有用。

7.2 ELMo 的 Feature-based Pre-Training

上面介绍的是 ELMo 的第一阶段:预训练阶段。那么预训练好网络结构后,如何给下游任务使用呢?

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上图展现了下游任务的使用过程,好比咱们的下游任务仍然是 QA 问题,此时对于问句 X:

  1. 咱们能够先将句子 X 做为预训练好的 ELMo 网络的输入,这样句子 X 中每一个单词在 ELMO 网络中都能得到对应的三个 Embedding;
  2. 以后给予这三个 Embedding 中的每个 Embedding 一个权重 a,这个权重能够学习得来,根据各自权重累加求和,将三个 Embedding 整合成一个;
  3. 而后将整合后的这个 Embedding 做为 X 句在本身任务的那个网络结构中对应单词的输入,以此做为补充的新特征给下游任务使用。
  4. 对于上图所示下游任务 QA 中的回答句子 Y 来讲也是如此处理。

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

至于为什么这么作可以达到区分多义词的效果,缘由在于在训练好 ELMo 后,在特征提取的时候,每一个单词在两层 LSTM 上都会有对应的节点,这两个节点会编码单词的一些句法特征和语义特征,而且它们的 Embedding 编码是动态改变的,会受到上下文单词的影响,周围单词的上下文不一样应该会强化某种语义,弱化其它语义,进而就解决了多义词的问题。

8、Attention

上面巴拉巴拉了一堆,都在为 BERT 的讲解作铺垫,而接下来要叙述的 Attention 和 Transformer 一样如此,它们都只是 BERT 构成的一部分。

8.1 人类的视觉注意力

Attention 是注意力的意思,从它的命名方式看,很明显借鉴了人类的注意力机制,所以,咱们首先介绍人类的视觉注意力。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

视觉注意力机制是人类视觉所特有的大脑信号处理机制。人类视觉经过快速扫描全局图像,得到须要重点关注的目标区域,也就是通常所说的注意力焦点,然后对这一区域投入更多注意力资源,以获取更多所须要关注目标的细节信息,而抑制其余无用信息。

这是人类利用有限的注意力资源从大量信息中快速筛选出高价值信息的手段,是人类在长期进化中造成的一种生存机制,人类视觉注意力机制极大地提升了视觉信息处理的效率与准确性。

上图形象化展现了人类在看到一副图像时是如何高效分配有限的注意力资源的,其中红色区域代表视觉系统更关注的目标,很明显对于上图所示的场景,人们会把注意力更多投入到人的脸部,文本的标题以及文章首句等位置。

深度学习中的注意力机制从本质上讲和人类的选择性视觉注意力机制相似,核心目标也是从众多信息中选择出对当前任务目标更关键的信息。

8.2 Attention 的本质思想

从人类的视觉注意力能够看出,注意力模型 Attention 的本质思想为:从大量信息中有选择地筛选出少许重要信息并聚焦到这些重要信息上,忽略不重要的信息。

在详细讲解 Attention以前,咱们在讲讲 Attention的其余做用。以前咱们讲解 LSTM 的时候说到,虽然 LSTM 解决了序列长距离依赖问题,可是单词超过 200 的时候就会失效。而 Attention 机制能够更加好的解决序列长距离依赖问题,而且具备并行计算能力。如今不明白这点不重要,随着咱们对 Attention 的慢慢深刻,相信你会明白。

首先咱们得明确一个点,注意力模型从大量信息 Values 中筛选出少许重要信息,这些重要信息必定是相对于另一个信息 Query 而言是重要的,例如对于上面那张婴儿图,Query 就是观察者。也就是说,咱们要搭建一个注意力模型,咱们必须得要有一个 Query 和一个 Values,而后经过 Query 这个信息从 Values 中筛选出重要信息。

经过 Query 这个信息从 Values 中筛选出重要信息,简单点说,就是计算 Query 和 Values 中每一个信息的相关程度。

再具体点,Attention 一般能够进行以下描述,表示为将 Query(Q) 和 key-value pairs(把 Values 拆分红了键值对的形式) 映射到输出上,其中 query、每一个 key、每一个 value 都是向量,输出是 V 中全部 values 的加权,其中权重是由 Query 和每一个 key 计算出来的,计算方法分为三步:

  1. 第一步:计算比较 Q 和 K 的类似度,用 f 来表示:\(f(Q,K_i)\quad i=1,2,\cdots,m\),通常第一步计算方法包括四种
    1. 点乘(Transformer 使用):\(f(Q,K_i) = Q^T K_i\)
    2. 权重:\(f(Q,K_i) = Q^TWK_i\)
    3. 拼接权重:\(f(Q,K_i) = W[Q^T;K_i]\)
    4. 感知器:\(f(Q,K_i)=V^T \tanh(WQ+UK_i)\)
  2. 第二步:将获得的类似度进行 softmax 操做,进行归一化:\(\alpha_i = softmax(\frac{f(Q,K_i)}{\sqrt d_k})\)
    1. 这里简单讲解除以 \(\sqrt d_k\) 的做用:假设 \(Q\) , \(K\) 里的元素的均值为0,方差为 1,那么 \(A^T=Q^TK\) 中元素的均值为 0,方差为 d。当 d 变得很大时, \(A\) 中的元素的方差也会变得很大,若是 \(A\) 中的元素方差很大(分布的方差大,分布集中在绝对值大的区域),在数量级较大时, softmax 将几乎所有的几率分布都分配给了最大值对应的标签,因为某一维度的数量级较大,进而会致使 softmax 将来求梯度时会消失。总结一下就是 \(\operatorname{softmax}\left(A\right)\) 的分布会和d有关。所以 \(A\) 中每个元素乘上 \(\frac{1}{\sqrt{d_k}}\) 后,方差又变为 1,而且 \(A\) 的数量级也将会变小。
  3. 第三步:针对计算出来的权重 \(\alpha_i\),对 \(V\) 中的全部 values 进行加权求和计算,获得 Attention 向量:\(Attention = \sum_{i=1}^m \alpha_i V_i\)

8.3 Self Attention 模型

上面已经讲了 Attention 就是从一堆信息中筛选出重要的信息,如今咱们来经过 Self Attention 模型来详细讲解如何找到这些重要的信息。

Self Attention 模型的架构以下图所示,接下来咱们将按照这个模型架构的顺序来逐一解释。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

首先能够看到 Self Attention 有三个输入 Q、K、V:对于 Self Attention,Q、K、V 来自句子 X 的 词向量 x 的线性转化,即对于词向量 x,给定三个可学习的矩阵参数 \(W_Q,W_k,W_v\),x 分别右乘上述矩阵获得 Q、K、V。

接下来为了表示的方便,咱们先经过向量的计算叙述 Self Attention 计算的流程,而后再描述 Self Attention 的矩阵计算过程

  1. 第一步,Q、K、V 的获取

    1.  
    watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

    上图操做:两个单词 Thinking 和 Machines。经过线性变换,即 \(x_i\) 和 \(x_2\) 两个向量分别与\(W_q,W_k,W_v\) 三个矩阵点乘获得 ${q_1,q_2},{k_1,k_2},{v_1,v_2} $ 共 6 个向量。矩阵 Q 则是向量 \(q_1,q_2\) 的拼接,K、V 同理。

  2. 第二步,MatMul

    1. watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

      上图操做:向量 \({q_1,k_1}\) 作点乘获得得分 112, \({q_1,k_2}\) 作点乘获得得分96。注意:这里是经过 \(q_1\) 这个信息找到 \(x_1,x_2\) 中的重要信息。

  3. 第三步和第四步,Scale + Softmax

    1. watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

    上图操做:对该得分进行规范,除以 \(\sqrt {d_k} = 8\)

  4. 第五步,MatMul

    1. watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

用得分比例 [0.88,0.12] 乘以 \([v_1,v_2]\) 值获得一个加权后的值,将这些值加起来获得 \(z_1\)。

上述所说就是 Self Attention 模型所作的事,仔细感觉一下,用 \(q_1\)、\(K=[k_1,k_2]\) 去计算一个 Thinking 相对于 Thinking 和 Machine 的权重,再用权重乘以 Thinking 和 Machine 的 \(V=[v_1,v_2]\) 获得加权后的 Thinking 和 Machine 的 \(V=[v_1,v_2]\),最后求和获得针对各单词的输出 \(z_1\)。

同理能够计算出 Machine 相对于 Thinking 和 Machine 的加权输出 \(z_2\),拼接 \(z_1\) 和 \(z_2\) 便可获得 Attention 值 \(Z=[z_1,z_2]\),这就是 Self Attention 的矩阵计算,以下所示。

以前的例子是单个向量的运算例子。这张图展现的是矩阵运算的例子,输入是一个 [2x4] 的矩阵(句子中每一个单词的词向量的拼接),每一个运算是 [4x3] 的矩阵,求得 Q、K、V。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

Q 对 K 转制作点乘,除以 \(\sqrt d_k\),作一个 softmax 获得合为 1 的比例,对 V 作点乘获得输出 Z。那么这个 Z 就是一个考虑过 Thinking 周围单词 Machine 的输出。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

注意看这个公式,\(QK^T\) 其实就会组成一个 word2word 的 attention map!(加了 softmax 以后就是一个合为 1 的权重了)。好比说你的输入是一句话 "i have a dream" 总共 4 个单词,这里就会造成一张 4x4 的注意力机制的图:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

这样一来,每个单词对应每个单词都会有一个权重,这也是 Self Attention 名字的来源,即 Attention 的计算来源于 Source(源句) 和 Source 自己,通俗点讲就是 Q、K、V 都来源于输入 X 自己。

8.4 Self Attention 和 RNN、LSTM 的区别

引入 Self Attention 有什么好处呢?或者说经过 Self Attention 到底学到了哪些规律或者抽取出了哪些特征呢?咱们能够经过下述两幅图来说解:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

从上述两张图能够看出,Self Attention 能够捕获同一个句子中单词之间的一些句法特征(例如第一张图展现的有必定距离的短语结构)或者语义特征(例如第二张图展现的 its 的指代对象为 Law)。

有了上述的讲解,咱们如今能够来看看 Self Attention 和 RNN、LSTM 的区别:

  • RNN、LSTM:若是是 RNN 或者 LSTM,须要依次序列计算,对于远距离的相互依赖的特征,要通过若干时间步步骤的信息累积才能将二者联系起来,而距离越远,有效捕获的可能性越小。
  • Self Attention:
    • 经过上述两幅图,很明显的能够看出,引入 Self Attention 后会更容易捕获句子中长距离的相互依赖的特征,由于 Self Attention 在计算过程当中会直接将句子中任意两个单词的联系经过一个计算步骤直接联系起来,因此远距离依赖特征之间的距离被极大缩短,有利于有效地利用这些特征;
    • 除此以外,Self
      Attention 对于一句话中的每一个单词均可以单独的进行 Attention 值的计算,也就是说 Self Attention 对计算的并行性也有直接帮助做用,而对于必须得依次序列计算的 RNN 而言,是没法作到并行计算的。

上述所说的,则是为什么 Self Attention 逐渐替代 RNN、LSTM 被普遍使用的缘由所在。

8.5 Masked Self Attention 模型

趁热打铁,咱们讲讲 Transformer 将来会用到的 Masked Self Attention 模型,这里的 Masked 就是要在作语言模型(或者像翻译)的时候,不给模型看到将来的信息,它的结构以下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上图中和 Self Attention 重复的部分此处就不讲了,主要讲讲 Mask 这一块。

假设在此以前咱们已经经过 scale 以前的步骤获得了一个 attention map,而 mask 就是沿着对角线把灰色的区域用0覆盖掉,不给模型看到将来的信息,以下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

详细来讲:

  1. "i" 做为第一个单词,只能有和 "i" 本身的 attention;
  2. "have" 做为第二个单词,有和 "i、have" 前面两个单词的 attention;
  3. "a" 做为第三个单词,有和 "i、have、a" 前面三个单词的 attention;
  4. "dream" 做为最后一个单词,才有对整个句子 4 个单词的 attention。

而且在作完 softmax 以后,横轴结果合为 1。以下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

具体为何要 mask,将来再讲解 Transformer 的时候咱们会详细解释。

8.6 Multi-head Self Attention 模型

因为 Transformer 使用的都是 Self Attention 的进阶版 Multi-head Self Attention,咱们简单讲讲 Multi-head Self Attention 的架构,而且在该小节结尾处讲讲它的优势。

Multi-Head Attention 就是把 Self Attention的过程作 H 次,而后把输出 Z 合起来。论文中,它的结构图以下:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

咱们仍是以上面的形式来解释,首先,咱们使用 8 组不一样的 \(W_Q^i,W_k^i,W_V^i\quad i=1,2,\cdots,8\) ,重复 8 次和 Self Attention 类似的操做,获得 8 个 \(Z_i\) 矩阵:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

为了使得输出与输入结构相同,拼接矩阵 \(Z_i\) 后乘以一个线性 \(W_0\) 获得最终的Z:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

看完了 Multi-head Self Attention 的架构,发现它与 Self Attention 的区别,在于用了 \(n\) 组 \(W_Q^i,W_k^i,W_V^i\quad i=1,2,\cdots,n\) 获得 \(n\) 组 \(Q_i,K_i,V_i \quad i=1,2,\cdots,n\)。

能够经过下图看看 multi-head attention 的整个流程:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上述操做有什么好处呢?使用多套参数,多套参数至关于把原始信息 Source 放入了多个子空间中,也就是捕捉了多个信息,对于使用 multi-head(多头) attention 的简单回答就是,多头保证了 attention 能够注意到不一样子空间的信息,捕捉到更加丰富的特征信息。其实本质上是论文原做者发现这样效果确实好。

9、Position Embedding

在 Attention 和 RNN、LSTM 的对比中,咱们说到 Attention 解决了长距离依赖问题,而且能够支持并行化,可是它就真的百利而无一害了吗?

其实否则,咱们往前回顾,Self Attention 的 Q、K、V 三个矩阵是由同一个输入 \(X_1=(x_1,x_2,\cdots,x_n)\) 线性转换而来,也就是说对于这样的一个被打乱序列顺序的 \(X_2=(x_2,x_1,\cdots,x_n)\) 而言,因为 Attention 值的计算最终会被加权求和,也就是说二者最终计算的 Attention 值都是同样的,进而也就代表了 Attention 丢掉了 \(X_1\) 的序列顺序信息。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

如上图所示,为了解决 Attention 丢失的序列顺序信息,Transformer 的提出者提出了 Position Embedding,也就是对于输入 \(X\) 进行 Attention 计算以前,在 \(X\) 的词向量中加上位置信息,也就是说 \(X\) 的词向量为 \(X_{final\_embedding} = Embedding + Positional\, Embedding\)

可是如何获得 \(X\) 的位置向量呢?

其中位置编码公式以下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

其中 pos 表示位置、i 表示维度、\(d_{model}\)表示位置向量的向量维度 、\(2i、2i+1\) 表示的是奇偶数(奇偶维度),上图所示就是偶数位置使用 \(\sin\) 函数,奇数位置使用 \(\cos\) 函数。

有了位置编码,咱们再来看看位置编码是如何嵌入单词编码的(其中 512 表示编码维度),经过把单词的词向量和位置向量进行叠加,这种方式就称做位置嵌入,以下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

Position Embedding 自己是一个绝对位置的信息,但在语言模型中,相对位置也很重要。那么为何位置嵌入机制有用呢?

咱们不要去关心三角函数公式,能够看看下图公式(3)中的第一行,咱们作以下的解释,对于 “我爱吃苹果” 这一句话,有 5 个单词,假设序号分别为 一、二、三、四、5。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

假设 \(pos=1=我、k=2=爱、pos+k=3=吃\),也就是说 \(pos+k=3\) 位置的位置向量的某一维能够经过 \(pos=1\) 位置的位置向量的某一维线性组合加以线性表示,经过该线性表示能够得出 “吃” 的位置编码信息蕴含了相对于前两个字 “我” 的位置编码信息。

总而言之就是,某个单词的位置信息是其余单词位置信息的线性组合,这种线性组合就意味着位置向量中蕴含了相对位置信息。

10、Transformer

10.1 Transformer 的结构

万事俱备,只欠东风,下面咱们来说讲咱们的重点之一,Transformer,你能够先记住这一句话:Transformer 简单点看其实就是 self-attention 模型的叠加,首先咱们来看看 Transformer 的总体框架。

Transformer 的总体框架以下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上图所示的总体框架乍一眼一看很是复杂,因为 Transformer 起初是做为翻译模型,所以咱们以翻译举例,简化一下上述的总体框架:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

从上图能够看出 Transformer 至关于一个黑箱,左边输入 “Je suis etudiant”,右边会获得一个翻译结果 “I am a student”。

再往细里讲,Transformer 也是一个 Seq2Seq 模型(Encoder-Decoder 框架的模型),左边一个 Encoders 把输入读进去,右边一个 Decoders 获得输出,以下所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

在这里,咱们穿插描述下 Encoder-Decoder 框架的模型是如何进行文本翻译的:

  1. 将序列 \((x_1,x_2,\cdots,x_n)\) 做为 Encoders 的输入,获得输出序列 \((z_1,z_2,\cdots,z_n)\)
  2. 把 Encoders 的输出序列 \((z_1,z_2,\cdots,z_n)\) 做为 Decoders 的输入,生成一个输出序列 \((y_1,y_2,\cdots,y_m)\)。注:Decoders 每一个时刻输出一个结果

第一眼看到上述的 Encodes-Decoders 框架图,随之产生问题就是 Transformer 中 左边 Encoders 的输出是怎么和右边 Decoders 结合的。由于decoders 里面是有N层的,再画张图直观的看就是这样:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

也就是说,Encoders 的输出,会和每一层的 Decoder 进行结合。

如今咱们取其中一层进行详细的展现:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

经过上述分析,发现咱们想要详细了解 Transformer,只要了解 Transformer 中的 Encoder 和 Decoder 单元便可,接下来咱们将详细阐述这两个单元。

10.2 Encoder

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

有了上述那么多知识的铺垫,咱们知道 Eecoders 是 N=6 层,经过上图咱们能够看到每层 Encoder 包括两个 sub-layers:

  • 第一个 sub-layer 是 multi-head self-attention,用来计算输入的 self-attention;
  • 第二个 sub-layer 是简单的前馈神经网络层 Feed Forward;

注意:在每一个 sub-layer 咱们都模拟了残差网络(在下面的数据流示意图中会细讲),每一个sub-layer的输出都是 \(LayerNorm(x+Sub\_layer(x))\),其中 \(sub\_layer\) 表示的是该层的上一层的输出

如今咱们给出 Encoder 的数据流示意图,一步一步去剖析

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
  1. 深绿色的 \(x_1\) 表示 Embedding 层的输出,加上表明 Positional Embedding 的向量以后,获得最后输入 Encoder 中的特征向量,也就是浅绿色向量 \(x_1\);
  2. 浅绿色向量 \(x_1\) 表示单词 “Thinking” 的特征向量,其中 \(x_1\) 通过 Self-Attention 层,变成浅粉色向量 \(z_1\);
  3. \(x_1\) 做为残差结构的直连向量,直接和 \(z_1\) 相加,以后进行 Layer Norm 操做,获得粉色向量 \(z_1\);
    1. 残差结构的做用:避免出现梯度消失的状况
    2. Layer Norm 的做用:为了保证数据特征分布的稳定性,而且能够加速模型的收敛
  4. \(z_1\) 通过前馈神经网络(Feed Forward)层,通过残差结构与自身相加,以后通过 LN 层,获得一个输出向量 \(r_1\);
    1. 该前馈神经网络包括两个线性变换和一个ReLU激活函数:\(FFN(x) = max(0,xW_1+b_1)W_2+b2\)
  5. 因为 Transformer 的 Encoders 具备 6 个 Encoder,\(r_1\) 也将会做为下一层 Encoder 的输入,代替 \(x_1\) 的角色,如此循环,直至最后一层 Encoder。

须要注意的是,上述的 \(x、z、r\) 都具备相同的维数,论文中为 512 维。

10.3 Decoder

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

Decoders 也是 N=6 层,经过上图咱们能够看到每层 Decoder 包括 3 个 sub-layers:

  • 第一个 sub-layer 是 Masked multi-head self-attention,也是计算输入的 self-attention;
    • 在这里,先不解释为何要作 Masked,后面在 “Transformer 动态流程展现” 这一小节会解释
  • 第二个 sub-layer 是 Encoder-Decoder Attention 计算,对 Encoder 的输入和 Decoder 的Masked multi-head self-attention 的输出进行 attention 计算;
    • 在这里,一样不解释为何要对 Encoder 和 Decoder 的输出一同作 attention 计算,后面在 “Transformer 动态流程展现” 这一小节会解释
  • 第三个 sub-layer 是前馈神经网络层,与 Encoder 相同。

10.4 Transformer 输出结果

以上,就讲完了 Transformer 编码和解码两大模块,那么咱们回归最初的问题,将 “机器学习” 翻译成 “machine learing”,解码器的输出是一个浮点型的向量,怎么转化成 “machine learing” 这两个词呢?让咱们来看看 Encoders 和 Decoders 交互的过程寻找答案:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

从上图能够看出,Transformer 最后的工做是让解码器的输出经过线性层 Linear 后接上一个 softmax

  • 其中线性层是一个简单的全链接神经网络,它将解码器产生的向量 A 投影到一个更高维度的向量 B 上,假设咱们模型的词汇表是10000个词,那么向量 B 就有10000个维度,每一个维度对应一个唯一的词的得分。
  • 以后的softmax层将这些分数转换为几率。选择几率最大的维度,并对应地生成与之关联的单词做为此时间步的输出就是最终的输出啦!
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

假设词汇表维度是 6,那么输出最大几率词汇的过程以下:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=11、Transformer 动态流程展现

首先咱们来看看拿 Transformer 做翻译时,如何生成翻译结果的:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

继续进行:

tf-%E5%8A%A8%E6%80%81%E7%BB%93%E6%9E%9C-2.gif watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

假设上图是训练模型的某一个阶段,咱们来结合 Transformer 的完整框架描述下这个动态的流程图:

  1. 输入 “je suis etudiant” 到 Encoders,而后获得一个 \(K_e\)、\(V_e\) 矩阵;
  2. 输入 “I am a student” 到 Decoders ,首先经过 Masked Multi-head Attention 层获得 “I am a student” 的 attention 值 \(Q_d\),而后用 attention 值 \(Q_d\) 和 Encoders 的输出 \(K_e\)、\(V_e\) 矩阵进行 attention 计算,获得第 1 个输出 “I”;
  3. 输入 “I am a student” 到 Decoders ,首先经过 Masked Multi-head Attention 层获得 “I am a student” 的 attention 值 \(Q_d\),而后用 attention 值 \(Q_d\) 和 Encoders 的输出 \(K_e\)、\(V_e\) 矩阵进行 attention 计算,获得第 2 个输出 “am”;
  4. ……

如今咱们来解释咱们以前遗留的两个问题。

11.1 为何 Decoder 须要作 Mask

  • 训练阶段:咱们知道 “je suis etudiant” 的翻译结果为 “I am a student”,咱们把 “I am a student” 的 Embedding 输入到 Decoders 里面,翻译第一个词 “I” 时

    • 若是对 “I am a student” attention 计算不作 mask,“am,a,student” 对 “I” 的翻译将会有必定的贡献
    • 若是对 “I am a student” attention 计算作 mask,“am,a,student” 对 “I” 的翻译将没有贡献
  • 测试阶段:咱们不知道 “我爱中国” 的翻译结果为 “I love China”,咱们只能随机初始化一个 Embedding 输入到 Decoders 里面,翻译第一个词 “I” 时:

    • 不管是否作 mask,“love,China” 对 “I” 的翻译都不会产生贡献
    • 可是翻译了第一个词 “I” 后,随机初始化的 Embedding 有了 “I” 的 Embedding,也就是说在翻译第二词 “love” 的时候,“I” 的 Embedding 将有必定的贡献,可是 “China” 对 “love” 的翻译毫无贡献,随之翻译的进行,已经翻译的结果将会对下一个要翻译的词都会有必定的贡献,这就和作了 mask 的训练阶段作到了一种匹配

总结下就是:Decoder 作 Mask,是为了让训练阶段和测试阶段行为一致,不会出现间隙,避免过拟合

11.2 为何 Encoder 给予 Decoders 的是 K、V 矩阵

咱们在讲解 Attention 机制中曾提到,Query 的目的是借助它从一堆信息中找到重要的信息。

如今 Encoder 提供了 \(K_e、V_e\) 矩阵,Decoder 提供了 \(Q_d\) 矩阵,经过 “我爱中国” 翻译为 “I love China” 这句话详细解释下。

当咱们翻译 “I” 的时候,因为 Decoder 提供了 \(Q_d\) 矩阵,经过与 \(K_e、V_e\) 矩阵的计算,它能够在 “我爱中国” 这四个字中找到对 “I” 翻译最有用的单词是哪几个,并以此为依据翻译出 “I” 这个单词,这就很好的体现了注意力机制想要达到的目的,把焦点放在对本身而言更为重要的信息上。

  • 其实上述说的就是 Attention 里的 soft attention机制,解决了曾经的 Encoder-Decoder 框架的一个问题,在这里很少作叙述,有兴趣的能够参考网上的一些资料。
    • 早期的 Encoder-Decoder 框架中的 Encoder 经过 LSTM 提取出源句(Source) “我爱中国” 的特征信息 C,而后 Decoder 作翻译的时候,目标句(Target)“I love China” 中的任何一个单词的翻译都来源于相同特征信息 C,这种作法是极其不合理的,例如翻译 “I” 时应该着眼于 “我”,翻译 “China” 应该着眼于 “中国”,而早期的这种作法并无体现出,然而 Transformer 却经过 Attention 的作法解决了这个问题。
12、GPT 模型

12.1 GPT 模型的预训练

在讲解 ELMo 的时候,咱们说到 ELMo 这一类预训练的方法被称为 “Feature-based Pre-Training”。而且若是把 ELMo 这种预训练方法和图像领域的预训练方法对比,发现二者模式看上去仍是有很大差别的。

除了以 ELMo 为表明的这种基于特征融合的预训练方法外,NLP 里还有一种典型作法,这种作法和图像领域的方式就是看上去一致的了,通常将这种方法称为 “基于Fine-tuning的模式”,而 GPT 就是这一模式的典型开创者,下面先让咱们看看 GPT 的网络结构。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

GPT 是 “Generative Pre-Training” 的简称,从名字看其含义是指的生成式的预训练。

GPT也采用两阶段过程:

  1. 第一个阶段:利用语言模型进行预训练;
  2. 第二个阶段:经过 Fine-tuning 的模式解决下游任务。

上图展现了 GPT 的预训练过程,其实和 ELMo 是相似的,主要不一样在于两点:

  1. 首先,特征抽取器用的不是 RNN,而是用的 Transformer,它的特征抽取能力要强于RNN,这个选择很明显是很明智的;
  2. 其次,
    1. GPT 的预训练虽然仍然是以语言模型做为目标任务,可是采用的是单向的语言模型,所谓 “单向” 的含义是指:语言模型训练的任务目标是根据 \(w_i\) 单词的上下文去正确预测单词 \(w_i\) , \(w_i\) 以前的单词序列Context-before称为上文,以后的单词序列Context-after称为下文。
    2. ELMo 在作语言模型预训练的时候,预测单词 \(w_i\) 同时使用了上文和下文,而 GPT 则只采用 Context-before 这个单词的上文来进行预测,而抛开了下文。
    3. GPT 这个选择如今看不是个太好的选择,缘由很简单,它没有把单词的下文融合进来,这限制了其在更多应用场景的效果,好比阅读理解这种任务,在作任务的时候是能够容许同时看到上文和下文一块儿作决策的。若是预训练时候不把单词的下文嵌入到 Word Embedding 中,是很吃亏的,白白丢掉了不少信息。

12.2 GPT 模型的 Fine-tuning

上面讲的是 GPT 如何进行第一阶段的预训练,那么假设预训练好了网络模型,后面下游任务怎么用?它有本身的个性,和 ELMO 的方式大有不一样。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上图展现了 GPT 在第二阶段如何使用:

  1. 首先,对于不一样的下游任务来讲,原本你能够任意设计本身的网络结构,如今不行了,你要向 GPT 的网络结构看齐,把任务的网络结构改形成和 GPT 同样的网络结构。

  2. 而后,在作下游任务的时候,利用第一步预训练好的参数初始化 GPT 的网络结构,这样经过预训练学到的语言学知识就被引入到你手头的任务里来了。

  3. 再次,你能够用手头的任务去训练这个网络,对网络参数进行 Fine-tuning,使得这个网络更适合解决手头的问题。就是这样。

这有没有让你想起最开始提到的图像领域如何作预训练的过程,对,这跟那个预训练的模式是如出一辙的。

对于 NLP 各类花样的不一样任务,怎么改造才能靠近 GPT 的网络结构呢?因为 GPT 对下游任务的改造过程和 BERT 对下游任务的改造极其相似,而且咱们主要目的是为了讲解 BERT,因此这个问题将会在 BERT 那里获得回答。

十3、BERT 模型

13.1 BERT:公认的里程碑

BERT 模型能够做为公认的里程碑式的模型,可是它最大的优势不是创新,而是集大成者,而且这个集大成者有了各项突破,下面让咱们看看 BERT 是怎么集大成者的。

  • BERT 的意义在于:从大量无标记数据集中训练获得的深度模型,能够显著提升各项天然语言处理任务的准确率。
  • 近年来优秀预训练语言模型的集大成者:参考了 ELMO 模型的双向编码思想、借鉴了 GPT 用 Transformer 做为特征提取器的思路、采用了 word2vec 所使用的 CBOW 方法
  • BERT 和 GPT 之间的区别:
    • GPT:GPT 使用 Transformer Decoder 做为特征提取器、具备良好的文本生成能力,然而当前词的语义只能由其前序词决定,而且在语义理解上不足
    • BERT:使用了 Transformer Encoder 做为特征提取器,并使用了与其配套的掩码训练方法。虽然使用双向编码让 BERT 再也不具备文本生成能力,可是 BERT 的语义信息提取能力更强
  • 单向编码和双向编码的差别,以该句话举例 “今每天气很{},咱们不得不取消户外运动”,分别从单向编码和双向编码的角度去考虑 {} 中应该填什么词:
    • 单向编码:单向编码只会考虑 “今每天气很”,以人类的经验,大几率会从 “好”、“不错”、“差”、“糟糕” 这几个词中选择,这些词能够被划为大相径庭的两类
    • 双向编码:双向编码会同时考虑上下文的信息,即除了会考虑 “今每天气很” 这五个字,还会考虑 “咱们不得不取消户外运动” 来帮助模型判断,则大几率会从 “差”、“糟糕” 这一类词中选择

13.2 BERT 的结构:强大的特征提取能力

  • 以下图所示,咱们来看看 ELMo、GPT 和 BERT 三者的区别

    • watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
    • ELMo 使用自左向右编码和自右向左编码的两个 LSTM 网络,分别以 \(P(w_i|w_1,\cdots,w_{i-1})\) 和 \(P(w_i|w_{i+1},\cdots,w_n)\) 为目标函数独立训练,将训练获得的特征向量以拼接的形式实现双向编码,本质上仍是单向编码,只不过是两个方向上的单向编码的拼接而成的双向编码。
    • GPT 使用 Transformer Decoder 做为 Transformer Block,以 \(P(w_i|w_1,\cdots,w_{i-1})\) 为目标函数进行训练,用 Transformer Block 取代 LSTM 做为特征提取器,实现了单向编码,是一个标准的预训练语言模型,即便用 Fine-Tuning 模式解决下游任务。
    • BERT 也是一个标准的预训练语言模型,它以 \(P(w_i|w_1,\cdots,w_{i-1},w_{i+1},\cdots,w_n)\) 为目标函数进行训练,BERT 使用的编码器属于双向编码器。
      • BERT 和 ELMo 的区别在于使用 Transformer Block 做为特征提取器,增强了语义特征提取的能力;
      • BERT 和 GPT 的区别在于使用 Transformer Encoder 做为 Transformer Block,而且将 GPT 的单向编码改为双向编码,也就是说 BERT 舍弃了文本生成能力,换来了更强的语义理解能力。

BERT 的模型结构以下图所示:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

从上图能够发现,BERT 的模型结构其实就是 Transformer Encoder 模块的堆叠。在模型参数选择上,论文给出了两套大小不一致的模型。

\(BERT_{BASE}\) :L = 12,H = 768,A = 12,总参数量为 1.1 亿

\(BERT_{LARGE}\):L = 24,H = 1024,A = 16,总参数量为 3.4 亿

其中 L 表明 Transformer Block 的层数;H 表明特征向量的维数(此处默认 Feed Forward 层中的中间隐层的维数为 4H);A 表示 Self-Attention 的头数,使用这三个参数基本能够定义 BERT的量级。

BERT 参数量级的计算公式:

 

\[\begin{align*} & 词向量参数+ 12 * (Multi-Heads参数 + 全链接层参数 + layernorm参数)\\ & = (30522+512 + 2)* 768 + 768 * 2 \\ & + 12 * (768 * 768 / 12 * 3 * 12 + 768 * 768 + 768 * 3072 * 2 + 768 * 2 * 2) \\ & = 108808704.0 \\ & \approx 110M \end{align*} \]

 

训练过程也是很花费计算资源和时间的,总之表示膜拜,普通人即使有 idea 没有算力也只能跪着。

13.3 BERT 之无监督训练

和 GPT 同样,BERT 也采用二段式训练方法:

  1. 第一阶段:使用易获取的大规模无标签余料,来训练基础语言模型;
  2. 第二阶段:根据指定任务的少许带标签训练数据进行微调训练。

不一样于 GPT 等标准语言模型使用 \(P(w_i|w_1,\cdots,w_{i-1})\) 为目标函数进行训练,能看到全局信息的 BERT 使用 \(P(w_i|w_1,\cdots,w_{i-1},w_{i+1},\cdots,w_n)\) 为目标函数进行训练。

而且 BERT 用语言掩码模型(MLM)方法训练词的语义理解能力;用下句预测(NSP)方法训练句子之间的理解能力,从而更好地支持下游任务。

13.4 BERT之语言掩码模型(MLM)

BERT 做者认为,使用自左向右编码和自右向左编码的单向编码器拼接而成的双向编码器,在性能、参数规模和效率等方面,都不如直接使用深度双向编码器强大,这也是为何 BERT 使用 Transformer Encoder 做为特征提取器,而不使用自左向右编码和自右向左编码的两个 Transformer Decoder做为特征提取器的缘由。

因为没法使用标准语言模型的训练模式,BERT 借鉴完形填空任务和 CBOW 的思想,使用语言掩码模型(MLM )方法训练模型。

MLM 方法也就是随机去掉句子中的部分 token(单词),而后模型来预测被去掉的 token 是什么。这样实际上已经不是传统的神经网络语言模型(相似于生成模型)了,而是单纯做为分类问题,根据这个时刻的 hidden state 来预测这个时刻的 token 应该是什么,而不是预测下一个时刻的词的几率分布了。

随机去掉的 token 被称做掩码词,在训练中,掩码词将以 15% 的几率被替换成 [MASK],也就是说随机 mask 语料中 15% 的 token,这个操做则称为掩码操做。注意:在CBOW 模型中,每一个词都会被预测一遍。

可是这样设计 MLM 的训练方法会引入弊端:在模型微调训练阶段或模型推理(测试)阶段,输入的文本中将没有 [MASK],进而致使产生由训练和预测数据误差致使的性能损失。

考虑到上述的弊端,BERT 并无总用 [MASK] 替换掩码词,而是按照必定比例选取替换词。在选择 15% 的词做为掩码词后这些掩码词有三类替换选项:

  • 80% 练样本中:将选中的词用 [MASK] 来代替,例如:
“地球是[MASK]八大行星之一”
  • 10% 的训练样本中:选中的词不发生变化,该作法是为了缓解训练文本和预测文本的误差带来的性能损失,例如:
“地球是太阳系八大行星之一”
  • 10% 的训练样本中:将选中的词用任意的词来进行代替,该作法是为了让 BERT 学会根据上下文信息自动纠错,例如:
“地球是苹果八大行星之一”

做者在论文中提到这样作的好处是,编码器不知道哪些词须要预测的,哪些词是错误的,所以被迫须要学习每个 token 的表示向量,另外做者也表示双向编码器比单项编码器训练要慢,进而致使BERT 的训练效率低了不少,可是实验也证实 MLM 训练方法可让 BERT 得到超出同期全部预训练语言模型的语义理解能力,牺牲训练效率是值得的。

13.5 BERT 之下句预测(NSP)

在不少天然语言处理的下游任务中,如问答和天然语言推断,都基于两个句子作逻辑推理,而语言模型并不具有直接捕获句子之间的语义联系的能力,或者能够说成单词预测粒度的训练到不了句子关系这个层级,为了学会捕捉句子之间的语义联系,BERT 采用了下句预测(NSP )做为无监督预训练的一部分。

NSP 的具体作法是,BERT 输入的语句将由两个句子构成,其中,50% 的几率将语义连贯的两个连续句子做为训练文本(连续句对通常选自篇章级别的语料,以此确保先后语句的语义强相关),另外 50% 的几率将彻底随机抽取两个句子做为训练文本。

连续句对:[CLS]今每天气很糟糕[SEP]下午的体育课取消了[SEP]

随机句对:[CLS]今每天气很糟糕[SEP]鱼快被烤焦啦[SEP]

其中 [SEP] 标签表示分隔符。 [CLS] 表示标签用于类别预测,结果为 1,表示输入为连续句对;结果为 0,表示输入为随机句对。

经过训练 [CLS] 编码后的输出标签,BERT 能够学会捕捉两个输入句对的文本语义,在连续句对的预测任务中,BERT 的正确率能够达到 97%-98%。

13.6 BERT 之输入表示

BERT 在预训练阶段使用了前文所述的两种训练方法,在真实训练中通常是两种方法混合使用。

因为 BERT 经过 Transformer 模型堆叠而成,因此 BERT 的输入须要两套 Embedding 操做:

  1. 一套为 One-hot 词表映射编码(对应下图的 Token Embeddings);
  2. 另外一套为位置编码(对应下图的 Position Embeddings),不一样于 Transformer 的位置编码用三角函数表示,BERT 的位置编码将在预训练过程当中训练获得(训练思想相似于Word Embedding 的 Q 矩阵)
  3. 因为在 MLM 的训练过程当中,存在单句输入和双句输入的状况,所以 BERT 还须要一套区分输入语句的分割编码(对应下图的 Segment Embeddings),BERT 的分割编码也将在预训练过程当中训练获得
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

对于分割编码,Segment Embeddings 层只有两种向量表示。前一个向量是把 0 赋给第一个句子中的各个 token,后一个向量是把 1 赋给第二个句子中的各个 token ;若是输入仅仅只有一个句子,那么它的 segment embedding 就是全 0,下面咱们简单举个例子描述下:

[CLS]I like dogs[SEP]I like cats[SEP] 对应编码 0 0 0 0 0 1 1 1 1

[SEP]I Iike dogs and cats[SEP] 对应编码 0 0 0 0 0 0 0

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=十4、BERT 下游任务改造

BERT 根据天然语言处理下游任务的输入和输出的形式,将微调训练支持的任务分为四类,分别是句对分类、单句分类、文本问答和单句标注,接下来咱们将简要的介绍下 BERT 如何经过微调训练适应这四类任务的要求。

14.1 句对分类

给定两个句子,判断它们的关系,称为句对分类,例如判断句对是否类似、判断后者是否为前者的答案。

针对句对分类任务,BERT 在预训练过程当中就使用了 NSP 训练方法得到了直接捕获句对语义关系的能力。

以下图所示,句对用 [SEP] 分隔符拼接成文本序列,在句首加入标签 [CLS],将句首标签所对应的输出值做为分类标签,计算预测分类标签与真实分类标签的交叉熵,将其做为优化目标,在任务数据上进行微调训练。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

针对二分类任务,BERT 不须要对输入数据和输出数据的结构作任何改动,直接使用与 NSP 训练方法同样的输入和输出结构就行。

针对多分类任务,须要在句首标签 [CLS] 的输出特征向量后接一个全链接层和 Softmax 层,保证输出维数与类别数目一致,最后经过 arg max 操做(取最大值时对应的索引序号)获得相对应的类别结果。

下面给出句对分类似性任务的实例:

任务:判断句子 “我很喜欢你” 和句子 “我很中意你” 是否类似

输入改写:“[CLS]我很喜欢你[SEP]我很中意你”

取 “[CLS]” 标签对应输出:[0.02, 0.98]

经过 arg max 操做获得类似类别为 1(类别索引从 0 开始),即两个句子类似

14.2 单句分类

给定一个句子,判断该句子的类别,统称为单句分类,例如判断情感类别、判断是否为语义连贯的句子。

针对单句二分类任务,也无须对 BERT 的输入数据和输出数据的结构作任何改动。

以下图所示,单句分类在句首加入标签 [CLS],将句首标签所对应的输出值做为分类标签,计算预测分类标签与真实分类标签的交叉熵,将其做为优化目标,在任务数据上进行微调训练。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

一样,针对多分类任务,须要在句首标签 [CLS] 的输出特征向量后接一个全链接层和 Softmax 层,保证输出维数与类别数目一致,最后经过 argmax 操做获得相对应的类别结果。

下面给出语义连贯性判断任务的实例:

任务:判断句子“海大球星饭茶吃” 是否为一句话

输入改写:“[CLS]海大球星饭茶吃”

取 “[CLS]” 标签对应输出:[0.99, 0.01]

经过 arg max 操做获得类似类别为 0,即这个句子不是一个语义连贯的句子

14.3 文本问答

给定一个问句和一个蕴含答案的句子,找出答案在后这种的位置,称为文本问答,例如给定一个问题(句子 A),在给定的段落(句子 B)中标注答案的其实位置和终止位置。

文本问答任何和前面讲的其余任务有较大的差异,不管是在优化目标上,仍是在输入数据和输出数据的形式上,都须要作一些特殊的处理。

为了标注答案的起始位置和终止位置,BERT 引入两个辅助向量 s(start,判断答案的起始位置) 和 e(end,判断答案的终止位置)。

以下图所示,BERT 判断句子 B 中答案位置的作法是,将句子 B 中的每个次获得的最终特征向量 \(T_i'\) 通过全链接层(利用全链接层将词的抽象语义特征转化为任务指向的特征)后,分别与向量 s 和 e 求内积,对全部内积分别进行 softmax 操做,便可获得词 Tok m(\(m\in [1,M]\))做为答案其实位置和终止位置的几率。最后,去几率最大的片断做为最终的答案。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

文本回答任务的微调训练使用了两个技巧:

  1. 用全链接层把 BERT 提取后的深层特征向量转化为用于判断答案位置的特征向量
  2. 引入辅助向量 s 和 e 做为答案其实位置和终止位置的基准向量,明确优化目标的方向和度量方法

下面给出文本问答任务的实例:

任务:给定问句 “今天的最高温度是多少”,在文本 “天气预报显示今天最高温度 37 摄氏度” 中标注答案的起始位置和终止位置

输入改写:“[CLS]今天的最高温度是多少[SEP]天气预报显示今天最高温度 37 摄氏度”

BERT Softmax 结果:

篇章文本 天气 预报 显示 今天 最高温 37 摄氏度
起始位置几率 0.01 0.01 0.01 0.04 0.10 0.80 0.03
终止位置几率 0.01 0.01 0.01 0.03 0.04 0.10 0.80

对 Softmax 的结果取 arg max,获得答案的起始位置为 6,终止位置为 7,即答案为 “37 摄氏度”

14.4 单句标注

给定一个句子,标注每一个次的标签,称为单句标注。例如给定一个句子,标注句子中的人名、地名和机构名。

单句标注任务和 BERT 预训练任务具备较大差别,但与文本问答任务较为类似。

以下图所示,在进行单句标注任务时,须要在每一个词的最终语义特征向量以后添加全链接层,将语义特征转化为序列标注任务所需的特征,单句标注任务须要对每一个词都作标注,所以不须要引入辅助向量,直接对通过全链接层后的结果作 Softmax 操做,便可获得各种标签的几率分布。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

因为 BERT 须要对输入文本进行分词操做,独立词将会被分红若干子词,所以 BERT 预测的结果将会是 5 类(细分为 13 小类):

  • O(非人名地名机构名,O 表示 Other)
  • B-PER/LOC/ORG(人名/地名/机构名初始单词,B 表示 Begin)
  • I-PER/LOC/ORG(人名/地名/机构名中间单词,I 表示 Intermediate)
  • E-PER/LOC/ORG(人名/地名/机构名终止单词,E 表示 End)
  • S-PER/LOC/ORG(人名/地名/机构名独立单词,S 表示 Single)

将 5 大类的首字母结合,可得 IOBES,这是序列标注最经常使用的标注方法。

下面给出命名实体识别(NER)任务的示例:

任务:给定句子 “爱因斯坦在柏林发表演讲”,根据 IOBES 标注 NER 结果

输入改写:“[CLS]爱 因 斯坦 在 柏林 发表 演讲”

BERT Softmax 结果:

BOBES 斯坦 柏林 发表 演讲
O 0.01 0.01 0.01 0.90 0.01 0.90 0.90
B-PER 0.90 0.01 0.01 0.01 0.01 0.01 0.01
I-PER 0.01 0.90 0.01 0.01 0.01 0.01 0.01
E-PER 0.01 0.01 0.90 0.01 0.01 0.01 0.01
S-LOC 0.01 0.01 0.01 0.01 0.01 0.01 0.01

对 Softmax 的结果取 arg max,获得最终地 NER 标注结果为:“爱因斯坦” 是人名;“柏林” 是地名

14.5 BERT效果展现

不管如何,从上述讲解能够看出,NLP 四大类任务均可以比较方便地改形成 Bert 可以接受的方式,总之不一样类型的任务须要对模型作不一样的修改,可是修改都是很是简单的,最多加一层神经网络便可。这实际上是 Bert 的很是大的优势,这意味着它几乎能够作任何NLP的下游任务,具有普适性,这是很强的。

可是讲了这么多,一个新模型好很差,效果才是王道。那么Bert 采用这种两阶段方式解决各类 NLP 任务效果如何?

在 11 个各类类型的 NLP 任务中达到目前最好的效果,某些任务性能有极大的提高。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=十5、预训练语言模型总结 watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

到这里咱们能够再梳理下几个模型之间的演进关系。

从上图可见,Bert 其实和 ELMO 及 GPT 存在千丝万缕的关系,好比若是咱们把 GPT 预训练阶段换成双向语言模型,那么就获得了 Bert;而若是咱们把 ELMO 的特征抽取器换成 Transformer,那么咱们也会获得Bert。

因此你能够看出:Bert最关键两点,一点是特征抽取器采用 Transformer;第二点是预训练的时候采用双向语言模型。

那么新问题来了:对于 Transformer 来讲,怎么才能在这个结构上作双向语言模型任务呢?乍一看上去好像不太好搞。我以为吧,其实有一种很直观的思路,怎么办?看看 ELMO 的网络结构图,只须要把两个 LSTM 替换成两个 Transformer,一个负责正向,一个负责反向特征提取,其实应该就能够。

固然这是我本身的改造,Bert 没这么作。那么 Bert 是怎么作的呢?咱们前面不是提过 Word2Vec 吗?我前面确定不是漫无目的地提到它,提它是为了在这里引出那个 CBOW 训练方法,所谓写做时候埋伏笔的 “草蛇灰线,伏脉千里”,大概就是这个意思吧?

前面提到了 CBOW 方法,它的核心思想是:在作语言模型任务的时候,我把要预测的单词抠掉,而后根据它的上文 Context-Before 和下文 Context-afte r去预测单词。

其实 Bert 怎么作的?Bert 就是这么作的。从这里能够看到方法间的继承关系。固然 Bert 做者没提 Word2Vec 及 CBOW 方法,这是个人判断,Bert 做者说是受到完形填空任务的启发,这也极可能,可是我以为他们要是没想到过 CBOW 估计是不太可能的。

从这里能够看出,在文章开始我说过 Bert 在模型方面其实没有太大创新,更像一个最近几年 NLP 重要技术的集大成者,缘由在于此,固然我不肯定你怎么看,是否定同这种见解,并且我也不关心你怎么看。其实 Bert 自己的效果好和普适性强才是最大的亮点。

最后,我讲讲我对Bert的评价和见解,我以为 Bert 是 NLP 里里程碑式的工做,对于后面 NLP 的研究和工业应用会产生长久的影响,这点毫无疑问。可是从上文介绍也能够看出,从模型或者方法角度看,Bert 借鉴了 ELMO,GPT 及 CBOW,主要提出了 Masked 语言模型及 Next Sentence Prediction,可是这里 Next Sentence Prediction 基本不影响大局,而 Masked LM 明显借鉴了 CBOW 的思想。因此说 Bert 的模型没什么大的创新,更像最近几年 NLP 重要进展的集大成者,这点若是你看懂了上文估计也没有太大异议,若是你有大的异议,杠精这个大帽子我随时准备戴给你。

若是概括一下这些进展就是:首先是两阶段模型,第一阶段双向语言模型预训练,这里注意要用双向而不是单向,第二阶段采用具体任务 Fine-tuning 或者作特征集成;第二是特征抽取要用Transformer 做为特征提取器而不是 RNN 或者 CNN;第三,双向语言模型能够采起 CBOW 的方法去作(固然我以为这个是个细节问题,不算太关键,前两个因素比较关键)。Bert 最大的亮点在于效果好及普适性强,几乎全部 NLP 任务均可以套用 Bert 这种两阶段解决思路,并且效果应该会有明显提高。能够预见的是,将来一段时间在 NLP 应用领域,Transformer 将占据主导地位,并且这种两阶段预训练方法也会主导各类应用。

另外,咱们应该弄清楚预训练这个过程本质上是在作什么事情,本质上预训练是经过设计好一个网络结构来作语言模型任务,而后把大量甚至是无穷尽的无标注的天然语言文本利用起来,预训练任务把大量语言学知识抽取出来编码到网络结构中,当手头任务带有标注信息的数据有限时,这些先验的语言学特征固然会对手头任务有极大的特征补充做用,由于当数据有限的时候,不少语言学现象是覆盖不到的,泛化能力就弱,集成尽可能通用的语言学知识天然会增强模型的泛化能力。如何引入先验的语言学知识其实一直是 NLP 尤为是深度学习场景下的 NLP 的主要目标之一,不过一直没有太好的解决办法,而 ELMO/GPT/Bert 的这种两阶段模式看起来无疑是解决这个问题天然又简洁的方法,这也是这些方法的主要价值所在。

对于当前 NLP 的发展方向,我我的以为有两点很是重要:

  1. 一个是须要更强的特征抽取器,目前看 Transformer 会逐渐担当大任,可是确定仍是不够强的,须要发展更强的特征抽取器;
  2. 第二个就是如何优雅地引入大量无监督数据中包含的语言学知识,注意我这里强调地是优雅,而不是引入,此前至关多的工做试图作各类语言学知识的嫁接或者引入,可是不少方法看着让人牙疼,就是我说的不优雅。

目前看预训练这种两阶段方法仍是颇有效的,也很是简洁,固然后面确定还会有更好的模型出现。

完了,这就是预训练语言模型的前世此生。

因为我的刚入门 NLP 方向,就不妄自总结,上述总结所有来自知乎文章:从Word Embedding到Bert模型—天然语言处理中的预训练技术发展史-张俊林

十6、参考资料

我只是知识的搬运工,想详细了解各个知识点的读者能够自行选择参考下列资料。