万字长文 · 多图解析 | 建议收藏后反复阅读
导读Transformer 不仅打破了传统卷积网络的垄断,而且以其独特的网络结构吸引了大批人员进行研究改进。但也因为难以理解而让小白止步,本文将详细讲解其结构,从根本为大家讲解其工作原理。
01导语:Transformer 从何而来?
谷歌推出的 BERT 模型在 11 项 NLP 任务中夺得 SOTA 结果,引爆了整个 NLP 界。而 BERT 取得成功的一个关键因素是 Transformer 的强大作用。
谷歌的 Transformer 模型最早用于机器翻译任务,当时达到了 SOTA 效果。它改进了 RNN 最被人诟病的训练慢的缺点,利用 self-attention 机制实现快速并行。并且 Transformer 可以增加到非常深的深度,充分发掘 DNN 模型的特性,提升模型准确率。
Transformer = 并行计算 + 自注意力机制 + 可堆叠的深度架构
02正文开始:拆解 Transformer
Transformer 由论文《Attention is All You Need》提出,现在是谷歌云 TPU 推荐的参考模型。论文相关的 TensorFlow 代码可以从 GitHub 获取,其作为 Tensor2Tensor 包的一部分。哈佛的 NLP 团队也实现了一个基于 PyTorch 的版本,并注释该论文。
核心论文与资源
Attention is All You Need:arxiv.org/abs/1706.03762从宏观视角开始:把它看成黑箱
首先将这个模型看成是一个黑箱操作。在机器翻译中,就是输入一种语言,输出另一种语言。
那么拆开这个黑箱,可以看到它由编码组件、解码组件和它们之间的连接组成。
拆开黑箱:编码组件 + 解码组件
编码组件由一堆编码器(encoder)构成(论文中是将 6 个编码器叠在一起——数字 6 没有什么神奇之处,你也可以尝试其他数字)。解码组件也是由相同数量的解码器(decoder)组成。
6 个编码器堆叠 + 6 个解码器堆叠
所有的编码器在结构上都是相同的,但它们没有共享参数。每个编码器可以分解为两个子层:
每个编码器的两个子层:自注意力层 + 前馈神经网络
从编码器输入的句子首先会经过一个自注意力(self-attention)层,这层帮助编码器在对每个单词编码时关注输入句子的其他单词。自注意力层的输出会传递到前馈(feed-forward)神经网络中。每个位置的单词对应的前馈神经网络完全一样。
解码器中也有编码器的自注意力层和前馈层。除此之外,这两个层之间还有一个注意力层,用来关注输入句子的相关部分(和 seq2seq 模型的注意力作用相似)。
解码器的三个子层:自注意力 + 编码-解码注意力 + 前馈
将张量引入图景
我们已经了解了模型的主要部分,接下来看一下各种向量或张量是怎样在模型的不同部分中,将输入转化为输出的。
像大部分 NLP 应用一样,我们首先将每个输入单词通过词嵌入算法转换为词向量。每个单词都被嵌入为 512 维的向量。
每个单词被嵌入为 512 维向量
词嵌入过程只发生在最底层的编码器中。所有的编码器都接收一个向量列表,列表中每个向量大小为 512 维。在底层编码器中它就是词向量,在其他编码器中则是下一层的输出。向量列表大小是可设置的超参数——一般是训练集中最长句子的长度。
词嵌入流经编码器堆栈
接下来我们看看 Transformer 的一个核心特性:输入序列中每个位置的单词都有自己独特的路径流入编码器。在自注意力层中,这些路径之间存在依赖关系;而前馈层没有这些依赖关系,因此可以并行执行各种路径。
每个单词的路径:自注意力层有依赖,前馈层可并行
然后我们将以一个更短的句子为例,看看编码器的每个子层中发生了什么。
以一个短句为例进行编码
03现在我们开始「编码」
一个编码器接收向量列表作为输入,将向量传递到自注意力层进行处理,然后传递到前馈神经网络层,将输出结果传递到下一个编码器中。
输入序列的每个单词各自通过前向传播神经网络
04自注意力机制:Transformer 的核心
从宏观视角看自注意力
不要被「自注意力」这个词弄迷糊了,好像每个人都应该熟悉这个概念。其实在读到 Attention is All You Need 这篇论文时,很多人也是第一次接触这个概念。
例如句子:The animal didn't cross the street because it was too tired这个「it」是指 street 还是 animal?对于人类来说很简单,但对于算法则不是。自注意力机制允许「it」与「animal」建立联系。
随着模型处理输入序列的每个单词,自注意力会关注整个输入序列的所有单词,帮助模型对本单词更好地进行编码。
编码「it」时,注意力机制关注到「The Animal」
如果你熟悉 RNN,回忆一下它是如何维持隐藏层的——RNN 会将已处理过的前面所有单词的表示与当前单词结合起来。而自注意力机制会将所有相关单词的理解融入到正在处理的单词中。
在栈最上层编码器中编码「it」时,注意力机制关注到「The Animal」
从微观视角看自注意力:六步计算
计算自注意力的第一步,是从每个编码器的输入向量中生成三个向量:查询向量(Q)、键向量(K)和值向量(V)。这三个向量通过词嵌入与三个权重矩阵相乘创建。
每个单词创建查询向量、键向量和值向量
什么是查询(Q)、键(K)、值(V)向量?
它们都是有助于计算和理解注意力机制的抽象概念。查询向量是当前单词的「提问」,键向量是其他单词的「标签」,值向量是其他单词的「内容」。通过 Q 和 K 的匹配程度,决定从 V 中提取多少信息。
1
计算得分
假设为第一个词「Thinking」计算自注意力。需要拿输入句子中每个单词对「Thinking」打分。分数通过打分单词的键向量与「Thinking」的查询向量点积来计算。
第一步:计算 Q 与 K 的点积得分
2
缩放分数
将分数除以 8(8 是键向量维数 64 的平方根),这会让梯度更稳定。
3
Softmax 归一化
通过 softmax 传递结果,使所有单词的分数归一化为正值且和为 1。这个分数决定了每个单词对编码当下位置的贡献。
第三步:Softmax 使分数归一化
4
加权值向量
将每个值向量乘以 softmax 分数(准备求和)。直觉是关注语义上相关的单词,并弱化不相关的单词。
第四步:将值向量乘以 softmax 分数
网上杠杆配资5
对加权值向量求和
对加权值向量求和,即得到自注意力层在该位置的输出。自注意力的本质就是在编码某个单词时,将所有单词的值向量进行加权求和,权重由查询向量和键向量的点积经 softmax 得到。
第五步:对加权值向量求和,得到自注意力输出
这样自注意力的计算就完成了,得到的向量可以传给前馈神经网络。
通过矩阵运算实现自注意力
实际中,这些计算以矩阵形式完成,以便算得更快。第一步是计算查询矩阵、键矩阵和值矩阵:将输入句子的词嵌入装进矩阵 X 中,乘以训练的权重矩阵(WQ, WK, WV)。
矩阵运算:X 乘以 WQ/WK/WV 得到 Q/K/V 矩阵
最后,由于我们处理的是矩阵,可以将步骤 2 到步骤 6 合并为一个公式来计算自注意力层的输出:
自注意力的矩阵运算公式
Attention(Q, K, V) = softmax(QKᵀ / √dₖ) · V
05大战多头怪:多头注意力机制

