🏠 总目录📚 本教程 02 · Transformer 原理
📑 本页目录(点开跳转)

02 · Transformer 原理

36 分钟 | ⭐⭐ 12 个方向里最值得补的一块


🎯 一句话

Transformer 做的事只有一件:让每个词去「看」句子里的其他词,然后根据看到的东西更新自己的含义。这个动作叫注意力(Attention),堆几十层,就成了大模型。

输入向量 xQ 查询我在找什么×WK 键我能提供什么×WV 值我实际的内容×WQ·Kᵀ → 谁该看谁加权求和 V → 输出同一个输入,乘三个不同的矩阵,得到三个不同角色⭐ 一个查字典的类比:Q 是你要查的词,K 是词条标题,V 是词条内容Q·Kᵀ 算出「和每个词条有多匹配」,再按匹配度把 V 混起来 —— 这就是注意力
同一个输入乘三个不同矩阵,得到三个不同角色。⭐ 一个查字典的类比:Q 是你要查的词,K 是词条标题,V 是词条内容 —— Q·Kᵀ 算出和每个词条有多匹配,再按匹配度把 V 混起来。
当前位置能看到哪些位置训练时整句话一起算,但每个位置只准看它左边的橙色 = 可以看红色 = 被掩掉⭐ 没有这个掩码,模型就能「偷看答案」——训练时完美,生成时完全不会这也是为什么它能一次并行算完整句,而不用像 RNN 那样一步步来
训练时整句话一起算,但每个位置只准看它左边的(红色被掩掉)。⭐ 没有这个掩码,模型就能「偷看答案」—— 训练时完美,生成时完全不会。这也是它能一次并行算完整句、而不用像 RNN 那样一步步来的原因。
输入 token路由器Gating专家1专家2专家3专家4专家5加权求和每个 token 只走【两个】专家,其余的完全不算⭐ 所以参数量可以很大(总容量),但每次实际计算量很小(激活参数)⚠️ 代价:显存要装下【全部】专家,且路由不均衡时部分专家会被闲置
每个 token 只走两个专家,其余的完全不参与计算。⭐ 所以总参数量可以很大,而每次实际计算量很小。⚠️ 代价:显存要装下全部专家,且路由不均衡时会有专家被闲置。
LayerNorm多头自注意力每个位置去看所有位置LayerNorm前馈网络 FFN逐位置独立变换残差残差输入输出(喂给下一个完全一样的块)「看别人」位置之间交换信息「想自己」每个位置各算各的⭐ 一个块只做两件事堆几十个,就是大模型
一个块只做两件事:「看别人」(注意力,位置之间交换信息)和「想自己」(FFN,每个位置各算各的)。⭐ 两条蓝色残差旁路是深层能训起来的关键 —— 把这个块堆几十个,就是大模型。
老鼠老鼠查询被看的词(Key)「它」把注意力分给了「猫」和「老鼠」—— 指代消解不是规则写出来的,是学出来的
颜色越深=注意力越高。看「它」那一行:模型把注意力分给了「猫」和「老鼠」。⭐ 这种指代关系没有人写规则告诉它,是从数据里学出来的 —— 这就是注意力的价值。

🧠 核心概念一:注意力(Attention)

先看它解决什么问题

   句子:「那只猫没抓到它,因为它跑得太快」

   第二个「它」指谁?猫还是老鼠?
   → 要理解「它」,必须看句子里的其他词
   → 而且不同的词,重要程度不一样

注意力 = 给每个词分配「该看谁、看多重」的权重。

机制:Q、K、V 三个角色

每个词会生成三个向量,用一个图书馆的类比:

   Query  (查询)  = 「我想找什么」      ← 我这个词的需求
   Key    (键)    = 「我是什么」        ← 每个词的索引标签
   Value  (值)    = 「我的实际内容」    ← 每个词的信息

   过程:
   ① 我的 Q  ·  每个词的 K   → 算出「我和它有多相关」(打分)
   ② 分数过 softmax          → 变成加起来等于 1 的权重
   ③ 按权重加权求和所有 V     → 得到我的新表示

   💡 这就是「查字典」:用需求匹配索引,取出内容,按相关度混合

公式(看不懂跳过,下面有人话):

$$\text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V$$

💡 人话翻译

QK^T = 每个词和每个词的相关度矩阵(就是推荐/搜索里算相似度的那个点积,一模一样) ÷√d_k = 防止维度高时数值过大导致 softmax 变得极端 softmax = 把分数变成权重(加起来 = 1) ×V = 按权重把大家的内容混合起来

