Bert技术

Bert技术,第1张

google在2018年10月底公布BERT在11项nlp任务中的卓越表现,NLP任务的两个衡量指标上全面超越人类,并且还在11种不同NLP测试中创出最佳成绩,包括将GLUE基准推至80.4%(绝对改进7.6%),MultiNLI准确度达到86.7% (绝对改进率5.6%)等,此后,BERT(Bidirectional Encoder Representation from Transformers)就成为NLP领域大火、整个ML界略有耳闻的模型

BERT的出现,彻底改变了预训练产生词向量和下游具体NLP任务的关系,提出龙骨级的训练词向量概念。

词向量,就是用一个向量的形式表示一个词。

(1)one-hot编码:词的符号化。

(2)词的分布式表示:词的语义由其上下文决定。以(CBOW)为例,如果有一个句子“the cat sits one the mat”,在训练的时候,将“the cat sits one the”作为输入,预测出最后一个词是“mat”。分布式表示的较大优点在于它具有非常强大的表征能力,比如n维向量每维k个值,可以表征k的n次方个概念。

其中,词嵌入就是分布式表示的一种:基于神经网络的分布表示一般称为词向量、词嵌入( word embedding)或分布式表示( distributed representation)。核心依然是上下文的表示以及上下文与目标词之间的关系的建模。本质:词向量是训练神经网络时候的隐藏层参数或者说矩阵。

两种训练模式:CBOW (Continuous Bag-of-Words Model)和Skip-gram (Continuous Skip-gram Model)

NLP任务分成两部分,一是预训练产生词向量,二是对词向量 *** 作实现特定功能。而词向量模型是一个工具,可以把抽象存在的文字转换成可以进行数学公式 *** 作的向量,而对这些向量的 *** 作,才是NLP真正要做的任务。从word2vec到ELMo到BERT,做的其实主要是把下游具体NLP任务的活逐渐移到预训练产生词向量上。

(1)word2vec:上下文概率的一种表示,但无法对一词多义进行建模

(2)ELMo:用的是一个双向的LSTM语言模型,由一个前向和一个后向语言模型构成,目标函数就是取这两个方向语言模型的最大似然。

在预训练好这个语言模型之后,ELMo就是根据下面的公式来用作词表示,其实就是把这个双向语言模型的每一中间层进行一个求和。最简单的也可以使用最高层的表示来作为ELMo。

然后在进行有监督的NLP任务时,可以将ELMo直接当做特征拼接到具体任务模型的词向量输入或者是模型的最高层表示上。总结一下,不像传统的词向量,每一个词只对应一个词向量,ELMo利用预训练好的双向语言模型,然后根据具体输入从该语言模型中可以得到上下文依赖的当前词表示(对于不同上下文的同一个词的表示是不一样的),再当成特征加入到具体的NLP有监督模型里。

(3)bert

word2vec——>ELMo:

结果:上下文无关的static向量变成上下文相关的dynamic向量,比如苹果在不同语境vector不同。

*** 作:encoder *** 作转移到预训练产生词向量过程实现。

ELMo——>BERT:

结果:训练出的word-level向量变成sentence-level的向量,下游具体NLP任务调用更方便,修正了ELMo模型的潜在问题。

*** 作:使用句子级负采样获得句子表示/句对关系,Transformer模型代替LSTM提升表达和时间上的效率,masked LM解决“自己看到自己”的问题。

(1)bert模型证明了双向预训练对于语言表示的重要性。与采用单向语言模型进行预训练的模型不同,BERT使用masked language models 进行预训练的深层双向表示。

(2)经过预训练的模型表示解决了许多为特定任务而设计架构的需要。BERT是第一个基于微调的表示模型,它在一系列句子级和词级别的任务上实现了最先进的性能,优于许多具有特定任务架构的系统。

bert架构由两步实现:预训练和模型微调;在预训练阶段,基于无标注数据通过多轮预训练任务完成。在微调阶段,bert模型由预训练的参数进行初始化,然后由待下游的任务数据进行参数微调。

