⌂
CS336 语言模型从零认知课

Stanford CS336 · Spring 2026 · 中文学习载体

CS336 语言模型从零认知课

这不是 Stanford 原课的搬运版,也不是完整作业训练营。它把 CS336 的公开课程、讲义和作业压缩成一条工程认知链路:一个语言模型从文本、模型、训练系统、数据、评测到 post-training,最终怎样成为可用的 AI 产品底座。

19覆盖官方 schedule 中的全部 lecture,包括两场 guest lecture 的公开材料缺口说明。
5串联 A1-A5 作业:Basics、Systems、Scaling、Data、Alignment。
1主线:用软件工程视角理解 AI Infra,不强求从零复现所有实验。

这门课该怎么读

你的背景假设:你有 CS Master 背景和 4 年软件开发经验,能读代码、理解系统边界和工程 tradeoff,但不是专门做 AI Infra。这里的学习目标不是刷 leaderboard,而是建立“我知道每一层在解决什么问题”的知识链。

CS336 的原始设计很硬:它希望学生亲手实现 tokenizer、Transformer、optimizer、training loop、profiling、FlashAttention、DDP/FSDP、scaling law、数据清洗和 reasoning RL。对非 AI Infra 工程师,最有价值的不是把每个 kernel 写到最优,而是理解训练栈中每一层为什么存在、输入输出是什么、成本瓶颈在哪里、什么时候该把问题交给专门的 Infra 团队。

因此这份 HTML 采用三层读法:

  • 第一遍看链路:顺序读“总地图”和 19 章正文,先知道语言模型训练和服务的端到端路径。
  • 第二遍看作业:读 A1-A5 的实验地图,理解每个作业验证哪类工程能力。
  • 第三遍做轻练习:每讲做一个闭卷问题,不需要完整实现,但要能用自己的话解释机制。

完整教材正文

这一节是主课。19 章按官方讲次顺序重写成中文正文,外链只作为来源和下钻入口;读者不打开视频或 slide,也能建立从 token 到训练系统、数据、评测和 post-training 的完整链路。

01. Overview, Tokenization

本讲要建立两个东西:第一,语言模型不是一个 API,而是一条从原始文本到可训练参数的工程链路;第二,tokenizer 是这条链路的入口,它会影响模型能看到什么、上下文有多长、训练和推理要花多少钱。

1. 先把语言模型还原成一条数据路径

你平时调用模型时看到的是一段文本输入和一段文本输出。训练系统看到的不是文本,而是一串整数。更完整地说,语言模型训练的路径大致是:

raw text / bytes → tokenizer.encode(...) → token ids → embedding lookup → Transformer blocks → logits over vocabulary → next-token loss → gradients → optimizer step → checkpoint

这条路径里,每一步都会把问题改写成下一层能处理的形式。tokenizer 把不定长、混合语言、带 emoji、带代码和符号的文本,变成一个整数序列。embedding 把整数查表成向量。Transformer 对向量序列做计算。最后模型在每个位置预测下一个 token,loss 把“预测错了多少”变成可以反向传播的数字。

这个视角比“Transformer 很强”更有用。因为你做 Agent 时经常碰到的痛点,比如上下文太长、JSON 输出不稳定、中文和代码成本不同、tool trace 占满窗口,最早都可以追到 token 序列这一层。模型没有看到“一个 JSON 对象”或“一句中文”,它看到的是 token id 序列和位置。

训练时的问题给定很多 token,模型在每个位置预测下一个 token。训练目标是让真实下一个 token 的概率更高。
推理时的问题给定已有 token,模型一次生成一个新 token。生成出的 token 又会进入下一步输入。
系统时的问题token 数越多,attention、KV cache、prefill、decode 和费用都会变。tokenizer 是成本模型的一部分。
产品时的问题提示词、工具 schema、历史消息和输出格式都会变成 token。你的产品设计会改变底层资源消耗。

2. tokenizer 的合同:可逆,但不等于语义理解

CS336 在第一讲里给 tokenizer 一个很朴素的接口:encode(str) -> list[int],以及 decode(list[int]) -> str。一个合格 tokenizer 至少要能 round-trip:文本编码成 token,再解码回来,应该回到原文本。

class Tokenizer:
    def encode(self, string: str) -> list[int]:
        ...

    def decode(self, indices: list[int]) -> str:
        ...

但“可逆”不代表“按人类语义切分”。同一个英文单词,开头出现和前面带空格出现,可能是不同 token。一个 emoji 在 Unicode 里是一个 code point,但在 UTF-8 中可能占 4 个 byte。一个罕见中文词可能被拆成多个 token,而一个常见英文片段可能是单 token。模型训练时不关心你主观上觉得哪个是“一个字”或“一个词”。

因此 tokenizer 同时承担两个互相拉扯的目标:一方面,词表不能无限大,否则很多 token 很少出现,embedding 学不好;另一方面,序列不能太长,否则 attention 和推理成本上升。这个取舍很早就进入系统设计。

方案好处问题工程后果
Character概念简单,能处理 Unicode 字符。Unicode 空间很大,很多字符极少出现。词表稀疏,压缩率也不好。
Byte词表固定为 256,任何文本都能表示。一个自然语言片段会被拆成很多 byte。序列变长,attention 成本变高。
Wordtoken 更接近人类词语。词表随语料增长,罕见词和未登录词难处理。需要 UNK 或复杂规则,perplexity 也会被影响。
BPE从 byte 出发,按数据里常见相邻片段合并。切分仍是启发式,不保证语义边界。在词表大小和序列长度之间取得实用平衡。

3. BPE 的机制:从 byte 开始,把常见 pair 合起来

Byte Pair Encoding 最早来自数据压缩,后来被用于神经机器翻译,并进入 GPT 系列 tokenizer。它的核心流程不复杂:

  1. 把训练文本转成 UTF-8 bytes,每个 byte 先是一个 token。
  2. 统计当前 token 序列里最常见的相邻 pair。
  3. 把这个 pair 合并成一个新 token,并把它加入词表。
  4. 重复这个过程,直到达到目标词表大小或 merge 次数。

比如训练文本里 the 经常出现,BPE 可能先把 t 和 h 合并成一个 token,再把这个 token 和 e 合并。最终常见片段会变短,罕见片段仍然能退回 byte 表示。这样不会出现“完全没见过的字符无法表示”的问题。

这也是为什么 tokenizer 是“训练出来的组件”。它不是一套固定语法规则,而是语料分布的产物。换语料、换语言比例、换代码占比、换 special tokens,都会改变 token 成本和模型看到的片段边界。

自测:为什么 byte tokenizer 看起来最稳,却不是现代 LLM 的常规选择?

byte tokenizer 的词表小,覆盖所有输入,但序列太长。Transformer 的 attention 和上下文管理都按 token 序列工作,序列变长会直接提高训练和推理成本。BPE 用更大的词表换更短序列,通常更适合当前架构。

4. special tokens 是模型和系统之间的协议

Assignment 1 会要求处理 special tokens,例如 <|endoftext|>。special token 不是普通字符串。它经常用来表达文档边界、对话角色、工具调用边界、消息结束或其他控制信息。训练和推理系统会把这些 token 当成协议的一部分。

这点对 Agent 开发很实际。你定义 tool schema、消息 role、函数调用格式、observation 边界时,本质上是在给模型造一套输入输出协议。如果这些协议切成很多罕见 token,或者和训练时格式不一致,模型就更容易出格式错、漏参数、生成奇怪边界。prompt 不是一段“自然语言说明”,它是 token-level interface。

5. 这一讲应保留的判断力

  • 语言模型从一开始就是系统工程:文本会先变成 token,token 数决定很多后续成本。
  • tokenizer 的好坏不能只看是否能编码文本,还要看压缩率、词表稀疏性、语言覆盖和 special token 协议。
  • BPE 是当前工程上的折中,不是最终答案。byte-level 或 tokenizer-free 方向存在,但大规模主流模型仍大量使用 tokenizer。
  • Agent 里的长上下文、工具调用和结构化输出,都应当被当成 token 预算问题来设计。
闭卷复述题:请解释 string → token ids → logits → loss 这条路径。

参考答案:原始 string 先由 tokenizer 编成 token ids;embedding 层把 ids 变成向量;Transformer 根据上下文更新每个位置的向量;输出层为每个位置给出词表上所有 token 的 logits;cross-entropy loss 比较 logits 和真实下一个 token;loss 反向传播产生梯度,optimizer 用梯度更新参数。

官方可执行 Lecture 1 Lecture 1 源码 Assignment 1 Basics Tokenizer 交互观察工具

02. PyTorch, Einops, Resource Accounting

第二讲的核心不是 PyTorch API,而是资源账本。你要能拿到一个模型配置后,大致算出参数、梯度、optimizer state、activation、FLOPs、显存和带宽压力。没有这张账本,就很难判断一个训练或推理方案是否现实。

1. tensor 是所有状态的共同形式

深度学习代码看起来有很多对象:dataset、model、loss、optimizer、checkpoint。落到计算层,它们大多是 tensor 和 tensor operation。CS336 第二讲先把所有训练状态放到同一张表里:

