Transformer原理详解----李宏毅机器学习课程笔记
下述内容又来源有参考,真实可靠
下述大多是讲Transformer怎么设计的,没有讲为什么要这样设计。已累,有时间再补。本笔记参考:
1.https://www.rethink.fun/
2.The Illustrated Transformer – Jay Alammar – Visualizing machine learning one concept at a time.
3.Speech and Language Processing. Daniel Jurafsky & James H. Martin. Copyright © 2026. All rights reserved. Draft of January 6, 2026.
4.李宏毅视频
5.论文:Attention is all you need
一.序列建模问题
1.1 序列信号
序列信号可以是文本、语言等。
token序列处理过程中的最小操作基元
1.2 Seq2Seq问题
1.每个输入多对应一个label
比如词性标准,你需要给每个词都输出词性。
2.整局输入对应一个lable
比如语义分类,将这个句子分为正面或者负面。
3.输出长度不固定
比如智能问答。
这种任务叫做Seq2Seq任务
1.3 序列建模问题
1.不使用上下文信息
全连接神经网络没有使用上下文信息肯定不行
2.有限的上下文信息
使用一个窗口,使用窗口里面的信息,但窗口长度难以确定。窗口小了信息不够,窗口大了模型参数量大
二.self-attention
对于上述序列建模问题,我们需要思考怎么样可以在对特定单词进行编码时,去关注输入句子中的其他单词,但不增加模型参数量,这时就引出自注意力机制。
self-attention正是 Transformer 用来将对其他相关单词的“理解”融入到当前正在处理的单词中的方法。
自注意力机制输入输出数量一致,里面使用线性代数运算。整体结构如下,输入为 a 1 , a 2 , a 3 , a 4 a^1,a^2,a^3,a^4 a1,a2,a3,a4,输出为 b 1 , b 2 , b 3 , b 4 b^1,b^2,b^3,b^4 b1,b2,b3,b4。
2.1 self-attention内部结构
先来看怎么生成 b 1 b^1 b1。
怎么计算 a 1 a^1 a1与 a 2 , a 3 , a 4 a^2,a^3,a^4 a2,a3,a4的相关性 α \alpha α,也就是对序列中的第 1 个单词,是如何计算出它对其他单词的关注程度的。
此处进行的计算有:
- q i = W q ⋅ a i q^i=W^q \cdot a^i qi=Wq⋅ai
- k i = W k ⋅ a i k^i=W^k \cdot a^i ki=Wk⋅ai
- α 1 , 2 = q 1 ⋅ k 2 \alpha_{1,2} = q^1 \cdot k^2 α1,2=q1⋅k2, α 1 , 3 = q 1 ⋅ k 3 \alpha_{1,3} = q^1 \cdot k^3 α1,3=q1⋅k3, α 1 , 4 = q 1 ⋅ k 4 \alpha_{1,4} = q^1 \cdot k^4 α1,4=q1⋅k4。
模型并不是直接用原始的 a a a 向量去计算相似度,而是引入了可学习的权重矩阵 W q W^q Wq 和 W k W^k Wk。
- 将输入 a 1 a^1 a1 乘以 W q W^q Wq,将其投影到“查询空间”,生成查询向量 q 1 q^1 q1。
- 将输入 a 2 , a 3 , a 4 a^2, a^3, a^4 a2,a3,a4 乘以 W k W^k Wk,将其投影到“键空间”,生成键向量 k 2 , k 3 , k 4 k^2, k^3, k^4 k2,k3,k4。
α \alpha α 代表“attention”,这个分数决定了当我们在某个特定位置对单词进行编码时,应该将多少注意力(焦点)放在输入句子的其他部分上。