通过增加「多头」注意力(multi-headed attention)机制,论文进一步完善了自注意力层,在两方面提高了性能:
1
扩展专注不同位置的能力
虽然每个编码在 z1 中有或多或少的体现,但可能被单词本身所支配。多头注意机制可以让模型从不同角度关注不同位置。
2
给出多个「表示子空间」
对于多头注意机制,有多个查询/键/值权重矩阵集(Transformer 使用八个注意力头)。每个集合都将输入投影到不同的表示子空间中。
多头注意力:每个头有独立的 Q/K/V 权重矩阵
如果我们做与上述相同的自注意力计算,只需八次不同的权重矩阵运算,就会得到八个不同的 Z 矩阵。
八个注意力头产生八个不同的 Z 矩阵
前馈层不需要 8 个矩阵,它只需要一个矩阵。所以需要把这八个矩阵压缩成一个:直接拼接,然后用一个附加的权重矩阵 WO 与它们相乘。
将八个矩阵拼接后乘以 WO,压缩为一个矩阵
这几乎就是多头自注意力的全部。把所有矩阵集中在一个图片中,可以一眼看清:
多头自注意力的完整计算流程
不同注意力头关注什么?
让我们重温之前的例子,看看编码「it」一词时,不同的注意力头集中在哪里:
一个头集中在「animal」上,另一个集中在「tired」上
如果我们把所有的 attention 都加到图示里,事情就更难解释了:
所有八个注意力头的关注情况汇总
06使用位置编码表示序列的顺序
到目前为止,模型缺少一种理解输入单词顺序的方法。为了解决这个问题,Transformer 为每个输入的词嵌入添加了一个位置编码向量。
这些向量遵循模型学习到的特定模式,有助于确定每个单词的位置,或序列中不同单词之间的距离。将位置向量添加到词嵌入中,使得它们在接下来的运算中能够更好地表达词与词之间的距离。
位置编码向量与词嵌入相加
如果我们假设词嵌入的维数为 4,则实际的位置编码如下:
尺寸为 4 的迷你词嵌入位置编码实例
在下图中,每一行对应一个词向量的位置编码。每行包含 512 个值,每个值介于 1 和 -1 之间。左半部分由正弦函数生成,右半部分由余弦函数生成。
20 字(行)的位置编码实例,词嵌入大小为 512(列)
位置编码的优点是能够扩展到未知的序列长度——当我们训练出的模型需要翻译远比训练集更长的句子时,依然有效。
07残差模块与层归一化
在每个编码器中的每个子层(自注意力、前馈网络)周围都有一个残差连接,并且都跟随着一个「层-归一化」步骤。
每个子层都有残差连接和层归一化
如果我们去可视化这些向量以及与自注意力相关联的层-归一化操作,看起来就像下面这样:
向量在残差连接和层归一化中的流动
解码器的子层也是这样的。如果我们想象一个 2 层编码-解码结构的 Transformer,它看起来会像这样:
2 层编码-解码结构的 Transformer 全貌
08解码组件:逐步输出
编码器通过处理输入序列开启工作。顶端编码器的输出之后会被转化为一个包含向量 K(键向量)和 V(值向量)的注意力向量集。这些向量将被每个解码器用于自身的「编码-解码注意力层」。
顶端编码器的输出转化为 K/V 向量集,传递给解码器
在完成编码阶段后,则开始解码阶段。解码阶段的每个步骤都会输出一个输出序列的元素。接下来的步骤重复这个过程,直到到达一个特殊的终止符号。
解码阶段:每个步骤输出一个元素,直到终止符号
元股证券:ygzq.hk解码器中的自注意力层与编码器不同:在解码器中,自注意力层只被允许处理输出序列中更靠前的那些位置。在 softmax 步骤前,它会把后面的位置隐去(设为 -inf)。
「编码-解码注意力层」工作方式基本就像多头自注意力层一样,只不过它是通过在它下面的层来创造查询矩阵,并从编码器的输出中取得键/值矩阵。
09最终的线性变换和 Softmax 层
解码组件最后会输出一个实数向量。如何把浮点数变成一个单词?这便是线性变换层要做的工作,它之后就是 Softmax 层。
线性变换层是一个简单的全连接神经网络,它把解码组件产生的向量投射到一个更大的、被称作对数几率(logits)的向量里。假设模型学习了一万个不同的英语单词,那么对数几率向量为一万个单元格长度——每个单元格对应某一个单词的分数。
接下来的 Softmax 层便把那些分数变成概率(都为正数、上限 1.0)。概率最高的单元格被选中,它对应的单词就是这个时间步的输出。
从解码器输出到最终单词:线性变换 → Softmax → 输出词
10训练过程:损失函数与优化
在训练过程中,一个未经训练的模型会通过一个完全一样的前向传播。但因为我们用有标记的训练集来训练它,所以可以用它的输出去与真实的输出做比较。
训练的核心流程:模型输出概率分布 → 与真实标签比较 → 计算损失(交叉熵 / KL 散度)→ 反向传播调整权重 → 重复直到收敛
假设输出词汇仅仅包含六个单词:「a」「am」「i」「thanks」「student」以及「」。我们可以用一个 one-hot 编码来表示词汇表中的每一个单词——即一个只有一个位置为 1、其余全为 0 的向量。
因为模型的参数都被随机生成,未经训练的模型产生的概率分布会在每个单元格里赋予随机数值。我们可以用真实的输出来比较它,然后用反向传播算法来略微调整所有模型的权重,生成更接近结果的输出。
如何比较两个概率分布?
可以简单地用其中一个减去另一个。更精确的方法是使用交叉熵(Cross-Entropy)和 KL 散度(Kullback-Leibler Divergence)来衡量两个分布之间的差异。交叉熵越小,模型输出越接近真实标签。
更现实的情况是处理一个句子。例如输入「je suis étudiant」并期望输出「i am a student」。那我们希望模型能够在这些情况下输出正确的概率分布:第一个分布中「i」概率最高,第二个分布中「am」概率最高,以此类推。
在一个足够大的数据集上充分训练后,模型输出的概率分布应该集中在正确的单词上。注意到每个位置都得到了一点概率,即使它不太可能成为那个时间步的输出——这是 softmax 的一个有用性质,可以帮助模型训练。
模型一次只产生一个输出。贪心解码:每步选择概率最高的单词。集束搜索(Beam Search):保留概率最高的 N 个候选,在下一步中分别展开,最终选择总概率最高的序列。
11进阶资源
我希望通过上文已经让你们了解到Transformer的主要概念了。如果你想在这个领域深入,我建议可以走以下几步:阅读Attention Is All You Need,Transformer博客和Tensor2Tensor announcement,以及看看Łukasz Kaiser的介绍,了解模型和细节。
Attention Is All You Need:
https://arxiv.org/abs/1706.03762
Transformer博客:
https://ai.googleblog.com/2017/08/transformer-novel-neural-network.html
Tensor2Tensor announcement:
https://ai.googleblog.com/2017/06/accelerating-deep-learning-research.html
Łukasz Kaiser的介绍:
https://colab.research.google.com/github/tensorflow/tensor2tensor/blob/master/tensor2tensor/notebooks/hello_t2t.ipynb
核心要点速览
黑箱结构:Transformer = 编码器堆栈 + 解码器堆栈,输入序列 → 输出序列
自注意力:每个单词通过 Q/K/V 三个向量与所有单词交互,权重由点积+softmax 决定
多头注意力:8 个独立的注意力头并行计算,拼接后乘以 WO 压缩
位置编码:用正弦/余弦函数生成位置向量,加到词嵌入上,赋予顺序信息
残差连接 + 层归一化:每个子层都包裹,稳定梯度、支持深层堆叠
解码器:自注意力只能看前面位置(掩码),编码-解码注意力连接两端
输出:线性层投射到词表维度 → Softmax → 选词
解码策略:贪心(选最高概率)或集束搜索(保留 N 个候选)
来源:海豚数智科学实验室
本文仅用于学术分享,如有侵权,请联系后台作删文处理 ]article_adlist-->全国股票配资开户提示:本文来自互联网,不代表本网站观点。