☰
fuse_for_vllm.py 源码精读:gpt-oss-20b-BF16-w8a8-llmcompressor 如何重写 MoE 专家权重布局以无缝适配 vLLM 加载器
2026/11/3 19:14:27 网站建设 项目流程

fuse_for_vllm.py 源码精读:gpt-oss-20b-BF16-w8a8-llmcompressor 如何重写 MoE 专家权重布局以无缝适配 vLLM 加载器

【免费下载链接】gpt-oss-20b-BF16-w8a8-llmcompressor项目地址: https://ai.gitcode.com/hf_mirrors/amd/gpt-oss-20b-BF16-w8a8-llmcompressor

gpt-oss-20b-BF16-w8a8-llmcompressor 是 AMD 基于 LLM Compressor 产出的 W8A8 量化版本,磁盘体积从 39.0 GiB 压到 20.6 GiB。它的 MoE 专家权重布局无法被 vLLM 直接加载,仓库中的 fuse_for_vllm.py 就是来解决这件事的:把逐专家存储的专家张量重写(拼接、转置、重新分片)成 vLLM 期望的融合布局,无需修改任何模型文件。

模型速览:为什么专家权重是大头

项目数值
基座模型gpt-oss-20b(BF16,39.0 GiB)
量化方案W8A8:INT8 权重 + per-token 动态 INT8 激活,对称 per-channel 缩放
量化后体积约 20.6 GiB(-47%)
MoE 结构24 层 × 32 专家,每 token 选 top-4 专家(experts_per_token: 4)
推理目标AMD EPYC CPU,vLLM 0.26.0

从 config.json 可以看到num_hidden_layers: 24、num_local_experts: 32。量化配置见 config.json 与 recipe.yaml:只量化Linear层,MoE 路由器、lm_head、embed_tokens保持 BF16。

问题出在布局上。gpt-oss 原生的专家是一个融合的 3D 张量,量化时必须先用 shim 模块拆成逐专家的独立nn.Linear(见 README.md 的说明),量化后检查点里每个专家存成gate_proj/up_proj/down_proj三组独立键。但 vLLM 的 gpt-oss 加载路径要求:gate 与 up 合并为一个投影(内部叫 w13),且读取后要做一次固定的"截取 + 转置"——所以存储侧必须提前把转置后的结果存好,两边组合起来才恰好是加载器期望的方向(源码注释 fuse_for_vllm.py)。

💡 仓库里同时保留了两组 safetensors:model-*-of-00005是量化产出的原始布局,model-*-of-00006是融合后的产物,可以直接对照键名差异。

转换流程总览:一条命令四步走

运行方式(见文件头注释 fuse_for_vllm.py):

python fuse_for_vllm.py SRC_DIR DST_DIR
步骤动作代码位置
1️⃣ 键分类读 model.safetensors.index.json,把 5019 个张量分成"专家键"与"普通键"fuse_for_vllm.py
2️⃣ 逐专家融合gate+up 按行拼接后转置,每专家产出 6 个融合张量fuse_for_vllm.py
3️⃣ 增量分片缓冲到约 4 GiB 即落盘,最后统一改名并重建索引fuse_for_vllm.py
4️⃣ 文件搬运非权重文件(config、tokenizer 等)原样复制到目标目录fuse_for_vllm.py

第 1 步:用一条正则识别 MoE 专家权重键

整个脚本的"路由"靠一条正则完成(fuse_for_vllm.py):

_EXPERT_KEY = re.compile( r"^(?P<prefix>.*\.mlp\.experts)\.(?P<expert>\d+)\." r"(?P<proj>gate_proj|up_proj|down_proj)\." r"(?P<kind>weight|weight_scale|bias)$")

四个命名组把键拆解为:层前缀(prefix)、专家编号(expert)、投影名(proj)、张量类型(kind)。匹配不上的键(注意力投影、LayerNorm、24 个 attention sinks 等 411 个张量)走"直通"通道原样复制。若某个键含mlp.experts.却又匹配不上,脚本会直接报错,避免静默丢权重(fuse_for_vllm.py)。

第 2 步:gate/up 融合与转置——每个专家的 6 个键

以本仓库的 W8A8 格式为例,每个专家从 9 个键变成 6 个:

原始键(逐专家)融合后键变换
gate_proj.weight+up_proj.weightgate_up_proj.weight沿第 0 维拼接 → 转置
gate_proj.weight_scale+up_proj.weight_scalegate_up_proj.weight_scale拼接 → 转置
down_proj.weightdown_proj.weight转置
down_proj.weight_scaledown_proj.weight_scale转置
gate_proj.bias+up_proj.biasgate_up_proj.bias拼接(不转置)
down_proj.biasdown_proj.bias原样

核心代码就一行(fuse_for_vllm.py):

torch.cat([gate_w, up_w], 0).t().contiguous()

为什么要转置?vLLM 加载器读到的张量会被再转置一次,预存转置结果才能让最终方向正确——这是"无缝适配"的关键一步。

⚠️W4A16 例外:两种量化方案的参数轴向顺序相反——INT8 的 w13 逻辑上是[2I, K],packed INT4 的 w13 是[K/8, 2I]。因此 W4A16 分支直接"按拼接原样存储",不转置(fuse_for_vllm.py、fuse_for_vllm.py)。此外 W8A8 的gate_up_proj.weight靠 vLLM 的hf_to_vllm_mapper映射到w13_weight,而 W4A16 因无对应映射规则,直接以w13_weight_packed命名,未匹配的键会原样穿透映射器(fuse_for_vllm.py)。

第 3 步:4 GiB 增量分片与索引重建

  • 懒加载读取:_Source 按需打开 safetensors 分片句柄并缓存,不会把整个检查点读进内存。
  • 缓冲写出:_ShardWriter 累计到约 4 GiB(可用--shard-size-gib调整)就先落盘为part-00001.safetensors;finalize时统一改名为model-00001-of-00006.safetensors并生成weight_map。
  • 一个贴心的细节:save_file新建文件权限是 0600,放在 NFS 上其他用户会读不了,所以脚本显式chmod 0o644(fuse_for_vllm.py)。
  • 重建索引:重写 model.safetensors.index.json,写入total_size(本仓库约 20.6 GiB)与排序后的weight_map(fuse_for_vllm.py)。

使用前的三个限制,先知道再动手

  1. 仅支持 TP=1:更高的张量并行度下,down 投影的 per-channel scale 无法正确传到非零 rank(fuse_for_vllm.py)。
  2. 融合布局不属于 compressed-tensors 惯例:所以源检查点仍是对外发布的正式产物,融合版只是 vLLM 专用的派生形态(fuse_for_vllm.py)。
  3. W4A16 还需 vLLM 侧配合:必须把w13_weight_packed/w2_weight_packed加入 vLLMgpt_oss.py的_GPT_OSS_STREAMED_EXPERT_SUFFIX_TO_SHARD(精确匹配,检查点侧无绕法);W8A8 则不需要(fuse_for_vllm.py)。

总结与参考文件

一句话总结:fuse_for_vllm.py用"正则分类 → 拼接转置 → 增量分片 → 重建索引"四步,把 W8A8/W4A16 量化检查点的 4608 个 MoE 专家张量重排成 vLLM 可直读的融合布局,全程流式处理、不改模型文件。

  • 核心脚本:fuse_for_vllm.py
  • 融合后检查点索引:model.safetensors.index.json
  • 模型架构与量化配置:config.json
  • 量化配方:recipe.yaml
  • 模型卡与量化流程说明:README.md
  • 许可证:LICENSE

如需完整运行,先获取包含全部权重文件的仓库副本:

git clone https://gitcode.com/hf_mirrors/amd/gpt-oss-20b-BF16-w8a8-llmcompressor

【免费下载链接】gpt-oss-20b-BF16-w8a8-llmcompressor项目地址: https://ai.gitcode.com/hf_mirrors/amd/gpt-oss-20b-BF16-w8a8-llmcompressor

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询