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

1. 先搞清楚瓶颈:自回归生成的两个阶段为什么是天生的短板

前阵子帮团队调一个70B模型的在线推理服务,GPU规模不小,量化早就上了INT8,显存也够,可用户体感的生成速度就是上不去。排查到最后,问题不在"算力不够",而在一个很多人忽略的基本事实:大模型生成是自回归的,一次前向只吐一个token,而且计算密集的预填充和访存密集的逐词生成这两个阶段,对GPU资源的需求是截然相反的,硬挤在同一批卡上,谁都跑不痛快。

这篇文章把量化、投机采样、PD分离这三件事从头到尾讲透。它们分别对应三种完全不同的加速思路:量化让单次计算更快、显存更省;投机采样减少自回归解码的步数;PD分离优化系统层面的GPU调度方式。三者在不同场景下的收益差异很大,选错了组合,可能辛苦折腾半天,延迟纹丝不动。适合正在做推理部署、或想搞懂vLLM、TensorRT-LLM这些推理引擎背后原理的工程师阅读,也适合打算本地部署开源大模型但又嫌慢的朋友参考。

1.1 一次只吐一个词:自回归本质决定的核心约束

大模型的推理和训练最大的不同,是它有严格的"时序依赖"。给定输入序列,模型需要逐个预测下一个词,第t个词的概率分布依赖前t-1个词的上下文。也就是说,无论GPU多强,第100个token都必须等第99个token算完才能开始。这不是工程没做好,而是Transformer自回归架构的数学本质,绕不开。

这就引出了第一个关键结论:推理加速的核心,要么让每一步前向计算更快,要么让需要前向的次数更少。量化属于前者,投机采样属于后者。PD分离则更进一步,它不改变单步计算本身,而是让不同性质的请求不要互相干扰,从而让整张GPU卡的实际利用率上去。

很多刚接触推理优化的人容易犯一个错误:一上来就把所有注意力放在"怎么让单个token的计算变快"上,而忽视了自回归带来的串行瓶颈。我见过有人在单卡上把量化方案做到极致,单token推理从20ms优化到12ms,但端到端生成2000个token,总耗时还是让人着急——因为步数并没有减少。所以先把这个底层约束刻在脑子里,后面看所有加速手段都会豁然开朗。

1.2 Prefill与Decode:一个吃算力,一个吃带宽

自回归的每一步,在GPU眼里并不是一样的。业内把推理过程分成两个阶段,命名很形象:Prefill(预填充)和Decode(逐词生成)。

Prefill阶段一次性处理用户输入的整个prompt,比如几千个token。这个阶段是典型的计算密集型:矩阵乘法的规模很大,GPU的Tensor Core能充分跑起来,算力利用率非常高。代价是它占用的显存和耗时跟输入长度近似成正比,遇到超长文档理解类请求,一次prefill可能吃掉几十GB的显存带宽,甚至拖慢整卡好几百毫秒。

Decode阶段则恰恰相反。每次只生成一个token,需要把模型全部权重和已经累积的KV Cache读一遍,但只产生一个token的计算量。用行话讲,这是**显存带宽瓶颈(Memory-Bound)**阶段:GPU不是在"算不过来",而是在"等数据从显存搬到计算单元"。实测中,小batch场景下Decode的算力利用率经常只有个位数百分比。

这两个阶段在同一张卡上混合跑,是很多线上服务性能差的根源。想象一条高速公路,prefill像一大排货车缓慢并道,decode像大量小车要频繁进出,混在一起谁都被堵住。后面要讲的PD分离,本质就是给这两种车各修一条专用道路。

1.3 三大加速思路的坐标定位

把瓶颈定位清楚之后,三个加速技术的定位就非常清晰了:

  • 量化:降低每一步计算和搬运的数据量。权重从FP16压缩到INT8/INT4,参数少了一半甚至更多,显存带宽压力和显存占用同步下降。它不影响步数,也不改变调度逻辑,是收益最直接、适用范围最广的"基础操作"。
  • 投机采样:减少大模型前向的次数。用一个便宜的小模型先草拟一串token,大模型跑一次前向并行验证好几个位置,一次"批处理"顶原来的多次串行解码。
  • PD分离:改变的是GPU资源的组织方式。把prefill和decode拆到不同机器或不同资源池,避免互相抢占,提升整体吞吐和延迟稳定性。