此处进行的计算有:
- α 1 , i ′ = exp ( α 1 , i ) ∑ j exp ( α 1 , j ) \alpha'_{1,i} = \frac{\exp(\alpha_{1,i})}{\sum_j \exp(\alpha_{1,j})} α1,i′=∑jexp(α1,j)exp(α1,i)
- 注意此处还通过 α 1 , 1 = q 1 ⋅ k 1 \alpha_{1,1} = q^1 \cdot k^1 α1,1=q1⋅k1得到了自身的注意力得分。
加上softmax操作,归一化分值使得全为正数且加和为1。
这个 softmax 分数决定了每个单词在这个位置上将被表达的程度。显然,当前位置的单词将具有最高的 softmax 分数,但有时去关注另一个与当前单词相关的单词也是非常有用的。
此处进行的计算有:
- v i = W v ⋅ a i v^i=W^v \cdot a^i vi=Wv⋅ai
- b 1 = ∑ i α 1 , i ′ v i b^1 = \sum_i \alpha'_{1,i} v^i b1=∑iα1,i′vi
将softmax分值与value-vec按位相乘这里的直觉是:保持我们想要关注的单词的值完好无损,并淹没掉不相关的单词(例如,通过将它们乘以像 0.001 这样的微小数字)。
将所有加权向量加和,产生该位置的self-attention的输出结果。
b 2 b^2 b2的计算过程如下,可以发现 b 1 , b 2 , b 3 , b 4 b^1,b^2,b^3,b^4 b1,b2,b3,b4计算相互独立,可以并行。
2.2 self-attention矩阵表述
在实际的工程实现中,为了加快计算速度,这一过程是以矩阵形式进行的。既然我们已经了解了单词级别的计算直觉,现在让我们来看看具体的矩阵计算过程。
所有输入共享 W q , W k , W v W^q,W^k,W^v Wq,Wk,Wv矩阵,于是在计算 q i , k i , v i q^i,k^i,v^i qi,ki,vi时可以得到下述表示:
- Q = W q ⋅ I Q=W^q \cdot I Q=Wq⋅I
- K = W k ⋅ I K=W^k \cdot I K=Wk⋅I
- V = W v ⋅ I V=W^v \cdot I V=Wv⋅I

在计算 α i , j \alpha_{i,j} αi,j的时候也可以变成矩阵的形式:
- A = K T ⋅ Q A=K^T \cdot Q A=KT⋅Q
- A A A通过softmax转变为 A ′ A' A′

计算 b i b^i bi的时候用矩阵表示如下:
- O = V ∗ A ′ O=V*A' O=V∗A′

最后将整个过程使用矩阵表示如下图:
所以整个过程 W q , W k , W v W^q,W^k,W^v Wq,Wk,Wv矩阵是未知的,需要学习的。
这整个过程输入长度变化并不会使 W q , W k , W v W^q,W^k,W^v Wq,Wk,Wv矩阵变大,所以不会增加参数量。
但输入越大,计算量越大。
2.3 多头self-attention
下图展示了只有两个头是计算 b i b^{i} bi(与 a i a^i ai相对应的输出)的过程:
- q , k , v q,k,v q,k,v的计算原理类似,以 q q q为例
- 首先根据 a i a^i ai得到 q i q_i qi
- q i q_i qi再通过 q i , 1 = W q , 1 q i , q i , 2 = W q , 2 q i q^{i,1}=W^{q,1}q^i,q^{i,2}=W^{q,2}q^i qi,1=Wq,1qi,qi,2=Wq,2qi得到 q i , 1 , q i , 2 q^{i,1},q^{i,2} qi,1,qi,2
- 我们需要对每个头进行计算,得到 b i , 1 , b i , 2 b^{i,1},b^{i,2} bi,1,bi,2
- 然后因为最终输出是只有 b i b^i bi,所以我们需要引入一个新的矩阵 W o W^o Wo。

2.4 self-attention vs CNN
self-attention是全局相关性
CNN是局部相关性
2.5 self-attention vs RNN
RNN的原理使它无法并行
RNN时间越长,第n个与第1个相关性约复杂
RNN容易发生梯度消失和梯度爆炸
三.Transformer模型
3.1 总体结构
其中,编码器将输入序列的符号表示 ( x 1 , . . . , x n ) (x_1, ..., x_n) (x1,...,xn)映射为连续表示序列 z = ( z 1 , . . . , z n ) z = (z_1, ..., z_n) z=(z1,...,zn)。在给定 z z z的情况下,解码器逐步生成输出符号序列 ( y 1 , . . . , y m ) (y_1, ..., y_m) (y1,...,ym)。
在每一步中,模型是自回归的(auto-regressive),即在生成下一个符号时,会将之前已经生成的符号作为额外输入。
上面这张图是Transformer的架构图,由两个部分组成:编码器、解码器,如下图所示:
3.2 分词
语言模型是以token为单位对文本进行处理的,所以首先需要将文本划分成token。
模型需要学习切分的规则:
- 这里会使用大量的文字,通过Byte Pair Encoding (BPE)算法,得到一个token list
- 一般不同的大模型分词方式的细节不一样
得到了token list,对输入字符串进行最大匹配切分,就可以得到token序列。
3.3 词嵌入
词嵌入的目的是将词元转化为向量,在这里也使用查表。
- 语义相近的token有相近的Embedding

3.4 位置编码
在self-attetion中,只是将对其他相关单词的“理解”融入到当前正在处理的单词中,没有考虑位置因素。
因此可以为每一个位置设定一个向量 e i e^i ei,然后加在 a i a^i ai上。
3.5 编码器结构
如下图,编码器的输入与输出长度一致。

详细的步骤如图:
- 在self-attention的输出 x 2 x_2 x2会加上输入 x 1 x_1 x1,得到一个结果 x 3 x_3 x3
- 上述结果 x 3 x_3 x3会使用Layer Norm进行归一化,得到一个结果 x 4 x_4 x4
- 上述结果 x 4 x_4 x4再通过Feed Forward产生一个输出 x 5 x_5 x5
- 将这个输出 x 5 x_5 x5与Feed Forwaed的输入 x 4 x_4 x4相加得到一个结果 x 6 x_6 x6
- 上述结果 x 7 x_7 x7使用Layer Norm进行归一化,得到一个结果 x 7 x_7 x7
- 上述结果 x 7 x_7 x7为一个块的最终结果
注意原始的Transformer的编码器架构,它不一定是最好的架构。
3.3 解码器结构
如下图,解码器的输入输出序列长度不一致。

3.3.1 编码器总体结构
Decoder会把自己的输出当作接下来自己的输入

3.3.2 Masked Multi-Head-Attention
掩码自注意力机制是只能使用前面的来计算 b i b^i bi:
- 计算 b 1 b^1 b1只使用了 a 1 a^1 a1
- 计算 b 2 b^2 b2使用了 a 1 , a 2 a^1,a^2 a1,a2
- 计算 b 3 b^3 b3使用了 a 1 , a 2 , a 3 a^1,a^2,a^3 a1,a2,a3
- 计算 b 4 b^4 b4使用了 a 1 , a 2 , a 3 , a 4 a^1,a^2,a^3,a^4 a1,a2,a3,a4

3.3.3 Cross-attention
在cross-attention实现了编码器与解码器的信息传递。
- 从图中可以看出,Encoder提供了两个输入,DeCoder提供了一个输入
- 这使得解码器中的每一个位置都可以关注输入序列中的所有位置。

图片中的处理过程如下:
- 首先begin通过mask self-attetion产生一个向量,然后乘以一个矩阵得到 q q q。
- a 1 , a 2 , a 3 a^1,a^2,a^3 a1,a2,a3分别于矩阵相乘得到 k 1 , k 2 , k 3 k^1,k^2,k^3 k1,k2,k3。
- 将 q q q与 k 1 , k 2 , k 3 k^1,k^2,k^3 k1,k2,k3相乘和softmax得到 α 1 ′ , α 2 ′ , α 3 ′ \alpha'_1,\alpha'_2,\alpha'_3 α1′,α2′,α3′。
- α 1 ′ , α 2 ′ , α 3 ′ \alpha'_1,\alpha'_2,\alpha'_3 α1′,α2′,α3′与 v 1 , v 2 , v 3 v^1,v^2,v^3 v1,v2,v3得到 v v v
- v v v将丢到Feed Forward进行处理
所以在cross attention中, q q q来自decoder, k , v k,v k,v来自encoder

