type
status
date
slug
summary
tags
category
icon
password
😀
温故而知新,这篇文章希望再次系统梳理一下transformer的结构,同时也做个记录防止自己忘记了其中的一些思考和细节。
注:本文参考图重度参考:https://jalammar.github.io/illustrated-transformer/

📝 从公式出发

我们都知道,Transformer中有一个极基础极重要的概念——attention,同时有一个见过很多次的注意力机制计算公式:
那么这个公式到底是什么意思呢?这一行小小的公式是如何支撑起Transformer甚至后面的自回归LLM这样的庞然大物的呢?

👣Encoder-Decoder

notion image
上图展示的是一个以机器翻译为例的Transformer架构,如你所见,这个架构中分别有六个Encoder和Decoder。
每一个encoder和decoder的内部简版结构如下图:
notion image
encoder包含两层,一个self-attention层和一个前馈神经网络,self-attention能帮助当前节点不仅仅只关注当前的词,从而能获取到上下文的语义。
decoder也包含encoder提到的两层网络,但是在这两层中间还有一层Encoder-Decoder
attention层,这一层是为了保证目标句子(Decoder)在生成每个词时,都能动态地去关注源句子(Encoder)的哪些部分最相关。

基础解释一、为什么self attention能计算到相关性得分?

假设输入是一个序列
每个 是一个 token 的 embedding。
用三个线性变换得到:
其中
现在我们知道Q,K,V是怎么来的了,那让我们回到attention的公式:
用Q和K做内积,为什么就能衡量相关性分数?
notion image
我们知道,在几何空间中,内积的公式可以写作:
那么当两个向量方向接近(夹角小,大)时,点积大 ⇒ 表示语义上相似、相关性高。
步骤
数学公式
语义
1. 线性变换
将输入映射到查询、键、值空间
2. 相似度计算
计算每个词与其他词的相似度
3. 权重归一化
转成概率(相关性权重)
4. 信息聚合
用相关性加权聚合上下文信息
形象地讲,attention是这样的过程:
notion image
如果我们为了提高计算速度采用矩阵运算的方式,那么attention机制就可以表示为:
notion image

🧠MHA

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

基础解释二、MHA中如何实现不同的头关注的注意力各不相同的?

MHA 最终的输出:
会传递到后续层(比如 Feed Forward 或分类头),最后形成一个全局 loss(例如语言建模的交叉熵)。这个 loss 是共享的,不会单独分给每个头。
但是在BP过程中,
注意:
  • 每个头的参数 只影响自己那一支的输出;
  • 所以虽然损失函数是同一个,但是每个头接收到的梯度方向不同,因为它们的中间激活()不同。
这意味着:
所有头共享优化目标,但由于输入的特征映射不同,各自学习到的梯度更新方向也不同。
由于各个 从不同的随机点初始化,这在高维非凸空间中,它们几乎不可能收敛到同一个功能;因此MHA达成了不同的头关注的注意力各不相同的效果

🙋位置编码

到目前为止,transformer模型中还缺少一种解释输入序列中单词顺序的方法。为了处理这个问题,transformer给encoder层和decoder层的输入添加了一个额外的向量Positional Encoding,维度和embedding的维度一样,这个向量采用了一种很独特的方法来让模型学习到这个值,这个向量能决定当前词的位置,或者说在一个句子中不同的词之间的距离。这个位置向量的具体计算方法有很多种,论文中的计算方法如下
其中pos是指当前词在句子中的位置,i是指向量中每个值的index,可以看出,在偶数位置,使用正弦编码,在奇数位置,使用余弦编码。
最后把这个Positional Encoding与embedding的值相加,作为输入送到下一层。
notion image

🥱LN层

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

🤖Transformer

好了,到这一步要请出一位大家都见过的图了:
notion image

基础解释三、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:
  1. Sequence Mask(未来位置遮挡)
  1. 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 的输出),但它们会通过各自的线性层得到不同的投影空间。