Skip to content

Fix CPU Attention causal mask alignment - #29050

Merged
titaiwangms merged 4 commits into
microsoft:mainfrom
FuZoe:codex-fix-attention-causal-upper-left
Jun 25, 2026
Merged

Fix CPU Attention causal mask alignment#29050
titaiwangms merged 4 commits into
microsoft:mainfrom
FuZoe:codex-fix-attention-causal-upper-left

Conversation

@FuZoe

@FuZoe FuZoe commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #29020

Validation

  • python -m py_compile onnxruntime/test/python/transformers/test_onnx_attention/common.py onnxruntime/test/python/transformers/test_onnx_attention/test_mha.py onnxruntime/test/python/transformers/test_onnx_attention/test_gqa.py onnxruntime/test/python/transformers/test_onnx_attention/test_tensorscatter_attention.py
  • git diff --check

Notes:

  • pytest onnxruntime/test/python/transformers/test_onnx_attention/test_tensorscatter_attention.py -k "cpu_fp32 and causal" -q could not run locally because this Python environment does not have onnx / onnxruntime installed.
  • After the latest follow-up commit, an incremental rebuild of onnxruntime_provider_test was attempted but failed in MSBuild before compiling this change due to a local environment issue: duplicate Path / PATH environment keys when launching CL.exe.

@FuZoe FuZoe changed the title [codex] Fix CPU Attention causal mask alignment Fix CPU Attention causal mask alignment Jun 15, 2026
@tianleiwu

Copy link
Copy Markdown
Contributor

#28958 tried to fix the same issue?

@FuZoe

FuZoe commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

I checked the #28958 diff. It appears to target the opset-24 nonpad_kv_seqlen external/static KV-cache path.

For the #29020 repro path, where there is no nonpad_kv_seqlen, CPU still has:

bool causal = parameters.is_causal && parameters.q_sequence_length > 1;

So for is_causal=1, q_len=1, kv_len>1, no past, and no nonpad_kv_seqlen, CPU still skips causal masking in #28958.

This PR fixes that separate no-nonpad_kv_seqlen path. The two PRs are complementary — #28958 handles the nonpad_kv_seqlen path, this one handles the plain no-past path.

@FuZoe

FuZoe commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Local Windows CPU validation:

.\build\Windows\Release\Release\onnxruntime_provider_test.exe --gtest_filter=AttentionTest.Attention4DCausalSingleQueryCrossAttentionUpperLeft

Result:

[ RUN      ] AttentionTest.Attention4DCausalSingleQueryCrossAttentionUpperLeft
[       OK ] AttentionTest.Attention4DCausalSingleQueryCrossAttentionUpperLeft (7 ms)
[  PASSED  ] 1 test.
QQ_1781505563944

@FuZoe

FuZoe commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree

@FuZoe
FuZoe marked this pull request as ready for review June 15, 2026 07:01
@tianleiwu
tianleiwu requested review from Copilot and titaiwangms June 15, 2026 08:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns the CPU Execution Provider’s opset-23 Attention causal masking behavior with the ONNX spec’s upper-left alignment for the q_len=1, kv_len>1, no past case (matching CUDA), and updates the Python reference implementation plus tests to reflect the same semantics. It also adds a targeted regression test for the CPU/CUDA divergence reported in issue #29020.

Changes:

  • Fix CPU causal-mask gating so is_causal=1 is honored for q_sequence_length==1 when there is no past.
  • Update the Python attention reference causal mask to model ONNX “upper-left” alignment, with an explicit past_seqlen offset.
  • Add a regression test that fails if CPU incorrectly allows the single query to attend to all KV positions in the no-past cross-attention case.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
onnxruntime/core/providers/cpu/llm/attention.cc Adjusts causal-mask enablement so q_len==1 no longer disables causal masking when past_sequence_length==0.
onnxruntime/test/providers/cpu/llm/attention_op_test.cc Adds Attention4DCausalSingleQueryCrossAttentionUpperLeft to prevent CPU/CUDA divergence for q_len=1, kv_len>1, no past.
onnxruntime/test/python/transformers/test_onnx_attention/common.py Updates reference causal mask to ONNX upper-left behavior and adds past_seqlen to correctly offset decode masking.
onnxruntime/test/python/transformers/test_onnx_attention/test_mha.py Passes past_seqlen into the Python reference attention for decode/past parity checks.
onnxruntime/test/python/transformers/test_onnx_attention/test_gqa.py Passes past_seqlen into the Python reference attention for GQA decode/past parity checks (including padding path).

@FuZoe FuZoe closed this Jun 15, 2026
@FuZoe FuZoe reopened this Jun 15, 2026
@FuZoe

FuZoe commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

CI workflows are pending maintainer approval for the latest commit.

@FuZoe

FuZoe commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

The merge conflicts are resolved now. Please continue the review when convenient.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment thread onnxruntime/core/providers/cpu/llm/attention.cc
titaiwangms
titaiwangms previously approved these changes Jun 23, 2026

@titaiwangms titaiwangms left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Minor / nits (non-blocking): add a comment explaining why the nonpad branch drops causal at q=1; add a CPU regression test for  nonpad+causal+q=1 ; the new test ( y  all-ones vs 1/6 unfixed) is correctly discriminative.

@FuZoe

FuZoe commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Thanks. I added a comment explaining why the nonpad q_len=1 path keeps causal disabled, and added a CPU regression test for nonpad + causal + q_len=1.

The new test expects 1/6 for bottom-right decode behavior; applying the no-nonpad upper-left overlay would produce 1.0 instead.

@titaiwangms
titaiwangms enabled auto-merge (squash) June 25, 2026 00:58
@titaiwangms
titaiwangms merged commit d4b01e4 into microsoft:main Jun 25, 2026
90 of 91 checks passed
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.

Opset-23 Attention op: is_causal alignment differs between CPU (bottom-right) and CUDA (upper-left) for q_len < kv_len with no past

4 participants