pytorch - ✅(Solved) Fix When using the cuDNN backend, custom masks become ineffective. [1 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#177842Fetched 2026-04-08 01:03:15
View on GitHub
Comments
1
Participants
2
Timeline
39
Reactions
0
Author
Participants
Timeline (top)
mentioned ×14subscribed ×14labeled ×5referenced ×3

Fix Action

Fix / Workaround

CPU: 架构: x86_64 CPU 运行模式: 32-bit, 64-bit Address sizes: 48 bits physical, 48 bits virtual 字节序: Little Endian CPU: 32 在线 CPU 列表: 0-31 厂商 ID: AuthenticAMD 型号名称: AMD Ryzen 9 9950X 16-Core Processor CPU 系列: 26 型号: 68 每个核的线程数: 2 每个座的核数: 16 座: 1 步进: 0 Frequency boost: enabled CPU(s) scaling MHz: 55% CPU 最大 MHz: 5756.4521 CPU 最小 MHz: 624.1940 BogoMIPS: 8583.31 标记: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good amd_lbr_v2 nopl xtopology nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpuid_fault cpb cat_l3 cdp_l3 hw_pstate ssbd mba perfmon_v2 ibrs ibpb stibp ibrs_enhanced vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local user_shstk avx_vnni avx512_bf16 clzero irperf xsaveerptr rdpru wbnoinvd cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif x2avic v_spec_ctrl vnmi avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid bus_lock_detect movdiri movdir64b overflow_recov succor smca fsrm avx512_vp2intersect flush_l1d amd_lbr_pmc_freeze 虚拟化: AMD-V L1d 缓存: 768 KiB (16 instances) L1i 缓存: 512 KiB (16 instances) L2 缓存: 16 MiB (16 instances) L3 缓存: 64 MiB (2 instances) NUMA 节点: 1 NUMA 节点0 CPU: 0-31 Vulnerability Gather data sampling: Not affected Vulnerability Ghostwrite: Not affected Vulnerability Indirect target selection: 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 Old microcode: Not affected Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Mitigation; IBPB on VMEXIT only Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; STIBP always-on; PBRSB-eIBRS Not affected; BHI Not affected Vulnerability Srbds: Not affected Vulnerability Tsa: Not affected Vulnerability Tsx async abort: Not affected Vulnerability Vmscape: Mitigation; IBPB on VMEXIT

PR fix notes

PR #177868: [cuDNN][SDPA] Fix attn-mask conversion constant

Description (problem / solution / changelog)

To fix #177842

Previous workaround of using fp16 min seems to now break stuff? Will need to sync with the cuDNN team on whether versions guards are needed here

cc @csarofeen @ptrblck @nWEIdia

Changed files

  • aten/src/ATen/native/transformers/attention.cpp (modified, +3/-14)
  • test/test_transformers.py (modified, +77/-0)

Code Example

import torch
from torch.nn.attention import SDPBackend, sdpa_kernel

torch.set_printoptions(sci_mode=False, precision=4)

def calc_and_print(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, attention_mask: torch.Tensor):
    with sdpa_kernel(SDPBackend.MATH):
        attn_output_math = torch.nn.functional.scaled_dot_product_attention(
            query=q.transpose(1, 2),
            key=k.transpose(1, 2),
            value=v.transpose(1, 2),
            attn_mask=attention_mask,
            is_causal=False,
            enable_gqa=True,
        )
    with sdpa_kernel(SDPBackend.CUDNN_ATTENTION):
        attn_output_cudnn = torch.nn.functional.scaled_dot_product_attention(
            query=q.transpose(1, 2),
            key=k.transpose(1, 2),
            value=v.transpose(1, 2),
            attn_mask=attention_mask,
            is_causal=False,
            enable_gqa=True,
        )
    return attn_output_math, attn_output_cudnn

q = torch.randn(1, 10, 8, 8).to("cuda").bfloat16()
k = torch.randn(1, 10, 1, 8).to("cuda").bfloat16()
v = torch.randn(1, 10, 1, 8).to("cuda").bfloat16()

attention_mask_custom = torch.zeros(10, 10, dtype=torch.bool).to("cuda")
attention_mask_custom[:7, :7] = torch.tril(torch.ones(7, 7, dtype=torch.bool), diagonal=0)
attention_mask_full = torch.tril(torch.ones(10, 10, dtype=torch.bool), diagonal=0).to("cuda")

print(f"attention_mask_custom:\n{attention_mask_custom}")
custom_math, custom_cudnn = calc_and_print(q, k, v, attention_mask_custom)
print(f"custom_math:\n{custom_math[0,0]}")
print(f"custom_cudnn:\n{custom_cudnn[0,0]}")

print("="*40)

print(f"attention_mask_full:\n{attention_mask_full}")
full_math, full_cudnn = calc_and_print(q, k, v, attention_mask_full)
print(f"full_math:\n{full_math[0,0]}")
print(f"full_cudnn:\n{full_cudnn[0,0]}")

print("="*40)

cudnn_diff_between_custom_and_full = custom_cudnn - full_cudnn
print(f"cudnn_diff_between_custom_and_full:\n{cudnn_diff_between_custom_and_full[0,0]}")

---

attention_mask_custom:
tensor([[ True, False, False, False, False, False, False, False, False, False],
        [ True,  True, False, False, False, False, False, False, False, False],
        [ True,  True,  True, False, False, False, False, False, False, False],
        [ True,  True,  True,  True, False, False, False, False, False, False],
        [ True,  True,  True,  True,  True, False, False, False, False, False],
        [ True,  True,  True,  True,  True,  True, False, False, False, False],
        [ True,  True,  True,  True,  True,  True,  True, False, False, False],
        [False, False, False, False, False, False, False, False, False, False],
        [False, False, False, False, False, False, False, False, False, False],
        [False, False, False, False, False, False, False, False, False, False]],
       device='cuda:0')
custom_math:
tensor([[ 1.1094,  2.0938,  1.3906,  0.7969,  0.4492,  0.6875,  2.0312,  1.6250],
        [-0.1836,  0.9102,  0.7188,  0.0947,  0.7812,  1.2656,  0.9336,  1.6094],
        [-0.0588,  1.2109,  0.8789,  0.0933,  0.6680,  1.0078,  1.1641,  1.4297],
        [ 0.6836,  1.3984,  0.8594,  0.4863,  0.5938,  0.9023,  1.6016,  1.4375],
        [ 0.4180,  1.0625,  0.5625, -0.0527,  0.4629,  0.5781,  1.1406,  1.0625],
        [-0.6133,  0.4707,  0.5039, -0.9375,  0.4648,  0.7305, -0.1934,  1.3125],
        [ 0.4727,  0.8164,  0.4043, -0.5547,  0.2227,  0.4453,  1.0469,  0.4531],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000]],
       device='cuda:0', dtype=torch.bfloat16)
