pytorch - ✅(Solved) Fix grid_sample` backward silently non-deterministic under `use_deterministic_algorithms(True) [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
pytorch/pytorch#179338Fetched 2026-04-08 02:43:35
View on GitHub
Comments
1
Participants
2
Timeline
82
Reactions
0
Author
Participants
Timeline (top)
mentioned ×36subscribed ×36labeled ×7cross-referenced ×2

Error Message

Max gradient diff: 2.441406e-04

Fix Action

Fix / Workaround

CPU: Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 52 bits physical, 57 bits virtual Byte Order: Little Endian CPU(s): 240 On-line CPU(s) list: 0-239 Vendor ID: GenuineIntel Model name: INTEL(R) XEON(R) PLATINUM 8580 CPU family: 6 Model: 207 Thread(s) per core: 2 Core(s) per socket: 60 Socket(s): 2 Stepping: 2 CPU max MHz: 2000.0000 CPU min MHz: 800.0000 BogoMIPS: 4000.00 Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities Virtualization: VT-x L1d cache: 5.6 MiB (120 instances) L1i cache: 3.8 MiB (120 instances) L2 cache: 240 MiB (120 instances) L3 cache: 600 MiB (2 instances) NUMA node(s): 4 NUMA node0 CPU(s): 0-29,120-149 NUMA node1 CPU(s): 30-59,150-179 NUMA node2 CPU(s): 60-89,180-209 NUMA node3 CPU(s): 90-119,210-239 Vulnerability Gather data sampling: Not affected Vulnerability Itlb multihit: Not affected Vulnerability L1tf: Not affected Vulnerability Mds: Not affected Vulnerability Meltdown: Not affected Vulnerability Mmio stale data: Not affected Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Not affected Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; RSB filling; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Not affected

PR fix notes

PR #179369: [MPS] Add deterministic guard for grid_sample backward

Description (problem / solution / changelog)

Description

This PR addresses silent non-determinism in grid_sample backward on the MPS backend (referencing #179338).

While CUDA has explicit guards in GridSampler.cu, the MPS implementation was previously missing a backward dispatch, likely falling back to generic kernels without deterministic checks. This PR adds a guarded entry point for MPS to ensure torch.use_deterministic_algorithms(True) is respected.

Testing

  • Verified via source code analysis that alertNotDeterministic was missing from aten/src/ATen/native/mps/operations/GridSampler.mm.
  • Added a stub for grid_sampler_2d_backward_mps that triggers the required alert.

Changed files

  • aten/src/ATen/native/mps/operations/GridSampler.mm (modified, +19/-0)
  • aten/src/ATen/native/native_functions.yaml (modified, +2/-1)

PR #180417: Properly error determnisitc mode for grid sample

Description (problem / solution / changelog)

Stack from ghstack (oldest at bottom):

  • -> #180417

TLDR: we were erroring on our inhouse kernel but the error was not on the cudnn path, and from local testing it indeed is not deterministic

Fixes #179338

Changed files

  • aten/src/ATen/native/cudnn/GridSampler.cpp (modified, +2/-0)
  • test/test_torch.py (modified, +16/-0)

Code Example

import os
os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8"
import torch
import torch.nn as nn
import torch.nn.functional as F

torch.use_deterministic_algorithms(True)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
torch.backends.cuda.matmul.allow_tf32 = False
torch.backends.cudnn.allow_tf32 = False

# Bug 1: Should throw RuntimeError but doesn't
x = torch.randn(4, 1, 16, 16, device='cuda', requires_grad=True)
grid = torch.rand(4, 1, 81, 2, device='cuda') * 2 - 1
out = F.grid_sample(x, grid, align_corners=True)
out.sum().backward()  # No error raised

# Bug 2: Gradients differ between identical runs
grads = []
for run in range(2):
    torch.manual_seed(0)
    torch.cuda.manual_seed_all(0)

    conv = nn.Conv2d(3, 64, 7, stride=8, padding=3).cuda()
    x = torch.randn(2, 3, 256, 256, device='cuda')
    feat = conv(x)

    f2 = torch.randn(2, 64, 16, 16, device='cuda')
    corr = torch.matmul(
        feat.view(2, 64, -1).transpose(1, 2),
        f2.view(2, 64, -1),
    ).view(2048, 1, 16, 16)

    grid = torch.rand(2048, 1, 81, 2, device='cuda') * 2 - 1
    F.grid_sample(corr, grid, align_corners=True).sum().backward()
    grads.append(conv.weight.grad.clone())

diff = (grads[0] - grads[1]).abs().max().item()
print(f"Max gradient diff: {diff:.6e}")  # ~2.4e-04, should be 0.0

---

Max gradient diff: 2.441406e-04
RAW_BUFFERClick to expand / collapse

🐛 Describe the bug

Bug

F.grid_sample backward on CUDA runs without raising RuntimeError when torch.use_deterministic_algorithms(True) is set, despite being documented as an operation that should throw. The backward then produces non-deterministic gradients (~2e-4 max abs diff) between identical runs.

Expected behavior

Per the docs, torch.nn.functional.grid_sample() when attempting to differentiate a CUDA tensor should throw RuntimeError under use_deterministic_algorithms(True):

The following normally-nondeterministic operations will throw a RuntimeError when mode=True: ... torch.nn.functional.grid_sample() when attempting to differentiate a CUDA tensor

Instead, backward completes silently and produces different gradients across runs with identical seeds and inputs.

Minimal reproduction

import os
os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8"
import torch
import torch.nn as nn
import torch.nn.functional as F

torch.use_deterministic_algorithms(True)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
torch.backends.cuda.matmul.allow_tf32 = False
torch.backends.cudnn.allow_tf32 = False

# Bug 1: Should throw RuntimeError but doesn't
x = torch.randn(4, 1, 16, 16, device='cuda', requires_grad=True)
grid = torch.rand(4, 1, 81, 2, device='cuda') * 2 - 1
out = F.grid_sample(x, grid, align_corners=True)
out.sum().backward()  # No error raised

# Bug 2: Gradients differ between identical runs
grads = []
for run in range(2):
    torch.manual_seed(0)
    torch.cuda.manual_seed_all(0)

    conv = nn.Conv2d(3, 64, 7, stride=8, padding=3).cuda()
    x = torch.randn(2, 3, 256, 256, device='cuda')
    feat = conv(x)

    f2 = torch.randn(2, 64, 16, 16, device='cuda')
    corr = torch.matmul(
        feat.view(2, 64, -1).transpose(1, 2),
        f2.view(2, 64, -1),
    ).view(2048, 1, 16, 16)

    grid = torch.rand(2048, 1, 81, 2, device='cuda') * 2 - 1
    F.grid_sample(corr, grid, align_corners=True).sum().backward()
    grads.append(conv.weight.grad.clone())

diff = (grads[0] - grads[1]).abs().max().item()
print(f"Max gradient diff: {diff:.6e}")  # ~2.4e-04, should be 0.0

Observed behavior

Max gradient diff: 2.441406e-04

No RuntimeError raised. Gradients differ by ~2e-4 between two identical runs in the same process, same GPU.

Note: Replacing the random grid with uniform coordinates (torch.zeros(...)) makes it deterministic — the non-determinism is triggered specifically by non-uniform grid coordinates across the batch dimension.

Environment

Tested across multiple versions — same result on all:

PyTorchCUDAcuDNNGPUResult
2.0.111.88.7.0H200Non-deterministic, no error
2.1.212.18.9.02H200Non-deterministic, no error
2.4.112.49.1.0H200Non-deterministic, no error
2.11.012.69.10.02H200Non-deterministic, no error

Not yet tested on A100/V100.

Impact

Any model that uses F.grid_sample in its forward pass (e.g., RAFT, optical flow networks, spatial transformers, homography estimation) cannot achieve deterministic training on CUDA, even with all deterministic flags properly configured. Users get no warning — the operation silently produces different results.

Additional context

  • grid_sample forward is deterministic — only backward is affected
  • The non-determinism scales with gradient magnitude (~1e-5 relative error)
  • Uniform grids (all batch elements sample the same coordinates) are deterministic; non-uniform grids (each batch element samples different coordinates) are not
  • The effect is independent of spatial size, batch size, and number of sample points

Versions

Collecting environment information... PyTorch version: 2.4.1+cu124 Is debug build: False CUDA used to build PyTorch: 12.4 ROCM used to build PyTorch: N/A

OS: Ubuntu 22.04.5 LTS (x86_64) GCC version: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 Clang version: Could not collect CMake version: version 3.22.1 Libc version: glibc-2.35

Python version: 3.11.14 (main, Feb 3 2026, 22:51:56) [Clang 21.1.4 ] (64-bit runtime) Python platform: Linux-5.15.0-139-generic-x86_64-with-glibc2.35 Is CUDA available: False CUDA runtime version: 11.5.119 CUDA_MODULE_LOADING set to: N/A GPU models and configuration: GPU 0: NVIDIA H200 GPU 1: NVIDIA H200 GPU 2: NVIDIA H200 GPU 3: NVIDIA H200 GPU 4: NVIDIA H200 GPU 5: NVIDIA H200 GPU 6: NVIDIA H200 GPU 7: NVIDIA H200

Nvidia driver version: 570.133.20 cuDNN version: Could not collect Is XPU available: False HIP runtime version: N/A MIOpen runtime version: N/A Is XNNPACK available: True Caching allocator config: N/A

CPU: Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 52 bits physical, 57 bits virtual Byte Order: Little Endian CPU(s): 240 On-line CPU(s) list: 0-239 Vendor ID: GenuineIntel Model name: INTEL(R) XEON(R) PLATINUM 8580 CPU family: 6 Model: 207 Thread(s) per core: 2 Core(s) per socket: 60 Socket(s): 2 Stepping: 2 CPU max MHz: 2000.0000 CPU min MHz: 800.0000 BogoMIPS: 4000.00 Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb cat_l3 cat_l2 cdp_l3 invpcid_single intel_ppin cdp_l2 ssbd mba ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb intel_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local split_lock_detect avx_vnni avx512_bf16 wbnoinvd dtherm arat pln pts hwp hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq la57 rdpid bus_lock_detect cldemote movdiri movdir64b enqcmd fsrm md_clear serialize tsxldtrk pconfig arch_lbr amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities Virtualization: VT-x L1d cache: 5.6 MiB (120 instances) L1i cache: 3.8 MiB (120 instances) L2 cache: 240 MiB (120 instances) L3 cache: 600 MiB (2 instances) NUMA node(s): 4 NUMA node0 CPU(s): 0-29,120-149 NUMA node1 CPU(s): 30-59,150-179 NUMA node2 CPU(s): 60-89,180-209 NUMA node3 CPU(s): 90-119,210-239 Vulnerability Gather data sampling: Not affected Vulnerability Itlb multihit: Not affected Vulnerability L1tf: Not affected Vulnerability Mds: Not affected Vulnerability Meltdown: Not affected Vulnerability Mmio stale data: Not affected Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Not affected Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; RSB filling; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Not affected

Versions of relevant libraries: [pip3] Could not collect [conda] Could not collect

cc @ezyang @albanD @gqchen @nikitaved @soulitzer @Varal7 @bobrenjc93 @mruberry @jbschlosser @walterddr @mikaylagawarecki @ptrblck @msaroufim @eqy @jerryzh168 @tinglvv @nWEIdia @kurtamohler

extent analysis

TL;DR

The issue can be mitigated by avoiding the use of torch.use_deterministic_algorithms(True) with F.grid_sample on CUDA or by using a uniform grid.

Guidance

  • The non-determinism is triggered by non-uniform grid coordinates across the batch dimension, so using a uniform grid can make the operation deterministic.
  • The issue is specific to the backward pass of F.grid_sample on CUDA, so using a different device (e.g., CPU) or a different operation may avoid the problem.
  • The torch.use_deterministic_algorithms(True) flag is intended to ensure deterministic behavior, but it does not currently work correctly with F.grid_sample on CUDA.
  • To verify the fix, run the minimal reproduction code with the suggested changes and check that the gradients are identical between runs.

Example

# Use a uniform grid to make the operation deterministic
grid = torch.zeros(2048, 1, 81, 2, device='cuda')

Notes

  • The issue is not specific to a particular version of PyTorch or CUDA, as it has been reproduced across multiple versions.
  • The non-determinism scales with gradient magnitude, so it may be more pronounced in certain models or scenarios.

Recommendation

Apply workaround: use a uniform grid or avoid using torch.use_deterministic_algorithms(True) with F.grid_sample on CUDA, as this flag does not currently ensure deterministic behavior for this operation.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Per the docs, torch.nn.functional.grid_sample() when attempting to differentiate a CUDA tensor should throw RuntimeError under use_deterministic_algorithms(True):

The following normally-nondeterministic operations will throw a RuntimeError when mode=True: ... torch.nn.functional.grid_sample() when attempting to differentiate a CUDA tensor

Instead, backward completes silently and produces different gradients across runs with identical seeds and inputs.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING