ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

大模型推理加速实战:量化、投机采样与PD分离的落地指南

大模型推理加速实战:量化、投机采样与PD分离的落地指南 大模型推理这件事真正落到生产环境里最扎心的往往不是模型效果而是延迟和成本。一个 70B 级别的模型如果老老实实用 FP16 跑单张 80G 显存卡连权重都放不下更别提 KV Cache 和并发请求了。我最早接触这块的时候天真地以为推理加速就是换个更快的 GPU后来才发现真正的加速发生在算法和系统层面——量化把权重压小投机采样把串行解码变成并行验证PD 分离把预填充和解码这两件性质完全不同的事拆到不同硬件上跑。这三样东西基本构成了当前大模型推理加速的三根支柱。这篇内容我想把这三项技术从是什么讲到怎么落地重点不是复述论文而是把我在实际部署中踩过的坑、算过的账、调过的参数摊开来讲。适合已经跑通过基础推理服务、想进一步压延迟降成本的工程师也适合刚接触推理优化、想建立整体认知的同学。读完之后你应该能判断自己的场景该先上哪一项、每项技术的收益边界在哪、以及哪些参数是真正影响性能的关键。1. 为什么推理加速绕不开这三条路1.1 推理的两个阶段决定了优化的两个方向要理解加速技术得先搞清楚大模型推理到底在干什么。一次完整的生成请求其实分成两个性质截然不同的阶段Prefill预填充和Decode解码。Prefill 阶段处理的是你输入的整段 prompt所有 token 一次性送进模型做的是大规模的矩阵乘法。这个阶段的特点是计算密集GPU 的算力能被吃得很满属于算力瓶颈。而 Decode 阶段是逐 token 生成的每生成一个 token 都要把整个模型权重读一遍但实际参与计算的数据量很小属于访存密集GPU 的算力利用率往往只有个位数百分比瓶颈在显存带宽。这个区别极其关键。因为量化主要优化的是权重占多大、读多快直接打在 Decode 的访存瓶颈上投机采样优化的是一次前向能出几个 token减少 Decode 的循环次数PD 分离则是承认这两个阶段硬件需求不同干脆拆开部署。三条路对应三个不同的瓶颈点这也是为什么它们能叠加使用而不是互相替代。1.2 一个反直觉的账为什么 Decode 阶段 GPU 在摸鱼我拿一个具体的例子算给你看。假设跑一个 13B 模型FP16 权重约 26GB。Decode 阶段生成一个 token需要把 26GB 权重从显存完整读一遍。一张 A100 的显存带宽大约是 2TB/s那么读一遍权重的时间是 26GB / 2000GB/s ≈ 13ms。而这张卡的 FP16 算力是 312 TFLOPS生成一个 token 的计算量大约是 2 × 13B 26 GFLOP算下来计算时间只有 26e9 / 312e12 ≈ 0.08ms。也就是说访存时间是计算时间的 160 多倍。GPU 的算力单元绝大部分时间在等数据从显存搬过来。这就是 Decode 阶段的真相——不是算不动是喂不饱。理解了这一点你就明白为什么量化减少要读的数据量和投机采样一次多出几个 token摊薄权重读取成本能带来那么大的收益了。1.3 三项技术的收益量级与适用边界在动手之前先建立一个收益预期免得期望落空。根据我的实测经验这三项技术的典型收益大致如下技术主要优化目标典型收益主要代价量化INT8/INT4显存占用、访存带宽显存降 50%-75%吞吐提升 1.5-3x精度损失、部分算子需适配投机采样Decode 循环次数延迟降 1.5-3x取决于接受率额外草稿模型开销、实现复杂PD 分离资源利用率、TTFTTTFT 降 30%-60%吞吐提升明显部署复杂度、KV 传输开销需要强调的是这些收益不是简单相乘的。量化和投机采样叠加时草稿模型的接受率可能因为量化而下降PD 分离的收益高度依赖你的请求特征prompt 长度、并发量。所以别指望三个都上就快 10 倍实际落地要一项一项测。2. 量化把权重压小让访存不再拖后腿2.1 量化的本质是一次精度换带宽的交易量化的核心思想很朴素神经网络权重里那些 FP16 的数字其实不需要那么高的精度。一个 FP16 数占 2 字节如果我用 INT8 表示就只占 1 字节显存直接减半访存带宽需求也减半。极端一点用 INT4只占 0.5 字节理论上能压到原来的四分之一。但这里有个关键问题权重的数值范围差异很大有的层数值集中在 [-0.1, 0.1]有的层能到 [-5, 5]。如果统一用一个缩放因子把 FP16 映射到 INT8 的 [-127, 127]那些数值范围小的层就会被压扁精度损失严重。所以量化的核心难点从来不是怎么压而是怎么压得准。2.2 从 PTQ 到 QAT两条技术路线的取舍按量化发生的时机主流方案分两类PTQ训练后量化是拿一个训练好的模型用一批校准数据跑一遍统计各层的数值分布然后确定缩放因子。优点是快几十分钟就能搞定不需要重新训练。缺点是精度损失相对大尤其是低比特INT4时。GPTQ、AWQ 都属于这一类。QAT量化感知训练是在训练过程中就模拟量化的舍入误差让模型提前适应低精度。精度保持得更好但需要完整的训练流程和算力成本高得多。一般只有在对精度极其敏感、且 PTQ 实在救不回来的场景才用。对绝大多数推理部署场景我的建议是先上 PTQ。GPTQ 和 AWQ 在 4bit 下的精度损失通常可以控制在 1% 以内用困惑度衡量对实际业务几乎无感。除非你的任务对数值极其敏感比如某些科学计算否则没必要碰 QAT。2.3 权重量化、激活量化与 KV Cache 量化很多人一说量化就只想到权重其实量化有三个可以下手的地方收益和难度各不相同权重量化最成熟收益最直接。权重是静态的可以离线量化好推理时直接加载。INT8/INT4 权重是标配。激活量化激活值是动态的每次输入不同范围会变。要做在线量化需要动态统计实现复杂精度也更难保证。W8A8权重 8bit、激活 8bit是常见组合。KV Cache 量化这个容易被忽略但在长上下文场景下收益巨大。KV Cache 会随着序列长度线性增长一个 32K 上下文的请求KV Cache 可能比权重还占显存。把 KV Cache 量化到 INT8显存能省一半而且对精度影响通常很小。我的经验是权重先量化到 INT4KV Cache 量化到 INT8激活量化看情况。这个组合在显存和精度之间平衡得最好。2.4 实操用 GPTQ 量化一个模型并验证精度下面给一个可复现的流程。假设你有一个 FP16 的模型想量化成 4bit。# 依赖auto-gptq, transformers, datasets from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig from transformers import AutoTokenizer from datasets import load_dataset model_id your-model-path tokenizer AutoTokenizer.from_pretrained(model_id) # 量化配置4bitgroup_size128 是精度和压缩率的平衡点 quantize_config BaseQuantizeConfig( bits4, group_size128, desc_actFalse, # 关闭激活重排序速度更快精度略降 ) # 准备校准数据128-256 条即可覆盖你的业务分布 calib_dataset load_dataset(your-calib-data, splittrain[:256]) calib_texts [tokenizer(t) for t in calib_dataset[text]] model AutoGPTQForCausalLM.from_pretrained(model_id, quantize_config) model.quantize(calib_texts) model.save_quantized(your-model-4bit)量化完之后一定要做精度验证别直接上线。验证方法是用同一批测试数据分别跑 FP16 和量化模型对比困惑度PPL和实际任务指标。# 简单的 PPL 对比 import torch from transformers import AutoModelForCausalLM def compute_ppl(model, tokenizer, texts): model.eval() total_loss, total_tokens 0, 0 with torch.no_grad(): for text in texts: inputs tokenizer(text, return_tensorspt).to(model.device) outputs model(**inputs, labelsinputs[input_ids]) total_loss outputs.loss.item() * inputs[input_ids].size(1) total_tokens inputs[input_ids].size(1) return torch.exp(torch.tensor(total_loss / total_tokens))注意group_size 是个关键参数。设成 128 时每 128 个权重共享一个缩放因子精度和压缩率平衡较好设成 -1 表示整层共享一个缩放因子压缩率最高但精度损失大。我实测下来128 是大多数场景的甜点。2.5 量化踩坑实录那些文档不会告诉你的问题坑一不是所有算子都支持量化。有些模型用了特殊的算子比如某些自定义的 LayerNorm 变体量化工具链可能不支持会直接报错或者静默回退到 FP16导致你以为量化了其实没有。部署前一定要检查实际加载后的显存占用。坑二量化后的模型在长文本上精度衰减更明显。短文本测试 PPL 只涨了 0.1看着很美但一到长上下文误差会累积放大。我的做法是专门用长文本测试集验证别只测短句。坑三不同推理框架对量化格式的支持不一样。GPTQ 格式在 vLLM 里支持很好但换成别的框架可能就要转格式。选量化方案前先确认你的推理框架支持哪种格式别量化完了发现跑不起来。3. 投机采样用草稿验证打破串行魔咒3.1 自回归解码的串行困境Decode 阶段最要命的地方在于它是严格串行的生成第 N 个 token 必须等第 N-1 个 token 算完。这意味着你没法通过并行来加速只能一个接一个地出。前面算过每出一个 token 要读一遍全部权重13ms 就为了出一个字这效率实在感人。投机采样的思路很巧妙既然大模型一次前向只能出一个 token 太浪费那我能不能一次前向验证多个 token具体做法是先用一个又小又快的草稿模型一口气生成 K 个候选 token然后把这 K 个 token 一起送给大模型让大模型一次性验证这 K 个 token 哪些是对的。因为大模型的一次前向本来就要读一遍权重验证 1 个 token 和验证 K 个 token 的访存成本几乎一样所以如果 K 个里有多个被接受就相当于白赚了。3.2 接受率才是决定收益的唯一指标投机采样的收益公式其实很简单加速比 ≈ 平均接受 token 数 / (1 草稿模型开销占比)假设草稿模型的开销是大模型的 1/5平均每次接受 3 个 token那么加速比大约是 3 / 1.2 ≈ 2.5x。但如果接受率很低平均只接受 1 个 token那加速比就接近 1甚至因为草稿模型的开销而变慢。所以接受率是投机采样的生命线。而接受率取决于草稿模型和大模型的相似度。草稿模型和大模型的分布越接近草稿猜的 token 越容易被接受。这就引出了几种不同的实现路线。3.3 三种主流实现路线对比路线草稿来源接受率额外显存适用场景独立小模型单独训练的小模型中需加载草稿模型有同系列小模型可用Medusa大模型加多个预测头中高少量预测头可微调模型EAGLE特征层复用轻量头高少量追求极致加速独立小模型最简单比如用 1B 模型给 70B 模型做草稿。但问题是小模型和大模型的分布差异大接受率往往一般。Medusa在大模型最后一层加几个并行的预测头每个头预测未来第 2、3、4 个 token。因为共享了大模型的特征接受率比独立小模型高。但需要微调预测头。EAGLE是目前公认效果最好的它不重新训练一个模型而是在大模型的特征层上接一个轻量头复用大模型已经算出来的特征来预测下一个 token 的特征。接受率通常能到 0.7 以上加速比能到 3x 左右。3.4 实操在推理框架里开启投机采样以 vLLM 为例开启投机采样非常简单但参数调优有讲究# 用独立小模型做草稿 python -m vllm.entrypoints.openai.api_server \ --model your-large-model \ --speculative-model your-draft-model \ --num-speculative-tokens 5 \ --tensor-parallel-size 2num-speculative-tokens是每次草稿生成的候选数这个参数很关键。设太小收益不够设太大草稿模型的开销和验证失败的概率都会上升。我的经验是从 5 开始试然后根据实测的接受率调整。如果接受率能稳定在 0.6 以上可以往上加到 7-8如果接受率低于 0.4说明草稿模型和大模型差异太大加多少都没用得换草稿方案。3.5 投机采样的隐藏成本与调优心得成本一草稿模型的显存占用。草稿模型虽然小但也要占显存。如果你的显存本来就紧张加载草稿模型可能挤掉 KV Cache 的空间反而降低并发能力。这时候可以考虑 Medusa 或 EAGLE 这种不额外加载完整模型的方案。成本二验证失败的回滚。如果草稿猜的 token 被拒绝需要回滚到最后一个被接受的 token 重新生成。这个回滚逻辑如果实现不好会引入额外延迟。好在主流框架都处理好了自己实现的话要特别注意。心得投机采样和量化叠加时草稿模型最好也用相同的量化方案。我试过草稿模型用 FP16、大模型用 INT4结果接受率明显下降因为两者的数值分布差异被量化放大了。统一量化方案后接受率回升了不少。4. PD 分离让预填充和解码各得其所4.1 一个请求里藏着两种完全不同的负载回到第 1 节讲的 Prefill 和 Decode。Prefill 是计算密集需要大算力Decode 是访存密集需要大带宽。如果把它们放在同一张卡上跑会发生什么假设你有一批请求同时到达。Prefill 阶段会把 GPU 算力吃满这时候正在 Decode 的请求就被卡住了token 生成速度骤降。反过来当大量请求都在 Decode 时GPU 算力闲置新来的请求 Prefill 又要排队。两种负载互相干扰谁也跑不痛快。PD 分离Prefill-Decode Disaggregation的核心思想就是把 Prefill 和 Decode 拆到不同的实例上跑。Prefill 实例专门做计算密集的预填充Decode 实例专门做访存密集的解码。请求先送到 Prefill 实例算完 KV Cache再把 KV Cache 传给 Decode 实例继续生成。4.2 PD 分离真正解决的是什么问题很多人以为 PD 分离是为了更快其实它主要解决的是资源利用率和尾延迟问题。在混合部署下一个长 prompt 的 Prefill 可能占用几百毫秒这期间所有 Decode 请求都被拖慢导致 TTFT首 token 时间和 TPOT每 token 时间的尾延迟都很差。PD 分离后Prefill 和 Decode 互不干扰各自的延迟都更稳定。另一个收益是资源可以按需配比。Prefill 吃算力那就配算力强的卡Decode 吃带宽那就配带宽大的卡。不用为了兼顾两者而妥协。在实际业务里Prefill 和 Decode 的负载比例会随请求特征变化分离部署让扩缩容也更灵活。4.3 KV Cache 传输PD 分离最大的工程挑战PD 分离不是没有代价的最大的代价就是KV Cache 要在 Prefill 和 Decode 实例之间传输。KV Cache 有多大一个 70B 模型32 层hidden size 8192FP16 精度每个 token 的 KV Cache 大约是 2 × 32 × 8192 × 2 字节 ≈ 1MB。一个 4K 上下文的请求KV Cache 就有 4GB。要在实例间传 4GB 数据如果走普通网络延迟会非常可观。所以 PD 分离对网络要求很高。实践中通常用高速互联比如 NVLink、RDMA传输延迟能压到毫秒级。如果网络带宽不够KV 传输的开销可能吃掉分离带来的收益那就得不偿失了。4.4 什么场景该上 PD 分离什么场景别碰PD 分离不是银弹它有明确的适用边界适合上的场景请求量大、并发高Prefill 和 Decode 互相干扰严重prompt 普遍较长长上下文场景Prefill 开销占比高有高速互联网络KV 传输不是瓶颈需要精细控制 TTFT 和 TPOT 的 SLA别碰的场景请求量小单实例就能扛住分离反而增加复杂度网络条件差KV 传输开销大于收益团队运维能力有限PD 分离的部署和调试成本不低我的建议是先把量化和投机采样做扎实这两项收益直接、落地简单。等业务量真的上来了Prefill 和 Decode 的干扰成为瓶颈时再考虑 PD 分离。4.5 部署 PD 分离时的参数与监控要点如果决定上 PD 分离有几个参数和监控指标必须盯紧KV 传输带宽利用率这是 PD 分离的命脉。如果带宽利用率长期接近 100%说明传输是瓶颈要么升级网络要么减少传输量比如量化 KV Cache。Prefill 和 Decode 实例的比例这个比例要根据实际负载动态调整。监控两个实例的 GPU 利用率如果 Prefill 实例长期满载而 Decode 实例空闲就该增加 Prefill 实例。KV Cache 的量化前面提过KV Cache 量化到 INT8 能省一半传输量对 PD 分离来说这是直接的收益。强烈建议在 PD 分离场景下开启 KV Cache 量化。提示PD 分离的调试比单机部署复杂得多建议先用小规模集群验证确认收益后再扩大。我见过不少团队一上来就大规模部署结果被各种网络和同步问题搞得焦头烂额。5. 三项技术如何组合一份可落地的决策清单5.1 按瓶颈选技术而不是按热度选三项技术不是越多越好关键看你的瓶颈在哪。我整理了一份决策清单你的瓶颈优先上原因显存不够模型加载不下量化直接减少权重占用单请求延迟高吞吐还行投机采样减少 Decode 循环次数并发高尾延迟差PD 分离隔离 Prefill 和 Decode 干扰长上下文KV Cache 爆显存KV Cache 量化直接压缩 KV 占用综合成本高量化 投机采样两项叠加收益最大5.2 组合顺序与叠加效应如果三项都要上我的推荐顺序是先量化再投机采样最后 PD 分离。先量化的原因很简单它落地最简单收益最直接而且量化后的模型显存占用小为后续加载草稿模型、部署多实例腾出了空间。投机采样在量化之后上注意草稿模型和大模型用统一的量化方案。PD 分离放最后因为它对基础设施要求最高等前两项把单机性能榨干之后再考虑分布式拆分。叠加时要注意收益不是简单相乘。量化让 Decode 变快投机采样让 Decode 循环变少两者叠加时投机采样的接受率可能因为量化而略降实际加速比会比单独测算的低一些。所以每上一项都要重新测一遍端到端指标别拿旧数据推算。5.3 一套完整的验证流程最后给一套我常用的验证流程确保每项技术都真正带来了收益建立基线FP16 模型单实例测出 TTFT、TPOT、吞吐、显存占用四个核心指标。上量化量化后重测四个指标同时验证精度PPL 业务指标。确认收益后再进入下一步。上投机采样在量化模型基础上开启重点测接受率和端到端延迟。如果接受率低于 0.4考虑换草稿方案。上 PD 分离小规模验证 KV 传输开销确认网络不是瓶颈后再扩大。回归测试每步都保留上一版的配置方便对比和回滚。这套流程看起来繁琐但能帮你避免上了新技术反而变慢的尴尬。我踩过最深的坑就是一次性把三项都上了结果出问题时分不清是哪一项导致的排查花了好几天。一次只改一个变量这是性能优化最朴素也最有效的原则。6. 我在实际部署中攒下的几条经验量化这块我最想强调的是别迷信工具给的默认参数。group_size、desc_act 这些参数对精度和速度的影响很大一定要用自己的业务数据测。我见过有人直接用默认配置量化结果在特定任务上精度掉了 5 个点换了个 group_size 就恢复到 1 个点以内。投机采样这块接受率要持续监控。业务请求的分布会变今天接受率 0.7明天可能因为用户输入风格变化掉到 0.5。建议把接受率做成监控指标低于阈值就告警及时调整草稿策略。PD 分离这块网络是命门。上线前一定要做压力测试模拟高并发下的 KV 传输确认带宽和延迟都在可接受范围。我见过网络没测好就上线的高峰期 KV 传输排队延迟比不分离还差。最后说个心态问题。推理加速是个持续优化的过程没有一劳永逸的方案。模型在变、业务在变、硬件在变今天的最优配置明天可能就不是了。保持测量、保持迭代比追求某个终极方案实在得多。
返回列表