执行摘要
- 一句话:新增 --warmup-num-frames,对齐视频 BCG 预热与 serving 帧数
- 推荐动作:值得短读。重点关注三处设计决策:
_resolve_warmup_num_frames 中显式覆写与 MagicMock 兼容的写法;_adjust_warmup 将帧数纳入“显式形状”推断的联动逻辑;build_sglang_cmd 中 preset 参数到服务参数的透传模式。这些模式对后续增加更多 warmup 形状配置有参考价值。
功能与动机
PR body 明确指出问题根因:Breakable CUDA graphs replay only exact latent shapes。SANA-Video 模型默认 81 帧,而入库的 benchmark preset 请求 17 帧,因此 warmup 捕获了 (1, 16, 21, 60, 104),serving 请求却是 (1, 16, 5, 60, 104),BCG 日志出现 serving-signature miss 并回退 eager 执行,性能收益完全丢失。修复方式是提供显式帧数覆写,使 warmup 与 serving 使用完全相同的帧数。
实现拆解
- 配置入口(
server_args.py):在 ServerArgs 中新增 warmup_num_frames: int | None = None 字段,并在 add_cli_args 注册 --warmup-num-frames 参数。_adjust_warmup 增加正数校验(<= 0 抛 ValueError),并把“显式 warmup 形状”的判定从仅 warmup_resolutions 扩展为分辨率或帧数任一非空,从而在 warmup_mode 为 off 时自动提升为 request 模式。
- 预热请求构建(
warmup_request_builder.py):_resolve_warmup_num_frames 优先读取 server_args.warmup_num_frames,且只接受具体 int 实例(规避 MagicMock 缺失属性被误判为配置);随后仍走既有分支——BCG 或非 server warmup 使用完整帧数,普通 server warmup 按 SERVER_WARMUP_MAX_VIDEO_FRAMES 帧预算封顶——最后统一经过 pipeline_config.adjust_num_frames 做模型专属时序对齐。
- 基准脚本透传(
bench_diffusion_denoise.py):build_sglang_cmd 在用户未显式传 --warmup-num-frames 且 preset 带 num-frames 时自动追加该参数,保证 BCG 基准跑出的 warmup 与 serving 帧数一致。
- 测试与文档配套:
test_server_args.py 新增 test_num_frames_forces_warmup_on 与 test_num_frames_must_be_positive;test_cfg_parallel_warmup.py 新增 test_breakable_cuda_graph_uses_explicit_warmup_num_frames(验证显式 17 覆盖模型默认 81,且 adjust_num_frames 只调用一次);test_diffusion_benchmark_skill.py 断言 sana-video BCG 命令包含 --warmup-num-frames 17;两份 benchmark 技能文档同步更新。
关键文件:
python/sglang/multimodal_gen/runtime/server_args/server_args.py(模块 服务参数;类别 source;类型 core-logic;符号 ServerArgs, warmup_num_frames, _adjust_warmup, add_cli_args): 配置入口:新增 warmup_num_frames 字段、CLI 参数与正数校验,并让显式帧数与 warmup_resolutions 一样能自动开启 request 模式 warmup。
python/sglang/multimodal_gen/runtime/warmup_request_builder.py(模块 启动预热;类别 source;类型 core-logic;符号 _resolve_warmup_num_frames): 核心逻辑:_resolve_warmup_num_frames 支持显式帧数覆写,仍经 adjust_num_frames 保持模型时序对齐;只接受具体 int 以避免 MagicMock 误判。
python/sglang/multimodal_gen/test/unit/test_server_args.py(模块 参数测试;类别 test;类型 test-coverage;符号 test_num_frames_forces_warmup_on, test_num_frames_must_be_positive): 新增两个单测,覆盖“帧数强制开启 warmup”和“非正数报错”两条新行为。
python/sglang/multimodal_gen/test/unit/test_cfg_parallel_warmup.py(模块 预热测试;类别 test;类型 test-coverage;符号 test_breakable_cuda_graph_uses_explicit_warmup_num_frames): 验证 BCG 场景下显式 warmup_num_frames=17 覆盖模型默认 81 帧,并只调用一次 adjust_num_frames(17)。
python/sglang/multimodal_gen/.claude/skills/sglang-diffusion-benchmark-profile/scripts/bench_diffusion_denoise.py(模块 基准脚本;类别 source;类型 core-logic;符号 build_sglang_cmd): 基准脚本在 BCG 模式下自动把 preset 的 num-frames 透传为 --warmup-num-frames,避免人工遗漏导致 warmup 与 serving 帧数不一致。
python/sglang/multimodal_gen/test/unit/test_diffusion_benchmark_skill.py(模块 基准测试;类别 test;类型 test-coverage;符号 test_quality_and_bcg_comparators_are_explicit_and_exclusive): 为 sana-video BCG 命令断言 --warmup-num-frames 17 已正确注入。
python/sglang/multimodal_gen/.claude/skills/sglang-diffusion-benchmark-profile/benchmark-and-profile.md(模块 基准文档;类别 docs;类型 documentation): 基准与性能分析文档同步更新,说明 BCG 模式下 warmup 帧数会自动沿用视频 preset。
python/sglang/multimodal_gen/.claude/skills/sglang-diffusion-benchmark-profile/SKILL.md(模块 技能文档;类别 docs;类型 documentation): Claude 技能文档同步更新,避免技能使用者按旧命令手动指定帧数。
关键符号:_resolve_warmup_num_frames, _adjust_warmup, add_cli_args, build_sglang_cmd
关键源码片段
python/sglang/multimodal_gen/runtime/server_args/server_args.py
配置入口:新增 warmup_num_frames 字段、CLI 参数与正数校验,并让显式帧数与 warmup_resolutions 一样能自动开启 request 模式 warmup。
server_args.py:帧数校验与 warmup mode 推断
def _adjust_warmup(self):
# 校验 canonical warmup mode 取值。
if self.warmup_mode is not None and self.warmup_mode not in WARMUP_MODES:
raise ValueError(
f'Invalid --warmup-mode {self.warmup_mode!r}; '
f'expected one of {WARMUP_MODES}.'
)
# 新配置项:帧数必须是正整数,否则直接拒绝启动。
if self.warmup_num_frames is not None and self.warmup_num_frames <= 0:
raise ValueError('--warmup-num-frames must be a positive integer.')
# torch.compile 首次请求会付编译延迟,未显式指定时自动开启
# server warmup,让第一个真实请求不被打断。
if self.enable_torch_compile and self.warmup_mode is None:
self.warmup_mode = 'server'
logger.info(
'Automatically enabled server warmup for torch.compile so first '
'real requests do not pay compile latency. Set --warmup-mode off '
'to disable this behavior.'
)
# 显式 warmup 形状(分辨率或帧数)需要一个请求路径,除非已有
# server 默认的合成启动请求;否则在 off 时提升为 request 模式。
if (
self.warmup_resolutions is not None or self.warmup_num_frames is not None
) and self.warmup_mode in (None, 'off'):
self.warmup_mode = 'request'
# 后续 BCG 强制 server warmup、disagg 角色互斥等逻辑保持不变,
# 本 PR 只扩展了“显式形状”的判定条件。
python/sglang/multimodal_gen/runtime/warmup_request_builder.py
核心逻辑:_resolve_warmup_num_frames 支持显式帧数覆写,仍经 adjust_num_frames 保持模型时序对齐;只接受具体 int 以避免 MagicMock 误判。
warmup_request_builder.py:显式帧数如何进入 warmup 请求
def _resolve_warmup_num_frames(
server_args: ServerArgs,
sampling_defaults: SamplingParams,
*,
server_based_warmup: bool,
) -> int:
# 先取模型默认帧数;非视频任务直接返回,不进入 warmup 特殊逻辑。
default_num_frames = getattr(sampling_defaults, 'num_frames', 1)
if not _is_video_warmup_task(server_args):
return default_num_frames
# 显式覆写只接受具体整数:测试或轻量集成常使用 MagicMock
# 构造 server args,缺失属性会解析成另一个 mock,不能当作配置值。
explicit_num_frames = getattr(server_args, 'warmup_num_frames', None)
num_frames = (
explicit_num_frames
if isinstance(explicit_num_frames, int)
else default_num_frames
)
if num_frames is None:
return num_frames
# BCG 只重放完全一致的 latent shape:warmup 请求必须携带 serving
# 的真实帧数,capture 出的图才能命中 serving 签名(与
# _resolve_warmup_steps 不封顶步数的规则同理)。
if (
not server_based_warmup
or getattr(server_args, 'enable_breakable_cuda_graph', False) is True
):
warmup_num_frames = num_frames
else:
# 普通 server warmup 按帧预算封顶,例如多卡 LTX 两阶段
# 会把一秒请求对齐到 25 帧,只需覆盖其 latent shape。
frame_budget = (
SERVER_WARMUP_LTX2_TWO_STAGE_MAX_VIDEO_FRAMES
if is_ltx2_two_stage_pipeline_name(server_args.pipeline_class_name)
and server_args.num_gpus > 1
else SERVER_WARMUP_MAX_VIDEO_FRAMES
)
warmup_num_frames = min(num_frames, frame_budget)
# 最后交给 pipeline 做模型专属时间维对齐(像素帧到 latent 帧换算)。
return server_args.pipeline_config.adjust_num_frames(warmup_num_frames)
评论区精华
本 PR 没有公开 review 评论线程(review_comments_count = 0),设计取舍主要体现在代码注释中:一是显式覆写只接受具体 int,避免 MagicMock 缺失属性被当作配置,这是面向测试友好的兼容设计;二是帧数覆写仍经过各 pipeline 的 adjust_num_frames,保证模型专属的时间维对齐不被破坏;三是 quality=high + BCG 仍是 SANA-Video 不支持组合,由既有运行时 guard 拒绝,本 PR 不改变该边界。
风险与影响
- 风险:
- 显存峰值上升:RTX PRO 6000 验证中 reserved memory 从 20,470 MB 升至 21,540 MB(约 +5.2%),warmup 使用与 serving 一致的 latent shape 后显存占用可能变化,显存紧张环境需实测确认。
- 平台验证缺口:AMD ROCm 7.2 CI 失败(Run #33051917814),大概率与本改动无关(未触碰 ROCm 路径),但该平台尚未得到绿验证。
- 静默回退风险:
_resolve_warmup_num_frames 只认 Python int 作为显式覆写;若未来配置源传入其他数值类型(如 numpy 标量),覆写会被静默忽略并回退模型默认,可能再次产生签名 miss。
- 行为兼容性:未设置新参数时行为与之前一致;普通 server warmup 仍受
SERVER_WARMUP_MAX_VIDEO_FRAMES 帧预算封顶,显式传大帧数时需确认该封顶逻辑符合预期。
- 影响:影响范围集中于 multimodal_gen 视频生成 warmup 路径:用户侧,SANA-Video 等视频模型在 BCG 模式下可手动指定 warmup 帧数,规避 eager 回退;系统侧,server args 校验与 warmup 请求构建新增一个可选配置,未设置时保持模型默认行为,向后兼容;团队侧,diffusion benchmark 技能自动透传帧数,减少人工遗漏,文档同步更新。整体影响程度中等,不涉及核心推理算子或跨模块重构。
- 风险标记:BCG warmup 显存峰值上升约 5%, AMD ROCm CI 未通过待确认, 显式覆写仅认 int,其他数值类型会静默回退, 普通 server warmup 仍受帧预算封顶
关联脉络
- PR #36553 [diffusion] Accept mesh benchmark artifacts: 与本 PR 改动同一批文件(
bench_diffusion_denoise.py、test_diffusion_benchmark_skill.py 及 benchmark 技能文档),共同演进 diffusion 基准工具链。
- PR #36571 [diffusion] Fuse Cosmos3 Nano T2I attention on Hopper: 同为 diffusion 视频模型在 Hopper 上的 BCG/图融合加速方向,验证 BCG 捕获与 serving 签名对齐的重要性。
- PR #36592 [Diffusion][Kernel] Fuse Wan FFN GELU epilogue: 同为 diffusion 性能优化系列(BCG/内核融合),体现该方向持续追求降低 denoise 延迟。
参与讨论