type
status
date
slug
summary
tags
category
icon
password
温故而知新,这篇文章希望再次系统梳理一下transformer的结构,同时也做个记录防止自己忘记了其中的一些思考和细节。
📝 从公式出发
我们都知道,Transformer中有一个极基础极重要的概念——attention,同时有一个见过很多次的注意力机制计算公式:
那么这个公式到底是什么意思呢?这一行小小的公式是如何支撑起Transformer甚至后面的自回归LLM这样的庞然大物的呢?
👣Encoder-Decoder

上图展示的是一个以机器翻译为例的Transformer架构,如你所见,这个架构中分别有六个Encoder和Decoder。
每一个encoder和decoder的内部简版结构如下图:

encoder包含两层,一个self-attention层和一个前馈神经网络,self-attention能帮助当前节点不仅仅只关注当前的词,从而能获取到上下文的语义。
decoder也包含encoder提到的两层网络,但是在这两层中间还有一层Encoder-Decoder
attention层,这一层是为了保证目标句子(Decoder)在生成每个词时,都能动态地去关注源句子(Encoder)的哪些部分最相关。
基础解释一、为什么self attention能计算到相关性得分?
假设输入是一个序列
每个 是一个 token 的 embedding。
用三个线性变换得到:
其中
现在我们知道Q,K,V是怎么来的了,那让我们回到attention的公式:
用Q和K做内积,为什么就能衡量相关性分数?

我们知道,在几何空间中,内积的公式可以写作:
那么当两个向量方向接近(夹角小,大)时,点积大 ⇒ 表示语义上相似、相关性高。
步骤 | 数学公式 | 语义 |
1. 线性变换 | 将输入映射到查询、键、值空间 | |
2. 相似度计算 | 计算每个词与其他词的相似度 | |
3. 权重归一化 | 转成概率(相关性权重) | |
4. 信息聚合 | 用相关性加权聚合上下文信息 |
形象地讲,attention是这样的过程:

如果我们为了提高计算速度采用矩阵运算的方式,那么attention机制就可以表示为:

🧠MHA
为什么我们需要MHA?
我们刚刚讲到的单头注意力其实有两个主要限制:
- 只在一个“视角”上看相似性
- 例如,如果我们只用一个头,“吃”可能只学会关注“鱼”这种语义对象;
- 但语言中的依赖关系是多样的:有语法关系(主谓、宾语)、语义关系(主题、情感)、位置关系等;
- 单一空间很难同时表达所有这些关系。
- 信息容量受限
- Q,K,V的维度固定为
- 所以每次注意力只能捕捉一种加权模式;
- 如果想同时捕捉多种依赖关系,就会信息“拥挤”。
该机制理解起来很简单,就是说不仅仅只初始化一组Q、K、V的矩阵,而是初始化多组,tranformer是使用了8组,所以最后得到的结果是8个矩阵。


但是FFN没法输入8个矩阵该怎么办呢?答案是concat:

整体上来说,MHA的流程是这样的:

基础解释二、MHA中如何实现不同的头关注的注意力各不相同的?
MHA 最终的输出:
会传递到后续层(比如 Feed Forward 或分类头),最后形成一个全局 loss(例如语言建模的交叉熵)。这个 loss 是共享的,不会单独分给每个头。
但是在BP过程中,
注意:
- 每个头的参数 只影响自己那一支的输出;
- 所以虽然损失函数是同一个,但是每个头接收到的梯度方向不同,因为它们的中间激活()不同。
这意味着:
所有头共享优化目标,但由于输入的特征映射不同,各自学习到的梯度更新方向也不同。
由于各个 从不同的随机点初始化,这在高维非凸空间中,它们几乎不可能收敛到同一个功能;因此MHA达成了不同的头关注的注意力各不相同的效果
🙋位置编码
到目前为止,transformer模型中还缺少一种解释输入序列中单词顺序的方法。为了处理这个问题,transformer给encoder层和decoder层的输入添加了一个额外的向量Positional Encoding,维度和embedding的维度一样,这个向量采用了一种很独特的方法来让模型学习到这个值,这个向量能决定当前词的位置,或者说在一个句子中不同的词之间的距离。这个位置向量的具体计算方法有很多种,论文中的计算方法如下
其中pos是指当前词在句子中的位置,i是指向量中每个值的index,可以看出,在偶数位置,使用正弦编码,在奇数位置,使用余弦编码。
最后把这个Positional Encoding与embedding的值相加,作为输入送到下一层。

🥱LN层

残差的公式:
作用:
- 保留原始输入信息;
- 防止模型在深层堆叠时梯度消失;
- 让每一层更容易学习“相对变化”而非绝对值。
换句话说:
每层只需要学习“在原有表示上修正多少”,而不是“重新建造一个表示”。
这使得训练更稳定、更快收敛。
🤖Transformer
好了,到这一步要请出一位大家都见过的图了:

基础解释三、Decoder 第一层的输入(“Output”)是什么?
Decoder 的输入并不是模型生成的最终输出,而是 目标序列的前缀(shifted right tokens)。
例如在训练机器翻译时:
目标句子:
y = [BOS, 我, 喜欢, 鱼, EOS]
Decoder 输入:
[BOS, 我, 喜欢, 鱼] (右移一位)
模型需要预测:
[我, 喜欢, 鱼, EOS]
在 Decoder 第一个子层(Masked Self-Attention)中:
- 输入 是“目标句子已生成的部分”(即 Output Embedding)
- 输出 是“预测下一个词的上下文表征”
基础解释四、Masked Multi-Head Attention 的目的
核心目标:
在自回归生成中,防止模型在预测第 t 个 token 时“偷看”未来的 token。
即:
- 当模型在预测 “喜欢” 时,只能看到 “[BOS, 我]”,
不能看到 “鱼”、“EOS”。
否则模型会泄漏未来信息,训练时和推理时行为不一致。
实际上,Decoder 的 Masked MHA 同时使用了两种 mask:
- Sequence Mask(未来位置遮挡)
- Padding Mask(填充位置遮挡)
这两个 mask 通常会在实现中相加或相乘融合。具体而言:
1.sequence mask:
目标:防止“看到未来”
矩阵形状:
[seq_len, seq_len]上三角部分被置为
-inf(或 0-mask)。示例(假设序列长度 4):
softmax 之后,被 -inf 的位置概率变为 0。这样当计算第3个词的注意力时,只能看到第1、2个词。
2.padding mask:
目标:防止模型关注输入中 “<PAD>” 的位置。
- 序列长度往往被 padding 到固定长度;
- PAD 位置没有有效语义,不应影响注意力。
矩阵形状:
[batch_size, 1, 1, seq_len]在这些位置上也加上
-inf(在 softmax 前)。基础解释五、如何理解Encoder-Decoder Attention
符号 | 来源 | 含义 |
Q (Query) | Decoder 上一层的输出(例如 Masked MHA + Add&Norm 的结果) | “我现在正在生成的目标部分,希望去关注源句子的哪些信息” |
K (Key) | Encoder 最后一层输出 | “源句子中每个 token 的语义特征键” |
V (Value) | Encoder 最后一层输出 | “源句子中每个 token 的语义内容值” |
K 和 V 通常来自同一个张量(即 Encoder 的输出),但它们会通过各自的线性层得到不同的投影空间。