🔗 如果你做过推荐或搜索:这里的「点积衡量相关度」和矩阵分解里的用户向量·物品向量是同一个思想。 区别只有一个:推荐取 top-k 是"硬选",注意力用 softmax 是"软选"且可微。

🧮 用那个句子走一遍

   「那只猫没抓到它,因为它跑得太快」
                          ↑ 处理这个「它」

   ① 「它」的 Query 大致在问:「我是个代词,我指的是谁?」

   ② 和每个词的 Key 打分(数字是示意):
        那只  0.1
        猫    2.8   ← 名词,可能是指代对象
        没    0.1
        抓到  0.9   ← 动作,提供了语义线索
        它    0.3
        因为  0.2
        跑得  1.5   ← 「跑得快」这个属性很关键
        太快  1.4

   ③ softmax 后 → 「猫」拿到最大权重

   ④ 加权求和各词的 Value
      → 「它」的新向量里,混进了大量「猫」的信息 ⭐

   💡 经过这一层之后,「它」这个 token 的表示,
      已经不再是通用的"它",而是"指代猫的那个它"

🔑 这就是"更新自己的含义"的具体过程。 堆几十层,每层都做一次这种融合——词的表示会越来越"上下文化"。

多头注意力(Multi-Head)

一组 QKV 只能捕捉一种关系。所以并行做 多组(如 32 组),每组关注不同的东西:

   头1:关注语法主谓关系
   头2:关注指代(「它」指谁)
   头3:关注远距离的上下文
   ...        (实际上每个头学什么,是自动涌现的,不是人指定的)
        ↓
   把所有头的结果拼起来 → 过一个线性层混合

🧠 核心概念二:一层 Transformer 长什么样

   输入向量
      │
      ├──────────────┐
      ▼              │
   多头注意力          │  ← 词之间交流信息
      │              │
      ▼              │
   + 残差相加 ◄──────┘  ← 保留原信息,防止深层退化
      │
   LayerNorm           ← 数值归一化,训练更稳
      │
      ├──────────────┐
      ▼              │
   前馈网络 FFN        │  ← 每个词独立地"深加工"(参数量的大头!)
   (放大4倍再压回)     │
      │              │
      ▼              │
   + 残差相加 ◄──────┘
      │
   LayerNorm
      │
      ▼
   输出(喂给下一层)

堆 32~120 层,就是一个现代大模型。

💡 反直觉的事实:参数量的大头在 FFN(约 2/3),不是注意力。注意力负责「词之间交流」,FFN 负责「存知识」——研究表明事实性知识主要存在 FFN 里。

🔑 一句话记住这个分工

   注意力:横向的  —— 【token 之间】交换信息  ← "谁和谁有关系"
   FFN:  纵向的  —— 【每个 token 单独】深加工 ← "这个东西是什么"

   ⭐ 一层 = 一次"看看别人" + 一次"自己想想"
      堆 32~120 层 = 反复这两件事

💡 这个分工解释了三件事

现象 解释
MoE 为什么只替换 FFN 因为 FFN 是参数大头,稀疏化它收益最大;而注意力必须每个 token 都参与
模型"记住"了某个事实存在哪 主要在 FFN 里(可以被定位甚至编辑,这是"模型编辑"研究的基础)
为什么加长上下文不增加"知识量" 上下文影响的是注意力这一侧,FFN 里的知识是训练时固化的 ⭐

🧱 每个零件为什么必须存在

零件 拿掉会怎样
注意力 token 之间无法交流,退化成对每个词独立处理
FFN 只剩加权平均,没有非线性变换能力(🔗 ML 基础第 7 章的异或实验)
残差连接 几十层根本训不动——梯度连乘会消失 ⭐
LayerNorm 数值尺度层层漂移,训练不稳定
位置编码 打乱词序结果完全一样(注意力是置换等变的)

🔗 《机器学习基础》第 14 章会告诉你: 这些零件除了位置编码,全都是 Transformer 之前就有的。 Transformer 的贡献是组合方式,不是发明新零件。


🧠 核心概念三:因果掩码(为什么它只会「续写」)

   预测第 4 个词时,能看到的:
   位置1 ✅  位置2 ✅  位置3 ✅  位置4 ❌  位置5 ❌

   → 不许偷看未来
   → 训练目标就是「根据前面所有词,猜下一个词」
   → 这叫 自回归(Autoregressive)

这解释了一切:为什么模型是「一个字一个字往外蹦」的、为什么它本质上是个超级续写机、为什么第 1 章说预训练完的模型不会当助手。

🔗 做过序列推荐的话SASRec 用的是一模一样的因果掩码——序列推荐和语言模型是同一套机制


🧠 核心概念四:KV Cache(连接到你已知的痛点)

生成第 100 个词时,前 99 个词的 K 和 V 其实上一步已经算过了。缓存起来别重算——这就是 KV Cache。

   没有 Cache:生成 n 个词,计算量 O(n²),慢到不能用
   有  Cache:每步只算新词的 QKV,快几十倍 ✅

   代价:显存!
   KV Cache 大小 ≈ 2 × 层数 × 头数 × 头维度 × 序列长度 × batch × 精度字节
   → 长上下文时,KV Cache 可能比模型权重还占显存 💀

🔑 这一条解释了两件你早就遇到的事: 1. 为什么长上下文那么贵 —— KV Cache 线性增长,且吃显存 2. 为什么「上下文腐烂」(智能体教程第 4 章)—— 注意力要算 n² 的两两关系,token 越多,每个词分到的注意力越被摊薄

🧮 算一个具体的数

   一个 70B 模型(80 层,64 头,头维度 128,FP16):

   每个 token 的 KV Cache = 2 × 80 × 64 × 128 × 2 字节 ≈ 2.6 MB

   上下文 10,000 token  →  26 GB  😨
   上下文 100,000 token →  260 GB 💀

   ⭐ 模型权重才 140GB —— KV Cache 轻松超过它

💡 这就是 MQA / GQA 存在的理由: 让多个 Query 头共享同一组 K 和 V,KV Cache 直接砍到 1/8 甚至 1/64。 代价是一点点效果,换来的是长上下文变得可负担。 🔗 详见第 6 章推理优化

⏱️ 两个阶段:Prefill vs Decode(理解延迟的关键)

   ① Prefill(预填充):处理你的输入
      · 所有 token【并行】计算 → GPU 吃满
      · 计算密集型,受【算力】限制
      · 决定了"首字延迟"(TTFT)

   ② Decode(解码):一个一个吐 token
      · 每步只算 1 个 token,但要读【全部】KV Cache
      · 内存带宽密集型,受【显存带宽】限制 ⭐
      · 决定了"每秒吐几个字"

🔑 这个区分解释了很多实际现象: - 为什么输出 token 比输入贵:decode 阶段 GPU 利用率极低,一次只处理 1 个 token - 为什么 batch 起来更划算:decode 是带宽瓶颈,同时处理多个请求几乎不增加时间 ⭐ - 为什么 Prefix Caching 省这么多:它直接跳过了 prefill 的重复计算


🔗 和你已知的关系

左列有的来自日常用 LLM 的经验,有的在站内别的板块讲过——碰上过哪几条就从哪几条接进来,一条没碰过也不影响读这一章

你可能已经知道的 这一章给出的「为什么」
上下文越长效果越差 注意力是 n² 的,且长序列训练数据少、位置编码要外推
长上下文很贵 KV Cache 随长度线性增长,显存和带宽都是瓶颈
模型一个字一个字输出 因果掩码 + 自回归,本质是「续写」
SASRec 的因果掩码(做过序列推荐的话) 完全一样的机制,序列推荐 = 小号语言模型
点积算相关度 Attention 的 QK^T 就是点积

📦 深挖的话要学什么

真要吃透这一层,需要:

📍 每条后面标了它在哪本库有 = 站内已经讲透,点进去就行;要外找 = 站内没有,得去论文或别处。 (这份清单以前只列词不说去哪,指到的坑有些站内根本没挖过,按图索骥会扑空。)

需要的前置:Python + 一点线性代数(矩阵乘法)+ PyTorch 基础。不需要微积分推导。


⚖️ 要不要深挖

你的情况 建议
只调 API 做应用 🟡 看完本章够了,知道 KV Cache 和 n² 就行
老觉得「知其然不知其所以然」很难受 强烈建议——补完这块,前面学的很多结论会突然通透
想做微调 / 训练 / 推理优化 必须,后面 04–07 章全建立在这上面
想进模型团队或做研究 ✅ 必须,且要手写一遍

🔑 我的判断:这是 12 个方向里性价比最高的一块。它不大(手写 GPT 一个周末能搞定),但补完之后,你对整个领域的理解会从「记住了很多结论」变成「知道为什么」。


