想要理解VLA/LLM/Agent肯定是离不开这篇伟大的论文的;

更加离不开的就是decoder部分,几乎所有的现代大模型都是decoder演变而来;

网络上对于transformer的科普一言难尽,还有很多用文字代替向量流动忽略shape变换的事情,

此外,训练阶段与推理阶段的数据传输与变化也很重要;

不仅如此,还需要串联传统的oss反向更新参数与kv cache,以及后续的teacher-forcing、我们说的LN部分

我知道会有点难,大家一起耐心看完吧

从零理解 Transformer:从 Encoder、Decoder 到 QKV、Mask、反向传播与 KV Cache

——基于《Attention Is All You Need》的完整数据流、数学推导与 Tensor Shape 分析

0. 为什么要重新理解 Transformer?

2017 年,Ashish Vaswani 等人在论文 Attention Is All You Need 中提出了 Transformer 架构。

这篇论文最重要的贡献之一,是使用注意力机制构建序列建模网络,不再依赖此前常见的循环神经网络结构进行逐位置的信息传递,并展示了它在机器翻译任务上的性能和并行计算优势。

从今天的 LLM 到部分 VLA 模型,Transformer 及其变体已经成为非常重要的基础组件。

不过,需要先纠正几个术语:

  • Decoder 才是解码器的英文名称,不是 Decode。Decode 通常表示解码操作。

  • Loss 是损失函数,不是 OSS。

  • Teacher Forcing 并非 Transformer 出现之后才发明的方法。它早已用于循环神经网络和序列建模。Transformer 利用右移目标序列与因果 Mask,使这类训练能够在目标位置上并行计算。

  • 并不是所有现代大模型都属于 Decoder-only。GPT 类自回归语言模型主要采用 Decoder-only 路线,而 BERT、ViT、T5 以及不同 VLA 系统还存在 Encoder-only、Encoder–Decoder 和混合架构。

本文先严格研究原始 Encoder–Decoder Transformer。等弄懂以后,再解释 GPT 为什么通常只有 Decoder,以及这些机制如何用于 VLA。

我们始终坚持四个原则:

  1. 文字不直接进入 Attention,真正进入计算的是数值向量。

  2. 讲清每个矩阵从哪里来、传到哪里去。

  3. 每次矩阵乘法都标注 Shape。

  4. 训练与推理分别讲解,不在一个计算步骤里来回切换。

一、阅读 Transformer 之前,先建立五个基本概念

1.1 Token、Token ID、Embedding、隐藏向量不是一回事

以一句英文为例:

I love you.

为了方便理解,假设 Tokenizer 将它拆分为:

\[ [\text{I},\text{love},\text{you}] \]

注意,真实 Tokenizer 不一定按单词切分,可能使用子词或其他切分方式。

假设词表中对应的编号为:

\[ [101,205,309] \]

这三个整数叫做 Token ID。

接下来,Embedding 层通过可训练的嵌入矩阵,将每个 Token ID 映射为一个连续向量。

例如:

\[ E= \begin{bmatrix} 0.2&0.8&0.1&0.5\\ 0.7&0.3&0.9&0.2\\ 0.4&0.6&0.2&0.8 \end{bmatrix} \]

这个矩阵有 3 行、4 列。

  • 3 行表示 3 个 Token。

  • 4 列表示每个 Token 有 4 个特征维度。

所以:

\[ \operatorname{Shape}(E)=[3,4] \]

这些数字并不需要分别对应人类语言中的“主语”“动作”“名词”等含义。它们是模型可以通过训练调整和使用的特征。

当这些向量经过 Self-Attention、FFN 等模块后,会形成包含上下文信息的隐藏向量。

因此,必须区分:

概念

含义

示例

原始文字

人类阅读的信息

love

Token

Tokenizer 切分得到的单位

love

Token ID

词表中的整数编号

205

Embedding

Token ID 对应的连续向量

[0.7, 0.3, 0.9, 0.2]

Hidden State

网络某层产生的隐藏表示

[0.4, 0.1, 0.8, 0.6]

Logits

对词表候选 Token 的未归一化预测分数

[1.2, 0.5, -0.3, …]

后续所有 Attention 运算,本质上都在处理向量或矩阵,而不是字符串。

1.2 Shape 到底是什么意思?

Shape 表示一个 Tensor(张量)在各维度上的大小。

例如:

\[ X\in\mathbb R^{3\times4} \]

表示 X 是一个 3 行 4 列的矩阵。

如果一次处理多句话,就需要加入 Batch 维度。

例如:

\[ X\in\mathbb R^{2\times3\times4} \]

可以理解为:

  • 一次处理 2 条样本;

  • 每条样本有 3 个 Token;

  • 每个 Token 有 4 个特征。

Transformer 的多头注意力还会引入 Head 维度。

因此,真实模型里经常出现四维 Tensor:

\[ [B,H,T,d_k] \]

这些符号如果不统一,后面讲 QKV 和 KV Cache 就很容易混乱。

1.3 全文统一使用的维度符号

符号

含义

\(B\)

Batch Size,一批样本的数量

\(S\)

Encoder 输入序列长度

\(T\)

Decoder 输入序列长度

\(d_{\mathrm{model}}\)

Transformer 主隐藏向量维度

\(H\)

Attention Head 数量

\(d_k\)

每个 Head 的 Query、Key 维度

\(d_v\)

每个 Head 的 Value 维度

\(d_{\mathrm{ff}}\)

FFN 中间层维度

\(V_{\mathrm{ocab}}\)

Token 词表大小

\(N\)

Encoder 或 Decoder 的堆叠层数

下面为了演示矩阵变化,统一设定:

\[ \boxed{ B=2,\quad S=3,\quad T=4 } \]

\[ \boxed{ d_{\mathrm{model}}=8,\quad H=2 } \]

\[ \boxed{ d_k=d_v=4,\quad d_{\mathrm{ff}}=16 } \]

词表大小暂时假设:

\[ V_{\mathrm{ocab}}=100 \]

这些数字只是为了方便教学。

原始 Transformer Base 则使用:

\[ d_{\mathrm{model}}=512,\quad H=8 \]

\[ d_k=d_v=64,\quad d_{\mathrm{ff}}=2048 \]

Encoder 和 Decoder 分别堆叠 6 层。

1.4 Transformer 的参数与计算结果必须区分

这一点非常重要。

例如:

\[ Q=XW_Q \]

这里:

  • \(X\) 是当前输入产生的数据。

  • \(W_Q\) 是可训练的权重参数。

  • \(Q\) 是利用当前数据和权重计算得到的结果。

训练时,主要通过优化器更新 \(W_Q\)。

推理时,通常固定 \(W_Q\),但输入 X 变化后,Q 仍然会变化。

同理,Encoder 输出的上下文矩阵也不是事先训练好、永久不变的矩阵。

准确说法应该是:

Encoder 使用已经学习到的参数,对当前输入执行前向计算,得到包含上下文信息的隐藏表示矩阵。

这个矩阵随后传入 Decoder。

1.5 原始 Transformer 的整体结构

论文中最经典的架构图,左侧是 Encoder,右侧是 Decoder。

原始架构可以整理成两条主线。

Encoder:

输入 Token ID → Embedding → 位置编码 → Multi-Head Self-Attention → Add & Norm → FFN → Add & Norm → 重复 N 层 → Encoder 输出矩阵。

Decoder:

目标端 Token ID → Embedding → 位置编码 → Masked Multi-Head Self-Attention → Add & Norm → Cross-Attention → Add & Norm → FFN → Add & Norm → 重复 N 层 → Linear → Softmax → Token 概率。

其中,Encoder 的输出进入 Decoder 的 Cross-Attention。

这里有三个特别容易看错的地方:

第一,Decoder 不是直接使用 Encoder 输出的向量代替自己的输入,而是同时处理目标端已有信息和Encoder 提供的源端信息。

