大模型推理加速实战:量化、投机采样与PD分离的工程选型与调优

发布时间:2026/10/8 9:23:36
大模型推理加速实战:量化、投机采样与PD分离的工程选型与调优
1. 大模型推理加速的底层逻辑与方案选型大模型推理这件事真正落到生产环境里最核心的矛盾从来不是“模型能不能跑”而是“跑得够不够快、够不够便宜”。我接触过不少团队模型训练阶段砸了几百万上线之后发现单次推理延迟高得离谱并发一上来显存直接爆掉最后不得不砍功能或者加机器。推理加速技术要解决的就是这个落差——让一个几十亿甚至上百亿参数的模型在有限的硬件资源下用可接受的延迟和成本完成服务。目前业界主流的加速路径可以归为三大类量化、投机采样和PD分离。这三者不是互斥关系而是从不同维度切入的优化手段。量化解决的是“模型本身太重”的问题通过降低数值精度来压缩模型体积和计算量投机采样解决的是“逐token生成太慢”的问题用小模型快速草拟、大模型批量验证来提升吞吐PD分离解决的是“Prefill和Decode互相拖累”的问题把两个计算特征截然不同的阶段拆到不同硬件上执行。为什么是这三条路因为大模型推理的瓶颈本质上就三个显存带宽、计算吞吐、调度效率。量化直接砍显存占用和带宽压力投机采样提升单位时间内的有效计算量PD分离优化资源利用率。三者叠加使用往往能带来数倍的端到端加速。注意这三项技术各有适用边界不是所有场景都适合全部上。比如极低并发场景下PD分离的收益可能被通信开销吃掉量化到INT4以下时精度损失可能不可接受。选型之前一定要先做profiling搞清楚瓶颈在哪。1.1 量化技术的核心分类与选择依据量化说白了就是用更少的bit来表示原本的浮点参数。FP16是16位INT8是8位INT4是4位理论上INT4能把模型体积压到FP16的四分之一。但量化不是简单的类型转换它涉及到scale因子的选取、离群值的处理、激活值的动态范围估计等一系列问题。从实操角度量化分两大流派训练后量化PTQ和量化感知训练QAT。PTQ不需要重新训练拿训练好的模型直接做校准和转换成本低、上手快适合大多数推理场景。QAT则是在训练阶段就模拟量化误差让模型参数去适应低精度表示精度保持更好但需要额外的训练资源和数据。再往下细分PTQ又分权重量化和权重激活量化。权重量化只压模型参数激活值还是FP16实现简单对精度影响小适合对延迟不那么敏感的场景。权重激活量化把中间计算结果也压到低精度计算量和显存占用都能进一步降低但对校准数据的要求更高精度风险也更大。量化方案显存节省精度损失实现难度适用场景FP16基准无低精度敏感型任务INT8权重约50%极小低通用推理INT8权重激活约50%小中高吞吐服务INT4权重约75%中等中显存受限场景INT4权重激活约75%较大高极致压缩场景选择量化方案时我一般建议从INT8权重量化起步跑一轮评测看精度掉多少。如果精度可接受且显存还是不够再考虑INT4。INT4权重激活这种激进方案除非你确实被显存卡死了否则不建议轻易上。1.2 投机采样的工作原理与收益模型投机采样的核心思想可以用一句话概括用便宜的小模型去猜用昂贵的大模型去验。具体来说维护一个小的draft模型和一个大的target模型。draft模型自回归生成K个token然后target模型一次性对这K个token做并行验证。如果验证通过就接受这些token如果某个位置不匹配就从该位置重新采样。这个方法的收益取决于两个关键指标接受率和加速比。接受率越高说明draft模型和target模型的输出分布越接近浪费的计算越少。加速比则取决于draft模型比target模型快多少以及一次验证能接受多少个token。假设draft模型生成K个token的时间是T_dtarget模型验证K个token的时间是T_v那么一轮的总时间是T_d T_v。如果平均接受α个token那么每个token的平均时间是(T_d T_v) / α。相比target模型单独生成每个token的时间T_t加速比就是 T_t * α / (T_d T_v)。要让这个比值大于1需要满足几个条件draft模型足够快T_d远小于T_t接受率足够高α接近K验证开销可控T_v不要太大。实践中draft模型通常选target模型的1/10到1/5大小K取4到8比较合适。提示投机采样对draft模型的质量很敏感。如果draft模型太差接受率低反而会拖慢整体速度。建议先用小规模数据测一下接受率低于60%就要考虑换draft模型或者调整K值。1.3 PD分离的架构动机与部署考量PD分离是Prefill-Decode Disaggregation的缩写。要理解它为什么有用得先搞清楚Prefill和Decode这两个阶段的差异。Prefill阶段是处理用户输入的prompt把所有token一次性送进模型计算量大但并行度高属于计算密集型。Decode阶段是逐token生成输出每次只处理一个token计算量小但需要反复读取KV Cache属于显存带宽密集型。这两个阶段混在一起跑就会出现资源争抢Prefill占着计算单元不放Decode在旁边干等Decode频繁读显存Prefill的计算效率也被拉低。PD分离的思路很直接把Prefill和Decode拆到不同的实例甚至不同的机器上。Prefill实例专注做计算Decode实例专注做生成各自用最适合的硬件配置。中间通过KV Cache的传输来衔接。这样做的好处是资源利用率更高延迟更稳定尤其适合长prompt和长输出的场景。但PD分离也有代价。KV Cache在不同实例之间传输需要网络带宽如果传输时间超过节省的时间那就得不偿失。所以PD分离更适合高并发、长序列的场景低并发短序列下收益不明显。2. 量化实操从校准到部署的完整链路量化这件事理论看着简单实操坑不少。我见过太多人拿着开源工具跑一遍发现精度掉得没法用或者部署之后速度没提升多少。问题往往出在校准数据的选取、量化粒度的配置、以及推理引擎的适配这几个环节。2.1 校准数据集的构建与预处理校准数据集是PTQ量化的灵魂。它的作用是让量化算法观察到模型在实际输入下的激活值分布从而确定合适的scale和zero-point。校准数据选得不好量化后的模型在真实场景下就会崩。校准数据的基本原则是分布对齐校准集的输入分布要尽可能接近真实推理时的输入分布。如果你做的是客服对话场景校准集就应该用真实的客服对话数据而不是随便拿一堆新闻语料。数量上通常128到512条样本就够了太多没必要太少覆盖不全。预处理环节要注意几点首先校准数据要经过和推理时完全一致的tokenizer处理包括padding、truncation这些细节。其次如果模型有特殊的输入格式比如chat template校准数据也要按同样格式组织。最后校准过程中要关闭dropout、固定随机种子确保结果可复现。# 校准数据构建示例伪代码 from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(model_path) calib_samples [] for text in raw_calib_data: # 按推理时的格式处理 formatted apply_chat_template(text) encoded tokenizer( formatted, truncationTrue, max_length2048, paddingmax_length, return_tensorspt ) calib_samples.append(encoded) # 通常取128-512条 calib_dataset calib_samples[:256]注意校准数据不要用训练数据否则量化后的模型在训练集上表现好在真实场景下可能翻车。另外校准数据的长度分布也要和真实场景匹配如果真实场景prompt很长校准集里全是短文本长序列的激活值分布就没被覆盖到。2.2 量化粒度与离群值处理策略量化粒度决定了scale因子怎么共享。Per-tensor是整个张量共用一个scale实现最简单但精度最差。Per-channel是每个通道一个scale精度好一些但计算稍复杂。Per-group是把通道分成若干组每组一个scale在精度和效率之间取平衡。实践中权重常用per-channel或per-groupgroup size取128激活常用per-tensor。离群值是量化的大敌。大模型激活值里经常出现一些极端大的值如果直接量化这些值会把scale拉得很大导致其他正常值被压到很小的范围精度损失严重。处理离群值有几种常见手段Clipping设定一个阈值超过阈值的值直接截断。简单但可能丢失信息。SmoothQuant把激活的量化难度转移到权重上通过数学等价变换让激活分布更平滑。AWQ基于激活值分布识别重要通道对这些通道保留更高精度。GPTQ逐层做量化用Hessian矩阵指导权重的舍入方向最小化量化误差。这些方法各有优劣选择时主要看你的精度要求和工程成本。SmoothQuant和AWQ实现相对简单效果也不错是我比较常用的方案。2.3 量化模型的推理引擎适配量化模型训练出来只是第一步能不能在推理引擎里跑出加速效果还得看引擎的支持程度。不同推理引擎对量化的支持差异很大。TensorRT-LLM对INT8和INT4的支持比较成熟per-channel和per-group都支持但模型转换流程比较重需要先把权重转成特定的格式。vLLM对GPTQ和AWQ的支持不错加载量化模型比较方便适合快速验证。llama.cpp对GGUF格式的量化支持最全从Q2到Q8都有适合CPU和边缘设备部署。推理引擎支持量化类型转换难度适用硬件TensorRT-LLMINT8/INT4/FP8高NVIDIA GPUvLLMGPTQ/AWQ/INT8中NVIDIA GPUllama.cppGGUF全系列低CPU/GPU/边缘ONNX RuntimeINT8/INT4中多平台适配时最容易踩的坑是算子不支持。有些量化方案会引入自定义算子如果推理引擎没有实现对应的kernel就会回退到FP16甚至报错。部署前一定要确认引擎的算子覆盖情况必要时做算子替换或自定义实现。3. 投机采样的工程实现与调优投机采样听起来很美好但工程落地时有一堆细节要处理。draft模型怎么选、K值怎么定、验证逻辑怎么写、KV Cache怎么管理每个环节都影响最终效果。3.1 Draft模型的选择与训练Draft模型的选择有两个方向独立小模型和自蒸馏模型。独立小模型就是直接拿一个同系列的小模型来用比如target是70Bdraft就用7B。这种方案实现简单但draft和target的分布差异可能较大接受率不稳定。自蒸馏模型是用target模型的输出训练一个更小的模型让draft尽可能模仿target的行为接受率更高但需要额外的训练成本。我一般建议先用独立小模型快速验证如果接受率不理想再考虑自蒸馏。选draft模型时参数量不是唯一指标还要看它的推理速度。有些小模型虽然参数少但架构不适合快速推理实际延迟可能比预期高。提示draft模型和target模型的tokenizer必须一致否则验证逻辑没法对齐。如果找不到同tokenizer的小模型可以考虑用target模型的前几层作为draft这样tokenizer天然一致。3.2 验证逻辑与采样策略的配合投机采样的验证逻辑需要保证输出分布和target模型单独采样时一致。标准的做法是对draft生成的每个token计算target模型在该位置的输出分布然后用一个接受-拒绝采样来决定是否接受。如果拒绝就从target分布中重新采样一个token。这个过程中温度参数、top-p、top-k这些采样策略都要在验证时正确应用。如果target模型用了temperature0.7验证时也要用同样的temperature否则输出分布会偏。另外如果draft模型和target模型的采样策略不同接受率会受影响建议保持一致。# 投机采样验证逻辑简化版 def speculative_decode(draft_model, target_model, input_ids, K5): draft_tokens [] draft_probs [] # draft模型自回归生成K个token for _ in range(K): logits draft_model(input_ids draft_tokens) probs softmax(logits / temperature) token sample(probs, top_p, top_k) draft_tokens.append(token) draft_probs.append(probs[token]) # target模型并行验证 target_logits target_model(input_ids draft_tokens) accepted [] for i, token in enumerate(draft_tokens): target_probs softmax(target_logits[i] / temperature) accept_prob min(1, target_probs[token] / draft_probs[i]) if random() accept_prob: accepted.append(token) else: # 从修正后的分布重新采样 adjusted_probs max(0, target_probs - draft_probs[i]) adjusted_probs adjusted_probs / adjusted_probs.sum() accepted.append(sample(adjusted_probs)) break return accepted3.3 K值与接受率的动态平衡K值是投机采样最关键的调参。K太小验证次数多开销大K太大draft生成时间长而且后面的token接受率会下降。实践中K取4到8是比较常见的范围但最优值取决于具体模型和任务。一个实用的调优方法是先固定K5跑一轮统计平均接受长度。如果接受长度接近K说明K还可以加大如果接受长度远小于K说明draft质量不够或者K太大了。根据统计结果逐步调整找到加速比最大的K值。另外不同请求的接受率可能差异很大。有些简单请求draft几乎全对有些复杂请求draft错得离谱。可以考虑做动态K值根据历史接受率调整当前请求的K值接受率高就加大K接受率低就减小K。这个策略在高并发场景下效果比较明显。4. PD分离的部署架构与性能调优PD分离的落地比前两项技术更重涉及到多实例部署、KV Cache传输、请求调度等一系列工程问题。搞好了收益很大搞不好还不如不拆。4.1 Prefill与Decode实例的资源配置Prefill实例是计算密集型的应该配计算能力强的GPU比如A100、H100这类。Decode实例是显存带宽密集型的对计算能力要求没那么高但需要大显存来存KV Cache可以用显存大但计算一般的卡。资源配比方面Prefill和Decode的实例数量比取决于请求特征。如果prompt很长、输出很短Prefill压力大需要更多Prefill实例。如果prompt短、输出长Decode压力大需要更多Decode实例。实际配比要通过压测来确定一般从1:1开始调。注意Prefill和Decode实例之间的网络带宽很关键。KV Cache的传输量跟序列长度和模型层数成正比如果带宽不够传输时间会吃掉分离带来的收益。建议用高速互联比如NVLink或InfiniBand至少也要25Gbps以上的网络。4.2 KV Cache的传输与复用策略KV Cache传输是PD分离的核心环节。Prefill实例算完KV Cache后需要把它传给Decode实例。传输的内容包括每层的key和value张量大小取决于序列长度、层数、注意力头数和head dimension。传输策略有几种全量传输是把整个KV Cache一次性传过去简单但传输量大。分块传输是把KV Cache分成若干块Decode实例需要哪块就传哪块减少传输量但增加调度复杂度。压缩传输是对KV Cache做量化或稀疏化后再传进一步降低带宽需求。实际部署中我一般先用全量传输跑通流程再根据带宽瓶颈决定是否上分块或压缩。KV Cache的复用也值得考虑如果多个请求共享相同的prompt前缀可以复用这部分KV Cache避免重复计算和传输。4.3 请求调度与负载均衡PD分离架构下请求调度变得更复杂。一个请求要先送到Prefill实例做prefill再送到Decode实例做decode。调度器需要决定哪个Prefill实例处理这个请求哪个Decode实例接收KV Cache如何保证负载均衡常见的调度策略有轮询、最少连接、基于负载预测等。轮询简单但不够灵活最少连接好一些但可能忽略实例的实际负载差异。基于负载预测的策略会考虑每个实例的当前队列长度、计算利用率、显存占用等指标做更精细的调度。负载均衡还要考虑亲和性如果某个Decode实例已经缓存了某个会话的KV Cache后续请求最好还送到这个实例避免重复传输。这个策略对多轮对话场景特别有用。5. 三项技术的组合与场景化选型量化、投机采样、PD分离这三项技术单独用都有收益组合起来用收益更大但组合方式需要根据场景来定。5.1 不同业务场景下的技术组合方案高并发在线服务量化INT8 PD分离。高并发下显存和计算都是瓶颈量化压显存PD分离提利用率。投机采样在这个场景下可能不太合适因为draft模型也要占资源并发一高反而抢资源。低延迟交互场景量化INT8 投机采样。交互场景对首token延迟和每token延迟都敏感投机采样能显著降低生成延迟量化减少模型加载和计算时间。PD分离在这个场景下收益不大因为请求量不够大分离的开销收不回来。长文本生成场景量化INT4 PD分离 投机采样。长文本生成Decode阶段特别长PD分离让Decode实例专注生成投机采样加速逐token生成INT4量化压显存让更长的序列能塞进去。这个组合最复杂但收益也最大。边缘设备部署量化INT4/INT8。边缘设备资源有限量化是刚需。投机采样和PD分离在边缘场景下基本用不上因为模型本身就小没有拆分的必要。场景量化投机采样PD分离预期加速比高并发在线INT8可选推荐3-5x低延迟交互INT8推荐不推荐2-4x长文本生成INT4推荐推荐4-8x边缘部署INT4/INT8不推荐不推荐2-3x5.2 组合部署时的资源冲突与规避三项技术组合时资源冲突是常见问题。量化会改变模型的计算图可能影响投机采样的验证逻辑PD分离引入的网络传输可能和投机采样的draft模型抢带宽draft模型本身也要占显存和量化省下来的显存形成对冲。规避这些冲突的关键是分层优化先做量化把模型压到目标显存以内再上PD分离把Prefill和Decode的资源分开最后在Decode实例上开投机采样用省下来的显存放draft模型。这个顺序能最大化资源利用效率。另外监控很重要。组合部署后要密切监控每个环节的延迟、吞吐、显存占用、网络带宽。任何一个指标成为瓶颈整体加速比都会打折扣。我一般会搭一个简单的dashboard把关键指标可视化方便快速定位问题。6. 实操中的常见问题与排查技巧6.1 量化精度下降的排查路径量化后精度下降是最常见的问题。排查时按这个顺序走先看校准数据是否匹配真实分布再看量化粒度是否太粗然后看离群值处理是否到位最后看推理引擎的算子实现是否有问题。如果校准数据没问题可以试试换更细的量化粒度比如从per-tensor换成per-channel。如果还不行考虑上SmoothQuant或AWQ。如果这些都不行可能这个模型对量化就是敏感只能退到INT8或者混合精度。提示量化精度下降不一定是均匀的。有些任务掉点严重有些任务几乎没影响。评测时要分任务看不要只看平均分。6.2 投机采样加速比不达预期的原因加速比不达预期先看接受率。接受率低于60%基本可以判定draft模型不行换模型或者做自蒸馏。接受率没问题但加速比还是低看draft模型的推理速度如果draft本身就很慢那加速空间有限。还要看验证开销如果target模型验证K个token的时间和生成K个token差不多那投机采样就没意义了。另一个容易被忽略的点是batch size。投机采样在batch size1时效果最好batch大了之后target模型的验证计算量线性增长加速比会下降。高并发场景下要权衡。6.3 PD分离部署中的网络瓶颈定位PD分离后性能反而下降大概率是网络瓶颈。用iperf或者类似的工具测一下Prefill和Decode实例之间的实际带宽和KV Cache的传输量对比一下。如果传输时间占比超过20%就要考虑优化网络或者上KV Cache压缩。还有一个隐蔽的问题是KV Cache格式不匹配。Prefill实例和Decode实例如果用了不同的模型版本或者不同的量化方案KV Cache的格式可能对不上导致传输后无法使用。部署前一定要确认两边的模型配置完全一致。问题现象可能原因排查方法解决方向量化后精度暴跌校准数据不匹配对比校准集和真实输入分布重新构建校准集投机采样无加速接受率低统计平均接受长度换draft模型或调K值PD分离后延迟升高网络带宽不足测实际带宽和传输量上高速网络或压缩KV组合部署OOM资源冲突监控各环节显存占用调整部署顺序和配比7. 个人实操体会与后续扩展方向这三项技术我都在生产环境里跑过踩过的坑不少。量化最深的体会是校准数据决定上限量化算法决定下限。校准数据选对了简单算法也能有好效果校准数据选错了再复杂的算法也救不回来。投机采样最深的体会是draft模型不是越小越好而是越像越好。一个7B的draft如果接受率只有50%还不如一个3B但接受率80%的draft。PD分离最深的体会是网络是隐形杀手。算力再强网络跟不上分离就是白拆。后续如果要继续深挖有几个方向值得关注。一是FP8量化新一代GPU对FP8的支持越来越好精度和速度的平衡比INT8更优。二是多draft投机采样用多个draft模型并行草拟进一步提升接受率。三是PD分离的自动化调度根据实时负载动态调整Prefill和Decode的实例配比这个在云原生环境下特别有价值。最后分享一个小技巧做推理加速时先profile再优化。不要凭感觉猜瓶颈在哪用nsight或者perf跑一遍看清楚时间花在计算上还是显存上还是通信上。方向对了优化才有意义。