第 19 讲 · 长上下文 LLM · Long Context in LLMs

Generative AI · Lecture 19。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应 Maps to:CMU 10-423 / 10-623 / 10-723 Generative AI(Matt Gormley),Lecture 19 · Wed 25-Mar · Long Context in LLM(slides:lecture19-long)。 阅读材料:Kamradt (2023), Needle In A Haystack;Chen et al. (2023), Extending Context Window of Large Language Models via Positional Interpolation;Fu et al. (2024), Data Engineering for Scaling Language Models to 128K Context;Bertsch et al. (2024), In-Context Learning with Long-Context Models;Child et al. (2019), Sparse Transformers;Beltagy et al. (2020), Longformer;Ding et al. (2023), LongNet;Liu & Abbeel (2023), Blockwise Parallel Transformer;Liu, Zaharia & Abbeel (2023), Ring Attention;Liu et al. (2024), Large World Model。 依据说明:本讲按原课第 19 讲公开的 slides 展开:一个视频问答的例子撞上”超过 4096 的最大上下文”;2019–2026 年各模型的上下文长度表;大海捞针测试;扩展短上下文模型的两个关键(可扩展的位置编码、挑选长数据)和一般配方;微调 vs 上下文学习(2023 年的看法和长上下文下的新结果);近似注意力(稀疏、滑动窗口的三种实现、空洞);高效的精确注意力(FLOPs 随上下文的增长、序列并行、BPT、环形注意力及其结果、Large World Model)。所有实验是本讲义自己设计的,不代表课堂上讲了什么。 配套代码 Code:code/lecture19/(4 个脚本 + 1 个模块;02、03 第一次各约 3 分钟,之后几秒到半分钟) 预计阅读时间:2.5 小时(含运行代码)


0. 本讲导航 · How to read this lecture

0.1 学习目标 Learning goals

学完这一讲,你应该能够:

  1. 说出长上下文贵在哪里:训练的 FLOPs、推理的 KV 缓存、预填充的时间,并算出量级。
  2. 解释大海捞针测试测什么、不测什么;为什么”找不到”往往是”太远”而不是”太长”。
  3. 用 RoPE 的频率解释外推为什么失败,说出位置插值(PI)、调大 base(NTK / ABF)各改了什么、代价是什么。
  4. 说明扩展上下文时”数据要有长距离依赖”的意思。
  5. 比较稀疏、滑动窗口、空洞注意力的代价与局限,用”两跳之内能不能到”判断一个模式会丢掉什么。
  6. 描述 BPT 和环形注意力怎样让每块设备的显存和序列长度无关,以及通信被计算藏住的条件 c≥F/Bc \ge F/B。

0.2 先修与本讲范围 Prerequisites & scope

默认你已经会 Assumed本讲只给直觉,后面再展开 Previewed only
第 4 讲:RoPE、GQA、滑动窗口(三种实现、感受野、滚动缓存)状态空间模型、线性注意力(第 21 讲)
第 18 讲:在线 softmax 的 (m,ℓ,o)(m, \ell, o)、FlashAttentionYaRN 等更细的位置编码缩放方法
第 11 讲:上下文学习;第 17 讲:并行与通信长上下文的评测基准(RULER、LongBench 等)的细节

0.3 本讲地图 Map

§1  上下文有多长,贵在哪里                                      ← 代码 01
§2  大海捞针:一个最小的长上下文测试                            ← 代码 02 第 1、2 部分
§3  扩展短上下文模型:位置编码 + 长数据                          ← 代码 02 第 3–5 部分
§4  近似注意力:稀疏、滑动窗口、空洞                            ← 代码 03
§5  高效的精确注意力:BPT 与环形注意力                          ← 代码 04
§6–10  小结、误区、练习、延伸阅读、下一讲

本讲的实验模型在 long_lab.py 里:一个 37 万参数、2 层的 Llama 式小 Transformer(RMSNorm、RoPE、SwiGLU),可以换位置编码和注意力模式;玩具世界是一个”大海捞针”的 token 语言。


1. 上下文有多长,贵在哪里 · How long, and what does it cost

1.1 为什么需要长上下文

