☰
大模型推理加速实战:量化、投机采样与PD分离的工程指南
2026/10/1 4:44:13 网站建设 项目流程

大模型推理这件事,真正跑过线上服务的人都知道,训练只是前半场,推理才是那个天天烧钱、天天被业务方催着降本的无底洞。一个70B级别的模型,如果用FP16权重全量加载,光显存就吃掉140GB,两张80G的卡刚够塞下权重,KV Cache和中间激活还没算进去。业务侧还要求首token延迟低于500ms、吞吐拉到每秒几百token,这时候你会发现,光靠堆卡是堆不出性价比的。量化、投机采样、PD分离这三样东西,基本就是当前推理加速的三根支柱:量化解决"权重和计算太占资源"的问题,投机采样解决"自回归解码一次只出一个token太慢"的问题,PD分离解决"预填充和解码互相拖累、资源利用率上不去"的问题。这篇内容我打算把这三块拆开揉碎讲清楚,从原理到实操参数,再到我踩过的坑,适合已经跑过推理服务、想进一步压榨性能的工程师,也适合刚接触推理优化、想建立完整认知框架的同学。

1. 量化:把权重从FP16压到INT8甚至INT4到底动了什么

1.1 量化的本质是一次带误差的映射

量化的核心动作,是把一个连续的浮点数值域,映射到一个离散的整数数值域上。以INT8为例,FP16的权重范围可能是[-3.2, 3.1],我们要把它压到[-127, 127]这个整数区间。映射公式很朴素:

scale = (max_val - min_val) / (q_max - q_min) zero_point = q_min - round(min_val / scale) q = round(x / scale) + zero_point

反量化的时候就是x_hat = (q - zero_point) * scale。这里的关键在于,x_hat和原始x之间必然存在误差,因为round操作丢掉了小数部分。量化要做的所有工程优化,本质上都是在让这个误差对最终模型输出的影响尽可能小。

为什么INT8通常掉点很少,而INT4就容易崩?因为INT8有256个离散档位,FP16的尾数有10位,两者表达能力差距没那么夸张;INT4只有16个档位,对于权重分布比较分散的层,量化误差会直接放大到输出上。我实测过一个13B模型,INT8 weight-only量化后困惑度(perplexity)从5.62涨到5.71,基本无感;换成INT4的group-wise量化(group size=128),困惑度涨到5.98,还能接受;但如果用per-tensor的INT4,直接飙到7.3,生成质量肉眼可见地变差。

1.2 权重量化、激活量化、KV Cache量化是三件不同的事

很多人一说量化就笼统地讲"我把模型量化了",但实际线上部署时,你得区分清楚量化的是哪一部分,因为它们的收益和代价完全不同。

权重量化(Weight-only Quantization)是最常见的做法,只把模型权重压成INT8或INT4,计算时反量化回FP16再做矩阵乘。它的收益是显存占用直接砍半甚至砍到四分之一,加载速度也快。代价是计算过程没有真正加速,因为反量化有额外开销,实际算力还是FP16的。适合显存瓶颈明显、算力相对充裕的场景。

权重+激活量化(W8A8)是把权重和激活值都量化成INT8,这样矩阵乘可以用INT8的Tensor Core来算,理论算力是FP16的2倍。但激活值的动态范围比权重难搞得多,因为激活值跟输入数据强相关,不同batch、不同序列长度下分布差异很大。所以W8A8通常需要做动态量化(per-token或per-channel),校准集的选择就很关键。

KV Cache量化是长上下文场景的救命稻草。一个32K上下文的70B模型,KV Cache能占到几十GB。把KV Cache从FP16压到INT8,显存直接省一半,能多塞好几个并发请求。但KV Cache量化对精度的影响比权重量化敏感,尤其是attention score的计算,量化误差会被softmax放大。

量化类型显存收益算力收益精度风险适用场景
Weight-only INT8约50%几乎无低显存瓶颈
Weight-only INT4约75%几乎无中显存极度紧张
W8A8约50%约2倍中算力瓶颈
KV Cache INT8KV部分50%无中高长上下文高并发

