全文共7055字,预计学习时长14分钟git
BERT全称是来自变换器的双向编码器表征量(Bidirectional Encoder Representations from Transformers),它是Google于2018年底开发并发布的一种新型语言模型。与BERT模型类似的预训练语言模型例如问答、命名实体识别、天然语言推理、文本分类等在许多天然语言处理任务中发挥着重要做用。微信
BERT是一种基于微调的多层双向变换器编码器。首先介绍下该变换器的架构,这一点尤其重要。网络
什么是变换器(Transformer)?架构
2017年,谷歌发表了一篇题为《你所须要的是注意力》的论文,该论文提出一种基于注意力的结构,以处理与序列模型相关的问题,例如机器翻译。传统的神经机器翻译大多使用循环神经网络(RNN)或卷积神经网络(CNN)做为编码-解码的模型库。然而,谷歌这一基于注意力的变换器模型摒弃传统的RNN和CNN公式。该模型高度并行运行,所以在提升翻译性能的同时,其训练速度也很是快。并发
进一步阐述变换器模型前,咱们先对注意力作个介绍。函数
什么是注意力(Attention)?性能
注意力机制可看做模糊记忆的一种形式。记忆由模型的隐藏状态组成,模型选择从记忆中检索内容。深刻了解注意力以前,先简要回顾Seq2Seq模型。传统的机器翻译主要基于Seq2Seq模型。该模型分为编码层和解码层,并由RNN或RNN变体(LSTM、GRU等)组成。编码矢量是从模型的编码部分产生的最终隐藏状态。该向量旨在封装全部输入元素的信息,以帮助解码器进行准确的预测。其用于充当模型解码器部分的初始隐藏状态。学习
Seq2Seq模型的主要瓶颈是须要将源序列的所有内容压缩为固定大小的矢量。若是文本稍长,则很容易丢失文本的某些信息。为解决这个问题,注意力应运而生。注意机制经过使解码器回顾源序列隐藏状态,而后将其加权平均值做为附加输入提供给解码器来缓解该问题。使用注意力,顾名思义,模型在解码阶段选择最适合当前节点的上下文做为输入内容。编码
注意力与传统的Seq2Seq模型有两个主要区别。人工智能
第一,编码器向解码器提供更多数据,而且编码器会向解码器提供全部节点的隐藏状态,而不只仅是编码器的最后节点的隐藏状态。
第二,解码器不直接将全部编码器提供的隐藏状态做为输入,而是采用选择机制来选择与当前位置最匹配的隐藏状态。为此,它尝试经过计算每一个隐藏状态的得分值并对得分进行softmax计算来肯定哪一个隐藏状态与当前节点相关性最高,这使得隐藏状态的更高相关性具备更大的分数值,不太相关的隐藏状态具备较小的分数值。而后它将每一个隐藏状态与其softmax得分相乘,从而放大分数高的隐藏状态,淹没分数低的隐藏状态。该评分练习在解码器侧的每一个迭代时间完成。
如今,将注意机制用可视化予以表现,研究注意流程如何进行:
1.注意解码器RNN接收<END>令牌的嵌入和初始解码器隐藏状态。
2.RNN处理其输入,产生一个输出和一个新的隐藏状态向量(h4),并丢弃输入。
3.注意步骤:使用编码器隐藏状态和h4向量来计算该迭代时间的语境向量(C4)。
4.将h4和C4连成一个向量。
5.将这个向量传递给前馈神经网络(一个与模型共同训练的网络)。
6.前馈神经网络的输出即该迭代时间的输出字。
7.重复下一个迭代时间的步骤
回到变换器
变换器模型使用编码器-解码器(encoder-decoder)架构。在谷歌发表的论文中,编码层和解码层都由6个编码器堆叠而成。每一个编码器和解码器的内部结构以下:
编码器由两层组成,一个自注意层和一个前馈神经网络。自我关注不只有助于当前节点关注当前单词,还能助其获取上下文的语义。解码器还包含编码器提到的双层网络,但在两层中间还有一个注意层,以帮助当前节点得到须要注意的关键内容。
如下是变换器架构的详细结构:
接下来逐个分析其组成部分。
自注意(Self-Attention)
自注意是变换器将其余相关单词的“理解”转换为所处理的单词的一种方式。
首先,自注意计算三个新的向量。在论文中,向量的维度是512维。将这三个向量分别称为Query,Key和Value。这三个向量经过字嵌入向量与随机初始化矩阵(论文中的维数为(64,512))相乘而产生的,并在反向传播过程当中不断更新。
接下来,计算自注意的分数值,在某个位置编码单词时,它能决定在所输入句子其他部分投入的注意力。该分数值可经过Query和Key向量计算得出。而后用所得结果除以一个常数。本文中,该常数为8,这个值一般是上述矩阵第一维的平方根,即64的平方根8。而后对全部得分进行softmax计算。结果表示每一个单词与当前位置单词的相关性。固然,当前词的相关性确定会很大。最后一步是将Value向量与softmax所得结果相乘并求和。结果是当前节点处的自注意值。
这种经过查询和密钥之间的类似度,来肯定值的权重分布的方法,被称为缩放的点积注意。
多头注意
本论文中更精辟的部分是增长了另外一种自注意机制,称为“多头”注意,它不只仅初始化一组Q,K,V矩阵。相反,初始化多个组,且变换器使用8个组,所以最终结果是8个矩阵。
前馈神经网络不能接受8个矩阵,所以须要一种方法将其减小为1个。为此,首先将8个矩阵链接在一块儿获得一个大矩阵,而后将这个组合矩阵与一个随机初始化矩阵相乘获得最后的矩阵。整个流程以下图所示。
变换器的多头注意有三种使用方式:
1.在“编码-解码注意”层中,查询来自先前的解码器层,存储器键和值来自编码器的输出。这使解码器中的每一个位置都参与输入序列中的全部位置。并模拟出序列到序列模型中典型的编码-解码注意机制。
2.编码器包含自注意层。在自注意层中,全部键、全部值和查询都来自相同的位置,在这种状况下,它们来自于编码器中前一层的输出。编码器中的每一个位置均可以处理编码器前一层中的全部位置。
3.与其类似的是,解码器中的自注意层令解码器中的每一个位置参与到解码器中的全部位置,直到并包括该位置。在此须要预防解码器中的向左信息流,以此保持自回归属性。经过掩蔽(设置为-∞)softmax中与非法链接相对应的全部值来实现缩放点积注意。这将在解码器部分更加详细地探讨,在此仅讨论掩蔽(Masking)。
位置编码
到目前为止,尚未办法解释变换器模型中输入序列中的单词顺序。为了解决此问题,变换器在编码器和解码器层的输入端增长了一个额外的矢量位置编码。其维度与嵌入维度相同。此位置编码的值将添加到嵌入层的值中,并做为输入发送到下一层。位置编码选项有不少,包括学习和修复。
残余链接和层规范化
在编码器和解码器中,在两个子层的周围都采用残余链接,而后进行层规范化。跳过链接或残余链接用于容许梯度直接流过网络,而不经过非线性激活功能。非线性激活函数本质上是非线性的,致使梯度爆炸或消失(取决于权重)。从概念上说,跳过链接造成一条“总线”,它在网络中流动,反过来,梯度也能够沿着它向后流动。规范化有助于解决内部协变量偏移的问题。内部协变量偏移是指在神经网络内发生的协变量偏移,即从(例如)第2层到第3层。这是由于当网络学习且权重被更新时,网络中特定层的输出分布会发生变化。这迫使较高层适应该漂移,这减慢了学习速度。在对神经网络中的输入进行归一化后,没必要担忧输入特征的规模差异很大。要了解层规范化,将其与批规范化进行对比很是有用。一小批包含具备相同数量功能的多个示例。小批是矩阵 - 若是每一个输入是多维的,则为张量 - 其中一个轴对应批,另外一个轴或多个轴对应特征尺寸。批规范化规范批维度中的输入要素。层规范化的关键特性是它能够对要素之间的输入进行标准化。在批规范化中,统计信息在批处理中计算,而且对于批中的每一个示例都是相同的。相反,在层规范化中,统计数据是跨每一个特征计算的,而且与其余示例无关。
将残余链接和层规范化放在一块儿
解码器
回看变换器体系结构图,能够看到解码器部分与编码器部分类似,但底部有一个掩盖的多头注意。Mask表示屏蔽某些值的掩码,以便在更新参数时它们不起做用。变换器模型中有两种掩码—填充掩码和序列掩码。填充掩码用于全部缩放的点积注意,序列掩码仅用于解码器的自注意。
填充掩码解决了输入序列具备可变长度的问题。具体来讲,在较短的序列后填0。可是若是输入序列太长,则会截取左侧的内容,并直接丢弃多余的内容。由于这些填充的位置实际上没有意义,注意机制不该该集中在这些位置,因此须要作一些处理。具体方法是在这些位置的值上加一个很是大的负数(负无穷大),这样这些位置的几率在softmax计算以后将接近0!填充掩码其实是一个张量,每一个值都是一个布尔值,false值指想要处理的值。
A序列掩码旨在确保解码器没法查看未来的信息。也就是说,对于序列,在time_step t,解码输出应该仅取决于t以前的输出,而不取决于t以后的输出。这针对于变换器架构,由于没有RNN,能够按顺序输入序列。在此,一块儿输入全部内容,若是没有掩码,多头注意将考虑每一个位置的整个解码器输入序列。经过生成上三角矩阵来实现这一点,上三角形的值全为零,并将该矩阵应用于每一个序列。
对于解码器的自注意,在此使用缩放的点积注意,而且添加填充掩码和序列掩码做为attn_mask。在其余状况下,attn_mask等于填充掩码。
另外一个细节是解码器输入将向右移动一个位置。这样作的一个缘由是不但愿模型在训练期间学习如何复制解码器输入,但仍是想要了解给定编码器序列和模型已经看到的特定解码器序列,从而预测下一个单词/字符。若是不移位解码器序列,模型则简单地学习“复制”解码器输入,由于位置 i 的目标字/字符将是解码器输入中的字/字符 i 。所以,经过将解码器输入移位一个位置,模型须要预测仅在解码器序列中看到单词/字符 1, …, i-1 的位置 i 的目标字/字符。这能够防止模型学习复制/粘贴任务。用句子开头令牌填充解码器输入的第一个位置,因为右移,该位置将是空的。相似地,将一个句末标记附加到解码器输入序列以标记该序列的结尾,而且它还附加到目标输出语句。
输出层
在彻底执行解码器层后,为将获得的矢量映射到来自词汇表的单词,在结尾添加彻底链接层和softmax层。
线性层是一个简单的彻底链接的神经网络,它将解码器堆栈产生的矢量投影到一个更大的矢量中,称为logits矢量。假设模型知道从训练数据集中学到的10,000个独特的英语单词(模型的“输出词汇表”) 这将使logits矢量10,000个细胞变宽 - 每一个单元对应于一个惟一单词的得分。这就是对于线性层后的模型输出的解释。而后,softmax层将这些分数转换为几率(全部正数,全部加起来都为1.0)。选择具备最高几率的单元,并将与其相关联的单词做为该迭代时长的输出。
回到BERT模型
BERT模型基于变换器架构。它是一种具备双向深度的神经网络模型。BERT模型的关键技术创新是将变换器的双向培训应用于语言建模。这与先前从左到右查看文本序列或从左到右和从右到左组合训练的努力尝试造成对比。BERT模型采用了一种名为掩蔽语言模型(Masked Language Modeling)的新技术(将在后文看到),它容许在从前不可能使用的模型中进行双向训练。在其vanilla form中,变换器包括两个独立的机制——读取文本输入的编码器和产生任务预测的解码器。因为BERT模型的目标是生成语言模型,所以只须要编码器机制。
谷歌最初发布了两个版本,以下图所示。这里L表示变压器的层数,H表示输出的维数,A表示多头注意的数量。在这两个版本中,前馈大小都设置为4层。
BERTBASE: L=12, H=768, A=12, Total Parameters=110M
BERTLARGE: L=24, H=1024, A=16, Total Parameters=340M
使用BERT模型有两个阶段:预训练和微调。在预训练期间,模型在不一样的预训练任务上训练未标记的数据。对于微调,首先使用预训练参数初始化BERT模型,并使用来自下游任务的标记数据对全部参数进行微调。每一个下游任务都有单独的微调模型,即便它们使用相同的预训练参数进行初始化。BERT模型的一个显著特色是它跨越不一样任务的统一架构。预训练架构与最终下游架构之间的差别很小。在微调期间,全部参数都通过微调。
BERT模型预训练过程
BERT模型预训练阶段包括两个无监督预测任务:掩蔽语言模型和下一句预测。
掩蔽语言模型(MLM)——因为BERT模型的双向功能(双向性)及其使用的多层自关注机制的效果,为了训练深度双向表示,一些百分比(论文中为15%)输入令牌的输入被简单地随机掩盖,而后预测那些被屏蔽的令牌。对应于掩模标记的最终隐藏向量被馈送到词汇表上的输出softmax,如在标准学习模型LM中。与从左到右的语言模型预训练不一样,MLM目标容许表示融合的左侧和右侧的上下文,这使得能够预先训练深度双向变换器。虽然这容许得到双向预训练模型,但缺点是预训练和微调之间存在不匹配,由于在微调期间不出现[MASK]标记。为了缓解这种状况,做者并不老是用实际的[MASK]标记替换“蒙面”单词。训练数据生成器随机选择15%的令牌位置进行预测。若是选择了第i个令牌,则将其替换为(1)[MASK]标记80%的时间(2)随机标记10%的时间(3)未更改的第i个标记10%时间。BERT模型损失函数仅考虑掩蔽值的预测并忽略非掩蔽字的预测。所以,模型比定向模型收敛得慢,这一特征被其增长的情境感知所抵消。
下一句预测(NSP)。为了训练理解句子关系以及单词之间的语义关系的模型,BERT模型还预先训练二进制化的下一句预测任务,该任务能够从任何文本语料库中轻易生成。为A和B选择一些句子,其中50%的数据B是A的下一个句子,剩余的50%的数据B是在语料库中随机选择的,而后学习相关性。添加这种预训练的目的是许多天然语言处理任务(如QA和NLI)须要理解两个句子之间的关系,以便预训练模型可以更好地适应这些任务。
为了帮助模型区分训练中的两个句子,输入在进入模型以前按如下方式处理:
1.在第一个句子的开头插入[CLS]标记,并在每一个句子的末尾插入[SEP]标记。
2.在每一个标记中添加表示句子A或句子B的句子嵌入。句子嵌入在概念上相似于词汇量为2的标记嵌入。
3.向每一个标记添加位置嵌入以指示其在序列中的位置。位置嵌入的概念和实现已在变换器论文中给出。
要预测第二个句子是否确实与第一个句子链接,需执行如下步骤:
1.整个输入序列通过变换器模型。
2.使用简单的分类层(权重和误差的学习矩阵)将[CLS]标记的输出转换为2×1型的矢量。
3.使用softmax计算IsNextSequence的几率。
在训练BERT模型时,MLM和NSP是被同时训练的,目标是最小化两种策略的组合损失函数。
标记化—BERT模型不会将单词视做标记。相反,它会看WordPieces。这意味着一个单词能够分解为多个子单词。这种标记化在处理词汇单词时是有益的,它能够帮助更好地表示复杂的单词。
BERT模型的输入
BERT的输入能够是单词序列中的单个句子或句子对(例如,[问题,答案])。对于给定的单词,其输入表示能够由三部分嵌入求和组成。嵌入的可视化表示以下所示:
标记嵌入表示单词向量。第一个字是CLS标志,可用于后续分类任务。对于非分类任务,能够忽略CLS标志。段嵌入用于区分两个句子,由于预训练不只是语言模型,并且仍是具备两个句子做为输入的分类任务。位置嵌入编码字顺序。
用于下游天然语言处理任务的BERT模型微调
对于每一个下游天然语言处理任务,只需将特定于任务的输入和输出插入BERT模型,并对端到端的全部参数进行微调。在输入处,来自预训练的句子A和句子B可类比于释义中的句子对,蕴涵中的假设前提对,问题回答中的问题通道对等。在输出处,标记表示被馈送到用于标记级别任务的输出层,例如序列标记或问题回答,而且[CLS]表示被馈送到输出层以进行分类,例如蕴涵或情绪分析。与预训练相比,微调相对便宜。
BERT模型可用于各类语言任务,而只需在核心模型中添加一个小层:
1.经过在[CLS]标记的变换器输出上添加分类层,相似于下一句分类,进行情感分析等分类任务。
2.在问题回答任务(例如SQUAD v1.1)中,软件会收到有关文本序列的问题,而且须要在序列中标记答案。使用BERT模型,能够经过学习标记答案开始和结束的两个额外向量来训练Q&A模型。
3.在命名实体识别(NER)中,软件接收文本序列,而且须要标记文本中出现的各类类型的实体(人员,组织,日期等)。使用BERT模型,能够经过将每一个标记的输出向量馈送到预测NER标签的分类层来训练NER模型。
BERT模型用于特征提取
微调法不是使用BERT模型的惟一方法。可使用预先训练的BERT模型建立语境化词嵌入。而后,能够将这些嵌入提供给现有的模型——该过程本文展现了产生结果,在命名实体识别等任务上微调BERT模型并不远。
哪一个向量最适合做为上下文嵌入呢?这要视任务而定。本文共考察了六种可选方法(与得分为96.4的微调模型相比):
留言 点赞 关注
咱们一块儿分享AI学习与发展的干货
欢迎关注全平台AI垂类自媒体 “读芯术”
(添加小编微信:dxsxbb,加入读者圈,一块儿讨论最新鲜的人工智能科技哦~)