slides 从一段代码开始:把一段视频的每一帧用 ViT 编码成 66 个 token,和问题一起喂给 GPT-2 做视频问答。10 帧就是 660 个图像 token;帧数一多——“错误:输入超过了 Transformer 的最大上下文长度 4096 个 token”。长文档、整个代码库、长对话、多张图片、视频,都需要长上下文。

slides 的表(节选):

模型年份上下文
GPT-220191,024
GPT-320202,048
LLaMA-220234,096
Claude-2.12023200K
Gemini-1.520241M
LLaMA-3.12024128K
Llama 4 Scout / Maverick202510M
GPT-5.4 / Gemini 3.1 Pro / Claude Opus 4.620261M

七年里涨了三个数量级。代价在哪里?

1.2 训练:FLOPs 涨得没有想象的快(代码 01 第 1 部分)

训练时每个 token 的 FLOPs ≈ 6N6N(参数部分,第 15 讲)+ 注意力部分。注意力每层前向对 TT 个键做 QK⊤QK^\top 和 PVPV,各 2Td2Td 次运算,反向是前向的两倍,因果掩码再省一半(第 18 讲 §4.3):约 6LTd6LTd。整个序列的注意力是 O(T2)O(T^2),摊到每个 token 只是 O(T)O(T):

模型4K 时注意力占比1M 时注意力占比每 token 1M 比 4K 贵
Llama-3 8B6%94%17.0×
Llama-3 70B4%91%10.3×
Llama-3.1 405B2%84%6.2×

上下文变长 256 倍,每个 token 只贵 6–17 倍;模型越大(6N6N 越大),注意力占比越小、涨得越慢。这就是 slides(引自 Ring Attention 论文)说的”FLOPs 随上下文增长得没有你想象的那么快:除了 O(N2)O(N^2) 的注意力,Transformer 还有很多计算密集的部分”。

1.3 推理:KV 缓存和预填充(代码 01 第 2、3 部分)

一个序列的 KV 缓存(BF16、GQA 8 个 KV 头):

模型权重每 token128K1MKV = 权重时的长度
Llama-3 8B15 GiB128 KiB16 GiB128 GiB120K
Llama-3 70B131 GiB320 KiB40 GiB320 GiB421K
Llama-3.1 405B756 GiB504 KiB63 GiB504 GiB1,536K

8B 模型在约 12 万个 token 时 KV 缓存就和权重一样大,100 万 token 的一个请求要 128 GiB——比一块 H100 还大。H100 上的 roofline 估计(批大小 1):8B 模型解码一个 token,4K 时 5.0 ms(读 KV 只占 3%),1M 时 45.8 ms(读 KV 占 90%);预填充一个 1M 的提示,8B 要 5 分钟、70B 要 27 分钟,大部分时间在注意力上。

所以长上下文的瓶颈是显存(训练时的激活值、推理时的 KV 缓存)和预填充时间,而不只是每 token 的 FLOPs。§4 的近似注意力、§5 的环形注意力、第 21 讲的状态空间模型,都是在对付这些。


2. 大海捞针 · Needle in a haystack

2.1 测试是什么

slides:“大海捞针测试是一个极其简单、最低限度的测试,看 LLM 能不能在长上下文里找到信息。“做法:造一个长文档;在某个深度埋一个事实(“针”);问一个答案就是这个事实的问题。把”文档长度 × 针的深度”画成热力图(gkamradt 的仓库),一眼看出模型在哪里找不到。

“最低限度”的意思是:找到一句话和”理解长文档”差得很远——后来的基准(例如 RULER)加入了多根针、多跳、聚合等任务,发现很多模型的”有效上下文”比标称的短得多。但如果连这一关都过不了,长上下文就无从谈起。

2.2 我们的玩具版(代码 02 第 1 部分)

long_lab.NeedleTask:16 个键 k0…k15、16 个值 v0…v15、32 个填充词 f0…f31。草堆是填充词组成的马尔可夫链(像一段有规律、但和问题无关的文字);针是 “N k v”;问题是 “Q k”,要预测 v。键值配对每个序列都不一样,答案只能从针里抄。测试时每个序列放 4 根针(1 根要找、3 根干扰):

