Prhub

#36917 [Diffusion] Reject incompatible transformer fallback

原始 PR 作者 mickqian 合并时间 2026-08-30 16:33 文件变更 6 提交数 5 评论 1 代码增减 +128 / -0

执行摘要

拒绝分布式执行请求下的原生 Diffusers transformer 回退

PR body 明确说明动机:"reject native Diffusers fallback when a transformer component requires TP, sequence parallelism, Ulysses, Ring, or exact-component FSDP"。此前 ComponentLoader.load() 的模板方法在定制加载失败后会静默回退到 Diffusers/transformers 原生实现,但原生实现的 transformer 无法兑现分布式执行契约(TP/SP/Ulysses/Ring/FSDP),不兼容的配置会在推理阶段才暴露错误。本 PR 决定把问题提前到加载期暴露,并给出明确的修正路径;同时 FSDP 需要按 loader 区分准入——native DiT 与 MOVA bridge 构造分片参数,保留 FSDP 请求是合法的,其他 loader 复制加载自己的模块则必须撤销 FSDP 请求。

值得精读。核心价值不在代码量,而在「准入控制优于静默降级」的设计取舍:用模板方法 + hook 把契约校验注入所有组件 loader,避免了逐个模型特判;报错信息刻意列出全部冲突项并给出两条修正路径,属于良好的用户引导实践。关注 ComponentLoader 基类的两个 hook 与 TransformerLoader 的具体实现,可作为后续组件加载准入逻辑的参考范式。

讨论亮点

本 PR 没有 review 评论线程,唯一的讨论来自作者 mickqian 对 CI 失败的处置说明:NVIDIA multimodal shards 在依赖安装阶段(scripts/ci/cuda/ci_install_dependency.sh 导入 deep_ep)发生 Bus error (core dumped),未启动任何 diffusion 测试。作者判定这是不稳定的 runner 环境问题,与本次变更无源码级关联(PR 在依赖安装前没有执行路径),因此不重跑同一失败。

实现拆解

变更入口在 python/sglang/multimodal_gen/runtime/loader/component_loaders/component_loader.py,通过模板方法 + hook 的方式推广到所有组件 loader。

  1. 基类契约扩展:新增 supports_fsdp_inference = False 类属性,以及两个 hook——validate_native_fallback(server_args, component_name)(默认空实现)和 disable_unsupported_component_fsdp(server_args, component_name)(当 loader 不支持 FSDP 且 server_args.should_use_fsdp_for_component() 返回 True 时,调用 server_args.disable_fsdp_for_component() 撤销请求)。
  2. 模板方法接入调用点:在 load() 中两处插入——方法开头先调用 disable_unsupported_component_fsdp,确保复制加载的组件不会响应分片请求;在 should_raise_customized_load_error() 检查通过、真正执行 native fallback 之前调用 validate_native_fallback,使「先撤销不支持的 FSDP,再校验 fallback 契约」成为所有组件 loader 的通用流程。
  3. TransformerLoader 实现准入校验:在 transformer_loader.py 中收集 tp_sizesp_degreeulysses_degreering_degree 大于 1 的项以及组件 FSDP 请求,任一命中即抛 RuntimeError,报错信息列出全部冲突项并指引用户改用 SGLang-native transformer 实现或关闭分布式配置;同时将 supports_fsdp_inference 置为 True。
  4. BridgeLoader 声明 FSDP 支持:MOVA dual tower bridge 加载时构造分片参数,把 supports_fsdp_inference 置为 True,避免被基类的撤销逻辑误伤。
  5. 测试配套:新增 test_transformer_loader_fallback.pyTestTransformerLoaderFallbackAdmissionSimpleNamespace 伪造 server args 覆盖三类场景(分布式配置被拒绝、复制执行放行、仅 FSDP 物化器保留请求);test_vae_loader.pytest_image_encoder_loader.py 给 fixture 补充 should_use_fsdp_for_component 假实现以适配基类新调用。
文件 模块 状态 重要度
python/sglang/multimodal_gen/runtime/loader/component_loaders/component_loader.py 组件加载器 modified 7.01
python/sglang/multimodal_gen/runtime/loader/component_loaders/transformer_loader.py 组件加载器 modified 6.93
python/sglang/multimodal_gen/runtime/loader/component_loaders/bridge_loader.py 组件加载器 modified 4.35
python/sglang/multimodal_gen/test/unit/test_transformer_loader_fallback.py 加载器测试 added 7.01
python/sglang/multimodal_gen/test/unit/test_vae_loader.py 加载器测试 modified 3.74
python/sglang/multimodal_gen/test/unit/test_image_encoder_loader.py 加载器测试 modified 3.28

关键符号

ComponentLoader.validate_native_fallback ComponentLoader.disable_unsupported_component_fsdp ComponentLoader.load TransformerLoader.validate_native_fallback

关键源码片段

python/sglang/multimodal_gen/runtime/loader/component_loaders/component_loader.py core-logic

契约机制的核心:新增 `supports_fsdp_inference` 类属性、`validate_native_fallback` 与 `disable_unsupported_component_fsdp` 两个 hook,并在 `load()` 模板方法中接入调用点,让所有组件 loader 统一执行 FSDP 撤销与 fallback 校验。

class ComponentLoader(ABC):
    """组件加载基类:约定组件的加载优先级与 fallback 规则。"""
​
    # 该 loader 是否支持 FSDP 推理;只有构造分片参数的 loader 才置为 True,
    # 例如 DiT 的 TransformerLoader、MOVA 的 BridgeLoader
    supports_fsdp_inference = False
​
    def validate_native_fallback(
        self, _server_args: ServerArgs, _component_name: str
    ) -> None:
        """校验 native fallback 是否满足组件的运行时契约。        默认不施加限制;需要拒绝特定执行配置的 loader 覆盖此方法,
        例如 TransformerLoader 会拒绝分布式执行下的 native fallback。
        """
        pass
​
    def disable_unsupported_component_fsdp(
        self, server_args: ServerArgs, component_name: str
    ) -> None:
        """loader 不支持 FSDP 时,撤销 server_args 上对该组件的 FSDP 请求。"""
        if (
            not self.supports_fsdp_inference
            and server_args.should_use_fsdp_for_component(component_name)
        ):
            server_args.disable_fsdp_for_component(component_name)
​
    def load(
        self,
        component_model_path: str,
        server_args: ServerArgs,
        component_name: str,
        transformers_or_diffusers: str,
    ):
        """模板方法:先撤销不支持的 FSDP 请求,定制加载失败后校验 fallback 契约。"""
        self._native_load_manages_placement = False
        # 加载前撤销 FSDP:复制加载的组件不应响应分片请求
        self.disable_unsupported_component_fsdp(server_args, component_name)
        # ... 先尝试定制加载 ...
        except Exception as e:
            # ... 判断是否允许抛错、是否需要 native loader ...
            # 真正降级前校验契约,不满足直接抛错而非静默带病运行
            self.validate_native_fallback(server_args, component_name)
            # ... 然后才执行 native fallback 加载与告警日志 ...
python/sglang/multimodal_gen/runtime/loader/component_loaders/transformer_loader.py core-logic

实现 TransformerLoader 的准入校验:收集 TP/SP/Ulysses/Ring/FSDP 请求并抛 RuntimeError,是本 PR 行为变更的直接落点;同时声明 `supports_fsdp_inference = True`。

class TransformerLoader(ComponentLoader):
    """(视频/音频) DiT transformer 的共享 loader。"""
​
    # DiT 加载时构造分片参数,因此保留组件的 FSDP 请求
    supports_fsdp_inference = True
