Enable cuDNN SDPA for contrib Attention#29717
Conversation
Route eligible FP16 and BF16 Attention nodes with compact sequence-length masks through the existing cuDNN SDPA runner on Hopper and newer GPUs. Keep raw masks and cache paths on the existing kernels.
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
@mastryukov1990 please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.
Contributor License AgreementContribution License AgreementThis Contribution License Agreement (“Agreement”) is agreed to by the party signing below (“You”),
|
|
@tianleiwu Could you please take a look and approve the pending GitHub Actions workflows when you have a chance? This PR extends the cuDNN SDPA integration from #28849 to the fused contrib |
There was a problem hiding this comment.
Pull request overview
This PR extends the CUDA implementation of the contrib com.microsoft::Attention operator to reuse the existing cuDNN SDPA (Flash Attention) runner when eligible (FP16/BF16, no raw mask, no KV cache, and cuDNN reports support), aligning its dispatch behavior more closely with existing MultiHeadAttention/GroupQueryAttention integration.
Changes:
- Add cuDNN SDPA enable/auto-enable flags to the contrib CUDA
Attentionkernel and compute cuDNN eligibility early in dispatch. - Route eligible contrib
Attentionexecutions toAttentionKernel_CudnnFlashAttention, including temp-space allocator wiring for the cuDNN runner. - Add a new contrib
Attentiontest using a 1D key sequence-length mask intended to exercise the cuDNN SDPA path.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| onnxruntime/test/contrib_ops/attention_op_test.cc | Adds a new CUDA-focused test case using a 1D key sequence-length mask and env-var kernel selection controls. |
| onnxruntime/contrib_ops/cuda/bert/attention.h | Adds member flags to track explicit and auto cuDNN SDPA enablement for contrib Attention. |
| onnxruntime/contrib_ops/cuda/bert/attention.cc | Implements cuDNN SDPA eligibility checks and dispatch integration for contrib Attention, and propagates the selection into workspace sizing and execution data. |
|
@tianleiwu The follow-up commit 55624f9 addresses the review feedback by asserting the actual cuDNN kernel selection. I validated it on H100: the targeted test passed (1/1) and the full |
|
The The sibling TensorRT CUDA Minimal build completed successfully, so this looks like a transient network/infrastructure failure. A rerun of the failed job should be sufficient. Failed job: https://github.com/microsoft/onnxruntime/actions/runs/29374987406/job/87230486564 |
|
Sorry for tagging you again, @tianleiwu. The failed Linux TensorRT CI job appears to be a transient Gradle download timeout. Could you please rerun the failed job when you have a chance? Thank you! |
@mastryukov1990, CI pipeline has some issues right now (some jobs are queued forever). I could help trigger CIs later. |
|
Hi @tianleiwu, sorry to follow up again. The PR currently has 20 successful workflows and 11 cancelled ones (mostly Windows workflows, plus ONNX Runtime CUDA Builds); none are queued or running now. Is the CI infrastructure healthy enough to rerun the cancelled workflows at this point, or should we wait a bit longer? If it is safe now, could you please trigger them? Thank you! |
|
@mastryukov1990, please merge latest main branch, which has a commit for CI pool change. |
|
@tianleiwu Done — I merged the latest |
tianleiwu
left a comment
There was a problem hiding this comment.
Reviewed the cuDNN SDPA enablement for the fused contrib Attention kernel. The change reuses the shared cudnn_sdpa::is_stable/is_supported predicate and AttentionKernel_CudnnFlashAttention dispatch already used by MultiHeadAttention, so no new kernel is introduced.
Verified against the surrounding paths:
- Mutual exclusion preserved —
cudnn_sdpa_supportedcorrectly gates off flash, the fused TRT runner, and memory-efficient attention; theQkvToContext<= 1fused-kernel assert still holds. - QKV format is valid — with cuDNN selected,
PrepareQkv_Attentionfalls into the unfused branch producingQ_K_V_BNSH, whichCudnnFlashAttention/build_graphexplicitly accept and stride correctly. - Workspace sizing is correct —
GetAttentionWorkspaceSize(..., cudnn_sdpa_supported, false)returns the fullqkv_bytestranspose buffer (previously this arg was hard-codedfalse). - Safe default —
AttentionData::kernel_typedefaults toAttentionKernel_Default, so non-eligible calls keep their existing dispatch. - Test validates both kernel selection (
SdpaKernel=CUDNN_FLASH_ATTENTION) and numerics (masked key/value token excluded from both outputs), and skips cleanly when cuDNN is unavailable.
No blocking issues. One maintainability suggestion left inline regarding the implicit attention_bias safety invariant.
|
|
||
| const bool cudnn_sdpa_enabled = enable_cudnn_flash_attention_ || | ||
| (auto_enable_cudnn_flash_attention_ && sm >= 90); | ||
| const bool cudnn_sdpa_supported = cudnn_sdpa_enabled && |
There was a problem hiding this comment.
Unlike the flash path (nullptr == attention_bias) and unlike MultiHeadAttention (which adds an explicit cudnn_sdpa_bias_ok term), this predicate does not mention attention_bias. An Attention node with an attention_bias input plus no/1D mask will now newly dispatch to cuDNN and forward the bias.
This is correct here only because the fused Attention op is always self-attention with no past/present, so sequence_length == total_sequence_length and cuDNN never selects the bottom-right causal alignment that is incompatible with bias (exactly the case MHA's cudnn_sdpa_bias_ok protects against). Broadcast dims are also set by CheckInputs, so data flow is fine.
The safety relies on an implicit, untested invariant. Consider a short comment documenting why bias is safe here (s_q == s_kv ⇒ TOP_LEFT causal), and/or a test covering the attention_bias + cuDNN combination, so a future change that relaxes the no-past/present restriction doesn't silently route an unsupported bias + bottom-right case to cuDNN.
Description
Enable the existing cuDNN SDPA runner for the CUDA implementation of the contrib
Attentionoperator when:On Hopper and newer GPUs, cuDNN SDPA is auto-preferred consistently with
MultiHeadAttention. Explicit kernel selection continues to be respected. Raw attention masks and cache paths remain on their existing kernels.The new test forces cuDNN SDPA and uses a partial sequence-length mask, verifying that the masked key/value token is excluded from both output positions.
Motivation and Context
Transformer optimizer fusions can produce
com.microsoft::Attentionnodes with compact sequence-length masks. Although cuDNN SDPA was enabled forMultiHeadAttentionandGroupQueryAttentionin #28849, the legacy fusedAttentionpath did not dispatch to the shared cuDNN runner. On an H100, all 24 attention nodes in a BGE encoder consequently selected the math kernel.This change reuses the existing cuDNN implementation and eligibility checks rather than adding another attention kernel.
Performance
Exact A/B comparison using the same patched build of current
main, with cuDNN auto-dispatch disabled for the baseline viaORT_ENABLE_CUDNN_FLASH_ATTENTION=0:Environment: NVIDIA H100 (SM90), CUDA 12.8, cuDNN frontend 1.24, FP16 BGE encoder with right-padded batches. Debug dispatch confirmed
CUDNN_FLASH_ATTENTIONfor 24/24 fusedAttentionnodes.Numerical comparison against the same build with cuDNN disabled, over sampled embeddings:
0.001465;0.999955.Validation
ContribOpAttentionTest.CudnnFlashAttentionWithKeySequenceLengthMask: passed and reportedSdpaKernel=CUDNN_FLASH_ATTENTION.ContribOpAttentionTest.*: 46/46 passed (one pre-existing disabled test).clang-format --dry-run --Werroron all changed files.git diff --check.