custom_cudnn:
tensor([[ 1.1094,  2.0938,  1.3906,  0.7969,  0.4492,  0.6875,  2.0312,  1.6250],
        [-0.1826,  0.9102,  0.7227,  0.0952,  0.7812,  1.2656,  0.9336,  1.6094],
        [-0.0598,  1.2109,  0.8789,  0.0933,  0.6680,  1.0156,  1.1641,  1.4297],
        [ 0.6836,  1.3984,  0.8594,  0.4863,  0.5938,  0.9023,  1.6016,  1.4375],
        [ 0.4160,  1.0625,  0.5625, -0.0527,  0.4629,  0.5781,  1.1406,  1.0625],
        [-0.6133,  0.4707,  0.5039, -0.9375,  0.4648,  0.7305, -0.1924,  1.3125],
        [ 0.4727,  0.8164,  0.4043, -0.5547,  0.2236,  0.4473,  1.0469,  0.4551],
        [-0.0286,  0.7109,  0.2773, -0.7461,  0.1924,  0.3477,  0.1807, -0.1001],
        [ 0.2891,  0.6914,  0.6562, -0.7227,  0.0913,  0.4238,  0.2021,  0.4531],
        [ 0.6562,  0.8047,  0.5039, -0.4668,  0.1260,  0.4707,  1.1172,  0.2793]],
       device='cuda:0', dtype=torch.bfloat16)