<s> f3 f30 f31 … N k10 v1 f6 f19 … N k15 v11 … N k6 v3 … N k2 v2 … Q k10   → v1

这正是第 11 讲 §1.3 提到的”归纳头”(induction head)要做的事:找到前面出现过的同一个 k,把它后面的 token 抄过来。训练长度 128,模型 d = 128、2 层、2 个头。

训练这个模型比想象的难,过程本身就是一课(详见 README 的”计划 vs 实际”):

  • 只放 1 根针的测试是假的:模型可以只学”抄 N 后面第二个 token”,不比对键也全对——所以测试加了干扰针。
  • 捷径:训练时每根针恰好被问一次,模型学会了排除法(最后一个问题只剩一根没问过的针),准确率卡在 0.55,从不比对键。改成有放回地抽问题。
  • 头太窄:每个头 16 维(和第 2 讲的 GPT 一样)时,连最简单的键值检索都学不会;每头 64 维时 600 步就学会了。
  • 草堆挡住了学习:一开始就在长草堆里训练,3 个种子都卡在”随便抄一根针”(≈ 0.3)上;先在没有草堆的短序列上训练 600 步,学会检索之后再换成长草堆,就一直保持住了(课程学习)。而且种子 0 在所有设置下都学不会——这种”突然学会”的能力出不出现,和初始化关系很大(和第 11 讲 §1.3 ICL 的”突然出现”是同一类现象)。

最终的模型:前 600 步没有草堆(第 400 步准确率 0.654),换成草堆后第 800 步 0.997、第 1200 步起 1.000。

2.3 拿到更长的草堆上去测(代码 02 第 2 部分)

不做任何修改:

长度深度 0%(最远)25%50%75%100%(最近)平均
128(训练长度)0.981.001.001.001.001.00
2560.921.001.001.001.000.98
5120.640.880.941.001.000.89
10240.310.520.780.941.000.71

(每格 64 个序列;瞎猜 1/16,随便抄一根针 1/4。)1024 个 token 的草堆里,紧挨着问题的针仍然全对,最远的针只剩 0.31。失败的不是”长”本身,而是”远”:针和问题之间的距离超过训练时见过的最大距离(约 120)越多,越找不到——这就是大海捞针热力图上常见的”一角发红”。


3. 扩展一个短上下文模型 · Extending short-context models

slides:“扩展一个短上下文模型有两个关键:① 可扩展的位置编码;② 仔细挑选的长数据。“一般的配方(Fu et al., 2024):先用短上下文(块长 4K)在 1 万亿 token 上预训练;调整位置编码的超参数;再把块长增加到 80K 继续预训练,只用 50 亿 token——不到预训练的 1%。

3.1 为什么 RoPE 外推会失败(代码 02 第 3 部分)

回顾第 4 讲:RoPE 把查询和键的每一对维度按位置旋转,第 ii 对的转速是 θi=base−2i/d\theta_i = \text{base}^{-2i/d};qm⋅knq_m \cdot k_n 只取决于相对距离 m−nm - n 对应的角度 (m−n)θi(m-n)\theta_i。头维度 64、base 10000 时:

频率对 iiθi\theta_i转一圈要多少 token训练时最大角度(距离 127)测试时(距离 1023)
01.000006127.001023.00
100.056231127.1457.53
110.042171495.36(不到 2π2\pi)43.14
160.010006281.2710.23
310.0001347,1170.020.14

32 对频率里有 21 对在训练时连一圈都没转满:模型只见过圆周上的一段角度。测试时距离到了 1023,这些维度转到了训练时从未出现的角度,q⋅kq \cdot k 落到模型没学过的范围里。高频的几对转过很多圈,什么角度都见过,所以只靠高频就能分辨的”近处”不受影响——和 §2.3 的”远处失败、近处没事”正好对上。(第 4 讲 §7.3 看到的”RoPE 外推得最差”是同一类问题的另一面。)

3.2 不训练,只改位置编码(代码 02 第 4 部分)