第二,原始 Decoder 的子层顺序是:

\[ \boxed{ \text{Masked Self-Attention} \rightarrow \text{Cross-Attention} \rightarrow \text{FFN} } \]

不是先 FFN,再 Cross-Attention。

第三,图中的 N× 表示重复堆叠。不同层通常有各自独立的可训练参数,而不是简单地把同一组 QKV 权重使用 N 次。

二、Encoder:把输入文字变成上下文矩阵

2.1 Tokenizer 与 Embedding

还是使用:

I love you.

假设 Encoder 接收到 3 个 Token ID。

在 Batch Size 为 2 的情况下,输入 ID Tensor 的 Shape 为:

\[ X_{\mathrm{id}}:[2,3] \]

经过 Embedding:

\[ E_E:[2,3,8] \]

这里每个 Token 已经从一个整数 ID 变成 8 维向量。

但是仅靠 Embedding,网络还不能充分利用不同 Token 在序列中的位置信息。

所以还需要位置编码。

2.2 Positional Encoding:位置信息从哪里来?

原始 Transformer 使用正弦、余弦位置编码。

对于位置 pos 和特征维度索引 i:

\[ PE(pos,2i)= \sin\left( \frac{pos}{10000^{2i/d_{\mathrm{model}}}} \right) \]

\[ PE(pos,2i+1)= \cos\left( \frac{pos}{10000^{2i/d_{\mathrm{model}}}} \right) \]

其中:

  • pos 是 Token 在序列中的位置。

  • i 控制对应的维度与频率。

  • \(d_{\mathrm{model}}\) 是隐藏向量维度。

位置编码矩阵与 Embedding 有相同的特征维度。

于是:

\[ X_E=E_E+PE_E \]

Shape 保持不变:

\[ \boxed{X_E:[2,3,8]} \]

这里需要注意,加上位置编码并不是简单地在向量末尾拼接一个位置编号,而是按照对应特征维度进行逐元素相加。

原始论文的 Embedding 还包含 \(\sqrt{d_{\mathrm{model}}}\) 缩放,随后与位置编码相加。

2.3 Encoder Self-Attention:QKV 从哪里来?

假设当前某个 Encoder 层的输入是:

\[ X_E:[2,3,8] \]

它要分别计算:

\[ Q=X_EW_Q \]

\[ K=X_EW_K \]

\[ V=X_EW_V \]

注意,这里全部来自同一个 Encoder 输入表示。

所以叫 Self-Attention(自注意力)。

采用两个 Head,每个 Head 4 维时,经过线性投影及 Head 维度拆分:

\[ Q:[2,2,3,4] \]

\[ K:[2,2,3,4] \]

\[ V:[2,2,3,4] \]

顺序分别是:

\[ [B,H,S,d_k] \]

其中 Q 和 K 的最后一维必须匹配,才能计算点积;V 的特征维度可以独立设定。

为什么还要 Q、K、V 三套矩阵?

因为模型需要分别学习三件事情:

  • Q:当前这个位置要寻找什么类型的信息。

  • K:每个位置向其他查询提供什么匹配特征。

  • V:每个位置在被关注时实际贡献什么向量信息。

Q 和 K 负责计算匹配分数;V 负责被加权汇总。

Q 不是直接查询 V。

计算流程严格是:

\[ QK^T \rightarrow \text{Softmax} \rightarrow \text{Attention Weights} \rightarrow AV \]

2.4 Attention 的公式究竟怎么推导?

Scaled Dot-Product Attention 的核心公式为:

\[ \boxed{ \operatorname{Attention}(Q,K,V)= \operatorname{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right)V } \]

我们把它拆成四步。

第一步:计算 Q 与 K 的匹配分数

对某个 Query 向量 \(q_i\) 和某个 Key 向量 \(k_j\),使用点积:

\[ s_{ij}=q_i\cdot k_j \]

如果向量为:

\[ q_i=[1,0] \]

\[ k_1=[1,0],\qquad k_2=[0,1] \]

那么:

\[ q_i\cdot k_1=1 \]

\[ q_i\cdot k_2=0 \]

说明当前查询对第一个 Key 的匹配分数更高。

注意,这只是向量空间中的匹配分数,不意味着模型一定“理解”了某个词语的语义。

第二步:为什么要除以 \(\sqrt{d_k}\)?

假设 Q、K 的每个分量相互独立、均值为 0、方差为 1。

点积为:

\[ q\cdot k=\sum_{r=1}^{d_k}q_rk_r \]

在这些简化统计假设下:

\[ \operatorname{Var}(q\cdot k)=d_k \]

也就是说,随着特征维度增加,点积的典型数值尺度会增大。

如果直接将很大的分数送入 Softmax,概率可能过度集中,部分梯度变得很小。

于是将分数缩放:

\[ \boxed{s_{ij}=\frac{q_i\cdot k_j}{\sqrt{d_k}}} \]

使其数值尺度更容易控制。

这也是原论文对缩放因子的主要解释。

第三步:Softmax 转换注意力权重

对于第 i 个 Query:

\[ a_{ij}= \frac{e^{s_{ij}}}{\sum_m e^{s_{im}}} \]

Softmax 让每行注意力权重非负,且总和为 1。

例如:

\[ A_i=[0.2,0.7,0.1] \]

表示当前 Query 对三个可见 Key 的注意力权重分别为 20%、70%、10%。

第四步:对 V 加权求和

假设三个 Value 为:

\[ V_1=[1,0],\quad V_2=[0,2],\quad V_3=[1,1] \]

那么:

\[ O_i=0.2V_1+0.7V_2+0.1V_3 \]

代入:

\[ O_i= 0.2[1,0]+0.7[0,2]+0.1[1,1] \]

最终:

\[ \boxed{O_i=[0.3,1.5]} \]

这是一个新的特征向量,而不是文字 Token。

这也是整个 Transformer 最重要的认识之一:Attention 不是直接输出一个词,而是通过向量匹配与加权汇总,更新当前 Token 位置的隐藏表示。

2.5 Multi-Head Attention 的完整 Shape 变化

回到我们的统一示例:

\[ Q,K,V:[2,2,3,4] \]

计算:

\[ QK^T \]

这里的转置是交换 K 最后的两个维度:

\[ K^T:[2,2,4,3] \]

所以:

\[ QK^T:[2,2,3,3] \]

含义是:

  • Batch = 2;

  • Head = 2;

  • 每个 Head 都生成一个 \(3\times3\) 的注意力分数矩阵。

然后:

\[ A=\operatorname{softmax}(QK^T/\sqrt4) \]

Shape 不变:

\[ A:[2,2,3,3] \]

再与 V 相乘:

\[ [2,2,3,3]\times[2,2,3,4] \]

得到:

\[ O:[2,2,3,4] \]

此时两个 Head 分别产生了输出。

将两个 Head 拼接:

\[ [2,2,3,4] \rightarrow [2,3,8] \]

再经过输出投影矩阵 \(W_O\):

\[ O_{\mathrm{MHA}}=\operatorname{Concat}(O_1,O_2)W_O \]

最终:

\[ \boxed{O_{\mathrm{MHA}}:[2,3,8]} \]

这一步非常关键。

多头拼接后通过输出投影回到 \(d_{\mathrm{model}}\),因此能够与原输入进行残差相加。

整个过程可以汇总为:

操作

Tensor Shape

Encoder 输入 X

[2, 3, 8]

QKV 投影并拆分 Head

[2, 2, 3, 4]

QKᵀ 注意力分数

[2, 2, 3, 3]

Softmax 注意力权重

[2, 2, 3, 3]

Attention × V

[2, 2, 3, 4]

拼接 Head

[2, 3, 8]

输出投影

[2, 3, 8]