========================================
attention_mask_full:
tensor([[ True, False, False, False, False, False, False, False, False, False],
        [ True,  True, False, False, False, False, False, False, False, False],
        [ True,  True,  True, False, False, False, False, False, False, False],
        [ True,  True,  True,  True, False, False, False, False, False, False],
        [ True,  True,  True,  True,  True, False, False, False, False, False],
        [ True,  True,  True,  True,  True,  True, False, False, False, False],
        [ True,  True,  True,  True,  True,  True,  True, False, False, False],
        [ True,  True,  True,  True,  True,  True,  True,  True, False, False],
        [ True,  True,  True,  True,  True,  True,  True,  True,  True, False],
        [ True,  True,  True,  True,  True,  True,  True,  True,  True,  True]],
       device='cuda:0')
full_math:
tensor([[ 1.1094,  2.0938,  1.3906,  0.7969,  0.4492,  0.6875,  2.0312,  1.6250],
        [-0.1836,  0.9102,  0.7188,  0.0947,  0.7812,  1.2656,  0.9336,  1.6094],
        [-0.0588,  1.2109,  0.8789,  0.0933,  0.6680,  1.0078,  1.1641,  1.4297],
        [ 0.6836,  1.3984,  0.8594,  0.4863,  0.5938,  0.9023,  1.6016,  1.4375],
        [ 0.4180,  1.0625,  0.5625, -0.0527,  0.4629,  0.5781,  1.1406,  1.0625],
        [-0.6133,  0.4707,  0.5039, -0.9375,  0.4648,  0.7305, -0.1934,  1.3125],
        [ 0.4727,  0.8164,  0.4043, -0.5547,  0.2227,  0.4453,  1.0469,  0.4531],

        [-0.2598,  0.9922,  0.7188, -0.8516,  0.4336,  0.2100,  0.5195,  0.3965],
        [ 0.2637,  0.7539,  0.7969, -0.7383,  0.1377,  0.4004,  0.2793,  0.6172],
        [ 0.6562,  0.8047,  0.5039, -0.4668,  0.1270,  0.4707,  1.1172,  0.2793]],
       device='cuda:0', dtype=torch.bfloat16)
full_cudnn:
tensor([[ 1.1094,  2.0938,  1.3906,  0.7969,  0.4492,  0.6875,  2.0312,  1.6250],
        [-0.1826,  0.9102,  0.7227,  0.0952,  0.7812,  1.2656,  0.9336,  1.6094],
        [-0.0598,  1.2109,  0.8789,  0.0933,  0.6680,  1.0156,  1.1641,  1.4297],
        [ 0.6836,  1.3984,  0.8594,  0.4863,  0.5938,  0.9023,  1.6016,  1.4375],
        [ 0.4160,  1.0625,  0.5625, -0.0527,  0.4629,  0.5781,  1.1406,  1.0625],
        [-0.6133,  0.4707,  0.5039, -0.9375,  0.4648,  0.7305, -0.1924,  1.3125],
        [ 0.4727,  0.8164,  0.4043, -0.5547,  0.2236,  0.4473,  1.0469,  0.4551],
        [-0.2598,  0.9922,  0.7188, -0.8516,  0.4336,  0.2100,  0.5195,  0.3945],
        [ 0.2637,  0.7539,  0.7969, -0.7383,  0.1377,  0.4004,  0.2793,  0.6172],
        [ 0.6562,  0.8047,  0.5000, -0.4648,  0.1279,  0.4707,  1.1094,  0.2793]],
       device='cuda:0', dtype=torch.bfloat16)
========================================
cudnn_diff_between_custom_and_full:
tensor([[ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.2314, -0.2812, -0.4414,  0.1055, -0.2412,  0.1377, -0.3398, -0.4941],
        [ 0.0254, -0.0625, -0.1406,  0.0156, -0.0464,  0.0234, -0.0771, -0.1641],
        [ 0.0000,  0.0000,  0.0039, -0.0020, -0.0020,  0.0000,  0.0078,  0.0000]],
       device='cuda:0', dtype=torch.bfloat16)
