[diffusion] align video BCG warmup frame count (#36485)
This commit is contained in:
+4
-4
@@ -101,10 +101,10 @@ contains `[Diffusion BCG] captured` and contains no support-disable,
|
||||
capture-failure, serving-signature-miss, or late quality-fusion marker. In
|
||||
particular, a request-scoped DiT fusion mounted after lossless warmup capture
|
||||
would be bypassed by replay; reject that row even when capture and signature
|
||||
checks pass. `--warmup-resolutions` only declares width and height: a video
|
||||
request can still miss because its frame count differs from the model's
|
||||
synthetic warmup contract. Treat that as Eager fallback, not as a valid BCG
|
||||
measurement.
|
||||
checks pass. For video presets, the helper declares both the request resolution
|
||||
and `--warmup-num-frames` so the synthetic BCG warmup captures the requested
|
||||
temporal shape. Treat any remaining temporal or conditioning signature miss as
|
||||
Eager fallback, not as a valid BCG measurement.
|
||||
|
||||
A zero process exit is not sufficient evidence: every accepted row must also
|
||||
contain its requested perf dump and a generated image, video, or audio file.
|
||||
|
||||
+8
-9
@@ -144,7 +144,8 @@ Run one explicit quality or BCG comparator with `--quality lossless|high` and
|
||||
exclusive in this helper. A high+BCG command is only a compatibility probe:
|
||||
it is invalid if request-scoped DiT fusions mount after the lossless warmup
|
||||
graphs were captured. When a preset has explicit width and height, the helper
|
||||
declares that same `--warmup-resolutions` value automatically:
|
||||
declares that same `--warmup-resolutions` value automatically. Video presets
|
||||
with an explicit frame count also declare the matching `--warmup-num-frames`:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=python python3 "$BENCH_PY" \
|
||||
@@ -183,13 +184,11 @@ disable, capture failure, `serving signature MISSED`, a message that no graph
|
||||
will be captured, or a request-scoped high-quality DiT fusion mounted after
|
||||
capture. Do not average rejected rows with valid results.
|
||||
|
||||
BCG signatures include more than width and height. The public
|
||||
`--warmup-resolutions` flag declares only `WxH`; synthetic warmup still uses
|
||||
the model's own frame-count and conditioning defaults. A short video preset
|
||||
can therefore capture a default temporal shape and miss the actual request
|
||||
even at the same resolution. The helper marks that row invalid. Use a request
|
||||
whose complete temporal/conditioning contract matches warmup, or fix the
|
||||
model's BCG warmup/padding contract before claiming a speedup.
|
||||
BCG signatures include more than width and height. The helper maps an explicit
|
||||
video request frame count to `--warmup-num-frames`, while
|
||||
`--warmup-resolutions` declares `WxH`. Other temporal or conditioning inputs
|
||||
can still differ from the captured signature. The helper marks such a row
|
||||
invalid; fix the model's BCG warmup/padding contract before claiming a speedup.
|
||||
|
||||
The helper sets `SGLANG_DIFFUSION_SYNC_STAGE_PROFILING=1` for accurate stage
|
||||
attribution. Set it to `0` explicitly only when collecting an e2e-only run and
|
||||
@@ -320,7 +319,7 @@ Use the preset categories this way:
|
||||
| `qwen-edit-base` | `Qwen/Qwen-Image-Edit` | No | Covers the original native `QwenImageEditPipelineConfig`, which is distinct from the 2509/2511 edit-plus paths; public SGLang edit fixture, 1024x1024. |
|
||||
| `qwen-image-layered` | `Qwen/Qwen-Image-Layered` | No | Native layered-image path using the same public reference image and four-frame request as the GPU server case, at the registered 640x640 canvas. |
|
||||
| `stable-diffusion-3.5-medium` | `stabilityai/stable-diffusion-3.5-medium-diffusers` | No | Representative native `StableDiffusion3PipelineConfig` path at 1024x1024. The repository is gated, so export `HF_TOKEN`; an unauthenticated run is a recorded access blocker, not model evidence. |
|
||||
| `sana-video` | `Efficient-Large-Model/SANA-Video_2B_480p_diffusers` | No | CI-sized eager T2V baseline: 832x480, 17 frames, 8 steps, guidance 6.0. Compare `quality=lossless` and `quality=high`; high enables the BF16-input first linear-attention GEMM while retaining FP32 output and the FP32 second GEMM. |
|
||||
| `sana-video` | `Efficient-Large-Model/SANA-Video_2B_480p_diffusers` | No | CI-sized T2V baseline: 832x480, 17 frames, 8 steps, guidance 6.0. The BCG comparator declares the same 17-frame warmup shape. Compare `quality=lossless` and `quality=high`; high enables the BF16-input first linear-attention GEMM while retaining FP32 output and the FP32 second GEMM. |
|
||||
| `sana-wm-bidirectional` | `Efficient-Large-Model/SANA-WM_bidirectional` | No | Dense two-stage TI2V baseline at the native 1280x704 shape, 49 frames, 16 fps, 20 steps, guidance 4.5, and a 48-frame forward/left action program. Uses the shared cat fixture. |
|
||||
| `sana-wm-streaming` | `Efficient-Large-Model/SANA-WM_streaming` | No | Matching offline chunk-causal two-stage baseline with the streaming DiT and chunked refiner enabled; uses the same shape, fixture, seed, and camera action for comparison. |
|
||||
| `lingbot-video-moe` | `robbyant/lingbot-video-moe-30b-a3b` | No | One-GPU eager baseline using the CI structured-JSON caption, 384x640, 17 frames, 12 steps, and text-encoder CPU offload. |
|
||||
|
||||
+2
@@ -1724,6 +1724,8 @@ def build_sglang_cmd(
|
||||
if warmup_resolutions:
|
||||
cmd.append("--warmup-resolutions")
|
||||
cmd.extend(warmup_resolutions)
|
||||
if "warmup-num-frames" not in parsed_args and "num-frames" in parsed_args:
|
||||
cmd.extend(["--warmup-num-frames", str(parsed_args["num-frames"])])
|
||||
if bcg_text_buckets is not None:
|
||||
cmd.append("--bcg-text-buckets")
|
||||
cmd.extend(str(bucket) for bucket in bcg_text_buckets)
|
||||
|
||||
@@ -414,6 +414,7 @@ class ServerArgs(DisaggServerArgsMixin):
|
||||
warmup_mode: str | None = None
|
||||
|
||||
warmup_resolutions: list[str] = None
|
||||
warmup_num_frames: int | None = None
|
||||
warmup_steps: int = 1
|
||||
|
||||
disable_autocast: bool | None = None
|
||||
@@ -1162,6 +1163,8 @@ class ServerArgs(DisaggServerArgsMixin):
|
||||
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.")
|
||||
|
||||
if self.enable_torch_compile and self.warmup_mode is None:
|
||||
self.warmup_mode = "server"
|
||||
@@ -1171,9 +1174,11 @@ class ServerArgs(DisaggServerArgsMixin):
|
||||
"to disable this behavior."
|
||||
)
|
||||
|
||||
# Explicit resolutions need a request path unless an existing server
|
||||
# Explicit warmup shapes need a request path unless an existing server
|
||||
# default already supplies the synthetic startup request.
|
||||
if self.warmup_resolutions is not None and self.warmup_mode in (None, "off"):
|
||||
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 captures every graph during a synthetic warmup forward at startup
|
||||
@@ -2234,6 +2239,16 @@ class ServerArgs(DisaggServerArgsMixin):
|
||||
default=ServerArgs.warmup_resolutions,
|
||||
help="Specify explicit warmup resolutions. e.g., `--warmup-resolutions 256x256 720x720`",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--warmup-num-frames",
|
||||
type=int,
|
||||
default=ServerArgs.warmup_num_frames,
|
||||
help=(
|
||||
"Override the synthetic video warmup frame count. Use this with "
|
||||
"breakable CUDA graphs when serving a non-default frame count so "
|
||||
"the captured latent shape matches the request."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--warmup-steps",
|
||||
type=int,
|
||||
|
||||
@@ -232,8 +232,20 @@ def _resolve_warmup_num_frames(
|
||||
*,
|
||||
server_based_warmup: bool,
|
||||
) -> int:
|
||||
num_frames = getattr(sampling_defaults, "num_frames", 1)
|
||||
if not _is_video_warmup_task(server_args) or num_frames is None:
|
||||
default_num_frames = getattr(sampling_defaults, "num_frames", 1)
|
||||
if not _is_video_warmup_task(server_args):
|
||||
return default_num_frames
|
||||
|
||||
# Most tests and a few lightweight integrations use MagicMock server args,
|
||||
# whose missing attributes resolve to another mock. Only accept a concrete
|
||||
# integer as an explicit override.
|
||||
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
|
||||
|
||||
# Breakable CUDA graph replays only exact latent shapes: the warmup
|
||||
|
||||
@@ -519,6 +519,27 @@ class TestWarmupReqCfgParallel(unittest.TestCase):
|
||||
0,
|
||||
)
|
||||
|
||||
def test_breakable_cuda_graph_uses_explicit_warmup_num_frames(self):
|
||||
pipeline_config = MagicMock()
|
||||
pipeline_config.task_type = ModelTaskType.T2V
|
||||
pipeline_config.adjust_num_frames.side_effect = lambda value: value
|
||||
server_args = SimpleNamespace(
|
||||
pipeline_config=pipeline_config,
|
||||
enable_breakable_cuda_graph=True,
|
||||
pipeline_class_name=None,
|
||||
num_gpus=1,
|
||||
warmup_num_frames=17,
|
||||
)
|
||||
|
||||
num_frames = _resolve_warmup_num_frames(
|
||||
server_args,
|
||||
SamplingParams(num_frames=81),
|
||||
server_based_warmup=True,
|
||||
)
|
||||
|
||||
self.assertEqual(num_frames, 17)
|
||||
pipeline_config.adjust_num_frames.assert_called_once_with(17)
|
||||
|
||||
def test_server_based_warmup_uses_video_supported_resolution_budget(self):
|
||||
server_args = MagicMock()
|
||||
server_args.warmup_steps = 1
|
||||
|
||||
@@ -271,6 +271,14 @@ class TestDiffusionBenchmarkSkill(unittest.TestCase):
|
||||
bcg_cmd[bucket_index + 1 : bucket_index + 3], ["256", "512"]
|
||||
)
|
||||
|
||||
sana_video_bcg_cmd = module.build_sglang_cmd(
|
||||
"sana-video", breakable_cuda_graph=True
|
||||
)
|
||||
self.assertEqual(
|
||||
sana_video_bcg_cmd[sana_video_bcg_cmd.index("--warmup-num-frames") + 1],
|
||||
"17",
|
||||
)
|
||||
|
||||
for _, quality, breakable_cuda_graph in module.QUALITY_BCG_ABBA_MATRIX:
|
||||
module.build_sglang_cmd(
|
||||
"longcat-image",
|
||||
|
||||
@@ -679,6 +679,7 @@ class TestWarmupModeNormalization(unittest.TestCase):
|
||||
*,
|
||||
warmup_mode=None,
|
||||
warmup_resolutions=None,
|
||||
warmup_num_frames=None,
|
||||
enable_torch_compile=False,
|
||||
enable_breakable_cuda_graph=False,
|
||||
disagg_role=None,
|
||||
@@ -688,6 +689,7 @@ class TestWarmupModeNormalization(unittest.TestCase):
|
||||
sa = ServerArgs.__new__(ServerArgs)
|
||||
sa.warmup_mode = warmup_mode
|
||||
sa.warmup_resolutions = warmup_resolutions
|
||||
sa.warmup_num_frames = warmup_num_frames
|
||||
sa.enable_torch_compile = enable_torch_compile
|
||||
sa.enable_breakable_cuda_graph = enable_breakable_cuda_graph
|
||||
sa.disagg_role = RoleType.MONOLITHIC if disagg_role is None else disagg_role
|
||||
@@ -718,6 +720,16 @@ class TestWarmupModeNormalization(unittest.TestCase):
|
||||
)
|
||||
self.assertEqual(sa.warmup_mode, "request")
|
||||
|
||||
def test_num_frames_forces_warmup_on(self):
|
||||
sa = self._resolve(warmup_mode="off", warmup_num_frames=17)
|
||||
self.assertEqual(sa.warmup_mode, "request")
|
||||
|
||||
def test_num_frames_must_be_positive(self):
|
||||
for num_frames in (0, -1):
|
||||
with self.subTest(num_frames=num_frames):
|
||||
with self.assertRaisesRegex(ValueError, "positive"):
|
||||
self._resolve(warmup_num_frames=num_frames)
|
||||
|
||||
def test_torch_compile_defaults_to_server_warmup(self):
|
||||
sa = self._resolve(enable_torch_compile=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user