☰
LLM推理优化实战(二):AWQ INT4 量化实战:TPOT 降 65%、有效吞吐提升 5.5 倍
2026/10/4 21:34:37 网站建设 项目流程

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.95,TPOT 只从 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 bit,INT4 是 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 时 n=4)。clamp 是截断函数,保证量化后的整数不超出表示范围。

截断是精度损失的主要来源。举个例子:对称量化范围 [-7, 7],S=0.5,量化 r=3.7 时,3.7/0.5=7.4,round 后是 7,没超范围,反量化回来是 3.5,误差 0.2。但如果量化 r=4.2,4.2/0.5=8.4,round 后是 8,超出上限 7 被截断到 7,反量化回来还是 3.5,误差直接变成 0.7。截断阈值的选择是个 trade-off:阈值大则舍入误差大,阈值小则截断误差大。

2.2 为什么用对称量化:矩阵乘法的化简

实际部署中更常用对称量化(Z=0),原因在矩阵乘法里看得很清楚。非对称量化下 A = S_A·Q_A + Z_A,B = S_B·Q_B + Z_B,展开乘法会多出三项额外计算。而对称量化下 Z=0,A×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 对所有权重一视同仁地量化。AWQ(Activation-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/models,API 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 3090(Ampere 架构)上,默认走的是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/api,Key 从https://taotoken.net/api-keys获取,Model ID 填你实际调用的模型名。Coding Plan 适合长期编码和 Agent 场景,入口在https://taotoken.net/coding-plan。

3.3 精度评测配置

评测设置与基线完全一致(不加--apply_chat_template,0-shot),仅修改模型名和输出路径:

export OMP_NUM_THREADS=16 export HF_DATASETS_OFFLINE=1 export HF_DATASETS_CACHE=/root/autodl-tmp/hf_cache lm_eval \ --model local-completions \ --model_args "model=qwen2.5-7b-awq,base_url=http://localhost:8000/v1/completions,tokenizer_backend=huggingface,tokenizer=/root/autodl-tmp/models/qwen2.5-7b-instruct-awq,num_concurrent=32,max_length=4096" \ --tasks hellaswag,arc_easy,arc_challenge,gsm8k \ --num_fewshot 0 \ --output_path /root/autodl-tmp/results/lm_eval_awq \ --log_samples

3.4 性能基线测试配置

export HF_HUB_OFFLINE=1 export TRANSFORMERS_OFFLINE=1 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_awq

3.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_OFFLINE=1 export TRANSFORMERS_OFFLINE=1 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 done

4. 验证请求与成功结果: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 单次性能测试结果

先看 rate=4、conc=16 下的单次测试结果:

指标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/s+39%

TPOT P50 直接从 23.9ms 降到 9.0ms,降幅 62%,超出预期的"减半"目标。

4.3 参数扫描结果

实验组 A:固定 conc=32,扫描 request-rate

RateBF16 TPOT P50AWQ TPOT P50BF16 Out_TPSAWQ Out_TPS
120.4 ms6.9 ms2021222
222.1 ms7.1 ms3851842
424.2 ms7.5 ms6951806
826.5 ms10.0 ms9261451
1627.0 ms13.0 ms9671965
inf26.9 ms12.9 ms9792128

低负载下 TPOT 降幅更大:rate=1~4 时 AWQ 的 TPOT 稳定在 7ms 左右,是 BF16 的 1/3。吞吐饱和点后移:BF16 在 rate=8 就趋于饱和(926→967,+4.4%),AWQ 在 rate=16 才开始饱和(1965→2128,+8.3%)。原因是模型权重压缩后省出的显存全部给了 KV cache,GPU 能同时处理更多请求。

实验组 B:固定 rate=inf,扫描 max-concurrency

ConcBF16 TPOT P50AWQ TPOT P50BF16 TPOT P99AWQ TPOT P99BF16 Out_TPSAWQ Out_TPS
119.7 ms6.8 ms19.8 ms6.9 ms5014482
421.4 ms7.5 ms27.2 ms7.8 ms3459941
823.4 ms8.7 ms35.2 ms9.2 ms59516153
1626.8 ms12.9 ms60.2 ms14.5 ms97821266
3234.4 ms23.3 ms165 ms30.3 ms134123191
6451.9 ms39.4 ms387 ms60.9 ms15832509

单请求 TPOT 远超物理预期:conc=1 时 TPOT P50 = 6.84ms,已经超过了基线文章中定的 8ms 目标。理论下限重新计算:INT4 权重 ≈ 7B × 0.5 bytes ≈ 3.5 GB,RTX 3090 带宽 936 GB/s,理论 TPOT = 3.5 / 936 ≈ 3.7 ms,实测 6.84 ms,MBU ≈ 54%。MBU 比 BF16(76%)低,差距主要来自 INT4 反量化的额外计算开销——GPU 需要把 INT4 权重实时解压为 FP16 参与计算。

TPOT P99 拐点从 conc=32 后移到 conc=64:BF16 下 conc=32→64,TPOT P99 从 60ms 暴涨至 165ms;AWQ 下 conc=32→64,TPOT P99 从 14.5ms 涨至 30.3ms,翻倍但仍可控;conc=64→128 才开始恶化。拐点后移一档,说明量化后 KV cache 池更大,系统能承受更高的并发压力。生产甜点区从 conc=8~16 扩大到了 conc=16~32。

4.4 SLO 分析:有效吞吐提升 5.5 倍

严格 SLO(TTFT P99 < 300ms,TPOT P99 < 40ms):

BF16AWQ INT4
达标档位仅 rate=1~2全部达标(rate=1 到 inf)
最佳 Goodput826 tok/s(rate=2)4547 tok/s(rate=inf)
提升倍数—5.5×

这是量化收益最震撼的一个数字:BF16 下只有最轻的两档负载能满足严格 SLO,AWQ 下连 rate=inf 全速压测都轻松达标。有效吞吐提升 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 拐点: conc=32 → conc=64 (后移一档) 严格 SLO Goodput: 826 → 4547 tok/s (+450%) 生产甜点区: conc=8~16 → conc=16~32 模型体积: 权重大小: ~14 GB → ~4 GB (-71%)

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

5.1 401 Unauthorized:API 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/api,Key 从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 Cache(KV cache 减半,吞吐再涨 20~30%,精度损失 < 0.5%)、投机采样(低并发 TPOT 再降 30~50%,输出完全一致),以及组合优化冲击 TPOT < 4ms。

如果你在本地跑量化实验的同时,需要云端模型做对照评测或辅助生成校准数据,TaoToken 的模型对话入口在https://taotoken.net/models,API 地址是https://taotoken.net/api,API 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 倍的有效吞吐,对绝大多数生产场景来说都值得。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询