RAW_BUFFERClick to expand / collapse

🐛 Describe the bug

In PyTorch's SDPA implementation, when using different backends, custom masks don't seem to take effect.

The test compared two backends: SDPBackend.MATH and SDPBackend.CUDNN_ATTENTION.

import torch
from torch.nn.attention import SDPBackend, sdpa_kernel

torch.set_printoptions(sci_mode=False, precision=4)

def calc_and_print(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, attention_mask: torch.Tensor):
    with sdpa_kernel(SDPBackend.MATH):
        attn_output_math = torch.nn.functional.scaled_dot_product_attention(
            query=q.transpose(1, 2),
            key=k.transpose(1, 2),
            value=v.transpose(1, 2),
            attn_mask=attention_mask,
            is_causal=False,
            enable_gqa=True,
        )
    with sdpa_kernel(SDPBackend.CUDNN_ATTENTION):
        attn_output_cudnn = torch.nn.functional.scaled_dot_product_attention(
            query=q.transpose(1, 2),
            key=k.transpose(1, 2),
            value=v.transpose(1, 2),
            attn_mask=attention_mask,
            is_causal=False,
            enable_gqa=True,
        )
    return attn_output_math, attn_output_cudnn

q = torch.randn(1, 10, 8, 8).to("cuda").bfloat16()
k = torch.randn(1, 10, 1, 8).to("cuda").bfloat16()
v = torch.randn(1, 10, 1, 8).to("cuda").bfloat16()

attention_mask_custom = torch.zeros(10, 10, dtype=torch.bool).to("cuda")
attention_mask_custom[:7, :7] = torch.tril(torch.ones(7, 7, dtype=torch.bool), diagonal=0)
attention_mask_full = torch.tril(torch.ones(10, 10, dtype=torch.bool), diagonal=0).to("cuda")

print(f"attention_mask_custom:\n{attention_mask_custom}")
custom_math, custom_cudnn = calc_and_print(q, k, v, attention_mask_custom)
print(f"custom_math:\n{custom_math[0,0]}")
print(f"custom_cudnn:\n{custom_cudnn[0,0]}")

print("="*40)

print(f"attention_mask_full:\n{attention_mask_full}")
full_math, full_cudnn = calc_and_print(q, k, v, attention_mask_full)
print(f"full_math:\n{full_math[0,0]}")
print(f"full_cudnn:\n{full_cudnn[0,0]}")

print("="*40)

cudnn_diff_between_custom_and_full = custom_cudnn - full_cudnn
print(f"cudnn_diff_between_custom_and_full:\n{cudnn_diff_between_custom_and_full[0,0]}")

输出:

attention_mask_custom:
tensor([[ True, False, False, False, False, False, False, False, False, False],
        [ True,  True, False, False, False, False, False, False, False, False],
        [ True,  True,  True, False, False, False, False, False, False, False],
        [ True,  True,  True,  True, False, False, False, False, False, False],
        [ True,  True,  True,  True,  True, False, False, False, False, False],
        [ True,  True,  True,  True,  True,  True, False, False, False, False],
        [ True,  True,  True,  True,  True,  True,  True, False, False, False],
        [False, False, False, False, False, False, False, False, False, False],
        [False, False, False, False, False, False, False, False, False, False],
        [False, False, False, False, False, False, False, False, False, False]],
       device='cuda:0')
custom_math:
tensor([[ 1.1094,  2.0938,  1.3906,  0.7969,  0.4492,  0.6875,  2.0312,  1.6250],
        [-0.1836,  0.9102,  0.7188,  0.0947,  0.7812,  1.2656,  0.9336,  1.6094],
        [-0.0588,  1.2109,  0.8789,  0.0933,  0.6680,  1.0078,  1.1641,  1.4297],
        [ 0.6836,  1.3984,  0.8594,  0.4863,  0.5938,  0.9023,  1.6016,  1.4375],
        [ 0.4180,  1.0625,  0.5625, -0.0527,  0.4629,  0.5781,  1.1406,  1.0625],
        [-0.6133,  0.4707,  0.5039, -0.9375,  0.4648,  0.7305, -0.1934,  1.3125],
        [ 0.4727,  0.8164,  0.4043, -0.5547,  0.2227,  0.4453,  1.0469,  0.4531],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000]],
       device='cuda:0', dtype=torch.bfloat16)