bert模型是多层双向transformer编码器。将层的数量(Transformer blocks)表示为L,隐藏的大小表示为H,而self-attention heads 为A。在所有的情况下,我们将feed-forward/filter大小设置为4H,即H=768时,为3072, H=1024时,为4096.

bert的两种格式:

BERTBASE : L=12, H=768, A=12, Total Parameter=110M,

BERTLARGE : L=24, H=1024, A=16, Total Parameters=340M

为了使用bert可以应对各式各样的下游任务,bert的输入为token序列,它可以表示一个句子或句子对(比如对话)。使用该方案,输入可以是任意跨度的相邻文本,即一个token序列可以是单个句子,也可以是多个句子。

具体地说,bert使用30000个词的词级别的embeddings。每个序列的起始token是[CLS]。句子对被打包在一个序列中,用两种方式区别句子。方法一,使用特殊token[SEP];方法二,在每个标记中添加一个学习过的嵌入,表示它是属于句子A还是句子B。

两个无监督任务对BERT进行训练。

任务一:Masked LM语言模型。

为了训练双向表示模型,随机按百分比的方式(一般选15%)屏蔽输入序列中的部分词,然后预测那些屏蔽词。在这种情况下,屏蔽词的最终隐向量经softmax运算后输出。有点类似于中文的完形填空。

虽然如些 *** 作可以获得一个双向的预训练模型,但这在预训练和微调之间创建了一个不匹配,因为在微调过程中从来没有见过[MASK]词。为了减轻这一点,我们并不总是用实际的[MASK]词替换被屏蔽的词。相反,生成随机选择15%的词进行预测,例如在句子 my dog is hairy 选择了 hairy。接着执行下面的过程:

数据生成器不会总是用[MASK] 替换所选单词,而是执行以下 *** 作:

80%的时间,将单词替换为[MASK]词。例如 my dog is hairy ->my dog is [MASK]

10%的时间, 用一个随机词替换这个词, 例如 my dog is hairy ->my dog is apple

10%的时间, 保持单词不变,例如 my dog is hairy ->my dog is hairy。

每一轮使用交叉熵损失来预测原始词。

任务二:下一句的预测;

许多重要的下游任务,如问答(QA)和自然语言推理(NLI),都基于理解两个文本句之间的关系,而语言建模并不能直接捕获到这两个文本句之间的关系。为了训练一个理解句子关系的模型,我们预训练了一个二分类的预测下一个句子的任务,该任务可以由任何单语语料库生成。

具体来说,在为每个训练前的例子选择句子A和B时,50%的时间B是A后面的实际下一个句子,50%的时间B是来自语料库的随机句子。例如:

Input =[CLS] the man went to [MASK] store [SEP],he bought a gallon [MASK] milk [SEP]

Label = IsNext

Input = [CLS] the man [MASK] to the store [SEP],penguin [MASK] are flight ##less birds [SEP]

Label = NotNext

我们完全随机选择NotNext 句子,最终预测模型在这个任务中达到97%-98%的准确率。

预训练数据:预训练过程很大程度上依赖现有语言模型的数据。从维基百科上抽取文本信息,忽略列表,表格和标题。对于预训练过程来说,使用文档级别的语料库而不是经过乱序后的句子级语料库来提取长的连续序列是很重要的。

对于序列级别分类任务,BERT微调很简单。BERT使用self-attention机制来统一两个过程。因为编码文本序列中,使用self-attention有效地包含了两上句子之间双向交叉的attention。

微调过程,就是对于每一个任务,简单地将特定的输入和输出接入bert,然后端到端地调节全部参数即可。在输入端,句子A和句子B类似于(1)语义句子对(2)假设前提(3)问答中的问句(4)文本分类或序列标记中文本。在输出端,token向量被传递给token级别任务的输出层,例如,序列标签,问答对的答案。[CLS]向量被传递给分类的输出层,用于分类或情感分析。

相对于预训练,微调要相对容易。大多数模型超参数与预训练相同,除了批的大小、学习率和训练轮数。

