ARTICLE DETAIL

资讯详情

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

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

大模型推理加速实战:量化、投机采样与PD分离的选型与调优 1. 大模型推理加速的底层逻辑与方案选型大模型推理这件事真正落到生产环境里最扎心的从来不是模型效果而是延迟和成本。一个 70B 级别的模型如果按 FP16 精度部署光权重就要吃掉 140GB 显存单张卡根本放不下多卡并行又带来通信开销即便勉强跑起来单次生成几十个 token 就要等好几秒用户早就跑了。所以推理加速不是锦上添花而是能不能上线的生死线。我接触过的加速手段大致分三个层次模型层面量化、剪枝、蒸馏、解码层面投机采样、Medusa、Lookahead、系统层面PD 分离、连续批处理、KV Cache 优化。这三个层次不是互斥的实际工程里往往是组合拳。今天重点聊的就是其中最实用、落地收益最明显的三块量化、投机采样、PD 分离。先说清楚它们各自解决什么问题。量化解决的是显存占用和访存带宽问题——大模型推理本质是 memory-bound算力往往用不满瓶颈在把权重从显存搬到计算单元这一步。把 FP16 压到 INT8 甚至 INT4权重体积直接砍半甚至砍到四分之一访存压力骤降吞吐自然上去。投机采样解决的是解码串行问题——自回归生成一个 token 就要跑一次完整前向GPU 利用率极低投机采样用一个小模型猜多个 token大模型一次性验证把串行变并行。PD 分离解决的是资源错配问题——Prefill 阶段是计算密集型Decode 阶段是访存密集型两者混在一起跑会互相拖累拆开部署各用各的最优配置整体吞吐能提升一大截。提示这三项技术不是选一个用而是有明确的适用边界。量化几乎无脑上投机采样看你的场景能不能接受小模型额外开销PD 分离则要求你有足够的机器资源做拆分。选型的时候我一般按这个顺序判断先看显存够不够不够就上量化再看单请求延迟能不能接受不能就上投机采样最后看整体吞吐和成本要压榨集群利用率就上 PD 分离。下面逐个拆开讲。2. 量化从 FP16 到 INT4 的实操路径2.1 量化到底在做什么为什么能加速量化的本质是用更少的比特位表示权重和激活值。FP16 每个数占 16 位INT8 占 8 位INT4 占 4 位。听起来只是存储变小了但真正的加速来自访存带宽的节省。举个例子一个 7B 模型 FP16 权重约 14GBINT8 约 7GBINT4 约 3.5GB。推理时每生成一个 token 都要把全部权重读一遍带宽省一半理论上速度就能快接近一倍。但量化不是简单地把浮点数截断成整数那样精度会崩。主流做法是分组量化把权重按通道或按块分组每组单独算一个 scale 和 zero-point反量化时用real (int_val - zero_point) * scale还原。分组越细精度损失越小但元数据开销越大。实践中 128 一组是比较常见的折中。量化的粒度也有讲究。Per-tensor是整个张量一个 scale最省事但精度最差Per-channel是每个输出通道一个 scale精度好很多Per-group是每 128 个元素一组精度最好但实现复杂。我实测下来7B 以上模型用 INT8 per-channel 基本无损INT4 就得用 group-wise 才能保住效果。2.2 GPTQ、AWQ、GGUF 三条路线怎么选现在主流量化方案有三条路线各有各的脾气。GPTQ是基于二阶信息的后训练量化用 Hessian 矩阵指导权重的舍入方向尽量减小量化误差。它的优点是生态成熟Hugging Face 上大量模型都有 GPTQ 版本vLLM、TGI 都原生支持。缺点是量化过程比较慢7B 模型在单卡上要跑一两个小时。适合追求精度、有离线量化时间的场景。AWQActivation-aware Weight Quantization的核心洞察是不是所有权重都同等重要那些对应大激活值的权重通道更关键应该保留更高精度。它通过激活值分布来指导量化实测在 INT4 下比 GPTQ 精度略好尤其是小模型上优势明显。量化速度也比 GPTQ 快不少。GGUF是 llama.cpp 生态的格式主打 CPU 和混合推理支持从 2-bit 到 8-bit 的各种精度。它的优势是部署灵活一张消费级显卡甚至纯 CPU 都能跑。缺点是 GPU 上的吞吐不如前两者更适合个人开发者和边缘场景。方案精度表现量化速度GPU 吞吐适用场景GPTQ好慢高服务端批量推理AWQ很好中高服务端尤其小模型GGUF中快中本地/边缘/CPU2.3 量化实操以 AWQ 为例的完整流程假设你手上有一个 7B 的模型想量化成 INT4 部署到 vLLM。步骤大致如下。第一步准备校准数据。AWQ 需要一批代表性样本估计激活分布通常从训练集或业务数据里抽 128 到 512 条就够。数据质量比数量重要最好覆盖你的实际输入分布。from datasets import load_dataset calib_data load_dataset(your_dataset, splittrain[:256])第二步执行量化。用 AutoAWQ 库核心参数是w_bit4、q_group_size128、zero_pointTrue。from awq import AutoAWQForCausalLM from transformers import AutoTokenizer model_path your-model quant_path your-model-awq model AutoAWQForCausalLM.from_pretrained(model_path) tokenizer AutoTokenizer.from_pretrained(model_path) quant_config {w_bit: 4, q_group_size: 128, zero_point: True, version: GEMM} model.quantize(tokenizer, quant_configquant_config, calib_datacalib_data) model.save_quantized(quant_path) tokenizer.save_pretrained(quant_path)第三步验证精度。这一步千万别省。拿你的评测集跑一遍量化前后的对比重点看困惑度和下游任务指标。我见过太多人量化完直接上线结果生成质量断崖式下跌。第四步部署到 vLLM。vLLM 对 AWQ 支持很好启动时指定量化方式即可。python -m vllm.entrypoints.openai.api_server \ --model your-model-awq \ --quantization awq \ --dtype float16 \ --gpu-memory-utilization 0.9注意量化后的模型显存占用会明显下降但gpu-memory-utilization别设太满要给 KV Cache 留足空间否则并发一上来就 OOM。2.4 量化踩坑实录坑一校准数据不匹配。有次我用英文语料校准了一个中文模型结果中文生成质量明显下降。校准数据一定要贴合实际业务分布这是量化的隐形前提。坑二INT4 在小模型上翻车。1.5B 以下的模型做 INT4 量化精度损失会非常明显因为小模型本身冗余度低压不动。这种情况建议至少用 INT8。坑三量化后推理框架不匹配。GPTQ 和 AWQ 的 kernel 实现不同有些框架只支持其中一种。部署前先确认框架支持列表别量化完发现跑不起来。坑四忽略激活量化。只量化权重W4A16是最常见的做法但如果想进一步压可以尝试 W8A8 同时量化激活。不过激活量化对精度影响更大需要更细致的调参。3. 投机采样用小模型撬动大模型的解码效率3.1 为什么自回归解码这么慢大模型生成文本是逐 token 的每生成一个 token 都要把整个模型跑一遍前向。问题在于这个前向的计算量对于单个 token 来说太小了GPU 的算力根本吃不满瓶颈全在把权重从显存搬到计算单元。这就是典型的memory-bound。打个比方你请了一个顶级大厨GPU但每次只让他炒一盘菜一个 token大部分时间他都在等食材从仓库搬过来访存真正炒菜的时间很短。投机采样的思路就是让一个学徒小模型先猜接下来可能炒哪几盘菜大厨一次性把这几盘都炒了然后挑出真正要的那盘。这样大厨的等待时间就被摊薄了。3.2 投机采样的核心原理投机采样Speculative Decoding的流程分三步Draft 阶段用小模型draft model自回归生成 K 个候选 token。Verify 阶段把原始输入加上这 K 个候选 token 一起喂给大模型target model一次性算出每个位置的输出分布。接受/拒绝从前往后逐个比对如果大模型在该位置的采样结果和小模型一致就接受不一致就从大模型的分布重新采样丢弃后面的候选。关键在于这个验证过程是并行的大模型一次前向就能验证 K 个 token。如果小模型的接受率是 α那么平均每次大模型前向能产出约1/(1-α)个 token。α 越高加速越明显。实践中 α 在 0.6 到 0.8 之间比较常见对应 2.5x 到 5x 的加速。数学上投机采样能保证输出分布和大模型单独采样完全一致这是它相比其他近似方法的最大优势——不损失质量。3.3 实操用 vLLM 跑投机采样vLLM 从 0.4 版本开始支持投机采样配置很简单。你需要准备一个 draft model通常选同系列的小模型比如 target 用 70Bdraft 用 7B。python -m vllm.entrypoints.openai.api_server \ --model meta-llama/Llama-3-70B \ --speculative-model meta-llama/Llama-3-7B \ --num-speculative-tokens 5 \ --dtype float16num-speculative-tokens就是 K 值控制每次猜几个 token。这个参数很关键太小加速不明显太大接受率下降反而浪费算力。我一般从 5 开始调根据实测接受率微调。3.4 K 值怎么选一个实测的调参思路K 值的选择本质是权衡接受率和验证成本。K 越大一次验证能覆盖的 token 越多但后面的候选 token 接受率会递减因为小模型猜得越远越不准。我的经验是先固定 K5 跑一轮统计实际接受率。如果接受率高于 0.8可以尝试加到 7 或 8如果低于 0.6降到 3 或 4。同时观察端到端延迟因为验证阶段的计算量随 K 线性增长K 太大可能反而变慢。还有一个技巧是动态 K。有些实现会根据历史接受率动态调整 K 值接受率高时多猜几个低时少猜。这个在 vLLM 里还没原生支持但可以自己在上层做。3.5 投机采样的适用边界与坑坑一draft model 和 target model 分布差异大。如果两个模型不是同系列或者训练数据差异大接受率会很低加速效果还不如不加。最好选同系列、同 tokenizer 的模型。坑二batch size 大时收益下降。投机采样在低并发、低 batch 时收益最明显。当 batch size 已经很大GPU 算力被吃满时投机采样的额外开销可能得不偿失。所以它更适合低延迟优先的场景而不是高吞吐场景。坑三显存占用增加。draft model 也要占显存7B 的 draft 大概多占 14GBFP16。如果显存紧张可以考虑量化 draft model。坑四和量化的叠加。投机采样和量化可以叠加但要注意 draft model 和 target model 的量化方式最好一致否则分布差异会拉大。4. PD 分离把 Prefill 和 Decode 拆开部署4.1 Prefill 和 Decode 的本质差异大模型推理分两个阶段。Prefill是处理用户输入的 prompt一次性把所有输入 token 过一遍计算量大但并行度高是计算密集型。Decode是逐 token 生成每次只处理一个 token计算量小但访存频繁是访存密集型。这两个阶段的资源需求完全不同。Prefill 需要强大的算力Decode 需要高带宽。如果混在一起跑就会出现Prefill 抢占算力导致 Decode 卡顿或者Decode 占着显存导致 Prefill 排队的问题。尤其在多轮对话场景长 prompt 的 Prefill 会严重拖慢正在进行的 Decode。PD 分离Prefill-Decode Disaggregation的思路就是把两个阶段拆到不同的实例上Prefill 实例专门做计算Decode 实例专门做生成中间通过 KV Cache 传输衔接。4.2 PD 分离的架构与数据流典型架构是这样的请求先到 Prefill 实例完成 prompt 处理后生成 KV CacheKV Cache 通过网络传到 Decode 实例Decode 实例基于 KV Cache 逐 token 生成直到结束。这里的关键是KV Cache 的传输。KV Cache 体积不小一个 70B 模型处理 4K promptKV Cache 大概几个 GB。传输延迟必须控制好否则分离带来的收益会被传输开销吃掉。实践中通常用高速网络如 RDMA来传或者把 Prefill 和 Decode 放在同一台机器的不同 GPU 上。4.3 实操用 vLLM 的 disaggregated 模式vLLM 从 0.6 版本开始实验性支持 PD 分离。配置分两部分先起 Prefill 实例python -m vllm.entrypoints.openai.api_server \ --model your-model \ --kv-transfer-config {kv_connector:PyNcclConnector,kv_role:kv_producer} \ --port 8100再起 Decode 实例python -m vllm.entrypoints.openai.api_server \ --model your-model \ --kv-transfer-config {kv_connector:PyNcclConnector,kv_role:kv_consumer} \ --port 8200前面再挂一个 router 做请求分发。Prefill 实例处理完 prompt 后KV Cache 通过 NCCL 传到 Decode 实例。4.4 PD 分离的收益与代价收益方面最直接的是吞吐提升。因为 Prefill 和 Decode 各自用最优配置不再互相干扰。实测在混合负载下PD 分离能带来 1.5x 到 2x 的吞吐提升尤其在有长 prompt 的场景。代价也很明显。架构复杂度上升多了一层 KV Cache 传输运维成本增加。资源利用率可能下降因为 Prefill 和 Decode 的负载比例是动态的如果配比不当会出现一边闲一边忙。故障域扩大任何一个环节出问题都会影响整体。所以 PD 分离不是无脑上它适合大规模、高并发、有长 prompt的场景。小规模部署用连续批处理continuous batching就够了没必要引入这个复杂度。4.5 PD 分离的调优要点要点一Prefill 和 Decode 的实例比例。这个要根据实际负载的 prompt 长度和生成长度来定。经验公式是如果平均 prompt 长度是 P平均生成长度是 G那么 Prefill 和 Decode 的算力配比大致是P : G。比如 prompt 平均 2K生成平均 500那 Prefill 需要的算力占比就高。要点二KV Cache 传输的批量化。单次传输一个请求的 KV Cache 效率低最好攒一批一起传。但攒批会增加延迟需要权衡。要点三监控传输延迟。KV Cache 传输延迟如果超过 Decode 单步时间就会成为瓶颈。要持续监控这个指标必要时升级网络或调整部署拓扑。5. 三项技术的组合与场景化选型5.1 组合使用的收益叠加这三项技术可以叠加但收益不是简单相加。量化降低显存和访存压力为投机采样腾出空间投机采样提升 Decode 效率减轻 Decode 实例压力PD 分离优化整体资源利用。实际组合下来相比 FP16 朴素部署端到端吞吐提升 3x 到 5x 是常见的。但要注意叠加顺序。我一般建议先量化再考虑投机采样最后上 PD 分离。因为量化收益最确定、风险最低投机采样需要调参和验证PD 分离架构改动最大放最后。5.2 不同场景的选型建议场景推荐组合理由单卡部署显存紧张量化INT4/INT8最直接解决显存问题低延迟优先交互式应用量化 投机采样降低单请求延迟高吞吐批量处理量化 PD 分离压榨集群利用率大规模在线服务三者全上综合优化延迟和成本边缘/本地部署GGUF 量化灵活CPU 也能跑5.3 一个真实的调优案例之前有个项目70B 模型要求 P99 延迟低于 2 秒QPS 要跑到 50。初始 FP16 部署单卡放不下4 卡张量并行P99 延迟 5 秒QPS 只有 15。第一步上 AWQ INT4 量化显存降到 2 卡就能放下P99 降到 3.5 秒QPS 到 25。第二步加投机采样draft 用 7B 量化版K5P99 降到 2.2 秒QPS 到 35。第三步上 PD 分离Prefill 和 Decode 各 2 卡P99 稳定在 1.8 秒QPS 到 55。整个过程迭代了三周每一步都做了充分的精度验证和压测。这个案例说明加速技术不是一蹴而就的而是逐步迭代、持续调优的过程。每一步都要有数据支撑不能凭感觉。6. 常见问题与排查技巧实录6.1 量化相关问题速查问题现象可能原因排查方向量化后生成质量下降校准数据不匹配换业务相关校准集量化后推理报错框架不支持该量化格式确认框架支持列表INT4 效果差模型太小冗余度低改用 INT8量化后速度没提升瓶颈不在访存检查是否 compute-bound6.2 投机采样相关问题速查问题现象可能原因排查方向加速不明显接受率低换同系列 draft model反而变慢K 值太大降低 K观察接受率显存 OOMdraft model 占显存量化 draft model输出质量异常验证逻辑有 bug检查采样实现6.3 PD 分离相关问题速查问题现象可能原因排查方向吞吐没提升实例配比不当调整 Prefill/Decode 比例延迟增加KV Cache 传输慢检查网络批量化传输部分请求超时传输失败加重试和超时机制资源利用率低负载不均动态调度或调整配比6.4 几条压箱底的经验经验一量化后一定要做端到端评测。不要只看困惑度要跑真实业务数据看生成质量、指令遵循、格式正确率。我见过困惑度只涨了 0.1 但业务指标掉了 10% 的情况。经验二投机采样的 draft model 要定期更新。如果你的 target model 做了微调draft model 也要跟着更新否则分布差异会拉大接受率下降。经验三PD 分离的 KV Cache 传输要做压缩。KV Cache 里有大量冗余可以用量化或稀疏化压缩后再传能显著降低传输延迟。经验四所有加速手段都要有回退方案。生产环境里量化模型出问题要能快速切回 FP16投机采样异常要能关掉PD 分离故障要能降级到单实例。没有回退方案的优化都是耍流氓。经验五压测要覆盖真实负载分布。别用固定长度的 prompt 压测要模拟真实场景的 prompt 长度分布和生成长度分布否则调出来的参数上线就翻车。7. 我个人的一些实操体会这套东西我断断续续折腾了大半年踩的坑比走的路还多。最大的体会是加速技术的收益高度依赖场景没有银弹。量化在显存紧张时是救命稻草但模型太小反而伤精度投机采样在低延迟场景是神器但高并发下可能帮倒忙PD 分离在大规模集群里能压榨出可观收益但小规模部署纯属自找麻烦。另一个体会是监控比调优更重要。上线之后接受率、KV Cache 传输延迟、显存水位、P99 延迟这些指标要持续盯着因为负载是动态变化的今天调好的参数明天可能就不适用了。我一般会把这些指标接到告警系统一旦偏离阈值就自动降级。最后分享一个小技巧如果你不确定该不该上某项技术先做个最小可行验证。比如投机采样先拿一个请求手动跑一遍看看接受率和延迟再决定要不要铺开。别一上来就改架构那样试错成本太高。技术选型这件事数据永远比直觉靠谱。
返回列表