diff --git a/docs/design/inference_schema_parity_inventory.yaml b/docs/design/inference_schema_parity_inventory.yaml index eda1577fc3..2a5166ce85 100644 --- a/docs/design/inference_schema_parity_inventory.yaml +++ b/docs/design/inference_schema_parity_inventory.yaml @@ -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." @@ -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: @@ -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: diff --git a/fastvideo/tests/api/test_attn_qat_infer_capability_gate.py b/fastvideo/tests/api/test_attn_qat_infer_capability_gate.py index 7094e88449..1b31cfe76e 100644 --- a/fastvideo/tests/api/test_attn_qat_infer_capability_gate.py +++ b/fastvideo/tests/api/test_attn_qat_infer_capability_gate.py @@ -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 -- @@ -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 @@ -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) @@ -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)]) @@ -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): diff --git a/fastvideo/tests/contract/test_ci_test_collection.py b/fastvideo/tests/contract/test_ci_test_collection.py index 9b0152db2f..fec4f52c66 100644 --- a/fastvideo/tests/contract/test_ci_test_collection.py +++ b/fastvideo/tests/contract/test_ci_test_collection.py @@ -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", } diff --git a/fastvideo/tests/contract/test_modal_fa4_policy.py b/fastvideo/tests/contract/test_modal_fa4_policy.py index 1d0fa0e129..c013343dc0 100644 --- a/fastvideo/tests/contract/test_modal_fa4_policy.py +++ b/fastvideo/tests/contract/test_modal_fa4_policy.py @@ -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(): diff --git a/fastvideo/tests/modal/pr_test.py b/fastvideo/tests/modal/pr_test.py index fc007dd32b..5ae8bffee9 100644 --- a/fastvideo/tests/modal/pr_test.py +++ b/fastvideo/tests/modal/pr_test.py @@ -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 "