可以通过一个额外的输出层对预训练的BERT表示进行微调,以创建适用于各种任务的最先进模型,比如问答和语言推断,无需对特定与任务的架构进行实质性修改。

第一,如果NLP任务偏向在语言本身中就包含答案,而不特别依赖文本外的其它特征,往往应用Bert能够极大提升应用效果。

第二,Bert特别适合解决句子或者段落的匹配类任务。就是说,Bert特别适合用来解决判断句子关系类问题,这是相对单文本分类任务和序列标注等其它典型NLP任务来说的,很多实验结果表明了这一点。

第三,Bert的适用场景,与NLP任务对深层语义特征的需求程度有关。感觉越是需要深层语义特征的任务,越适合利用Bert来解决

第四,Bert比较适合解决输入长度不太长的NLP任务,而输入比较长的任务,典型的比如文档级别的任务,Bert解决起来可能就不太好。

【引用】:

bert论文:BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding

https://www.cnblogs.com/robert-dlut/p/8638283.html

https://blog.csdn.net/DarrenXf/article/details/89184225

https://www.cnblogs.com/xlturing/p/10824400.html

https://www.cnblogs.com/ylHe/p/10193166.html

首先我会详细阐述 BERT 原理,然后简单介绍一下 ELMO 以及 GPT

BERT 全称为 B idirectional E ncoder R epresentation from T ransformer,是 Google 以 无监督的方式利用大量无标注文本 「炼成」的语言模型,其架构为 Transformer 中的 Encoder(BERT=Encoder of Transformer)

我在 Transformer 详解 中已经详细的解释了所有 Transformer 的相关概念,这里就不再赘述

以往为了解决不同的 NLP 任务,我们会为该任务设计一个最合适的神经网络架构并做训练,以下是一些简单的例子

不同的 NLP 任务通常需要不同的模型,而设计这些模型并测试其 performance 是非常耗成本的(人力,时间,计算资源)。如果有一个能 直接处理各式 NLP 任务的通用架构 该有多好?

随着时代演进,不少人很自然地有了这样子的想法,而 BERT 就是其中一个将此概念付诸实践的例子

Google 在预训练 BERT 时让它同时进行两个任务:

1. 漏字填空

2. 下个句子预测

对正常人来说,要完成这两个任务非常简单。只要稍微看一下前后文就知道完形填空任务中 [MASK] 里应该填 退了 ;而 醒醒吧 后面接 你没有妹妹 也十分合理(?)

接下来我会分别详细介绍论文中这两个任务的设计细节

在 BERT 中,Masked LM(Masked Language Model)构建了语言模型,简单来说,就是 随机遮盖或替换 一句话里面的任意字或词,然后让模型通过上下文预测那一个被遮盖或替换的部分,之后 做 Loss 的时候也只计算被遮盖部分的 Loss ,这其实是一个很容易理解的任务,实际 *** 作如下:

这样做的好处是,BERT 并不知道 [MASK] 替换的是哪一个词,而且 任何一个词都有可能是被替换掉的,比如它看到的 apple 可能是被替换的词 。这样强迫模型在编码当前时刻词的时候 不能太依赖当前的词 ,而要考虑它的上下文,甚至根据上下文进行 "纠错"。比如上面的例子中,模型在编码 apple 时,根据上下文 my dog is,应该 把 apple 编码成 hairy 的语义而不是 apple 的语义

我们首先拿到属于上下文的一对句子,也就是两个句子,之后我们要在这两个句子中加一些特殊的 token: [CLS]上一句话[SEP]下一句话[SEP] 。也就是在句子开头加一个 [CLS] ,在两句话之间和句末加 [SEP] ,具体地如下图所示

可以看到,上图中的两句话明显是连续的。如果现在有这么一句话 [CLS] 我的狗很可爱 [SEP] 企鹅不擅长飞行 [SEP] ,可见这两句话就 不是连续的 。在实际训练中,我们会让这两种情况出现的数量为** 1:1**

