第 3 章 LLMTransformerToken

第 3 章 LLM 核心概念

第 3 章 LLM 核心概念

学习目标

  • 理解文本如何变成 token、token 如何变成向量(Embedding);
  • 掌握自注意力机制与 MHA/MQA/GQA 的演进逻辑;
  • 理解 RoPE、ALiBi 等位置编码解决什么问题;
  • 理解因果掩码、上下文窗口、KV Cache 如何决定 LLM 的生成行为;
  • 厘清 CLM、MLM、Span Corruption 三类预训练目标;
  • 建立对涌现、上下文学习、幻觉、对齐、可控生成的工程认知。

3.1 从字符到向量:Tokenization 与 Embedding

LLM 处理不了「字符」,只能处理「数字」。文本进入模型要经过两步:

  1. Tokenization(分词):把文本切成 token(词元);
  2. Embedding(嵌入):把每个 token 映射成一个稠密向量。

3.1.1 Tokenization

Token 是介于「字符」和「单词」之间的最小处理单元。三个主流的子词分词算法:

  • BPE(Byte Pair Encoding):从字符开始,反复合并出现频率最高的相邻字符对,直到达到目标词表大小。GPT 系用 BPE。
  • WordPiece:按「合并后能使语言模型似然提升最大」的原则合并子词。BERT 用 WordPiece。
  • SentencePiece:不依赖空格预分词,直接处理原始文本(含中文、日文等无空格语言),底层可用 BPE 或 unigram。Llama、Qwen 等新模型常用 SentencePiece + BPE。
# HuggingFace tokenizers 示例:感受 token 切分
from transformers import AutoTokenizer

tok = AutoTokenizer.from_pretrained("Qwen/Qwen2-7B")
text = "你好,大语言模型工程"
ids = tok.encode(text)
print(ids)                       # [151644, 100368, ...]
print(tok.decode(ids))           # 能还原回原文
print(tok.convert_ids_to_tokens(ids))  # 看每个 token 怎么切的

分词看似简单,实则影响深远:

  • 词表大小决定 Embedding 层参数规模(4 万词表 × 4096 维 ≈ 1.6 亿参数,占 7B 模型约 2%)。
  • 中文分词:中文常按「单字或双字子词」切分,同样 token 数下信息密度高于英文,这也是中文模型 token 成本更低的原因之一。
  • 生僻词/代码:BPE 会把生僻词切成一串子词,导致 token 数膨胀、成本上升。

3.1.2 Embedding

每个 token 对应词表中的一个索引,Embedding 层(一个可学习的矩阵,形状为「词表大小 × 隐藏维度」)把它查表映射为向量。这些向量在训练中学习到语义:语义相近的词向量相近(king - man + woman ≈ queen)。

一个关键工程点:Embedding 层只提供「初始表示」,真正的语义由后续每一层 Transformer 块加工。所以「词向量」与「上下文相关表示」要区分——LLM 里的词是「上下文相关」的,同一个词在不同句子里向量不同(第 1 章提过 ELMo 的开创意义)。

3.2 位置编码:让模型知道顺序

自注意力本身没有顺序概念——它把输入当集合处理,交换两个 token 顺序,输出不变(对注意力计算而言)。但语言是顺序敏感的,所以必须把位置信息注入。三类方案:

3.2.1 绝对位置编码(Sinusoidal / 可学习)

  • Sinusoidal(正弦):用固定频率的正余弦函数生成位置向量,与 token 向量相加。Transformer 原文用。
  • 可学习位置编码:位置向量作为参数学习(BERT、GPT-2)。缺点是外推到更长序列表现差。

3.2.2 相对位置编码与 RoPE

绝对位置编码把「绝对位置」告诉模型,但语言更依赖「相对距离」(第 5 个词和第 6 个词的关系,比第 5 个词和第 100 个词更重要)。于是有相对位置编码与旋转位置编码。

RoPE(Rotary Position Embedding,旋转位置编码) 是当下 LLM 的事实标准(Llama、Qwen、DeepSeek 都用)。核心思想:把每个位置的向量旋转一个与位置成正比的角度,从而把「相对位置」编码进注意力分数。它带来两个工程红利:

  1. 相对位置感知:注意力分数天然只依赖相对距离;
  2. 便于长上下文外推:配合位置插值(Position Interpolation)、NTK 等方法,可以把训练时的 4K 上下文扩展到 128K(第 4 章、第 8 章展开)。

3.2.3 ALiBi

ALiBi(Attention with Linear Biases)是另一种方案:不给输入加位置向量,而是在注意力分数上直接减去「相对距离 × 斜率」。实现极简、零参数,且外推能力天然较好。MosaicML 的 MPT 用过,但整体影响力不如 RoPE。