1.3 实操中量化校准集怎么选

做W8A8量化的时候,校准集(calibration dataset)的选择直接决定量化精度。我见过有人图省事,直接拿几百条通用语料跑一遍就完事,结果上线后特定领域的输出质量断崖式下跌。校准集的核心原则是:分布要贴近真实线上流量。

具体操作上,我会从线上日志里采样500到1000条真实请求,覆盖不同的输入长度、不同的业务类型。如果线上流量有长尾分布,校准集里也要体现出来。校准的步数不用太多,通常128到512个batch就够,因为量化参数(scale和zero_point)的估计收敛很快。

还有一个容易忽略的点:校准时的序列长度要覆盖线上最大长度。如果你校准用的是512长度,但线上跑的是8K长度,激活值的分布会完全不一样,量化误差会显著增大。我一般会把校准序列长度设成线上P99长度的1.2倍。

提示:量化校准不是一次性的工作。模型更新、业务流量变化后,最好重新跑一遍校准,否则精度会慢慢漂移。

1.4 量化模型部署时的那些坑

第一个坑是算子支持不全。你量化出来的模型,推理引擎不一定所有算子都支持INT8。比如某些特殊的激活函数、自定义的attention变体,可能只有FP16实现。这时候要么回退到FP16,要么自己写kernel,后者成本很高。部署前一定要用推理引擎的算子支持列表过一遍。

第二个坑是量化格式不统一。不同框架导出的量化模型格式五花八门,GPTQ、AWQ、GGUF、ONNX QDQ各有各的规范。跨框架迁移的时候经常出现"权重对不上"的问题。我建议在量化前就确定好目标推理引擎,用它官方推荐的量化工具链,别自己造轮子。

第三个坑是精度验证不充分。很多人量化完只看困惑度,觉得没涨多少就上线了。但困惑度是个平均指标,它掩盖了特定能力上的退化。我一般会准备一套任务级的评测集,覆盖问答、摘要、代码生成等场景,量化前后逐项对比。曾经遇到过一个案例,量化后困惑度只涨了0.05,但代码生成的通过率掉了8个百分点,这种问题只有任务级评测才能发现。

2. 投机采样:用一个小模型撬动大模型的解码速度

2.1 自回归解码的串行瓶颈

大模型推理慢,根子在于自回归解码是串行的。生成第t个token,必须等第t-1个token算完。这意味着GPU的并行算力在解码阶段根本吃不满,大部分时间花在等待内存读取权重上。一个70B模型,解码一个token要读140GB的权重(FP16),就算内存带宽是2TB/s,光读权重就要70ms,而实际计算量小得可怜。这就是所谓的memory-bound。

投机采样(Speculative Sampling)的思路很巧妙:既然大模型一次只能出一个token,那我找个小模型先"猜"出接下来几个token,然后让大模型一次性验证这几个token对不对。如果猜对了,就相当于大模型一次生成了多个token;如果猜错了,就回退到第一个错误的位置。这样把串行的解码变成了"并行验证",大幅提升了GPU利用率。

2.2 投机采样的数学保证:为什么猜错了也不影响输出分布

这是投机采样最精妙的地方。很多人担心"小模型猜的token会不会改变大模型的输出分布",答案是:不会。投机采样有一套严格的接受-拒绝机制,保证最终输出的分布和大模型单独解码的分布完全一致。

具体来说,假设小模型(draft model)对下一个token的预测概率是q(x),大模型(target model)的概率是p(x)。我们从小模型采样一个token x,然后以概率min(1, p(x)/q(x))接受它。如果拒绝,就从修正后的分布norm(max(0, p(x)-q(x)))中重新采样。数学上可以证明,这样得到的样本服从p(x)分布。

这个性质意味着,投机采样是无损的,它不会牺牲生成质量,只是加速。这一点和量化不同,量化是有损的,投机采样是无损的。所以如果你的场景对精度要求极高,投机采样是比量化更安全的选择。

