执行摘要
- 一句话:新增索引式组件权重集解析,重构 transformer 覆盖加载
- 推荐动作:值得精读。重点看
weights/source.py 中 index 权威解析与错误类型区分的设计,以及 transformer_load_utils.py 如何从自维护下载逻辑收敛到共享解析器;这套解析器可视为给其他组件加权重覆盖的现成模板。
功能与动机
PR body 将其定位为“shared checkpoint infrastructure for pipeline-declared components”:需要一个模型无关的组件权重集解析器,统一处理本地路径、HF repo、子文件夹、精确文件和标准 safetensors indexes,并“treat the index as shard authority,reject ambiguous unindexed variants”,同时把权重与相邻量化元数据固定到同一不可变 Hub revision,避免加载到混搭的不同 checkpoint 版本。历史 PR #22360 曾因重复加载 transformer safetensors 变体引入防御测试,本 PR 正是从解析层根治该问题。
实现拆解
-
权重源层新增索引解析(python/sglang/multimodal_gen/runtime/weights/source.py,+236/-13):新增 _SAFETENSORS_INDEX_SUFFIX 与 _WEIGHT_REFERENCE_SUFFIXES 常量,使 .safetensors.index.json 也能作为显式权重引用;新增 ResolvedWeightSet(选中文件元组 + 权威 index 文件名)与 NoSafetensorsWeightsError 异常;_local_index_inventory 只按 index 的 weight_map 收集本地分片;resolve_safetensors_weight_set / materialize_weight_set 及私有辅助 _read_safetensors_index、_resolve_index_shard、_materialize_inventory_file 完成索引解析与物化,无索引歧义目录抛 ValueError,无 safetensors 载荷抛专有异常。
-
transformer 覆盖加载收敛到共享解析器(python/sglang/multimodal_gen/runtime/loader/transformer_load_utils.py,+54/-101):删除 _HF_SAFETENSORS_URL_RE 正则以及直接调用 hf_hub_download、maybe_download_model、snapshot_download 的分支;resolve_transformer_safetensors_to_load 重构为 resolve_transformer_checkpoint_files,返回新增的 TransformerCheckpointFiles(safetensors 元组 + config_path),覆盖路径全部委托给 resolve_safetensors_weight_set,同时保留 _select_single_mixed_safetensors_file 作为既有 *-mixed.safetensors 单文件兼容路径。
-
加载器接入(python/sglang/multimodal_gen/runtime/loader/component_loaders/transformer_loader.py,+6/-2):load_customized 改用 resolve_transformer_checkpoint_files,并把 checkpoint_files.config_path 传入 TransformerQuantLoadSpec 的新字段 transformer_override_config_path;GGUF 分支保持原样(safetensors_list = [])。
-
测试配套:test_weight_source.py 新增 8 个用例,覆盖 index 只选声明 shard、精确 index 解析相邻 shard、拒绝无索引变体、拒绝非权重 shard、缺失 shard 不算“无权重”、远端多 shard 固定单一 revision 等;test_transformer_quant.py 把 mock 目标从 transformer_load_utils.hf_hub_download 迁移到 weights.source.HfApi.model_info / hf_hub_download,并验证单文件覆盖、HF revision 固定与 mixed 兼容路径。
关键文件:
python/sglang/multimodal_gen/runtime/weights/source.py(模块 权重解析;类别 source;类型 core-logic;符号 ResolvedWeightSet, NoSafetensorsWeightsError, _local_index_inventory, materialize_weight): 新增 ResolvedWeightSet、NoSafetensorsWeightsError 与 resolve_safetensors_weight_set 等索引权重集解析核心,是本次变更的主实现。
python/sglang/multimodal_gen/runtime/loader/transformer_load_utils.py(模块 加载逻辑;类别 source;类型 refactor;符号 TransformerCheckpointFiles, resolve_transformer_safetensors_to_load, resolve_transformer_checkpoint_files, _select_single_mixed_safetensors_file): 将 transformer 权重覆盖从自维护的 HF 下载/正则分支迁移到共享解析器,新增 TransformerCheckpointFiles 返回结构,删除约 100 行重复逻辑。
python/sglang/multimodal_gen/runtime/loader/component_loaders/transformer_loader.py(模块 加载器;类别 source;类型 core-logic): 接入新解析结果,并把 transformer_override_config_path 传进量化 spec,是行为落地点。
python/sglang/multimodal_gen/test/unit/test_weight_source.py(模块 单元测试;类别 test;类型 test-coverage;符号 test_safetensors_index_selects_only_declared_shards, test_exact_local_safetensors_index_resolves_adjacent_shards, test_safetensors_weight_set_rejects_unindexed_variants, test_safetensors_index_rejects_non_weight_shard): 新增 8 个用例覆盖 index 解析、拒绝非权重 shard、无索引变体、远端单 revision 固定等核心行为。
python/sglang/multimodal_gen/test/unit/test_transformer_quant.py(模块 单元测试;类别 test;类型 test-coverage;符号 test_resolve_transformer_safetensors_to_load_uses_single_override_file, test_resolve_transformer_checkpoint_files_uses_single_override_file, test_resolve_transformer_safetensors_to_load_uses_hf_file_reference, test_resolve_transformer_checkpoint_files_uses_one_hf_revision): 测试随重构迁移 mock 位置,验证单文件覆盖、HF 单 revision 与 mixed 兼容路径。
关键符号:resolve_safetensors_weight_set, materialize_weight_set, materialize_weight_set_config, _local_index_inventory, _resolve_index_shard, _read_safetensors_index, resolve_transformer_checkpoint_files, _select_single_mixed_safetensors_file, materialize_weight
关键源码片段
python/sglang/multimodal_gen/runtime/weights/source.py
新增 ResolvedWeightSet、NoSafetensorsWeightsError 与 resolve_safetensors_weight_set 等索引权重集解析核心,是本次变更的主实现。
# python/sglang/multimodal_gen/runtime/weights/source.py
# 权重集解析核心:新增常量、数据结构和 index 解析辅助函数
_SAFETENSORS_INDEX_SUFFIX = ".safetensors.index.json"
_WEIGHT_REFERENCE_SUFFIXES = _WEIGHT_SUFFIXES + (_SAFETENSORS_INDEX_SUFFIX,)
@dataclass(frozen=True)
class ResolvedWeightSet:
"""一次解析得到的权重集:同一 checkpoint revision 下的一组文件。
与 ResolvedWeight 不同,它承载多个 safetensors 文件(分片),
并保留权威 index 文件名供日志与排障使用。
"""
inventory: WeightInventory
selected_files: tuple[str, ...]
index_file: str | None = None
class NoSafetensorsWeightsError(FileNotFoundError):
"""源中没有 safetensors 载荷可解析为权重集。
和普通 FileNotFoundError 区分开,让上层能识别
“没有权重”而不是“路径写错”。
"""
def _local_index_inventory(index_path: Path) -> tuple[str, ...]:
"""只列出精确的本地 index 及其声明、且物理存在的分片。
目录里可能还有别的 safetensors 变体(如 distilled/base),
但这里严格以 index 的 weight_map 为权威,避免歧义加载。
"""
with index_path.open(encoding="utf-8") as index_stream:
index = json.load(index_stream)
weight_map = index.get("weight_map") if isinstance(index, Mapping) else None
shard_names = weight_map.values() if isinstance(weight_map, Mapping) else ()
files = {index_path.name}
for shard_name in shard_names:
# 校验 shard 相对路径是否合法,避免目录穿越
if not isinstance(shard_name, str):
continue
shard_name = _validate_relative_hub_path(shard_name, "index shard")
shard_path = index_path.parent / shard_name
if shard_path.is_file():
files.add(shard_path.relative_to(index_path.parent).as_posix())
return tuple(sorted(files))
python/sglang/multimodal_gen/runtime/loader/transformer_load_utils.py
将 transformer 权重覆盖从自维护的 HF 下载/正则分支迁移到共享解析器,新增 TransformerCheckpointFiles 返回结构,删除约 100 行重复逻辑。
# python/sglang/multimodal_gen/runtime/loader/transformer_load_utils.py
# transformer 覆盖加载统一走共享权重集解析器
@dataclass(frozen=True)
class TransformerCheckpointFiles:
"""transformer 加载所需文件:safetensors 列表 + 相邻 config.json。"""
safetensors: tuple[str, ...]
config_path: str | None
def resolve_transformer_checkpoint_files(
server_args: ServerArgs, component_model_path: str
) -> TransformerCheckpointFiles:
"""从基础组件路径或量化覆盖路径解析 transformer 权重文件。
有覆盖时统一委托给 resolve_safetensors_weight_set,覆盖源可以
是本地目录、Hugging Face repo、子文件夹、精确文件或
safetensors index;解析出的 config.json 会作为配置路径带出。
无覆盖时回退到基础组件路径,并保留 *-mixed.safetensors
单文件兼容选择。
"""
quantized_path = server_args.transformer_weights_path
if quantized_path:
resolved = resolve_safetensors_weight_set(quantized_path)
safetensors = tuple(materialize_weight_set(resolved))
config_path = next(
(path for path in resolved.inventory.files
if path.endswith("config.json")),
None,
)
return TransformerCheckpointFiles(
safetensors=safetensors, config_path=config_path
)
# 基础组件路径:沿用原有探测逻辑,优先单一 mixed 导出
selected = _select_single_mixed_safetensors_file(component_model_path)
return TransformerCheckpointFiles(safetensors=selected, config_path=None)
评论区精华
PR 没有 review 评论,唯一讨论是作者 mickqian 在 issue 评论中的说明:重构把 checkpoint 物化移入通用 weight-source resolver 后,测试仍 patch 了已删除的私有导入 transformer_load_utils.maybe_download_model,导致 NVIDIA 单元测试失败。修复后,Nunchaku 测试保持聚焦量化 hook 解析,本地文件 resolver 测试验证既不调用 Hub 元数据也不调用下载 API,且没有新增任何运行时行为或兼容 shim。
- CI 失败:测试仍 patch 已删除的 maybe_download_model (testing): 测试改为 patch weights.source.HfApi.model_info 与 hf_hub_download,Nunchaku 测试保持专注 quant hook 解析,本地文件 resolver 测试验证不触发 Hub 元数据或下载 API。
风险与影响
- 风险:
- 行为变更:
resolve_safetensors_weight_set 会拒绝没有 index 的 safetensors 目录(报错信息含 “without an index”),原来依赖目录自动探测的用户配置可能报错。
- 下载逻辑集中化:transformer 覆盖中所有 HF URL 处理移入
weights/source.py,若存在未被 parse_weight_source 覆盖的 URL 形态,可能出现回归。
- 配置键调整:
TransformerQuantLoadSpec 新增 transformer_override_config_path 字段,需要确认所有构造点已同步更新。
- CI 信号:Extra 与 AMD ROCm 跑失败过,NVIDIA 修复后已重跑,仍提示跨平台回归风险。
- 兼容性保护:
*-mixed.safetensors 单文件路径与 GGUF 行为保持不变,风险总体可控。
- 影响:变更影响 sglang diffusion 运行时中 transformer 组件的权重覆盖加载路径,并为其建立共享基础设施。用户现在可以用 safetensors index 声明分片权重集,也可以继续使用单一 *-mixed.safetensors;GGUF 与基础组件加载不受影响。对团队而言,weights/source.py 成为各组件加载器的统一入口,后续新增组件权重覆盖可直接复用这套解析逻辑。
- 风险标记:无 index 权重目录将报错(行为变更), HF 下载逻辑集中迁移, CI Extra/AMD 曾失败, 量化覆盖配置键调整
关联脉络
- PR #36902 [Diffusion] Delegate recognized quantized components to Transformers: 同属 diffusion 组件加载与量化覆盖功能线,本 PR 将 transformer 覆盖解析交给共享 weight-source resolver,与组件委托加载形成配套。
- PR #36874 [Diffusion] Respect component weight overrides for upsamplers: 同一“组件权重覆盖”功能线,本 PR 为覆盖提供更通用的权重集解析基础。
- PR #36863 [Diffusion] Fix image encoder parallel folding proposal: 与 server_args/组件配置解析同区,可作为本次重构后的回归观察对象。
参与讨论