状态什么时候出现为什么占资源常见优化
parameters模型本体,训练和推理都需要。每次计算都要读权重,大模型权重本身就是显存压力。低精度、分片、量化、MoE。
gradients训练反向传播后产生。通常和参数同规模。梯度累积、分片、混合精度。
optimizer stateAdamW 等 optimizer 更新参数时保存动量。Adam 通常要保存一阶和二阶矩,常用 fp32。optimizer sharding、8-bit optimizer、换 optimizer。
activations前向过程中每层中间结果。训练时反向传播需要它们,随 batch、seq len、层数增长。activation checkpointing、micro-batch。
data / tokens输入 batch 和 label。长序列增加 attention、activation 和数据加载压力。packing、截断、混合策略、数据管线优化。

这个表直接改变你看训练的方式。显存不只是“模型参数放不放得下”。训练时还要放梯度、optimizer state 和 activations。推理时通常没有梯度和 optimizer state,但会出现 KV cache。不同阶段的账本不同,不能混在一起。

2. dtype 是内存、速度和数值稳定性的合同

一个 tensor 的内存占用由两个数决定:元素个数和每个元素的字节数。float32 是 4 bytes,float16 和 bfloat16 是 2 bytes。听起来 fp16/bf16 只是省一半内存,但它们的数值行为不同。

fp16 的 exponent 位更少,小数值容易 underflow。bf16 也用 2 bytes,但保留了接近 fp32 的动态范围,精度更粗。深度学习训练常用 mixed precision:参数、activation、梯度用 bf16/fp16,optimizer state 用 fp32,原因是动量和二阶矩要跨很多 step 累积,数值稳定性更重要。

memory(tensor) = num_elements × bytes_per_element AdamW training state, rough count: parameters: 2 bytes / parameter (bf16) gradients: 2 bytes / parameter (bf16) first moment: 4 bytes / parameter (fp32) second moment: 4 bytes / parameter (fp32) ---------------------------------------------- subtotal: 12 bytes / parameter, before activations

用这个粗账算 70B 参数模型,光参数、梯度和 AdamW state 就是约 840GB,还没算 activation、通信 buffer、fragmentation 和 checkpoint。8 张 80GB H100 只有 640GB 显存。于是你马上知道:全量 AdamW 训练不可能只是把模型塞进 8 卡就结束,必须分片、重算或换策略。

自测:为什么“70B 模型参数 bf16 只有 140GB”这个说法会误导训练预算?

因为 140GB 只算了参数。训练还需要梯度、optimizer state 和 activations。AdamW 常见粗账是 12 bytes/parameter,不含 activations,所以 70B 会到约 840GB。

3. FLOPs:先会算矩阵乘法,再看训练近似

FLOPs 是完成了多少浮点操作,FLOP/s 是硬件每秒能做多少浮点操作。两者很容易混淆。一个矩阵乘法 x @ w,如果 x 形状是 B × D,w 形状是 D × K,输出是 B × K。每个输出元素要做 D 次乘法和接近 D 次加法,所以粗略是:

matmul FLOPs ≈ 2 × B × D × K

训练时还要反向传播。对一个线性层,前向大约是 2 × batch × parameters FLOPs;反向要算输入梯度和权重梯度,大约是前向的 2 倍。于是总训练 FLOPs 粗略是:

training FLOPs ≈ 6 × tokens × parameters

这个公式在短上下文 Transformer 上是很好用的第一版估算。它不会替你处理 attention 在长上下文下的额外成本,也不会算 optimizer、通信和数据加载,但它能让你在几秒内判断数量级。

例如训练一个 70B 参数模型,数据量 15T tokens:

6 × 70e9 × 15e12 = 6.3e24 FLOPs

如果你有 1024 张 H100,假设 bf16 dense 峰值约等于 989.5 TFLOP/s,每张卡实际只拿到 50% MFU,那么每天能完成的 FLOPs 大约是:

989.5e12 × 0.5 × 1024 × 86400 ≈ 4.38e22 FLOPs / day 6.3e24 / 4.38e22 ≈ 144 days

这不是精确训练计划,但它能校准直觉:大模型训练首先是资源组织问题。任何“我们训练一个 70B”这种说法,后面都应该跟着 tokens、硬件、MFU、并行策略和失败恢复。

4. arithmetic intensity:为什么有些算子天生被内存卡住

一个 GPU 操作可以粗略拆成三步:从 HBM 读输入到计算单元,执行计算,把输出写回 HBM。硬件有两个上限:算力上限 FLOP/s 和内存带宽 bytes/s。workload 也有一个比例:每搬 1 byte 数据能做多少 FLOPs,这叫 arithmetic intensity。

arithmetic intensity = FLOPs / bytes moved accelerator intensity = peak FLOP/s / memory bandwidth if workload intensity < accelerator intensity: memory-bound if workload intensity > accelerator intensity: compute-bound

ReLU 这类 elementwise 操作,每个元素读一次、写一次,只做很少计算。它通常是 memory-bound。GeLU 比 ReLU 算得多,但单独看仍可能是 memory-bound。大矩阵乘法则不同:读入一块矩阵后可以参与很多乘加,数据复用多,arithmetic intensity 高,更容易 compute-bound。

这解释了很多反直觉现象:一个算子 FLOPs 少,不代表它快;一个优化减少了内存读写,可能比减少少量计算更有效。FlashAttention 的核心价值也在这里:不是改变 attention 数学,而是通过 tiling 和在线 softmax 减少 HBM 往返。

Elementwise读一个元素、算一点、写一个元素。FLOPs 少,但经常被内存带宽限制。
Matrix multiply读入的数据会被重复用于很多乘加。矩阵足够大时更容易把算力用满。
Training prefill大 batch 和完整序列让计算更像矩阵乘法,常见目标是提高 MFU。
Inference decode一次生成一个 token,经常要反复读权重和 KV cache,更容易 memory-bound。

5. Einops 的意义:给 tensor 维度命名

第二讲还讲了 Einops。它不是为了少写几个字符,而是减少维度错误。Transformer 里常见 tensor 形状包含 batch、sequence、heads、hidden。如果代码里到处是 transpose(-2, -1),你很快会忘记每个维度代表什么。

# 普通写法:你必须记住 -2 和 -1 是哪两个维度
scores = q @ k.transpose(-2, -1)

# einops/einsum 写法:维度名字进入表达式
scores = einsum(
    q, k,
    "batch heads query d, batch heads key d -> batch heads query key",
)

这对自学 A1 很重要。很多 Transformer bug 不是公式错,而是 shape 错、broadcast 错、head 维度拆错、mask 维度错。维度命名是工程防线。

6. activation memory:batch size 为什么不能无限加

训练时,反向传播需要用到前向的中间结果。层数越多、batch 越大、sequence 越长,activation memory 越大。你想增大 batch size 来提高吞吐或稳定训练,但显存可能先爆。

两种常见方法:

  • Gradient accumulation:把大 batch 拆成多个 micro-batch,分别前向和反向,梯度累积起来,最后再做一次 optimizer step。它降低单次 activation 峰值,但训练 step 变成多个 micro-step。
  • Activation checkpointing:前向时只保存部分层的 activation,反向时从最近 checkpoint 重新计算缺失部分。它用额外计算换显存。

这两者都是 AI Infra 里反复出现的取舍:显存、计算和时间三者互换。没有免费午餐,只有哪个资源更紧。

闭卷计算题:10B 参数模型,用 AdamW,bf16 参数和梯度、fp32 两个 moment,不算 activation,训练状态大约多少显存?

每个参数约 12 bytes。10B × 12 = 120GB。这个数字还不含 activation、通信 buffer 和框架开销,所以单张 80GB GPU 放不下完整训练状态。

7. 这一讲应保留的判断力

  • 任何训练计划都应该先写资源账本:参数、梯度、optimizer state、activation、FLOPs、显存、带宽。
  • 训练 FLOPs 的第一版估算是 6 × tokens × parameters,它能快速给出数量级。
  • 性能瓶颈要用 arithmetic intensity 和 roofline 思路判断,不能只看 FLOPs。
  • gradient accumulation 和 activation checkpointing 是用时间或计算换显存的工具。
  • Agent 推理成本也要按资源账本看:prefill、decode、KV cache、batching、模型大小都会进账。

官方可执行 Lecture 2 Lecture 2 源码 Assignment 1 Basics Roofline 参考

03. Architectures, Hyperparameters

这一讲把 Transformer 从论文图还原成一组可实现、可算账、可替换的模块。你要带走的不是“Transformer 有 attention”,而是每个结构选择会改变表达能力、训练稳定性、显存和推理成本。

1. decoder-only LM 的最小骨架

现代语言模型大多可以先看成 decoder-only Transformer。输入是一段 token ids,输出是在每个位置预测下一个 token 的 logits。最小骨架是:

token ids → token embedding + position information → repeated Transformer blocks → final normalization → vocabulary projection → logits for next-token prediction