2.3 Draft模型怎么选:不是越小越好

选draft模型是投机采样的核心决策。直觉上大家会觉得draft模型越小越快,但实际不是这样。draft模型太小,预测准确率低,大模型验证时频繁拒绝,反而浪费了验证的开销。draft模型太大,虽然准确率高,但draft本身的解码开销也上去了。

我实测下来的经验是,draft模型和target模型的参数量比例在1:10到1:20之间比较合适。比如target是70B,draft用3B到7B。另外draft模型最好和target模型同源,比如同一个base模型蒸馏出来的,这样两者的输出分布更接近,接受率更高。

还有一个技巧是用多层draft,也就是用两个不同大小的draft模型级联。小draft先猜,中等draft再猜,最后target验证。这样在不同难度的情况下都能有不错的接受率。不过实现复杂度高,收益提升有限,一般场景用单draft就够了。

Draft模型规模接受率(实测)单token加速比适用场景
1B以下40%-55%1.3x-1.6x简单任务
3B-7B65%-80%1.8x-2.5x通用场景
13B80%-90%1.5x-2.0x复杂任务

2.4 投机采样的参数调优:speculative length怎么定

投机采样有一个关键参数:每次让draft模型猜多少个token,也就是speculative length(也叫lookahead)。这个参数直接决定了加速效果。

猜得太少,比如只猜2个,那验证的并行度不够,加速有限。猜得太多,比如猜10个,draft模型后面几个token的准确率会急剧下降,大部分都被拒绝,浪费计算。我实测下来,speculative length在4到6之间比较平衡。具体值要看draft模型的接受率曲线,接受率高的可以设大一点。

还有一个动态调整的策略:根据历史接受率动态调整speculative length。如果最近几次接受率都很高,就增大length;如果接受率低,就减小。这样能自适应不同的输入难度。vLLM和TensorRT-LLM都支持这种动态策略。

注意:投机采样的加速比不是线性的。当batch size增大时,解码阶段逐渐从memory-bound变成compute-bound,投机采样的收益会下降。所以投机采样最适合低batch、低并发的场景,比如在线对话。高并发场景下,还是得靠batching和PD分离。

2.5 投机采样和量化的叠加效果

这两个技术可以叠加使用,而且叠加效果不错。量化降低了单次前向的显存和计算开销,投机采样提升了并行度。我实测过一个组合:70B模型做INT8权重量化,draft用7B模型,speculative length=5,在单请求场景下,相比FP16无投机采样,端到端加速比达到3.2倍。

但叠加时要注意,量化后的target模型和draft模型的分布差异可能变大,导致接受率下降。所以如果要做量化+投机采样,最好让draft模型也做同样的量化,保持分布一致性。

3. PD分离:把预填充和解码拆到不同机器上

3.1 预填充和解码的资源需求完全不同

大模型推理分两个阶段:预填充(Prefill)和解码(Decode)。预填充是把整个输入prompt一次性过一遍模型,计算出KV Cache,这个阶段是compute-bound,算力吃满,显存带宽反而没那么紧张。解码是逐token生成,每次只算一个token,这个阶段是memory-bound,算力闲置,显存带宽是瓶颈。

这两个阶段的资源需求差异巨大,如果放在同一张卡上跑,就会出现"预填充时解码饿死,解码时算力闲置"的情况。尤其是在线服务,请求是动态到达的,长prompt的预填充会阻塞后面的解码请求,导致首token延迟(TTFT)和token间延迟(TPOT)都很难看。

PD分离(Prefill-Decode Disaggregation)的思路就是:把预填充和解码拆到不同的机器或不同的GPU上,各自独立调度。预填充集群专门处理prompt,算完KV Cache后传给解码集群;解码集群专门做逐token生成。这样两边都能按自己的资源特性做优化,互不干扰。

3.2 KV Cache的传输是PD分离的核心难点

PD分离最大的工程挑战是KV Cache的传输。一个70B模型,32K上下文的KV Cache大小大概是:

KV Cache size = 2 * num_layers * num_kv_heads * head_dim * seq_len * dtype_size

以Llama 2 70B为例,80层,8个KV head(GQA),head_dim=128,seq_len=32768,FP16:

2 * 80 * 8 * 128 * 32768 * 2 bytes = 10.7 GB

10.7GB的数据要在预填充节点和解码节点之间传输。如果走PCIe 4.0 x16,理论带宽32GB/s,实际能到20GB/s左右,传输耗时约0.5秒。如果走网络(比如100Gbps网卡),理论12.5GB/s,实际8GB/s左右,传输要1.3秒。这个延迟对于TTFT来说是致命的。

所以PD分离的部署,预填充和解码节点之间的互联带宽是关键。同机多卡用NVLink最好,跨机的话至少要用高速网络。如果带宽不够,KV Cache传输的延迟会吃掉PD分离带来的所有收益。

3.3 实际部署中的调度策略

PD分离的调度比单体部署复杂得多。核心要解决两个问题:预填充请求怎么分配到预填充节点,解码请求怎么分配到解码节点,以及KV Cache怎么路由。

我实践下来比较有效的策略是分层调度。预填充层用最短队列优先(Shortest Queue First),因为预填充的计算时间跟prompt长度强相关,短prompt先处理能降低平均TTFT。解码层用连续批处理(Continuous Batching),把不同请求的解码步骤合并成一个batch,提升GPU利用率。

KV Cache的路由要保证同一个请求的预填充和解码在"配对"的节点上。通常会在预填充节点和解码节点之间维护一个映射表,预填充完成后,根据解码节点的负载情况选择一个节点,把KV Cache传过去。这里有个优化点:如果预填充节点和解码节点在同一台机器上,KV Cache可以通过共享内存传递,省掉网络传输。

调度策略优点缺点适用场景
最短队列优先降低平均TTFT长prompt可能饿死短prompt为主
轮询实现简单负载不均请求均匀
负载感知负载均衡好实现复杂大规模集群
亲和性调度减少KV传输可能负载不均同机多卡

3.4 PD分离的收益边界:什么时候不值得做

PD分离不是银弹,它有明确的适用边界。如果你的服务满足以下条件,PD分离的收益可能覆盖不了它的复杂度:

  • 请求量很小,单卡就能扛住,没有资源争抢
  • prompt都很短,预填充开销可以忽略
  • 对TTFT要求不严格,可以容忍预填充阻塞
  • 集群规模小,没有独立的预填充和解码资源池

我一般建议,当单卡QPS超过5,或者prompt长度P99超过2K,或者TTFT的P99要求低于1秒时,才考虑上PD分离。否则用连续批处理+chunked prefill就能解决大部分问题。

chunked prefill是个折中方案:把长prompt的预填充切成多个chunk,每个chunk和decode请求混在一个batch里跑。这样既不会让预填充阻塞解码,又不需要拆机器。实现上比PD分离简单得多,收益在中等规模场景下也很可观。

3.5 PD分离和量化的协同

PD分离场景下,量化的收益会被放大。因为预填充节点和解码节点的资源瓶颈不同,量化对两者的收益也不同。预填充是compute-bound,W8A8量化能直接提升算力,缩短预填充时间。解码是memory-bound,权重量化能减少显存带宽压力,提升解码速度。

我实测过一个配置:预填充节点用W8A8量化,解码节点用INT4权重量化+KV Cache INT8。相比全FP16的PD分离,整体吞吐提升了2.1倍,TTFT降低了35%。这个组合的关键是,预填充对精度敏感度低(因为只算一次),可以用更激进的量化;解码对精度敏感度高(因为误差会累积),量化要保守一些。

4. 三套技术的组合拳:怎么根据场景选型

4.1 先定位瓶颈,再选技术

推理加速最忌讳的就是"别人用什么我就用什么"。量化、投机采样、PD分离各自解决不同的问题,选错了不仅没收益,还会增加复杂度。