Token Embedding 就是正常的词向量,即 PyTorch 中的 nn.Embedding()

Segment Embedding 的作用是用 embedding 的信息让模型 分开上下句 ,我们给上句的 token 全 0,下句的 token 全 1,让模型得以判断上下句的起止位置,例如

Position Embedding 和 Transformer 中的不一样,不是三角函数,而是 学习出来的

BERT 预训练阶段实际上是将上述两个任务结合起来,同时进行,然后将所有的 Loss 相加,例如

BERT 的 Fine-Tuning 共分为 4 种类型,以下内容、图片均来自台大李宏毅老师 Machine Learning 课程 (以下内容 图在上,解释在下)

为什么要用CLS?

这里李宏毅老师有一点没讲到,就是为什么要用第一个位置,即 [CLS] 位置的 output。这里我看了网上的一些博客,结合自己的理解解释一下。因为 BERT 内部是 Transformer,而 Transformer 内部又是 Self-Attention, 所以 [CLS] 的 output 里面肯定含有整句话的完整信息 ,这是毋庸置疑的。但是 Self-Attention 向量中,自己和自己的值其实是占大头的,现在假设使用的 output 做分类,那么这个 output 中实际上会更加看重 ,而 又是一个有实际意义的字或词,这样难免会影响到最终的结果。但是 [CLS] 是没有任何实际意义的,只是一个占位符而已,所以就算 [CLS] 的 output 中自己的值占大头也无所谓。当然你 也可以将所有词的 output 进行 concat,作为最终的 output

首先将问题和文章通过 [SEP] 分隔,送入 BERT 之后,得到上图中黄色的输出。此时我们还要训练两个 vector,即上图中橙色和黄色的向量。首先将橙色和所有的黄色向量进行 dot product,然后通过 softmax,看哪一个输出的值最大,例如上图中 对应的输出概率最大,那我们就认为 s=2

同样地,我们用蓝色的向量和所有黄色向量进行 dot product,最终预测得 的概率最大,因此 e=3。最终,答案就是 s=2,e=3

你可能会觉得这里面有个问题,假设最终的输出 s>e 怎么办,那不就矛盾了吗?其实在某些训练集里,有的问题就是没有答案的,因此此时的预测搞不好是对的,就是没有答案

以上就是 BERT 的详细介绍,参考以下文章

ELMo是Embedding from language Model的缩写,它通过无监督的方式对语言模型进行预训练来学习单词表示

这篇论文的想法其实非常简单,但是效果却很好。它的思路是用 深度的双向 Language Model 在大量未标注数据上训练语言模型 ,如下图所示

在实际任务中,对于输入的句子,我们使用上面的语言模型来处理它,得到输出向量,因此这可以看作是一种 特征提取 。但是 ELMo 与普通的 Word2Vec 或 GloVe 不同,ELMo 得到的 Embedding 是 有上下文信息

具体来说,给定一个长度为 N 的句子,假设为 ,语言模型会计算给定 的条件下出现 的概率:

传统的 N-gram 模型 不能考虑很长的历史 ,因此现在的主流是使用 多层双向 LSTM 。在时刻 ,LSTM 的第 层会输出一个隐状态 ,其中 , 是 LSTM 的层数。最上层是 ,对它进行 softmax 之后得到输出词的概率

类似的,我们可以用 一个反向 来计算概率:

通过这个 LSTM,我们可以得到 。我们的损失函数是这两个 LSTM 的 加和 :

这两个 LSTM 有各自的参数 和 ,而 Word Embedding 参数和 Softmax 参数是共享的

为了用于下游(DownStream)的特定任务,我们会把不同层的隐状态组合起来,具体组合的参数是根据不同的特定任务学习出来的,公式如下:

GPT 得到的语言模型参数不是固定的,它会根据特定的任务进行调整(通常是微调),这样的到的句子表示能更好的适配特定任务。它的思想也很简单,使用 单向 Transformer 学习一个语言模型 ,对句子进行无监督的 Embedding,然后 根据具体任务对 Transformer 的参数进行微调 。GPT 与 ELMo 有两个主要的区别:

这里解释一下上面提到的 单向 Transformer 。在 Transformer 的文章中,提到了 Encoder 与 Decoder 使用的 Transformer Block 是不同的。在 Decoder Block 中,使用了 Masked Self-Attention ,即句子中的每个词都只能对 包括自己在内的前面所有词进行 Attention ,这就是单向 Transformer。GPT 使用的 Transformer 结构就是将 Encoder 中的 Self-Attention 替换成了 Masked Self-Attention ,具体结构如下图所示

训练的过程也非常简单,就是将 n 个词的词嵌入 ( ) 加上位置嵌入 ( ),然后输入到 Transformer 中,n 个输出分别预测该位置的下一个词

这里的位置编码没有使用传统 Transformer 固定编码的方式,而是动态学习的

Pretraining 之后,我们还需要针对特定任务进行 Fine-Tuning。假设监督数据集合 的输入 是一个词序列 ,输出是一个分类的标签 ,比如情感分类任务

我们把 输入 Transformer 模型,得到最上层最后一个时刻的输出 ,将其通过我们新增的一个 Softmax 层(参数为 )进行分类,最后用 CrossEntropyLoss 计算损失,从而根据标准数据调整 Transformer 的参数以及 Softmax 的参数 。这等价于最大似然估计:

正常来说,我们应该调整参数使得 最大,但是 为了提高训练速度和模型的泛化能力 ,我们使用 Multi-Task Learning,同时让它最大似然 和

这里使用的 还是之前语言模型的损失(似然),但是使用的数据不是前面无监督的数据 ,而是使用当前任务的数据 ,而且只使用其中的 ,而不需要标签

针对不同任务,需要简单修改下输入数据的格式,例如对于相似度计算或问答,输入是两个序列,为了能够使用 GPT,我们需要一些特殊的技巧把两个输入序列变成一个输入序列

ELMo 和 GPT 最大的问题就是 传统的语言模型是单向的 —— 我们根据之前的历史来预测当前词。但是我们不能利用后面的信息。比如句子 The animal didn’t cross the street because it was too tired 。我们在编码 it 的语义的时候需要同时利用前后的信息,因为在这个句子中, it 可能指代 animal 也可能指代 street 。根据 tired ,我们推断它指代的是 animal 。但是如果把 tired 改成 wide ,那么 it 就是指代 street 了。传统的语言模型,都 只能利用单方向的信息 。比如前向的 RNN,在编码 it 的时候它看到了 animal 和 street ,但是它还没有看到 tired ,因此它不能确定 it 到底指代什么。如果是后向的 RNN,在编码的时候它看到了 tired ,但是它还根本没看到 animal ,因此它也不能知道指代的是 animal 。 Transformer 的 Self-Attention 理论上是可以同时关注到这两个词的,但是根据前面的介绍,为了使用 Transformer 学习语言模型,必须 用 Mask 来让它看不到未来的信息 ,所以它也不能解决这个问题的

根据上文内容预测下一个可能跟随的单词,就是常说的自左向右的语言模型任务,或者反过来也行,就是根据下文预测前面的单词,这种类型的LM被称为自回归语言模型。(GPT,ELMO)GPT 就是典型的自回归语言模型。ELMO尽管看上去利用了上文,也利用了下文,但是本质上仍然是自回归LM,这个跟模型具体怎么实现有关系。ELMO是做了两个方向(从左到右以及从右到左两个方向的语言模型),但是是分别有两个方向的自回归LM,然后把LSTM的两个方向的隐节点状态拼接到一起,来体现双向语言模型这个事情的。所以其实是两个自回归语言模型的拼接,本质上仍然是自回归语言模型。