一个 Transformer block 内部通常有两条主路径:self-attention 和 feed-forward network。attention 让每个位置读取前面位置的信息,MLP/FFN 对每个位置做非线性变换。residual connection 让信息能跨层流动,也让梯度更容易回传。normalization 用来控制激活尺度,避免深层训练时数值发散。

2. attention 不是一个函数,而是一套张量合同

对每个 token 的 hidden state,模型先用线性层投影出 query、key、value。query 表示“我想找什么”,key 表示“我有什么可被匹配的信息”,value 表示“如果被匹配上,我提供什么内容”。在实现上它们都是 tensor,不是语义对象。

Q = X Wq K = X Wk V = X Wv scores = Q Kᵀ / sqrt(d_head) weights = softmax(mask(scores)) output = weights V

causal mask 很重要。语言模型在位置 t 预测下一个 token 时,不能偷看未来 token。mask 把未来位置的 score 变成不可选。没有 mask,训练 loss 会很好看,但模型学到的是作弊。

multi-head attention 把 hidden dimension 切成多个 head。每个 head 可以学习不同的匹配方式。实现时常见 bug 是 shape 搞错:batch, seq, heads, d_head 和 batch, heads, seq, d_head 只差一次转置,但 attention score 的语义完全变了。

3. 2024-2026 模型里的常见替换件

部件旧直觉常见现代选择为什么影响系统
NormalizationLayerNorm 放在 block 中控制尺度。RMSNorm、pre-norm、QK norm。影响训练稳定性和 kernel 形状。
ActivationReLU/GELU 给 MLP 非线性。SwiGLU、GeGLU。改变 MLP 参数量、FLOPs 和模型质量。
Position加固定或可学习位置向量。RoPE、ALiBi、RoPE scaling。影响长上下文泛化和 KV cache 使用。
Attention每个 head 都有完整 K/V。MQA、GQA、MLA。直接改变 KV cache 大小和 decode 带宽。
MLP每个 token 经过同一个 dense FFN。MoE、shared experts。改变参数量、激活计算量和跨设备通信。

4. hyperparameter 不是配置噪声

模型配置里的 d_model、层数、head 数、d_ff、vocab size、context length、batch size、learning rate、weight decay、warmup、dropout,都不是随手填的。它们共同决定三件事:模型能表达什么、训练是否稳定、资源是否够。

例如把 context length 翻倍,不只是让输入变长。attention score 矩阵的尺寸会变,activation 会变,KV cache 会变,数据 packing 会变,训练吞吐也会变。把 vocab size 变大,embedding 和输出投影都会变大。把 head 数改掉,单个 head 的维度会变,RoPE 和 attention kernel 的 shape 也会变。

自测:如果一个架构改动让 perplexity 基本不变,但 KV cache 小很多,为什么它仍然可能更适合 Agent 产品?

Agent 产品经常有长上下文和并发 decode。KV cache 小意味着同样显存能承载更多请求或更长上下文,decode 读取压力也更低。perplexity 不变时,服务成本下降本身就是收益。

5. 这一讲应保留的判断力

  • Transformer 是一组张量合同,不是一个不可拆的黑盒。
  • architecture choice 经常是质量、稳定性和系统成本的共同取舍。
  • attention 相关改动要特别看 KV cache 和长上下文成本。
  • 做 A1 时,shape 命名和测试比追论文术语更重要。

Lecture 3 slides Assignment 1 Basics Attention Is All You Need

04. Attention Alternatives and Mixture of Experts

这一讲回答一个现实问题:full attention 和 dense MLP 很强,但成本曲线不总是能接受。模型结构的很多变化,都是在试图改变“每个 token 需要多少计算、多少内存、多少通信”。

1. full attention 的成本来自哪里

标准 self-attention 需要每个 query 和所有可见 key 计算相似度。sequence length 是 S 时,score 矩阵大致是 S × S。上下文越长,这部分成本增长越快。训练时还要保存中间结果用于反向传播;推理时虽然每次只生成一个 token,但要不断读取历史 KV cache。

所以“长上下文”不是一个单纯产品开关。它会改变训练数据切分、attention kernel、KV cache 管理、显存预算和评测方式。很多 attention alternative 不是为了概念优雅,而是为了让成本曲线变得能承受。

2. 几类 attention 替代路线

路线基本想法得到什么付出什么
Local / sparse attention每个 token 只看局部窗口或少量全局位置。降低长上下文 attention 成本。远距离依赖需要额外机制。
Linear attention把 attention 写成可线性累积的形式。让序列长度成本从平方接近线性。改变 softmax attention 的表达形态。
State-space / recurrent用状态递推处理序列。长序列吞吐和 memory 可能更好。训练稳定性和能力边界需要实验证明。
Latent / compressed KV压缩 K/V 表示,减少 cache。改善 decode 和长上下文服务成本。实现复杂度和质量风险上升。

3. MoE:参数很多,但每个 token 只用一部分

Mixture of Experts 的直觉是把一个大的 MLP 拆成多个 expert。router 根据 token 表示选择少数 expert,例如 top-1 或 top-2。这样模型总参数量可以很大,但每个 token 激活的参数只是其中一部分。

dense FFN: each token → same large MLP MoE FFN: each token → router → selected experts → combine outputs

这解释了为什么 MoE 常被用来提高参数规模和能力,同时控制每 token 计算。但 MoE 没有让系统问题消失。router 可能把太多 token 分到同一个 expert,造成负载不均;expert 分布在不同 GPU 时,会产生 all-to-all 通信;训练时还需要 load balancing loss 或其他机制避免 expert 闲置。

4. Agent 视角的结构选择

Agent 工作负载和普通 chat 不太一样。它更长、更碎、更容易出现工具调用和多轮状态。attention alternative 和 MoE 对它的影响不只在 benchmark 分数上,还在服务形态上。

  • 长上下文任务会放大 attention 和 KV cache 设计差异。
  • 多轮短请求会放大 decode latency、batching 和 cache reuse。
  • MoE 模型可能有更好的能力/计算比,但 serving 需要处理路由、并发和 expert 负载。
  • 结构改变后,tool calling、格式稳定性和长任务评测必须重测。
自测:MoE 为什么经常需要 all-to-all 通信?

token 初始分布在不同 GPU 上,但 router 选择的 expert 可能在其他 GPU。系统需要把 token 表示发送到对应 expert,再把结果发回来。这个动态路由会形成 all-to-all 模式。

5. 这一讲应保留的判断力

  • attention alternative 主要是在改变长序列成本,不是简单替换公式。
  • MoE 把总参数量和每 token 计算量部分解耦,但引入路由和通信问题。
  • 结构选择要同时看训练、推理、长上下文和服务系统。
  • 没有一种架构在所有 workload 上天然胜出,必须回到资源账本和评测。

Lecture 4 slides Outrageously Large Neural Networks Switch Transformers

05. GPUs, TPUs

这一讲把“GPU 很快”拆成可操作的硬件模型。你需要知道 GPU 快在哪里,也要知道它什么时候会被数据搬运、分支、同步或内存层级拖住。

1. GPU 不是很多个强 CPU

CPU 优化的是少量复杂线程的低延迟执行。GPU 优化的是大量简单线程的总吞吐。CPU 有复杂分支预测、大 cache、乱序执行;GPU 把更多面积给算术单元和高带宽内存,通过大量线程隐藏内存等待。

这带来一个后果:GPU 喜欢形状规则、工作量大、数据访问连续、分支少的计算。大矩阵乘法非常适合 GPU。大量小算子、频繁 Python 调用、乱序访问和复杂控制流则容易浪费 GPU。

2. GPU 内存层级决定优化方向

层级特点你需要关心什么
Registers每个 thread 私有,最快,数量有限。寄存器用太多会降低 occupancy。
Shared memoryblock 内线程共享,速度快。适合 tile 复用,但要避免 bank conflict。
L2 cacheSM 间共享缓存。影响跨 block 数据复用和 cache hit。
HBM容量大、带宽高,但比片上内存慢得多。大模型权重、activation、KV cache 都在这里制造压力。
InterconnectNVLink、PCIe、InfiniBand 等。多 GPU 时,通信比单卡 HBM 更难隐藏。

3. SIMT、warp 和 coalescing

CUDA 程序写的是很多 thread,但硬件通常按 warp 执行。一个 warp 内的 thread 同步执行同一条指令。如果分支不同,有些 lane 会被 mask,warp divergence 就出现了。访存也类似:相邻 thread 访问连续地址时,硬件可以合并内存事务;地址分散时,带宽会浪费。

所以 GPU 优化经常是把计算重新排布成硬件喜欢的形状。你不是在“让代码更短”,而是在让 warp、memory transaction、shared memory 和 tensor core 都更接近理想工作状态。

4. Tensor Core 和低精度

现代 GPU 有专门做矩阵乘加的 Tensor Core。它们对 bf16、fp16、tf32、fp8 等 dtype 有不同吞吐。CS336 第二讲讲 dtype,到了这一讲要把 dtype 和硬件吞吐连起来:选 bf16 不只是省显存,也是走更快的硬件路径;选 fp32 可能更稳,但吞吐会低很多。

TPU 的设计目标类似,也是为机器学习矩阵计算提供高吞吐和高带宽互联。不同厂商硬件的编程模型不同,但资源账本相似:算力、片上内存、外部内存、互联、编译器和 runtime。

自测:为什么 GPU 利用率高,不一定说明模型训练效率好?

GPU 利用率可能只说明设备有 kernel 在跑。你还要看 MFU、内存带宽、kernel 时间分布、通信等待、数据加载和端到端 tokens/sec。忙不等于有效计算多。

5. 这一讲应保留的判断力

  • GPU 快是因为吞吐模型,不是因为单个线程更强。
  • 访存形状、分支和 tile 复用经常比源代码表面复杂度更重要。
  • Tensor Core、dtype 和矩阵形状共同决定实际 FLOP/s。
  • AI Infra 的很多优化都是减少 HBM 和跨设备数据搬运。

Lecture 5 slides CUDA Programming Guide NVIDIA FP8 primer

06. Kernels, Triton

这一讲把性能优化从“感觉慢”推进到“测出慢在哪里,然后改 kernel 或调用路径”。你不一定每天写 Triton,但要能读懂为什么 fused kernel、tiling 和 profiling 会改变模型速度。

1. PyTorch 操作背后是 kernel launch

在 PyTorch 里写 y = torch.relu(x) 看起来是一行。对 GPU 来说,它通常意味着启动一个 kernel:把输入从 HBM 读进来,计算 ReLU,再把输出写回 HBM。如果你连续写很多 elementwise 操作,每一步都可能读写一次 HBM。

naive: read x → compute A → write temp read temp → compute B → write y fused: read x → compute A and B → write y

这就是 fusion 的直觉。它不改变数学结果,但减少中间 tensor 的内存往返和 kernel launch 开销。对 memory-bound 操作,这类优化可能很明显。

2. benchmark 和 profiling 要先于优化

GPU 调用通常是异步的。你在 Python 里记录开始和结束时间,如果没有同步,测到的可能只是 CPU 提交 kernel 的时间,不是 GPU 真正执行的时间。正确 benchmark 要 warmup、同步、重复多次,并报告分布。

profiling 的目标是定位时间花在哪里。你要区分 Python overhead、kernel launch、单个 kernel 慢、数据拷贝、通信等待和内存分配。没有 profiling,优化容易变成改自己熟悉的代码,而不是改真正的瓶颈。

3. Triton 的思维单位是 program/block

Triton 让你用 Python 风格写 GPU kernel,但它不是普通 Python。你描述的是一组 program,每个 program 处理一个 block/tile。典型流程是:根据 program id 计算这一块负责的数据范围,从 HBM load 到寄存器或 SRAM 近似层级,做向量化计算,再 store 回 HBM。

这个模型适合写 fused elementwise、reduction、softmax、matmul tile、attention tile。它比手写 CUDA 更高层,但仍要求你理解 block size、mask、stride、coalescing 和 shared memory 相关问题。

4. FlashAttention 为什么是 kernel 课的核心例子

标准 attention 的问题不是公式难,而是中间矩阵太大。QKᵀ 生成 seq × seq score,再 softmax,再乘 V。如果把这些中间结果完整写回 HBM,成本会很高。FlashAttention 用 tiling 分块处理 Q、K、V,并用在线 softmax 保持数值正确,尽量不把巨大 score 矩阵写回 HBM。

这件事很适合训练系统直觉:同样的数学,内存访问计划不同,性能差很多。模型研究里的“attention”到了系统层会变成 tile size、SRAM、HBM、mask、数值稳定性和 backward pass。

自测:为什么 naive GeLU 可能比 fused GeLU 慢很多?

naive 写法可能拆成多个 kernel,每一步都读写 HBM。fused kernel 在一次 kernel 内完成多步计算,减少中间 tensor 的内存往返,也减少 launch 开销。

5. 这一讲应保留的判断力

  • kernel 优化首先是测量问题,不是写底层代码的冲动。
  • fusion 和 tiling 的共同目标是减少慢内存访问,提高数据复用。
  • Triton 把 GPU kernel 写作门槛降低了,但没有消除硬件模型。
  • FlashAttention 是“同样数学,不同数据搬运”的代表案例。

官方可执行 Lecture 6 Lecture 6 源码 Assignment 2 Systems Triton docs

07. Parallelism

单卡放不下或跑不快时,训练系统进入多 GPU。第七讲的核心是:多 GPU 不是把 GPU 数乘上去,而是把参数、梯度、optimizer state、activation、batch 和通信重新分配。

1. collective operations 是分布式训练的语言

多 GPU 程序不能只说“同步一下”。实际同步由一组 collective 操作组成:broadcast、scatter、gather、reduce、all-reduce、all-gather、reduce-scatter、all-to-all。每个操作对应不同的数据移动模式。

操作直觉训练里常见位置
all-reduce每张卡贡献一份数据,所有卡拿到聚合结果。DDP 同步梯度。
all-gather每张卡持有一片,所有卡收集完整数据。FSDP 前向前聚合参数。
reduce-scatter先聚合,再把结果分片给各卡。ZeRO/FSDP 梯度分片。
all-to-all每张卡给每张卡发送不同片段。MoE expert routing、sequence/expert parallel。

2. data parallel:最容易理解,也最容易遇到通信墙

Data Parallel 的做法是每张 GPU 放一份完整模型,处理不同 batch shard。反向传播后,每张卡得到自己的梯度;系统通过 all-reduce 求平均,让所有卡更新到同一组参数。

它的优点是简单,计算重复少,适合模型能放进单卡的情况。问题是每一步都要同步梯度,模型越大,通信越重。batch 太小,计算时间不够长,通信就更难隐藏。

3. FSDP/ZeRO:把训练状态切开

当完整模型、梯度和 AdamW state 放不进单卡时,就要分片。ZeRO 和 FSDP 的思路是把参数、梯度、optimizer state 分散到多张卡上。前向或反向需要某层参数时,再 all-gather;梯度出来后用 reduce-scatter 分回各卡。

这样能显著降低单卡显存压力,但通信模式更复杂。它把显存问题换成通信和调度问题。什么时候 gather、什么时候释放、能不能和计算重叠,都会影响吞吐。

4. tensor parallel 和 pipeline parallel

Tensor Parallel 把单层里的矩阵按维度切到多张卡。例如一个大 matmul,列切或行切后由多卡共同完成,再通过 collective 合并结果。它需要很快的互联,常用于节点内 GPU。

Pipeline Parallel 把模型层切成多个 stage。前几层在一组 GPU,后几层在另一组 GPU。它降低每个 stage 持有的层数,但会有 bubble:某些阶段等待输入或等待反向。micro-batch 可以让 pipeline 更满,但也增加调度复杂度。

自测:DDP 和 FSDP 的最核心差别是什么?

DDP 通常每张卡持有完整参数,只同步梯度。FSDP/ZeRO 会把参数、梯度或 optimizer state 分片,前向和反向时按需聚合,从而降低单卡显存。

5. 这一讲应保留的判断力

  • 多 GPU 训练是在显存、计算和通信之间重新分摊成本。
  • DDP 简单,但要求单卡能放下模型和训练状态。
  • FSDP/ZeRO 省显存,但增加 all-gather 和 reduce-scatter。
  • tensor/pipeline/expert parallel 要和硬件拓扑一起设计。

官方可执行 Lecture 7 Lecture 7 源码 Assignment 2 Systems ZeRO paper

08. Parallelism at Scale

第七讲讲了并行策略,第八讲把它放到更大的训练集群里。真实大训练不是单一并行方法,而是多种并行、通信层级、checkpoint、故障恢复和作业调度的组合。

1. 先看硬件拓扑,再谈并行策略

一台 8 GPU 机器内部可能有 NVLink/NVSwitch,跨机器可能是 InfiniBand 或 RoCE。节点内带宽和延迟通常比节点间好得多。并行策略如果忽视拓扑,就会把高频通信放到慢链路上。

经验上,tensor parallel 这类频繁同步的并行更适合节点内高速互联;data parallel 可以跨更多节点,因为每 step 同步一次梯度;pipeline parallel 的通信相对局部,但要处理 bubble。MoE 的 all-to-all 对网络压力更特殊,需要单独设计 expert 放置和负载均衡。

2. 组合并行:从二维到多维

大模型训练常常同时使用 data parallel、tensor parallel、pipeline parallel、sequence parallel、expert parallel。每一种并行切的是不同维度。你可以把它理解成一个多维网格:某些 GPU 共同负责一层的矩阵,某些 GPU 负责不同层,某些 GPU 负责不同 batch shard,某些 GPU 负责不同 expert。

组合越多,工程复杂度越高。每个维度都会引入自己的 collective、同步点、内存布局和 failure mode。一个训练 recipe 成功,不只是数学配置成功,也是系统配置成功。

3. checkpoint 和故障恢复不是后勤问题

长训练会失败。GPU、网络、存储、驱动、作业调度都可能出问题。checkpoint 决定失败后损失多少计算,也决定训练期间要花多少 I/O。checkpoint 太频繁,会拖慢训练;太少,失败一次损失巨大。

分布式 checkpoint 还要处理 sharded state:参数、optimizer state、random state、data loader 位置、scheduler 状态都要能恢复。否则恢复后 loss 曲线可能变,或者数据重复/跳过,实验不可复现。

4. 通信计算重叠

多 GPU 训练的理想状态是计算某层时,同时通信另一层的梯度或参数。DDP 会在反向过程中按 bucket 触发梯度 all-reduce,FSDP 会尝试提前 gather 下一层参数。重叠做得好,通信时间被藏在计算下面;做不好,GPU 会在同步点空等。

这也是为什么 profiling 多卡训练比单卡复杂。你要看 kernel timeline、NCCL timeline、stream、bucket 大小、拓扑和 straggler。吞吐下降可能不是算子慢,而是一张卡慢导致所有卡等。

自测:为什么几千张 GPU 的训练不能只报 GPU 数?

GPU 数只说明资源规模。真正决定训练效率的是拓扑、并行切分、通信重叠、checkpoint、故障恢复、数据加载和 MFU。GPU 多但网络或调度差,吞吐会很低。

5. 这一讲应保留的判断力

  • 大训练要先看拓扑和通信层级,再选并行组合。
  • 组合并行是在多个维度切模型和数据,复杂度会快速上升。
  • checkpoint、恢复和可复现性是训练系统的一部分。
  • 多卡性能诊断要同时看计算、通信和 straggler。

Lecture 8 slides Assignment 2 Systems How to Scale Your Model

09. Scaling Laws

Scaling law 的作用不是给大模型套神秘曲线,而是用小实验降低大训练的错误成本。第九讲要你学会把“训练多大模型、用多少 token、花多少 compute”变成可估算的工程决策。

1. 为什么需要 scaling law

大模型训练贵,不能靠一次大 run 试错。你真正想知道的是:给定计算预算 C,应该选多大的模型 N,喂多少数据 D,用什么学习率和训练 recipe,最终 loss 大概会到哪里。

最粗的训练 compute 关系是第二讲已经见过的:

C ≈ 6 × N × D

如果 C 固定,N 和 D 就在抢预算。模型太大,token 不够,模型会 undertrained;模型太小,token 再多也可能容量不够。Scaling law 试图用一组小规模实验拟合这个关系,再外推到目标预算。

2. ISOFLOP 的直觉

一种常见做法是画 ISOFLOP 曲线:固定某个 compute budget,训练不同模型大小和 token 数的组合,找 loss 最低的点。对多个预算重复这个过程,就能观察最优模型大小如何随 compute 增长。

budget C1: try N1,D1 / N2,D2 / N3,D3 → best N* budget C2: try N1,D1 / N2,D2 / N3,D3 → best N* budget C3: try ... fit: compute budget → good N and D

Chinchilla 的结论常被简化成“每个参数约 20 个 token”。这只是一个有用锚点,不是永恒定律。数据质量、模型结构、optimizer、上下文长度、重复数据和推理成本都会改变最佳点。

3. scaling recipe 比单点超参更重要

Scaling law 不是只拟合一条 loss 曲线。更完整的做法是设计一个 scaling recipe:模型变大时,宽度、深度、batch size、learning rate、warmup、训练 tokens、正则和初始化如何一起变化。你要评估的是这条 recipe 是否可预测。

如果小模型和大模型的超参不能迁移,小实验就没有意义。muP 等参数化方法想解决的正是这个问题:让某些超参在 scale 改变时更稳定。对工程团队来说,可预测有时比局部最优更重要,因为它能减少昂贵训练失败。

4. scaling law 的边界

Scaling law 通常预测 loss,不直接预测产品体验。loss 更低不一定意味着 tool calling 更稳、coding agent 更强或用户更满意。它也可能被数据污染、重复样本、评测选择和训练 recipe 改变。外推距离越大,风险越大。

因此 scaling law 应被看作预算决策工具。它回答“在这类数据和 recipe 下,大概怎么分配 compute 更合理”,不回答“哪个模型有智能”这种模糊问题。

自测:为什么不能只用一次 10B run 来决定 100B run 的训练配置?

单次小 run 不能分离模型大小、token 数、学习率、batch 和数据质量的影响。Scaling 需要多个规模和多个配置点,才能判断趋势是否稳定并支持外推。

5. 这一讲应保留的判断力

  • Scaling law 是昂贵训练前的风险控制工具。
  • 固定 compute 下,模型大小和训练 token 数存在取舍。
  • 预测的是某个 recipe 的行为,不是所有模型的普遍命运。
  • 产品能力还需要 task-level evaluation,不能只看 loss。

Lecture 9 slides Assignment 3 Scaling Kaplan scaling laws Chinchilla

10. Inference

训练结束后,模型还不能自动成为产品。第十讲讨论 inference:给定 prompt 生成 token。对 Agent 开发者来说,这讲很重要,因为 Agent 会把推理成本、延迟和上下文管理放大。

1. prefill 和 decode 是两种不同工作负载

LLM 推理通常分两段。prefill 处理用户给出的 prompt,所有 prompt token 已知,可以并行计算每个位置的 hidden state,并建立 KV cache。decode 每次生成一个新 token,新 token 生成后才知道下一步输入。

阶段输入特点常见瓶颈
Prefill完整 prompt tokens。并行度高,像训练前向。长 prompt 的 attention 和 activation。
Decode已经生成的上下文 + 当前 token。逐 token 串行。权重读取、KV cache 读取、batch 调度。

这就是为什么长 prompt 会影响 Time To First Token,而长输出会影响总延迟和吞吐。Agent trace 很长时,prefill 会变重;Agent 反复思考或输出很多步骤时,decode 会变重。

2. KV cache 是推理系统的核心状态

没有 KV cache,模型每生成一个 token 都要重新计算全部历史 token 的 K/V。KV cache 保存每层每个历史 token 的 key 和 value,下一个 token 只需要追加新的 K/V,并读取历史 K/V 做 attention。

KV cache 省计算,但占显存。它随 batch size、sequence length、layer 数、head 数、head dimension 和 dtype 增长。GQA/MQA/MLA 等 attention 变体的一个重要收益,就是减少 K/V 的存储和读取。

3. serving 指标要分开看

推理系统常见指标有 TTFT、TPOT、latency、throughput、tokens/sec、request/sec、显存占用和成本。它们经常互相冲突。continuous batching 可以提高吞吐,但可能增加等待。更大的 batch 可以提高硬件利用率,但也会增加 KV cache 压力和尾延迟。

对用户交互而言,TTFT 和流式输出的稳定性很重要。对离线评测或 RL rollout 而言,总吞吐可能更重要。把这两类 workload 混在一个指标里,会得到错误结论。

4. 几种加速方向

  • 模型变小:剪枝、蒸馏、量化、MoE 路由、选择更小模型。
  • kernel 更好:FlashAttention、fused kernels、quantized GEMM、paged KV。
  • 调度更好:dynamic batching、continuous batching、prefix cache、请求优先级。
  • 生成更少:上下文压缩、工具结果裁剪、早停、speculative decoding。

Speculative decoding 值得单独记:小 draft model 先生成多个 token,大模型并行验证。接受的 token 可以一次推进多步,同时保持目标模型分布。它不是简单换小模型,而是用小模型减少大模型串行 decode 次数。

自测:为什么 Agent 比普通 chat 更容易把推理成本打爆?

Agent 通常有多轮工具调用、长 trace、失败重试、多样本搜索和评测循环。每一步都会增加 prompt tokens、generated tokens、KV cache 或等待时间,所以单次模型调用成本会被链路放大。

5. 这一讲应保留的判断力

  • 推理不是训练的附属品,它有自己的瓶颈和指标。
  • prefill 和 decode 要分开诊断。
  • KV cache 是长上下文和并发服务的主要状态。
  • Agent 系统要把模型调用次数、上下文长度和输出长度纳入设计。

官方可执行 Lecture 10 Lecture 10 源码 vLLM Speculative decoding

11. Scaling in Practice

第九讲讲 scaling law 的概念,第十一讲讲它为什么难落地。实践里,外推失败常常不是公式错,而是小模型实验、参数化、optimizer、batch、数据和评测口径没对齐。

1. 小规模实验必须像大规模实验

如果你希望小模型实验预测大模型,二者必须属于同一条 recipe。数据来源、tokenizer、architecture 比例、optimizer、schedule、batch 规则、训练时长和评测集都要可比。否则你拟合的是实验噪声。

一个常见错误是小模型调参很随意,大模型训练又换了数据、换了 normalization、换了 batch 和 learning rate。这样小实验最多说明“小模型这样跑还行”,不能支撑大训练下注。

2. hyperparameter transfer 是实践核心