custom_cudnn:
tensor([[ 1.1094,  2.0938,  1.3906,  0.7969,  0.4492,  0.6875,  2.0312,  1.6250],
        [-0.1826,  0.9102,  0.7227,  0.0952,  0.7812,  1.2656,  0.9336,  1.6094],
        [-0.0598,  1.2109,  0.8789,  0.0933,  0.6680,  1.0156,  1.1641,  1.4297],
        [ 0.6836,  1.3984,  0.8594,  0.4863,  0.5938,  0.9023,  1.6016,  1.4375],
        [ 0.4160,  1.0625,  0.5625, -0.0527,  0.4629,  0.5781,  1.1406,  1.0625],
        [-0.6133,  0.4707,  0.5039, -0.9375,  0.4648,  0.7305, -0.1924,  1.3125],
        [ 0.4727,  0.8164,  0.4043, -0.5547,  0.2236,  0.4473,  1.0469,  0.4551],
        [-0.0286,  0.7109,  0.2773, -0.7461,  0.1924,  0.3477,  0.1807, -0.1001],
        [ 0.2891,  0.6914,  0.6562, -0.7227,  0.0913,  0.4238,  0.2021,  0.4531],
        [ 0.6562,  0.8047,  0.5039, -0.4668,  0.1260,  0.4707,  1.1172,  0.2793]],
       device='cuda:0', dtype=torch.bfloat16)
========================================
attention_mask_full:
tensor([[ True, False, False, False, False, False, False, False, False, False],
        [ True,  True, False, False, False, False, False, False, False, False],
        [ True,  True,  True, False, False, False, False, False, False, False],
        [ True,  True,  True,  True, False, False, False, False, False, False],
        [ True,  True,  True,  True,  True, False, False, False, False, False],
        [ True,  True,  True,  True,  True,  True, False, False, False, False],
        [ True,  True,  True,  True,  True,  True,  True, False, False, False],
        [ True,  True,  True,  True,  True,  True,  True,  True, False, False],
        [ True,  True,  True,  True,  True,  True,  True,  True,  True, False],
        [ True,  True,  True,  True,  True,  True,  True,  True,  True,  True]],
       device='cuda:0')
full_math:
tensor([[ 1.1094,  2.0938,  1.3906,  0.7969,  0.4492,  0.6875,  2.0312,  1.6250],
        [-0.1836,  0.9102,  0.7188,  0.0947,  0.7812,  1.2656,  0.9336,  1.6094],
        [-0.0588,  1.2109,  0.8789,  0.0933,  0.6680,  1.0078,  1.1641,  1.4297],
        [ 0.6836,  1.3984,  0.8594,  0.4863,  0.5938,  0.9023,  1.6016,  1.4375],
        [ 0.4180,  1.0625,  0.5625, -0.0527,  0.4629,  0.5781,  1.1406,  1.0625],
        [-0.6133,  0.4707,  0.5039, -0.9375,  0.4648,  0.7305, -0.1934,  1.3125],
        [ 0.4727,  0.8164,  0.4043, -0.5547,  0.2227,  0.4453,  1.0469,  0.4531],

        [-0.2598,  0.9922,  0.7188, -0.8516,  0.4336,  0.2100,  0.5195,  0.3965],
        [ 0.2637,  0.7539,  0.7969, -0.7383,  0.1377,  0.4004,  0.2793,  0.6172],
        [ 0.6562,  0.8047,  0.5039, -0.4668,  0.1270,  0.4707,  1.1172,  0.2793]],
       device='cuda:0', dtype=torch.bfloat16)
