pytorch - 💡(How to fix) Fix [CUDA] nn.LSTM numerical inconsistency: Sample Independence Violation (NaN in batch vs valid individually) at float32 edge values [3 comments, 3 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#177016Fetched 2026-04-08 00:22:50
View on GitHub
Comments
3
Participants
3
Timeline
6
Reactions
0
Author
Timeline (top)
commented ×3labeled ×2closed ×1

Root Cause

I am reporting a severe discrepancy between the documented behavior of "Batched computations" and the actual results observed in nn.LSTM on CUDA. According to PyTorch documentation, results from batched computations might be "slightly different" due to low-level optimizations. However, my findings show a total functional failure rather than a minor variance: an identical sample that produces a perfectly valid numerical output (~0.995) when processed individually results in a NaN when included as part of a batch. This transition from a valid number to NaN cannot be categorized as a "slight difference"—it is a catastrophic breakdown of numerical consistency. Fundamentally, batching is intended as a performance optimization to improve throughput. It should not violate the principle of sample independence or compromise the mathematical validity of individual samples. If the system is capable of computing a correct result for a sample in isolation, it should not produce an invalid result simply because that sample is processed alongside others. I would like to verify if this behavior is truly intended under the "slightly different" clause, as it suggests a significant issue in the CUDA/cuDNN batching logic that handles edge-case values.

Fix Action

Fix / Workaround

CPU: Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 40 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 48 On-line CPU(s) list: 0-47 Vendor ID: GenuineIntel Model name: QEMU Virtual CPU version 2.5+ CPU family: 15 Model: 107 Thread(s) per core: 1 Core(s) per socket: 48 Socket(s): 1 Stepping: 1 BogoMIPS: 4190.15 Flags: fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx lm constant_tsc nopl xtopology cpuid tsc_known_freq pni ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c hypervisor lahf_lm abm cpuid_fault pti bmi1 avx2 bmi2 avx512f avx512dq avx512cd avx512bw avx512vl Hypervisor vendor: KVM Virtualization type: full L1d cache: 1.5 MiB (48 instances) L1i cache: 1.5 MiB (48 instances) L2 cache: 192 MiB (48 instances) L3 cache: 16 MiB (1 instance) NUMA node(s): 1 NUMA node0 CPU(s): 0-47 Vulnerability Gather data sampling: Not affected Vulnerability Itlb multihit: KVM: Mitigation: VMX unsupported Vulnerability L1tf: Mitigation; PTE Inversion Vulnerability Mds: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown Vulnerability Meltdown: Mitigation; PTI Vulnerability Mmio stale data: Unknown: No mitigations Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Not affected Vulnerability Spec store bypass: Vulnerable Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Retpolines; STIBP disabled; RSB filling; PBRSB-eIBRS Not affected; BHI Retpoline Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Not affected Vulnerability Vmscape: Not affected

Code Example

import torch
import torch.nn as nn
import os

def check_status(t):
    t = t.detach().cpu().float()
    return torch.isnan(t).any().item(), (t.max().item() if t.numel() > 0 else 0.0)

def reproduce_lstm1():
    bundle_path = "bundle.pt"
    bundle = torch.load(bundle_path, map_location="cpu")
    sample_idx = 7
    x_batch = bundle["input_cpu_fp32"].cuda().float()
    
    in_nan, in_mx = check_status(x_batch)
    print(f">>> Input Check  -> NaN: {in_nan}, Max: {in_mx:.2e}")
    
    x_single = x_batch[sample_idx : sample_idx + 1]

    print(">>> Creating independent lstm1 operator and loading weights from lstm1_weights.pt...")
    lstm1 = nn.LSTM(input_size=50, hidden_size=50, num_layers=1, batch_first=True, bidirectional=False).cuda().float()

    lstm1_weights_path = "lstm1_weights.pt"

    sd = torch.load(lstm1_weights_path, map_location="cpu")
    lstm1.load_state_dict(sd)
    lstm1.eval()
    
    with torch.no_grad():
        out_batch_full, _ = lstm1(x_batch)
        res_from_batch = out_batch_full[sample_idx : sample_idx + 1]
        res_single_run, _ = lstm1(x_single)

    nan_b, mx_b = check_status(res_from_batch)
    nan_s, mx_s = check_status(res_single_run)

    print(f"\n[ lstm1 CUDA/FP32 ]")
    print(f"Batch Result  -> NaN: {nan_b}, Max: {mx_b:.2e}")
    print(f"Single Result -> NaN: {nan_s}, Max: {mx_s:.2e}")

if __name__ == "__main__":
    reproduce_lstm1()

---

>>> Input Check  -> NaN: False, Max: 3.40e+38
>>> Creating independent lstm1 operator and loading weights from lstm1_weights.pt...

[ lstm1 CUDA/FP32 ]
Batch Result  -> NaN: True, Max: nan
Single Result -> NaN: False, Max: 9.95e-01
RAW_BUFFERClick to expand / collapse

🐛 Describe the bug

I am reporting a severe discrepancy between the documented behavior of "Batched computations" and the actual results observed in nn.LSTM on CUDA. According to PyTorch documentation, results from batched computations might be "slightly different" due to low-level optimizations. However, my findings show a total functional failure rather than a minor variance: an identical sample that produces a perfectly valid numerical output (~0.995) when processed individually results in a NaN when included as part of a batch. This transition from a valid number to NaN cannot be categorized as a "slight difference"—it is a catastrophic breakdown of numerical consistency. Fundamentally, batching is intended as a performance optimization to improve throughput. It should not violate the principle of sample independence or compromise the mathematical validity of individual samples. If the system is capable of computing a correct result for a sample in isolation, it should not produce an invalid result simply because that sample is processed alongside others. I would like to verify if this behavior is truly intended under the "slightly different" clause, as it suggests a significant issue in the CUDA/cuDNN batching logic that handles edge-case values.

import torch
import torch.nn as nn
import os

def check_status(t):
    t = t.detach().cpu().float()
    return torch.isnan(t).any().item(), (t.max().item() if t.numel() > 0 else 0.0)

def reproduce_lstm1():
    bundle_path = "bundle.pt"
    bundle = torch.load(bundle_path, map_location="cpu")
    sample_idx = 7
    x_batch = bundle["input_cpu_fp32"].cuda().float()
    
    in_nan, in_mx = check_status(x_batch)
    print(f">>> Input Check  -> NaN: {in_nan}, Max: {in_mx:.2e}")
    
    x_single = x_batch[sample_idx : sample_idx + 1]

    print(">>> Creating independent lstm1 operator and loading weights from lstm1_weights.pt...")
    lstm1 = nn.LSTM(input_size=50, hidden_size=50, num_layers=1, batch_first=True, bidirectional=False).cuda().float()

    lstm1_weights_path = "lstm1_weights.pt"

    sd = torch.load(lstm1_weights_path, map_location="cpu")
    lstm1.load_state_dict(sd)
    lstm1.eval()
    
    with torch.no_grad():
        out_batch_full, _ = lstm1(x_batch)
        res_from_batch = out_batch_full[sample_idx : sample_idx + 1]
        res_single_run, _ = lstm1(x_single)

    nan_b, mx_b = check_status(res_from_batch)
    nan_s, mx_s = check_status(res_single_run)

    print(f"\n[ lstm1 CUDA/FP32 ]")
    print(f"Batch Result  -> NaN: {nan_b}, Max: {mx_b:.2e}")
    print(f"Single Result -> NaN: {nan_s}, Max: {mx_s:.2e}")

if __name__ == "__main__":
    reproduce_lstm1()
>>> Input Check  -> NaN: False, Max: 3.40e+38
>>> Creating independent lstm1 operator and loading weights from lstm1_weights.pt...

[ lstm1 CUDA/FP32 ]
Batch Result  -> NaN: True, Max: nan
Single Result -> NaN: False, Max: 9.95e-01

repro_lstm_cuda_batch_pollution.zip

Versions

PyTorch version: 2.10.0+cu126 Is debug build: False CUDA used to build PyTorch: 12.6 ROCM used to build PyTorch: N/A

OS: Ubuntu 24.04.3 LTS (x86_64) GCC version: (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 Clang version: Could not collect CMake version: Could not collect Libc version: glibc-2.39

Python version: 3.10.19 | packaged by conda-forge | (main, Jan 26 2026, 23:45:08) [GCC 14.3.0] (64-bit runtime) Python platform: Linux-6.8.0-90-generic-x86_64-with-glibc2.39 Is CUDA available: True CUDA runtime version: 12.6.20 CUDA_MODULE_LOADING set to: GPU models and configuration: GPU 0: NVIDIA GeForce RTX 3090 GPU 1: NVIDIA GeForce RTX 3090

Nvidia driver version: 560.35.03 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: 40 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 48 On-line CPU(s) list: 0-47 Vendor ID: GenuineIntel Model name: QEMU Virtual CPU version 2.5+ CPU family: 15 Model: 107 Thread(s) per core: 1 Core(s) per socket: 48 Socket(s): 1 Stepping: 1 BogoMIPS: 4190.15 Flags: fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx lm constant_tsc nopl xtopology cpuid tsc_known_freq pni ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c hypervisor lahf_lm abm cpuid_fault pti bmi1 avx2 bmi2 avx512f avx512dq avx512cd avx512bw avx512vl Hypervisor vendor: KVM Virtualization type: full L1d cache: 1.5 MiB (48 instances) L1i cache: 1.5 MiB (48 instances) L2 cache: 192 MiB (48 instances) L3 cache: 16 MiB (1 instance) NUMA node(s): 1 NUMA node0 CPU(s): 0-47 Vulnerability Gather data sampling: Not affected Vulnerability Itlb multihit: KVM: Mitigation: VMX unsupported Vulnerability L1tf: Mitigation; PTE Inversion Vulnerability Mds: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown Vulnerability Meltdown: Mitigation; PTI Vulnerability Mmio stale data: Unknown: No mitigations Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Not affected Vulnerability Spec store bypass: Vulnerable Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Retpolines; STIBP disabled; RSB filling; PBRSB-eIBRS Not affected; BHI Retpoline Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Not affected Vulnerability Vmscape: Not affected

Versions of relevant libraries: [pip3] numpy==1.26.4 [pip3] nvidia-cublas-cu12==12.6.4.1 [pip3] nvidia-cuda-cupti-cu12==12.6.80 [pip3] nvidia-cuda-nvrtc-cu12==12.6.77 [pip3] nvidia-cuda-runtime-cu12==12.6.77 [pip3] nvidia-cudnn-cu12==9.10.2.21 [pip3] nvidia-cufft-cu12==11.3.0.4 [pip3] nvidia-curand-cu12==10.3.7.77 [pip3] nvidia-cusolver-cu12==11.7.1.2 [pip3] nvidia-cusparse-cu12==12.5.4.2 [pip3] nvidia-cusparselt-cu12==0.7.1 [pip3] nvidia-nccl-cu12==2.27.5 [pip3] nvidia-nvjitlink-cu12==12.6.85 [pip3] nvidia-nvtx-cu12==12.6.77 [pip3] onnxruntime-gpu==1.23.2 [pip3] optree==0.18.0 [pip3] pytorch-triton==3.2.0+git4b3bb1f8 [pip3] torch==2.10.0+cu126 [pip3] torchaudio==2.11.0.dev20260127+cu126 [pip3] torchvision==0.25.0+cu126 [pip3] triton==3.6.0+git9844da95 [conda] numpy 1.26.4 pypi_0 pypi [conda] nvidia-cublas-cu12 12.6.4.1 pypi_0 pypi [conda] nvidia-cuda-cupti-cu12 12.6.80 pypi_0 pypi [conda] nvidia-cuda-nvrtc-cu12 12.6.77 pypi_0 pypi [conda] nvidia-cuda-runtime-cu12 12.6.77 pypi_0 pypi [conda] nvidia-cudnn-cu12 9.10.2.21 pypi_0 pypi [conda] nvidia-cufft-cu12 11.3.0.4 pypi_0 pypi [conda] nvidia-curand-cu12 10.3.7.77 pypi_0 pypi [conda] nvidia-cusolver-cu12 11.7.1.2 pypi_0 pypi [conda] nvidia-cusparse-cu12 12.5.4.2 pypi_0 pypi [conda] nvidia-cusparselt-cu12 0.7.1 pypi_0 pypi [conda] nvidia-nccl-cu12 2.27.5 pypi_0 pypi [conda] nvidia-nvjitlink-cu12 12.6.85 pypi_0 pypi [conda] nvidia-nvtx-cu12 12.6.77 pypi_0 pypi [conda] optree 0.18.0 pypi_0 pypi [conda] pytorch-triton 3.2.0+git4b3bb1f8 pypi_0 pypi [conda] torch 2.10.0+cu126 pypi_0 pypi [conda] torchaudio 2.11.0.dev20260127+cu126 pypi_0 pypi [conda] torchvision 0.25.0+cu126 pypi_0 pypi [conda] triton 3.6.0+git9844da95 pypi_0 pypi

extent analysis

Fix Plan

Step 1: Update PyTorch to the latest version

Update PyTorch to the latest version (2.12.0 or later) to see if the issue is resolved.

pip install torch torchvision --upgrade

Step 2: Check for CUDA and cuDNN compatibility

Ensure that the CUDA and cuDNN versions are compatible with PyTorch. You can check the compatibility by running the following command:

python -c "import torch; print(torch.cuda.get_device_name(0))"

This will print the CUDA device name. You can then check the cuDNN version by running:

python -c "import torch; print(torch.backends.cudnn.version())"

Step 3: Disable cuDNN

If the cuDNN version is not compatible, try disabling it by setting the torch.backends.cudnn.enabled flag to False:

import torch
torch.backends.cudnn.enabled = False

Step 4: Verify the fix

Run the reproduce_lstm1 function again to verify that the issue is resolved.

reproduce_lstm1()

Step 5: Monitor for regressions

Monitor the system for any regressions by running the reproduce_lstm1 function periodically.

while True:
    reproduce_lstm1()
    time.sleep(60)  # Run every 60 seconds

Extra Tips

  • Always update PyTorch to the latest version to ensure that you have the latest bug fixes and performance improvements.
  • Ensure that the CUDA and cuDNN versions are compatible with PyTorch.
  • Disable cuDNN if it is not compatible with PyTorch.
  • Monitor the system for any regressions by running the reproduce_lstm1 function periodically.

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

pytorch - 💡(How to fix) Fix [CUDA] nn.LSTM numerical inconsistency: Sample Independence Violation (NaN in batch vs valid individually) at float32 edge values [3 comments, 3 participants]