对下一个的处理是一样的
3.3.4 Stop Token
Decoder必须自己决定输出的长度,那怎么停止输出呢?
所以需要一个特殊的符号“END”
在这里插入图片描述
我们期望当把习作为输入的时候,Decoder能够产生“END”,如下图:
3.4 Linear and Softmax Layer
线性层本质上是一个简单的前馈全连接神经网络,它负责将解码器堆栈产生的稠密向量投影到一个维度极大扩展的向量空间中,该向量被称为对数几率向量。
假设我们的模型从训练数据集中学习到了 10,000 个不重复的英文单词(即构成我们模型的“输出词表 ”)。这将使得 logits 向量的维度达到 10,000 维——向量中的每一个单元格都对应着词表中一个特定单词的原始评估得分。这就是我们对模型经过线性层处理后所得输出的物理意义解释。
随后,Softmax 层会将这些原始得分转化为概率分布(所有概率值均为正数,且总和严格为 1.0)。具有最高概率值的单元格将被选中(即 Argmax 操作),与其相关联的单词便作为当前时间步的最终预测结果进行输出。
四.Transformer总体概览
如果你对上述在实际中的使用还有疑惑,没关系,看下述内容。
4.1 为什么需要Transformer
之前我们讲的是为什么需要self-attention
- 自注意力机制正是 Transformer 用来将对其他相关单词的“理解”融入到当前正在处理的单词中的方法。
现在我们要知道为什么需要Transformer
- 与循环神经网络比较
- 串行计算的限制:在Transformer之前,解决序列建模和序列转换问题使用的是RNN,LSTM,GRU。这些循环模型它们生成一系列隐藏状态 h t h_t ht,其中每个状态由前一个隐藏状态 h t − 1 h_{t-1} ht−1和当前位置 t t t的输入共同决定。那这种固有的顺序性使得在单个训练样本内部难以实现并行计算。因此需要Transformer,它摒弃循环结构的模型架构,完全依赖注意力机制来捕捉输入和输出之间的全局依赖关系。Transformer 在训练是实现显著更高程度的并行化。(注意是训练)
- 长距离依赖建模困难(梯度消失/爆炸):随着序列长度的增加,RNN在捕捉远距离元素间依赖关系时效果不佳,训练过程也变得不稳定。尽管LSTM和GRU在一定程度上缓解了这个问题,但仍然存在长距离依赖建模的瓶颈。
- 与卷积神经网络比较:
- 局部感受野的局限:CNN通过滑动卷积核提取局部特征,要建模长距离依赖关系,通常需要堆叠非常深的网络层,这不仅显著增加了模型参数量,也大大提升了计算复杂度。
4.2 训练
在训练的时候会给Decoder看正确答案,也就是“Teacher Forcing:using the ground truth as input”
4.3 测试
以下图为例:
- 输入:“I like to eat apple”
- 输出:“我爱吃苹果”

整体流程如下:
- "I like to eat apple"作为输入提供给编码器,假设整个输入为 ( x 1 , . . . , x n ) (x_1, ..., x_n) (x1,...,xn)
- 编码器经过处理以后产生与输入等长的向量,假设编码器输出为 z = ( z 1 , . . . , z n ) z = (z_1, ..., z_n) z=(z1,...,zn)
-------------------------------------------------------------------------------- 解码器的输入最开始就是一个begin的符号
- 解码器通过Masked Multi-Head-Attention不允许看后面的信息,因为在测试场景中后面是没有内容的。这允许解码器中的每一个位置关注解码器中截至当前(包含当前)的位置。为了保持自回归特性,我们需要防止信息从右向左流动(即不能看到未来位置)。通过Masked Multi-Head-Attention产生了一个向量,假设这个向量为 c i c_i ci
- 这个时候会使用解码器产生的向量 c i c_i ci和编码器产生的 z = ( z 1 , . . . , z n ) z = (z_1, ..., z_n) z=(z1,...,zn)产生输出 y i y_i yi。这使得解码器中的每一个位置都可以关注输入序列中的所有位置。
-------------------------------------------------------------------------------- 此时,上面的输出 y i y_i yi又会作为解码器输入去预测下一个输出

更多推荐


所有评论(0)