Skip to content

Commit 25a994b

Browse files
authored
fix(model): disable cuBLAS TF32 in the DiffusionGemma FP32 parity scripts (#6486)
Signed-off-by: Pruthviraj Prakash <pruprakash@nvidia.com>
1 parent 30efd79 commit 25a994b

6 files changed

Lines changed: 117 additions & 10 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Strict FP32 setup shared by the DiffusionGemma parity examples."""
16+
17+
import os
18+
19+
import torch
20+
21+
22+
def disable_tf32() -> bool:
23+
"""Disable TF32 in PyTorch and in cuBLAS-backed libraries such as Transformer Engine."""
24+
os.environ["NVIDIA_TF32_OVERRIDE"] = "0"
25+
torch.backends.cuda.matmul.allow_tf32 = False
26+
torch.backends.cudnn.allow_tf32 = False
27+
return tf32_disabled()
28+
29+
30+
def tf32_disabled() -> bool:
31+
"""Return whether TF32 is off for PyTorch matmul, cuDNN and cuBLAS-backed libraries."""
32+
return (
33+
os.environ.get("NVIDIA_TF32_OVERRIDE") == "0"
34+
and not torch.backends.cuda.matmul.allow_tf32
35+
and not torch.backends.cudnn.allow_tf32
36+
)

‎examples/models/diffusion_gemma/real_encoder_parity.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import torch
2525
import torch.distributed as dist
26+
from fp32_precision import disable_tf32, tf32_disabled
2627
from megatron.core.transformer.enums import AttnBackend
2728
from megatron.core.utils import unwrap_model
2829
from PIL import Image
@@ -396,8 +397,7 @@ def main() -> None:
396397

397398
dist.init_process_group("nccl")
398399
torch.cuda.set_device(0)
399-
torch.backends.cuda.matmul.allow_tf32 = False
400-
torch.backends.cudnn.allow_tf32 = False
400+
disable_tf32()
401401

402402
processor = AutoProcessor.from_pretrained(args.model_path, local_files_only=True)
403403
cases = encode_cases(processor)
@@ -542,7 +542,7 @@ def main() -> None:
542542
"ep": 1,
543543
"dtype": "bfloat16",
544544
"attention_backend": "unfused",
545-
"tf32_disabled": True,
545+
"tf32_disabled": tf32_disabled(),
546546
"thresholds": {"min_token_cosine": args.min_token_cosine, "max_relative_l2": args.max_relative_l2},
547547
"cases": results,
548548
"vision_diagnostics": vision_diagnostics,

‎examples/models/diffusion_gemma/real_fp32_parity.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import torch
2424
import torch.distributed as dist
25+
from fp32_precision import disable_tf32
2526
from megatron.core.transformer.enums import AttnBackend
2627
from megatron.core.utils import unwrap_model
2728
from real_encoder_parity import compare, device_inputs, encode_cases, native_hf_masks
@@ -106,8 +107,7 @@ def main() -> None:
106107

107108
dist.init_process_group("nccl")
108109
torch.cuda.set_device(0)
109-
torch.backends.cuda.matmul.allow_tf32 = False
110-
torch.backends.cudnn.allow_tf32 = False
110+
disable_tf32()
111111

112112
processor = AutoProcessor.from_pretrained(args.model_path, local_files_only=True)
113113
cases = encode_cases(processor)

‎examples/models/diffusion_gemma/toy_parity.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import torch
2424
import torch.distributed as dist
25+
from fp32_precision import disable_tf32, tf32_disabled
2526
from megatron.core.transformer.enums import AttnBackend
2627
from transformers.models.diffusion_gemma import DiffusionGemmaConfig, DiffusionGemmaForBlockDiffusion
2728

@@ -141,8 +142,7 @@ def main() -> None:
141142
dist.init_process_group("nccl")
142143
torch.cuda.set_device(0)
143144
torch.manual_seed(1234)
144-
torch.backends.cuda.matmul.allow_tf32 = False
145-
torch.backends.cudnn.allow_tf32 = False
145+
disable_tf32()
146146

147147
with tempfile.TemporaryDirectory() as tmp:
148148
model_dir = Path(tmp) / "diffusiongemma-toy"
@@ -279,7 +279,7 @@ def main() -> None:
279279
"decoder": decoder_results,
280280
"atol": args.atol,
281281
"attention_backend": args.attention_backend,
282-
"tf32_disabled": True,
282+
"tf32_disabled": tf32_disabled(),
283283
"passed": all(case["encoder_max_abs_diff"] <= args.atol for case in results.values())
284284
and all(case["relative_l2"] <= 0.001 for case in decoder_results.values()),
285285
}

‎examples/models/diffusion_gemma/toy_training_parity.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import torch
3333
import torch.distributed as dist
34+
from fp32_precision import disable_tf32
3435
from megatron.core.transformer.enums import AttnBackend
3536
from real_encoder_parity import compare_layer0, hf_layer0_trace, megatron_layer0_trace
3637
from toy_parity import image_case, native_hf_encoder_inputs, toy_config
@@ -351,8 +352,7 @@ def main() -> None:
351352
dist.init_process_group("nccl")
352353
torch.cuda.set_device(int(os.environ.get("LOCAL_RANK", "0")))
353354
torch.manual_seed(1234)
354-
torch.backends.cuda.matmul.allow_tf32 = False
355-
torch.backends.cudnn.allow_tf32 = False
355+
disable_tf32()
356356

357357
shared_dir = [tempfile.mkdtemp(prefix="diffusiongemma-toy-") if dist.get_rank() == 0 else None]
358358
dist.broadcast_object_list(shared_dir, src=0)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import importlib.util
16+
import os
17+
from pathlib import Path
18+
19+
import pytest
20+
import torch
21+
22+
23+
pytestmark = pytest.mark.unit
24+
25+
EXAMPLE_DIR = Path(__file__).resolve().parents[3] / "examples" / "models" / "diffusion_gemma"
26+
PARITY_SCRIPTS = ("toy_parity.py", "toy_training_parity.py", "real_encoder_parity.py", "real_fp32_parity.py")
27+
28+
29+
def _load_fp32_precision():
30+
spec = importlib.util.spec_from_file_location("fp32_precision", EXAMPLE_DIR / "fp32_precision.py")
31+
module = importlib.util.module_from_spec(spec)
32+
spec.loader.exec_module(module)
33+
return module
34+
35+
36+
@pytest.fixture
37+
def tf32_state():
38+
matmul, cudnn = torch.backends.cuda.matmul.allow_tf32, torch.backends.cudnn.allow_tf32
39+
override = os.environ.pop("NVIDIA_TF32_OVERRIDE", None)
40+
yield
41+
os.environ.pop("NVIDIA_TF32_OVERRIDE", None)
42+
if override is not None:
43+
os.environ["NVIDIA_TF32_OVERRIDE"] = override
44+
torch.backends.cuda.matmul.allow_tf32, torch.backends.cudnn.allow_tf32 = matmul, cudnn
45+
46+
47+
def test_disable_tf32_also_disables_cublas_tf32(tf32_state):
48+
fp32_precision = _load_fp32_precision()
49+
torch.backends.cuda.matmul.allow_tf32 = True
50+
torch.backends.cudnn.allow_tf32 = True
51+
52+
assert fp32_precision.disable_tf32() is True
53+
assert os.environ["NVIDIA_TF32_OVERRIDE"] == "0"
54+
assert torch.backends.cuda.matmul.allow_tf32 is False
55+
assert torch.backends.cudnn.allow_tf32 is False
56+
57+
58+
def test_torch_flags_alone_do_not_count_as_tf32_disabled(tf32_state):
59+
fp32_precision = _load_fp32_precision()
60+
torch.backends.cuda.matmul.allow_tf32 = False
61+
torch.backends.cudnn.allow_tf32 = False
62+
63+
assert fp32_precision.tf32_disabled() is False
64+
65+
66+
@pytest.mark.parametrize("script", PARITY_SCRIPTS)
67+
def test_parity_scripts_disable_tf32_through_the_shared_helper(script):
68+
source = (EXAMPLE_DIR / script).read_text()
69+
70+
assert "disable_tf32()" in source
71+
assert "allow_tf32 = False" not in source

0 commit comments

Comments
 (0)