模型变宽、变深、变长以后,激活尺度和梯度尺度可能改变。学习率在小模型上合适,不代表大模型上稳定。muP 等方法希望让某些超参在宽度变化时更可迁移。它不是魔法,而是让实验设计更像“同一族模型”。

实践里你会关心 loss curve 是否平滑、是否出现 spike、不同规模是否有相似趋势、学习率是否能从小规模迁移。一个可预测 recipe 的价值很大,因为它能减少大训练中途崩掉或训练完才发现配置差的风险。

3. batch size 和 learning rate 不只是优化器问题

batch size 影响统计效率、硬件利用率、activation memory 和通信。learning rate schedule 影响收敛速度和稳定性。warmup 太短可能早期不稳,decay 策略影响后期 loss。WSD、cosine 等 schedule 不是装饰,它们改变训练 compute 的使用方式。

大 batch 还会遇到 critical batch size:超过某个点后,继续增大 batch 对训练效率的收益下降。系统上大 batch 更容易喂饱硬件,优化上却可能浪费样本效率。训练 recipe 必须同时看这两边。

4. 开源模型 recipe 的价值

开放模型论文和训练报告最有价值的部分,常常不是最终 benchmark,而是数据混合、训练 tokens、学习率、batch、硬件、失败记录和 ablation。CS336 会反复引用 open models,就是因为这些资料让课程可以讲真实模型工程,而不只能猜闭源模型。

读模型报告时,建议按固定表格摘录:模型大小、tokens、context length、optimizer、lr schedule、batch、数据来源、训练硬件、推理结构、评测。这样你能比较 recipe,而不是只比较名称。

自测:为什么“小模型最佳 learning rate”不能直接搬到大模型?

宽度、深度、初始化和 normalization 会改变激活与梯度尺度。没有稳定参数化或迁移规则时,小模型的学习率可能让大模型不稳定或训练效率差。

5. 这一讲应保留的判断力

  • 实践 scaling 的单位是 recipe,不是单次 run。
  • 超参迁移失败会让小实验失去预测力。
  • batch 和 learning rate 同时影响优化、显存和硬件利用率。
  • 开放训练报告要按工程字段读,不要只看模型名和榜单。

Lecture 11 slides Assignment 3 Scaling muP

12. Evaluation

Evaluation 决定你会优化什么,也决定你会忽略什么。第十二讲要你把“模型好不好”拆成多个评测层次:预训练 loss、考试题、开放回答、代码任务、Agent 任务和真实产品数据。

1. perplexity 有用,但它不是全部

Perplexity 来自 next-token prediction。它衡量模型给真实文本分配概率的能力。预训练和 scaling 阶段,perplexity 很有用,因为它平滑、便宜、可以跨规模比较。

但 perplexity 不等于真实任务质量。一个模型在网页文本上 perplexity 更低,不一定更会调用工具、更会写你的业务代码、更会遵守格式。数据分布不一致时,perplexity 还可能误导你。

2. benchmark 类型和盲区

评测类型例子适合看什么盲区
Exam QAMMLU、GPQA、HLE。知识和推理题。可能离真实使用很远,也有污染风险。
Chat evalArena、AlpacaEval。开放回答偏好。受 judge、长度和风格影响。
Code evalHumanEval、SWE-bench。代码生成和修复。脚手架、环境和测试质量影响很大。
Agent evalTerminal-Bench、浏览器任务。模型加工具后能否完成任务。评估的是模型、工具、状态和执行环境的组合。

3. contamination 和生态有效性

训练数据可能包含 benchmark 题目或相似内容,这会让模型看起来更强。去重、私有评测集和时间切分可以降低污染风险,但不能完全消除。尤其是网页、GitHub、论坛和论文数据都可能进入训练语料。

另一个问题是生态有效性:评测任务是否像真实任务。很多用户任务有上下文、工具权限、文件系统、网络、失败恢复和人工反馈。单轮选择题无法覆盖这些条件。Agent 产品应该建立自己的离线 eval,并持续和真实用户失败样本对齐。

4. LM judge 的使用边界

用另一个模型当 judge 很方便,尤其适合开放回答。但 LM judge 会有偏好:更长答案、某种格式、某类措辞、和 judge 同源模型相似的输出,都可能被偏爱。它还可能被 prompt 注入或标准不清影响。

可验证任务应优先使用外部 verifier:代码跑测试、数学答案比对、SQL 结果校验、工具副作用检查。开放任务再用人类偏好或 LM judge 补充。不要把 judge 分数当成唯一真相。

自测:为什么 Agent eval 不能只评模型本身?

Agent 成败取决于模型、prompt、工具 schema、记忆、执行环境、错误恢复、权限和评测器。换一个脚手架,同一模型表现可能不同,所以评估对象是整个系统。

5. 这一讲应保留的判断力

  • 评测定义优化方向,错误评测会让工程走偏。
  • perplexity、benchmark、产品指标各自回答不同问题。
  • 污染和生态有效性是评测可信度的两个大问题。
  • Agent 需要自己的任务集、失败样本库和回归测试。

官方可执行 Lecture 12 Lecture 12 源码 Assignment 3 Scaling SWE-bench

13. Data Sources and Datasets

第十三讲把模型能力拉回数据。预训练数据不是“网上文本”四个字,它是一条从 raw crawl 到训练 shard 的数据系统。模型会学到什么,首先取决于你让它反复预测什么。

1. 原始数据不是训练数据

网页抓取下来通常是 HTML、模板、导航、广告、脚本、重复内容、乱码、表格、评论、样式和正文混在一起。PDF、代码仓库、论坛、书籍、论文、对话数据也都有各自格式。把这些东西变成训练文本,需要 extraction、cleaning、filtering、deduplication、mixing 和 sharding。

这和普通后端数据管线类似,但目标不同。普通业务管线常常追求字段准确;预训练数据管线追求让模型在海量 token 上学到有用分布,同时避免污染、违法、过多重复和低质量内容。

2. 数据来源决定能力,也决定风险

来源可能带来什么主要风险
Common Crawl / Web覆盖面广,多语言、多主题。噪声、重复、垃圾内容、版权和安全问题。
Wikipedia / books较稳定的知识和长文本。覆盖有限,风格不等于对话或任务。
GitHub / code代码生成、API、工程模式。许可证、低质量仓库、泄漏 secrets、重复 fork。
arXiv / papers技术和数学文本。PDF 抽取质量、公式处理、领域偏差。
Dialog / agent traces指令跟随、工具调用、任务执行。隐私、格式污染、低质量示范会教坏模型。

3. pretraining、mid-training、post-training 数据不同

Pretraining 数据大而杂,目标是让模型学习广泛语言、知识和模式。Mid-training 常常更高质量、更接近目标能力,例如长上下文、代码、数学或特定领域。Post-training 数据更小,但离产品行为近,例如 instruction-response、preference、tool use trace、reasoning trajectory。

这三类数据不能混为一谈。预训练解决“模型知道世界和语言”;post-training 解决“模型按产品期望行动”。Agent 能力尤其依赖 post-training 数据和外部脚手架:工具调用格式、错误恢复、观察结果解释、状态更新,都要在数据或训练目标里出现。

4. 数据许可和可追溯性

模型数据不是纯技术问题。网页、书籍、代码、论坛和对话都有许可、隐私和合规边界。公开模型报告里越来越多会说明数据来源、过滤策略和许可处理,但细节仍经常不足。工程上至少要能追溯:某个训练 shard 来自哪里,经过哪些过滤,是否包含敏感数据,是否可能污染评测集。

自测:为什么 Common Crawl 不能直接当高质量训练文本?

它是网页原始抓取,包含导航、广告、模板、重复、乱码、垃圾内容和潜在有害文本。必须先做正文抽取、过滤、去重和质量控制。

5. 这一讲应保留的判断力

  • 数据管线本身就是模型能力的一部分。
  • 不同数据来源带来不同能力,也带来不同法律和质量风险。
  • pretraining、mid-training、post-training 服务于不同目标。
  • Agent traces 是高价值数据,但也更容易包含隐私、工具副作用和错误示范。

官方可执行 Lecture 13 Lecture 13 源码 Assignment 4 Data The Pile

14. Filtering, Deduplication, Mixing, Synthetic Data

第十四讲进入数据加工细节。它回答的是:给定一堆 raw text,怎样决定哪些 token 值得让模型学习,哪些 token 会浪费 compute,哪些 token 会污染评测或损害产品行为。

1. filtering:选择你愿意让模型模仿的分布

Filtering 可以是规则、分类器、语言模型 judge 或组合系统。常见过滤包括语言识别、质量分类、有害内容过滤、PII 检测、代码许可检查、文档长度和重复模板过滤。每个 filter 都有误杀和漏杀。

高质量 filter 不是越严格越好。过严会丢掉少数语言、边缘领域、非标准表达和真实用户风格;过松会引入垃圾内容、模板噪声和不良行为。Filtering 实际上是在定义模型的训练分布。

2. deduplication:省 compute,也保护评测