实际框架可以采用不同的维度布局,例如先放序列维或先放 Head 维,但数学关系不变。

2.6 Add & Norm 与 FFN

原始 Transformer 的 Encoder 层不是 Attention 之后直接输出,而是使用:

\[ Y=\operatorname{LN}(X+\operatorname{MHA}(X)) \]

其中 LN 是 LayerNorm。

然后进入 FFN:

\[ \operatorname{FFN}(Y) = \operatorname{ReLU}(YW_1+b_1)W_2+b_2 \]

两个线性变换对应的 Shape 是:

\[ [2,3,8] \rightarrow [2,3,16] \rightarrow [2,3,8] \]

因此 FFN 不改变 Token 数量,只对每个位置的特征进行非线性变换。

之后再次 Add & Norm:

\[ Z=\operatorname{LN}(Y+\operatorname{FFN}(Y)) \]

Encoder 会重复这些层,最后输出:

\[ \boxed{H_E:[2,3,8]} \]

这里还有一个重要细节:

Encoder 并不是经过所有层后才第一次拥有上下文信息。每一层 Self-Attention 都可能进一步融合上下文,而最终输出是经过多层变换得到的表示。

到这里,Encoder 的数据流已经完整。

接下来就是我们前面反复讨论、也是整篇文章的核心——Decoder。

三、Decoder:为什么需要两套 QKV?

Encoder 已经产生:

\[ H_E:[2,3,8] \]

现在进入 Decoder。

为了避免混淆,先建立一个绝对重要的概念:

原始 Transformer 的 Decoder 包含两次不同的注意力计算:Masked Self-Attention 和 Cross-Attention。

第一套 QKV 处理 Decoder 自身的目标端信息。

第二套 QKV 则负责让 Decoder 查询 Encoder 输出的信息。

这两套权重矩阵通常相互独立。

3.1 训练时 Decoder 到底输入什么?

假设英文和中文训练样本是:

输入:

I love you.

正确输出:

我爱你。

这里必须引入两个特殊 Token。

<BOS>:Beginning of Sequence,序列起始符。

<EOS>:End of Sequence,序列结束符。

训练目标序列可以表示为:

\[ Y=[\text{我},\text{爱},\text{你},\mathrm{EOS}] \]

但是 Decoder 的输入并不是直接使用这个序列。

而是:

\[ X_D=[\mathrm{BOS},\text{我},\text{爱},\text{你}] \]

我们让输入和预测目标错开一个位置。

Decoder 输入位置

输入 Token

希望预测的 Token

1

BOS

我

2

我

爱

3

爱

你

4

你

EOS

这个设计是理解 Mask 的前提。

BOS 是用于预测第一个目标 Token 的起点,而不是自己变成了第一个目标 Token。

训练时,Decoder 可以一次接收整个右移后的正确目标序列。

经过 Tokenizer、Embedding 和位置编码后:

\[ X_D:[2,4,8] \]

其中 4 表示目标端输入长度。

3.2 第一次注意力:Masked Self-Attention

Decoder 首先处理自己的输入矩阵:

\[ X_D:[2,4,8] \]

计算:

\[ Q_s=X_DW_Q^s \]

\[ K_s=X_DW_K^s \]

\[ V_s=X_DW_V^s \]

拆成 2 个 Head 后:

\[ Q_s,K_s,V_s:[2,2,4,4] \]

这里三个 Tensor 都来自 Decoder,因此属于 Self-Attention。

但是与 Encoder 不同,Decoder 还需要一个因果 Mask。

为什么?

因为训练时正确答案已经出现在 Decoder 的输入序列里。

如果 BOS 的 Query 能够获取后面“我”的 Key、Value,那么 BOS 位置就有可能直接读取它需要预测的正确答案。

这相当于考试时提前拿到了答案。

所以必须限制每个 Query 能访问哪些位置。

3.3 因果 Mask 的数学表达

未添加 Mask 的分数为:

\[ S=\frac{Q_sK_s^T}{\sqrt{d_k}} \]

此时:

\[ S:[2,2,4,4] \]

对一个 Head 来说,分数矩阵是:

\[ S= \begin{bmatrix} s_{11}&s_{12}&s_{13}&s_{14}\\ s_{21}&s_{22}&s_{23}&s_{24}\\ s_{31}&s_{32}&s_{33}&s_{34}\\ s_{41}&s_{42}&s_{43}&s_{44} \end{bmatrix} \]

第一行是 BOS 的 Query 与全部四个 Key 的匹配分数。

但是 BOS 不能查看未来位置。

因此,需要构建:

\[ M= \begin{bmatrix} 0&-\infty&-\infty&-\infty\\ 0&0&-\infty&-\infty\\ 0&0&0&-\infty\\ 0&0&0&0 \end{bmatrix} \]

之后:

\[ S_{\mathrm{masked}}=S+M \]

再进行 Softmax:

\[ A_s=\operatorname{softmax}(S_{\mathrm{masked}}) \]

由于:

\[ e^{-\infty}=0 \]

被屏蔽位置的注意力权重变成 0。

我们最终得到的注意力权重矩阵大致具有以下结构:

\[ A_s= \begin{bmatrix} 1&0&0&0\\ a_{21}&a_{22}&0&0\\ a_{31}&a_{32}&a_{33}&0\\ a_{41}&a_{42}&a_{43}&a_{44} \end{bmatrix} \]

每行权重之和为 1。

这里每个 \(a_{ij}\) 是训练得到的投影参数与当前输入共同决定的,不是人为固定的数字。

最后:

\[ O_s=A_sV_s \]

经过多头拼接、输出投影及 Add & Norm 后:

\[ \boxed{Z_D:[2,4,8]} \]

这是 Decoder 第一子层的输出。

它包含四个位置各自的因果上下文表示,但仍然不是四个预测出来的中文 Token。

3.4 为什么“我”的 Q 可以看“我”的 K、V?

这一点我们之前反复讨论过。

训练输入是:

\[ [\mathrm{BOS},\text{我},\text{爱},\text{你}] \]

但监督目标是:

\[ [\text{我},\text{爱},\text{你},\mathrm{EOS}] \]

因此,“我”位置负责预测的是“爱”,不是“我”。

所以:

\[ q_{\text{我}} \]

可以查询:

\[ k_{\mathrm{BOS}},k_{\text{我}} \]

并加权汇总对应的 Value。

这不会泄露正确答案“爱”。

但是它不能读取后面的“爱”位置,因为那里包含它要预测的正确目标 Token。

因果 Mask 允许当前位置关注自己,原因就在于输入序列相对于预测目标右移了一个位置。

3.5 第二次注意力:Cross-Attention

现在终于轮到 Encoder 输出的信息参与 Decoder 计算。

我们已经拥有:

Encoder 输出:

\[ H_E:[2,3,8] \]

Decoder Masked Self-Attention 后的中间表示:

\[ Z_D:[2,4,8] \]

Cross-Attention 使用:

\[ Q_c=Z_DW_Q^c \]

\[ K_c=H_EW_K^c \]

\[ V_c=H_EW_V^c \]

这里与第一次注意力的根本区别是:

  • Q 来自 Decoder。

  • K、V 来自 Encoder。

这也回答了一个非常容易理解错的问题:

不是 Encoder 把自己内部 Self-Attention 用过的 K、V 原封不动地传给 Decoder。

Encoder 传递的是最终隐藏表示 \(H_E\)。

Decoder 的每个 Cross-Attention 层再利用各自的投影参数,将 \(H_E\) 变换为该层需要的 K、V。

Cross-Attention 的 Shape

Decoder 的 Query:

\[ Q_c:[2,2,4,4] \]

Encoder 提供的 Key:

\[ K_c:[2,2,3,4] \]

Value:

\[ V_c:[2,2,3,4] \]

进行矩阵乘法:

\[ Q_cK_c^T \]

即:

\[ [2,2,4,4]\times[2,2,4,3] \]

得到:

\[ \boxed{S_c:[2,2,4,3]} \]

为什么是 \(4\times3\)?

因为有 4 个 Decoder 查询位置,以及 3 个 Encoder 信息位置。

每个 Decoder 位置都可以分别与三个 Encoder Key 计算匹配分数。

之后:

\[ A_c=\operatorname{softmax} \left(\frac{Q_cK_c^T}{\sqrt{d_k}}\right) \]

再计算:

\[ O_c=A_cV_c \]

其 Shape 为:

\[ [2,2,4,3]\times[2,2,3,4] \]

因此:

\[ O_c:[2,2,4,4] \]

拼接 Head、输出投影后:

\[ \boxed{O_{\mathrm{cross}}:[2,4,8]} \]

Cross-Attention 的输出长度跟随 Query,也就是 Decoder 的序列长度。

这件事情需要特别记住:

Attention 的输出位置数由 Query 的位置数决定,不是由 Key 或 Value 的位置数决定。

为什么 Cross-Attention 不需要相同的因果 Mask?

因为在翻译任务中,完整英文句子从一开始就是已知的。

BOS 虽然不能查看未来的中文“我”,但可以查询整个英文句子的上下文信息。

因此,Cross-Attention 通常允许 Decoder 的每个查询位置读取全部有效的 Encoder 位置。

如果输入有 Padding Token,依然需要相应的 Padding Mask。

3.6 两种 Attention 的数据来源与 Shape 总结

内容

Masked Self-Attention

Cross-Attention

Query 来源

Decoder

Decoder

Key 来源

Decoder

Encoder

Value 来源

Decoder

Encoder

Query Shape

[2, 2, 4, 4]

[2, 2, 4, 4]

Key Shape

[2, 2, 4, 4]

[2, 2, 3, 4]

注意力分数 Shape

[2, 2, 4, 4]

[2, 2, 4, 3]

Value 加权结果

[2, 2, 4, 4]

[2, 2, 4, 4]

是否使用目标端因果 Mask

是

通常否

主要任务

整合已有目标端信息

获取源端上下文信息

理解这张表,基本就不会再把两套 QKV 混淆。

3.7 Cross-Attention 之后还有什么?

原始 Decoder 的一个完整层包含三个子层:

\[ \text{Masked Self-Attention} \]

\[ \downarrow \]

\[ \text{Cross-Attention} \]

\[ \downarrow \]

\[ \text{FFN} \]

每个子层还包含残差连接和 LayerNorm。

其中 FFN 的计算与 Encoder 中类似:

\[ \operatorname{FFN}(X)= \operatorname{ReLU}(XW_1+b_1)W_2+b_2 \]

Shape:

\[ [2,4,8]\rightarrow[2,4,16]\rightarrow[2,4,8] \]

经过一个 Decoder 层,序列长度和模型隐藏维度保持不变。

经过 N 个 Decoder 层之后,最终:

\[ \boxed{H_D:[2,4,8]} \]

这个矩阵才会交给词表输出层。

四、LayerNorm 与 Add:为什么原论文里到处都有 LN?

这也是一个不应该忽略的部分。

很多科普文章只关注 Attention,但实际深层 Transformer 的训练稳定性与残差连接、LayerNorm 密切相关。

4.1 什么是残差连接?

假设某个子层输入为 X,经过 Attention 得到:

\[ F(X) \]

如果直接使用:

\[ Y=F(X) \]

原输入需要完全通过这一子层变换后才能进入下一层。

残差连接则将原输入加回:

\[ \boxed{Y=X+F(X)} \]

例如:

\[ X=[1,2] \]

\[ F(X)=[0.2,0.5] \]

那么:

\[ Y=[1.2,2.5] \]

这样既能保留原有信息,又为反向传播提供更直接的梯度通路。

但这不表示残差连接能彻底解决所有梯度问题。

4.2 LayerNorm 究竟归一化什么?

假设某个 Token 的隐藏向量为:

\[ x=[1,2,3,4] \]

LayerNorm 通常沿着这个 Token 的特征维度计算均值与方差。

均值:

\[ \mu=\frac1d\sum_{i=1}^{d}x_i \]

方差:

\[ \sigma^2=\frac1d\sum_{i=1}^{d}(x_i-\mu)^2 \]

对每个特征进行归一化:

\[ \hat{x}_i= \frac{x_i-\mu}{\sqrt{\sigma^2+\epsilon}} \]

最后加入可训练缩放和平移参数:

\[ \boxed{ y_i=\gamma_i\hat{x}_i+\beta_i } \]

其中:

  • \(\gamma_i\):可训练缩放参数。

  • \(\beta_i\):可训练偏置参数。

  • \(\epsilon\):防止分母为零的小常数。

LayerNorm 不是把所有 Token、所有 Batch 的数值混在一起求一个平均值。

在常见 Transformer 中,它主要对每个 Token 隐藏向量的最后一个特征维度归一化。

假设:

\[ X:[2,4,8] \]

LayerNorm 对各个位置的 8 维特征分别进行归一化,输出 Shape 仍然为:

\[ [2,4,8] \]

4.3 Post-LN 和 Pre-LN 的区别

原始 Transformer 采用的是常说的 Post-LN 结构:

\[ \boxed{ Y=\operatorname{LN}(X+F(X)) } \]

即:

子层计算 → 残差相加 → LayerNorm。

而很多后来的 Transformer 变体采用 Pre-LN:

\[ \boxed{ Y=X+F(\operatorname{LN}(X)) } \]

也就是:

先进行 LayerNorm → 子层计算 → 残差相加。

二者并不只是绘图位置不同。

LayerNorm 的位置会改变前向计算及反向梯度的传播路径,从而影响深层网络的优化特性。

因此,在阅读 PyTorch 源码或现代 LLM 论文时,不能仅凭原始 Transformer 图判断实际的 LayerNorm 顺序。

此外,原始论文还有 Dropout 等训练设计。严格按照论文的子层写法,应理解为子层输出经过相应 Dropout 后,与残差相加,再进行 LayerNorm。

五、训练阶段:Decoder 的向量怎么变成文字预测?

现在 Encoder、Decoder 的前向计算已经讲完。

我们得到:

\[ H_D:[2,4,8] \]

这里有:

  • 2 条样本。

  • 每条样本 4 个目标位置。

  • 每个位置一个 8 维隐藏向量。

接下来需要预测 Token。

5.1 Output Projection:隐藏向量映射到词表

设词表大小为 \(V_{\mathrm{vocab}}=100\)。

模型使用一个输出投影矩阵:

\[ W_{\mathrm{out}}\in\mathbb R^{8\times100} \]

计算:

\[ L=H_DW_{\mathrm{out}}+b \]

Shape:

\[ [2,4,8]\times[8,100] \]

得到:

\[ \boxed{L:[2,4,100]} \]

这里的 L 是 Logits,而不是 Loss。

这表示:每条样本的每个 Decoder 位置,都会生成 100 个候选 Token 的分数。

原始 Transformer 使用 Linear 和 Softmax,将 Decoder 输出转换成词表概率;论文中还采用了 Embedding 和输出投影之间的权重共享设计,但这种共享并非所有现代模型都必须采用。

5.2 Logits 为什么不是概率?

假设我们单独取“我”位置的预测结果。

为了方便手算,暂时把词表缩小到三个候选:

\[ [\text{我},\text{爱},\text{你}] \]

假设输出:

\[ L=[1,2,0] \]

这是三个 Logit。

它们可以是任意实数,并不要求和为 1。

通过 Softmax:

\[ p_i=\frac{e^{l_i}}{\sum_j e^{l_j}} \]

得到:

\[ P(\text{我})\approx0.245 \]

\[ P(\text{爱})\approx0.665 \]