%%{init: {"themeVariables": {"primaryTextColor": "#000000", "textColor": "#000000", "labelColor": "#000000", "nodeTextColor": "#000000", "labelTextColor": "#000000", "scaleLabelColor": "#000000"}}}%%
graph LR
    A[绝对位置编码
Sinusoidal/可学习] -->|外推差| B[RoPE 旋转位置编码
相对感知+可外推] A -->|实现简| C[ALiBi 线性偏置
零参数] B --> D[现代 LLM 主流
Llama/Qwen/DeepSeek]

3.3 自注意力:LLM 的心脏

3.3.1 核心计算

自注意力(Self-Attention)让序列中每个 token 都能「看到」所有 token,并动态决定关注谁。对输入 XX,计算:

Q=XWQ,K=XWK,V=XWVQ = XW_Q,\quad K = XW_K,\quad V = XW_V

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

  • QQ(Query,查询):当前 token「想找什么」;
  • KK(Key,键):每个 token「能提供什么」;
  • VV(Value,值):每个 token「实际贡献的内容」;
  • QK/dkQK^\top / \sqrt{d_k}:查询与所有键的点积,衡量相关度,除以 dk\sqrt{d_k} 防数值过大;
  • softmax:归一化成权重;
  • VV:按权重加权汇总。
# 单头注意力最小实现(教学版)
import torch
import torch.nn.functional as F

def attention(Q, K, V):
    d_k = Q.size(-1)
    scores = Q @ K.transpose(-2, -1) / (d_k ** 0.5)
    weights = F.softmax(scores, dim=-1)
    return weights @ V

这个计算就是「自注意力」,O(n²) 的复杂度(n 为序列长度)决定了后续一切推理优化(KV Cache、PagedAttention、长上下文——第 4、14 章)。

3.3.2 多头注意力:MHA → MQA → GQA

单头注意力只能学到一种「关系模式」,多头让模型同时学多种模式(语法、指代、语义)。演进路径:

  • MHA(Multi-Head Attention):每头独立的 Q/K/V,表达力最强,但 KV 参数最多、推理内存最贵。
  • MQA(Multi-Query Attention):所有头共享一份 K/V,只有 Q 分头。推理显存大减,但表达能力下降(Llama 1 早期用过)。
  • GQA(Grouped-Query Attention):把头分成若干组,组内共享 K/V。在表达力与内存之间取折中,是当下主流(Llama 2/3、Mistral 都用)。
变体 Q 头数 K/V 头数 KV 缓存大小 使用方
MHA H H 早期 Transformer
MQA H 1 Llama 1、Falcon
GQA H G(1<G<H) Llama 2/3、Mistral、Qwen

为什么业界从 MHA 转向 GQA? 因为推理时 KV Cache 大小与 K/V 头数成正比(3.5 节),而 KV Cache 是长上下文推理的显存瓶颈。GQA 用「少一点表达力」换「大幅降低推理内存」,是典型的工程权衡——这就是本书反复强调的「性能/成本/安全权衡」的一个具体实例。

3.4 其他核心组件:FFN、残差、归一化

每个 Transformer 块除了注意力,还有三件套:

  • FFN(前馈网络):两层全连接 + 激活函数(GELU/SiLU),扩展维度通常为隐藏维的 4 倍(7B 模型的 FFN 参数约占 2/3)。它提供非线性与容量。
  • 残差连接(Residual Connection)输出 = 子层(x) + x,解决深层网络的梯度消失,让千层 Transformer 可训练。
  • 归一化(LayerNorm / RMSNorm):稳定训练。RMSNorm(去掉均值中心化的简化版)是 Llama 系标配,计算更省。
%%{init: {"themeVariables": {"primaryTextColor": "#000000", "textColor": "#000000", "labelColor": "#000000", "nodeTextColor": "#000000", "labelTextColor": "#000000", "scaleLabelColor": "#000000"}}}%%
flowchart TD
    X[输入向量] --> A[LayerNorm/RMSNorm]
    A --> B[Multi-Head Attention]
    B --> C[残差加回]
    C --> D[LayerNorm/RMSNorm]
    D --> E[FFN]
    E --> F[残差加回]
    F --> G[输出]

因果掩码(Causal Mask):Decoder-only 的注意力必须只让 token「看到自己及之前的 token」,不能看到未来。实现方式是在注意力分数矩阵的上三角加 -inf,softmax 后这些位置权重为 0。这个掩码是自回归生成的根本保证,也是与双向模型(BERT)的本质区别。

3.5 上下文窗口与 KV Cache

3.5.1 上下文窗口(Context Window)