两种零样本的做法,ss = 测试长度 / 训练长度:

  • 位置插值(PI,Chen et al., 2023):把位置 mm 换成 m/sm/s。长度 sLsL 的序列被”压”回训练见过的角度范围 [0,L)[0, L)。代价是相邻两个 token 的角度差也缩小了 ss 倍——高频的分辨率下降。
  • NTK 式缩放:不改位置,改 base:base′=base⋅sd/(d−2)\text{base}' = \text{base}\cdot s^{d/(d-2)}。最高频几乎不变(近处照常外推),最低频被拉长 ss 倍(远处相当于插值)。
长度做法深度 0%平均
1024原样外推0.310.71
1024PI(s=8s = 8)0.980.91
1024NTK0.890.96

都不需要训练,就把远处的针大部分救了回来。PI 在 1024 时每个深度都略降(相邻 token 的角度差被压缩了 8 倍);NTK 只拉长低频,近处几乎不受影响。真实的大模型里,零样本的 PI 通常不够好,要配合少量微调(PI 论文:把 LLaMA 扩展到 32K 只要 1000 步左右的微调);NTK 的思路后来发展成 YaRN 等方法。

调大 base(ABF) 是更常见的做法:Code Llama 把 base 从 1 万调到 100 万,Llama-3 预训练就用 50 万——slides 配方里的”调整位置编码的超参数”指的主要就是这个,然后再用长数据继续训练。

3.3 继续训练:数据里要有长距离依赖(代码 02 第 5 部分)

从基础模型出发,在 512 个 token 上继续训练 150 步,三种做法:

做法512 · 深度 0%512 · 平均1024 · 深度 0%1024 · 平均
(不训练,原样外推)0.640.890.310.71
RoPE + 长依赖的数据(针在整个草堆里均匀分布)1.001.000.730.92
RoPE + 短依赖的数据(针只在最后 20%)0.610.880.220.68
PI(s=4s = 4)+ 长依赖的数据1.001.001.000.99

序列一样长、步数一样多,差别只在”针离问题有多远”。依赖都很短的长序列几乎没有帮助(0.61,和不训练的 0.64 一样):模型只学会了在长草堆里找近处的针。这就是 slides 说的”仔细挑选长数据”:把很多短网页拼接成长序列,内容仍是局部的,教不会模型用远处的信息;要的是书、长代码文件这类真正有长距离依赖的数据(Fu et al. 还发现要保持各领域的比例、在每个领域内部增加长文档的比例)。调整位置编码(PI)+ 长依赖数据的组合最好,在 2 倍于训练长度的 1024 上也几乎全对。

3.4 长上下文改变了”微调 vs 上下文学习”

slides 回到第 11 讲的问题。2023 年的看法(Mosbach et al., 2023):“即使对很大的语言模型,微调也常常胜过上下文学习”——在 RTE、MNLI 上公平比较,多数规模下微调更好。slides 的批注:“至少 2023 年的普遍看法是这样。到了 2025 年,故事可能不一样了。”

Bertsch et al. (2024) 用长上下文的 LLaMA-2-7B,在两个多分类数据集(Clinic-150 有 151 个标签、Trecfine 有 50 个标签)上比较:LoRA 微调、随机挑例子的 ICL、用 BM25 检索最相似例子的 ICL。上下文能放下成百上千个例子时,ICL 的效果随例子数持续上升,可以接近甚至超过微调;例子越多,“检索相似例子”相对”随机挑”的优势越小。长上下文让”把训练集塞进提示”成为一种可行的适配方式——不用训练,代价是每次推理都要处理很长的提示(§1.3)。


4. 近似注意力 · Approximate attention

slides:“标准注意力需要 O(N2)O(N^2) 的显存和计算。计算也许还能接受,显存通常不行。“(第 18 讲的 FlashAttention 已经把显存降到 O(N)O(N),但计算仍是平方的。)一个办法是近似:稀疏注意力(2019,O(NN)O(N\sqrt N))、滑动窗口(2020,O(N)O(N))、空洞注意力(2023,O(N)O(N))。