\[ P(\text{你})\approx0.090 \]

概率总和为 1。

如果当前采用贪心解码,就可以选取分数最高的“爱”。

但是现在我们讨论的是训练阶段。

因此,接下来不需要先选择一个 Token 再送回 Decoder。

训练时要根据整个预测分布和正确答案计算损失。

5.3 Teacher Forcing:为什么训练时不用等待模型生成?

训练目标:

\[ [\text{我},\text{爱},\text{你},\mathrm{EOS}] \]

Decoder 输入:

\[ [\mathrm{BOS},\text{我},\text{爱},\text{你}] \]

我们已经知道全部正确答案。

所以训练时,模型即使在 BOS 位置错误地预测了“你”,下一个位置仍然可以直接使用训练数据中正确的“我”。

这就是 Teacher Forcing 的基本思想:

训练时使用真实的历史目标 Token,而不是每次使用模型自己生成的 Token 继续训练。

这种设计使得所有目标位置可以在同一次前向传播中并行计算。

当然,必须配合因果 Mask,防止每个位置读取自己的未来正确答案。

这里还需要澄清一个历史问题:Teacher Forcing 在 Transformer 出现之前就已经存在,不是后来才由 Transformer 发明的技术。

5.4 Cross-Entropy Loss 怎么计算?

假设我们正在预测“爱”。

模型输出:

\[ P(\text{爱})=0.665 \]

正确标签就是“爱”。

标准单 Token 交叉熵损失:

\[ \mathcal L=-\log P(\text{正确Token}) \]

因此:

\[ \mathcal L=-\log(0.665)\approx0.408 \]

如果正确答案概率更高,Loss 通常更小。

现在推导一下梯度。

设三个 Logits 为:

\[ z=[z_1,z_2,z_3] \]

Softmax:

\[ p_i=\frac{e^{z_i}}{\sum_j e^{z_j}} \]

真实标签是类别 y。

交叉熵:

\[ \mathcal L=-\log p_y \]

代入:

\[ \mathcal L= -\log \left( \frac{e^{z_y}}{\sum_j e^{z_j}} \right) \]

根据对数运算:

\[ \boxed{ \mathcal L=-z_y+\log\sum_j e^{z_j} } \]

对任意 Logit \(z_i\) 求导:

\[ \frac{\partial\mathcal L}{\partial z_i} = \frac{e^{z_i}}{\sum_j e^{z_j}} -\mathbb 1(i=y) \]

因此:

\[ \boxed{ \frac{\partial\mathcal L}{\partial z_i} = p_i-y_i } \]

其中 \(y_i\) 是 One-Hot 标签中的对应值。

这就是 Softmax 与交叉熵组合后非常重要的梯度公式。

5.5 为什么训练时要计算所有位置的 Loss?

因为每个位置都对应一个预测任务。

例如:

输入位置

正确预测目标

位置损失

BOS

我

\(\mathcal L_1\)

我

爱

\(\mathcal L_2\)

爱

你

\(\mathcal L_3\)

你

EOS

\(\mathcal L_4\)

标准训练通常将有效位置的 Loss 汇总、求平均:

\[ \boxed{ \mathcal L_{\mathrm{total}} = -\frac{1}{N_{\mathrm{valid}}} \sum_{t\in\mathrm{valid}}\log p_t(y_t) } \]

其中 \(N_{\mathrm{valid}}\) 是有效监督 Token 数量。

如果 Batch 内有 Padding,一般需要避免将 Padding 位置计入普通目标损失。

另外,原始 Transformer 使用过 Label Smoothing(标签平滑),因此上面的标准 One-Hot 交叉熵公式是为了讲清训练原理,并非完整复刻原论文的全部损失设置。

六、Loss 如何反向传播,更新 QKV 权重?

这是理解模型为什么能够学习的关键。

到目前为止,我们完成的是前向计算:

\[ \text{Token ID} \rightarrow \text{Embedding} \rightarrow \text{Attention} \rightarrow \text{FFN} \rightarrow \text{Logits} \rightarrow \text{Loss} \]

但 Loss 本身不会自动让参数改变。

我们还需要:

  1. 反向传播,计算参数梯度。

  2. 使用优化器,按照梯度更新参数。

6.1 先从输出层反向传播

输出层:

\[ L=H_DW_{\mathrm{out}}+b \]

假设损失对 Logits 的梯度已经得到:

\[ G_L=\frac{\partial\mathcal L}{\partial L} \]

那么:

\[ \boxed{ \frac{\partial\mathcal L}{\partial W_{\mathrm{out}}} = H_D^TG_L } \]

这里为便于书写,省略 Batch 和序列维度的展开操作;实际梯度需要对所有有效位置累加。

同时:

\[ \boxed{ \frac{\partial\mathcal L}{\partial H_D} = G_LW_{\mathrm{out}}^T } \]

这个公式告诉我们:

Loss 不只能够更新输出层权重,也能够继续向 Decoder 内部传递梯度。

然后梯度依次经过 Decoder 的 FFN、LayerNorm、Cross-Attention、Masked Self-Attention 等模块。

6.2 Attention 的梯度怎么传回 Q、K、V?

我们只看一个注意力头。

前向计算:

\[ S=\frac{QK^T}{\sqrt{d_k}}+M \]

\[ A=\operatorname{softmax}(S) \]

\[ O=AV \]

假设从后面的网络已经得到:

\[ G_O=\frac{\partial\mathcal L}{\partial O} \]

那么我们可以先对:

\[ O=AV \]

求导。

对于 Value:

\[ \boxed{ G_V=A^TG_O } \]

对于 Attention Weights:

\[ \boxed{ G_A=G_OV^T } \]

这意味着损失能够同时影响 Value 和注意力权重。

但是注意力权重 A 不是独立参数,它是 Softmax 计算得到的。

因此需要继续反向传播。

对于 Softmax 的某一行:

\[ a_j=\frac{e^{s_j}}{\sum_k e^{s_k}} \]

其梯度可以写成:

\[ \boxed{ G_{S,j} = a_j\left( G_{A,j}-\sum_k a_kG_{A,k} \right) } \]

对于因果 Mask 屏蔽的位置,相应注意力权重和对分数的梯度为零。

接下来:

\[ S=\frac{QK^T}{\sqrt{d_k}}+M \]

因此:

\[ \boxed{ G_Q=\frac{G_SK}{\sqrt{d_k}} } \]

\[ \boxed{ G_K=\frac{G_S^TQ}{\sqrt{d_k}} } \]

终于可以继续传到投影权重。

因为:

\[ Q=XW_Q \]

所以:

\[ \boxed{ \frac{\partial\mathcal L}{\partial W_Q}=X^TG_Q } \]

同样:

\[ \boxed{ \frac{\partial\mathcal L}{\partial W_K}=X^TG_K } \]

\[ \boxed{ \frac{\partial\mathcal L}{\partial W_V}=X^TG_V } \]

这些公式省略了多头拆分和 Batch 维度,但揭示了一个重要事实:

Q、K、V 的权重矩阵全部可以通过最终 Loss 的梯度学习。

其中:

  • \(W_Q,W_K\) 通过改变匹配分数,影响注意力分布。

  • \(W_V\) 通过改变 Value 表示,影响被汇总的信息。

6.3 Cross-Attention 的梯度会不会进入 Encoder?

会。

因为:

\[ K_c=H_EW_K^c \]

\[ V_c=H_EW_V^c \]

Cross-Attention 的输出会影响最终预测结果。

因此,Loss 能够沿着 Cross-Attention 的 K、V 路径反向传到 \(H_E\),再继续传入 Encoder。

所以正常联合训练时:

Decoder 的 Loss 不仅训练 Decoder,也能够训练 Encoder。

不过,如果在某些工程中刻意冻结 Encoder 参数,那么反向传播虽然可能计算到相关中间量,但优化器不会更新被冻结的 Encoder 权重。

