大模型推理加速实战:量化、投机采样与PD分离的组合优化

发布时间:2026/10/5 12:23:42
大模型推理加速实战:量化、投机采样与PD分离的组合优化
最近这半年我一直在折腾大模型推理服务的性能优化从最初单纯把模型跑起来到后来一门心思压首字延迟和吞吐量。走了不少弯路也把量化、投机采样、PD分离这几条主流加速路径从理论到落地完整过了一遍。这篇文章就是把我的实操记录、踩坑经历和一些测试数据整理出来给同样在搞推理加速的朋友一个参考。无论你是刚接触推理优化还是已经部署过服务想进一步压榨性能这篇文章应该都能提供一些有价值的东西。先说结论量化省显存也提吞吐但如果精度敏感场景不做校准模型可能“变笨”投机采样能显著降低延迟但效果高度依赖草稿模型和业务场景PD分离则从架构层面解决长上下文场景下预填充与解码的资源冲突是服务化部署走向规模化的关键一步。三者侧重点不同组合使用效果最佳。1. 量化把FP16的“大胖子”压缩成INT8/INT4的“精瘦子”量化是这几项技术里最“亲民”的因为它带来的收益最直观模型文件变小了显存占用降了推理速度也快了。核心思想用一句话概括就是用更少的比特数去近似表示神经网络的权重和激活值。1.1 量化为什么能加速计算量和显存带宽的双重降负大模型推理是个极度吃显存带宽的活儿。自回归生成的时候每一步都要把权重从显存里搬到计算单元FP16就是每个数占2字节假设你的算子访存和计算比是10:1那瓶颈几乎全在搬数据上。换成INT8每个数只占1字节搬运量直接减半换INT4再减一半。数据搬得快了GPU计算单元就不会因为等数据而空转端到端速度自然就上去了。显存这边更好理解。比如一个70B模型FP16权重就要140GB你至少得两张80GB的卡才能塞下用INT4量化后权重只剩35GB左右一张卡就搞得定。省下来的显存还能加大并发请求数吞吐量跟着蹭蹭涨。这也是为什么我常跟人讲量化不是“能不能用”的问题是“精度损失你能不能接受”的问题。1.2 两种主流量化方式PTQ与QAT训练后量化是主流因为不用重新训练模型。做法是拿一批校准数据calibration dataset喂给模型统计每一层激活值的分布范围然后算出缩放因子和零点把FP16的权重映射到INT8/INT4能表示的整数区间。业界用得多的工具是GPTQ、AWQ前者基于二阶近似做权重重建后者根据激活值分布来保护重要权重通道各有千秋。量化感知训练则把假量化操作嵌入训练过程让网络在训练时就适应低比特带来的扰动精度通常比PTQ好但成本极高要重新训练模型一般只有把模型做到万卡训练规模的厂商才会考虑。对大模型推理场景我的建议很简单先用GPTQ或AWQ做PTQ试试效果不行再上QAT。大多数情况PTQ配合校准集已经能压住精度损失了。1.3 实操记录vLLM本地部署量化模型的完整配置我最近的验证环境是4卡A800。部署工具选的是vLLM现在它对量化模型的支持已经非常成熟。我把部署步骤和关键参数记录一下。# 环境基础 conda create -n infer python3.11 -y conda activate infer pip install vllm flash-attn # 启动量化模型的推理服务 python -m vllm.entrypoints.openai.api_server \ --model /models/Qwen2.5-72B-GPTQ-Int4 \ --quantization gptq \ --max-model-len 32768 \ --gpu-memory-utilization 0.92 \ --tensor-parallel-size 2 \ --port 8000关键参数解释--quantization gptq告诉vLLM这个模型是GPTQ量化格式它会走专门的量化kernel而不是反量化回FP16再算否则加速效果大打折扣。--tensor-parallel-size 2因为INT4的72B模型权重只有36GB左右两张40GB的卡就能装下所以TP2足够。--gpu-memory-utilization 0.92给KV Cache预留更多空间提高并发能力。启动后我用OpenAI兼容接口发请求做验证一个简单测试示例curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: /models/Qwen2.5-72B-GPTQ-Int4, messages: [{role: user, content: 用一句话解释什么是量化}], max_tokens: 128, temperature: 0.7 }用python -m vllm.entrypoints.openai.api_server起来后--max-model-len要注意INT4量化后显存余量变大你有更多空间把上下文窗口开大但如果同时开很大并发KV Cache还是会爆建议先小并发跑压测观察nvidia-smi里的显存占用再逐步上调。1.4 量化精度对比不同任务对低比特的容忍度差异我测试过同一个72B模型在FP16、INT8、INT4三种精度下的表现结论是分任务而定的。代码任务、数学推理对量化非常敏感INT4下代码补全的准确率能掉5个百分点以上通用问答、摘要这类相对鲁棒INT4下有时候损失都感知不到。你如果要做量化选型把这个矩阵存下来参考场景FP16基准INT8INT4通用对话100%99.5%97.2%代码生成100%99.1%94.3%数学推理100%98.7%93.6%长文本摘要100%99.3%96.8%INT8对绝大多数任务来说损失都划得来INT4就要掂量一下了。如果你业务里代码和数学任务占比大或者干脆做的是Agent这种要走多步推理的场景建议INT8打底INT4谨慎使用并且一定要用业务数据做校准集。2. 投机采样小模型带头探路大模型只做裁判投机采样的思路非常聪明。大模型一步步生成token太慢了每一步都要等前一步算完而每一步的开销又完全一样不管下一个token多简单。投机采样就让一个又快又笨的小模型先“猜”出后面几个token再让大模型一次性校验这些猜测如果都对那这一步就同时生成了好几个token速度快了好几倍。2.1 从一步一token到一次多token投机采样原理拆解具体流程是小模型也叫草稿模型先按自回归方式从当前上下文猜出接下来K个token。大模型拿到这K个token一次前向计算并行算出这K个位置的概率分布。逐一比对如果第i个位置大模型概率最高的token和小模型猜测的一致则接受不一致就拒绝并在这个位置重新采样作为最终输出。最多接受K个token然后重新开始下一轮。这里有个关键点拒绝之后大模型在该位置生成的token可以用于更新KV Cache不是白白浪费了。整体效果取决于接受长度和草稿模型的命中率。2.2 草稿模型怎么选尺寸、能力和场景匹配草稿模型并不是越强越好。它和大模型同构但是小一号比如用1.5B的模型给72B的模型当草稿接受率高用7B模型当草稿猜测质量高但在显存和延迟上是额外负担性价比反而不一定好。我踩过的坑是一开始给Qwen2.5-72B配了同系列7B的草稿模型想着猜得准结果发现7B模型的前向计算时间和72B模型校验K个token的时间加在一起已经接近甚至超过直接用大模型生成K个token的时间了加速等于零。后来换成1.5B草稿模型接受率虽然低了点但整体速度反而提升了1.8倍。选草稿模型的核心指标是两个一个是接受率也就是草稿token被大模型认可的比例另一个是草稿模型的解码速度。两个指标要与草稿模型本身的延迟放到一起做权衡。2.3 vLLM里跑投机采样的配置与参数调优vLLM从某个版本开始支持投机解码的完整参数配置代码如下# 启动参数摘录 --speculative-config {model: /models/Qwen2.5-1.5B, num_speculative_tokens: 5} --max-model-len 32768 --gpu-memory-utilization 0.92实测我调过不同num_speculative_tokens也就是草稿token数K效果差异非常大草稿token数 K平均接受长度端到端加速比32.11.4x52.81.8x73.01.7xK不是越大越好。K太大草稿模型要花大力气猜更多token而后面那些token被拒绝的概率更高白算。K在5左右是我的经验甜点区。另外有个细节如果业务场景是风格高度固定的文本比如客服模板回复、评论文档生成投机采样的接受率会高得离谱加速比能到2.5倍如果场景是开放域创作、代码生成接受率会明显下降。这个特性在业务逻辑层面就要有预判。2.4 投机采样的实现成本显存占用与调度复杂度投机采样不是零成本的。多部署一个草稿模型就得额外占显存哪怕是1.5B的模型也要占3GB左右。KV Cache的空间要被分走一部分PagedAttention的调度逻辑也要兼容两套模型。在显存已经捉襟见肘的旧机器上投机采样可能带来的提升会被显存压力抵消。还有一个工程层面的点草稿模型和大模型是串行还是并行推理。真正高性能的实现会做流水线并行草稿模型猜测下一批token的同时大模型校验上一批token。vLLM内部对投机采样的调度做了专门优化但如果你是自己从零搭服务务必考虑并发调度否则收益会缩水。3. PD分离把预填充和解码拆成两条生产线PD分离就是Prefill-Decode Disaggregation中文一般叫预填充与解码分离。之前我们习惯在一个GPU上同时处理用户的输入阶段和生成阶段但这两者资源需求完全不同放在一起相互拖累PD分离把它们拆到不同的机器上各干各的互不干扰。3.1 为什么P和D必须拆开资源需求的本质冲突预填充阶段处理的是一次性把用户输入的整个prompt算完计算量大时间长GPU利用率高解码阶段则是每次为一个token做前向计算虽然计算量小但延迟敏感而且每一步都要反复读取KV Cache非常吃显存带宽。把这两件事放在同一批GPU上会出现什么情况预填充请求占用了计算单元正在执行的解码请求就被排队输出速度变得闪烁不定。解码请求占着显存和带宽预填充的大块头请求又拿不到足够的计算资源。最典型的一个现象就是你post一个长prompt的请求同时又一个用户在持续对话结果两边都变慢。不是因为机器不行而是因为两类负载在打架。从另一个角度看如果不拆GPU利用率很难做满。预填充的请求是阵发性的解码请求倒是稳定但两者计算特征不同混在一起调度GPU要么算到冒烟要么闲着等待显存搬运。拆开后Prefill节点可以专门应对高峰计算的请求Decode节点做流式token生成两者都能稳定达到各自的资源跑满状态。3.2 PD分离部署拓扑多节点分工的详细方案一个最基础的PD分离部署至少需要两类节点Prefill节点负责处理用户prompt做一次完整的前向计算把生成的KV Cache存下来再传给Decode节点。Decode节点从Prefill节点接收KV Cache和上下文状态逐token生成回复。它们之间通过高性能网络传输KV Cache。传输的东西看着大但比重新计算便宜得多长prompt的KV Cache一次性传过去换来的是Decode节点不用重新计算那部分网络输出。这里要压题的是为什么不直接重新计算如果Decode节点也从头算一遍prompt它就要把用户输入的一次性计算压力再吃一遍第一个token延迟翻倍这完全背离了分离的初衷。所以KV Cache的传输是PD分离架构里最核心的“血脉”。在拓扑设计上我的建议是Prefill节点数量少但单节点计算力强Decode节点数量多且吃得起显存带宽。硬件配置按流量配比调整比如线上峰值并发小时段Prefill节点的GPU利用率会冲到95%以上平时可能只有40%多。这时候靠调度系统的弹性伸缩来补。3.3 调度与KV Cache传输PD分离里最难啃的两块硬骨头PD分离拆开容易真正开始实施才发现难的是两层问题。第一层是调度层。请求怎么路由一个请求先落在哪台Prefill节点、再迁移到哪台Decode节点同一轮生成的多次迭代之间要不要绑定在同一台Decode节点上不同业务之间怎么隔离目前业界主流的做法是在框架层引入“全局调度器”的概念调度器统一维护所有节点的状态包括每台机器显存余量、当前负载、KV Cache占用情况。Prefill节点做完一轮后调度器根据Decode节点的空闲情况实时决策把KV Cache迁移到哪去。这个链路一旦延迟高整体服务表现立刻恶化调度本身的耗时必须控制到毫秒级。第二层是KV Cache的传输。KV Cache可不是一个小文件几万token的上下文显存占用按GB算。PV和PD之间如果只是简单的HTTP搬运速度根本跟不上。业界做法是上RDMA也就是远程直接内存访问绕过CPU和操作系统直接从一台机器的显存搬到另一台机器的显存中延迟从几十毫秒压到几毫秒。如果基础设施不支持RDMA至少也要用NVMe Over TCP这类高性能网络方案千兆内网跑PD分离会非常吃力。我的建议是PD分离在上线前先做网络基线验证。在两台机器之间跑一个简单的KV Cache传输压测脚本确认单次传输耗时在你的首字延迟预算之内。否则架构搭好了性能全卡在网络上白忙活。3.4 什么规模的场景需要上PD分离成本与收益的临界点PD分离不是银弹它带来的额外成本是明显的要维护两套节点、KV Cache传输带宽开销、调度系统复杂度。小规模部署直接上PD分离大概率得不偿失。我的经验是当出现下面情况时开始考虑PD分离首token延迟不稳定长prompt请求一多整个服务的延迟抖动明显。并发用户量上来后解码吞吐掉得厉害。单机已经撑不住服务的并发要求本来就要上多机分布式推理。换句话说单机部署且并发量不高的情况先别急着PD分离。先优化调度、开量化、上投机采样这些手段落地快、改造成本低。等到QPS上了三位数再上PD分离收益立刻显现。4. 三管齐下一套完整的推理加速配置示例讲完三项技术单独怎么用再说说怎么把它们组合起来达到最优效果。注意这三位不是简单的叠加配置顺序和资源分配是有讲究的。4.1 组合逻辑谁先谁后资源怎么切我的组合顺序是先量化保住显存预算再上投机采样进一步降低延迟和计算量最后考虑PD分离解决多并发时的调度瓶颈。量化是基础它让模型体积降下来了给后面两项留出显存和算力空间。投机采样的草稿模型需要额外显存如果模型是全精度塞下草稿模型就得牺牲KV Cache容量反而拖垮并发。PD分离需要至少两批机器如果模型没量化每批机器都堆满权重硬件成本直接翻倍。资源分配上有个建议量化后的模型权重如果装在Prefill节点和Decode节点上是同一份可以共用存储Decode节点的显存更多偏向KV CachePrefill节点的算力尽量跑满。4.2 联合部署的完整配置与实测数据我自己搭过一套Qwen2.5-72B的服务配置如下Prefill节点2卡A800模型INT4量化TP2。Decode节点4卡A800模型INT4量化TP4开启投机采样草稿模型1.5BK5。网络RDMAKV Cache传输延迟约2ms。压测工具用的是vllm-bench和llmperf数据集模拟了真实业务平均输入450 tokens输出180 tokens。结果如下指标普通部署INT4量化量化投机采样量化投机PD分离首token延迟p50780ms620ms610ms540ms单token延迟p9545ms32ms18ms17ms吞吐量tokens/s3105206801150显存占用GB141384248能明显看到量化对吞吐量的提升最大投机采样把p95的单token延迟压缩了一倍多PD分离对吞吐量帮助很大。三项叠起来吞吐量从310干到1150 tokens/s首token延迟也砍掉三成。值得注意的一点是PD分离对首token延迟的优化部分来自Prefill节点的计算能力集中化长prompt排队的时间减少了投机采样主要在解码阶段起作用对首token的直接影响很小但它能降低每个请求的整体时延。4.3 联合配置时的坑我基本都踩了一遍联合配置比单独跑每项技术难得多主要是配置参数互相制约。第一个坑量化后精度下降导致投机采样的接受率降低。我一开始没有对量化模型和草稿模型的联合效果做评估结果部署后加速比远低于预期。后来发现INT4量化让大模型对某些token的概率分布变躁了草稿模型猜中的比例降了。解决办法是给草稿模型同步做量化校准让两头的行为更“同步”。第二个坑PD分离后Prefill节点产生的KV Cache格式和Decode节点预期的不一致。这主要发生在跨版本升级上某个版本的KV Cache布局变了导致迁移后解码报错。任何升级操作都要先跑一遍两端节点的兼容性验证。第三个坑动态批处理和投机采样的batch冲突。当多个请求同时在投机采样流程里时vLLM的调度要保证草稿模型的batch形状和大模型校验的batch形状一致。有段时间我改了max_num_batched_tokens结果投机采样的batch被截断接受长度直接崩到1加速效果完全消失。这类参数动完必须重新压测。5. 加速效果的验证方法别拍脑袋用数据说话很多朋友优化了一通最后就甩一句“感觉快了”这不行。推理优化必须建立可量化的评测体系否则你没法判断改动是正向还是负向也没法说服团队跟上你的方案。5.1 关键指标首token延迟、单token延迟与吞吐量评估推理加速最核心的三个指标建议盯住首token延迟TTFT意思是用户发起请求到收到第一个token的时间。体现的是预填充和调度效率。单token延迟TPOT是生成阶段每个token的平均耗时。体现的是解码效率和带宽利用情况。吞吐量通常是每秒生成的token数。体现的是系统整体的并发处理能力。这三个指标之间存在相互制约的关系吞吐量高单token延迟也可能高因为排队了首token延迟低可能牺牲了后面的调度效率。评测时不能只看一个要给出p50、p90、p99多个分位数。压测工具的选择首推vllm-bench是和vLLM配套的官方工具支持并发模拟、输入输出长度自定义。其次是llmperf支持更细粒度的指标统计。这类工具的使用注意点是压测要模拟真实场景别用固定长度文本跑。我建议用真实业务的请求日志来构造压测集统计长度分布这样测出来的指标才有落地参考价值。5.2 一个科学评测的完整流程我的评测流程是这样的固定硬件环境和模型版本跑一轮基线压测。分别开启量化、投机采样、PD分离每开一项就压测一轮记录三个指标的分位数。全部开启后再跑一轮测联合效果。用业务真实prompt做精度回测确保加速手段没有明显损伤模型质量。这个流程看着简单但容易忽略的地方在于每一步都要保持并发数和请求长度分布一致否则数据没有可比性。并发数建议从1、4、16、32逐步加记录每个并发下的指标曲线而不是只测一个并发点。精度回测也要有统一口径拿同一批测试题目对比加速前后模型输出与标准答案的匹配率或人工评分。量化投机PD分离这种叠加优化最终损失了多少精度心里要有数。6. 几个容易被忽视的系统级要点技术方案聊完了最后谈谈系统层面容易被忽略的点。推理加速不只是改模型和架构参数底层依赖和运行环境同样重要。6.1 算子库版本与CUDA环境的隐形影响量化kernel、投机采样、KV Cache传输这些环节的算子实现在底层的效果直接受cuBLAS、cuDNN、FlashAttention这些算子库的版本影响。我同样一段代码在CUDA 11.8和CUDA 12.1下跑量化解码吞吐量的差异可以到15%以上。这不是玄学是新算子库对低比特矩阵乘法的优化更到位。所以部署的时候务必按vLLM官方推荐的版本组合锁定环境。我用的是CUDA 12.1搭配PyTorch 2.1开了FlashAttention 2整体效果比默认配置好不少。另外说一句FlashAttention的版本会影响KV Cache的内存布局直接影响PD分离迁移时的兼容性。版本要统一否则Prefill节点和Decode节点之间传KV Cache时还得做格式转换白白消耗时间。6.2 显存不足时的降级策略没有银弹假设一切配置都到位了机器还是不够怎么办我遇到过很多团队项目迭代快到发布节点发现显存顶不住的情况。此时我的经验是按照影响面从小到大逐步降级先降低gpu-memory-utilization给KV Cache腾空间但会牺牲并发。再关掉投机采样草稿模型的显存释放出来。还不行就降低并发上限或者缩短max-model-len限制上下文长度。最不济才是退回更高比特的量化比如INT4退回INT8精度保住了但速度变慢。这个降级顺序的逻辑是速度可以牺牲但服务稳定性和模型精度不能崩。宁可慢一点也不能因为显存溢出导致服务全挂。我自己经历过一次线上事故为了追求极致性能把所有能开的优化全开了结果某个大prompt请求一到KV Cache直接溢出OOM所有在途请求全断了。后来我加了显存监控和请求级保护机制当显存使用超过阈值时自动拒绝部分请求保服务整体稳定。这块方案分别是做压测和运维策略的人一定要评估的。6.3 推理加速的未来方向组合拳继续打目前这几个方向还在持续演进。量化侧FP8推理逐步成熟INT2这种极端比特也在探索投机采样侧多草稿模型的并行猜测和更聪明的接受策略开始出现PD分离侧集群级调度与异构计算结合是把服务做大的必经之路。我的判断是推理加速早已不是单一技术的比拼而是工程系统级的能力。量化、投机采样、PD分离只是当前阶段的主菜未来还会有更多主菜上桌。抓住基础原理掌握验证科学的方法才是真正能持续受益的能力。最后再分享一个我个人的实操心得不要等所有优化方案都在文档里写完美了再动手先跑通一条链路、量化出一个能用的模型、搭起一套压测脚本比你脑子里想象一个“完美系统”有用得多。正是在一次次跑数、调参、看NVIDIA-SMI的循环里你对这些加速技术从纸面上的概念变成掌心上的手感。希望这篇文章能让你少走几个坑尽早跑出自己的加速效果。