ARTICLE DETAIL

资讯详情

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

LLM推理优化实战(二):AWQ INT4 量化实战:TPOT 降 65%、有效吞吐提升 5.5 倍

LLM推理优化实战(二):AWQ INT4 量化实战:TPOT 降 65%、有效吞吐提升 5.5 倍 1. 为什么单卡跑 7B 模型TPOT 卡在 19.7ms 下不来如果你在 RTX 3090 这类单卡上部署过 Qwen2.5-7B-Instruct大概率遇到过这个场景模型能跑起来首 token 也还行但一旦进入连续对话每个 token 的生成时间TPOT就稳定在 20ms 上下怎么调--max-num-seqs、怎么改 batch size 都压不下去。我试过把gpu-memory-utilization从 0.8 拉到 0.95TPOT 只从 19.7ms 降到 19.2ms基本没动。这不是参数没调好而是撞到了显存带宽的物理墙。BF16 精度下7B 模型的权重约 14GB每次 decode 都要把这 14GB 权重从显存完整读一遍。RTX 3090 的显存带宽是 936 GB/s理论下限就是 14 / 936 ≈ 15ms实测 19.7ms 已经达到 76% 的带宽利用率MBU纯软件调参的空间基本到顶了。想继续压 TPOT只有一条路减少每次 decode 需要搬运的权重字节数。这就是 AWQ INT4 量化要解决的问题——把每个参数从 2 字节压到 0.5 字节权重体积直接砍掉 75%。本文会从校准数据准备、权重分组、kernel 选择一路讲到可复制的量化配置最后用 TPOT 和吞吐对比脚本验证单卡上 TPOT 降 65%、有效吞吐提升 5.5 倍到底是怎么跑出来的。适合谁看已经在单卡上部署过 LLM、想进一步压延迟和提吞吐的工程师对量化原理有基本概念、但没实际跑过 AWQ 落地流程的同学以及正在做推理成本优化、需要一份可复现实验记录的人。2. AWQ INT4 量化前置原理、模型与 TaoToken 接入准备2.1 量化到底在做什么从 BF16 到 INT4 的线性映射量化的核心思想很朴素用更少的 bit 表示原本高精度的浮点数。BF16 是 16 bitINT4 是 4 bit存储和带宽都变成原来的 1/4。代价是精度损失——用有限个离散整数去近似连续浮点区间必然有舍入误差。量化本质是一个线性映射把浮点数 r 映射到整数 Q(r)量化 Q(r) clamp(round(r / S) - Z, -2^(n-1), 2^(n-1) - 1) 反量化r_hat S × (Q(r) Z)其中 S 是缩放因子决定每个整数格对应多大浮点范围Z 是零点偏移n 是位宽INT4 时 n4。clamp 是截断函数保证量化后的整数不超出表示范围。截断是精度损失的主要来源。举个例子对称量化范围 [-7, 7]S0.5量化 r3.7 时3.7/0.57.4round 后是 7没超范围反量化回来是 3.5误差 0.2。但如果量化 r4.24.2/0.58.4round 后是 8超出上限 7 被截断到 7反量化回来还是 3.5误差直接变成 0.7。截断阈值的选择是个 trade-off阈值大则舍入误差大阈值小则截断误差大。2.2 为什么用对称量化矩阵乘法的化简实际部署中更常用对称量化Z0原因在矩阵乘法里看得很清楚。非对称量化下 A S_A·Q_A Z_AB S_B·Q_B Z_B展开乘法会多出三项额外计算。而对称量化下 Z0A×B S_A·S_B·Q_A·Q_B只剩一项纯整数乘法加一次缩放硬件实现更简单更快。对称量化的代价是要用 [-127, 127] 而不是 [-128, 127]牺牲 1/256 的表示范围INT4 时是 1/16换取无偏差的矩阵乘法。如果强行用 [-128, 127]正负不对称会引入系统偏差——比如 A[-2.2,-1.1,1.1,2.2] 和 B[0.5,0.3,0.3,0.5] 的点积理论值是 0用 [-128,127] 量化后 2.2 被截断到 127 而 -2.2 保留 -128结果会变成 -0.00853偏向负无穷。改用 [-127,127] 后结果精确为 0。2.3 AWQ 的核心改进保护重要通道普通 PTQ 对所有权重一视同仁地量化。AWQActivation-aware Weight Quantization的改进在于先用校准数据跑一遍前向传播找出每层中对激活值影响最大的重要权重通道对这些通道做保护性缩放后再统一量化。这样在同样的 INT4 精度下能显著减少精度损失。AWQ 属于 PTQ训练后量化不需要重新训练模型用少量校准数据找到每层最优缩放因子即可。2.4 模型下载与 TaoToken 接入准备Qwen 官方在 ModelScope 上发布了预量化好的 AWQ INT4 版本直接下载即可modelscope download \ --model qwen/Qwen2.5-7B-Instruct-AWQ \ --local_dir /root/autodl-tmp/models/qwen2.5-7b-instruct-awq下载完成后验证量化配置cat /root/autodl-tmp/models/qwen2.5-7b-instruct-awq/config.json | grep -A5 quantization看到bits: 4说明是 INT4 量化模型。模型文件总大小约 4~5 GB对比 BF16 的 14 GB 压缩了约 70%。如果你在本地做量化实验的同时还需要调用云端大模型做对比评测或辅助生成校准数据可以通过 TaoToken 统一接入。它的 API 地址是https://taotoken.net/api兼容 OpenAI 接口格式模型对话入口在https://taotoken.net/modelsAPI Key 在https://taotoken.net/api-keys管理。这样本地跑 AWQ 量化、云端调模型做对照两套流程互不干扰。3. 可复制配置vLLM 启动参数与量化 kernel 选择3.1 vLLM 启动 AWQ 模型vLLM 会自动识别 AWQ 量化格式不需要额外参数。启动命令如下python -m vllm.entrypoints.openai.api_server \ --model /root/autodl-tmp/models/qwen2.5-7b-instruct-awq \ --served-model-name qwen2.5-7b-awq \ --host 0.0.0.0 \ --port 8000 \ --gpu-memory-utilization 0.85 \ --max-model-len 4096这里有个容易踩的坑量化模型的权重从 ~14GB 降到 ~4GB但nvidia-smi显示的显存占用不会明显减少。因为 vLLM 的预分配机制会把省出来的 ~10GB 显存全部分配给 KV cache 池。这意味着系统能同时处理更多并发请求吞吐天花板会大幅提升——这是量化收益的第二重来源很多人只看到 TPOT 下降忽略了 KV cache 扩容带来的吞吐红利。3.2 量化 kernel 选择与配置片段vLLM 加载 AWQ 模型时底层会根据 GPU 架构自动选择量化 kernel。在 RTX 3090Ampere 架构上默认走的是awq_marlin或awq_gemm路径。如果你需要显式指定可以在启动时加--quantization awq但通常不需要。对于需要精细控制 kernel 的场景可以在模型目录下放一份quant_config.json内容如下{ quant_method: awq, bits: 4, group_size: 128, zero_point: true, version: gemm }group_size是权重分组大小128 是 AWQ 的默认值。分组越小缩放因子越精细精度越高但反量化开销也越大。实测下来 128 是精度和速度的平衡点改成 64 精度提升不到 0.3%但 TPOT 会涨 5% 左右。如果你用的是 Cline MCP 或 Claude Code 这类工具做辅助开发需要配置三件套Base URL 填https://taotoken.net/apiKey 从https://taotoken.net/api-keys获取Model ID 填你实际调用的模型名。Coding Plan 适合长期编码和 Agent 场景入口在https://taotoken.net/coding-plan。3.3 精度评测配置评测设置与基线完全一致不加--apply_chat_template0-shot仅修改模型名和输出路径export OMP_NUM_THREADS16 export HF_DATASETS_OFFLINE1 export HF_DATASETS_CACHE/root/autodl-tmp/hf_cache lm_eval \ --model local-completions \ --model_args modelqwen2.5-7b-awq,base_urlhttp://localhost:8000/v1/completions,tokenizer_backendhuggingface,tokenizer/root/autodl-tmp/models/qwen2.5-7b-instruct-awq,num_concurrent32,max_length4096 \ --tasks hellaswag,arc_easy,arc_challenge,gsm8k \ --num_fewshot 0 \ --output_path /root/autodl-tmp/results/lm_eval_awq \ --log_samples3.4 性能基线测试配置export HF_HUB_OFFLINE1 export TRANSFORMERS_OFFLINE1 vllm bench serve \ --backend openai-chat \ --base-url http://localhost:8000 \ --endpoint /v1/chat/completions \ --model qwen2.5-7b-awq \ --tokenizer /root/autodl-tmp/models/qwen2.5-7b-instruct-awq \ --dataset-name sharegpt \ --dataset-path /root/autodl-tmp/datasets/sharegpt.json \ --num-prompts 200 \ --request-rate 4 \ --max-concurrency 16 \ --save-result \ --result-dir /root/autodl-tmp/results/perf_awq3.5 参数扫描脚本与基线相同的扫描方案实验组 A 扫描 request-rate实验组 B 扫描 max-concurrency仅替换模型名和输出路径#!/bin/bash mkdir -p /root/autodl-tmp/results/sweep_awq COMMON_ARGS --backend openai-chat --base-url http://localhost:8000 --endpoint /v1/chat/completions --model qwen2.5-7b-awq --tokenizer /root/autodl-tmp/models/qwen2.5-7b-instruct-awq --dataset-name sharegpt --dataset-path /root/autodl-tmp/datasets/sharegpt.json --num-prompts 200 --save-result export HF_HUB_OFFLINE1 export TRANSFORMERS_OFFLINE1 echo 实验组 A扫描 request-rate for rate in 1 2 4 8 16 inf; do vllm bench serve $COMMON_ARGS \ --request-rate $rate \ --max-concurrency 32 \ --result-dir /root/autodl-tmp/results/sweep_awq \ --result-filename expA_rate${rate}_conc32.json sleep 5 done echo 实验组 B扫描 max-concurrency for conc in 1 4 8 16 32 64 128; do vllm bench serve $COMMON_ARGS \ --request-rate inf \ --max-concurrency $conc \ --result-dir /root/autodl-tmp/results/sweep_awq \ --result-filename expB_rateinf_conc${conc}.json sleep 5 done4. 验证请求与成功结果TPOT 降 65%、吞吐提升 5.5 倍4.1 精度对比结果数据集指标BF16 基线AWQ INT4绝对下降相对下降HellaSwagacc_norm80.5%79.6%-0.9%-1.1%ARC-Easyacc_norm81.0%78.8%-2.2%-2.7%ARC-Challengeacc_norm55.5%54.5%-1.0%-1.8%GSM8Kflexible-extract71.3%69.2%-2.1%-2.9%精度损失在 1~3% 之间常识推理HellaSwag损失最小数学推理GSM8K和科学知识ARC-Easy略高说明这两类任务对权重精度更敏感。总体在可接受范围内。4.2 单次性能测试结果先看 rate4、conc16 下的单次测试结果指标BF16 基线AWQ INT4变化TTFT P50113 ms93 ms-18%TTFT P99293 ms293 ms≈0%TPOT P5023.9 ms9.0 ms-62%TPOT P9934.4 ms21.7 ms-37%Out_TPS558 tok/s777 tok/s39%TPOT P50 直接从 23.9ms 降到 9.0ms降幅 62%超出预期的减半目标。4.3 参数扫描结果实验组 A固定 conc32扫描 request-rateRateBF16 TPOT P50AWQ TPOT P50BF16 Out_TPSAWQ Out_TPS120.4 ms6.9 ms2021222222.1 ms7.1 ms3851842424.2 ms7.5 ms6951806826.5 ms10.0 ms92614511627.0 ms13.0 ms9671965inf26.9 ms12.9 ms9792128低负载下 TPOT 降幅更大rate1~4 时 AWQ 的 TPOT 稳定在 7ms 左右是 BF16 的 1/3。吞吐饱和点后移BF16 在 rate8 就趋于饱和926→9674.4%AWQ 在 rate16 才开始饱和1965→21288.3%。原因是模型权重压缩后省出的显存全部给了 KV cacheGPU 能同时处理更多请求。实验组 B固定 rateinf扫描 max-concurrencyConcBF16 TPOT P50AWQ TPOT P50BF16 TPOT P99AWQ TPOT P99BF16 Out_TPSAWQ Out_TPS119.7 ms6.8 ms19.8 ms6.9 ms5014482421.4 ms7.5 ms27.2 ms7.8 ms3459941823.4 ms8.7 ms35.2 ms9.2 ms595161531626.8 ms12.9 ms60.2 ms14.5 ms978212663234.4 ms23.3 ms165 ms30.3 ms1341231916451.9 ms39.4 ms387 ms60.9 ms15832509单请求 TPOT 远超物理预期conc1 时 TPOT P50 6.84ms已经超过了基线文章中定的 8ms 目标。理论下限重新计算INT4 权重 ≈ 7B × 0.5 bytes ≈ 3.5 GBRTX 3090 带宽 936 GB/s理论 TPOT 3.5 / 936 ≈ 3.7 ms实测 6.84 msMBU ≈ 54%。MBU 比 BF1676%低差距主要来自 INT4 反量化的额外计算开销——GPU 需要把 INT4 权重实时解压为 FP16 参与计算。TPOT P99 拐点从 conc32 后移到 conc64BF16 下 conc32→64TPOT P99 从 60ms 暴涨至 165msAWQ 下 conc32→64TPOT P99 从 14.5ms 涨至 30.3ms翻倍但仍可控conc64→128 才开始恶化。拐点后移一档说明量化后 KV cache 池更大系统能承受更高的并发压力。生产甜点区从 conc8~16 扩大到了 conc16~32。4.4 SLO 分析有效吞吐提升 5.5 倍严格 SLOTTFT P99 300msTPOT P99 40msBF16AWQ INT4达标档位仅 rate1~2全部达标rate1 到 inf最佳 Goodput826 tok/srate24547 tok/srateinf提升倍数—5.5×这是量化收益最震撼的一个数字BF16 下只有最轻的两档负载能满足严格 SLOAWQ 下连 rateinf 全速压测都轻松达标。有效吞吐提升 5.5 倍。原因是双重收益叠加TPOT 大幅下降让每个请求处理更快排队时间缩短TTFT 也跟着下降全链路延迟改善。4.5 完整对比汇总 BF16 基线 vs AWQ INT4 完整对比 精度0-shot不加 chat template HellaSwag: 80.5% → 79.6% (-0.9%) ARC-Easy: 81.0% → 78.8% (-2.2%) ARC-Challenge: 55.5% → 54.5% (-1.0%) GSM8K: 71.3% → 69.2% (-2.1%) 性能 单请求 TPOT P50: 19.7 ms → 6.84 ms (-65%) 吞吐天花板(Out_TPS): 978 → 2126 tok/s (117%) TPOT P99 拐点: conc32 → conc64 (后移一档) 严格 SLO Goodput: 826 → 4547 tok/s (450%) 生产甜点区: conc8~16 → conc16~32 模型体积 权重大小: ~14 GB → ~4 GB (-71%)5. 本篇常见错排查401、local proxy failed、reading choices、OAuth5.1 401 UnauthorizedAPI Key 没配对如果你在评测脚本里通过 TaoToken 调用云端模型做对照报 401 通常是 Key 没填对或没带上。检查https://taotoken.net/api-keys里生成的 Key 是否复制完整请求头里是否带了Authorization: Bearer your-key。本地 vLLM 服务默认不校验 Key所以 401 一般出现在云端调用环节。5.2 local proxy failed本地代理配置冲突这个报错通常出现在lm_eval或vllm bench serve请求本地 8000 端口时。原因是环境变量里残留了HTTP_PROXY或HTTPS_PROXY导致请求被转发到不存在的代理。解决办法是在脚本开头清掉unset HTTP_PROXY unset HTTPS_PROXY unset http_proxy unset https_proxy然后重新跑评测。本地服务不需要走任何代理直连http://localhost:8000即可。5.3 reading choices数据集格式不匹配vllm bench serve报reading choices相关错误一般是--dataset-name sharegpt和--dataset-path指向的文件格式对不上。ShareGPT 格式要求 JSON 数组每个元素包含conversations字段里面是from/value的列表。检查你的sharegpt.json是否符合这个结构或者改用--dataset-name random先跑通流程。5.4 OAuth 相关报错Claude Code 接入配置如果你用 Claude Code 接入 TaoToken 做辅助开发遇到 OAuth 报错通常是 Base URL 或 Model ID 没配对。三件套配置如下Base URL 填https://taotoken.net/apiKey 从https://taotoken.net/api-keys获取Model ID 填实际模型名。Claude Code 的接入文档在https://taotoken.net/doc里面有完整的配置示例。如果用的是 Codex 的auth.json确保里面的base_url和api_key字段与上面一致。5.5 量化模型加载失败config.json 缺字段如果 vLLM 启动时报quantization method not found或类似错误检查模型目录下的config.json是否有quantization_config字段。有些第三方量化模型会漏掉这个字段手动补上即可quantization_config: { quant_method: awq, bits: 4, group_size: 128, zero_point: true }补完后重启 vLLM 服务应该能正常识别。6. 从量化到生产下一步优化方向与接入入口AWQ INT4 已经把 TPOT 压到了 6.84ms距离理论下限 3.7ms 还有空间但剩余优化的难度和收益比会逐渐递减。后续可以叠加 FP8 KV CacheKV cache 减半吞吐再涨 20~30%精度损失 0.5%、投机采样低并发 TPOT 再降 30~50%输出完全一致以及组合优化冲击 TPOT 4ms。如果你在本地跑量化实验的同时需要云端模型做对照评测或辅助生成校准数据TaoToken 的模型对话入口在https://taotoken.net/modelsAPI 地址是https://taotoken.net/apiAPI Key 在https://taotoken.net/api-keys管理。长期做编码和 Agent 场景的话Coding Plan 入口在https://taotoken.net/coding-plan接入文档在https://taotoken.net/doc。量化收益的本质不是简单的权重变小了而是三重复利效应叠加TPOT 下降权重搬运量降 71%、KV cache 扩容省出 ~10GB 显存全给 KV cache、SLO 全面达标TPOT 下降带动 TTFT 下降Goodput 提升 5.5 倍。这三重收益互相放大最终效果远大于单纯的4 倍压缩所暗示的线性提升。1~3% 的精度换 5.5 倍的有效吞吐对绝大多数生产场景来说都值得。
返回列表