6.4 Optimizer 究竟做了什么?

反向传播负责计算梯度,优化器负责更新参数。

最简单的 SGD(随机梯度下降)更新方式是:

\[ \boxed{ W^{(t+1)} = W^{(t)} -\eta\frac{\partial\mathcal L}{\partial W^{(t)}} } \]

其中:

  • \(W^{(t)}\):更新前的权重。

  • \(\eta\):学习率。

  • \(\partial\mathcal L/\partial W^{(t)}\):当前梯度。

例如某个权重:

\[ w=0.5 \]

梯度为:

\[ \frac{\partial\mathcal L}{\partial w}=0.2 \]

学习率:

\[ \eta=0.1 \]

更新:

\[ w_{\mathrm{new}}=0.5-0.1\times0.2 \]

得到:

\[ \boxed{w_{\mathrm{new}}=0.48} \]

这就完成了一次参数更新。

但需要说明,SGD 在这里是用来解释梯度更新原理的。原始 Transformer 论文实际使用 Adam 优化器,并采用学习率 Warmup 等训练策略。

6.5 一次训练迭代的完整流程

注意,这里的 Loss、反向传播、优化器更新,都属于训练阶段。

正常推理不会根据本轮生成结果执行这一套参数更新过程。

七、推理阶段:模型训练完成后,怎么真正生成文字?

现在假设模型已经训练好了。

Encoder、Decoder 的全部可训练参数已经确定。

我们重新输入:

I love you.

这一次没有正确的中文答案供模型直接使用。

模型必须自己逐步生成。

7.1 第一次推理:Decoder 只有 BOS

英文进入 Encoder:

\[ H_E:[1,3,8] \]

这里为了演示单句推理,将 Batch Size 设为 1。

Decoder 首次接收到:

\[ [\mathrm{BOS}] \]

Embedding 与位置信息处理后:

\[ X_D:[1,1,8] \]

经过 Masked Self-Attention:

\[ Q_s,K_s,V_s:[1,2,1,4] \]

对应注意力分数:

\[ Q_sK_s^T:[1,2,1,1] \]

因为只有一个位置,注意力权重只能是 1。

此时虽然 Self-Attention 还没有其他目标 Token 可以关注,但是 Decoder 后续仍然可以通过 Cross-Attention 读取 Encoder 的信息。

在 Cross-Attention 中:

\[ Q_c:[1,2,1,4] \]

\[ K_c,V_c:[1,2,3,4] \]

因此分数矩阵:

\[ Q_cK_c^T:[1,2,1,3] \]

说明当前 BOS 查询可以分别关注三个英文位置。

经过剩余 Decoder 计算:

\[ H_D:[1,1,8] \]

取最后位置,经输出层:

\[ \mathrm{Logits}:[1,100] \]

然后按照解码策略选择 Token。

假设选择:

\[ \mathrm{TokenID}=11 \]

代表:

我

这里必须注意:

模型实际选择的是 Token ID,而不是先生成文字“我”,再重新转换为 Token ID。

文字显示可以由 Tokenizer 的 Decode 操作完成,但模型内部可以直接将 ID 11 用作下一步输入。

7.2 第二次推理:BOS 与“我”一起进入 Decoder

现在已经生成:

\[ [\mathrm{BOS},\text{我}] \]

对应的 ID 假设为:

\[ [1,11] \]

如果暂时不使用 KV Cache,那么可以重新计算整个前缀。

输入:

\[ X_D:[1,2,8] \]

Masked Self-Attention:

\[ Q_s,K_s,V_s:[1,2,2,4] \]

注意力分数:

\[ S_s:[1,2,2,2] \]

使用因果 Mask 后,每个 Head 的可见结构如下:

Query

BOS 的 Key

“我”的 Key

BOS

允许

禁止

我

允许

允许

现在要生成的是“爱”。

所以我们使用最后一个输入位置——“我”对应的最终隐藏向量进行预测。

假设模型选择:

\[ \mathrm{TokenID}=12 \]

也就是“爱”。

生成序列变为:

\[ [1,11,12] \]

7.3 一个非常容易误解的问题:推理时为什么仍然要 Mask?

这里正是我们之前讨论很久的地方。

第一次推理时:

\[ [\mathrm{BOS}] \]

还没有“我”,自然不可能发生 BOS 读取“我”的事情。

第二次推理时:

\[ [\mathrm{BOS},\text{我}] \]

“我”已经生成了。

所以对于当前预测“爱”的任务来说,“我”是合法历史信息。

因此,不能说:

推理时如果 BOS 查询“我”的 K,就必然泄露下一次要预测的“爱”。

这个推论不正确。

那么为什么还要限制 BOS?

因为因果 Transformer 需要保持这样的计算性质:

\[ h_i=f(x_1,x_2,\ldots,x_i) \]

即第 i 个位置的隐藏表示,只依赖当前及之前的位置。

对于同一模型、相同位置和固定参数,加入未来位置后,不应该改变前面位置本来拥有的因果表示。

这保证了训练与推理遵循一致的因果结构。

另外,保持历史位置表示不受后来 Token 影响,也为复用历史 K、V 提供了基础。

如果模型只有一层 Self-Attention,并且仅关注最后位置的输出,重新计算完整已知前缀时,移除 Mask 不一定改变最后一行的结果。

但在多层 Decoder 中,前面位置的变化可能通过后续层传递到最后位置,因此不能把这种特殊情况推广到整个 Transformer。

7.4 为什么推理必须逐 Token,而训练可以并行?

我们先区分两个层级。

第一个层级:生成的时间顺序。

假设要生成:

\[ \text{我}\rightarrow\text{爱}\rightarrow\text{你} \]

模型生成“爱”以前,需要已经得到“我”。

生成“你”以前,需要已经得到“爱”。

因此在标准自回归推理中,输出 Token 之间存在顺序依赖。

第二个层级:一次网络前向计算内部。

即使当前只生成一个 Token,模型内部仍然需要完成大量矩阵乘法。

例如当前最后位置的 Query:

\[ q=[1,1] \]

三个已知 Key:

\[ K= \begin{bmatrix} 1&0\\ 0&1\\ 1&1 \end{bmatrix} \]

计算:

\[ qK^T=[1,1,2] \]

这三个点积可以通过矩阵运算并行处理。

真实模型还存在多个 Head、较大的隐藏维度、FFN 矩阵乘法,以及多个样本的 Batch 计算。

因此:

自回归推理是输出时间步之间串行,不意味着时间步内部的所有矩阵运算都是串行。

7.5 训练与推理的并行区别

内容

训练

推理

是否已知完整目标序列

是

否

是否可以并行计算多个已知位置

是

可以并行处理已知前缀

是否能够一次并行得到所有未知未来 Token

不需要,目标已知

标准自回归生成不能

矩阵乘法能否并行

能

能

多头注意力能否并行

能

能

是否需要逐步追加模型预测结果

标准 Teacher Forcing 不需要

需要

所以 Transformer 的并行能力与自回归生成的串行性并不矛盾。

八、KV Cache:为什么推理时不需要每次重新计算历史 Token?

现在我们进入 Transformer 高效推理的另一个关键机制。

8.1 不使用 KV Cache 会发生什么?

假设生成过程为:

第一次:

\[ [\mathrm{BOS}] \]

第二次:

\[ [\mathrm{BOS},\text{我}] \]

第三次:

\[ [\mathrm{BOS},\text{我},\text{爱}] \]

如果每一步都重新计算完整前缀,那么 BOS 的相关计算会反复执行。

序列越长,重复计算越多。

实际上,历史 Token 的某些结果可以保留下来。

8.2 为什么缓存的是 K、V,而不是 Q?

先看 Attention:

\[ O=\operatorname{softmax} \left( \frac{QK^T}{\sqrt{d_k}} \right)V \]

