推理模型响应速度直接决定用户留存。一个对话产品接入大模型后,如果首字延迟从800毫秒涨到3秒,单token耗时超过50毫秒,即使回答质量再好,用户也可能在中途退出。很多团队第一反应是增加显卡或升级更高端GPU,但实际上推理链路的低效往往来自权重访存、逐token解码和静态调度。先把模型量化和推理引擎优化做扎实,通常能在不换硬件的情况下把延迟压回可接受范围,并同时提升单卡吞吐和并发能力。

一、先定位推理慢在哪:访存、计算与调度
大模型推理是自回归过程,每生成一个token都要访问一次完整权重。以7B参数模型为例,FP16格式权重约14GB,生成一个token理论上至少需要从显存读取14GB数据。即便显存带宽达到2TB/s,仅权重读取就要7毫秒左右。实际推理中还叠加了注意力计算、KV Cache读写、LayerNorm和激活函数等算子,以及推理引擎的调度开销,因此单token耗时经常落到30到80毫秒,长序列输入时首字延迟会更糟糕。
除了访存压力,逐token解码带来的计算形态也值得注意。训练和prefill阶段矩阵运算维度大,GPU利用率较高;但decode阶段每次只处理一个新token,矩阵乘变成矩阵向量乘,计算强度低,很容易变成访存受限任务。此时GPU算力再高也发挥不出来。另一个问题是调度:如果每个请求都独立等待前向完成,多用户并发时请求排队会造成P99延迟飙升。短请求被长请求阻塞的情况非常常见,这不是算力不足,而是批处理策略太粗放。
因此优化要分两层走。量化负责减少每次前向需要搬运的权重字节数,让同样的显存带宽能服务更多token。推理引擎负责重组计算图、提升算子执行效率,并用连续批处理和PagedAttention等机制减少空闲等待。两者目标不同,但可以叠加使用,达到延迟降低和吞吐提升的综合效果。
二、模型量化:从FP16到INT4的精度与速度平衡
模型量化按是否重新训练分为训练后量化(PTQ)和量化感知训练(QAT)。PTQ不需要更新权重,只用少量校准样本统计激活值范围,把FP16权重映射到低比特整数。对大多数文本生成、摘要和对话任务,INT8 PTQ的精度损失通常很小,延迟可降低20%到40%,显存占用直接减半。INT4量化还能把模型体积压到FP16的四分之一左右,在显存较小的GPU上可以加载更大模型或服务更多并发。
但INT4不是无脑用。常规INT4量化容易在数学推理、代码生成和低资源语言任务上出现明显掉点,需要引入分组量化、非对称量化或GPTQ、AWQ等算法保护敏感权重通道。下面是一个使用bitsandbytes加载INT4模型的例子,它适合快速验证量化对业务效果的影响,不需要额外训练或复杂校准。
import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
quant_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16
)
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
quantization_config=quant_config,
device_map="auto"
)
选择量化精度时,建议先以FP16为基线,然后尝试INT8,确认业务指标没有明显下降后再评估INT4。对于长文本摘要、代码补全或需要强推理能力的场景,INT4可能放大错误,甚至导致格式不稳定。如果训练资源充足,可以对关键层做量化感知训练或混合精度量化,让敏感层保持FP16,其他层降到INT8或INT4。这种按层敏感度分配精度的方式,往往比全局量化更稳,也更适合对质量要求高的在线服务。
三、推理引擎优化:算子融合、KV Cache与连续批处理
量化解决的是带宽瓶颈,推理引擎则更多从计算图和调度机制入手。TensorRT、vLLM、llama.cpp、OpenVINO等引擎各自面向不同硬件,但优化思路有共同点:通过算子融合减少kernel启动次数,比如把LayerNorm后接的Scale合并到后续矩阵乘;通过FlashAttention减少注意力计算中的显存读写;通过高效矩阵乘库提升底层计算效率。这些优化在FP16和INT8模型上都能生效,尤其是小批量decode时效果更明显。
连续批处理是在线推理的关键一步。传统静态批处理要求一个batch内所有序列全部生成结束后才能释放资源,少数长回复会拖累大量短请求。连续批处理允许某个序列完成后立即插入新请求,减少GPU空转。配合PagedAttention把KV Cache改为分页管理,可以避免为每个序列预分配大块连续显存,显著提高并发规模。下面是启动一个AWQ INT4模型服务时常见的vLLM配置:
python -m vllm.entrypoints.openai.api_server \ --model /data/models/qwen2-7b-instruct-int4 \ --quantization awq \ --gpu-memory-utilization 0.92 \ --max-num-batched-tokens 4096 \ --enable-prefix-caching
其中gpu-memory-utilization控制单个GPU可分配给KV Cache的显存比例,max-num-batched-tokens限制单次批处理的总token数,enable-prefix-caching可以复用相同prompt前缀的KV Cache。对于首字延迟敏感的场景,还可以引入投机解码,用小模型先起草多个token,再由大模型统一验证;或者把prefill和decode拆到不同GPU上做PD分离,避免长prompt抢占解码资源。这些方案不是所有业务都需要,但当延迟指标长期不达标时,它们能带来非常直接的改善。
四、落地顺序与效果验证
优化动作要有顺序,否则容易陷入反复试错。建议先建立基线,记录首字延迟、单token耗时、P50/P99延迟、单卡吞吐和显存占用。基线清楚后再启用引擎自带的高性能注意力实现和连续批处理,这一步通常风险最小,收益也稳定。接下来尝试FP16切换INT8或FP8量化,验证模型输出质量。如果显存不足或需要更高并发,再评估INT4。每一步都建议用内部固定评测集做回归,关注BLEU、ROUGE、代码通过率或人工胜率,而不是只看速度。
举一个实际压测中的对比:某7B模型部署在单张24GB显存GPU上,FP16加vLLM连续批处理时,并发16请求的吞吐约1100 token/s,P99首字延迟2.8秒。切换AWQ INT4后,模型显存占用从22GB降到6GB,并发提升到32,吞吐约2100 token/s,P99首字延迟降到1.3秒,输出质量指标仅下降不到1个百分点。这个结果说明量化与引擎优化叠加后带来的不只是吞吐,还有延迟和并发容量的同步改善。
需要避开几个常见误区。一是过度追求INT4,导致长尾任务质量不可控;二是只调量化而不优化引擎,带宽瓶颈缓解了,但调度等待仍然存在;三是把并发调得过高,造成请求排队和延迟抖动。另外要注意预热和CUDA Graph的问题,未做预热时前几次请求延迟会异常高,压测数据可能失真。最终建议把量化参数和引擎配置纳入统一配置管理,每次模型版本升级后按同样的压测脚本重新回归,确保线上体验不随时间退化。