4.1 三种模式(代码 03 第 1、2 部分)

  • 滑动窗口(Longformer 的局部注意力,第 4 讲 §6):只看最近 WW 个 token。slides 再次列出它的三种实现(朴素的掩码、for 循环、滑动分块),第 4 讲已经实现过。
  • 跨步稀疏(Sparse Transformer,Child et al., 2019):最近 stride 个,再加上每隔 stride 个取一个;stride ≈ N\sqrt N 时每个查询看 O(N)O(\sqrt N) 个键。
  • 空洞注意力(LongNet,Ding et al., 2023):把序列切成长度 ww 的段,段内每隔 rr 个取一个;几种 (w,r)(w, r) 合起来——近处密、远处疏。slides 的评价:“运行时间很好,但它已经是另一个模型了。“(我们实现的是只抽稀键的简化版;LongNet 原文让不同的头用不同的起点。)

要算的 (查询, 键) 对:

NN完整(因果)滑动窗口 W=256W = 256跨步稀疏 stride = N\sqrt N空洞
1,024524,80043.7%9.2%5.2%
4,0968,390,65612.1%4.6%1.6%

(这些模式要配专门的核函数,只算需要的块,才真正省时间。)

4.2 能从多远的地方传过来(代码 03 第 3 部分)

每一层是一”跳”。T=128T = 128,2 层:

模式一跳能到的 (i,j)(i, j)两跳能到的
完整100%100%
滑动窗口 W=16W = 1623.4%42.4%
跨步稀疏 stride = 1225.3%100%
空洞 (8,1)(32,4)(128,16)16.3%30.2%

跨步稀疏的”列”位置像中转站:任何位置都在某个列的局部窗口里,两跳处处可达。但”能到”只说明有路——模型得学会走这条路。

4.3 同样的配方训练四个模型(代码 03 第 4 部分)

训练长度 128(600 步没有草堆 + 900 步有草堆),在 128 个 token 上找针,每格 128 个序列:

模式深度 0%(距离 124)25%(96)50%(68)75%(39)100%(11)平均
完整1.001.001.001.001.001.00
跨步稀疏0.980.980.950.951.000.97
空洞(简化版)0.100.050.160.350.980.33
滑动窗口0.080.060.080.101.000.26
  • 滑动窗口只能找到窗口附近的针:第二层只看最近 16 个位置,这些位置在第一层也只看再往前 16 个——最远约 30 个 token。窗口之外的信息,在两层之内根本过不来(第 4 讲 §6.5 的主谓一致是同一个现象)。
  • 跨步稀疏几乎和完整注意力一样好,只算了约四分之一的对。按它的掩码,远处的针只能先被附近的列位置在第一层”收进来”,第二层再从列上取——模型学会了用这些中转站。
  • 空洞(简化版) 的段是对齐的块,块开头附近的位置在第一层看不到多少历史,两跳只能到 30%,中转站很难建立。

教训:省下的计算是有代价的;代价多大,取决于这个模式有没有给远处的信息留一条模型学得会的路。这也是 Longformer、BigBird 额外加几个”全局 token”(能看所有位置、也被所有位置看)的原因,也是 Gemma、gpt-oss 等把滑动窗口层和全局注意力层交替使用的原因(第 4 讲 §6.5)。


5. 高效的精确注意力:BPT 与环形注意力 · Efficient full attention

5.1 序列并行的问题

slides:序列并行(Li et al., 2021)把一个长序列切成几段,每段给一块设备;对仅解码器的 Transformer,前面设备的计算结果要传给后面的设备。“问题:这样扩展得并不高效,因为后面的查询仍然要看 O(N)O(N) 个键和值。”

5.2 BPT:注意力和前馈层都分块(代码 04 第 1 部分)

FlashAttention 把注意力的显存降了下来,但”只在注意力层里做分块计算”。BPT(Blockwise Parallel Transformer,Liu & Abbeel, 2023)对每一块查询 QiQ_i,遍历所有键值块算完注意力(用第 18 讲的在线 softmax:slides 说”softmax 对平移不变,所以可以分块计算,再根据其他块的充分统计量重新缩放之前的输出”),然后立刻对这一块做前馈层和残差连接——前馈层 4h 宽的中间结果也只存一块。Ring Attention 论文表 1 的每层最大激活值(BF16,h=4096h = 4096、32 个头,块 c=4096c = 4096):