在当前时刻,我们主要需要最新位置的输出。

例如目前已经存在:

\[ [\mathrm{BOS},\text{我},\text{爱}] \]

当前 Query:

\[ q_{\text{爱}} \]

它需要查询:

\[ K= \begin{bmatrix} k_{\mathrm{BOS}}\\ k_{\text{我}}\\ k_{\text{爱}} \end{bmatrix} \]

然后对:

\[ V= \begin{bmatrix} v_{\mathrm{BOS}}\\ v_{\text{我}}\\ v_{\text{爱}} \end{bmatrix} \]

进行加权汇总。

历史 Q 主要服务于历史位置当时的查询输出。

在标准逐 Token 自回归推理中,我们不需要重新使用 BOS 的 Q 来产生当前新位置的输出。

但是新位置需要历史位置的 K、V。

因此缓存历史 K、V 是合理的。

8.3 带有 KV Cache 的矩阵 Shape

假设当前已经处理了 t 个目标端 Token。

一个 Decoder Self-Attention 层保存:

\[ K_{\mathrm{cache}}:[B,H,t,d_k] \]

\[ V_{\mathrm{cache}}:[B,H,t,d_v] \]

下一轮处理一个新 Token 时:

\[ Q_{\mathrm{new}}:[B,H,1,d_k] \]

新的 K、V 会被加入缓存。

假设加入后缓存长度为 \(t+1\),那么:

\[ K_{\mathrm{all}}:[B,H,t+1,d_k] \]

\[ V_{\mathrm{all}}:[B,H,t+1,d_v] \]

新的注意力分数:

\[ Q_{\mathrm{new}}K_{\mathrm{all}}^T \]

Shape:

\[ \boxed{[B,H,1,t+1]} \]

再乘 Value,得到:

\[ \boxed{O_{\mathrm{new}}:[B,H,1,d_v]} \]

因此,增量推理主要计算当前新位置需要的结果,而不是重新处理所有历史 Query 位置。

需要说明,每个 Decoder 层都会有自己的相关缓存,不是整个模型只保存一份统一的 K、V。

8.4 Encoder 传入的 K、V 能不能缓存?

当然可以。

对于原始 Encoder–Decoder Transformer:

\[ H_E:[B,S,d_{\mathrm{model}}] \]

假设英文输入没有变化,那么 Encoder 输出也不需要每生成一个中文 Token 就重新计算一次。

各 Decoder Cross-Attention 层可以分别计算并缓存自己的:

\[ K_c:[B,H,S,d_k] \]

\[ V_c:[B,H,S,d_v] \]

于是存在两类不同的 KV Cache。

缓存

数据来源

变化方式

Decoder Self-Attention KV Cache

目标端已经处理的 Token

每次生成并处理新 Token,缓存逐步增长

Decoder Cross-Attention KV Cache

Encoder 输出矩阵

当前源输入不变时,可以重复使用

这也是为什么讨论 KV Cache 时,不能把原始 Encoder–Decoder 模型与 GPT 的 Decoder-only 模型完全混为一谈。

GPT 类 Decoder-only 模型通常没有原始结构中的 Encoder–Decoder Cross-Attention,因此主要关注其自注意力缓存。

8.5 KV Cache 和因果 Mask 有什么关系?

如果使用正确的逐 Token 增量推理:

当前 Query 只对应最新位置。

历史 K、V 只包含已经处理的 Token。

因此,未来 Token 的 K、V 根本不在当前可访问的缓存中。

这种情况下,因果约束天然成立,不一定需要显式构造完整的三角 Mask。

但如果一次并行处理多个目标端位置,仍然需要正确处理它们之间的因果可见关系。

这一点在实际框架实现中尤其重要,不能简单认为设置了某个 Mask 参数就一定符合想要的位置对齐方式。

8.6 Prefill 和 Decode 是什么?

现代推理实现中还经常使用两个术语。

Prefill(预填充)

先处理已经确定的输入前缀。

例如 Decoder-only LLM 收到一个 100 Token 的用户问题,可以通过因果注意力并行处理这些已知 Token,建立缓存。

Decode(逐步生成)

在已有缓存基础上,一个 Token 接一个 Token 地生成后续内容。

所以可以概括为:

\[ \boxed{ \text{Prefill:处理已知前缀} } \]

\[ \boxed{ \text{Decode:逐步生成未知后续} } \]

注意,在原始翻译 Transformer 中,Encoder 对源句子的处理与 Decoder 的 Prefill 并不是同一个概念。

KV Cache 的价值是减少历史计算重复,但需要消耗额外显存,并不会让自回归生成完全摆脱时间步之间的依赖。

九、为什么 GPT 只有 Decoder,却没有独立 Encoder?

前面我们一直讲的是原始 Transformer。

但很多现代生成式 LLM 使用 Decoder-only 架构。

这并不意味着它们不理解输入。

区别在于:

Decoder-only 把输入上下文本身放入同一条自回归序列,通过因果 Self-Attention 进行建模。

例如用户输入:

什么是 Transformer?

模型可能接收包括用户问题和相应对话格式标记在内的一串 Token ID。

这些 Token 经过 Embedding,然后进入多个 Decoder-only Transformer 层。

每个位置都可以按照因果规则利用前面的位置。

因此,Decoder-only 模型同样能够形成包含上下文信息的隐藏表示。

它不需要原始翻译 Transformer 中那种独立 Encoder 输出,再通过 Cross-Attention 查询的结构。

简单对比:

架构

常见代表

注意力特征

Encoder-only

BERT

通常使用双向 Self-Attention

Encoder–Decoder

原始 Transformer、T5

Encoder Self-Attention + Decoder Masked Self-Attention + Cross-Attention

Decoder-only

GPT 类基础语言模型

主要使用因果 Self-Attention

所以,你最开始说“现代大模型很多从 Decoder 演变而来”,对于主流自回归生成式 LLM 是一个合理的理解方向,但不能推广为所有 Transformer 模型都只有 Decoder。

十、Transformer 与 VLA、Agent 到底有什么关系?

理解完原始 Transformer,我们就能看出它为什么重要。

10.1 对于 LLM

Decoder-only LLM 的基本生成流程是:

\[ \text{文本Token} \rightarrow \text{Embedding} \rightarrow \text{因果Attention} \rightarrow \text{隐藏向量} \rightarrow \text{Logits} \rightarrow \text{TokenID} \]

通过反复执行上述过程,生成新的文本。

这里最核心的训练机制依然包含:

  • 预测目标;

  • Loss;

  • 反向传播;

  • 参数优化。

而推理阶段可以使用 KV Cache 加速。

10.2 对于 VLA

VLA(Vision-Language-Action)要处理的输入可能不再只有文字。

例如:

抓取桌面上的红色积木。

它可能需要同时利用:

  • 图像特征;

  • 文本指令;

  • 机器人当前状态;

  • 历史动作信息。

模型最终可能输出:

\[ a_t= [\Delta x,\Delta y,\Delta z,\Delta r_x,\Delta r_y,\Delta r_z,g] \]

这里:

  • \(\Delta x,\Delta y,\Delta z\):末端位置变化量。

  • \(\Delta r_x,\Delta r_y,\Delta r_z\):某种姿态增量表示。

  • \(g\):夹爪相关控制量。

这只是一个示意性的动作表示,实际模型可能使用关节动作、末端位姿、动作块或其他格式。

一些 VLA 会把动作离散成 Action Token,通过 Token 预测方式输出。

另一些则可能采用连续动作回归、扩散模型或 Flow Matching 等动作生成方式。

因此,理解 Transformer 的注意力、隐藏向量和训练机制,可以帮助我们理解 VLA 中的信息融合,但不代表所有 VLA 都通过 Softmax 逐字生成机器人动作。