自回归语言模型有优点有缺点,缺点是只能利用上文或者下文的信息,不能同时利用上文和下文的信息,当然,貌似ELMO这种双向都做,然后拼接看上去能够解决这个问题,因为融合模式过于简单,所以效果其实并不是太好。它的优点,其实跟下游NLP任务有关,比如生成类NLP任务,比如文本摘要,机器翻译等,在实际生成内容的时候,就是从左向右的, 自回归语言模型天然匹配这个过程 。而Bert这种DAE模式,在生成类NLP任务中,就面临训练过程和应用过程不一致的问题,导致 生成类的NLP任务到目前为止都做不太好

自回归语言模型只能根据上文预测下一个单词,或者反过来,只能根据下文预测前面一个单词。相比而言,Bert通过 在输入X中随机Mask掉一部分单词 ,然后预训练过程的主要任务之一是根据上下文单词来预测这些被Mask掉的单词,如果你对Denoising Autoencoder比较熟悉的话,会看出,这确实是典型的DAE的思路。那些被Mask掉的单词就是在输入侧加入的所谓噪音。类似Bert这种预训练模式,被称为DAE LM。

这种DAE LM的优缺点正好和自回归LM反过来,它能比较自然地融入双向语言模型,同时看到被预测单词的上文和下文,这是好处。缺点是啥呢? 主要在输入侧引入[Mask]标记,导致预训练阶段和Fine-tuning阶段不一致的问题 ,因为Fine-tuning阶段是看不到[Mask]标记的。DAE吗,就要引入噪音,[Mask] 标记就是引入噪音的手段,这个正常。

XLNet的出发点就是:能否 融合自回归LM和DAE LM两者的优点 。就是说如果站在自回归LM的角度,如何引入和双向语言模型等价的效果;如果站在DAE LM的角度看,它本身是融入双向语言模型的,如何抛掉表面的那个[Mask]标记,让预训练和Fine-tuning保持一致。当然,XLNet还讲到了一个Bert被Mask单词之间相互独立的问题。

离开深度学习瞎折腾了一段时间后,我终于又回来了。

于是赶紧回顾了下18年之后NLP的发展,基本就是将迁移学习更广泛的用于NLP领域,以及把17年年底的《Attention is all you need》里的思想给发扬光大了,ELMO弥补了传统word2vec多义词表示的不足,GPT使用更强大的特征提取器Transformer取代LSTM,Bert使用双向Transformer进一步改进了GPT成为这两年发展的集大成者。

从Bert模型所带来的NLP界里程碑式的影响和所取得的成就来看,无疑Bert将会是未来两三年NLP应用发展的基石,于是有必要仔细的看看其模型的结构,数据是如何流动的,训练的和测试的。

不得不说现在的学习环境相对几年前好太多了,本文主要参考了以下几篇文章,然后加了点自己的理解:

Dissecting BERT Part 1: The Encoder

The Illustrated Transformer

Dissecting BERT Appendix: The Decoder

它的总体框架同lstm时代的MNT或者是attention is all you need中的 transformer 一样的 encoder-decoder 结构:

我们先来介绍一下Encoder部分。

为了理解这个架构,我们使用一个简单的具体的例子,来看一下 输入 的数据是怎么通过 encoder 一步一步变化让后到 输出 的。

bert的词嵌入由三个嵌入token embedding、segment embedding,和position embedding叠加而成。

这个过程跟以往的RNNs没什么区别,比如给定一个句子:

第一步是先将其标记化:

然后是数字化,将每个标记映射到语料词汇表中的唯一整数编号:

接下来就是得到序列中每个词的词嵌入,也就是将整数映射到一个 维的向量,这个向量是模型在训练时学习的,你可以将其视为一个查表的过程,这些向量的元素作为模型的参数,像其他权重一样通过反向传播进行了优化。

在论文中是使用WordPiece tokenization 来将英文单词转换成768( )维的向量,转化的过程类似这样:

把每个词的向量放到一起,就得到了一个 句子长度x向量维度 ( ) 尺寸的矩阵 Z :

说明一点,我们通常使用 填充 的方式来让输入序列具有相同的长度,比如通过添加"<pad>" 标记来增加某些序列的长度,还是前面的例子,填充后可能变为:

如果设定 设定为9,那我们就把句子从5填充到了9。

但是,上面的embedding并没有包含词的位置信息。于是,我们的目标是能够根据词在句子中的位置适当调整这个向量,使它带上位置信息。

作者选择的方法是使用预定的(非学习的)正余弦函数将 之间的数字加到前面的embedding中,即通过正余弦函数将位置表示为彼此的线性组合,从而实现网络学习中标记位置之间的相对关系。在Token embedding 获得的矩阵 的基础上加上位置矩阵。

数学上,用 表示序列中标记的位置,用 表示token embedding特征向量中的位置:

具体来说,对于给定的句子 ,其位置嵌入矩阵为:

作者解释说,使用这种确定性方法的结果和学习位置表示(就像我们对词嵌入那样)的结果差不多,因此这样反而会有一些优势:

因此,添加了位置信息之后的矩阵是:

它是第一个encoder块的输入,尺寸是

共有N个编码器块连接在一起直到生成编码器的输出,特定的块负责查找输入表示之间的关系并将编码在其输出中。

直观地,通过这些块的迭代过程将帮助神经网络捕获输入序列中的词之间的更加复杂的关系,你可以把它理解成一个整体用来捕捉输入序列的语义。

encoder中使用Transformer的多头注意力机制,这意味着它将计算 份不同权重矩阵的自注意力,然后将结果连接在一起。

这些并行注意力计算的结果称之为Head,我们用下标 来表示一个特定的head和相关的权重矩阵。

如上图所示,一旦计算了所有head,它们将被连接起来,得到一个尺寸为 的矩阵,然后将它乘以一个尺寸为 的权重矩阵进行线性变换,就得到了一个尺寸为 的最终结果,用数学公式表示就是:

其中的 通过 乘以相应权重矩阵 获得,我们通过一个简单的例子来可视化的看一下这个过程。

这图描绘了输入标记通过 token embedding 和 positional encoding ,再输入到Encoder:

接下来,我们再来看下Encoder中的 *** 作过程,先看一下单头的self-attention:

上图描绘了一个Head的 是怎么来的,其中的 的尺寸是, 因为Q和K需要计算相似性,所以维度应当是相同的, 的尺寸是 , 的维度可以相同也可以不同,在论文中 .

所谓的自注意力,就是 与 的点积进行 的缩放之后通过softmax获得一个概率权重,然后用这些权重分别乘以各自的 即可:

为了加深理解,我们选择其中一个头,通过图形继续可视化的看一下这个变化过程:

然后计算self-attention,

多头的话就是同时有多个上述计算过程在进行:

假设我们有8个Head,那么我们就获得8个 :

但是,显然前馈层只需要一个矩阵 ,怎么处理呢?类似多卷积核的处理,把这8个矩阵连起来,乘以一个权重矩阵 压缩到一个矩阵。

为了有一个更加全面直观的认识,我们把上面整个过程放到一个图里,

显然,第二个encoder块是不需要embedding过程的,只要把第一个encoder块的输出作为输入即可。

经过上面的介绍,你应该对这个过程已经有了足够的了解,但是,为什么可以利用向量点积来计算注意力概率呢?

于是让我们进一步深入来了解其中的原理。

这个结构体系的关键在于:

也就是每个词的q向量与每个词的k向量的点积,套用点积公式:

这意味着 和 的方向越相似,长度越大,点积就越大。词与此之间关联越大,对于理解这个词时得到的关注越大,跟我们的本意是相同的。

我们再看一下最开头的结构示意图,每个encoder块在Multi-Head Attention之后经过一个 Add &Norm层才进入下一个块。于是我们来看一下这一层做了些什么。

Add 实际就是一个残差连接,将输出加上输入,这个在每一块的self-attenton以及FFN之后都会有,然后跟随一个Layer Norm 。

Norm 是一个Layer Normlization,将 正则化,就是把它缩放到一个均值为0方差为1的域里。因为