full_cudnn:
tensor([[ 1.1094,  2.0938,  1.3906,  0.7969,  0.4492,  0.6875,  2.0312,  1.6250],
        [-0.1826,  0.9102,  0.7227,  0.0952,  0.7812,  1.2656,  0.9336,  1.6094],
        [-0.0598,  1.2109,  0.8789,  0.0933,  0.6680,  1.0156,  1.1641,  1.4297],
        [ 0.6836,  1.3984,  0.8594,  0.4863,  0.5938,  0.9023,  1.6016,  1.4375],
        [ 0.4160,  1.0625,  0.5625, -0.0527,  0.4629,  0.5781,  1.1406,  1.0625],
        [-0.6133,  0.4707,  0.5039, -0.9375,  0.4648,  0.7305, -0.1924,  1.3125],
        [ 0.4727,  0.8164,  0.4043, -0.5547,  0.2236,  0.4473,  1.0469,  0.4551],
        [-0.2598,  0.9922,  0.7188, -0.8516,  0.4336,  0.2100,  0.5195,  0.3945],
        [ 0.2637,  0.7539,  0.7969, -0.7383,  0.1377,  0.4004,  0.2793,  0.6172],
        [ 0.6562,  0.8047,  0.5000, -0.4648,  0.1279,  0.4707,  1.1094,  0.2793]],
       device='cuda:0', dtype=torch.bfloat16)
========================================
cudnn_diff_between_custom_and_full:
tensor([[ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [ 0.2314, -0.2812, -0.4414,  0.1055, -0.2412,  0.1377, -0.3398, -0.4941],
        [ 0.0254, -0.0625, -0.1406,  0.0156, -0.0464,  0.0234, -0.0771, -0.1641],
        [ 0.0000,  0.0000,  0.0039, -0.0020, -0.0020,  0.0000,  0.0078,  0.0000]],
       device='cuda:0', dtype=torch.bfloat16)

As you can see, when using a custom-shaped mask, cuDNN appears to maintain output in positions that should output 0. However, the behavior in other positions is consistent with the math backend.

Versions

Collecting environment information... PyTorch version: 2.10.0+cu128 Is debug build: False CUDA used to build PyTorch: 12.8 ROCM used to build PyTorch: N/A

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

Python version: 3.12.3 (main, Mar 3 2026, 12:15:18) [GCC 13.3.0] (64-bit runtime) Python platform: Linux-6.17.0-19-generic-x86_64-with-glibc2.39 Is CUDA available: True CUDA runtime version: 13.2.51 CUDA_MODULE_LOADING set to: GPU models and configuration: GPU 0: NVIDIA RTX 6000D Nvidia driver version: 595.45.04 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: 架构: x86_64 CPU 运行模式: 32-bit, 64-bit Address sizes: 48 bits physical, 48 bits virtual 字节序: Little Endian CPU: 32 在线 CPU 列表: 0-31 厂商 ID: AuthenticAMD 型号名称: AMD Ryzen 9 9950X 16-Core Processor CPU 系列: 26 型号: 68 每个核的线程数: 2 每个座的核数: 16 座: 1 步进: 0 Frequency boost: enabled CPU(s) scaling MHz: 55% CPU 最大 MHz: 5756.4521 CPU 最小 MHz: 624.1940 BogoMIPS: 8583.31 标记: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good amd_lbr_v2 nopl xtopology nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpuid_fault cpb cat_l3 cdp_l3 hw_pstate ssbd mba perfmon_v2 ibrs ibpb stibp ibrs_enhanced vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local user_shstk avx_vnni avx512_bf16 clzero irperf xsaveerptr rdpru wbnoinvd cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif x2avic v_spec_ctrl vnmi avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid bus_lock_detect movdiri movdir64b overflow_recov succor smca fsrm avx512_vp2intersect flush_l1d amd_lbr_pmc_freeze 虚拟化: AMD-V L1d 缓存: 768 KiB (16 instances) L1i 缓存: 512 KiB (16 instances) L2 缓存: 16 MiB (16 instances) L3 缓存: 64 MiB (2 instances) NUMA 节点: 1 NUMA 节点0 CPU: 0-31 Vulnerability Gather data sampling: Not affected Vulnerability Ghostwrite: Not affected Vulnerability Indirect target selection: 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 Old microcode: Not affected Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Mitigation; IBPB on VMEXIT only Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; STIBP always-on; PBRSB-eIBRS Not affected; BHI Not affected Vulnerability Srbds: Not affected Vulnerability Tsa: Not affected Vulnerability Tsx async abort: Not affected Vulnerability Vmscape: Mitigation; IBPB on VMEXIT

Versions of relevant libraries: [pip3] numpy==2.4.3 [pip3] nvidia-cublas-cu12==12.8.4.1 [pip3] nvidia-cuda-cupti-cu12==12.8.90 [pip3] nvidia-cuda-nvrtc-cu12==12.8.93 [pip3] nvidia-cuda-runtime-cu12==12.8.90 [pip3] nvidia-cudnn-cu12==9.10.2.21 [pip3] nvidia-cudnn-frontend==1.20.0 [pip3] nvidia-cufft-cu12==11.3.3.83 [pip3] nvidia-curand-cu12==10.3.9.90 [pip3] nvidia-cusolver-cu12==11.7.3.90 [pip3] nvidia-cusparse-cu12==12.5.8.93 [pip3] nvidia-cusparselt-cu12==0.7.1 [pip3] nvidia-nccl-cu12==2.27.5 [pip3] nvidia-nccl-cu13==2.29.7 [pip3] nvidia-nvjitlink-cu12==12.8.93 [pip3] nvidia-nvtx-cu12==12.8.90 [pip3] torch==2.10.0 [pip3] torch_c_dlpack_ext==0.1.5 [pip3] torchvision==0.25.0 [pip3] triton==3.6.0 [conda] Could not collect

cc @csarofeen @ptrblck @eqy @nWEIdia @drisspg @liangel-02 @howardzhang-cv

extent analysis

Fix Plan

The issue seems to be related to the cuDNN backend not respecting custom masks in PyTorch's SDPA implementation.

To fix this, you can try the following steps:

  • Update cuDNN version: Ensure you are using the latest version of cuDNN. You can update cuDNN using the following command:

pip install --upgrade nvidia-cudnn-cu12

*   **Check mask shape and type**: Verify that the custom mask has the correct shape and type. The mask should be a boolean tensor with shape `(batch_size, sequence_length, sequence_length)` or `(sequence_length, sequence_length)` if batch size is 1.
*   **Use `attn_mask` with `torch.nn.functional.scaled_dot_product_attention`**: Make sure you are passing the custom mask to the `attn_mask` argument of `torch.nn.functional.scaled_dot_product_attention`.

Here is an example code snippet that demonstrates how to use a custom mask with `torch.nn.functional.scaled_dot_product_attention`:
```python
import torch
from torch.nn import functional as F

# Define custom mask
custom_mask = torch.zeros(10, 10, dtype=torch.bool)
custom_mask[:7, :7] = torch.tril(torch.ones(7, 7, dtype=torch.bool), diagonal=0)

# Define query, key, and value tensors
q = torch.randn(1, 10, 8, 8)
k = torch.randn(1, 10, 1, 8)
v = torch.randn(1, 10, 1, 8)

# Apply custom mask to attention
with torch.cuda.amp.autocast():
    attn_output = F.scaled_dot_product_attention(
        query=q.transpose(1, 2),
        key=k.transpose(1, 2),
        value=v.transpose(1, 2),
        attn_mask=custom_mask,
        is_causal=False,
        enable_gqa=True,
    )

Verification

To verify that the fix worked, you can compare the output of the attention layer with and without the custom mask. The output should be different when using the custom mask.

You can use the following code snippet to verify the fix:

# Define custom mask
custom_mask = torch.zeros(10, 10, dtype=torch.bool)
custom_mask[:7, :7] = torch.tril(torch.ones(7, 7, dtype=torch.bool), diagonal=0)

# Define query, key, and value tensors
q = torch.randn(1, 10, 8, 8)
k = torch.randn(1, 10, 1, 8)
v = torch.randn(1, 10, 1, 8)

# Apply custom mask to attention
with torch.cuda.amp.autocast():
    attn_output_custom =

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