模型一次能处理的 token 总数(输入 + 输出)。从 GPT-3 的 2K,到今天的 128K/1M(Gemini 1M、Qwen 128K)。窗口越大,能处理的长文档、多轮对话、长代码越多。代价是注意力 O(n²) 计算与 KV Cache 的 O(n) 内存增长。

3.5.2 KV Cache

自回归生成是逐 token 进行的:生成第 t+1t+1 个 token 时,前 tt 个 token 的 K/V 其实已经算过了,没必要重算。KV Cache 就是把历史上每一步的 K/V 缓存下来,每步只对新 token 计算 Q、并复用缓存的 K/V 做注意力。

# 伪代码:带 KV Cache 的自回归生成
def generate_step(model, input_ids, past_key_values, position_ids):
    # 只对最后一个 token 前向一次
    outputs = model(input_ids[:, -1:], past_key_values=past_key_values)
    next_token = sample(outputs.logits[:, -1, :])
    # 新 KV 追加进缓存
    past_key_values = outputs.past_key_values
    return next_token, past_key_values

KV Cache 大小估算(贯穿全书的显存公式,第 4 章会给出完整版):

MKV=2×L×G×dh×S×pM_{\text{KV}} = 2 \times L \times G \times d_h \times S \times p

其中 LL 为层数,GG 为 KV 头数(GQA 下每组共享一份 K/V),dhd_h 为头维度,SS 为序列长度,pp 为每个数值的字节数(FP16/BF16 时 p=2p=2)。第一个因子 22 表示每个 token 同时缓存 K 和 V 两份矩阵,与 pp 的含义不同,不要混为一谈。若考虑并发数 BB,则再乘上 BB(第 4 章完整版)。

以 7B 模型、GQA(8 KV 头)、128K 上下文为例,KV Cache 可达 数十 GB,远超模型权重本身(~14GB)。这正是第 4 章、第 14 章 PagedAttention、KV 量化等技术的出发点。

3.6 预训练目标:CLM、MLM、Span Corruption

不同架构用不同的自监督目标,这决定了「模型学到什么」:

目标 全称 做法 代表 学到什么
CLM Causal Language Modeling 预测下一个 token GPT 系 生成能力
MLM Masked Language Modeling 遮住 token 预测它 BERT 双向理解
Span Corruption 遮住一段预测整段 把连续片段替换为哨兵 token,预测原片段 T5 理解 + 生成
  • CLM:Decoder-only 专用,因果掩码保证。学的是「给定上文生成下文」的分布。这是 GPT 家族的统一任务。
  • MLM:Encoder-only 专用,双向上下文,学的是「语言理解」。
  • Span Corruption:Encoder-Decoder 用,输入是被破坏的句子,输出是恢复的片段,让编码器学理解、解码器学生成。

一个常被忽略的点:预训练目标决定了能力天花板,对齐只调整行为方式。CLM 学到的世界知识与推理先验,是后续 SFT/RLHF 无法凭空补上的。这也是为什么「预训练数据质量」如此重要(第 6 章)。

3.7 涌现能力、上下文学习、思维链、指令跟随

这些「能力」不是显式训练出来的,而是规模、数据、对齐共同作用的产物。厘清它们的层级关系:

%%{init: {"themeVariables": {"primaryTextColor": "#000000", "textColor": "#000000", "labelColor": "#000000", "nodeTextColor": "#000000", "labelTextColor": "#000000", "scaleLabelColor": "#000000"}}}%%
flowchart TD
    A[自监督预训练
CLM] --> B[基础能力
语言理解/世界知识] B --> C[涌现能力
上下文学习/推理] C --> D[对齐
SFT + RLHF/DPO] D --> E[用户可见能力
指令跟随/对话/工具使用] E --> F[应用增强
CoT/RAG/Agent]
  • 涌现能力(Emergent Abilities):小模型没有、跨过规模阈值后出现的能力(第 1 章已谈及其争议)。
  • 上下文学习(ICL):不改参数,靠 Prompt 中的示例完成任务。few-shot 的基础。
  • 思维链(CoT):让模型「先想后答」。「让我们一步步思考」这类提示显著提升数学/逻辑推理,是推理增强的起点(第 12 章在 AI 算法书里展开,本书第 26 章 Agent 会用到)。
  • 指令跟随(Instruction Following):SFT + RLHF 的产物,让模型「听懂人话并按指令做」,这是从「语言模型」到「对话助手」的关键一跃。

工程含义:这些能力决定了使用方式——你是在「用模型补全文本」还是「给模型下指令」还是「让模型当 Agent 自主决策」,同一模型用法天差地别(第 17、26 章)。

3.8 幻觉、对齐、安全、可控生成

3.8.1 幻觉