序列长度普通注意力 2bns22bns^2FlashAttention(前馈层 8bsh8bsh 最大)BPT 2bsh2bsh环形注意力 6bch6bch(每块设备)
32K64 GiB1.0 GiB256 MiB96 MiB
128K1.0 TiB4.0 GiB1.0 GiB96 MiB
1M64 TiB32 GiB8 GiB96 MiB

BPT 之后,一层只剩它的输出本身(2bsh2bsh)——但仍和 ss 成正比,一块设备总有放不下的时候。

5.3 环形注意力(代码 04 第 2 部分)

slides 的关键想法:“用 BPT 在很多设备上处理很长的序列;K、V 块在设备之间传递的模式,和它们在注意力计算里被使用的模式完全相同。“结果:“能放进显存的序列长度随设备数线性增长。“(slides 把它叫作”击鼓传花” pass the parcel。)

把 NN 个 token 分给 PP 块设备,第 rr 块持有自己的 Qr,Kr,VrQ_r, K_r, V_r。一共 PP 轮:每一轮,每块设备用手上当前的 K、V 块和自己的 QrQ_r 算一块注意力,用 (m,ℓ,o)(m, \ell, o) 合并进累加器;然后把手上的 K、V 块传给环上的下一块设备、从上一块收一块。PP 轮之后,每块设备都见过了全部的 K、V。

04 真的算了一遍(N=512N = 512、d=32d = 32、float64):P=4,8P = 4, 8,有无因果掩码,和整段注意力的差都在 10−1610^{-16} 量级。每块设备一共发出 P−1P - 1 个 K/V 块,总量 2Nd(P−1)/P2Nd(P-1)/P——和一次 all-gather(第 17 讲)一样多,但拆成了 P−1P - 1 次、每次只和邻居通信,正好可以和计算重叠。每块设备只存 6 个块(QQ、当前的 K/V、正在接收的 K/V、输出),和序列长度无关(§5.2 表的最后一列)。

5.4 因果掩码下的负载均衡(代码 04 第 3 部分)

因果掩码让连续切分忙闲不均:设备 0 拿最前面的 token,只需要看自己那一块;设备 7 拿最后的 token,要看全部 8 块。每一轮大家都要等最忙的那块:

切分(N=512N = 512、P=8P = 8)各设备的工作量效率
连续2k / 6k / … / 30k53%
条带(token tt → 设备 t mod Pt \bmod P)16k × 899%

条带式切分(Brandon et al., 2023 的 Striped Attention)让每块设备都有早有晚的 token,每一轮的工作量都差不多是半块。

5.5 通信藏得住吗(代码 04 第 4 部分)

一块 QQ 对一块 K/V 要 4dc24dc^2 次运算,同时要收发 4cd4cd 字节(K、V 各 c×dc \times d,BF16)。重叠的条件 4dc2/F≥4cd/B4dc^2/F \ge 4cd/B,即

c≥F/Bc \ge F/B

——和头维度无关,只看”算力 / 带宽”。论文表 2(我们逐行重算):A100 + NVLink(312 TFLOPS、300 GB/s)c≥1.0Kc \ge 1.0\text{K};A100 + InfiniBand(12.5 GB/s)c≥25.0Kc \ge 25.0\text{K}(论文写 24.5K);TPU v4 1.0K1.0\text{K}。每块设备的序列至少约 6c6c。块够大时,传下一块的时间完全藏在算这一块的时间里,环形注意力几乎没有额外开销。

5.6 结果与 Large World Model

slides 列出的结果:13B 模型在 8 块 A100 上能处理 128K 的上下文;7B 模型在 32 块 A100 上能处理 400 万 token。Large World Model(Liu et al., 2024)用环形注意力训练,分几个阶段逐步把上下文扩到 100 万 token,同时处理长视频和长文本——这就是 §1.1 那个视频问答例子的答案之一。