我的选型逻辑是这样的:先看显存是不是瓶颈。如果模型加载后显存剩余不足20%,优先上权重量化。再看算力是不是瓶颈。如果GPU利用率长期低于50%,说明是memory-bound,优先上投机采样或KV Cache量化。最后看调度是不是瓶颈。如果TTFT和TPOT的P99波动很大,说明预填充和解码在互相干扰,考虑PD分离或chunked prefill。

瓶颈类型判断指标首选技术次选技术
显存不足显存利用率>90%权重量化KV Cache量化
算力闲置GPU利用率<50%投机采样增大batch
调度干扰TTFT/TPOT波动大chunked prefillPD分离
长上下文KV Cache占比>50%KV Cache量化PD分离

4.2 一个真实的组合案例

我经手过一个在线客服场景,模型是13B,平均prompt长度800,平均输出长度200,QPS峰值15。最初的部署是单机双卡FP16,TTFT的P99是2.3秒,TPOT的P99是180ms,业务方不满意。

第一步,上了INT8权重量化,显存从26GB降到14GB,单卡能塞下模型了,TTFT降到1.8秒。第二步,加了KV Cache INT8量化,显存进一步降到11GB,batch size从4提到8,TPOT降到120ms。第三步,上了投机采样,draft用1.5B模型,speculative length=4,接受率72%,TPOT降到75ms。第四步,因为QPS上来了,单机双卡开始出现预填充阻塞,上了chunked prefill,TTFT的P99降到1.1秒。

最终配置:INT8权重量化 + KV Cache INT8 + 投机采样 + chunked prefill,TTFT的P99从2.3秒降到1.1秒,TPOT的P99从180ms降到75ms,单机吞吐从8 QPS提到22 QPS。整个过程没有上PD分离,因为chunked prefill已经解决了调度问题,PD分离的复杂度不值得。

4.3 组合时的相互影响

这几个技术组合时,不是简单叠加,它们之间有相互影响。

量化会影响投机采样的接受率。量化后的target模型输出分布会有微小偏移,如果draft模型没做同样的量化,接受率会下降。我实测过,target做INT8量化、draft不做量化,接受率从75%降到62%。所以要么两者都量化,要么都不量化。

量化也会影响PD分离的KV Cache传输量。KV Cache量化后,传输的数据量减半,传输延迟也减半。这在跨机PD分离场景下收益很明显。

投机采样和PD分离的协同比较微妙。投机采样提升了解码速度,意味着解码节点能处理更多请求,可能会加剧预填充节点的压力。所以如果同时上这两个技术,预填充和解码的资源配比要重新调。

4.4 精度验证的完整流程

不管上哪个技术,精度验证都是必须的。我一般分三层验证:

第一层是困惑度对比,快速筛掉明显有问题的配置。困惑度涨幅超过5%就要警惕。

第二层是任务级评测,用业务相关的评测集,覆盖主要场景。这一层能发现困惑度掩盖的问题。

第三层是在线A/B测试,小流量灰度,对比业务指标(比如客服场景的解决率、用户满意度)。这一层最真实,但成本也最高。

三层都过了,才能全量上线。我见过太多团队跳过第二层直接上线,结果被业务方投诉生成质量下降,回头排查发现是量化校准集没覆盖某个业务场景。

提示:精度验证要固定随机种子,否则生成结果的波动会干扰判断。另外评测集要定期更新,避免模型对评测集过拟合。

5. 工程落地中的几个反直觉发现

5.1 量化不一定省时间,但一定省显存

很多人以为量化后推理会变快,实际上权重量化(weight-only)在不少场景下反而变慢,因为反量化有额外开销,而且INT8的矩阵乘如果没有专门的kernel优化,可能还不如FP16。量化的核心收益是显存,显存省下来能塞更大的batch,间接提升吞吐。所以如果你的瓶颈是算力而不是显存,权重量化帮不上忙,得用W8A8。

5.2 投机采样的加速比和batch size成反比

