怎么降低 LLM 的 inference cost
和 token 用量?
先弄清楚:每个概念是什么
- Prefill 与 decode
- prefill 一次读完整个 prompt,矩阵乘矩阵,compute-bound。decode 每步只出一个 token,却要把全部 weight 从 GPU memory 搬一遍,memory-bound(见 KV cache)。
- Quantization
- weight 用更少的 bit 存:INT8、INT4(怎么量化见 INT8 quantization)。decode 主要在搬 weight,搬得少就快,也省 GPU memory。
- Continuous batching
- 按 iteration 调度,每一步做完的请求离开,新请求马上补进来。static batching 要等整批里最长的请求结束,短请求的位置空转,还要 padding。读一次 weight 服务一整批请求,所以 throughput 高。
- Prompt / prefix caching
- 很多请求开头一样(system prompt、few-shot、tool 定义),这段的 KV cache 算一次存起来,后面的请求直接复用,只算新增部分。
- Speculative decoding
- 小 draft model 先猜 \(\gamma\) 个 token,大模型一次 forward 并行验证,猜对的都收下。
30 秒回答
I'd measure cost and latency at fixed quality, then pull three levers. Tokens: trim the system prompt and few-shot examples, summarize long history, retrieve only the top chunks, cap output length, and put the static prefix first so prompt caching can reuse it. Model: route easy queries to a smaller model, distill, and quantize weights to INT8 or INT4, which speeds up decoding because decoding is memory-bandwidth-bound. Serving: KV cache, continuous batching with PagedAttention for throughput, and speculative decoding, where a small draft model proposes several tokens and the large model verifies them in one pass without changing the output distribution.
按 lever 分
| 层 | 手段 | 省什么 |
|---|---|---|
| token | 精简 system prompt、少放 few-shot;长 history 压成 summary;RAG 只放 rerank 后的 top chunk;限制输出长度 | input / output token |
| token | prompt caching | 重复前缀的 prefill |
| model | routing / cascade:简单请求给小模型 | 大模型调用次数 |
| model | distillation;quantization(GPTQ、AWQ) | 参数量、GPU memory、decode 时间 |
| serving | KV cache;MQA / GQA 缩小 KV cache | 重复计算、KV cache 的 GPU memory |
| serving | continuous batching + PagedAttention | throughput |
| serving | speculative decoding | latency |
手算例子:7B 模型的 GPU memory 和速度
- weight:fp16 是 \(7\times10^9\times 2\) B = 14 GB;INT8 7 GB;INT4 3.5 GB。
- decode 下限(batch = 1,每个 token 读一遍 weight,带宽 1 TB/s):fp16 14 ms/token(约 71 token/s),INT4 3.5 ms(约 285 token/s)。
- KV cache:LLaMA-7B 每 token 512 KiB(怎么算),4096 context × batch 8 = 16 GiB,比 weight 还大,batch size 被它卡住。
推导 / 关键公式:speculative decoding
\(\alpha\) = draft token 被接受的平均概率,\(c\) = draft 与大模型单次 forward 的耗时比:
\[ \mathbb{E}[\#\text{tokens per run}] = \frac{1-\alpha^{\gamma+1}}{1-\alpha} \] \[ \text{speedup} = \frac{1-\alpha^{\gamma+1}}{(1-\alpha)(\gamma c+1)} \]例:\(\alpha = 0.8\)、\(\gamma = 4\)、\(c = 0.05\):大模型每跑一次平均产出 3.36 个 token,加速 \(3.36/1.2 = 2.8\times\)。代价:被拒的 token 白算,大模型总 FLOPs 约多 49%。
必答点
- 先定指标:quality 不降的前提下比 cost、latency(首 token 时间、每 token 时间)、throughput
- 三层 lever:token / model / serving
- decode 是 memory-bound → quantization、batching 有效;prefill 是 compute-bound
- KV cache 的 GPU memory 卡住 batch size → GQA、PagedAttention
- speculative decoding 降 latency、不改输出分布,但不省 FLOPs
追问
speculative decoding 为什么不改变输出分布?
draft 给出 token \(x\):\(q(x) \le p(x)\) 直接接受;否则以 \(1 - p(x)/q(x)\) 的概率拒绝,并从 \(\mathrm{norm}(\max(0, p - q))\) 重新采样,结果仍服从 \(p\)。\(\alpha\) 低,或 batch 已经大到 GPU 没有空闲算力时,就不划算。
prompt caching 怎么用才能命中?
只复用完全相同的前缀,所以 tools、system prompt、few-shot 放最前,user input、时间戳放后面。Anthropic API 的 5 分钟 cache 写入按 1.25× 计费,读取 0.1×(个别新模型更低)。
W8A8 还是 W4A16?
W8A8 把 weight 和 activation 都压成 INT8,矩阵乘本身变快,适合 prefill、大 batch。W4A16 只压 weight,省 GPU memory,主要加速 memory-bound 的 decode。bit 越低,round-to-nearest 掉点越多(Llama-2-7B perplexity:FP16 5.47,INT4 5.73,INT3 6.66),所以用 GPTQ(用 Hessian 信息逐列量化,并更新还没量化的 weight 补偿误差)或 AWQ(按 activation 找出约 1% 的 salient channel,放大后再量化,INT4 是 5.60)。
routing / cascade 怎么做?
FrugalGPT 先让便宜模型回答,scorer 给答案打分,低于阈值再交给更贵的模型。达到 GPT-4 同等效果时 cost 最多降 98%。
来源Kwon et al. 2023, vLLM §1(pp.1–2)、§2.2–2.3(p.3)、§4.4 Shared prefix(pp.7–8)· Leviathan et al. 2023 §2.3、§3.1 eq. 1、Thm 3.8、Thm 3.11(pp.3–4)· Frantar et al. 2023, GPTQ abstract、§3(pp.3–5)· Lin et al. 2024, AWQ §2(p.2)、§4.1(p.6)、§5.1 Table 4(p.7)· Chen et al. 2023, FrugalGPT §3(pp.3–5)· Touvron et al. 2023, LLaMA Table 2(p.3)· Anthropic prompt caching(Pricing)