一个容易混淆的点是:这三者不是互斥的,而是可以叠加的。量化是"地基";投机采样针对decode阶段的低利用率;PD分离解决的是调度层面的"内耗"。实际生产中,三者经常同时出现,只是在不同规模下有不同优先级。接下来逐一拆解。

2. 量化:最朴素的"降维打击",但也最容易翻车

量化是推理加速里最热门、落地最广的手段,网上随便一搜就是"int8量化""qwen 27b int4量化本地部署"之类的内容。它确实好用,但很多教程只讲"怎么跑通",不讲"为什么有效、什么时候失效"。如果只是照抄别人的量化脚本,很容易在精度和加速上同时翻车。

2.1 量化到底在做什么:映射、缩放与误差来源

量化的本质一句话:把模型权重和激活值从高精度浮点数(通常是FP16或FP32)映射到低比特整数(INT8、INT4),减少存储和计算开销。

映射公式很基础:q = round(r / scale) + zero_point,反量化则是r = (q - zero_point) * scale。其中scale是缩放系数,zero_point是零点偏移,用来把浮点数值域对齐到整数范围。比如FP16的数值范围可能落在[-6, 6],映射到INT8的[-128, 127],scale就约等于6/127。

听起来简单,但量化是一个有损压缩过程,误差主要来自两个方面:

  • 截断误差:超出scale覆盖范围的极端权重会被直接截断到边界值,这部分信息彻底丢失。
  • 舍入误差:量化后再反量化无法精确还原原始值,中间差的那一点就是我们说的量化误差。

所有量化方案的差异,本质都在解决这两个误差。有的方案用校准数据去统计权重的真实分布,让scale选得更聪明;有的方案发现Transformer里只有少数"显著通道"对精度影响巨大,于是对这些通道特殊照顾。理解了这一点,再看GPTQ、AWQ这些名词就不会觉得玄乎了。

2.2 三种量化粒度:权重、激活与KV Cache

量化按作用对象分,主要三种,很多人一开始只做了第一种:

权重量化(Weight-Only Quantization):只压缩模型权重,激活值保持FP16。这是性价比最高的选择,因为模型参数一动也不动,除了精度和显存,运行时激活计算还是高精度,掉点最轻微。市面上大多数"INT4推理"都属于这一类,典型代表是llama.cpp的GGUF系列。

激活量化(Weight + Activation Quantization):把每层前向传播中的激活值也量化到INT8。好处是可以真正利用NVIDIA Tensor Core的INT8矩阵乘算力,计算速度提升明显,坏处是激活值的分布往往随输入变化,一不小心就掉精度。需要仔细选校准集,推理引擎如TensorRT-LLM里做INT8/FP8通常都属于这种。

KV Cache量化:推理到一半时,每一层每个token都要缓存一份K和V向量,长上下文、高并发时这部分显存占用甚至超过模型权重本身。把KV Cache从FP16压到INT8通常能省一半显存,把并发度直接拉高一截。这点在PD分离架构里尤其重要,后面会细说。

三种粒度的收益不是"都要做"才好,而是得看瓶颈。显存不够就先做权重量化;服务吞吐上不去再考虑激活量化和算子优化;长上下文场景优先盯住KV Cache。

2.3 GPTQ、AWQ与GGUF:主流PTQ方案怎么选

目前大部分落地用的是训练后量化(PTQ),不用重新训练,只需要少量校准数据。我用过的方案里,最主流的三个是:

方案适用引擎核心思路我的使用建议
GPTQ主要是GPU推理(vLLM、ExLlama)逐层渐进式量化,通过补偿更新剩余权重来减小误差显存紧张、追求INT4低比特时优先考虑
AWQvLLM、HuggingFace生态按激活值显著性保护少量关键权重通道,不掉点精度敏感场景靠谱,校准数据要选好
GGUFllama.cpp / Ollama等分片存储、支持CPU+GPU混合推理本地部署、消费级显卡首选,CPU也能跑

GPTQ的原理值得多说两句。它受"最优脑外科"方法的启发:逐层跑前向,量化当前层权重后,用最小二乘法更新当前层剩余权重,来补偿被量化破坏的信息。实测中GPTQ在7B、13B级别的模型上INT4掉点通常很小,但模型越大,校准数据的选择越重要。

AWQ的切入点更有意思。它观察到,权重矩阵里虽然大部分数值分布均匀,但总有少数通道的激活值特别大,这些通道对应的权重一旦被量化,误差会被放大。于是AWQ按激活值统计给不同通道分配不同缩放因子,只保护这些关键通道,其余照常量化。我实际对比过同条件下AWQ和普通RTN(直接取整)量化,MMLU类基准上AWQ经常能救回1到2个点。

2.4 实测要看的几个数字:显存、精度与"假加速"陷阱

量化最大的误区,是把"显存减少"直接等同于"速度变快"。拿一个27B级别的Qwen模型举例:FP16权重约54GB,INT8约27GB,INT4约13.5GB。单张4090(24GB显存)跑FP16版本根本加载不下;INT8版本可以加载但留给上下文的空间有限;INT4版本就很从容,还能开较大的并发。量化的首要价值是让模型"放得下、跑得起",其次才是通过减少显存带宽压力换取速度。

速度方面,要看具体硬件。NVIDIA的GPU对INT8矩阵乘有专门的Tensor Core加速,所以INT8在计算密集场景确实能实打实变快;但INT4在很多卡上并没有原生INT4计算单元,常见做法是存储用INT4、计算时反量化为FP16或INT8,这时省的是显存和搬运开销,计算本身不会翻倍快。很多博主说的"INT4快了两倍",多半是在说显存节省,不是结算加速。部署前先搞清楚自己卡的原生支持能力,能少走不少弯路。

精度验证也千万别省。量化后不要只看一两句话生成是否顺眼,要么跑一下困惑度,要么跑一组标准评测集,和FP16基线对比。低于0.5到1个百分点可以接受,明显掉点说明校准集或量化粒度选得不对。

提示:从我的实践看,INT8权重量化在绝大多数场景下对精度的影响小到可以忽略,是"无脑可以先上"的配置;INT4则需要多做一轮精度校验,尤其是在数学、代码这类对输出严谨度要求高的任务上。

3. 投机采样:小模型打草稿,大模型做裁判,少跑几步冤枉路

量化解决"每一步算得更快",投机采样换了一个思路:让大模型每一步吐出更多有效token。这是近两年推理加速研究最活跃的方向之一,从2022年底的推测解码(Speculative Decoding),到Medusa、EAGLE这些变体,都已经进入主流推理引擎。

3.1 核心原理:一次前向换一串token

投机采样的流程,想象一个场景:资深专家写报告速度慢,但让他审阅实习生的草稿很快。我们先让一个**小模型(草稿模型)快速自回归生成K个token(比如K=4,就是草拟4个词);然后把草拟的K个token接在原始上下文后面,交给大模型(目标模型)**做一次前向,并行算出这K个位置的token概率。

大模型拿到数据后开始"审稿":从第1个草拟token开始,如果草稿token的概率不低于大模型自身的概率,就接受它;如果低于,就拒绝,并从修正后的分布中重新采样。被接受的最长前缀能直接作为输出,一口气吐出好几个token——但大模型只做了一次前向。

这里的关键是,大模型输出的概率分布和纯自回归时保持一致。实现上用**拒绝采样(Modified Rejection Sampling)**保证无偏性:草稿token若被接受,直接输出;若被拒绝,则按max(0, p_target(x) - p_draft(x))归一化后的分布重新采样。这样从数学上讲,投机采样得到的结果和直接大模型自回归是等价的,质量不打折。

3.2 加速比到底怎么算:接受率、草稿长度与开销

很多人以为投机采样的加速比等于草稿token数K,以为草拟5个就能快5倍,这是最典型的误解。实际上每轮接受的token数是个随机变量,取决于草稿模型和目标模型输出分布的匹配程度。

假设草稿模型每步的接受率都是α,那么每轮接受期望token数约等于1 + α + α² + ... + α^K。当α=0.7、K取6时,期望大概在3倍左右;当α只有0.3时,期望不到1.4倍。草稿模型质量是投机采样的第一决定因素,K值越大,后面的token被接受的概率越小,边际收益迅速递减,反而白白增加草稿模型耗时。

第二个因素是草稿模型的推理开销。大模型前向假设耗时1个单位,小模型假设耗时0.2个单位。如果每轮期望接受2.5个token,那么一个完整周期耗时是0.2+1=1.2,实际加速比约为2.5/1.2≈2.08倍,远低于理论接受率2.5倍。所以草稿模型不是"越小越好",而是要跟目标模型在token分布上接近、并且本身足够快。

第三个因素是batch大小。这是为什么很多人实测投机采样效果不佳的重要原因:小batch(比如单请求流式输出)时空闲算力多,投机采样收益明显;一旦batch大起来,目标模型本身的算力利用率已经很高,加一个草稿模型反而是负累。在线高并发服务使用投机采样前,务必拿真实并发做压测,别被单请求的漂亮加速比迷惑。

3.3 工程落地的坑:tokenizer不一致、分布偏移与batch冲突

说几个我踩过或见别人踩过的坑。

第一,草稿模型和目标模型的词表必须完全一致。模型打草稿时输出的token id,要直接喂给目标模型去算对应位置的概率,如果两个模型用了不同的tokenizer,整个校验流程根本走不通。所以草稿模型一般选择同源小版本,比如Qwen-7B配Qwen-0.5B这种同族组合,而不是随便拿一个大模型配一个完全不相干的模型。

第二,投机采样对温度敏感。温度接近1时,分布比较"诚实",草稿模型匹配度尚可;但低温采样时输出更确定,草稿模型容易被过高自信的预测坑害,接受率会下降。如果业务需要低温或贪心解码,建议多调几档K值对比。

第三,服务端的batch调度冲突。投机采样需要目标模型对草稿token做一次前向,而草稿token生成的KV状态和真实输出状态要分开管理,在vLLM这类引擎里如果配置不当,会干扰动态batching的正常调度。我建议优先使用推理引擎官方实现的投机采样支持(vLLM的--speculative-config、TensorRT-LLM的相关配置),而不是自己手写,除非你有团队有能力维护这套状态管理逻辑。

除了"小模型草拟"这条路,Medusa和EAGLE的思路也值得一提。它们不引入独立小模型,而是给目标模型本身训练几个额外的预测头/特征映射,让模型在一次前向后直接给出多个位置的候选token。好处是省去一套小模型的前向开销,也没有tokenizer对齐问题;坏处是需要额外训练这些附件结构,应用范围受限,更适合模型团队自研的场景。

4. PD分离:把prefill和decode拆到不同机器,让它们各干各的

量化是对单步计算动刀,投机采样是对解码步数动刀,PD分离则直接改变GPU的组织架构。最近一年各种推理框架都在宣传这个能力,但真正理解它价值的人不多。我先说清楚它解决的具体问题。

4.1 混部环境下的"互相拖累"问题

回到1.2节说的两个阶段。假设你有一个在线服务,用户既会发长文档分析(几万字prompt),也会发短对话(几十字prompt)。在没有分离的"混部"模式下,每次有新请求进来,prefill和decode都在同一批GPU上混合跑。

问题来了:一个超长文档的prefill可能占满整卡算力几百毫秒。在这期间,正在decode的所有请求都被迫排队等待,用户的生成速度出现明显卡顿。更麻烦的是,prefill和decode的最优batch策略不同,prefill适合尽量填满算力、一次多算几个请求,decode又希望每个请求能被稳定调度、延迟不抖动。两套目标在同批卡上妥协,结果就是TTFT(首token延迟)和TPOT(单token生成延迟)双双不稳定,预测性差,用户体验糟糕。

有人会说,这不就是调度器调度的问题吗?改进动态批处理就行。是的,但prefill计算量随输入长度变化剧烈,哪怕调度器再聪明,一个巨型prompt的到来也会造成瞬时的资源冲击。与其让调度器在毫秒级别精打细算,不如从物理层面解决。

4.2 PD分离架构与KV Cache传输的核心代价

PD分离的做法很直接:把集群中的GPU分成两组,一组专门跑prefill,另一组专门跑decode。prefill节点接收到请求后,快速把整段输入的KV Cache算好,然后通过网络把KV Cache传给decode节点;decode节点不需要重新计算prompt部分的KV,直接拿着传过来的KV Cache开始逐token生成。

这样做的好处:

  • TTFT更短:prefill节点全神贯注处理新请求,不用被decode请求挤占资源,长prompt的响应速度大幅提升。
  • TPOT更稳定:decode节点只做小步快跑的自回归生成,不会被prefill的突发大计算打断,延迟方差显著下降。
  • 资源弹性更好:prefill和decode可以分别扩缩容。如果产品是聊天机器人,decode节点要多配;如果产品是文档分析,prefill节点要多配。

最大的代价和难点是KV Cache传输。KV Cache不是个小东西:一个7B模型的32层Transformer,处理2K长度的输入,每生成一个序列产生的KV Cache就可能接近或超过1GB。到了70B级别、上下文4K到8K,一份KV Cache就是几十GB。把这些数据从prefill节点传到decode节点,延迟和带宽都是真金白银的开销。

所以PD分离工程上一般配套做三件事:

  1. KV Cache量化,把传输的KV Cache从FP16压到INT8甚至INT4,这是前面量化章节里"KV Cache量化"在这个架构下的最佳应用场景。
  2. 优化传输链路,节点间用高带宽网络(如RDMA)或GPU直连(如NVLink域)减少拷贝开销,部分实现还会把KV Cache按前缀去重,复用相同的系统提示词缓存,进一步减少需要传输的数据量。
  3. 压缩与延迟权衡,如果prefill节点和decode节点距离远,宁可KV Cache多压缩一点;如果同机柜,则可以少量化一点保住质量。这是个系统级调优问题,没有标准答案,得用数据说话。

4.3 适用场景与和量化的化学反应

PD分离不是万金油,它更适用于高并发、长上下文、对延迟稳定性要求高的在线服务。如果你的场景是离线批量跑一堆样本,或者本地个人使用(一台机器一张卡),PD分离毫无意义——你根本没有集群。这也是很多人看论文看得热血沸腾,回到自己单卡环境却发现用不上的原因。

但一旦服务规模上来了,PD分离和量化、投机采样的"化学反应"是立体的。prefill节点上,因为不涉及逐token生成、不需要维护稳定主频占用,可以放心用高吞吐的INT8/FP8激活量化;decode节点上,读权重和KV Cache是主要瓶颈,权重量化和KV Cache量化直接降低带宽压力,同时可以在这基础上叠加投机采样——decode节点往往batch适中,空闲算力较多,投机采样的加速比正合适。

还有一类实践是把PD分离与流式输出管线结合。请求到达后,prefill节点可以先把首段KV发送给decode节点,decode节点即可开始吐第一个token,无需等待整个长输入的prefill全部完成。对超长上下文场景,这能把TTFT从"几十秒"压到"几百毫秒"级别,效果非常震撼。各推理引擎对这些能力都有一些实验性配置,读取官方文档时重点看"disaggregated prefill"或"prefill-decode disaggregation"关键词。

5. 组合拳怎么打:从单卡本地到大规模集群的加速决策

把三大技术单个讲完,最后一个关键问题是:具体到我自己的场景,该上哪些、按什么顺序上?

5.1 按场景选方案:个人部署、中小服务与大集群

我按最常见的三类环境给一个参考决策表:

环境典型配置首选方案次选方案不建议
个人本地部署单张消费级显卡(24GB以下)INT4权重量化(GGUF)投机采样(如果推理引擎支持且显存有余量)PD分离
中小团队在线服务1到几十张A100/H800INT8/FP8量化 + KV Cache量化投机采样(单路或低并发流式场景)先不要上复杂PD分离,优先调好调度器
大规模集群服务几十到上百张卡,高并发PD分离 + KV Cache量化结合FP8激活量化和投机采样不加压测验证就盲目叠加

个人部署的逻辑最清楚:先让模型能在显存放得下。以27B级别模型为例,FP16权重约54GB,单张消费卡根本无戏;INT4权重约13.5GB,配4090不仅跑得动,还能留出上下文空间。这个量级下投机采样能否开启,取决于推理引擎支持情况和草稿模型的显存占用。llama.cpp、Ollama等工具里通常有简单开关,实测下来部分场景有20%到50%的收益,但也有场景因为草稿模型跑在CPU上而拖慢整体速度,建议真机压一下再决定。

中小团队服务的优化顺序,我个人的经验是:优先把量化落到位,然后把调度器的参数调对(比如vLLM的max_num_seqs、KV Cache池大小),最后再考虑投机采样。很多团队一上来就追投机采样,结果高并发batch下被草稿模型拖累,事与愿违。低并发、流式、交互感强的场景(比如AI陪聊),投机采样的体验提升是显著的。

上了几十张卡规模的集群,不做PD分离基本扛不住高并发的延迟抖动。这个时候,KV Cache量化、网络传输优化、prefill/decode节点比例这些系统级配置,都要纳入日常运维参数。

5.2 设计评估实验:别被"假加速"骗了

在一个新的硬件或模型组合上做加速优化,最忌讳直接拿单条Prompt的耗时下结论。我习惯用一组固定的评估维度来避免"假加速":

  • 单请求TTFT与TPOT:反映用户直接体验。
  • 多并发压测吞吐:比如32路并发下每秒完成的总token数,反映系统利用率。
  • 长上下文专项:8K、32K等不同长度下的显存占用与延迟,验证KV Cache优化是否生效。
  • 精度回退:困惑度或标准benchmark分数,量化后必须和FP16基线对比。

举一个常见的嘲讽场景:某个方案把单个请求的TPOT从40ms优化到15ms,看起来提速近3倍;但同时在32路并发压测下吞吐反而掉了一半。原因是所谓"优化"只是在小batch下获得了更高的GPU空闲利用率,一旦批变大,多余的计算还是得排队。投机采样就经常出现这种反向效果。所以优化的标准,永远是"目标负载下"的延迟/吞吐/成本综合结果,不是单点指标。

5.3 我的经验:先用profile定位瓶颈,再谈加速

最后分享一点方法论层面的体会。很多人拿到一个慢的推理服务,第一反应是"上量化""上投机采样",好像加速手段是越多越高级。我建议反过来,先定位瓶颈再动手:

第一步,开启推理引擎的profiler或简单的计时日志,看请求在prefill和decode分别花了多少时间;第二步,观察GPU利用率和显存占用,判断是算力瓶颈、带宽瓶颈还是显存不足;第三步,再决定用哪把钥匙。

如果GPU利用率已经很高但还是慢,说明是算法步数问题,优先想投机采样这类减少步数的方案;如果GPU利用率低且显存读取是瓶颈,量化是首选项;如果服务并发时延迟剧烈抖动,这个问题量化解决不了,得从调度和架构入手,也就是PD分离的范畴。这比无脑堆方案高效太多。

我踩过最深刻的一次坑,是把大量精力花在量化精度调优上,结果事后用profiler一看,decode阶段的GPU利用率只有5%,瓶颈完全在显存带宽。此时不管量化做得多精美,也只是小幅缓解搬运压力,真正的解法是减少解码步数或换高带宽硬件。这个认知转变,让后续所有优化工作都有了清晰的方向。

代码终归是干活用的,加速技术也终归要为具体业务服务。希望这篇把三套主流方案的原理、适用边界和组合逻辑讲清楚了,能让你在下次面对推理性能问题时,少走几步弯路。

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

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

立即咨询