​
    def validate_native_fallback(
        self, server_args: ServerArgs, component_name: str
    ) -> None:
        """原生 Diffusers fallback 无法兑现分布式执行,收集全部请求并拒绝。"""
        requested_distributed_execution = []
        # TP / SP / Ulysses / Ring 任一大于 1,或组件请求 FSDP,都视为分布式执行
        if server_args.tp_size is not None and server_args.tp_size > 1:
            requested_distributed_execution.append(f"tp_size={server_args.tp_size}")
        if server_args.sp_degree is not None and server_args.sp_degree > 1:
            requested_distributed_execution.append(f"sp_degree={server_args.sp_degree}")
        if server_args.ulysses_degree is not None and server_args.ulysses_degree > 1:
            requested_distributed_execution.append(
                f"ulysses_degree={server_args.ulysses_degree}"
            )
        if server_args.ring_degree is not None and server_args.ring_degree > 1:
            requested_distributed_execution.append(
                f"ring_degree={server_args.ring_degree}"
            )
        if server_args.should_use_fsdp_for_component(component_name):
            requested_distributed_execution.append("FSDP")
        if requested_distributed_execution:
            # 报错信息列出全部冲突项,并给出两条修正路径
            raise RuntimeError(
                f"Native Diffusers fallback for transformer component "
                f"{component_name!r} cannot honor requested distributed execution: "
                f"{', '.join(requested_distributed_execution)}. Use an SGLang-native "
                "transformer implementation or set tp_size, sp_degree, "
                "ulysses_degree, and ring_degree to 1 without FSDP."
            )

评论区精华

CI 失败由不稳定 runner 导致,与 PR 无关 other

mickqian 在 issue 评论中说明:NVIDIA multimodal shards 未启动任何 diffusion 测试,在 scripts/ci/cuda/ci_install_dependency.sh 导入 deep_ep 时发生 Bus error (core dumped),例如 job 99069546065。该 PR 只改变 native fallback 准入,在依赖安装前没有执行路径,因此没有源码级失败需要修复。

结论:判定为不稳定 runner 环境失败,与本次变更无源码级关联,不重跑同一失败。 · 已解决

风险与影响

  • 行为变更(有意为之):分布式配置下的 transformer 原生回退从「静默降级」变为「启动报错」。已有依赖该回退的部署会直接失败,但报错信息给出了修正路径,属于可控的破坏性变更。
  • 契约依赖:新逻辑依赖 ServerArgs 上的 should_use_fsdp_for_component / disable_fsdp_for_component 方法。测试中所有用 SimpleNamespace 或假对象伪造 server args 的地方都必须补齐这两个方法,否则加载路径会 AttributeError;本 PR 已修复两处已知 fixture,但不排除其他测试或嵌入场景遗漏。
  • 覆盖盲区:目前只有单元测试,没有真实多 GPU 集成测试验证报错与引导流程;且基类默认 validate_native_fallback 是空实现,VAE、text encoder 等组件若存在类似的分布式契约问题,本次并未覆盖。
  • 兼容性:单卡与复制执行路径完全不变,load() 的返回结构与日志格式不变,对主流单卡 diffusion 推理无影响。
  • 用户/部署影响:多 GPU diffusion 部署(TP/SP/Ulysses/Ring/FSDP)中,若 transformer 组件没有 SGLang-native 实现,现在会在启动期直接报错并给出明确的修正指引,而不是带病运行到推理阶段。单卡与复制执行用户完全无感知。
  • 系统影响:仅在加载期增加一次校验与一次可能的状态撤销,无运行时性能开销。
  • 团队影响:确立了组件 loader 的新契约约定——新增 loader 必须声明 supports_fsdp_inference,并视需求覆盖 validate_native_fallback;后续 diffusion 组件加载的准入逻辑有了统一的扩展点。
分布式场景行为变更(静默回退变启动报错) 缺少多 GPU 集成测试 依赖 ServerArgs FSDP 新契约方法

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论