qwen部署
1 | conda create -n vllm-qwen python=3.11 -y |
必须通过两卡 + pipeline + 降并发的方式才能部署成功,否则会因为显存不足而报错。
1 | CUDA_VISIBLE_DEVICES=0,1 vllm serve /home/share/HDstorage/xyc/qwen/models/qwen14b \ |
部署成功后,可以通过以下方式进行测试:
1 | curl http://127.0.0.1:8000/v1/chat/completions \ |
关闭服务:
1 | pkill -f "vllm serve qwen14b" |
报告
基于 vLLM 的 BitsAndBytes 4-bit 支持,我已经把一个小型 NF4 模型推理链路跑通,并围绕“NF4 权重恢复发生在什么位置、成本有多大、显式反量化是否值得”做了对照分析。相关脚本和记录分别在 bench_vllm_qwen.py、vllm_bnb_benchmark_notes.md、benchmark_nf4_ikko.py、outputs/reports/nf4_ikko_experiments.md。
本次实际运行环境是服务器 deep 上的 vllm-qwen14b 环境,模型为 unsloth/Qwen2.5-14B-Instruct-bnb-4bit 本地副本。服务通过两卡、pipeline-parallel-size=2、低并发 max-num-seqs=1 成功启动并返回结果。这里需要明确一点:实际跑通的是两卡 PP=2,不是 TP=2。vLLM 日志已经确认 rank 0/1 分别是 PP rank 0/1, TP rank 0。之所以这样部署,是因为 vLLM 对 pre-quantized BitsAndBytes 模型显式禁止 tensor parallel,而允许 pipeline parallel。
从推理链路上看,NF4 权重恢复并不是“先把整层权重彻底反量化后常驻显存再计算”。vLLM 在加载 pre-quantized BitsAndBytes checkpoint 时,会先在 loader 中重建 QuantState。入口在 vLLM 安装里的 bitsandbytes_loader.py,其中 _quantized_4bit_generator() 会收集 weight.absmax、weight.quant_map、weight.nested_absmax、weight.nested_quant_map、weight.quant_state.bitsandbytes__nf4 等元数据,再通过 QuantState.from_dict(...) 组装成运行时量化状态。随后 _bind_quant_states_to_params() 会对 double-quant 的 scale 元数据做一次恢复,也就是把 nested 状态里的 absmax 展开成 float32;但 packed 的 4-bit 权重本体仍然保持 uint8 形式挂在参数上。对普通 dense 线性层,真正的计算热路径并不显式生成完整 dense 权重,而是直接调用 bitsandbytes.matmul_4bit(x, packed_weight.T, quant_state);只有 MoE 那条路径更接近“先 dequantize_4bit(...),再交给后续算子”。
在跑通服务后,我先做了 20 个串行请求的 benchmark,按短、中、长 prompt 分组,统计首 token 延迟和 completion 吞吐。整体结果是:平均 TTFT 0.0858s,p50/p95 TTFT 0.0791s / 0.1154s,completion 吞吐 70.76 tok/s。按输入长度看,短输入约 88 prompt tokens,对应 TTFT 0.0793s;中等输入约 363 tokens,对应 0.0861s;长输入约 963 tokens,对应 0.0986s。结论是低并发条件下,输入变长会推高 TTFT,但 decode 吞吐基本稳定在 70 tok/s 左右。
为了分析“显式反量化”这条替代路径,我没有直接修改 bitsandbytes 本体,而是在仓库里实现了一套实验性自定义扩展,文件是 fs_plugins/custom_ops/nf4_ikko.cpp、fs_plugins/custom_ops/nf4_ikko.cu、fs_plugins/custom_ops/nf4_ikko.py。它模拟的是“先把 packed NF4 权重恢复成 dense bf16,再做 F.linear”的实验路径。这样做的目的不是替换生产实现,而是把成本拆开量化:可以分别测单层恢复耗时、显式反量化后的中间写回开销,以及小 batch/decode-like 场景下它对总时延的贡献。
第一轮实验先做了一个保守版 restore kernel,随后又把在 mainla.cu 中的关键优化补进 restore 路径,包括 shared LUT、warp 内广播 scale、pair write 和 tail 处理。实验对象选了两个典型层:model.layers.0.mlp.down_proj.weight 和 model.layers.0.self_attn.q_proj.weight。这样可以分别观察大一点的 MLP 投影和更接近 decode 场景的 attention 投影。
结果很一致。对 down_proj,优化后单层 restore+decode 从 0.2600 ms 降到 0.2424 ms,decode only 从 0.2407 ms 降到 0.2120 ms。但即便如此,显式 restore 后再 linear 的总成本仍明显高于默认 bnb 路径。batch 1 时,bnb 是 0.0314 ms,自定义路径是 0.3227 ms;batch 8 时,bnb 是 0.3399 ms,自定义路径是 0.3591 ms。对 q_proj,优化效果更明显:restore+decode 从 0.1087 ms 降到 0.0746 ms,decode only 从 0.0749 ms 降到 0.0415 ms。但总路径上,bnb 仍更快。batch 1 时,bnb 是 0.0283 ms,自定义路径是 0.0596 ms;batch 8 时,bnb 是 0.0612 ms,自定义路径是 0.0686 ms。
这说明两件事同时成立。第一,NF4 restore kernel 本身确实可以通过那类优化做快,尤其在 restore 这一单独步骤上收益是存在的。第二,真正拖慢“显式反量化路径”的主因不是 LUT 访问或 double-quant scale 恢复,而是把整块 dense bf16 权重显式写回显存,然后再被 GEMM 重新读一遍。这个中间写回成本在 decode-like 小 batch 场景下尤其难以摊薄。比如优化后的 q_proj,batch 2/4/8 时,显式写回开销仍稳定在大约 0.041 ms;down_proj 上则在 0.17-0.21 ms 量级。这部分几乎就是“先恢复整层再算”这条路径的结构性成本。
因此,对“显式反量化的中间写回成本及其对端到端推理时延的影响”的结论是明确的:在 decode-like 小 batch 场景中,这部分成本不可忽略,而且足以抵消 restore kernel 的局部优化收益。默认 bitsandbytes 路径之所以占优,不仅因为它的 NF4 decode 做得成熟,更关键的是它没有把权重恢复成整块 dense matrix 再回写,而是直接消费 packed weight 和 QuantState 完成计算。换句话说,当前这类“显式 restore 到 dense 再算”的实验路径,适合作为 MoE restore 步骤或学术性对照,但不适合作为 dense BNB 路径的端到端替代方案。若后续继续推进,真正有潜力的方向应该是“直接消费 packed weight 的 fused decode+matmul”,而不是进一步压榨 restore-to-dense 这一步。
我是怎么做的
- 在服务器上确认模型和 vLLM 环境可用,启动两卡
PP=2的 vLLM 服务,并通过/v1/models和/v1/chat/completions验证模型可加载、可返回结果。 - 读取 vLLM 安装目录中的
bitsandbytes_loader.py和layers/quantization/bitsandbytes.py,定位 pre-quantized NF4 checkpoint 的加载路径、QuantState的恢复位置,以及 dense 与 MoE 两条不同计算路径。 - 编写 bench_vllm_qwen.py,在服务侧做 20 个串行流式请求 benchmark,统计 TTFT、completion throughput 和 prompt 长度变化趋势。
- 编写 fs_plugins/custom_ops/nf4_ikko.cpp、fs_plugins/custom_ops/nf4_ikko.cu、fs_plugins/custom_ops/nf4_ikko.py,实现实验性 NF4 restore 扩展。
- 编写 benchmark_nf4_ikko.py,直接从 safetensors checkpoint 读取 packed 4-bit 权重和量化元数据,构造两组对照:
- 默认
bitsandbytes.matmul_4bit - 自定义
restore -> dense bf16 -> F.linear
- 默认
- 对
down_proj和q_proj两个代表层做单层 restore 耗时、显式写回开销和 decode-like 小 batch 对照。 - 再将在 mainla.cu 中的关键优化迁移到 restore kernel,重跑实验,观察优化前后差异。
- 汇总全部结果,形成 vllm_bnb_benchmark_notes.md 和 outputs/reports/nf4_ikko_experiments.md。
- Title: qwen部署
- Author: Ikko
- Created at : 2026-03-29 17:23:18
- Updated at : 2026-03-30 17:17:48
- Link: http://ikko-debug.github.io/2026/03/29/qwen/
- License: This work is licensed under CC BY-NC-SA 4.0.