6. 小结 · Summary

  1. 长上下文的代价:每 token 的 FLOPs 涨得比 N2N^2 直觉慢得多(256 倍长度、6–17 倍代价),真正的瓶颈是显存(激活值、KV 缓存)和预填充时间。
  2. 大海捞针是”最低限度”的测试;找不到的往往是远处的针,而不是长序列本身。
  3. RoPE 外推失败,是因为低频维度在训练时没转满一圈;PI(压缩位置)和 NTK / ABF(调大 base)都能不训练就救回很多,配合少量长数据的继续训练效果最好。
  4. 继续训练的数据要真正包含长距离依赖;只是”长”而依赖很短的数据几乎没用。
  5. 近似注意力省计算,代价取决于模式能否给远处的信息留一条可学的路:跨步稀疏借中转站几乎不损失,滑动窗口和我们的空洞版本找不到远处的针。
  6. BPT 把前馈层也分块;环形注意力让每块设备的显存和序列长度无关,K/V 沿环传递、和计算重叠(c≥F/Bc \ge F/B),能处理的上下文随设备数线性增长;条带式切分解决因果掩码的负载不均。

7. 常见误区 · Common pitfalls

  • “上下文窗口是 1M,模型就能用好 1M 的信息。” 标称长度只是”放得下”;大海捞针是最低要求,多跳、聚合类任务上有效长度常常短得多。
  • “长上下文主要贵在注意力的 N2N^2 FLOPs。” 摊到每个 token 是线性的;大模型在 128K 时注意力只占一半左右(70B:55%),显存和预填充时间才是硬约束。
  • “RoPE 只编码相对位置,所以天然能外推。” 相对距离超出训练范围时,低频维度出现没见过的角度(我们:21/32 对),远处的针找不到。
  • “把短文档拼成长序列继续训练,就能扩展上下文。” 依赖仍是局部的,几乎没用(我们:0.61 vs 不训练的 0.64)。
  • “稀疏注意力只是精度略降的近似。” 损失取决于模式:滑动窗口在远处直接归零(0.06–0.10),跨步稀疏几乎没损失(0.97)。
  • “环形注意力减少了通信量。” 总通信量和一次 all-gather 一样;它的好处是显存和序列长度无关、通信可以被计算藏住。

8. 练习 · Exercises

练习 1(FLOPs)。 一个 L=32L = 32、d=4096d = 4096、N=8BN = 8\text{B} 的模型,训练时上下文 128K。(a) 每个 token 的参数部分和注意力部分各多少 GFLOP?(b) 如果不做因果掩码的跳过,注意力部分是多少?

参考答案

(a) 6N=486N = 48 GFLOP;6LTd=6×32×131072×4096≈1036LTd = 6 \times 32 \times 131072 \times 4096 \approx 103 GFLOP(01 的表:48 / 103,注意力占 68%)。(b) 不跳过时 12LTd≈20612LTd \approx 206 GFLOP——FlashAttention 的块跳过把它减半。

练习 2(RoPE 转满一圈)。 头维度 d=128d = 128、base 10000、训练长度 4096。哪些频率对在训练时没转满一圈?把 base 调到 50 万呢?

参考答案

第 ii 对转满一圈要 2π/θi=2π⋅100002i/1282\pi/\theta_i = 2\pi\cdot 10000^{2i/128} 个 token。要求 <4096< 4096:10000i/64<65210000^{i/64} < 652,i<64log⁡652/log⁡10000≈45.0i < 64 \log 652 / \log 10000 \approx 45.0,所以 i=46…63i = 46 \ldots 63 这 18 对没转满。base = 50 万时 i<64log⁡652/log⁡500000≈31.6i < 64\log 652/\log 500000 \approx 31.6,i=32…63i = 32\ldots63 共 32 对没转满——调大 base 让更多维度在训练时”转得慢”,相当于在训练时就为更长的距离预留了没用过的角度区间;继续训练时,模型在长数据上学会使用它们。

练习 3(PI 的代价)。 训练长度 4K、用 PI 扩展到 128K(s=32s = 32)。相邻两个 token 在最高频那一对上的角度差变成多少?为什么这会伤害局部的建模?

参考答案

