























原文链接:https://mp.weixin.qq.com/s/R3BxCMu5CSFo_HPcVJTuOA
欢迎关注公gh: Al-Frontiers
transformer往期文章推荐
从这篇开始,将通过一系列文章,给大家介绍 LLM 背后的技术架构:transformer。我们将采用自顶向下的方式,阐述transformer的功能、基础知识、架构、注意力机制及其内部工作原理。希望通过这些系列文档的介绍,能够帮助大家更好地理解 LLM 运行机制。
自2017年,Google发布 「Attention Is All You Need」(https://arxiv.org/abs/1706.03762)以来,transformer架构一直霸榜 NLP 领域,包括 Google 和 OpenAI 在内发布的各类明星模型,都是以 transformer 架构为基础,在当时都取得了效果最佳的基准测试结果。
本篇将以通俗易懂、图文并茂的方式,为大家讲解 Transformer 在 NLP 中的应用、相比RNN的优势,重点介绍注意力机制如何提升性能。
transformer 架构擅长处理本质上具有顺序性的文本数据。它以文本序列作为输入,并生成另一个文本序列作为输出。例如,将输入的英文句子翻译成西班牙语。

它的核心是一系列编码器层和解码器层。为避免混淆,我们将单个层称为「编码器」或「解码器」,而将一组编码器层称为「编码器堆栈」或「解码器堆栈」。
编码器栈和解码器栈各自都有对应的嵌入层,用于处理各自的输入。最后,还有一个输出层来生成最终的输出。

所有编码器和解码器在架构上都是相同,但是他们之间的权重是不共享的。

编码器:包含自注意力层(Self-attention )和前馈层(Feed-forward ),前者负责计算序列中不同词汇之间的关系,后者将注意力层的输出作为输入。
解码器:包含自注意力层和前馈层,以及编码器-解码器注意力层。
每个编码器和解码器都有自己的一组权重。
编码器是一个可复用的模块,是所有Transformer架构的核心组件。除了上述两层之外,它还在这两层周围设置了残差连接,并包含两个归一化层。

transformer架构有很多变体。有些Transformer架构完全没有解码器,只依赖于编码器(后面会再写文章给大家介绍)。
transformer 能取得突破性性能,关键在于它使用了注意力机制。
在处理一个词时,注意力机制使模型能够关注输入中与该词密切相关的其他词。
例如,下面这句话,"ball" 与 "blue"、"holding"这两个词密切相关, 而 "blue" 与 "boy" 无关。

transformer 架构使用的自注意力机制,会把输入序列里的每一个词和其他所有词关联起来。
例如:考虑以下两个句子:
The cat drank the milk because it was hungry.
The cat drank the milk because it was sweet.
在第一句中,"it" 指的是 "cat",而在第二句中,"it" 指的是 "milk"。当模型处理 "it" 这个词时,自注意力机制会给模型提供更多关于其含义的信息,以便模型能够将 "it" 与正确的词联系起来。

为了让模型能处理句子意图和语义中更细微的差别,transformer 为每个词都配备了多个注意力得分。
例如,在处理单词 "it" 时,第一个得分突出显示了 "cat",而第二个得分突出显示了 "hungry"。因此,当它解码单词 "it" 时,例如将其翻译成另一种语言,它会将 "cat" 和 "hungry" 的某些特征融入到翻译后的单词中。

transformer 在训练阶段和推理阶段的工作方式略有不同。
我们先看看训练时的数据流向。训练数据包含两部分:
源序列,也就是输入序列(比如翻译任务里的英文句子:"You are welcome")。
目标序列,也就是期望的输出序列(比如对应的西班牙语:"De nada")。
transformer 的目标,就是学会如何同时利用输入序列和目标序列,来输出正确的目标序列。

transformer 处理数据的过程是这样的:
输入序列被转换成嵌入向量(同时加入了位置编码),然后喂给编码器。
编码器堆栈处理这些数据,并生成输入序列的一个编码表示。
目标序列的开头会加上一个句子起始标记,然后也被转换成嵌入向量(同样加入位置编码),再喂给解码器。
解码器堆栈会结合上面编码器堆栈产生的编码表示,一起处理这些数据,最终生成目标序列的一个编码表示。
输出层将这个编码表示转换成词汇概率,并输出最终的输出序列。
transformer 的损失函数(Loss function) 会用这个输出序列跟训练数据里的目标序列做比较。产生的损失值用于生成梯度,通过反向传播来训练 transformer。
在推理阶段,我们只有输入序列,没有目标序列作为解码器的输入。Transformer 的目标是仅根据输入序列生成目标序列。
因此,就像在 Seq2Seq 模型中一样,我们在一个循环中生成输出,并将前一个时间步的输出序列输入到下一个时间步的解码器中,直到遇到句子结束标记为止。
跟 Seq2Seq 模型不同的是,在每一个时间步,我们不是只喂给解码器上一个词,而是把到目前为止生成的所有输出序列都重新喂进去。

推理阶段的数据流向是:
输入序列被转换成嵌入向量(加位置编码),喂给编码器。
编码器堆栈处理这些数据,生成输入序列的编码表示。
这时,我们不用目标序列,而是用一个只包含句子起始标记的空序列。同样,把它转换成嵌入向量(加位置编码),喂给解码器。
解码器堆栈结合编码器堆栈的编码表示,处理这些数据,生成一个目标序列的编码表示。
输出层将其转换成词汇概率,并产出一个输出序列。
我们取这个输出序列概率最大的词,作为当前预测出的词。然后,把这个词填入解码器输入序列的第二位置。这时,解码器的输入序列就包含了:句子起始标记 + 第一个预测词。
回到第3步。和之前一样,把新的解码器序列喂给模型。然后,取这次输出的第二个词,将其添加到解码器序列的末尾。重复这个过程,直到模型预测出句子结束标记。
注意:因为编码器序列在每次迭代中都不变,所以我们不必重复第1步和第2步。
训练时把目标序列直接喂给解码器的做法,叫做教师强制(Teacher Forcing)。
为什么要这么做?这个术语又是什么意思呢?
其实,训练时原本可以采用和推理时一样的方法:让 transformer 在一个循环里跑,每次取输出序列概率最大的词,拼接到解码器输入后面,再喂给解码器进行下一次迭代。直到预测出句子结束标记,再用损失函数比较生成的输出序列和目标序列,来训练网络。
但这种循环式的训练不仅会让训练时间成倍增加,还会让模型更难训练。因为模型可能需要基于可能有误的第一个预测词,去预测第二个词,这样一步步,错误就会像滚雪球一样累积。
相反,我们把目标序列喂给解码器,等于是给了它一个提示,就像老师做的那样。即使模型第一步预测错了,它还是能直接用正确的第一个词去学习预测第二个词,从而避免错误不断累积。
此外,这种并行方式也让 transformer 能在训练时一次性输出所有词,无需循环,极大地加速了训练。
transformer模型用途广泛,可用于大多数自然语言处理任务,例如语言模型和文本分类。它们经常用于序列到序列模型,应用于机器翻译、文本摘要、问答系统、命名实体识别和语音识别等领域。
针对不同的问题,transformer架构有多种不同的变体。基本的编码器层是这些架构的通用构建模块,而不同的「头部」则根据所要解决的问题而有所不同。
以情感分析应用为例。它接收一个文本文档作为输入。一个分类头会接收 transformer 的输出,然后生成对类别标签的预测,比如 "正面"或 "负面" 情绪。

语言模型架构会接收输入序列(比如一个句子的前半部分),然后通过预测后续句子来生成新的文本。一个语言模型头会接收 transformer 的输出,并为词汇表中的每一个词生成一个概率。其中概率最高的那个词,就会被作为句中下一个词的预测结果。

在 transformer 横空出世并取而代之之前,RNN 及其变体 LSTM 和 GRU,是所有自然语言处理应用事实上的标准架构。
基于 RNN 的序列到序列模型表现不错。而且,当注意力机制刚被提出时,它首先是被用来增强 RNN 模型性能的。
但,RNN 有两个局限:
很难处理长距离依赖关系,即那些在很长的句子里分布得很开的词汇之间的联系。
RNN 一个接一个地顺序处理输入序列,这意味着在完成第 t-1 步的计算之前,无法进行第 t 步的计算。这会拖慢训练和推理的速度。
顺便提一句,对于 CNN 来说,所有的输出都可以并行计算,这让卷积操作快得多。然而,CNN 在处理长距离依赖时同样存在局限:
transformer 架构则同时解决了这两个局限。它彻底抛弃了 RNN,完全依赖于注意力机制的优势。

本篇我们对 Transformer 有了一个宏观的概念,下一篇将深入 transformer 内部结构,深入理解它的工作机制。
感谢阅读文章,如果觉得不错,欢迎点个赞、转发!
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。