第 1 章已定义。从机制上理解:LLM 生成是「概率采样」,不区分「训练时见过的真知识」和「没见过的编造」。当用户问题超出训练分布或模型自信地「接续最可能的 token」时,就产生幻觉。RAG 是把「模型记忆」换成「实时检索」来对抗幻觉,但检索失败时模型仍可能编造。

3.8.2 对齐(Alignment)

让模型「说人话、做好事、拒绝坏事」。对齐不只是安全,还包括有用性(Helpful)、诚实性(Honest)、无害性(Harmless) 三个维度(HHH)。技术路线:SFT(教它怎么答)→ RLHF/DPO(教它偏好什么)。第 7 章展开。

3.8.3 可控生成

业务上经常需要「模型按指定格式/口径输出」:结构化输出(JSON Schema)、字数限制、语气控制、知识范围限定。手段分训练侧(指令微调、偏好对齐)与推理侧(结构化解码、约束采样、Prompt 约束)。第 17 章函数调用与结构化输出展开。

3.9 提示、对话模板、系统提示、结构化输出

LLM 的产品化绕不开这几个词:

  • 提示(Prompt):给模型的输入文本,可以包含指令、示例、上下文、问题。
  • 对话模板(Chat Template):把「用户消息、助手消息、系统消息」编码成模型训练时的格式(<|im_start|>user...)。必须与训练一致,否则模型行为异常——这是工程上最常见的坑之一。
  • 系统提示(System Prompt):定义模型角色与全局规则,优先级最高,也最容易被提示注入攻击(第 23 章)。
  • 结构化输出(Structured Output):让模型输出符合 JSON Schema 的结果,用于程序化消费。实现有「提示约束 + 解析重试」与「约束解码(如 vLLM guided decoding、Outlines)」两条路线,后者更可靠(第 17 章)。
# 对话模板:同一段对话,不同模型格式不同
from transformers import AutoTokenizer

tok = AutoTokenizer.from_pretrained("Qwen/Qwen2-7B")
msgs = [
    {"role": "system", "content": "你是一个严谨的助手。"},
    {"role": "user", "content": "1+1=?"},
]
prompt = tok.apply_chat_template(msgs, tokenize=False)
# Qwen: <|im_start|>system\n你是一个严谨的助手。<|im_end|>\n<|im_start|>user\n1+1=?<|im_end|>\n<|im_start|>assistant\n

本章要点回顾

  1. 文本 → token(BPE/WordPiece/SentencePiece)→ 向量(Embedding)。分词决定 token 成本与中文信息密度。
  2. 自注意力是 LLM 心脏:Q/K/V 点积 + softmax + 加权求和,O(n²) 复杂度。
  3. 多头演进 MHA → MQA → GQA:用少量表达力换大量推理内存,这是全书权衡主题的第一次出场。
  4. RoPE 成为位置编码标准:相对感知 + 长上下文可外推。
  5. 因果掩码保证自回归;KV Cache 缓存历史 K/V,是推理显存的第一大瓶颈。
  6. 预训练目标(CLM/MLM/Span Corruption)决定能力天花板,对齐只改行为方式。
  7. 涌现、ICL、CoT、指令跟随是有层级的能力栈;幻觉、对齐、可控生成是产品化必须面对的三角。
  8. 对话模板必须与训练格式一致,这是工程上最常见的坑。

习题

  1. 手算一个 4-token 序列的单头自注意力(无残差),体会 Q/K/V 的计算过程。
  2. 7B 模型、GQA 8 个 KV 头、隐藏 4096、128K 上下文,估算 KV Cache 显存(FP16)。验证 3.5 节的说法。
  3. 为什么 MQA 在 Llama 1 之后被 GQA 取代?说出 GQA 相对 MQA 的取舍。
  4. 中文和英文在 token 效率上有什么差异?用两个不同 tokenizer 实测同一段中文的 token 数。
  5. 给「客服助手」设计系统提示,并说明如何用对话模板保证格式正确。

延伸阅读

  • Vaswani et al., Attention Is All You Need, 2017
  • Su et al., RoFormer: Enhanced Transformer with Rotary Position Embedding(RoPE), 2021
  • Ainslie et al., GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints, 2023
  • Press et al., Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation(ALiBi), 2021
  • Sennrich et al., Neural Machine Translation of Rare Words with Subword Units(BPE), 2016
  • Kudo & Richardson, SentencePiece: A Simple and Language Independent Subword Tokenizer, 2018

下一章预告

第 4 章聚焦「规模」这个全书最核心的变量:参数、FLOPs、显存、KV Cache 怎么算,稠密 vs MoE,Scaling Law 与 Chinchilla 规律,以及「小模型为什么有价值」。