Skip to content

Commit e5e01be

Browse files
committed
[perf]: batched classifier-free guidance for Wan/Cosmos
Run cond + uncond as a single batch=2 DiT forward per denoise step instead of two sequential batch=1 forwards. Composable with Adaptive Guidance (hao-ai-lab#1372). Mechanism is bit-equivalent to sequential CFG on H100 FA3 eager (SSIM=1.000000, 5 prompts, Wan 14B 720x1280x49f/30steps). See PR body for full validation matrix across L40S/H100 and eager/compile. Changes: - fastvideo_args.py: new use_batched_cfg: bool = True field + --use-batched-cfg CLI. Auto-fallback to sequential when V2V/I2V/ TI2V/action/camera conditioning is present (those carry batch=1 conditioning tensors out of scope for this PR). - entrypoints/video_generator.py: add use_batched_cfg to _FROM_PRETRAINED_CONVENIENCE_KWARGS so users don't see the DeprecationWarning from the legacy kwarg path. - pipelines/stages/denoising.py: gated batched branch in main DenoisingStage.forward. Cats [neg, pos] along batch dim with shape-match defensive fallback, single forward, chunk(2), existing CFG-combine + guidance_rescale math reused. Other DenoisingStage subclasses (Cosmos25, Dmd, ...) unchanged. Sequential CFG path preserved bit-for-bit for non-batched callers. Other DiTs (HunyuanVideo, LongCat, ...) unaffected.
1 parent 0192396 commit e5e01be

6 files changed

Lines changed: 194 additions & 97 deletions

File tree

docs/design/inference_schema_parity_inventory.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ surfaces:
3939
torch_compile_kwargs_audio_vae: generator.engine.compile.audio_vae_kwargs
4040
transformer_quant: generator.engine.quantization.transformer_quant
4141
disable_autocast: generator.engine.disable_autocast
42+
use_batched_cfg: generator.engine.use_batched_cfg
4243
enable_stage_verification: generator.engine.enable_stage_verification
4344
prompt_txt: request.inputs.prompt_path
4445
override_text_encoder_safetensors: generator.pipeline.components.text_encoder_weights

fastvideo/api/compat.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def legacy_from_pretrained_to_config(
157157
preset_refine["num_inference_steps"] = value
158158
elif key == "ltx2_refine_guidance_scale":
159159
preset_refine["guidance_scale"] = value
160-
elif key in {"enable_stage_verification", "use_fsdp_inference", "disable_autocast"}:
160+
elif key in {"enable_stage_verification", "use_fsdp_inference", "disable_autocast", "use_batched_cfg"}:
161161
engine[key] = value
162162
elif key == "override_text_encoder_quant":
163163
quantization["text_encoder_quant"] = value
@@ -244,6 +244,7 @@ def generator_config_to_fastvideo_args(config: GeneratorConfig | Mapping[str, An
244244
"enable_stage_verification": engine.enable_stage_verification,
245245
"use_fsdp_inference": engine.use_fsdp_inference,
246246
"disable_autocast": engine.disable_autocast,
247+
"use_batched_cfg": engine.use_batched_cfg,
247248
}
248249
if normalized.pipeline.workload_type is not None:
249250
kwargs["workload_type"] = normalized.pipeline.workload_type

fastvideo/api/schema.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class EngineConfig:
8181
enable_stage_verification: bool = True
8282
use_fsdp_inference: bool = False
8383
disable_autocast: bool = False
84+
use_batched_cfg: bool = True
8485
quantization: QuantizationConfig | None = None
8586

8687

fastvideo/entrypoints/video_generator.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
"pin_cpu_memory",
9595
"enable_torch_compile",
9696
"torch_compile_kwargs",
97+
"use_batched_cfg",
9798
"output_type",
9899
"nvfp4_fa4",
99100
})

fastvideo/fastvideo_args.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ class FastVideoArgs:
153153

154154
disable_autocast: bool = False
155155

156+
# Batched classifier-free guidance: run cond + uncond as a single
157+
# batch=2 DiT forward per denoise step instead of two sequential
158+
# batch=1 forwards. Output-identical (SSIM=1.0); reduces per-step
159+
# launch + memory-traffic overhead. Disable to fall back to the
160+
# legacy sequential path (e.g. for debugging or for entry points
161+
# that aren't covered by the batched path yet).
162+
use_batched_cfg: bool = True
163+
156164
# VSA parameters
157165
VSA_sparsity: float = 0.0 # inference/validation sparsity
158166

@@ -538,6 +546,17 @@ def add_cli_args(parser: FlexibleArgumentParser) -> FlexibleArgumentParser:
538546
help="Use torch.compile to speed up DiT inference." +
539547
"However, will likely cause precision drifts. See (https://github.com/pytorch/pytorch/issues/145213)",
540548
)
549+
parser.add_argument(
550+
"--use-batched-cfg",
551+
action=StoreBoolean,
552+
default=FastVideoArgs.use_batched_cfg,
553+
help="Run classifier-free guidance as a single batch=2 DiT "
554+
"forward per step (cond+uncond stacked) instead of two "
555+
"sequential batch=1 forwards. Output-identical at SSIM=1.0; "
556+
"reduces per-step launch + memory overhead. Falls back to "
557+
"the sequential path when V2V/I2V/TI2V/action/camera "
558+
"conditioning is present.",
559+
)
541560
parser.add_argument(
542561
"--torch-compile-kwargs",
543562
type=str,

0 commit comments

Comments
 (0)