这个前面提过,但值得再强调。投机采样在batch size=1时加速比最高,能到2到3倍。batch size增大后,解码阶段逐渐变成compute-bound,投机采样的并行验证优势被稀释,加速比可能降到1.2倍甚至更低。所以投机采样最适合在线低并发场景,高并发场景下batching的收益更大。

5.3 PD分离的收益在长prompt场景才明显

如果prompt都很短(比如平均100 token),预填充开销很小,PD分离的收益微乎其微,反而增加了KV Cache传输的开销。PD分离的收益在prompt长度超过1K、且请求混合了长短prompt时才明显。短prompt场景用chunked prefill就够了。

5.4 KV Cache量化对长上下文的影响是非线性的

KV Cache量化在短上下文下几乎无感,但上下文越长,量化误差累积越严重。我实测过,4K上下文下KV Cache INT8的困惑度涨幅是0.02,32K上下文下涨到0.15。所以长上下文场景做KV Cache量化,要么用更细粒度的量化(per-channel),要么保留部分层不量化。

6. 从实验到生产的检查清单

把这三套技术从实验推到生产,我总结了一份检查清单,每次上线前过一遍,能避开大部分坑。

量化相关:

  • 校准集是否覆盖线上主要场景和长度分布
  • 推理引擎是否支持所有量化算子
  • 量化格式是否和目标引擎匹配
  • 任务级评测是否通过
  • 是否有回退到FP16的预案

投机采样相关:

  • draft模型和target模型是否同源
  • speculative length是否根据接受率动态调整
  • 接受率是否在合理区间(60%以上)
  • 高并发场景下加速比是否仍然为正
  • draft模型的显存开销是否可接受

PD分离相关:

  • 预填充和解码节点之间的带宽是否足够
  • KV Cache传输是否有压缩或量化
  • 调度策略是否适配请求分布
  • 是否有降级到单体部署的预案
  • 监控是否覆盖TTFT、TPOT、KV传输延迟

通用:

  • 是否有完整的性能基线(TTFT、TPOT、吞吐、显存)
  • 是否有精度基线(困惑度、任务指标)
  • 是否有灰度发布和回滚机制
  • 监控告警是否覆盖关键指标

这份清单不是摆设,我每次上线前都会逐项确认。有一次就是因为漏了"推理引擎算子支持"这一项,上线后发现某个自定义attention算子没有INT8实现,整个量化模型跑不起来,临时回退浪费了两个小时。

7. 我个人在实际操作中的几点体会

做推理加速这几年,最大的体会是:没有银弹,只有权衡。量化省显存但可能掉精度,投机采样加速但增加复杂度,PD分离提升资源利用率但引入传输开销。每个技术都有它的适用边界,关键是先定位清楚自己的瓶颈在哪。

第二个体会是:先做简单的,再做复杂的。很多团队一上来就想上PD分离,结果发现chunked prefill就能解决问题。先上量化,再上投机采样,最后考虑PD分离,这个顺序在大多数场景下都是合理的。每上一步,都要有明确的性能收益和精度验证,不要为了技术而技术。

第三个体会是:监控比优化更重要。你优化了半天,如果没有完善的监控,根本不知道优化有没有效果,也不知道瓶颈转移到了哪里。TTFT、TPOT、GPU利用率、显存利用率、KV Cache命中率,这些指标要实时可见。我见过太多团队优化完不监控,结果线上出问题排查半天。

最后一个体会是:精度验证要贯穿始终。推理加速的所有技术,最终都要服务于生成质量。加速比再高,如果生成质量下降,业务方也不会买账。所以精度验证不是上线前的一道关卡,而是贯穿整个优化过程的持续动作。每次改配置,都要跑一遍精度验证,确保没有退化。

这套东西说起来复杂,但真正跑通一遍之后,你会发现推理加速的收益是实打实的。一个配置调优好的推理服务,相比朴素部署,成本能降一半以上,延迟能降一个数量级。这个投入产出比,值得花时间去啃。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询