Skip to content

Skip MEA in ONNX Attention for head_dim > 256 (CUTLASS shared memory limit) - #28383

Closed
justinchuby wants to merge 4 commits into
microsoft:mainfrom
justinchuby:fix-cuda-opset24-reshape-cast
Closed

Skip MEA in ONNX Attention for head_dim > 256 (CUTLASS shared memory limit)#28383
justinchuby wants to merge 4 commits into
microsoft:mainfrom
justinchuby:fix-cuda-opset24-reshape-cast

Conversation

@justinchuby

Copy link
Copy Markdown
Contributor

Description

CUTLASS FMHA shared memory scales with queries_per_block × head_dim. For head_dim > 256 (e.g. Gemma4 full-attention with head_dim=512), the kernel exceeds the SM's shared memory limit, causing cudaErrorInvalidValue on launch.

This is the same fix as c72a5f4 (GQA op) applied to the ONNX Attention op. The GQA contrib op already has parameters.head_size <= 256 in its MEA eligibility check, but the standard ONNX Attention op was missing this guard.

Fix

Add parameters.head_size <= 256 to the MEA eligibility check in attention.cc. Layers with head_dim > 256 now fall through to unfused attention (cuBLAS GEMM), which handles any head_dim.

Test

Verified with ONNX Attention op (opset 24):

  • GQA head_dim=64: ✅ (uses Flash/MEA as before)
  • GQA head_dim=256: ✅ (uses Flash/MEA as before)
  • GQA head_dim=512: ✅ (now falls to unfused, previously crashed)
  • MHA head_dim=512: ✅

All with is_causal=0, nonpad_kv_seqlen, fp16.

Motivation

This affects Gemma4 models which use dual head dimensions: head_dim=256 for sliding-window attention layers and head_dim=512 for full-attention (global) layers.

justinchuby and others added 4 commits May 5, 2026 21:51
ONNX opset 24 bumped Reshape and Cast (added float8e8m0 type support).
ORT CUDA EP only had opset 23 registrations, so these ops fell to
CPUExecutionProvider on opset 24 models, producing ~280
MemcpyFromHost/MemcpyToHost nodes.

Version existing opset 23 registrations to (23, 23) and add new
non-versioned opset 24 registrations. Same kernel implementations.

Result: 282 memcpy → 4 memcpy for opset 24 models on CUDA EP.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
BiasLoader hardcoded 128-bit (8 fp16 element) vectorized loads via
ElementsPerAccess = 128 / sizeof_bits<scalar_t> regardless of the
isAligned template parameter. When attention bias stride
(total_sequence_length) was not a multiple of 8, the unaligned kernel
was selected but BiasLoader still used 128-bit loads on the bias,
causing cudaErrorMisalignedAddress.

Fix: Use kAlignmentA (kMinimumAlignment=4 for unaligned path,
kAlignmentA=8 for aligned path) as BiasLoader's ElementsPerAccess.
This allows the unaligned kernel to use 64-bit loads for the bias.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
CUTLASS FMHA shared memory scales with queries_per_block × head_dim.
For head_dim > 256 (e.g. Gemma4 full_attention with head_dim=512),
the kernel exceeds the SM's shared memory limit, causing
cudaErrorInvalidValue on launch.

Add head_size <= 256 check to the MEA eligibility in GQA. This lets
the unfused fallback (cuBLAS GEMM, any head_dim) handle these layers.

Tested: Gemma4 CUDA EP with GQA head_dim=512 layers at 150 tok/s.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
CUTLASS FMHA's custom right-padding kernel variant (used when
nonpad_kv_seqlen is provided) has shared memory that scales with
queries_per_block × head_dim. For head_dim > 256 (e.g. Gemma4
full-attention with head_dim=512), this exceeds the SM shared memory
limit, causing cudaErrorInvalidValue on launch.

The standard MEA path (without nonpad_kv_seqlen) works fine for any
head_dim, so the guard is scoped to only the nonpad_kv_seqlen case.

Fix: skip MEA when nonpad_kv_seqlen is present AND head_size > 256.
These layers fall through to unfused attention (cuBLAS GEMM).

Tested on H200:
- hd=512 without nonpad: OK (MEA still used)
- hd=512 with nonpad: OK (unfused fallback, previously crashed)
- hd=64/256 with nonpad: OK (MEA still used)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
@justinchuby
justinchuby force-pushed the fix-cuda-opset24-reshape-cast branch from 2601af2 to 5541d36 Compare May 6, 2026 18:03
@justinchuby

Copy link
Copy Markdown
Contributor Author

Updated: Narrowed the fix based on feedback. The head_size <= 256 guard was too broad — MEA works fine for head_dim=512 in general. The crash only happens with the custom right-padding kernel variant used when nonpad_kv_seqlen is provided.

Refined fix: skip MEA only when nonpad_kv_seqlen != nullptr && head_size > 256. This preserves MEA performance for normal hd=512 attention while fixing the crash for the TensorScatter/static-cache path.

Verified:

  • hd=512 without nonpad: ✅ (MEA still used, no regression)
  • hd=512 with nonpad=21: ✅ (falls to unfused, previously crashed)

@justinchuby

Copy link
Copy Markdown
Contributor Author

Outdated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant