From a9da8daba7ed3c71a13347dcfa144678a7372ebb Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Sun, 16 Aug 2026 11:11:32 -0700 Subject: [PATCH 01/11] [None][test] DO NOT MERGE: CI diagnostic for Cosmos3 LPIPS golden divergence The Cosmos3 LPIPS goldens pass in CI but reproduce on no developer machine we can build. edge_t2i measures 0.117127 locally against the 0.0056 recorded at creation, while every other VisualGen golden (qwenimage at 50 steps, wan, flux) reproduces locally without trouble. Ruled out locally, each by measurement and nearly all bit-identical across the change: GPU generation (B200 vs B300), torch build (PyPI 2.11.0, 2.12.0, and NVIDIA-patched 2.13.0a0 inside an NGC container), the container itself, the checkpoint, the models root, negative and system prompts, tokenization, per-step transformer parity against diffusers, VAE round-trip, the flow schedule, the SDPA backend, diffusers/transformers versions, and test order. This instruments test_cosmos3_edge_t2i_lpips_against_golden to fingerprint the inputs and intermediates CI actually uses -- environment, checkpoint config hashes, golden bytes, conditioning text, the first and last transformer latent, and the measured score -- so they can be diffed against the local values. It reports through the assertion message and fails unconditionally because the CI report API returns empty stdout for tests that pass. To be reverted once the divergence is understood. Signed-off-by: Igor Shovkun --- .../visual_gen/test_visual_gen_cosmos3.py | 142 +++++++++++++++++- 1 file changed, 134 insertions(+), 8 deletions(-) diff --git a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py index bb72a4656f9f..29061773296d 100644 --- a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py +++ b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py @@ -855,6 +855,61 @@ def test_cosmos3_edge_i2v_lpips_against_golden(_visual_gen_deps, request, tmp_pa _assert_lpips_below_threshold(score, COSMOS3_EDGE_I2V_LPIPS_THRESHOLD) +def _ci_diag_hash(obj): + """sha256 of a tensor's bytes, plus shape/stats, for cross-machine diffing.""" + import hashlib + + t = obj.detach().float().cpu().contiguous() + return ( + f"sha={hashlib.sha256(t.numpy().tobytes()).hexdigest()[:16]} " + f"shape={tuple(t.shape)} mean={t.mean().item():+.6e} std={t.std().item():.6e}" + ) + + +def _ci_diag_file(path): + import hashlib + + data = open(str(path), "rb").read() + return f"sha={hashlib.sha256(data).hexdigest()[:16]} bytes={len(data)}" + + +def _ci_diag_environment(): + import hashlib + import platform + + lines = [] + try: + import torch + + lines.append( + f"torch={torch.__version__} cuda={torch.version.cuda} " + f"cudnn={torch.backends.cudnn.version()} gpu={torch.cuda.get_device_name(0)} " + f"cap={torch.cuda.get_device_capability(0)}" + ) + lines.append( + f"tf32_matmul={torch.backends.cuda.matmul.allow_tf32} " + f"tf32_cudnn={torch.backends.cudnn.allow_tf32} " + f"fp32_prec={torch.get_float32_matmul_precision()} " + f"deterministic={torch.are_deterministic_algorithms_enabled()} " + f"cublas_ws={os.environ.get('CUBLAS_WORKSPACE_CONFIG')}" + ) + except Exception as exc: # noqa: BLE001 - diagnostic only + lines.append(f"torch probe failed: {exc}") + for mod in ("diffusers", "transformers", "torchao", "tensorrt_llm"): + try: + lines.append(f"{mod}={__import__(mod).__version__}") + except Exception as exc: # noqa: BLE001 - diagnostic only + lines.append(f"{mod}=UNAVAILABLE({type(exc).__name__})") + ckpt = _lpips_model_path("Cosmos3-Edge") + lines.append(f"python={platform.python_version()} models_root={os.path.dirname(ckpt)}") + for rel in ("model_index.json", "vae/config.json", "transformer/config.json"): + p = os.path.join(ckpt, rel) + if os.path.exists(p): + digest = hashlib.sha256(open(p, "rb").read()).hexdigest()[:16] + lines.append(f"ckpt:{rel}={digest}") + return lines + + @pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA not available") def test_cosmos3_edge_t2i_lpips_against_golden(request, tmp_path): from tensorrt_llm.media.encoding import save_image @@ -863,14 +918,73 @@ def test_cosmos3_edge_t2i_lpips_against_golden(request, tmp_path): golden_path = _golden_media_path( tmp_path, "cosmos3_edge_t2i_lpips_golden.png", "Cosmos3-Edge T2I LPIPS golden image" ) - result = _run_cosmos3_edge_lpips_pipeline( - prompt=COSMOS3_EDGE_T2I_LPIPS_PROMPT, - height=640, - width=640, - num_inference_steps=COSMOS3_EDGE_T2I_LPIPS_STEPS, - guidance_scale=4.0, - output_type="image", - ) + + # --- TEMPORARY CI DIAGNOSTIC (DO NOT MERGE) ----------------------------- + # These goldens reproduce in CI but on no developer machine we can build: + # edge_t2i measures 0.117127 locally against 0.0056 recorded at creation, + # while every other VisualGen golden (qwenimage 50-step, wan, flux) + # reproduces locally. Ruled out locally, each by measurement and nearly all + # bit-identical: GPU generation (B200 vs B300), torch build (PyPI 2.11, + # 2.12, and NGC-patched 2.13a in a container), the container itself, the + # checkpoint, the models root, negative and system prompts, tokenization, + # per-step transformer parity against diffusers, VAE round-trip, the flow + # schedule, SDPA backend, diffusers/transformers versions, and test order. + # This captures CI's own inputs and intermediates so they can be diffed + # against the local ones, and reports through the assertion message because + # the CI report API returns empty stdout for tests that pass. + diag = list(_ci_diag_environment()) + diag.append(f"golden {_ci_diag_file(golden_path)}") + + import tensorrt_llm._torch.visual_gen.models.cosmos3.pipeline_cosmos3 as _p3 + from tensorrt_llm._torch.visual_gen.models.cosmos3.transformer_cosmos3 import ( + Cosmos3VFMTransformer, + ) + + _texts, _steps = [], [] + _orig_tmpl = _p3.Cosmos3OmniMoTPipeline._apply_metadata_templates + _orig_fwd = Cosmos3VFMTransformer.forward + + def _spy_tmpl(self, prompt, **kw): + out = _orig_tmpl(self, prompt, **kw) + _texts.append(out) + return out + + def _spy_fwd(self, *a, **kw): + hs = kw.get("hidden_states", a[0] if a else None) + if isinstance(hs, torch.Tensor): + # Keep the first call (initial latent) and the most recent one, so + # a divergence can be attributed to the noise draw vs the trajectory. + if len(_steps) < 2: + _steps.append(_ci_diag_hash(hs)) + else: + _steps[1] = _ci_diag_hash(hs) + return _orig_fwd(self, *a, **kw) + + _p3.Cosmos3OmniMoTPipeline._apply_metadata_templates = _spy_tmpl + Cosmos3VFMTransformer.forward = _spy_fwd + try: + result = _run_cosmos3_edge_lpips_pipeline( + prompt=COSMOS3_EDGE_T2I_LPIPS_PROMPT, + height=640, + width=640, + num_inference_steps=COSMOS3_EDGE_T2I_LPIPS_STEPS, + guidance_scale=4.0, + output_type="image", + ) + finally: + _p3.Cosmos3OmniMoTPipeline._apply_metadata_templates = _orig_tmpl + Cosmos3VFMTransformer.forward = _orig_fwd + + import hashlib + + for i, txt in enumerate(_texts): + diag.append( + f"text[{i}] sha={hashlib.sha256(txt.encode()).hexdigest()[:16]} chars={len(txt)}" + ) + for i, st in enumerate(_steps): + diag.append(f"latent[{'first' if i == 0 else 'last'}] {st}") + # --- end diagnostic ----------------------------------------------------- + assert result is not None and result.image is not None, "Edge T2I produced no image" save_image(result.image[0], str(generated_path)) score = _run_lpips_eval( @@ -888,4 +1002,16 @@ def test_cosmos3_edge_t2i_lpips_against_golden(request, tmp_path): generated_path, "cosmos3_edge_t2i_lpips_golden.png", ) + + # --- TEMPORARY CI DIAGNOSTIC (DO NOT MERGE) ----------------------------- + # Fail unconditionally so the fingerprint reaches the CI report, which only + # records error text -- a passing test reports empty stdout. Local values + # for the same fields, measured on B200 and B300 (identical to 6 dp): + # score 0.117127 (CI's recorded creation value: 0.0056) + # golden sha 59e2d3f30eb3c427 bytes=529144 + diag.append(f"generated {_ci_diag_file(generated_path)}") + diag.append(f"SCORE={score:.6f} threshold={COSMOS3_EDGE_T2I_LPIPS_THRESHOLD} LOCAL=0.117127") + raise AssertionError("COSMOS3-CI-DIAG || " + " || ".join(diag)) + # --- end diagnostic ----------------------------------------------------- + _assert_lpips_below_threshold(score, COSMOS3_EDGE_T2I_LPIPS_THRESHOLD) From 0ed750f38b28ce1789f1b2ec4516e4838d689267 Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Sun, 16 Aug 2026 22:35:38 -0700 Subject: [PATCH 02/11] [None][test] DO NOT MERGE: run the Cosmos3 diagnostic pre-merge The Cosmos3 LPIPS golden tests sit in an l0_b200.yml block whose terms are `stage: post_merge`, so a PR pipeline never schedules them. Two bot runs confirmed this: neither pipeline #54182 nor #54185 produced any record for test_visual_gen_cosmos3.py, including with --extra-stage "DGX_B200-PyTorch-Post-Merge-1", because the gate is in the test-db terms rather than in the stage selection. List the instrumented test in the pre_merge pytorch b200 block so the diagnostic actually runs on a PR pipeline. Remove together with the diagnostic itself. Signed-off-by: Igor Shovkun --- tests/integration/test_lists/test-db/l0_b200.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/integration/test_lists/test-db/l0_b200.yml b/tests/integration/test_lists/test-db/l0_b200.yml index 94168080bbfe..d446d6931baf 100644 --- a/tests/integration/test_lists/test-db/l0_b200.yml +++ b/tests/integration/test_lists/test-db/l0_b200.yml @@ -15,6 +15,11 @@ l0_b200: backend: pytorch tests: # ------------- PyTorch tests --------------- + # TEMPORARY (DO NOT MERGE): this test is normally post_merge only, so a PR + # pipeline never schedules it and --extra-stage cannot pull it in. Listed here + # so the Cosmos3 golden diagnostic actually runs pre-merge. Remove with the + # diagnostic. + - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_edge_t2i_lpips_against_golden TIMEOUT (15) - unittest/others/test_kv_cache_transceiver.py::test_cpp_nixl_sync_transfer_stress - accuracy/test_llm_api_pytorch.py::TestLlama3_1_8B::test_nvfp4 - accuracy/test_llm_api_pytorch.py::TestLlama3_1_8B::test_nvfp4_streaming[stream_interval_4] From a36c902e1b6cbdfab748696aae70b35953ab131a Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Mon, 17 Aug 2026 11:37:12 -0700 Subject: [PATCH 03/11] [None][test] DO NOT MERGE: fingerprint checkpoint weights and tokenizer too The payload hashed only checkpoint config JSONs, so a CI checkpoint with identical configs but different weight bytes would evade it -- and weights do not reach latent[first] either, so nothing else in the payload covers them. Add per-safetensors size plus head/tail-1MiB digests and the tokenizer.json hash, closing the different-checkpoint and different-tokenizer branches. Signed-off-by: Igor Shovkun --- .../visual_gen/test_visual_gen_cosmos3.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py index 29061773296d..b5651cd58bcd 100644 --- a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py +++ b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py @@ -902,11 +902,29 @@ def _ci_diag_environment(): lines.append(f"{mod}=UNAVAILABLE({type(exc).__name__})") ckpt = _lpips_model_path("Cosmos3-Edge") lines.append(f"python={platform.python_version()} models_root={os.path.dirname(ckpt)}") - for rel in ("model_index.json", "vae/config.json", "transformer/config.json"): + for rel in ("model_index.json", "vae/config.json", "transformer/config.json", "tokenizer.json"): p = os.path.join(ckpt, rel) if os.path.exists(p): digest = hashlib.sha256(open(p, "rb").read()).hexdigest()[:16] lines.append(f"ckpt:{rel}={digest}") + # Weight identity, not just configs: size plus head/tail 1 MiB of every + # safetensors file. Full hashes of 9 GB are too slow for a test; head+tail + # covers the header (tensor offsets) and trailing data, so any resave, + # truncation, or requantization shows up. + for root, _dirs, files in sorted(os.walk(ckpt)): + for fn in sorted(files): + if not fn.endswith(".safetensors"): + continue + p = os.path.join(root, fn) + size = os.path.getsize(p) + h = hashlib.sha256() + with open(p, "rb") as fh: + h.update(fh.read(1 << 20)) + if size > (2 << 20): + fh.seek(-(1 << 20), os.SEEK_END) + h.update(fh.read(1 << 20)) + rel = os.path.relpath(p, ckpt) + lines.append(f"wt:{rel}={h.hexdigest()[:16]},{size}") return lines From a4ed9a9c13a69b3c024debd0d83e12c8c734bf95 Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Mon, 17 Aug 2026 14:10:25 -0700 Subject: [PATCH 04/11] [https://nvbugs/6418815][test] Pin fp32-matmul precision in VisualGen LPIPS paths Root cause of the Cosmos3 LPIPS golden divergence (nvbugs 6418815, 6437341): NGC PyTorch containers default matmul TF32 on (float32_matmul_precision "high") while PyPI torch defaults it off ("highest"), and Cosmos3 is the only VisualGen model with fp32 GEMMs inside its denoising loop -- the RoPE frequency matmul (transformer_cosmos3.py:863) and the fp32 timestep embedder (:1604), both deliberately upcast for accuracy. A CI-side fingerprint proved the inputs bit-identical (same conditioning text, checkpoint, golden bytes, and initial latent) with the trajectory diverging, and a single-flag A/B moved LPIPS-to-golden 0.132 -> 0.054. bf16 compute is unaffected by the knob. Pin "highest" (measured bit-stable across torch 2.11/2.12 and B200/B300) and cuDNN TF32 in _lpips_deterministic_algorithms and around the three Cosmos3 generation helpers that do not use it, so goldens are portable across hosts instead of encoding the golden-cutting container's arithmetic. Production code inherits environment defaults unchanged; this pins tests only. This also reverts the temporary CI diagnostic instrumentation from test_cosmos3_edge_t2i_lpips_against_golden. Signed-off-by: Igor Shovkun --- .../visual_gen/test_visual_gen_cosmos3.py | 167 ++---------------- .../visual_gen/visual_gen_test_utils.py | 27 ++- 2 files changed, 39 insertions(+), 155 deletions(-) diff --git a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py index b5651cd58bcd..c2cb50580c41 100644 --- a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py +++ b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py @@ -35,6 +35,7 @@ _golden_media_path, _lpips_deterministic_algorithms, _lpips_model_path, + _lpips_pinned_fp32_matmul_precision, _preserve_lpips_candidate_on_failure, _run_lpips_eval, _run_reusable_image_lpips_eval, @@ -160,7 +161,9 @@ def _run_cosmos3_lpips_pipeline(num_frames, video=None): ) pipeline = PipelineLoader(args).load(skip_warmup=True) try: - with torch.no_grad(): + # Pin fp32-matmul arithmetic: the goldens are cut and compared + # under "highest" so they reproduce on both PyPI and NGC torch. + with torch.no_grad(), _lpips_pinned_fp32_matmul_precision(): result = pipeline.forward( prompt=COSMOS3_LPIPS_PROMPT, # The goldens were generated against an empty uncond branch, @@ -569,7 +572,7 @@ def _run_cosmos3_i2v_4step_lpips_pipeline(image_path): ) pipeline = PipelineLoader(args).load(skip_warmup=True) try: - with torch.no_grad(): + with torch.no_grad(), _lpips_pinned_fp32_matmul_precision(): result = pipeline.forward( prompt=COSMOS3_I2V_4STEP_LPIPS_PROMPT, # The goldens were generated against an empty uncond branch, @@ -760,7 +763,7 @@ def _run_cosmos3_edge_lpips_pipeline(**forward_kwargs): # The goldens were generated against an empty uncond branch, so pin it # here rather than inheriting the video-mode default negative prompt. forward_kwargs.setdefault("negative_prompt", "") - with torch.no_grad(): + with torch.no_grad(), _lpips_pinned_fp32_matmul_precision(): result = pipeline.forward( seed=COSMOS3_EDGE_LPIPS_SEED, use_guardrails=False, @@ -855,79 +858,6 @@ def test_cosmos3_edge_i2v_lpips_against_golden(_visual_gen_deps, request, tmp_pa _assert_lpips_below_threshold(score, COSMOS3_EDGE_I2V_LPIPS_THRESHOLD) -def _ci_diag_hash(obj): - """sha256 of a tensor's bytes, plus shape/stats, for cross-machine diffing.""" - import hashlib - - t = obj.detach().float().cpu().contiguous() - return ( - f"sha={hashlib.sha256(t.numpy().tobytes()).hexdigest()[:16]} " - f"shape={tuple(t.shape)} mean={t.mean().item():+.6e} std={t.std().item():.6e}" - ) - - -def _ci_diag_file(path): - import hashlib - - data = open(str(path), "rb").read() - return f"sha={hashlib.sha256(data).hexdigest()[:16]} bytes={len(data)}" - - -def _ci_diag_environment(): - import hashlib - import platform - - lines = [] - try: - import torch - - lines.append( - f"torch={torch.__version__} cuda={torch.version.cuda} " - f"cudnn={torch.backends.cudnn.version()} gpu={torch.cuda.get_device_name(0)} " - f"cap={torch.cuda.get_device_capability(0)}" - ) - lines.append( - f"tf32_matmul={torch.backends.cuda.matmul.allow_tf32} " - f"tf32_cudnn={torch.backends.cudnn.allow_tf32} " - f"fp32_prec={torch.get_float32_matmul_precision()} " - f"deterministic={torch.are_deterministic_algorithms_enabled()} " - f"cublas_ws={os.environ.get('CUBLAS_WORKSPACE_CONFIG')}" - ) - except Exception as exc: # noqa: BLE001 - diagnostic only - lines.append(f"torch probe failed: {exc}") - for mod in ("diffusers", "transformers", "torchao", "tensorrt_llm"): - try: - lines.append(f"{mod}={__import__(mod).__version__}") - except Exception as exc: # noqa: BLE001 - diagnostic only - lines.append(f"{mod}=UNAVAILABLE({type(exc).__name__})") - ckpt = _lpips_model_path("Cosmos3-Edge") - lines.append(f"python={platform.python_version()} models_root={os.path.dirname(ckpt)}") - for rel in ("model_index.json", "vae/config.json", "transformer/config.json", "tokenizer.json"): - p = os.path.join(ckpt, rel) - if os.path.exists(p): - digest = hashlib.sha256(open(p, "rb").read()).hexdigest()[:16] - lines.append(f"ckpt:{rel}={digest}") - # Weight identity, not just configs: size plus head/tail 1 MiB of every - # safetensors file. Full hashes of 9 GB are too slow for a test; head+tail - # covers the header (tensor offsets) and trailing data, so any resave, - # truncation, or requantization shows up. - for root, _dirs, files in sorted(os.walk(ckpt)): - for fn in sorted(files): - if not fn.endswith(".safetensors"): - continue - p = os.path.join(root, fn) - size = os.path.getsize(p) - h = hashlib.sha256() - with open(p, "rb") as fh: - h.update(fh.read(1 << 20)) - if size > (2 << 20): - fh.seek(-(1 << 20), os.SEEK_END) - h.update(fh.read(1 << 20)) - rel = os.path.relpath(p, ckpt) - lines.append(f"wt:{rel}={h.hexdigest()[:16]},{size}") - return lines - - @pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA not available") def test_cosmos3_edge_t2i_lpips_against_golden(request, tmp_path): from tensorrt_llm.media.encoding import save_image @@ -936,73 +866,14 @@ def test_cosmos3_edge_t2i_lpips_against_golden(request, tmp_path): golden_path = _golden_media_path( tmp_path, "cosmos3_edge_t2i_lpips_golden.png", "Cosmos3-Edge T2I LPIPS golden image" ) - - # --- TEMPORARY CI DIAGNOSTIC (DO NOT MERGE) ----------------------------- - # These goldens reproduce in CI but on no developer machine we can build: - # edge_t2i measures 0.117127 locally against 0.0056 recorded at creation, - # while every other VisualGen golden (qwenimage 50-step, wan, flux) - # reproduces locally. Ruled out locally, each by measurement and nearly all - # bit-identical: GPU generation (B200 vs B300), torch build (PyPI 2.11, - # 2.12, and NGC-patched 2.13a in a container), the container itself, the - # checkpoint, the models root, negative and system prompts, tokenization, - # per-step transformer parity against diffusers, VAE round-trip, the flow - # schedule, SDPA backend, diffusers/transformers versions, and test order. - # This captures CI's own inputs and intermediates so they can be diffed - # against the local ones, and reports through the assertion message because - # the CI report API returns empty stdout for tests that pass. - diag = list(_ci_diag_environment()) - diag.append(f"golden {_ci_diag_file(golden_path)}") - - import tensorrt_llm._torch.visual_gen.models.cosmos3.pipeline_cosmos3 as _p3 - from tensorrt_llm._torch.visual_gen.models.cosmos3.transformer_cosmos3 import ( - Cosmos3VFMTransformer, + result = _run_cosmos3_edge_lpips_pipeline( + prompt=COSMOS3_EDGE_T2I_LPIPS_PROMPT, + height=640, + width=640, + num_inference_steps=COSMOS3_EDGE_T2I_LPIPS_STEPS, + guidance_scale=4.0, + output_type="image", ) - - _texts, _steps = [], [] - _orig_tmpl = _p3.Cosmos3OmniMoTPipeline._apply_metadata_templates - _orig_fwd = Cosmos3VFMTransformer.forward - - def _spy_tmpl(self, prompt, **kw): - out = _orig_tmpl(self, prompt, **kw) - _texts.append(out) - return out - - def _spy_fwd(self, *a, **kw): - hs = kw.get("hidden_states", a[0] if a else None) - if isinstance(hs, torch.Tensor): - # Keep the first call (initial latent) and the most recent one, so - # a divergence can be attributed to the noise draw vs the trajectory. - if len(_steps) < 2: - _steps.append(_ci_diag_hash(hs)) - else: - _steps[1] = _ci_diag_hash(hs) - return _orig_fwd(self, *a, **kw) - - _p3.Cosmos3OmniMoTPipeline._apply_metadata_templates = _spy_tmpl - Cosmos3VFMTransformer.forward = _spy_fwd - try: - result = _run_cosmos3_edge_lpips_pipeline( - prompt=COSMOS3_EDGE_T2I_LPIPS_PROMPT, - height=640, - width=640, - num_inference_steps=COSMOS3_EDGE_T2I_LPIPS_STEPS, - guidance_scale=4.0, - output_type="image", - ) - finally: - _p3.Cosmos3OmniMoTPipeline._apply_metadata_templates = _orig_tmpl - Cosmos3VFMTransformer.forward = _orig_fwd - - import hashlib - - for i, txt in enumerate(_texts): - diag.append( - f"text[{i}] sha={hashlib.sha256(txt.encode()).hexdigest()[:16]} chars={len(txt)}" - ) - for i, st in enumerate(_steps): - diag.append(f"latent[{'first' if i == 0 else 'last'}] {st}") - # --- end diagnostic ----------------------------------------------------- - assert result is not None and result.image is not None, "Edge T2I produced no image" save_image(result.image[0], str(generated_path)) score = _run_lpips_eval( @@ -1020,16 +891,4 @@ def _spy_fwd(self, *a, **kw): generated_path, "cosmos3_edge_t2i_lpips_golden.png", ) - - # --- TEMPORARY CI DIAGNOSTIC (DO NOT MERGE) ----------------------------- - # Fail unconditionally so the fingerprint reaches the CI report, which only - # records error text -- a passing test reports empty stdout. Local values - # for the same fields, measured on B200 and B300 (identical to 6 dp): - # score 0.117127 (CI's recorded creation value: 0.0056) - # golden sha 59e2d3f30eb3c427 bytes=529144 - diag.append(f"generated {_ci_diag_file(generated_path)}") - diag.append(f"SCORE={score:.6f} threshold={COSMOS3_EDGE_T2I_LPIPS_THRESHOLD} LOCAL=0.117127") - raise AssertionError("COSMOS3-CI-DIAG || " + " || ".join(diag)) - # --- end diagnostic ----------------------------------------------------- - _assert_lpips_below_threshold(score, COSMOS3_EDGE_T2I_LPIPS_THRESHOLD) diff --git a/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py b/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py index 714d49652d88..e0e702fcdfe4 100644 --- a/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py +++ b/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py @@ -409,6 +409,31 @@ def _cleanup_cuda(): shutdown_compile_workers() +@contextlib.contextmanager +def _lpips_pinned_fp32_matmul_precision(): + """Pin fp32-matmul arithmetic so LPIPS goldens are portable across hosts. + + NGC PyTorch containers default matmul TF32 on (``float32_matmul_precision + == "high"``); PyPI torch defaults it off (``"highest"``). A model with fp32 + GEMMs inside its denoising loop (Cosmos3: the RoPE frequency matmul and the + fp32 timestep embedder) therefore produces a different trajectory under + each default, and a golden cut under one fails under the other -- measured + LPIPS-to-golden moved 0.132 -> 0.054 from this single flag. Pin "highest" + (IEEE fp32, measured bit-stable across torch 2.11/2.12 and B200/B300), and + pin cuDNN TF32 to its universal default so the second knob cannot drift. + bf16 compute -- all of the heavy kernels -- is unaffected by either knob. + """ + previous_precision = torch.get_float32_matmul_precision() + previous_cudnn_tf32 = torch.backends.cudnn.allow_tf32 + try: + torch.set_float32_matmul_precision("highest") + torch.backends.cudnn.allow_tf32 = True + yield + finally: + torch.set_float32_matmul_precision(previous_precision) + torch.backends.cudnn.allow_tf32 = previous_cudnn_tf32 + + @contextlib.contextmanager def _lpips_deterministic_algorithms(*, fully_eager=False): previous_deterministic = torch.are_deterministic_algorithms_enabled() @@ -421,7 +446,7 @@ def _lpips_deterministic_algorithms(*, fully_eager=False): compiler_context = ( torch.compiler.set_stance("force_eager") if fully_eager else contextlib.nullcontext() ) - with compiler_context: + with compiler_context, _lpips_pinned_fp32_matmul_precision(): yield finally: torch.use_deterministic_algorithms( From ccf3fda4062d2673ee4b0f69a27a280383a243cc Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Mon, 17 Aug 2026 15:58:14 -0700 Subject: [PATCH 05/11] [https://nvbugs/6418815][test] Re-baseline Cosmos3 LPIPS goldens under pinned arithmetic Re-cut all seven runnable Cosmos3 goldens with fp32-matmul precision pinned to "highest" (see the previous commit for the root cause: NGC-vs-PyPI TF32 defaults acting on Cosmos3's fp32 GEMM islands). Cut natively on B300 at torch 2.12.0+cu130; under the pin the trajectory measured bit-stable across torch versions and GPU generations, so these goldens are host-portable rather than bound to the golden-cutting container. - nano t2i / t2v: the two stale goldens (cut 2026-06-29, invalidated by the 07-02 negative-prompt default change) -- re-cut and unwaived (nvbugs 6418815, 6437341). - nano v2v, fp8-blockwise, edge t2i/t2v/i2v: previously CI-container-bound; re-cut under the pin. Edge goldens become TRT-LLM self-goldens; cross-stack correctness stays covered by TestDiffusersParity. - Provenance JSONs rewritten with real commit/torch/flags, explicit negative_prompt, and media sha256; first provenance record for v2v. - The other 35 zip members are byte-identical (CRC-verified on repack). - l0_b200.yml gains TEMPORARY pre_merge listings (marked REMOVE BEFORE MERGE) so the post_merge-gated tests run on this PR's pipeline for verification. Out of scope: i2v_4step (checkpoint absent in CI) and nvfp4 (nvbugs/6572800, cross-model break) -- both need a pinned-flags re-cut when unblocked. Signed-off-by: Igor Shovkun --- .../cosmos3_edge_i2v_lpips_golden_video.json | 34 ++++++++++--------- .../cosmos3_edge_t2i_lpips_golden.json | 32 +++++++++-------- .../cosmos3_edge_t2v_lpips_golden_video.json | 31 +++++++++-------- ...smos3_nano_fp8_blockwise_lpips_golden.json | 24 +++++++++---- .../cosmos3_nano_t2i_lpips_golden.json | 18 ++++++---- .../cosmos3_nano_t2v_lpips_golden_video.json | 17 ++++++---- .../cosmos3_nano_v2v_lpips_golden_frame.json | 30 ++++++++++++++++ .../visual_gen_lpips_golden_media.zip | 4 +-- .../test_lists/test-db/l0_b200.yml | 14 +++++--- tests/integration/test_lists/waives.txt | 2 -- 10 files changed, 135 insertions(+), 71 deletions(-) create mode 100644 tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_v2v_lpips_golden_frame.json diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_i2v_lpips_golden_video.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_i2v_lpips_golden_video.json index 00f4e3ececa9..8808e3ebf07a 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_i2v_lpips_golden_video.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_i2v_lpips_golden_video.json @@ -1,27 +1,29 @@ { - "source": "diffusers Cosmos3OmniPipeline on diffusers main (reference implementation, not a TRT-LLM self-golden)", - "diffusers_reference": "huggingface/diffusers#14181 'Cosmos3 edge support' + #14246 'Fix Cosmos3 Edge generator K normalization'", - "diffusers_version": "0.40.0.dev0", - "diffusers_commit": "2919c50968389232c527bdab1a3af69cef01ed07", - "scheduler_override": "UniPCMultistepScheduler.from_config(checkpoint config, use_karras_sigmas=False, flow_shift=3.0). With the checkpoint's use_native_flow_schedule=true this reproduces the cosmos-framework PyTorch backend schedule (fm_solvers_unipc @ 117c7d2) to fp32-ulp: timesteps bit-identical, full synthetic step() trajectories agree to <=1.6e-7 rel (see TestNativeFlowSchedule fixtures). Stock diffusers is NOT used as-is because its karras branch swallows the native flow sigmas.", - "prompt_text_matching": "The golden run passed pre-formatted cond AND uncond texts with add_duration_template=False and add_resolution_template=False. Both texts were produced by TRT-LLM's _format_prompt_with_metadata (keep-metadata negative-prompt semantics, matching cosmos-framework's CLI default rather than diffusers' inverse templates), so both stacks tokenize identical sequences in both CFG branches.", - "model": "Cosmos3-Edge", - "seed": 42, - "generator": "torch.Generator(device='cuda').manual_seed(42); initial latents match TRT-LLM's randn_tensor draw bit-for-bit (same shape/dtype/generator semantics)", - "use_system_prompt": false, - "torch_dtype": "bfloat16", - "lpips_net": "alex", "video": "cosmos3_edge_i2v_lpips_golden_video.mp4", + "model": "Cosmos3-Edge", + "source": "TensorRT-LLM VisualGen (self-golden)", "prompt": "The orange sphere slowly rises while the camera pans right across the scene", - "conditioning_image": "deterministic 832x480 image drawn by _write_cosmos3_edge_conditioning_image in test_visual_gen.py", + "negative_prompt": "", "height": 480, "width": 832, "num_frames": 29, "num_inference_steps": 10, "guidance_scale": 5.0, + "seed": 42, "frame_rate": 24.0, + "conditioning_image": "deterministic 832x480 image drawn by _write_cosmos3_edge_conditioning_image in test_visual_gen_cosmos3.py", + "note": "Regression gate only (TRT-LLM vs itself under pinned arithmetic). Cross-stack correctness vs diffusers is covered by the per-step parity unit test (test_cosmos3_edge.py::TestDiffusersParity).", + "attention_backend": "VANILLA", + "torch_compile": false, + "deterministic_algorithms": false, + "fp32_matmul_precision": "highest", + "cudnn_allow_tf32": true, + "lpips_net": "alex", "lpips_threshold": 0.13, - "measured_lpips_at_creation": 0.0778, - "threshold_rationale": "0.0778 measured cross-stack at 10 steps (I2V accumulates cross-stack drift faster than T2V: 0.1105 at the deployed 50 steps), plus ~0.04 cross-host headroom. The failure signal is far away: a wrong-seed run against this golden measures LPIPS 0.858. The deployed 50-step I2V shape is exercised by test_cosmos3_edge_i2v_example.", - "notes": "Per-step masked-velocity parity vs diffusers is 0.8-1.5 percent rel (noisy frames); diffusers zeroes the conditioned frame's velocity while TRT-LLM masks it in the pipeline - equivalent for the scheduler." + "diffusers_version": "0.39.0", + "torch_version": "2.12.0+cu130", + "tensorrt_llm_version": "1.3.0rc25", + "tensorrt_llm_commit": "a4ed9a9c13a69b3c024debd0d83e12c8c734bf95", + "environment": "Native build, no container; NVIDIA B300 (sm103). Portable by construction: generation pins float32_matmul_precision('highest') (see _lpips_pinned_fp32_matmul_precision), under which the trajectory measured bit-stable across torch 2.11/2.12 and B200/B300.", + "sha256": "1fd9b0ab24de130f593056a32a7b8555fafbbf073b76c29a4633504870b1dad0" } diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2i_lpips_golden.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2i_lpips_golden.json index 0a5331b8bbc1..1afb7f649fc2 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2i_lpips_golden.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2i_lpips_golden.json @@ -1,24 +1,28 @@ { - "source": "diffusers Cosmos3OmniPipeline on diffusers main (reference implementation, not a TRT-LLM self-golden)", - "diffusers_reference": "huggingface/diffusers#14181 'Cosmos3 edge support' + #14246 'Fix Cosmos3 Edge generator K normalization'", - "diffusers_version": "0.40.0.dev0", - "diffusers_commit": "2919c50968389232c527bdab1a3af69cef01ed07", - "scheduler_override": "UniPCMultistepScheduler.from_config(checkpoint config, use_karras_sigmas=False, flow_shift=3.0). With the checkpoint's use_native_flow_schedule=true this reproduces the cosmos-framework PyTorch backend schedule (fm_solvers_unipc @ 117c7d2) to fp32-ulp: timesteps bit-identical, full synthetic step() trajectories agree to <=1.6e-7 rel (see TestNativeFlowSchedule fixtures). Stock diffusers is NOT used as-is because its karras branch swallows the native flow sigmas.", - "prompt_text_matching": "The golden run passed pre-formatted cond AND uncond texts with add_duration_template=False and add_resolution_template=False. Both texts were produced by TRT-LLM's _format_prompt_with_metadata (keep-metadata negative-prompt semantics, matching cosmos-framework's CLI default rather than diffusers' inverse templates), so both stacks tokenize identical sequences in both CFG branches.", - "model": "Cosmos3-Edge", - "seed": 42, - "generator": "torch.Generator(device='cuda').manual_seed(42); initial latents match TRT-LLM's randn_tensor draw bit-for-bit (same shape/dtype/generator semantics)", - "use_system_prompt": false, - "torch_dtype": "bfloat16", - "lpips_net": "alex", "image": "cosmos3_edge_t2i_lpips_golden.png", + "model": "Cosmos3-Edge", + "source": "TensorRT-LLM VisualGen (self-golden)", "prompt": "A ceramic teapot pouring steaming tea into a cup, morning window light", + "negative_prompt": "", "height": 640, "width": 640, "num_frames": 1, "num_inference_steps": 50, "guidance_scale": 4.0, + "seed": 42, + "output_type": "image", + "note": "Regression gate only (TRT-LLM vs itself under pinned arithmetic). Cross-stack correctness vs diffusers is covered by the per-step parity unit test (test_cosmos3_edge.py::TestDiffusersParity).", + "attention_backend": "VANILLA", + "torch_compile": false, + "deterministic_algorithms": false, + "fp32_matmul_precision": "highest", + "cudnn_allow_tf32": true, + "lpips_net": "alex", "lpips_threshold": 0.05, - "measured_lpips_at_creation": 0.0056, - "threshold_rationale": "0.0056 measured cross-stack on B200; 0.05 matches the FLUX/QwenImage image-gate convention." + "diffusers_version": "0.39.0", + "torch_version": "2.12.0+cu130", + "tensorrt_llm_version": "1.3.0rc25", + "tensorrt_llm_commit": "a4ed9a9c13a69b3c024debd0d83e12c8c734bf95", + "environment": "Native build, no container; NVIDIA B300 (sm103). Portable by construction: generation pins float32_matmul_precision('highest') (see _lpips_pinned_fp32_matmul_precision), under which the trajectory measured bit-stable across torch 2.11/2.12 and B200/B300.", + "sha256": "3f7c9b958807356ced2de1734e301dc837fa0b095f8fed1e29da764993926046" } diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2v_lpips_golden_video.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2v_lpips_golden_video.json index 904374e075ef..bf30295845dd 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2v_lpips_golden_video.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2v_lpips_golden_video.json @@ -1,25 +1,28 @@ { - "source": "diffusers Cosmos3OmniPipeline on diffusers main (reference implementation, not a TRT-LLM self-golden)", - "diffusers_reference": "huggingface/diffusers#14181 'Cosmos3 edge support' + #14246 'Fix Cosmos3 Edge generator K normalization'", - "diffusers_version": "0.40.0.dev0", - "diffusers_commit": "2919c50968389232c527bdab1a3af69cef01ed07", - "scheduler_override": "UniPCMultistepScheduler.from_config(checkpoint config, use_karras_sigmas=False, flow_shift=3.0). With the checkpoint's use_native_flow_schedule=true this reproduces the cosmos-framework PyTorch backend schedule (fm_solvers_unipc @ 117c7d2) to fp32-ulp: timesteps bit-identical, full synthetic step() trajectories agree to <=1.6e-7 rel (see TestNativeFlowSchedule fixtures). Stock diffusers is NOT used as-is because its karras branch swallows the native flow sigmas.", - "prompt_text_matching": "The golden run passed pre-formatted cond AND uncond texts with add_duration_template=False and add_resolution_template=False. Both texts were produced by TRT-LLM's _format_prompt_with_metadata (keep-metadata negative-prompt semantics, matching cosmos-framework's CLI default rather than diffusers' inverse templates), so both stacks tokenize identical sequences in both CFG branches.", - "model": "Cosmos3-Edge", - "seed": 42, - "generator": "torch.Generator(device='cuda').manual_seed(42); initial latents match TRT-LLM's randn_tensor draw bit-for-bit (same shape/dtype/generator semantics)", - "use_system_prompt": false, - "torch_dtype": "bfloat16", - "lpips_net": "alex", "video": "cosmos3_edge_t2v_lpips_golden_video.mp4", + "model": "Cosmos3-Edge", + "source": "TensorRT-LLM VisualGen (self-golden)", "prompt": "A red ball rolls across a wooden floor, casting a soft shadow.", + "negative_prompt": "", "height": 480, "width": 832, "num_frames": 29, "num_inference_steps": 50, "guidance_scale": 5.0, + "seed": 42, "frame_rate": 24.0, + "note": "Regression gate only (TRT-LLM vs itself under pinned arithmetic). Cross-stack correctness vs diffusers is covered by the per-step parity unit test (test_cosmos3_edge.py::TestDiffusersParity).", + "attention_backend": "VANILLA", + "torch_compile": false, + "deterministic_algorithms": false, + "fp32_matmul_precision": "highest", + "cudnn_allow_tf32": true, + "lpips_net": "alex", "lpips_threshold": 0.1, - "measured_lpips_at_creation": 0.0447, - "threshold_rationale": "0.0447 measured cross-stack (TRT-LLM VANILLA attention vs diffusers main) on B200 with matched noise and matched CFG texts, plus headroom for the ~0.04 cross-host kernel drift documented in _preserve_lpips_candidate_on_failure." + "diffusers_version": "0.39.0", + "torch_version": "2.12.0+cu130", + "tensorrt_llm_version": "1.3.0rc25", + "tensorrt_llm_commit": "a4ed9a9c13a69b3c024debd0d83e12c8c734bf95", + "environment": "Native build, no container; NVIDIA B300 (sm103). Portable by construction: generation pins float32_matmul_precision('highest') (see _lpips_pinned_fp32_matmul_precision), under which the trajectory measured bit-stable across torch 2.11/2.12 and B200/B300.", + "sha256": "0ec80b5c906ae576deedf8fb48c55edd0c78203138608f12d0c439da11ab6f10" } diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_fp8_blockwise_lpips_golden.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_fp8_blockwise_lpips_golden.json index 0abf4430cc0c..0e91d261f121 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_fp8_blockwise_lpips_golden.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_fp8_blockwise_lpips_golden.json @@ -1,27 +1,37 @@ { "image": "cosmos3_nano_fp8_blockwise_lpips_golden.png", "model": "Cosmos3-Nano", - "source": "TensorRT-LLM VisualGen", + "source": "TensorRT-LLM VisualGen (self-golden)", "prompt": "A serene mountain landscape with snow-capped peaks and a flowing river", + "negative_prompt": "", "height": 720, "width": 1280, "num_frames": 1, "num_inference_steps": 35, "guidance_scale": 6.0, - "frame_rate": 24.0, "seed": 42, + "frame_rate": 24.0, "feature_config": { "quantization": "FP8_BLOCK_SCALES", "cuda_graph": false }, + "quantization_ignore": [ + "language_model.*", + "vae2llm", + "llm2vae", + "time_embedder.*" + ], + "attention_backend": "VANILLA", "torch_compile": false, "deterministic_algorithms": true, + "fp32_matmul_precision": "highest", + "cudnn_allow_tf32": true, "lpips_net": "alex", "lpips_threshold": 0.05, "diffusers_version": "0.39.0", - "torch_version": "2.12.0a0+5aff3928d8.nv26.05", - "tensorrt_llm_version": "1.3.0rc21", - "tensorrt_llm_commit": "b2131b181f5be6717cd302a0b53c22c6a70c65b3", - "container_image": "urm.nvidia.com/sw-tensorrt-docker/tensorrt-llm@sha256:475999862b896593159f10f486e16a748e7b7abb5cee558932a59ea6fc690d6b", - "sha256": "dbdfc83e3a6a038138f4c8e039fa09be8ab11cb308f1534405624523afed73a5" + "torch_version": "2.12.0+cu130", + "tensorrt_llm_version": "1.3.0rc25", + "tensorrt_llm_commit": "a4ed9a9c13a69b3c024debd0d83e12c8c734bf95", + "environment": "Native build, no container; NVIDIA B300 (sm103). Portable by construction: generation pins float32_matmul_precision('highest') (see _lpips_pinned_fp32_matmul_precision), under which the trajectory measured bit-stable across torch 2.11/2.12 and B200/B300.", + "sha256": "32c080983eb8d94d1da5d21378ea87912dadf018f00f15123a33f000640341ad" } diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2i_lpips_golden.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2i_lpips_golden.json index f0bfb8639013..26709e7a249c 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2i_lpips_golden.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2i_lpips_golden.json @@ -1,21 +1,27 @@ { "image": "cosmos3_nano_t2i_lpips_golden.png", "model": "Cosmos3-Nano", - "source": "TensorRT-LLM VisualGen", + "source": "TensorRT-LLM VisualGen (self-golden)", "prompt": "A serene mountain landscape with snow-capped peaks and a flowing river", + "negative_prompt": "", "height": 720, "width": 1280, "num_frames": 1, "num_inference_steps": 35, "guidance_scale": 6.0, "seed": 42, + "frame_rate": 24.0, "attention_backend": "VANILLA", "torch_compile": false, - "deterministic_algorithms": true, + "deterministic_algorithms": false, + "fp32_matmul_precision": "highest", + "cudnn_allow_tf32": true, "lpips_net": "alex", "lpips_threshold": 0.05, - "diffusers_version": "0.38.0", - "tensorrt_llm_version": "1.3.0rc20", - "tensorrt_llm_commit": "85665f5fd331d0154a78172954846d843085e83f", - "container_image": "urm.nvidia.com/sw-tensorrt-docker/tensorrt-llm-staging/release@sha256:3308a2dc0192a8329ea02eca7b5c44f290f5e894cd8c5921099308d84c3e5691" + "diffusers_version": "0.39.0", + "torch_version": "2.12.0+cu130", + "tensorrt_llm_version": "1.3.0rc25", + "tensorrt_llm_commit": "a4ed9a9c13a69b3c024debd0d83e12c8c734bf95", + "environment": "Native build, no container; NVIDIA B300 (sm103). Portable by construction: generation pins float32_matmul_precision('highest') (see _lpips_pinned_fp32_matmul_precision), under which the trajectory measured bit-stable across torch 2.11/2.12 and B200/B300.", + "sha256": "035f3e764e6a36159071178a2d7be6ec3cabc60899736099ff89a59c037e15e1" } diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2v_lpips_golden_video.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2v_lpips_golden_video.json index 450d085268df..dac9da525c0b 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2v_lpips_golden_video.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2v_lpips_golden_video.json @@ -1,8 +1,9 @@ { "video": "cosmos3_nano_t2v_lpips_golden_video.mp4", "model": "Cosmos3-Nano", - "source": "TensorRT-LLM VisualGen", + "source": "TensorRT-LLM VisualGen (self-golden)", "prompt": "A serene mountain landscape with snow-capped peaks and a flowing river", + "negative_prompt": "", "height": 720, "width": 1280, "num_frames": 189, @@ -12,11 +13,15 @@ "frame_rate": 24.0, "attention_backend": "VANILLA", "torch_compile": false, - "deterministic_algorithms": true, + "deterministic_algorithms": false, + "fp32_matmul_precision": "highest", + "cudnn_allow_tf32": true, "lpips_net": "alex", "lpips_threshold": 0.05, - "diffusers_version": "0.38.0", - "tensorrt_llm_version": "1.3.0rc20", - "tensorrt_llm_commit": "85665f5fd331d0154a78172954846d843085e83f", - "container_image": "urm.nvidia.com/sw-tensorrt-docker/tensorrt-llm-staging/release@sha256:3308a2dc0192a8329ea02eca7b5c44f290f5e894cd8c5921099308d84c3e5691" + "diffusers_version": "0.39.0", + "torch_version": "2.12.0+cu130", + "tensorrt_llm_version": "1.3.0rc25", + "tensorrt_llm_commit": "a4ed9a9c13a69b3c024debd0d83e12c8c734bf95", + "environment": "Native build, no container; NVIDIA B300 (sm103). Portable by construction: generation pins float32_matmul_precision('highest') (see _lpips_pinned_fp32_matmul_precision), under which the trajectory measured bit-stable across torch 2.11/2.12 and B200/B300.", + "sha256": "980849ba2f1ff1101c0dce2ac8897172212a614f23c3fb0cc6acbd970dd42976" } diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_v2v_lpips_golden_frame.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_v2v_lpips_golden_frame.json new file mode 100644 index 000000000000..b83ae2c739de --- /dev/null +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_v2v_lpips_golden_frame.json @@ -0,0 +1,30 @@ +{ + "image": "cosmos3_nano_v2v_lpips_golden_frame.png", + "model": "Cosmos3-Nano", + "source": "TensorRT-LLM VisualGen (self-golden)", + "prompt": "A serene mountain landscape with snow-capped peaks and a flowing river", + "negative_prompt": "", + "height": 720, + "width": 1280, + "num_frames": 9, + "num_inference_steps": 35, + "guidance_scale": 6.0, + "seed": 42, + "frame_rate": 24.0, + "free_frame_index": 8, + "conditioning_video": "tests/integration/defs/examples/visual_gen/test_data/cosmos3_v2v_lpips_reference.mp4 (in-repo fixture; H.264 decode is bit-exact by spec, NVDEC output deterministic)", + "note": "First provenance record for this golden; the original (#16155, 2026-08-03) shipped without one.", + "attention_backend": "VANILLA", + "torch_compile": false, + "deterministic_algorithms": false, + "fp32_matmul_precision": "highest", + "cudnn_allow_tf32": true, + "lpips_net": "alex", + "lpips_threshold": 0.05, + "diffusers_version": "0.39.0", + "torch_version": "2.12.0+cu130", + "tensorrt_llm_version": "1.3.0rc25", + "tensorrt_llm_commit": "a4ed9a9c13a69b3c024debd0d83e12c8c734bf95", + "environment": "Native build, no container; NVIDIA B300 (sm103). Portable by construction: generation pins float32_matmul_precision('highest') (see _lpips_pinned_fp32_matmul_precision), under which the trajectory measured bit-stable across torch 2.11/2.12 and B200/B300.", + "sha256": "728c9bed1c25bf7de2b727949cc8c985f0f5bf03fd78e19847f4bcc7edeb450b" +} diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/visual_gen_lpips_golden_media.zip b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/visual_gen_lpips_golden_media.zip index acb2348552ae..7cd47b1e3713 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/visual_gen_lpips_golden_media.zip +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/visual_gen_lpips_golden_media.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69011916707974699428b03ecfad96b96bf76750926452ae2779d62ada23e5b0 -size 34534138 +oid sha256:5810ecc334f9f15f12bb818832e6ff9e6251dcda5c781ff89293b85243022d3d +size 26679909 diff --git a/tests/integration/test_lists/test-db/l0_b200.yml b/tests/integration/test_lists/test-db/l0_b200.yml index 31ede1fb539b..cd716cb309c5 100644 --- a/tests/integration/test_lists/test-db/l0_b200.yml +++ b/tests/integration/test_lists/test-db/l0_b200.yml @@ -15,11 +15,17 @@ l0_b200: backend: pytorch tests: # ------------- PyTorch tests --------------- - # TEMPORARY (DO NOT MERGE): this test is normally post_merge only, so a PR - # pipeline never schedules it and --extra-stage cannot pull it in. Listed here - # so the Cosmos3 golden diagnostic actually runs pre-merge. Remove with the - # diagnostic. + # TEMPORARY (REMOVE BEFORE MERGE): these tests are post_merge-gated, so a PR + # pipeline never schedules them. Listed here only to prove the re-baselined + # goldens pass on the B200 CI lane before merge; the post_merge block below + # remains their permanent home. + - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_nano_t2i_lpips_against_golden TIMEOUT (10) + - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_nano_t2v_lpips_against_golden TIMEOUT (15) + - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_nano_v2v_lpips_against_golden TIMEOUT (10) + - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_feature_accuracy_against_golden[fp8-blockwise] - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_edge_t2i_lpips_against_golden TIMEOUT (15) + - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_edge_t2v_lpips_against_golden TIMEOUT (20) + - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_edge_i2v_lpips_against_golden TIMEOUT (15) - unittest/others/test_kv_cache_transceiver.py::test_cpp_nixl_sync_transfer_stress - accuracy/test_llm_api_pytorch.py::TestLlama3_1_8B::test_nvfp4 - accuracy/test_llm_api_pytorch.py::TestLlama3_1_8B::test_nvfp4_streaming[stream_interval_4] diff --git a/tests/integration/test_lists/waives.txt b/tests/integration/test_lists/waives.txt index 6f4db28bf2b7..ab08d72bd7f8 100644 --- a/tests/integration/test_lists/waives.txt +++ b/tests/integration/test_lists/waives.txt @@ -111,8 +111,6 @@ examples/test_ad_speculative_decoding.py::test_autodeploy_eagle3_one_model_accep examples/test_ray.py::test_ray_disaggregated_serving[tp2] SKIP (https://nvbugs/6601575) examples/test_ray.py::test_ray_disaggregated_serving_python[tp2] SKIP (https://nvbugs/6601574) examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_feature_accuracy_against_golden[nvfp4] SKIP (https://nvbugs/6572800) -examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_nano_t2i_lpips_against_golden SKIP (https://nvbugs/6418815) -examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_nano_t2v_lpips_against_golden SKIP (https://nvbugs/6437341) examples/visual_gen/test_visual_gen_flux.py::test_flux_accuracy_against_golden[flux1-nvfp4] SKIP (https://nvbugs/6572800) examples/visual_gen/test_visual_gen_flux.py::test_flux_accuracy_against_golden[flux2-nvfp4] SKIP (https://nvbugs/6572800) examples/visual_gen/test_visual_gen_ltx2.py::test_ltx2_cuda_graph_trtllm_backend SKIP (https://nvbugs/6463822) From e83a1a54e8a668520824f189e0a0f161326b3005 Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Mon, 17 Aug 2026 21:20:34 -0700 Subject: [PATCH 06/11] [https://nvbugs/6418815][test] Record self-verification scores; drop temporary test listings All seven re-baselined goldens self-verified at LPIPS 0.000000 (bit-exact regeneration under the pinned arithmetic; 7 passed in 19m12s on B300 native, torch 2.12.0+cu130). Record that in the provenance JSONs and remove the temporary pre_merge listings -- the tests return to their permanent post_merge home in l0_b200.yml, which is now identical to main. Signed-off-by: Igor Shovkun --- .../cosmos3_edge_i2v_lpips_golden_video.json | 2 ++ .../cosmos3_edge_t2i_lpips_golden.json | 2 ++ .../cosmos3_edge_t2v_lpips_golden_video.json | 2 ++ .../cosmos3_nano_fp8_blockwise_lpips_golden.json | 2 ++ .../cosmos3_nano_t2i_lpips_golden.json | 2 ++ .../cosmos3_nano_t2v_lpips_golden_video.json | 2 ++ .../cosmos3_nano_v2v_lpips_golden_frame.json | 2 ++ tests/integration/test_lists/test-db/l0_b200.yml | 11 ----------- 8 files changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_i2v_lpips_golden_video.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_i2v_lpips_golden_video.json index 8808e3ebf07a..596e180410bb 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_i2v_lpips_golden_video.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_i2v_lpips_golden_video.json @@ -20,6 +20,8 @@ "cudnn_allow_tf32": true, "lpips_net": "alex", "lpips_threshold": 0.13, + "measured_lpips_at_creation": 0.0, + "threshold_rationale": "self-regeneration distance on the cutting host; threshold kept at the pre-existing gate for this test", "diffusers_version": "0.39.0", "torch_version": "2.12.0+cu130", "tensorrt_llm_version": "1.3.0rc25", diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2i_lpips_golden.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2i_lpips_golden.json index 1afb7f649fc2..92ad6e4ba1f3 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2i_lpips_golden.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2i_lpips_golden.json @@ -19,6 +19,8 @@ "cudnn_allow_tf32": true, "lpips_net": "alex", "lpips_threshold": 0.05, + "measured_lpips_at_creation": 0.0, + "threshold_rationale": "self-regeneration distance on the cutting host; threshold kept at the pre-existing gate for this test", "diffusers_version": "0.39.0", "torch_version": "2.12.0+cu130", "tensorrt_llm_version": "1.3.0rc25", diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2v_lpips_golden_video.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2v_lpips_golden_video.json index bf30295845dd..3b053b41ad68 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2v_lpips_golden_video.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_edge_t2v_lpips_golden_video.json @@ -19,6 +19,8 @@ "cudnn_allow_tf32": true, "lpips_net": "alex", "lpips_threshold": 0.1, + "measured_lpips_at_creation": 0.0, + "threshold_rationale": "self-regeneration distance on the cutting host; threshold kept at the pre-existing gate for this test", "diffusers_version": "0.39.0", "torch_version": "2.12.0+cu130", "tensorrt_llm_version": "1.3.0rc25", diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_fp8_blockwise_lpips_golden.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_fp8_blockwise_lpips_golden.json index 0e91d261f121..55d4cf08a551 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_fp8_blockwise_lpips_golden.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_fp8_blockwise_lpips_golden.json @@ -28,6 +28,8 @@ "cudnn_allow_tf32": true, "lpips_net": "alex", "lpips_threshold": 0.05, + "measured_lpips_at_creation": 0.0, + "threshold_rationale": "self-regeneration distance on the cutting host; threshold kept at the pre-existing gate for this test", "diffusers_version": "0.39.0", "torch_version": "2.12.0+cu130", "tensorrt_llm_version": "1.3.0rc25", diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2i_lpips_golden.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2i_lpips_golden.json index 26709e7a249c..c09d9cc280a0 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2i_lpips_golden.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2i_lpips_golden.json @@ -18,6 +18,8 @@ "cudnn_allow_tf32": true, "lpips_net": "alex", "lpips_threshold": 0.05, + "measured_lpips_at_creation": 0.0, + "threshold_rationale": "self-regeneration distance on the cutting host; threshold kept at the pre-existing gate for this test", "diffusers_version": "0.39.0", "torch_version": "2.12.0+cu130", "tensorrt_llm_version": "1.3.0rc25", diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2v_lpips_golden_video.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2v_lpips_golden_video.json index dac9da525c0b..ee6014644db1 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2v_lpips_golden_video.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_t2v_lpips_golden_video.json @@ -18,6 +18,8 @@ "cudnn_allow_tf32": true, "lpips_net": "alex", "lpips_threshold": 0.05, + "measured_lpips_at_creation": 0.0, + "threshold_rationale": "self-regeneration distance on the cutting host; threshold kept at the pre-existing gate for this test", "diffusers_version": "0.39.0", "torch_version": "2.12.0+cu130", "tensorrt_llm_version": "1.3.0rc25", diff --git a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_v2v_lpips_golden_frame.json b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_v2v_lpips_golden_frame.json index b83ae2c739de..636b8c3b484f 100644 --- a/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_v2v_lpips_golden_frame.json +++ b/tests/integration/defs/examples/visual_gen/golden/visual_gen_lpips/cosmos3_nano_v2v_lpips_golden_frame.json @@ -21,6 +21,8 @@ "cudnn_allow_tf32": true, "lpips_net": "alex", "lpips_threshold": 0.05, + "measured_lpips_at_creation": 0.0, + "threshold_rationale": "self-regeneration distance on the cutting host; threshold kept at the pre-existing gate for this test", "diffusers_version": "0.39.0", "torch_version": "2.12.0+cu130", "tensorrt_llm_version": "1.3.0rc25", diff --git a/tests/integration/test_lists/test-db/l0_b200.yml b/tests/integration/test_lists/test-db/l0_b200.yml index cd716cb309c5..0ca143964ea6 100644 --- a/tests/integration/test_lists/test-db/l0_b200.yml +++ b/tests/integration/test_lists/test-db/l0_b200.yml @@ -15,17 +15,6 @@ l0_b200: backend: pytorch tests: # ------------- PyTorch tests --------------- - # TEMPORARY (REMOVE BEFORE MERGE): these tests are post_merge-gated, so a PR - # pipeline never schedules them. Listed here only to prove the re-baselined - # goldens pass on the B200 CI lane before merge; the post_merge block below - # remains their permanent home. - - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_nano_t2i_lpips_against_golden TIMEOUT (10) - - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_nano_t2v_lpips_against_golden TIMEOUT (15) - - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_nano_v2v_lpips_against_golden TIMEOUT (10) - - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_feature_accuracy_against_golden[fp8-blockwise] - - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_edge_t2i_lpips_against_golden TIMEOUT (15) - - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_edge_t2v_lpips_against_golden TIMEOUT (20) - - examples/visual_gen/test_visual_gen_cosmos3.py::test_cosmos3_edge_i2v_lpips_against_golden TIMEOUT (15) - unittest/others/test_kv_cache_transceiver.py::test_cpp_nixl_sync_transfer_stress - accuracy/test_llm_api_pytorch.py::TestLlama3_1_8B::test_nvfp4 - accuracy/test_llm_api_pytorch.py::TestLlama3_1_8B::test_nvfp4_streaming[stream_interval_4] From c859d388d3518b025487c8ea107604e60c146a46 Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Mon, 17 Aug 2026 22:21:52 -0700 Subject: [PATCH 07/11] [https://nvbugs/6418815][test] Pin fp32-matmul precision in the LPIPS scorer subprocess too The evaluator runs as a subprocess of _run_lpips_eval, so the parent's torch flags do not propagate (unlike CUBLAS_WORKSPACE_CONFIG, which travels via the environment). Pin the same arithmetic in the child so the scoring half of the path cannot inherit host defaults either. No behavioral change for the committed goldens: the LPIPS net is convolution-only under cuDNN whose TF32 flag already defaulted identically everywhere, and LPIPS of identical inputs is exactly zero under any arithmetic. Addresses CodeRabbit review on PR #17780. Signed-off-by: Igor Shovkun --- scripts/visualgen_eval/visual_gen_lpips_score_eval.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/visualgen_eval/visual_gen_lpips_score_eval.py b/scripts/visualgen_eval/visual_gen_lpips_score_eval.py index 9697655f72ea..bb7d926a4daa 100644 --- a/scripts/visualgen_eval/visual_gen_lpips_score_eval.py +++ b/scripts/visualgen_eval/visual_gen_lpips_score_eval.py @@ -762,6 +762,14 @@ def _evaluate(args: argparse.Namespace) -> dict[str, Any]: def main() -> None: + # Pin fp32-matmul arithmetic for scoring, mirroring the generation-side pin + # (_lpips_pinned_fp32_matmul_precision in visual_gen_test_utils.py). This + # script runs as a subprocess, so the parent's torch flags do not propagate; + # without the pin the scorer inherits the host default, which differs + # between NGC containers (TF32 on) and PyPI torch (TF32 off). + torch.set_float32_matmul_precision("highest") + torch.backends.cudnn.allow_tf32 = True + args = parse_args() result = _evaluate(args) From b110883621c2dc16a37a7169ae2c7256dfa9ef1e Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Tue, 18 Aug 2026 21:23:47 -0700 Subject: [PATCH 08/11] [https://nvbugs/6418815][test] Scope the fp32-matmul pin to Cosmos3 only _lpips_deterministic_algorithms wraps generation, not just scoring, for LTX-2 (148, 247), HunyuanVideo (71), FLUX (139, 170), QwenImage (250) and WAN (339) as well as Cosmos3. Pinning inside it therefore changed generation for five model families whose goldens this PR does not re-cut, and the change is invisible outside an NGC container -- on PyPI torch "highest" is already the default, so a local run cannot detect it, and every one of those golden tests is post_merge-gated. Apply the pin per generation path instead. Cosmos3's three pipelines already did so explicitly; add it to the feature-accuracy path and drop it from the shared helper, which returns byte-identical to main. Blast radius now equals the goldens this PR re-cuts. Note this also leaves the NVFP4 feature path unpinned: it generates in a spawned process via _run_single_device_feature_generator, reaching the shared helper rather than the Cosmos3 module. That matches scope -- the nvfp4 golden is waived under nvbugs/6572800 and is not re-cut here -- and should be pinned whenever that golden is re-cut. All seven re-baselined goldens re-verified after the change: LPIPS 0.000000 each, 7 passed in 13:16 (B300, torch 2.12.0+cu130). Addresses review feedback on PR #17780. Signed-off-by: Igor Shovkun --- .../examples/visual_gen/test_visual_gen_cosmos3.py | 6 +++++- .../examples/visual_gen/visual_gen_test_utils.py | 13 ++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py index c2cb50580c41..03f3e8d516ee 100644 --- a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py +++ b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py @@ -249,7 +249,11 @@ def _generate_cosmos3_feature_image(case, output_path): model_path = _lpips_model_path(COSMOS3_NANO_MODEL_SUBPATH) _skip_if_missing(model_path, "Cosmos3-Nano checkpoint", is_dir=True) _disable_inductor_compile_worker_quiesce() - with _lpips_deterministic_algorithms(), _fixed_nvfp4_quantization_backend(case.features): + with ( + _lpips_deterministic_algorithms(), + _lpips_pinned_fp32_matmul_precision(), + _fixed_nvfp4_quantization_backend(case.features), + ): args = _build_single_device_feature_args( model_path, case.features, diff --git a/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py b/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py index e0e702fcdfe4..856782a3123e 100644 --- a/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py +++ b/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py @@ -415,13 +415,20 @@ def _lpips_pinned_fp32_matmul_precision(): NGC PyTorch containers default matmul TF32 on (``float32_matmul_precision == "high"``); PyPI torch defaults it off (``"highest"``). A model with fp32 - GEMMs inside its denoising loop (Cosmos3: the RoPE frequency matmul and the - fp32 timestep embedder) therefore produces a different trajectory under + GEMMs inside its denoising loop (Cosmos3: the RoPE frequency matmul, the + fp32 timestep embedder, and the fp32 autocast block in + ``transformer_cosmos3.py``) therefore produces a different trajectory under each default, and a golden cut under one fails under the other -- measured LPIPS-to-golden moved 0.132 -> 0.054 from this single flag. Pin "highest" (IEEE fp32, measured bit-stable across torch 2.11/2.12 and B200/B300), and pin cuDNN TF32 to its universal default so the second knob cannot drift. bf16 compute -- all of the heavy kernels -- is unaffected by either knob. + + Applied per generation path rather than from + ``_lpips_deterministic_algorithms``: that helper also wraps generation for + LTX-2, HunyuanVideo, FLUX, QwenImage and WAN, whose goldens were cut + without the pin and are not re-baselined here. Keep the blast radius equal + to the goldens a change actually re-cuts. """ previous_precision = torch.get_float32_matmul_precision() previous_cudnn_tf32 = torch.backends.cudnn.allow_tf32 @@ -446,7 +453,7 @@ def _lpips_deterministic_algorithms(*, fully_eager=False): compiler_context = ( torch.compiler.set_stance("force_eager") if fully_eager else contextlib.nullcontext() ) - with compiler_context, _lpips_pinned_fp32_matmul_precision(): + with compiler_context: yield finally: torch.use_deterministic_algorithms( From 1e551f0cec3e2f028eab9332364c410f212f4086 Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Tue, 18 Aug 2026 21:29:45 -0700 Subject: [PATCH 09/11] [https://nvbugs/6418815][test] Leave the i2v_4step path unpinned The pin reached _run_cosmos3_i2v_4step_lpips_pipeline, but this PR declares i2v_4step out of scope and does not re-cut its golden. That golden is also a diffusers cross-stack reference (Cosmos3DistilledModularPipeline, measured 0.0563 against a 0.10 threshold) whose provenance records torch_dtype and the RNG patch but no fp32-matmul state and no container digest -- so whether pinning improves or degrades agreement with it cannot be determined from what is recorded. Leave the path unpinned so the pin does not silently change a test this PR says it is not touching. The test is skipped in CI today (checkpoint absent from the models root), and the path should be pinned when the golden is re-cut and the flag can be recorded alongside it. Does not affect the seven re-baselined goldens: they are produced by _run_cosmos3_lpips_pipeline, the feature-accuracy path, and _run_cosmos3_edge_lpips_pipeline, all of which keep their explicit pins. Addresses review feedback on PR #17780. Signed-off-by: Igor Shovkun --- .../defs/examples/visual_gen/test_visual_gen_cosmos3.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py index 03f3e8d516ee..5977d8931fad 100644 --- a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py +++ b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py @@ -576,7 +576,13 @@ def _run_cosmos3_i2v_4step_lpips_pipeline(image_path): ) pipeline = PipelineLoader(args).load(skip_warmup=True) try: - with torch.no_grad(), _lpips_pinned_fp32_matmul_precision(): + # Deliberately NOT pinned with _lpips_pinned_fp32_matmul_precision: + # this golden is a diffusers cross-stack reference whose provenance + # records no fp32-matmul state, so whether pinning improves or + # degrades agreement is unknown. The test is skipped in CI anyway + # (checkpoint absent), and its golden is not re-cut here. Pin this + # path when the golden is re-cut and the flag can be recorded. + with torch.no_grad(): result = pipeline.forward( prompt=COSMOS3_I2V_4STEP_LPIPS_PROMPT, # The goldens were generated against an empty uncond branch, From 69544cb86f403f592c344d1c78930fea7a38e573 Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Tue, 18 Aug 2026 21:34:34 -0700 Subject: [PATCH 10/11] [https://nvbugs/6418815][test] Annotate the fp32-matmul pin contextmanager Add the -> Iterator[None] return annotation, matching the repo's convention for contextmanager generators (visual_gen/profiler.py:156, flux/pipeline_flux2.py:582). Addresses CodeRabbit review on PR #17780. Signed-off-by: Igor Shovkun --- .../defs/examples/visual_gen/visual_gen_test_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py b/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py index 856782a3123e..14bc3c16a24d 100644 --- a/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py +++ b/tests/integration/defs/examples/visual_gen/visual_gen_test_utils.py @@ -26,7 +26,7 @@ import traceback import zipfile from dataclasses import dataclass -from typing import Collection, Literal +from typing import Collection, Iterator, Literal import pytest import torch @@ -410,7 +410,7 @@ def _cleanup_cuda(): @contextlib.contextmanager -def _lpips_pinned_fp32_matmul_precision(): +def _lpips_pinned_fp32_matmul_precision() -> Iterator[None]: """Pin fp32-matmul arithmetic so LPIPS goldens are portable across hosts. NGC PyTorch containers default matmul TF32 on (``float32_matmul_precision From 1fc46d18c23afe78ebbf42060bdeb4c41fb3dc97 Mon Sep 17 00:00:00 2001 From: Igor Shovkun Date: Tue, 18 Aug 2026 21:43:11 -0700 Subject: [PATCH 11/11] [https://nvbugs/6418815][test] Do not pin the NVFP4 feature profile Correcting b110883621, whose message claimed the rescope left the NVFP4 path unpinned. It did not. _run_single_device_feature_generator spawns a process for NVFP4, but the child calls the same _generate_cosmos3_feature_image, so the pin added there applied to NVFP4 too -- against a golden that is waived (nvbugs/6572800) and not re-cut in this PR. Make the precision context conditional on the profile so it covers only fp8-blockwise, whose golden is re-baselined here. The guard has to live inside the generator rather than at the call site, precisely because the spawned child re-enters that function. Pin the NVFP4 path when its golden is re-cut. Signed-off-by: Igor Shovkun --- .../examples/visual_gen/test_visual_gen_cosmos3.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py index 5977d8931fad..290028266292 100644 --- a/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py +++ b/tests/integration/defs/examples/visual_gen/test_visual_gen_cosmos3.py @@ -15,6 +15,7 @@ """Single-GPU integration and accuracy tests for Cosmos3.""" +import contextlib import os from dataclasses import dataclass @@ -249,9 +250,20 @@ def _generate_cosmos3_feature_image(case, output_path): model_path = _lpips_model_path(COSMOS3_NANO_MODEL_SUBPATH) _skip_if_missing(model_path, "Cosmos3-Nano checkpoint", is_dir=True) _disable_inductor_compile_worker_quiesce() + # Pin fp32-matmul arithmetic only for the profiles whose goldens are + # re-baselined under it. NVFP4's golden is waived (nvbugs/6572800) and + # not re-cut here, so it keeps generating under the host default; pin + # it when that golden is re-cut. Note the NVFP4 profile reaches this + # same function inside a spawned process, so the guard has to be here + # rather than at the call site. + precision_context = ( + contextlib.nullcontext() + if case.features.quantization == "NVFP4" + else _lpips_pinned_fp32_matmul_precision() + ) with ( _lpips_deterministic_algorithms(), - _lpips_pinned_fp32_matmul_precision(), + precision_context, _fixed_nvfp4_quantization_backend(case.features), ): args = _build_single_device_feature_args(