原来是 θ0=1\theta_0 = 1 弧度,插值后是 1/32≈0.0311/32 \approx 0.031 弧度。注意力要区分”上一个 token”和”上上个 token”,靠的就是高频维度上的角度差;它被压缩 32 倍后,相邻位置几乎不可分辨,模型需要重新学习(所以 PI 要配合微调),这也是 NTK / YaRN “高频不动、只插值低频”的动机。我们的 1024(s=8s = 8)上 PI 每个深度都略降,就是这个效应的小规模版本。

练习 4(滑动窗口的感受野)。 LL 层、窗口 WW 的模型,第 LL 层最远能用到多远的信息?为什么我们的 2 层、W=16W = 16 模型连距离 39 的针都找不到?

参考答案

L(W−1)L(W - 1)(第 4 讲 §6.3):2 层是 30。距离 39 超出了感受野,信息在两层之内根本过不来(0.10)。即使在感受野之内,“找针”还要求第二层直接看到一个已经收进了”键–值”配对的位置,所以实际能用的距离可能更短。

练习 5(环形注意力的显存)。 7B 模型(h=4096h = 4096)、BF16、每块设备的块 c=8192c = 8192。(a) 每层每块设备的最大激活值是多少?(b) 要处理 100 万 token 的序列、每块设备 8192 个 token,需要多少块设备?(c) InfiniBand 互联时这个块够大吗?

参考答案

(a) 6bch=6×8192×40966bch = 6 \times 8192 \times 4096 字节 = 192 MiB。(b) 106/8192≈12310^6/8192 \approx 123 块(取 128)。(c) InfiniBand 要求 c≥F/B≈25Kc \ge F/B \approx 25\text{K},8192 不够——通信藏不住,要么换 NVLink 域内的设备、要么把块加大到 25K 以上。

练习 6(条带式切分)。 为什么条带式切分下,每一轮每块设备的工作量约是”半块”?

参考答案

设备 rr 持有 token r,r+P,r+2P,…r, r+P, r+2P, \ldots,设备 ss 的键是 s,s+P,…s, s+P, \ldots。第 aa 个查询 r+aPr + aP 能看第 bb 个键 s+bPs + bP 当且仅当 s+bP≤r+aPs + bP \le r + aP,即 b<ab < a,或 b=ab = a 且 s≤rs \le r。所以每一对设备之间都是一个”下三角”(含或不含对角线),约占一块的一半。连续切分时则要么整块(s<rs < r)、要么半块(s=rs = r)、要么 0(s>rs > r)。

9. 延伸阅读 · Further reading

  • 评测:Kamradt (2023) 大海捞针;Liu et al. (2023), Lost in the Middle;Hsieh et al. (2024), RULER。
  • 位置编码的扩展:Chen et al. (2023) PI;Peng et al. (2023), YaRN;Xiong et al. (2023), Effective Long-Context Scaling of Foundation Models(ABF);Press et al. (2022), ALiBi。
  • 长数据:Fu et al. (2024), Data Engineering for Scaling Language Models to 128K Context。
  • 长上下文 ICL:Mosbach et al. (2023);Bertsch et al. (2024);Agarwal et al. (2024), Many-Shot In-Context Learning。
  • 近似注意力:Child et al. (2019);Beltagy et al. (2020);Zaheer et al. (2020), BigBird;Ding et al. (2023), LongNet。
  • 精确注意力的并行:Li et al. (2021), Sequence Parallelism;Liu & Abbeel (2023), BPT;Liu et al. (2023), Ring Attention;Brandon et al. (2023), Striped Attention;Liu et al. (2024), Large World Model。

10. 下一讲预告 · Next lecture

第 20 讲:推理模型。长上下文让模型”读得更多”;推理模型让模型”想得更久”。o1 和 DeepSeek-R1 先写出很长的思考过程再回答:训练时用强化学习(不需要奖励模型,只用”答案对不对”的规则),测试时花更多计算(想得更长、采样更多次)就能答对更难的题。我们会造一个能自己决定”想多少”的小模型,看测试时计算、STaR 自举和 GRPO 各自做了什么——包括 R1-Zero 那张”思考越练越长”的曲线是怎样出现的。

← 返回课程目录