10.3 对于 Agent

Agent 并不是 Transformer 内部的某一个固定子层。

它更像是围绕模型构建的任务执行系统。

例如:

用户提出任务 → 模型分析 → 生成工具调用 → 外部系统执行 → 返回执行结果 → 模型继续处理。

在这个过程中,LLM 可以使用 Transformer 的自回归生成能力输出工具调用内容。

但工具执行、外部状态管理、环境交互及任务调度,还涉及 Transformer 网络以外的软件和系统设计。

因此,不应该把 Agent 直接理解成“多加了一层 Attention 的 Transformer”。

十一、从头到尾再看一次:训练与推理的数据流到底有什么区别?

我们现在将所有环节统一整理。

11.1 训练阶段 Shape 总表

采用前面的统一示例:

\[ B=2,\ S=3,\ T=4,\ d_{\mathrm{model}}=8 \]

\[ H=2,\ d_k=d_v=4,\ V_{\mathrm{vocab}}=100 \]

步骤

输入 Shape

输出 Shape

Encoder Token ID

[2, 3]

[2, 3]

Encoder Embedding + Position

[2, 3]

[2, 3, 8]

Encoder QKV 拆 Head

[2, 3, 8]

各 [2, 2, 3, 4]

Encoder QKᵀ

Q、K

[2, 2, 3, 3]

Encoder Attention 输出

A、V

[2, 2, 3, 4]

Encoder 拼接与输出投影

[2, 2, 3, 4]

[2, 3, 8]

Encoder FFN

[2, 3, 8]

[2, 3, 8]

Encoder 最终输出

—

[2, 3, 8]

Decoder 目标输入 ID

[2, 4]

[2, 4]

Decoder Embedding + Position

[2, 4]

[2, 4, 8]

Decoder Self QKV

[2, 4, 8]

各 [2, 2, 4, 4]

Decoder Masked QKᵀ

Q、K

[2, 2, 4, 4]

Decoder Self-Attention 输出

A、V

[2, 2, 4, 4]

Decoder Self-Attention 投影后

—

[2, 4, 8]

Cross-Attention Q

Decoder

[2, 2, 4, 4]

Cross-Attention K、V

Encoder

各 [2, 2, 3, 4]

Cross-Attention QKᵀ

Q、K

[2, 2, 4, 3]

Cross-Attention 输出

A、V

[2, 2, 4, 4]

Decoder FFN 后

[2, 4, 8]

[2, 4, 8]

Decoder 最终隐藏表示

—

[2, 4, 8]

输出投影 Logits

[2, 4, 8]

[2, 4, 100]

正确标签 ID

—

[2, 4]

Loss 汇总

Logits、Labels

标量

然后:

\[ \text{Loss} \rightarrow \text{Backward} \rightarrow \text{Gradients} \rightarrow \text{Optimizer Step} \]

完成训练迭代。

11.2 推理阶段 Shape 总表

假设 Batch Size = 1,使用 KV Cache。

当前 Decoder 历史缓存长度为 t,再输入一个新 Token。

步骤

Shape

Encoder 输出

[1, 3, 8]

新目标 Token ID

[1, 1]

新 Token Embedding

[1, 1, 8]

当前 Self-Attention Q

[1, 2, 1, 4]

当前 Self-Attention K、V

各 [1, 2, 1, 4]

添加当前 Token 后的 Self-Attention K Cache

[1, 2, t+1, 4]

添加当前 Token 后的 Self-Attention V Cache

[1, 2, t+1, 4]

Self-Attention 分数

[1, 2, 1, t+1]

当前 Self-Attention 输出

[1, 2, 1, 4]

Cross-Attention Q

[1, 2, 1, 4]

Cross-Attention K、V

各 [1, 2, 3, 4]

Cross-Attention 分数

[1, 2, 1, 3]

Decoder 当前最终隐藏表示

[1, 1, 8]

当前词表 Logits

[1, 1, 100]

选择出的下一个 Token ID

[1, 1]

新的 Token ID 会被追加到生成序列中。

下一轮使用这个新 ID 的 Embedding 及对应位置信息,继续计算。

直到生成 EOS 或达到其他停止条件。

十二、最后回答我们学习过程中遇到的十个关键问题

问题

准确结论

1. Encoder 是否直接把自己的 QKV 传给 Decoder?

不是。它传递最终隐藏表示,Decoder 的 Cross-Attention 再生成本层 K、V。

2. Decoder 的 Self-Attention 是否使用 Encoder 的 K、V?

不使用。它使用目标端自己的 Q、K、V。

3. Cross-Attention 还要计算 QKᵀ 吗?

要。核心依然是 QKᵀ → Softmax → 加权 V。

4. 为什么 BOS 不能在训练时看后面的“我”?

因为 BOS 位置负责预测“我”,读取未来目标会泄露正确标签。

5. 为什么“我”的 Q 可以查看“我”的 K?

因为该位置的预测目标是下一个 Token“爱”,不是重新预测“我”。

6. 推理第二次时,“我”已经生成了,还算数据泄露吗?

对预测“爱”来说不算。继续保持因果约束,是为了维持一致的计算依赖和正确的缓存行为。

7. 为什么训练能并行而推理逐 Token?

训练已知目标序列,可以并行计算各位置;标准自回归推理的未来 Token 必须依次生成。

8. Attention 输出的是文字吗?

不是,是新的隐藏向量。文字预测需要后续网络与词表输出层。

9. Loss 怎么训练 QKV?

梯度通过输出层、FFN、Attention 等可微运算回传,再由优化器更新 QKV 权重。

10. KV Cache 为什么保存 K、V?

未来位置需要历史 K、V 来完成注意力计算,通常不需要重新计算历史 Query。

结语

Transformer 最难理解的地方,并不是它拥有多么复杂的公式。

恰恰相反,单独看每一部分,计算过程并不神秘。

Embedding 是查表获得向量。

Q、K、V 是不同的线性投影。

Attention 是 Q 与 K 匹配后,对 V 进行加权汇总。

FFN 是对隐藏特征进行非线性变换。

LayerNorm 与残差连接参与深层网络的信息传递和优化。

输出层将隐藏向量映射成词表分数。

Loss 衡量预测与正确答案的差距。

反向传播计算梯度,优化器更新参数。

推理时,模型利用已经学到的权重逐步生成 Token,而 KV Cache 则尽量避免重复计算历史信息。

真正容易让人困惑的,是这些环节如何组合成完整的信息流,尤其是训练和推理在时间顺序上的差别。

原始 Transformer 的结构图只描述了网络计算模块之间的关系,并没有完整展示 Teacher Forcing、Loss、反向传播、逐 Token 生成和 KV Cache 等过程。

因此,只记住那张著名的架构图是不够的。

我们必须能够从一个 Token ID 出发,追踪它怎样变成 Embedding,怎样生成 QKV,怎样在 Masked Self-Attention 和 Cross-Attention 中交换信息,怎样形成 Logits,怎样通过 Loss 更新参数,以及训练完成后如何借助 KV Cache 高效推理。

这条数据链一旦理解,后续学习 GPT、现代多模态模型乃至 VLA,就有了真正可以复用的基础。

参考资料

  1. Vaswani, A., et al. (2017). Attention Is All You Need. NeurIPS 2017. 

  2. Harvard NLP. The Annotated Transformer.带注释的 Transformer 结构与实现。

  3. PyTorch Documentation. Scaled Dot Product Attention. 官方 Attention 文档。

全文核心公式:

\[ \boxed{ \operatorname{Attention}(Q,K,V) = \operatorname{softmax} \left( \frac{QK^T}{\sqrt{d_k}}+M \right)V } \]

这一公式描述注意力内部的向量计算;而完整的 Transformer,还必须把它放回 Encoder、Decoder、残差归一化、FFN、训练与推理的数据流 中理解。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