LLM Transformer的解码器内幕

文章目录

一、前文回顾与本文概要

博文 讲什么 本文深入到哪里
第一篇 训练流程(预训练→SFT→RM→RL)
第二篇 神经网络怎么学习 Feed Forward 里的 WL1/WL2
第三篇 Transformer 五大步骤 Encoder/Decoder 未探究
第四篇 注意力机制解密 把Decoder拆开,解剖内部每一层

二、注意力机制 —— 从最简例子开始

2.1 场景:预测新同学体重

班里有 N 位同学,登记了身高和体重:
  同学①:身高 1.60m → 体重 50kg
  同学②:身高 1.65m → 体重 55kg
  同学③:身高 1.80m → 体重 70kg
  ...

新同学小明:身高 1.78m → 体重未知,怎么预测?

注意力机制的做法

  1. 计算相关度(相似度):小明身高 1.78m,跟每个同学比较身高差异

    • 身高 1.75m 的同学 → 相关度高(差异小)
    • 身高 1.60m 的同学 → 相关度低(差异大)
  2. Softmax 归一化:把所有相关度转成概率(加起来 = 1)

  3. 加权求和

    预测体重 = 相关度₁ × 体重₁ + 相关度₂ × 体重₂ + 相关度₃ × 体重₃ + ...
    

2.2 这就是 Q、K、V 的直觉理解

符号 含义 本例中
Q(Query) 发出查询的"我" 小明的身高(1.78m)
K(Key) 被查询的"标签" 每位同学的身高
V(Value) 真正有价值的内容 每位同学的体重
相关度 Q 和每个 K 的相似度 身高差异的量化
输出 V 的加权和 预测体重

核心洞察:Q 和 K 只是用来算相关度权重的工具人,真正有价值的是 V 的加权求和结果

2.3 不止一个特征:多维 QKV

只用身高预测体重不够准 —— 再加上胸围、腰围等特征:

Q = [身高, 胸围]     → 2 维向量
K = [身高, 胸围]ₙ    → N 个 2 维向量
V = [体重]ₙ           → N 个体重值

三、自注意力机制(Self-Attention)

3.1 从"不同角色"到"同一个我"

普通注意力 自注意力
Q 来源 外部查询(小明) 自己的向量
K 来源 数据库(同学) 自己的向量
V 来源 数据库(同学) 自己的向量
本质 Q ≠ K ≠ V Q = K = V(同一批向量复制三份)

3.2 自注意力在 Transformer 里如何工作

回顾前文:650 个汉字 → 1,300 个 Token → 1,300 个 12,288 维向量。

把这 1,300 个向量复制三份(Q、K、V 完全相同),然后:

第 1 个向量作为"中心主题词":
  ├── Q₁ 跟 K₁~K₁₃₀₀ 逐一计算相关度
  ├── 得到 1,300 个相关度系数(Softmax 后加起来 = 1)
  ├── 最大的系数一定是跟自己(Q₁ 和 K₁ 的相似度最高,如 0.6)
  └── 加权求和:0.6×V₁ + 0.01×V₂ + ... → 新向量₁

第 2 个向量作为"中心主题词":
  └── 同样操作 → 新向量₂

...(1,300 次)

输入 1,300 个向量 → 输出 1,300 个新向量(每个都聚合了全文信息)

关键特性:每个新向量"大部分"还是自己的信息(因为自相似度最高),但同时也"借"了一些其他 Token 的信息过来。

3.3 为什么要引入神经网络(Wq、Wk、Wv)?

如果 Q = K = V 完全一样,那限制太大了。算法工程师的做法:

                     ┌── Wq 神经网络 ──→ Q(1300 个向量)
1300 个原始向量 ──┼── Wk 神经网络 ──→ K(1300 个向量)
                     └── Wv 神经网络 ──→ V(1300 个向量)

三个神经网络把同一批向量"翻译"成了三种不同的"语言",从不同角度处理信息。


四、多头自注意力机制(Multi-Head Self-Attention)

4.1 为什么需要多头?

一组 QKV 只能从一个角度去理解文字。但一段文字的含义是多维的:

“无法挽回” —— 单头可能只看到"无法"和"挽回"组成了一个短语。但如果有 96 个头,有的头关注语法结构,有的头关注情感色彩,有的头关注前后逻辑…

4.2 多头的实现方式(以 GPT-3 为例)

核心参数:
  - 原始向量维度:12,288
  - 头数:96
  - 每头维度:128(12,288 ÷ 96 = 128)

每个头的处理:
  ┌─ 头₁:Wq₁(12288→128) → Q₁有128维 / Wk₁ → K₁ / Wv₁ → V₁ → 加权求和 → 128维输出
  │
  ├─ 头₂:Wq₂(12288→128) → Q₂有128维 / Wk₂ → K₂ / Wv₂ → V₂ → 加权求和 → 128维输出
  │
  ...(共96个头)
  │
  └─ 头₉₆:Wq₉₆(12288→128) → ... → 128维输出

最后:96 个 128 维拼起来 → 经过 Wo 神经网络 → 1 个 12,288 维向量

4.3 关键洞察

问题 答案
每个头从什么角度? 不知道,人类无法设定也无法事后描述
怎么保证角度不同? 随机初始化 Wq/Wk/Wv,随机数只要足够随机就不会相同
训练结束后能区分吗? 不能。最终参数人类看不懂,只看到 96 组数字确实不同
96 和 128 的关系? 96×128 = 12,288,这是 GPT-3 的巧合,不是必须

算法工程师真的是无所不用其极——他们把一段文字分成 96 个"分身",让每个分身从不同角度去理解,最后再汇总。人类无法设计这些角度,但通过机器学习和随机初始化,模型自己"摸索"出了 96 种不同的理解方式。

4.4 为什么自注意力能并行计算?

这是当年抛弃 RNN(循环神经网络)的核心原因:

RNN(串行):第 1 个字算完 → 第 2 个字才能算 → 第 3 个字...
  
Self-Attention(并行):同一层内所有 1,300 个向量互不依赖
  → 只需要等上一层全部算完,本层就可以全部并行
  → 1,000 张显卡同时开工,效率爆炸

五、前馈神经网络(Feed Forward)

5.1 每一层 Decoder 的两个模块

Decoder 每一层 = 多头自注意力 + Feed Forward

  输入(1300 个向量)──▶ 多头自注意力 ──▶ 输出(1300 个向量)
                                           │
                                           ▼
                              Feed Forward ──▶ 输出(1300 个向量)

两个模块性质不同:

多头自注意力 Feed Forward
主导者 人类算法工程师设计框架 机器/神经网络自主
参数规模 相对小 约 2 倍于多头注意力
向量间交互 有(Token 之间互相借信息) (每个向量单独处理)
结构 96 个头 + Wo 两层神经网络

5.2 Feed Forward 的结构

输入向量(12,288 维)
      │
      ▼
  WL1:放大 4 倍 → 49,152 维
      │
      ▼
  激活函数(非线性)
      │
      ▼
  WL2:缩回 → 12,288 维
  • 参数数量 ≈ 12,288 × 49,152 + 49,152 × 12,288 ≈ 12 亿参数/层
  • GPT-3 有 96 层 → Feed Forward 总参数超过 1,000 亿

为什么先放大再缩小? 放大是为了给特征更大的"表现空间",缩小是提取浓缩后的核心特征。就像把一张图放大 4 倍精细处理,再缩回原尺寸,但处理后的图包含的信息已经完全不同了。


六、GPT-3 完整参数盘点

每个 Decoder 层包含的参数

一层 Decoder:

  多头自注意力:
    Wq × 96   = (12288 × 128) × 96  = ~1.5 亿参数
    Wk × 96   = (12288 × 128) × 96  = ~1.5 亿参数
    Wv × 96   = (12288 × 128) × 96  = ~1.5 亿参数
    Wo        = 12288 × 12288       = ~1.5 亿参数
    小计:~6 亿参数

  Feed Forward:
    WL1       = 12288 × 49152       = ~6 亿参数
    WL2       = 49152 × 12288       = ~6 亿参数
    小计:~12 亿参数

  一层总计:~18 亿参数

96 层总计:~1,728 亿参数
+ Embedding:~6 亿参数
+ 位置编码:~0.25 亿参数
+ Linear 层:~6 亿参数(复用 Embedding 或独立)
─────────────────────
GPT-3 总计:~1,750 亿参数

七、注意力矩阵的 Mask(掩码)

为什么需要 Mask?

训练时给模型一条 1,000 字的数据:

当前任务:用前 200 字预测第 201 个字
问题:后面 800 个字不能让模型看到(那是答案!)

解决:Mask 矩阵
     Tok₁  Tok₂  Tok₃  Tok₄  ...
Tok₁  ✓     ✗     ✗     ✗
Tok₂  ✓     ✓     ✗     ✗
Tok₃  ✓     ✓     ✓     ✗
Tok₄  ✓     ✓     ✓     ✓

→ 形成下三角矩阵:只能往前看,不能往后看

使用模型时不需要 Mask —— 因为根本没有后面的内容可以偷看。


八、相关度计算:点积 + Softmax

两个向量如何算相似度?

向量 A = [0.1, 3, 0.1]
向量 B = [3, 0.1, 3]

