模块 09 · 约 20 分钟 · 跑得起来

推理与量化:在笔记本上跑大模型

训练完一个模型,怎么让它跑起来?训练用 1000 张 A100,推理一台笔记本就够 —— 这背后有两个关键技术:KV cache(避免重复计算)和量化(压缩权重存储)。 理解它们,你就能解释为什么 2023 年开始大家能在 MacBook 上跑 LLaMA、Mistral、Qwen 这些 7B/13B 级别的模型。

① 推理为什么是"显存瓶颈"

训练时模型一次"吃"成千上万个 token,GPU 的几百 TFLOPS 算力都能跑满。 但推理是自回归的 —— 每次只生成 1 个 token,把这一个 token 送进 96 层 Transformer, 每层都要读全部权重,算几行矩阵乘法,输出一个数字。

这种 batch=1 的推理有个很反直觉的特点:

  • 算力闲着:GPU 一秒能做 300T 次浮点运算,但只用到 1-2%
  • 显存带宽满:每次生成都要从 HBM 把 175B 参数读出来一遍
  • 瓶颈在"读",不在"算"

所以推理优化的第一原则是:减少每次要读的字节数。这就引出了两个核心技术:

  1. KV cache —— 不重复算已经算过的 token
  2. 量化 —— 压缩权重的字节数(INT8 / INT4 / INT2)

② 自回归生成的"重复计算"问题

朴素的生成循环每生成一个 token,把整段历史都重新送进模型:

python
直接编辑这段代码即可。输入 np. 看自动提示,⌘/Ctrl + Enter运行。

想象生成 100 个 token:第 1 步算 1 个位置,第 2 步算 2 个,... 第 100 步算 100 个。 累计要算 1+2+...+100 = 5050 个位置的 attention。 其中前 99 步的结果已经算过,纯属浪费。

③ 互动:KV cache 是怎么省下计算的

切换"用 / 不用 KV cache" 看每一步实际要算多少 attention:

推理方式:
已经生成的序列(绿色 = 这一步在重新算 attention)
·············
当前 step
1 / 14
本步重算量
1 个位置
累计计算量
1
生成 1 个 token 时: 无 cache 累计要算 1 个位置, 用 cache 只要算 1 个 →加速 1.0×

无 cache 时每生成一个 token 都要把整段历史重算一遍 attention —— 累计复杂度 O(L²)。 用 KV cache 之后,历史 token 的 K 和 V 都缓存住,新 token 来了只算自己 —— 累计复杂度降到 O(L),长序列下加速倍数随长度线性增长。

④ KV cache 的核心思想

attention 公式 softmax(QK/d)V\mathrm{softmax}(QK^\top/\sqrt{d}) V 里有三个张量:

  • Q(query):只有"当前正在生成"的这个 token 用得到 — 每步算一份新的
  • K(key):每个历史 token 都贡献一行 — 这些行从来不变
  • V(value):同上,每个历史 token 一行 — 不变

所以做法非常直接:第一次算过 K 和 V,缓存住。下一个 token 来时, 只算自己的新 K_new、V_new,追加到 cache 末尾。 attention 时 Q 是新的一个,K/V 用包含历史的完整缓存。

python
直接编辑这段代码即可。输入 np. 看自动提示,⌘/Ctrl + Enter运行。

⑤ KV cache 的代价:显存占用

天下没有免费的午餐。KV cache 把"算"变"读",但显存被吃掉一大块。 缓存大小的公式:

KV cache 大小=2×L×Nlayer×Nhead×dk×bytes\text{KV cache 大小} = 2 \times L \times N_{\text{layer}} \times N_{\text{head}} \times d_k \times \text{bytes}
↓ 对应的 Python 实现(可以直接改、直接运行)

这是为什么"长上下文"成本暴涨的原因 —— Claude 200k 上下文窗口的代价就是显存暴涨。 Grouped Query Attention (GQA, LLaMA-2 后)、Sliding Window Attention (Mistral) 都是用来缩小这个开销的。

⑥ 量化:用 4 个 bit 装一个权重

训练时权重是 fp16(16 bit)或者 bf16,每个数 2 字节。一个 7B 模型 = 7B × 2B = 14GB。 消费级显卡 RTX 3060 只有 12GB,根本装不下。

推理时其实不需要这么高的精度。研究发现把权重量化到 INT8 (8 bit, 1 字节),质量几乎无损; 到 INT4(4 bit, 0.5 字节)也只有微小退化,但模型大小直接压到 1/4

精度每权重7B 模型大小能在哪跑
fp16 / bf1616 bit14 GBA100, H100, RTX 3090/4090
INT88 bit7 GBRTX 3070/4070, M2 MacBook
INT44 bit3.5 GBRTX 3060, M1 MacBook Air, 树莓派 5
INT22 bit1.75 GB手机(精度有明显损失)

⑦ 量化的数学:从浮点到整数的映射

核心是个简单的线性变换:

q=round ⁣(ws),wqsq = \mathrm{round}\!\left(\frac{w}{s}\right), \quad w \approx q \cdot s
↓ 对应的 Python 实现(可以直接改、直接运行)

跑一下自己量化一个矩阵看看:

python
直接编辑这段代码即可。输入 np. 看自动提示,⌘/Ctrl + Enter运行。

⑧ 量化为什么有效(直觉解释)

训练得到的权重大部分接近 0,少数极端值才需要高精度。这种"长尾分布"特别适合量化:

  • 每 group 找一个最大值定 scale,浪费 1 个 bit 给极端值
  • 其余值按 scale 缩进 [-8, 7] 的整数格子,精度损失很小
  • 反量化时乘回 scale,误差通常 < 1%

而且推理时 大部分权重只参与一次乘法,单次乘法的小误差被 softmax 这种非线性操作"平滑", 累积起来对最终输出的影响很小。所以 INT4 量化的模型在标准基准测试上往往只丢失 1-3 分(相对 fp16)。

⑨ 现代量化方案:GPTQ、AWQ、GGUF

  • GPTQ(2022):用一小批校准数据"修正"量化误差,比朴素 round 精度好得多。开源生态主流。
  • AWQ(2023):发现"少数权重的极端值贡献了模型大部分能力", 量化时给这些权重单独保留高精度。质量比 GPTQ 更稳。
  • GGUF(llama.cpp 项目,2023):把量化模型打包成CPU 友好的格式, 让 Mac / Windows / Linux 不用 GPU 也能跑大模型。M2 Mac Studio 跑 Llama-70B Q4 速度 5-10 tok/s,可用。

⑩ 其他常见推理优化(点到为止)

  • Flash Attention(2022):用 GPU SRAM 缓存中间结果,减少 HBM 读写。训练和推理都快 2-3 倍。
  • Paged Attention / vLLM(2023):把 KV cache 分页管理,大幅提升 batch 推理吞吐。
  • Speculative Decoding:用一个"小模型"快速猜接下来 K 个 token,再用大模型一次验证,加速 2-3 倍。
  • Continuous batching:让不同请求的不同 step 在 GPU 上同时跑,吞吐量飙升。

这些都是 2022-2024 高速发展的方向 — 看完本节,你已经具备读这些论文的基础。

⑪ 小测验

Q1.为什么 LLM 推理通常是"显存瓶颈"而不是"算力瓶颈"?
Q2.INT4 量化(每个权重 4 bit)能把 7B 模型从 14GB 压缩到约多少?

⑫ 延伸阅读