重复数据会让训练浪费在同一内容上,也会增加记忆风险。Exact dedup 能删除完全相同文档,near dedup 需要 MinHash、LSH 或 embedding 相似度等方法。代码数据还要处理 fork、vendored dependencies 和生成文件。

去重对评测也重要。如果 benchmark 题目或相似答案出现在训练集中,模型可能靠记忆拿高分。训练集和测试集之间的去重,是评测可信度的一部分。

3. data mixing:比例就是训练目标

数据来源清洗完后,还要决定混合比例。代码、数学、网页、书籍、对话、多语言、长上下文数据各占多少?小而高质量的数据是否重复采样?某些低质量但覆盖面广的数据是否降权?这些选择会改变模型能力。

Data mixing 的难点在于目标不止一个。你可能希望模型会代码、会中文、会数学、会聊天、会长上下文,但每类数据都会占 token 预算。固定 compute 下,喂一种数据就少喂另一种。

4. synthetic data:便宜扩展,也可能自我污染

Synthetic data 可以把低质量文本改写成更适合训练的格式,也可以生成数学题、代码任务、工具调用轨迹或偏好样本。它的优势是可控、便宜、贴近目标任务。风险是模型生成数据会带来偏差、错误和风格收缩。

对 Agent 来说,synthetic traces 很有吸引力:可以批量生成任务、工具调用和错误恢复。但这些 trace 必须被 verifier 或真实环境检查。否则模型会学到看起来像任务执行、实际不可运行的轨迹。

自测:为什么去重既能省 compute,也能提高评测可信度?

重复样本会让训练反复学习同一内容,浪费 token 预算。训练集和测试集重复还会造成污染,让模型看似泛化,实际可能是记忆。

5. 这一讲应保留的判断力

  • Filtering、dedup 和 mixing 是模型训练目标的一部分。
  • 每个数据 filter 都有误杀和漏杀,必须用样本审计。
  • 数据混合比例决定能力取舍,不能只追总 token 数。
  • Synthetic data 需要 verifier 或真实任务闭环,否则容易制造漂亮噪声。

官方可执行 Lecture 14 Lecture 14 源码 Assignment 4 Data

15. Mid/Post-training, SFT/RLHF

前面的大部分内容都在讲 base model:用大量 token 训练下一个 token 预测。第十五讲开始回答另一个问题:一个会续写文本的模型,怎样变成会按指令行动的 assistant 或 Agent。

1. base model 不天然知道产品行为

Base model 学的是训练语料里的文本分布。给它一个问题,它可能回答,也可能续写问题、换风格、编故事、输出不符合格式的内容。它没有天然的“应该帮助用户完成任务”这个目标。

Supervised Fine-tuning 用 instruction-response 数据继续训练模型。输入是指令或对话上下文,目标是人类示范答案。SFT 的作用是让模型模仿期望行为:回答问题、遵守格式、拒绝某些请求、使用工具调用语法、保持对话角色。

2. SFT 的边界

SFT 能显著改变模型“像不像 assistant”,但它不一定让模型推理更强。模型只是模仿示范数据。示范里有严谨推理、工具使用、错误恢复,它才有机会学到;示范只是漂亮话,它就会学漂亮话。

这对 Agent 很现实。很多 Agent 能力不是 prompt 写得玄,而是数据里有任务轨迹:怎么读文件、怎么计划、怎么调用工具、怎么解释错误、怎么验证结果、什么时候停止。如果 SFT 数据没有这些结构,模型很难稳定执行。

3. RLHF:当评价比示范容易

有些任务很难写出唯一正确答案,但人能比较两个答案哪个更好。RLHF 的基本流程是:让模型生成多个回答,收集人类偏好,训练 reward model 或直接用偏好优化,再更新 policy,让模型更倾向于高分回答。

prompt → sample responses → human / model preference → reward model or preference loss → update policy

PPO 是早期 RLHF 常用算法,但实现复杂、训练不稳定、系统成本高。DPO 用偏好数据直接优化 policy,省掉显式 reward model 和在线 RL 的一部分复杂度。不同算法背后共同的问题是:奖励信号是否可信,模型是否在 reward 上投机。

4. mid-training 和 post-training 的数据配方

Mid-training 常用于把模型从通用预训练推向更高质量或更贴近目标能力的数据,例如代码、数学、长上下文、特定语言。Post-training 更靠近产品:SFT、preference、tool use、safety、reasoning traces。

这解释了为什么公开模型报告里 post-training 细节常常最少,但产品差异很大。Base model 的能力是一部分,post-training 数据和评测闭环会决定模型最终行为。

自测:为什么 SFT 后模型更像 assistant,但不一定推理更强?

SFT 学的是示范答案分布。它能学会语气、格式和指令跟随;如果示范数据没有覆盖长推理、工具使用或验证步骤,模型未必获得更强任务能力。

5. 这一讲应保留的判断力

  • Base model 学文本分布,assistant 行为需要 post-training。
  • SFT 是模仿示范,不是自动获得深推理。
  • Preference/RLHF 在“评价比生成容易”时有价值。
  • Agent 的 tool use 和错误恢复能力依赖数据、训练目标和脚手架共同塑造。

Lecture 15 slides Assignment 5 Alignment InstructGPT Direct Preference Optimization

16. Post-training: RLVR

RLVR 指 Reinforcement Learning with Verifiable Rewards。它和普通偏好训练的差别是:奖励不主要来自“看起来更好”,而来自可验证结果,例如数学答案、代码测试、形式化检查或工具执行结果。

1. 为什么 reasoning model 适合可验证奖励

很多推理任务有明确答案。数学题可以比对最终值,代码题可以跑单元测试,定理可以交给 proof checker,数据库任务可以校验查询结果。相比开放聊天,这些任务的奖励更客观,也更适合 RL。

RLVR 的基本流程是:对同一个 prompt 采样多个 response 或 trajectory,用 verifier 打分,把高分样本和低分样本之间的差异转成 policy 更新。模型会被直接推向“能通过验证器”的行为。

2. GRPO 的直觉

GRPO(Group Relative Policy Optimization)常见于 reasoning RL 讨论。它的核心直觉是对同一题采样一组回答,用组内相对奖励估计哪个回答更好。这样可以减少对单独 value model 的依赖。

for one prompt: sample response_1 ... response_k score each response with verifier normalize rewards within the group increase probability of better responses decrease probability of worse responses

这只是直觉。真实实现还要处理 KL penalty、advantage normalization、mask、micro-batch、采样温度、长输出、off-policy 数据和系统吞吐。A5 的价值就在于把这些细节拉回代码。

3. RLVR 的系统成本

RLVR 不是只多一个 loss。它需要大量采样,采样本身就是 inference;还要跑 verifier、收集轨迹、计算 reward、再训练 policy。训练过程会在 inference 和 training 之间来回切换,系统复杂度比 SFT 高很多。

此外,on-policy 程度和系统效率会冲突。越想用最新 policy 采样,系统越难批量化和缓存;越想提高吞吐,样本可能越旧。大规模 RL 训练要在这个取舍里工作。

4. reward hacking 对 Agent 更危险

Verifier 定义了模型会优化什么。代码测试不完整,模型可能写出只过测试的补丁;工具环境不隔离,模型可能修改评测脚本;数学答案只看最终值,模型可能学会猜格式。RL 会放大奖励设计的漏洞。

Agent 场景天然适合 RLVR,因为环境可执行。但也天然危险,因为工具有副作用。好的训练和评测环境需要权限隔离、隐藏测试、日志审计和回滚。

自测:为什么 coding agent 比普通聊天更适合 RLVR?

代码任务有外部验证器:编译、测试、lint、运行结果和隐藏用例。奖励比“回答看起来好不好”更客观,可以直接优化任务完成率。

5. 这一讲应保留的判断力

  • RLVR 的价值来自可验证奖励,不是来自 RL 这个词本身。
  • GRPO 用组内相对奖励训练 reasoning 行为,但实现细节很多。
  • RLVR 系统需要大量 inference、verifier 和训练闭环。
  • 奖励设计不严,模型会优化漏洞而不是任务。

Lecture 16 slides Assignment 5 Alignment DeepSeekMath / GRPO

17. Alignment: Multimodality

第十七讲把文本模型扩展到图像、视频和音频。核心问题仍然是表示:Transformer 吃的是 token 或向量序列,非文本信号必须先被转换成它能处理的形式。

1. 图像如何进入语言模型

常见做法是用视觉 encoder 把图像切成 patch 或特征,再通过 projector 映射到语言模型的 hidden space。语言模型看到的是一串视觉 token 或视觉特征,加上文本 token。LLaVA 这类路线就是把视觉 encoder、projection layer 和 LLM 连接起来,再用图文指令数据训练。

CLIP/SigLIP 这类模型提供图文对齐能力:让图像表示和文本表示在同一个空间里接近。它们不直接等于多模态 assistant,但经常是视觉理解组件的基础。

2. 分辨率、patch 和 token 预算

图像越大,patch 越多,视觉 token 越多。高分辨率能保留细节,但会增加 attention、显存和延迟。AnyRes、裁剪、多尺度、局部放大等方法都在处理这个问题:什么时候看全图,什么时候看局部,什么时候牺牲细节换成本。

