Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions docs/design/inference_schema_parity_inventory.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,14 @@ surfaces:
vae_precision: "Precision override pending dedicated typed component precision design."
vae_decode_precision: "Decode-only precision override pending dedicated typed component precision design."
image_encoder_precision: "Precision override pending dedicated typed component precision design."
image_encoder_precisions: "Multi-encoder precision overrides pending dedicated typed component precision design."
text_encoder_precisions: "Precision override pending dedicated typed component precision design."
internal_only:
dit_config: "Legacy internal component config object."
upsampler_config: "Legacy internal component config object."
vae_config: "Legacy internal component config object."
image_encoder_config: "Legacy internal component config object."
image_encoder_configs: "Legacy internal multi-encoder component config objects."
text_encoder_configs: "Legacy internal component config object."
preprocess_text_funcs: "Internal text preprocessing hooks."
postprocess_text_funcs: "Internal text postprocessing hooks."
Expand Down Expand Up @@ -375,6 +377,7 @@ surfaces:
- fastvideo.configs.pipelines.stable_audio.StableAudioOpenSmallConfig
max_audio_duration_s:
sources:
- fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig
- fastvideo.configs.pipelines.stable_audio.StableAudioT2AConfig
- fastvideo.configs.pipelines.stable_audio.StableAudioOpenSmallConfig
sample_size:
Expand All @@ -383,8 +386,33 @@ surfaces:
- fastvideo.configs.pipelines.stable_audio.StableAudioOpenSmallConfig
sampling_rate:
sources:
- fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig
- fastvideo.configs.pipelines.stable_audio.StableAudioT2AConfig
- fastvideo.configs.pipelines.stable_audio.StableAudioOpenSmallConfig
duration_s:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
spectrogram_frame_rate:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
latent_downsample_rate:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
clip_frame_rate:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
sync_frame_rate:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
sync_segment_size:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
sync_segment_stride:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
sync_downsample_rate:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
clip_image_size:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
sync_image_size:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
clip_batch_size_multiplier:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
sync_batch_size_multiplier:
sources: [fastvideo.configs.pipelines.mmaudio.MMAudioV2AConfig]
audio_txt_guidance_scale:
sources: [fastvideo.pipelines.basic.magi_human.pipeline_configs.MagiHumanBaseConfig]
cfg_number:
Expand Down
41 changes: 18 additions & 23 deletions fastvideo/tests/api/test_attn_qat_infer_capability_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
``is_attn_qat_infer_available()`` used to test only whether the kernel
extension imports. CUDA 13 wheel builds can carry the sm_120/sm_121
extension on any host (e.g. H100 sm_90, GB200 sm_100): the import
succeeds, ``CudaPlatformBase.get_attn_backend_cls`` selects the
consumer-Blackwell backend, and the first kernel call fails with an
unsupported-capability error -- instead of the FlashAttention fallback
the QAD README documents for non-sm_120 GPUs.
succeeds, ``CudaPlatformBase.get_attn_backend_cls`` must reject the explicitly
selected backend before the first kernel call can fail with an opaque
unsupported-capability error.

These tests drive the REAL resolver (``fastvideo.platforms.cuda``) and
the REAL availability function; only the two physical facts are faked --
Expand All @@ -17,8 +16,8 @@
(fastvideo/tests/stages/test_kandinsky5_attention_backend_guard.py)
injects an already-resolved backend and by design cannot see this bug.

CPU-only: the ATTN_QAT_INFER branch and its fallback never require a
physical GPU to *resolve* (only to run).
CPU-only: the ATTN_QAT_INFER branch does not require a physical GPU to
*resolve* (only to run).
"""
from __future__ import annotations

Expand All @@ -35,15 +34,6 @@
from fastvideo.platforms.interface import AttentionBackendEnum

ATTN_QAT_INFER_CLS = "fastvideo.attention.backends.attn_qat_infer.AttnQatInferBackend"
# What the resolver's fallthrough legitimately returns when ATTN_QAT_INFER
# is unavailable: FlashAttention, or SDPA when flash_attn isn't installed
# in the running environment (e.g. CPU-only CI).
FALLBACK_CLASSES = {
"fastvideo.attention.backends.flash_attn.FlashAttentionBackend",
"fastvideo.attention.backends.sdpa.SDPABackend",
}


def _fake_gpu(monkeypatch, *, capability: tuple[int, int], extension_imports: bool, fa4_imports: bool = False) -> None:
monkeypatch.setattr(torch.cuda, "is_available", lambda: True)
monkeypatch.setattr(torch.cuda, "get_device_capability", lambda device=None: capability)
Expand All @@ -66,22 +56,27 @@ def _resolve() -> str:
)


def test_sm90_host_with_bundled_extension_falls_back(monkeypatch):
def _assert_unavailable_backend_is_rejected() -> None:
with pytest.raises(ImportError, match="ATTN_QAT_INFER selected.*not usable"):
_resolve()


def test_sm90_host_with_bundled_extension_is_rejected(monkeypatch):
"""The reviewed failure: H100 + CUDA 13 wheel that bundles the sm_120
extension. Import succeeds; selection must still fall back."""
extension. Import succeeds; explicit selection must still be rejected."""
_fake_gpu(monkeypatch, capability=(9, 0), extension_imports=True)

assert not is_attn_qat_infer_available()
assert _resolve() in FALLBACK_CLASSES
_assert_unavailable_backend_is_rejected()


def test_sm100_host_with_bundled_extension_falls_back(monkeypatch):
def test_sm100_host_with_bundled_extension_is_rejected(monkeypatch):
"""sm_100 with only the (unrunnable) bundled sm_12x extension and no
FP4 FA4 kernel still falls back -- the original reviewed failure class."""
FP4 FA4 kernel is rejected -- the original reviewed failure class."""
_fake_gpu(monkeypatch, capability=(10, 0), extension_imports=True, fa4_imports=False)

assert not is_attn_qat_infer_available()
assert _resolve() in FALLBACK_CLASSES
_assert_unavailable_backend_is_rejected()


@pytest.mark.parametrize("capability", [(10, 0), (10, 3)])
Expand All @@ -102,11 +97,11 @@ def test_consumer_blackwell_with_extension_selects_backend(monkeypatch, capabili
assert _resolve() == ATTN_QAT_INFER_CLS


def test_consumer_blackwell_without_extension_falls_back(monkeypatch):
def test_consumer_blackwell_without_extension_is_rejected(monkeypatch):
_fake_gpu(monkeypatch, capability=(12, 0), extension_imports=False)

assert not is_attn_qat_infer_available()
assert _resolve() in FALLBACK_CLASSES
_assert_unavailable_backend_is_rejected()


def test_no_cuda_reports_unavailable(monkeypatch):
Expand Down
1 change: 1 addition & 0 deletions fastvideo/tests/contract/test_ci_test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"distributed": "no lane yet — multi-GPU torchrun tests, run manually",
"hooks": "no lane yet — run manually",
"layers": "no lane yet — torchrun FSDP dispatch tests, run manually",
"mlx": "Apple Silicon/Metal-specific suite; the Modal PR lanes run on Linux CUDA",
"nightly": "by design: nightly cadence, not per-PR",
"modal": "CI infrastructure itself, not a test suite",
}
Expand Down
22 changes: 18 additions & 4 deletions fastvideo/tests/contract/test_modal_fa4_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,28 @@ def _function_strings(path: Path, function_name: str) -> str:
raise AssertionError(f"{function_name} not found in {path}")


def _image_env_default(path: Path, env_name: str) -> str:
tree = ast.parse(path.read_text(encoding="utf-8"))
for node in ast.walk(tree):
if not isinstance(node, ast.Dict):
continue
for key, value in zip(node.keys, node.values, strict=True):
if not (isinstance(key, ast.Constant) and key.value == env_name):
continue
if (isinstance(value, ast.Call) and isinstance(value.func, ast.Attribute)
and value.func.attr == "get" and len(value.args) == 2
and isinstance(value.args[0], ast.Constant) and value.args[0].value == env_name
and isinstance(value.args[1], ast.Constant) and isinstance(value.args[1].value, str)):
return value.args[1].value
raise AssertionError(f"{env_name} default not found in an image environment dictionary in {path}")


def test_generic_l40s_launcher_defaults_fa4_off():
source = LAUNCH_L40S_JOB.read_text(encoding="utf-8")
assert '"FASTVIDEO_FA4": os.environ.get("FASTVIDEO_FA4", "0")' in source
assert _image_env_default(LAUNCH_L40S_JOB, "FASTVIDEO_FA4") == "0"


def test_ssim_launcher_keeps_fa4_enabled_by_default():
source = SSIM_TEST.read_text(encoding="utf-8")
assert '"FASTVIDEO_FA4": os.environ.get("FASTVIDEO_FA4", "1")' in source
assert _image_env_default(SSIM_TEST, "FASTVIDEO_FA4") == "1"


def test_performance_identity_env_reaches_modal_runtime():
Expand Down
1 change: 1 addition & 0 deletions fastvideo/tests/modal/pr_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ def run_unit_test():
run_test("pytest ./fastvideo/tests/api/ ./fastvideo/tests/contract/ ./fastvideo/tests/dataset/ "
"./fastvideo/tests/workflow/ ./fastvideo/tests/entrypoints/ ./fastvideo/tests/train/ "
"./fastvideo/tests/stages/ ./fastvideo/tests/ops/ ./fastvideo/tests/worker/ "
"./fastvideo/tests/platforms/ "
"./fastvideo/tests/training/test_trackers.py "
"./fastvideo/tests/attention/test_sdpa_metadata_mask_contract.py "
"./fastvideo/tests/modal/test_kernel_build_cache.py ./fastvideo/tests/modal/test_pr_test.py "
Expand Down
Loading