大模型推理这件事,真正做过线上部署的人都知道,训练只是前半场,推理才是那个天天要面对的成本黑洞。一个70B级别的模型,如果老老实实用FP16跑,光权重就要吃掉140GB显存,单卡根本放不下,多卡并行之后吞吐还是上不去,延迟也压不下来。这时候摆在面前的其实就三条路:把数值精度降下来(量化)、让一次前向多吐几个token(投机采样)、把计算密集和访存密集的阶段拆开部署(PD分离)。这三样东西不是互斥的选项,而是可以叠加的组合拳,但每一块都有自己的坑,配错了不但不加速,反而更慢。
我自己从最早用INT8跑BERT那会儿开始,到后来折腾LLaMA、Qwen系列的量化部署,再到最近在PD分离架构上踩了不少坑,中间交的学费不算少。这篇就把这三块技术从原理到实操完整捋一遍,重点讲清楚每项技术到底在解决什么问题、参数怎么选、什么场景下会翻车。不管你是刚接触推理优化的新手,还是已经在做线上服务的老手,应该都能从里面找到能直接抄作业的东西。
1. 量化:把权重和激活从FP16压到INT8/INT4到底省了什么
1.1 量化省的不只是显存,更是显存带宽
很多人一提量化第一反应是"省显存",这个理解对,但只对了一半。大模型推理在decode阶段是典型的memory-bound场景——每生成一个token,都要把整个模型的权重从显存里读一遍。以70B模型为例,FP16下每生成一个token要读140GB的数据,而A100的显存带宽大概是2TB/s,理论极限也就每秒14个token左右。这时候算力其实是闲置的,瓶颈全在带宽上。
把权重压到INT8,数据量直接减半,带宽压力也减半,理论吞吐就能翻倍。压到INT4,理论上能到4倍。这就是为什么量化在decode阶段效果特别明显,而在prefill阶段(计算密集)提升就没那么大——prefill阶段瓶颈在算力,不在带宽。
所以量化的核心收益可以拆成三块:
- 显存占用下降:权重从2字节/参数降到1字节(INT8)或0.5字节(INT4),70B模型从140GB降到70GB甚至35GB,单卡能装下的模型规模直接上一个台阶。
- 显存带宽压力下降:decode阶段吞吐提升的主要来源,通常INT8能带来1.5到1.9倍的实际加速,INT4能到2到3倍。
- 算力利用率提升:INT8的矩阵乘在支持Tensor Core INT8的卡上(比如A100、H100)理论算力是FP16的2倍,但实际能不能吃满要看kernel实现。
1.2 权重量化、激活量化、KV Cache量化是三件不同的事
新手最容易混淆的就是把"量化"当成一个整体。实际上在大模型推理里,量化至少分三个层面,每个层面的难度和收益都不一样。
权重量化(Weight-only Quantization)是最简单也最常用的。只把模型权重压成INT8或INT4,激活值还是FP16,计算的时候把权重反量化回FP16再做矩阵乘。这种方式实现简单,精度损失小,主要收益是省显存和带宽。GPTQ、AWQ、GGUF这些方案都属于这一类。
激活量化(Activation Quantization)就麻烦多了。激活值的分布是动态的,不同输入、不同层之间差异很大,而且经常有离群值(outlier)。直接量化激活会导致精度大幅下降。SmoothQuant的思路是通过数学等价变换,把激活的量化难度转移到权重上,让两者都好量化。只有权重和激活都量化成INT8,才能真正用上INT8的Tensor Core,拿到算力上的收益。
KV Cache量化是长上下文场景的救命稻草。上下文越长,KV Cache占的显存越多,有时候甚至超过模型权重本身。把KV Cache从FP16压到INT8,显存直接减半,能支持的并发数和上下文长度都上去了。但KV Cache的量化对精度影响比较敏感,尤其是attention的softmax之后,需要仔细调。
| 量化层面 | 典型方案 | 主要收益 | 精度风险 | 实现难度 |
|---|---|---|---|---|
| 权重量化 | GPTQ、AWQ、GGUF | 省显存、省带宽 | 低 | 低 |
| 激活量化 | SmoothQuant | 用上INT8算力 | 中高 | 高 |
| KV Cache量化 | FP8 KV、INT8 KV | 省显存、支持长上下文 | 中 | 中 |
1.3 GPTQ和AWQ怎么选:一个看校准集,一个看激活分布
GPTQ和AWQ是目前最主流的两种权重量化方案,很多人纠结选哪个。我的经验是看你的场景。
GPTQ是基于二阶信息(Hessian矩阵)的逐层量化方法,它通过最小化量化误差来逐列确定量化参数。优点是压缩率高,INT4下精度保持得不错,生态成熟,各种模型都有现成的量化版本。缺点是量化过程比较慢,而且对校准集比较敏感——校准集选得不好,某些层的精度会掉得厉害。
AWQ(Activation-aware Weight Quantization)的核心洞察是:不是所有权重都同等重要,应该根据激活值的分布来保护那些"重要"的权重通道。它通过观察激活的幅度,找出对输出影响大的权重通道,对这些通道保留更高的精度。优点是精度通常比GPTQ好一点,尤其是小模型上;量化速度快。缺点是生态相对GPTQ没那么全。
实操建议:
- 7B以下的小模型:优先AWQ,精度优势明显。
- 13B到70B的中大模型:两者差距不大,看哪个有现成的量化权重。
- 需要极致压缩(INT3甚至INT2):GPTQ的变体方案更多。
- 校准集:不管用哪个,校准集一定要覆盖你的实际业务场景。用通用语料校准的模型,在你的垂直领域上可能掉点严重。
提示:量化后的模型一定要在你的真实业务数据上做评测,不要只看 perplexity。PPL掉了0.1不代表业务效果没问题,有时候PPL几乎不变但某些特定任务的效果会崩。
1.4 INT4量化的显存账怎么算
拿Qwen系列27B模型举例,算一笔实际的账。FP16下权重是27B × 2字节 = 54GB,加上KV Cache和激活,单卡80GB的A100勉强能跑但并发很低。INT4量化后权重降到27B × 0.5字节 ≈ 13.5GB,加上KV Cache(假设8K上下文、batch size 16),大概再占10到15GB,总共不到30GB,一张A100就能跑得很舒服,并发还能往上提。
但这里有个坑:INT4的group size(分组大小)会影响显存和精度。group size越小,量化越精细,精度越好,但需要存储的scale和zero point越多,显存占用越大。常见的group size是128,如果降到64,精度会好一点但显存多占一些;升到256,显存省了但精度可能掉。这个参数需要根据你的精度要求来权衡。
另外要注意,INT4量化后反量化回FP16做计算,这个反量化本身有开销。如果kernel实现不好,省下来的带宽可能被反量化的计算吃掉。所以选推理框架的时候,要看它的INT4 kernel是不是经过优化的,比如vLLM、TensorRT-LLM这些都有专门的fused kernel。
2. 投机采样:用一个小模型给大模型"打草稿"
2.1 投机采样的本质是拿算力换带宽
投机采样(Speculative Decoding)这个思路第一次看会觉得有点反直觉:明明大模型已经够慢了,还要再跑一个小模型,不是更慢吗?
关键在于decode阶段是memory-bound的。大模型每生成一个token,都要把全部权重读一遍,但实际做的计算量很小。也就是说,算力大量闲置。投机采样就是利用这些闲置的算力:先用一个小模型(draft model)快速生成K个候选token,然后让大模型一次性验证这K个token。验证的时候,大模型只需要做一次前向(并行处理K个位置),就能判断哪些token是对的。
如果小模型猜得准,大模型一次前向就能确认多个token,相当于把"读一遍权重只生成一个token"变成了"读一遍权重生成多个token",带宽利用率大幅提升。这就是为什么投机采样能加速——它把memory-bound的decode变成了更接近compute-bound的批量验证。
加速比的理论上限是K+1(K个draft token加1个bonus token),但实际取决于小模型的接受率(acceptance rate)。接受率高,加速比就高;接受率低,大模型要频繁拒绝,反而浪费算力。
2.2 draft model的选择:不是越小越好
选draft model是投机采样最关键的一步。很多人以为draft model越小越快越好,其实不是。核心指标是接受率,而接受率和draft model与target model的"相似度"强相关。
常见的搭配策略:
- 同系列小模型:比如target是Qwen-72B,draft用Qwen-1.8B或Qwen-7B。同系列模型的tokenizer和训练数据分布接近,接受率通常比较高。
- 蒸馏模型:专门为某个大模型蒸馏出来的小模型,接受率往往比通用小模型高。
- EAGLE/Medusa:这类方法不走"独立小模型"的路线,而是在大模型上挂几个额外的预测头,直接预测后续token。EAGLE用特征层面的自回归,Medusa用多个解码头并行预测。它们的接受率通常比独立draft model高,但需要额外的训练。
我的实测经验:Qwen-72B配Qwen-7B做draft,在通用对话场景下接受率大概在0.7到0.8,加速比能到2倍左右。如果换成Qwen-1.8B,接受率掉到0.5左右,加速比反而只有1.5倍——因为小模型虽然快,但猜得不准,大模型验证时拒绝太多。
| draft model | 接受率(通用对话) | 实测加速比 | 备注 |
|---|---|---|---|
| 同系列7B | 0.7-0.8 | 约2.0x | 推荐 |
| 同系列1.8B | 0.5-0.6 | 约1.5x | 小但不够准 |
| EAGLE头 | 0.8-0.9 | 约2.5x | 需额外训练 |
| 通用小模型 | 0.4-0.6 | 约1.3x | 不推荐 |
2.3 K值怎么定:不是越大越好
投机采样里的K是每次draft生成的候选token数量。K越大,理论上一次验证能确认的token越多,但接受率会随着位置往后递减——第一个token接受率最高,越往后越低。
K=1时基本没有加速效果,因为验证的开销和收益抵消了。K=4到8是比较常见的甜点区。K太大(比如16),后面的token接受率很低,大模型验证时大部分被拒绝,浪费算力。
实际调K的时候,建议动态调整:根据当前的接受率来定。如果最近几次接受率都很高,可以适当增大K;如果接受率低,就减小K。vLLM和TensorRT-LLM都支持这种动态投机采样。
注意:投机采样在batch size较大时收益会下降。因为大batch下decode本身就不是纯memory-bound了,算力已经被利用起来,投机采样能榨取的额外算力就少了。所以投机采样最适合低并发、低延迟的场景,比如单用户对话。
2.4 投机采样的精度是严格无损的
这点必须强调:投机采样的输出分布和原始大模型是数学等价的。验证阶段的接受-拒绝机制保证了最终采样的token服从大模型的原始分布。所以投机采样不会损失精度,这是它相比量化的一大优势。
但有个前提:验证逻辑必须正确实现。有些实现为了图快,用了简化的验证策略,就会破坏等价性。自己实现的时候要特别注意,拒绝采样那一步的随机数生成和概率比较必须严格按论文来。
3. PD分离:把prefill和decode拆到不同的机器上
3.1 prefill和decode的瓶颈完全不同
要理解PD分离(Prefill-Decode Disaggregation),先得搞清楚prefill和decode这两个阶段的差异。
Prefill阶段处理的是用户输入的整个prompt,所有token并行计算,是典型的compute-bound场景。这个阶段算力吃满,显存带宽反而没那么紧张。耗时和prompt长度成正比。
Decode阶段是逐token生成,每次只处理一个token,是典型的memory-bound场景。算力闲置,带宽吃满。耗时和生成的token数成正比。
问题来了:如果把这两个阶段放在同一张卡上跑,它们会互相干扰。一个长prompt的prefill请求进来,会把decode的延迟拉高(因为prefill占用了算力);反过来,大量decode请求在跑,prefill的吞吐也会受影响。这就是所谓的prefill-decode干扰。
PD分离的思路很直接:把prefill和decode拆到不同的机器(或不同的GPU组)上,各自用最适合的资源配置。prefill机器用高算力的卡,decode机器用大显存的卡,互不干扰。
3.2 PD分离的架构长什么样
一个典型的PD分离架构包含这几个部分:
- Prefill集群:专门处理新进来的请求,做完整的prefill计算,生成KV Cache。
- Decode集群:接收prefill传来的KV Cache,逐token生成。
- KV Cache传输通道:prefill算完的KV Cache要传给decode节点,这是PD分离的核心难点。
- 调度器:决定请求怎么分配,什么时候触发KV Cache传输。
KV Cache的传输是最大的挑战。一个70B模型、8K上下文的请求,KV Cache大概有几个GB。这么大的数据要在节点间传输,网络带宽成了瓶颈。所以PD分离通常需要高速互联(比如NVLink、InfiniBand),普通以太网可能传输时间比省下来的还多。
传输方式有两种:
- 逐层传输:prefill算完一层就传一层,decode可以尽早开始。降低首token延迟,但实现复杂。
- 整体传输:prefill全部算完再传。实现简单,但首token延迟高。
3.3 什么场景下PD分离才划算
PD分离不是万能的,它的收益高度依赖场景。
适合的场景:
- 长prompt + 短输出:比如RAG、文档问答,prefill占大头,分离后prefill集群可以专门优化。
- 高并发、混合负载:有大量长短不一的请求,分离后可以分别调度,避免互相干扰。
- SLA要求严格:需要稳定控制首token延迟和每token延迟,分离后两者可以独立调优。
不适合的场景:
- 短prompt + 长输出:prefill占比小,分离的收益有限,还要承担KV Cache传输开销。
- 低并发:资源本来就闲着,分离反而增加复杂度。
- 网络带宽不足:KV Cache传输成为瓶颈,得不偿失。
我自己的经验是,PD分离在大规模、高并发的线上服务里收益最明显,小规模部署反而可能因为传输开销而变慢。上线前一定要做A/B测试,对比分离前后的端到端延迟和吞吐。
3.4 PD分离和量化的组合
PD分离和量化可以叠加,而且组合起来效果不错。prefill阶段是compute-bound,适合用量化来提升算力利用率(INT8的Tensor Core算力是FP16的两倍);decode阶段是memory-bound,适合用量化来降低带宽压力。
但要注意,prefill和decode用的量化方案可以不同。prefill可以用激进的INT8(甚至FP8),因为compute-bound场景对精度没那么敏感;decode用保守一点的权重量化,保证生成质量。这种混合精度的配置在PD分离架构下很容易实现,因为两个阶段本来就跑在不同的机器上。
KV Cache的量化在PD分离下更要仔细考虑,因为KV Cache要跨节点传输。量化后的KV Cache传输量更小,传输更快,但decode端反量化有开销。这个权衡需要根据网络带宽和算力来定。
4. 三项技术的组合实战与踩坑记录
4.1 组合顺序:先量化,再投机,最后PD分离
如果你打算把这三项技术都用上,建议的落地顺序是:
- 先做量化:这是收益最直接、风险最低的一步。先把模型压到INT8或INT4,把显存和带宽问题解决掉。
- 再加投机采样:在量化后的模型上加draft model,进一步榨取decode阶段的性能。注意draft model也要量化,否则它自己就成了瓶颈。
- 最后上PD分离:这是架构层面的改动,复杂度最高,放在最后做。前面两步已经把单机性能优化到位了,PD分离解决的是集群层面的调度问题。
这个顺序的好处是每一步都能独立验证收益,出问题也容易定位。如果一上来就三个一起上,性能不达标你都不知道是哪个环节的问题。
4.2 踩坑一:量化后投机采样的接受率暴跌
这是我踩过最坑的一个。单独用INT4量化的模型,精度没问题;单独用投机采样,加速比2倍。但两个一起用,接受率从0.75掉到0.4,加速比还不如不用投机采样。
原因在于:draft model和target model的量化误差不一致。draft model量化后输出的token分布,和量化后的target model的分布对不齐,导致验证时频繁拒绝。解决办法是让draft model和target model用相同的量化方案和校准集,保证两者的分布尽量对齐。如果还不行,draft model可以保持FP16不量化,虽然它慢一点,但接受率能回来。
4.3 踩坑二:PD分离的KV Cache传输把网络打满
第一次做PD分离的时候,没算清楚KV Cache的传输量。8K上下文、batch size 32的请求,KV Cache加起来几十GB,千兆网根本传不动,首token延迟反而比不分离还高。
后来换成了高速互联,并且做了几件事:
- KV Cache量化:传输前压成INT8,传输量减半。
- 逐层传输:prefill算完一层传一层,decode尽早开始,掩盖传输延迟。
- 请求分批:大batch拆成小batch传输,避免单次传输量过大。
调整之后首token延迟降下来了,吞吐也上去了。这个坑的教训是:PD分离之前一定要算清楚KV Cache的传输量,网络带宽是硬约束。
4.4 踩坑三:动态K值的投机采样在混合负载下抖动
投机采样的K值动态调整,在负载稳定的时候效果很好。但线上流量是波动的,K值频繁调整会导致延迟抖动。有时候K刚调大,流量模式就变了,接受率下降,反而拖慢。
解决办法是给K值调整加滞回区间(hysteresis):接受率高到一定程度才增大K,低到一定程度才减小K,中间区间保持不变。这样避免了频繁调整。另外可以按请求类型分组,不同类型的请求用不同的K值策略。
4.5 一个实际的配置参考
最后给一个我自己在用的配置,供参考。硬件是8卡A100 80GB,模型是Qwen-72B,服务的是通用对话场景,平均prompt 500 token,平均输出200 token。
| 配置项 | 设置 | 说明 |
|---|---|---|
| 权重量化 | AWQ INT4, group size 128 | 精度和显存的平衡点 |
| KV Cache | INT8 | 长上下文场景必需 |
| 投机采样 | 同系列7B draft, K=5 | 接受率约0.75 |
| PD分离 | prefill 3卡, decode 5卡 | 按负载比例分配 |
| KV传输 | 逐层传输 + INT8 | 降低首token延迟 |
这套配置下,相比FP16基线,吞吐提升了大概3.5倍,首token延迟降低了40%。当然这只是个参考,具体配置要根据你的模型、硬件和业务场景来调。
量化、投机采样、PD分离这三项技术,本质上都是在解决大模型推理的成本和延迟问题,但切入点不同:量化解决的是"每个参数占多少资源",投机采样解决的是"每次前向能产出多少token",PD分离解决的是"不同阶段怎么用不同的资源"。理解了这个底层逻辑,具体参数怎么调、方案怎么选,就有了判断的依据。真正上线的时候,别指望一套配置打天下,多测、多调、多对比,才是正道。