✅ 检查点

  1. 注意力里的 Q、K、V 各是什么角色?它和推荐系统的双塔召回什么区别?
  2. 用「那只猫没抓到它」那个例子说:经过一层注意力后,「它」这个 token 发生了什么?
  3. 注意力和 FFN 的分工是什么?这个分工解释了哪三件事?
  4. 五个零件里,拿掉哪个会导致"打乱词序结果不变"?拿掉哪个会导致"几十层训不动"?
  5. 参数量的大头在注意力还是 FFN?为什么 MoE 只替换 FFN?
  6. 因果掩码是干什么的?它导致了模型的什么本质特性?
  7. KV Cache 解决什么问题?70B 模型 10 万 token 大约要多少显存?
  8. Prefill 和 Decode 分别受什么限制?这解释了哪三个实际现象?
  9. 用这一章的知识解释:为什么长上下文又贵又容易「腐烂」?
👀 答案
  1. Q=我想找什么(需求),K=我是什么(索引),V=我的内容。Q·K 算相关度,softmax 成权重,加权求和 V。和双塔召回是同一个思想(点积算相关度),区别是召回取 top-k 硬选、注意力用 softmax 软选且可微。
  2. 「它」的 Query 在问"我指谁",和「猫」的 Key 打分最高,softmax 后「猫」拿到最大权重,加权求和时「猫」的信息被大量混进「它」的新向量——它从通用的"它"变成了"指代猫的那个它"。
  3. 注意力是横向的(token 之间交换信息),FFN 是纵向的(每个 token 单独深加工)。解释了:①MoE 为什么只替换 FFN(参数大头,且注意力必须每个 token 参与)②事实性知识存在 FFN 里 ③为什么加长上下文不增加知识量(上下文影响注意力侧,FFN 的知识是训练时固化的)。
  4. 拿掉位置编码 → 打乱词序结果不变(注意力是置换等变的);拿掉残差连接 → 几十层训不动(梯度连乘消失)。
  5. FFN(约 2/3)。MoE 只替换 FFN 是因为它是参数大头、稀疏化收益最大,而注意力必须每个 token 都参与不能稀疏。
  6. 禁止看未来的词,强制模型学"根据前文猜下一个词"(自回归)。导致模型本质是续写机,只能一个字一个字生成。
  7. 避免每生成一个词就重算前面所有词的 K/V。70B 模型每 token 约 2.6MB,10 万 token ≈ 260GB——比 140GB 的模型权重还大。这就是 MQA/GQA(共享 KV)存在的理由。
  8. Prefill 受算力限制(所有 token 并行,GPU 吃满,决定首字延迟);Decode 受显存带宽限制(每步只算 1 个 token 却要读全部 KV Cache)。解释了:①输出比输入贵(decode 时 GPU 利用率极低)②batch 起来几乎不增加时间(带宽瓶颈)③Prefix Caching 省很多(跳过 prefill 重复计算)。
  9. :KV Cache 随长度线性增长,占显存和带宽,decode 阶段每步都要读完整个 Cache。腐烂:注意力要算 n² 的两两关系,token 越多每个词分到的注意力越稀薄;加上长序列训练数据少、位置编码要外推。

🛑 可以停在这里

走神救援

Transformer=让每个词看其他词并更新自己。注意力用QKV:Q·K算相关度→softmax成权重→加权求和V(就是点积,和推荐的双塔同源,区别只是硬选vs软选)——⭐走一遍「猫…它」的例子:「它」的Q问"我指谁",「猫」的K得分最高,加权后猫的信息混进「它」的向量 → 它从通用的"它"变成"指代猫的它"。多头=并行多组捕捉不同关系。一层=注意力+残差+LayerNorm+FFN。⭐分工:注意力是横向的(token之间交换信息),FFN是纵向的(每个token单独深加工);FFN是参数大头(2/3)且存知识——这解释了 MoE 为什么只替换FFN、以及为什么加长上下文不增加知识量。五零件拿掉的后果:没位置编码→打乱词序结果不变;没残差→几十层训不动。因果掩码→只能续写(自回归)。KV Cache避免重算但吃显存——70B模型10万token要260GB,比140GB的权重还大,这就是MQA/GQA的理由。⭐Prefill受算力限制(并行,决定首字延迟)、Decode受显存带宽限制(每步算1个token却要读全部Cache) → 解释了输出比输入贵、batch起来几乎不增加时间、Prefix Caching 为什么省。性价比最高的一块,建议补。

下一节 👉 02b-现代LLM架构的四处改动.md

🧭 接下来三章(02b / 02c / 02d)是这一章的下游,讲的是「原始 Transformer 到今天的模型,中间改了什么、为什么」。 赶时间可以先跳到 03-Tokenizer与上下文.md,等真要读模型代码或被问到架构细节时再回来。

打卡记录保存在你的浏览器里,首页能看到总进度