不过一般在这一层之前,就会有一个dropout层。

每个encoder块都由 mulit-head atteion add &Normfeed forword networkadd &Norm 这样一个过程,下面来介绍一下这个Feed-Forward Network。

这是一个全连接层,包含两个线性变化和一个非线性函数(实际一般就是ReLu),

对于输入的 (尺寸为 ) ,通过权重矩阵 (尺寸为 )和偏置 线性变换到隐藏层 (尺寸为 ) ,然后**ReLu **激活 ,记下来再用权重矩阵 (尺寸为 ) 和偏置的线性变换到输出层(尺寸为 ) ,表示成数学公式就是:

在最后一个encoder块输出之后连接到decoder。

Decoder和Encoder的结构是类似的,但是因为可视信息的不同,又有所差别。

Transformer解决的是翻译的问题,将一个句子翻译成另一种语言,我们希望模型能够捕捉到输入句子中词之间的关系,并且将输入句子中包含的信息与每一步已翻译的内容结合起来。继续上面的例子,我们的目标是把一个句子从英文翻译为西班牙文,这是我们获得的序列标记:

我们同之前一样来看看输入到输出数据是如何流动的。

这是我们的解码器的输入标记:

然后这是解码器的期望输出:

但是,这里存在一个问题,比如输入这边我们已经看到了'como' 的后面是'estas', 然后再用它来预测'estas' ,这显然是不合理的,因为模型在测试的时候是看不到后面的词的。

因此,我们需要修改注意力层,防止模型可以看到预测词右边的信息,与此同时,它能利用已经预测的词,即左边的信息。

继续上面的例子,我们将输入标记转换成矩阵的形式,并添加位置信息:

和encoder一样,decoder块的输出也将是大小为 的矩阵,在逐行线性变换+softmax激活后,将生成一个举证,其中每行的最大元素表示下一个单词。也就是说,分配"<SS>" 的行负责预测“Hola”, 分配"Hola"的行负责预测"," ...以此类推。比如,为了预测"estas", 我们将允许该行直接和下图中绿色区域互动,而不能和红色区域互动:

但是,在我们使用多头注意力机制的时候,所有的行都会产生交互,因此需要在输入的时候添加遮罩,这个遮罩会在注意力计算之后进行:

这是 self-attention 的计算结果:

然后我们在此基础上添加遮掩,就是把矩阵上三角的位置全部设置为 :

于是,在进行softmax激活之后,矩阵就变成了:

恰好达到了我们的要求,那些需要在训练时忽略的右侧的词的注意力全部变成了0。

当将这个注意力矩阵与 相乘时,预测的词就是模型可以访问元素右边的元素。注意,这里的多头注意力输出将是 维的,因为它的序列长度是 。

这个就是 Decoder target序列 的输入,并经过 Masked Multi-Head Attention 的一个变化得到了 ,decoder的还有一部分输入来自于源语句经过 Encoder 的最终输出 (尺寸是)。

接下来,就是与encoder一样的 Multi-Head AttentionAdd and Layer Norm ->FFN 的过程。

只不过,现在的 来自于,而 来自于 :

计算每个query相对于key的注意力之后,得到的是一个 的矩阵, 继续咱们的例子,比如注意力矩阵为:

如上图所见,这个注意力是当前Decoder输入与Encoder输出的每个词之间的注意力,咱们用这个矩阵再乘以 ,就得到了一个 的矩阵,每一行代表了源语句相对于当前输入词汇的特征:

h个Head连接起来,尺寸变为,它通过 的权重矩阵 线性变换到一个 的输出。

这在多个Decoder之后,最后输出的矩阵通过乘以权重矩阵 ( ) 进行线性变换,变换之后再对每一行的向量softmax, 其中选择值最大位置对应词表索引的词就是预测的词。

损失的话只需要用预测的每个词向量与真实的词的one-hot词表示计算交叉熵即可。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/tougao/7836907.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-10
下一篇 2023-04-10

发表评论

登录后才能评论

评论列表(0条)

保存