这对 UI Agent 特别重要。截图里真正有用的信息可能只在一个按钮、表格单元格或错误提示里。整张高分辨率截图直接送入模型很贵,也不一定更准。更好的系统会结合 OCR、布局解析、局部裁剪和交互状态。

3. 视频和音频更像序列问题

视频比图像多时间维度。帧数、分辨率和采样率都会增加 token 或 feature 数量。音频也需要切成帧或离散 token。模型要处理时间顺序、跨帧变化和同步信息。多模态系统的成本很容易因为输入长度失控。

所以多模态不是“给 LLM 加一个图片接口”。它会改变 tokenizer/encoder、上下文长度、缓存、数据管线、评测任务和产品交互。

4. 统一 token 路线

有些模型尝试把图像也离散成 token,统一用 autoregressive modeling 处理文本和图像。这类路线的吸引力是接口统一:不同模态都变成 token 序列。但它也会带来长序列成本、离散化损失和生成质量问题。

无论采用哪条路线,多模态能力都不是纯架构问题。图文数据、视频数据、指令数据、对齐数据和评测集同样重要。模型会不会读表格、看 UI、理解图表,很大程度取决于训练数据里有没有这样的任务。

自测:为什么高分辨率图片会变成推理系统问题?

高分辨率会产生更多 patch/token 或更大的视觉特征,增加计算、显存、attention 和上下文成本。系统必须在细节保留和资源预算之间取舍。

5. 这一讲应保留的判断力

  • 多模态的入口是表示转换:非文本信号要变成 token 或向量序列。
  • 分辨率和采样率是推理成本参数,不只是质量参数。
  • UI/文档/视频 Agent 需要输入裁剪、结构解析和任务评测。
  • 多模态能力同样依赖数据和 post-training。

官方可执行 Lecture 17 Lecture 17 源码 CLIP LLaVA

18. Guest Lecture: Daniel Selsam

官方 schedule 把 Daniel Selsam 的 guest lecture 放在课程末尾,但当前公开页面没有稳定讲义链接。这里不编造讲义内容,只说明它在 CS336 知识链里的位置,以及你应该带着哪些问题去补这类前沿实践材料。

1. guest lecture 在课程中的作用

前 17 讲已经把语言模型从 tokenizer、architecture、training systems、scaling、data、evaluation 到 post-training 串起来。Guest lecture 通常承担另一个角色:把这些基础件放到真实研究或产业实践里,看哪些环节在现实中最脆弱。

自学时不应该把 guest lecture 当作必备基础。它更像一个检查点:你是否已经能听懂实践者说的瓶颈,例如数据质量、训练稳定性、评测污染、inference 成本、RL 系统吞吐或组织协作问题。

2. 应该带着什么问题听

  • 真实模型研发中,返工最多的是数据、训练系统、评测还是 post-training?
  • 小规模实验有哪些结论能迁移到大规模,哪些不能?
  • 训练失败通常怎样被发现:loss spike、eval 退化、样本质量、系统错误,还是人工观察?
  • Agent 或 reasoning 任务里,评测器和奖励设计怎样避免投机?

3. 这一讲应保留的判断力

完整学习 CS336,不等于每讲都有同等公开材料。对资料缺口诚实标注,比把未知内容写成摘要更有价值。后续如果官方补充 slides 或录播,这一章应该按原材料更新。

自测:如果只能问 guest lecturer 一个问题,问什么最能补你的工程认知?

建议问:在真实模型研发中,哪类证据最能提前发现大训练或 post-training 会失败?这个问题会逼对方给出可执行的诊断信号,而不是泛泛经验。

CS336 官方 schedule

19. Guest Lecture: Dan Fu

最后一讲同样是 guest lecture,且与 A5 截止接近。课程结构暗示:CS336 的最终整合点是 post-training、systems、data 和 evaluation 的闭环,而不是某个单独算法。

1. 把全课收束成一张工程图

学完 CS336,你应该能把一个模型产品拆成下面这些问题:

输入和协议:tokenizer, special tokens, context format 模型结构:attention, MLP, normalization, position, MoE 训练资源:FLOPs, memory, optimizer state, activations, parallelism 数据系统:sources, filtering, dedup, mixing, synthetic traces 评测系统:perplexity, task eval, agent eval, contamination checks 推理系统:prefill, decode, KV cache, batching, latency, throughput 行为塑形:SFT, preference, RLVR, multimodality, safety

这张图比背术语更重要。以后你听到“我们要换模型”“要做长上下文”“要训练 agentic model”“要降低推理成本”,都可以把问题放回这张图,追问缺少哪类证据。

2. 下一步该深入哪里

如果你做 Agent 开发,最值得继续深入的顺序通常是:Inference、Evaluation、Post-training Data、Systems。原因很直接:它们离产品成本和能力闭环最近。你不一定要马上写分布式训练框架,但应该能设计任务评测、理解推理瓶颈、知道什么样的 trace 对训练有价值。

如果以后要转 AI Infra,CS149 可以补并行计算和硬件性能模型,MIT 6.5940 可以补模型压缩、量化、TinyML 和高效 LLM 部署。它们不是和 CS336 并列的三份资料,而是同一张能力地图的不同切面。

3. 结课自检

  • 能不能解释 tokenizer 为什么影响上下文成本?
  • 能不能手算一个训练计划的 FLOPs 和显存粗账?
  • 能不能说明 FlashAttention 为什么减少 HBM 往返?
  • 能不能区分 DDP、FSDP、tensor parallel 和 pipeline parallel?
  • 能不能解释 scaling law 的用途和边界?
  • 能不能为一个 Agent 产品设计离线 eval 和失败样本库?
  • 能不能说明 SFT、DPO/RLHF、RLVR 分别依赖什么数据和奖励?
闭卷复述题:用 3 分钟解释 CS336 的完整知识链。

参考答案:原始数据经清洗、去重和混合后被 tokenizer 编成 token;Transformer 在 next-token loss 下训练,训练成本由 FLOPs、显存、activation、optimizer state 和并行通信决定;scaling law 用小实验规划大训练;evaluation 定义优化方向并检查污染和真实任务;inference 把模型变成服务,需要处理 prefill、decode、KV cache 和 batching;post-training 用 SFT、偏好或可验证奖励把 base model 塑造成 assistant、reasoning model 或 Agent。

CS336 官方 schedule Stanford CS336 GitHub CS336 YouTube playlist

总地图:语言模型训练栈

Raw Data网页、代码、书籍、对话、题目、图文数据。问题是版权、质量、去重、覆盖面。
TokensTokenizer 把字节/文本压成整数序列。上下文长度和词表稀疏性从这里开始。
TransformerEmbedding、Attention、MLP、Norm、位置编码。A1 让你亲手搭出骨架。
Training SystemGPU、kernel、并行、checkpoint、optimizer state。A2 解释为什么钱花在这里。
Scaling & Eval用小实验预测大训练,用评测定义“好”。A3 和 Lecture 12 接住决策问题。
Post-trainingSFT、RLHF、RLVR、GRPO、多模态。把 base model 变成能做任务的模型。

站在 Agent 开发者视角,最该抓住的一点是:Agent 产品里的“模型能力”不是一个黑盒参数。它受到 tokenizer、数据分布、训练目标、推理系统、评测口径和 post-training 的共同约束。你在做 tool use、long context、reasoning、SSE 输出或评测时,都会撞到这些底层事实。

课程模块

速查与进度卡片

这里用于快速回忆和勾选进度。每张卡片只保留问题、知识链路、工程判断和轻练习;需要系统阅读时,以上方“完整教材正文”为准。

A1-A5 作业地图

如果你没有时间完整做作业,至少要按下面的“轻量路径”读测试和接口。测试名会告诉你课程真正希望你掌握什么,而不只是 lecture 里提到了什么。

和 Agent 开发的关系

你不需要立刻成为训练工程师

如果你的主业是 Agent 应用,最常见的误区是把模型能力当成 API 供应商给出的常量。CS336 能帮你判断:为什么长上下文贵,为什么 agentic trace 会改变 post-training 数据,为什么 evaluation 不是简单 accuracy,为什么 inference 的动态 batching 会影响产品响应。

但你需要懂底层约束

当你设计 tool schema、上下文压缩、并发策略、模型路由、推理预算、离线评测、human feedback 数据闭环时,CS336 的概念会变成工程边界。你不一定写 FlashAttention,但要知道“瓶颈是 HBM 访问还是算力”这类问题为什么重要。

术语速查

公开资料来源

页面内容以公开资料为依据,正文为中文重写和工程化组织;不复制 lecture slides 或 assignment handout 的长段原文。需要深入时,优先打开官方材料。

材料边界:Lecture 18 和 Lecture 19 是 guest lectures,官方 schedule 公开了讲次和讲者,但当前公开页面没有可稳定引用的讲义链接。本页只说明它们在课程链路中的位置,不编造具体内容。
Built for learn.shukang.dev · Updated 2026-08-31