点积 = 0.1×3 + 3×0.1 + 0.1×3 = 0.3 + 0.3 + 0.3 = 0.9

点积越小 → 两个向量越不相似。

对比:

向量 C = [2.2, 0.6, 3.2]
B·C = 3×2.2 + 0.1×0.6 + 3×3.2 = 6.6 + 0.06 + 9.6 = 16.26

→ C 跟 B 的相似度远高于 A 跟 B。

Softmax 的作用

点积结果可能是 0.9、16.26、甚至负数 —— 无法直接判断"大"或"小"的尺度。

Softmax([0.9, 16.26, 1.2]) → [2.13×10E−7, 0.9999995, 2.88×10E−7]

特点:
  - 所有值变成 0~1 之间
  - 加起来等于 1
  - 原来大的依然大,小的依然小
  - 负数也能处理(负相关 → 极小的概率)

九、完整训练流程

以模型刚开始训练(所有参数随机初始化)为例,假设一条训练数据有 100 个字:

输入 3 个字"人类简"
      │
      ▼
Tokenization: 3 个字 → 若干 Token
      │
      ▼
Embedding: 每个 Token → 12,288 维向量(随机初始化的 W)
      │
      ▼
Positional Encoding: 位置向量相加(随机初始化的 W)
      │
      ▼
┌─ Decoder 第 1 层 ──────────────────────────────┐
│  多头自注意力(96 个头):                        │
│    Wq/Wk/Wv → 信息聚合 → Wo 汇总                 │
│  ↓                                              │
│  Feed Forward:                                  │
│    WL1 放大 4 倍 → 激活 → WL2 缩回               │
│  ↓                                              │
│  输出:3 个向量(维度不变,信息质变)               │
└─────────────────────────────────────────────────┘
      │
      ▼
  ...(重复 95 次,共 96 层)...
      │
      ▼
最后一层输出 3 个向量 → 只保留最后一个
      │
      ▼
Linear + Softmax → 50,000 个候选 Token 的概率分布
      │
      ▼
预测"第四个字" → 跟标准答案"史"对比 → 误差很大(因为参数都是随机的)
      │
      ▼
反向传播:从第 96 层 → 第 1 层 → Embedding → Positional Encoding
    每一层的每个参数都计算"该变大还是变小"
      │
      ▼
更新全部 1,750 亿参数
      │
      ▼
下一批训练数据...循环往复

十、核心概念速查表

概念 一句话解释
注意力机制 根据相似度决定每个 V 的权重,加权求和得到输出
Q(Query) “提问者”,用来跟 K 算相似度
K(Key) “被查询的标签”,跟 Q 比较得出相关度
V(Value) “真正有价值的内容”,被加权求和
自注意力 Q = K = V(同一批数据),自己能看见自己的注意力
多头注意力 96 组 Wq/Wk/Wv,从 96 个不同角度理解同一段文字
Feed Forward 两层神经网络,先放大 4 倍再缩回,参数≈多头注意力的 2 倍
点积 两个向量对应位置相乘再求和,衡量相似度
Softmax 把任意数值变成概率(0~1,和为 1)
Mask 训练时屏蔽后面内容,形成下三角矩阵
KV Cache DeepSeek 的核心优化,缓存 K 和 V 避免重复计算

十一、Q&A

Q: 为什么每个头的维度要减小(12,288 → 128)? A: 减小计算量。12,288 维点积太贵了,分成 96 个 128 维后计算量大幅降低,而且每个头专注不同的特征角度。

Q: 96 个头分别关注什么角度,人类能知道吗? A: 不能。虽然 QKV 都来自同一段文字,但多头随机初始化导致关注角度大概率不同,算法工程师也无法设定和描述,机器学习会自动找到最优的 96 种角度。

Q: 为什么先放大 4 倍再缩回?信息不会丢失吗? A: 会丢失,但这正好是特征提取的目的——神经网络学会了该保留什么、该丢弃什么。就像人脑处理信息,不可能也不需要对所有细节过目不忘。

Q: 自注意力为什么能并行计算? A: 同一层内,所有 Token 之间的计算互不依赖——只要你等上一层的 1,300 个向量全部算完,本层 1,300 个可以同时开工。这让多 GPU 并行成为可能。

Q: 自注意力和注意力机制有什么区别? A: 注意力 = QKV 来自不同来源(小明 vs 同学)。自注意力 = QKV 来自同一来源(自己的一段文字),是自己看自己。

Q: DeepSeek 为什么省算力? A: 核心创新在 KV Cache。注意力计算中有大量重复的 K 和 V 计算,DeepSeek 设计了压缩缓存方式,大幅减少了显存占用和重复计算。