4. 模型加载与配置:支持模型格式、加载参数与量化选项

vLLM 的模型加载层是连接“磁盘上的权重文件”与“GPU 上的推理引擎”之间的桥梁。这一层决定了服务能否成功启动、显存占用是否合理、吞吐量是否达标。实际运维中,大量启动失败或性能劣化问题并非来自推理内核,而是模型加载阶段配置不当。理解 vLLM 支持的模型格式、加载参数与量化选项,是部署大吞吐服务的第一步。

4.1 核心原理:模型格式、权重布局与加载流程

vLLM 本身不训练模型,它依赖 HuggingFace Transformers 的模型定义与分词器来解析网络结构,同时自行管理权重加载与显存布局。因此,模型格式的兼容性本质上取决于 vLLM 对 HuggingFace 权重目录结构的解析能力,以及对量化权重特殊布局的还原能力。

一个标准的 HuggingFace 模型目录通常包含以下文件:

my_model/
├── config.json          # 模型结构配置(层数、头数、维度等)
├── generation_config.json
├── tokenizer.json       # 分词器词表与合并规则
├── tokenizer_config.json
├── model.safetensors    # 权重文件(单个或多个分片)
├── model-00001-of-00003.safetensors
├── model-00002-of-00003.safetensors
├── model-00003-of-00003.safetensors
└── (可选) quant_config.json  # 量化配置

vLLM 加载流程遵循“先解析 config → 再读取权重 → 最后按张量并行切分”的顺序。其中,张量并行切分发生在权重加载之后、显存分配之前。vLLM 会将每个线性层的权重矩阵按行或列切分到多张 GPU 上,这要求模型格式必须支持按层索引的权重命名,HuggingFace 的 safetensors 分片机制天然满足这一需求。

关键认知:vLLM 并非直接加载原始权重文件到显存,而是先加载到 CPU 内存,经过 weight loading → tensor parallel partition → GPU placement 三个阶段。因此,CPU 内存不足同样会导致加载失败,尤其在加载 70B 以上大模型时。

4.2 支持的模型格式与量化格式

vLLM 对模型格式的支持分为两个维度:权重存储格式与量化格式。权重存储格式决定文件如何读取,量化格式决定权重如何解码到计算精度。

格式类型 代表格式 vLLM 支持情况 说明
权重存储 HuggingFace (safetensors) ✅ 原生支持 推荐格式,支持分片与流式加载
PyTorch bin (pickle) ✅ 兼容 不推荐,加载慢且有安全风险
量化格式 GPTQ (4-bit) ✅ 原生支持 需提供 quantize_config.json,使用 ExLlama 内核
AWQ (4-bit) ✅ 原生支持 需提供 quant_config.json,使用 AWQ 内核
FP8 / INT8 ✅ 支持 通过 quantization 参数指定,需模型本身支持

需要特别注意的是,HuggingFace 格式是基础格式,GPTQ 和 AWQ 模型在 HuggingFace Hub 上同样以 safetensors 存储,但内部权重数值是量化后的整数(如 int32 打包的 4-bit 组),并附带量化参数(scale、zero-point)。vLLM 通过读取模型目录中的量化配置文件来识别格式,而不是通过文件扩展名。

4.3 加载参数详解:dtype 与 tensor_parallel_size

加载参数直接决定显存占用与计算精度。最核心的两个参数是 dtype 与 tensor_parallel_size。

4.3.1 dtype:权重与激活的数值精度

dtype 控制模型权重在显存中的存储精度。vLLM 支持以下选项:

  • auto(默认):根据模型 config.json 中的 torch_dtype 字段自动选择,通常为 float16 或 bfloat16。
  • float16:半精度,显存占用为 FP32 的一半,适合大多数 GPU(A100、H100、V100 等)。
  • bfloat16:BF16,与 FP16 占用相同显存,但保留更大动态范围,对训练/推理稳定性更好,仅支持 Ampere 及以上架构。
  • float32:全精度,显存占用翻倍,通常仅用于调试或 CPU 推理。
常见误区:dtype 并不会自动将 FP16 权重“升级”为 BF16。如果模型原始权重是 FP16,设置 dtype=bfloat16 会导致 vLLM 在加载时执行精度转换,可能引入微小精度损失,且增加加载耗时。最佳实践是:让 dtype 与模型训练时的精度保持一致。

4.3.2 tensor_parallel_size:多 GPU 张量并行

tensor_parallel_size 指定将模型切分到几张 GPU 上。它直接影响显存上限与通信开销。切分策略如下:

  • 每个 Transformer 层的 QKV 投影矩阵按列切分到各 GPU;
  • 输出投影矩阵按行切分;
  • FFN 层的两个线性层分别按列/行切分;
  • 每层计算完成后通过 AllReduce 同步结果。

因此,tensor_parallel_size 必须能被模型隐藏层维度整除(通常为 2 的幂次)。例如,Llama-70B 的 hidden_size 为 8192,支持 TP=1, 2, 4, 8。若设置为 3,vLLM 会直接报错。

# 单 GPU 加载 7B 模型(FP16)
python -m vllm.entrypoints.openai.api_server \
    --model /models/llama-7b-hf \
    --dtype float16 \
    --tensor-parallel-size 1

# 4 卡加载 70B 模型(BF16)
python -m vllm.entrypoints.openai.api_server \
    --model /models/llama-70b-hf \
    --dtype bfloat16 \
    --tensor-parallel-size 4 \
    --gpu-memory-utilization 0.92

4.4 量化选项:GPTQ 与 AWQ 的加载配置

量化模型能显著降低显存占用,但加载方式与原始模型不同。vLLM 要求量化模型目录中必须包含对应的量化配置文件,否则会按原始模型加载并报错。

4.4.1 GPTQ 模型加载

GPTQ 模型目录中应包含 quantize_config.json,内容示例如下:

{
  "bits": 4,
  "group_size": 128,
  "desc_act": false,
  "sym": true,
  "model_name_or_path": "TheBloke/Llama-2-7B-GPTQ"
}

加载时无需额外指定量化参数,vLLM 自动识别:

python -m vllm.entrypoints.openai.api_server \
    --model /models/llama-2-7b-gptq \
    --quantization gptq \
    --dtype float16 \
    --tensor-parallel-size 1
注意:GPTQ 模型加载时 --dtype 应保持 float16,因为 GPTQ 反量化计算在 FP16 下进行。若设置为 bfloat16,部分 GPU 架构可能触发内核不兼容错误。

4.4.2 AWQ 模型加载

AWQ 模型目录中应包含 quant_config.json,vLLM 通过 --quantization awq 启用:

python -m vllm.entrypoints.openai.api_server \
    --model /models/mistral-7b-awq \
    --quantization awq \
    --dtype float16 \
    --tensor-parallel-size 2

AWQ 与 GPTQ 的核心区别在于:AWQ 不依赖反向传播重建权重,而是通过激活感知的缩放因子保护显著权重通道。因此 AWQ 在相同比特数下通常精度略高,且推理内核在部分 GPU 上吞吐更优。

4.5 案例:从 HuggingFace 原始模型到量化部署的完整流程

以下是一个实际部署场景:将 Meta-Llama-3-8B 从原始 FP16 转换为 AWQ 4-bit 并部署到 2 卡 GPU。

  1. 下载原始模型:从 HuggingFace Hub 拉取 safetensors 权重。
  2. 离线量化:使用 AutoAWQ 工具进行量化,生成 AWQ 权重与 quant_config.json。
  3. 验证目录结构:确保包含 model.safetensors、config.json、quant_config.json、tokenizer 文件。
  4. 启动 vLLM 服务:指定 quantization=awq,tensor-parallel-size=2。
  5. 验证加载日志:检查是否出现 "Loading AWQ model" 与 "Using AWQ kernel" 字样。
# 量化后目录结构
llama-3-8b-awq/
├── config.json
├── generation_config.json
├── model.safetensors
├── quant_config.json
├── tokenizer.json
└── tokenizer_config.json

# 启动命令
python -m vllm.entrypoints.openai.api_server \
    --model ./llama-3-8b-awq \
    --quantization awq \
    --tensor-parallel-size 2 \
    --max-model-len 8192 \
    --gpu-memory-utilization 0.90

启动成功后,可通过 nvidia-smi 观察显存占用。8B AWQ 模型在 2 卡上的显存占用约为每卡 6-7 GB(含 KV cache),相比 FP16 的 16 GB 显著降低。

4.6 误区与复盘:模型加载失败的常见根因

以下是在模型加载阶段最常踩的坑,以及对应的排查方向:

现象 可能根因 排查方法
报错 quant_config.json not found 量化模型缺少配置文件 检查模型目录,重新下载完整仓库
报错 tensor_parallel_size must be power of 2 TP 设置不合法 查看 config.json 中 hidden_size,选择可整除的 TP
加载后显存溢出 (OOM) dtype 设置过高或 gpu-memory-utilization 过大 改用 bfloat16,降低利用率至 0.85
推理结果异常(乱码) dtype 与量化格式不匹配 GPTQ/AWQ 必须使用 float16
加载速度极慢 使用 .bin 格式而非 safetensors 转换为 safetensors 格式
复盘要点:模型加载阶段的问题往往在启动后 30 秒内暴露。建议在正式部署前,先使用 --max-model-len 512 与 --tensor-parallel-size 1 做最小化冒烟测试,确认模型可加载后再逐步放大参数。切勿直接在生产配置下调试,否则会浪费大量时间在显存与通信配置上。