[None][fix] Fix unfused RoPE for yarn models: double rotation and GPT-OSS pairing - #16378
Conversation
Two stacked bugs made rope_fusion=False produce position-dependent garbage for GPT-OSS (and would for any yarn-scaled model): 1. Double RoPE: create_attention hands pos_embd_params to the backend whenever the embedding type is not in PositionEmbeddingType.is_rope(). yarn was missing from that list, so with rope_fusion=False the Python RotaryEmbedding rotated q/k once and the C++ QKV preprocess (which maps yarn onto its NeoX rotation branch) rotated them again before writing the KV cache: cached K ended up mscale^2-scaled and rotated by twice the angle, so the error grows with position and long generations degrade into fragments. Adding yarn to is_rope() restores the intended ownership (Python side rotates, backend receives no rope params) and extends the existing params validation to yarn. 2. GPT-OSS declared is_neox=False, but the model applies NeoX-style (rotate-half) RoPE, as in the HF reference. The fused kernel ignores the flag for yarn and always rotates NeoX-style, which masked the wrong value; the unfused path honors it and applied interleaved pairing. (modeling_mistral.py declares is_neox=False for yarn too and may deserve the same audit.) Verified on GPT-OSS-20B: post-fix unfused K cache is bitwise-aligned with the fused path at every position (cos=1.0, norm ratio=1.0); AIME25 avg pass@1 (n=8, official sampling) is 70.83 fused vs 70.00 unfused. Pre-fix unfused scored 0. Regression tests cover backend ownership and pairing-convention parity against the kernel cos/sin table. Signed-off-by: tianruih <tianruih@nvidia.com>
c1455b4 to
11e2ba3
Compare
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughYARN is now classified as a RoPE type, GPT-OSS uses NeoX YARN parameterization, and tests cover unfused YARN ownership and numerical rotation behavior. ChangesYARN RoPE handling
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
/bot run --disable-fail-fast |
|
PR_Github #59223 [ run ] triggered by Bot. Commit: |
|
PR_Github #59223 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #59318 [ run ] triggered by Bot. Commit: |
|
PR_Github #59318 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #59374 [ run ] triggered by Bot. Commit: |
|
PR_Github #59374 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #59403 [ run ] triggered by Bot. Commit: |
|
PR_Github #59403 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #59434 [ run ] triggered by Bot. Commit: |
|
PR_Github #59434 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #59449 [ run ] triggered by Bot. Commit: |
|
PR_Github #59449 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #59460 [ run ] triggered by Bot. Commit: |
|
PR_Github #59460 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #59570 [ run ] triggered by Bot. Commit: |
|
PR_Github #59570 [ run ] completed with state |
Description
With
rope_fusion=False, GPT-OSS (and any yarn-scaled model on the unfusedpath) generates position-dependent garbage: short outputs look fine, long
generations degrade into fragments. Two independent bugs stack on this path,
and both are needed for a correct rotation — one fix controls how many
times RoPE is applied, the other how it is applied.
Bug 1: RoPE applied twice (yarn missing from
is_rope())create_attentionhandspos_embd_paramsto the backend whenever theembedding type is not in
PositionEmbeddingType.is_rope(). yarn was missingfrom that list, so with
rope_fusion=Falsethe PythonRotaryEmbeddingrotated q/k once and the C++ QKV preprocess (which maps yarn onto its NeoX
rotation branch) rotated them again before writing the KV cache. The cached
K ends up mscale²-scaled and rotated by twice the angle, so the error grows
with position.
Fix: add
yarntois_rope(). The existing condition then keeps therope params away from the backend on the unfused path, and the existing
"rope types must carry rope params" validation now covers yarn too.
Bug 2: wrong pairing convention (GPT-OSS
is_neox=False)GPT-OSS applies NeoX-style (rotate-half) RoPE, matching the HF reference,
but declared
is_neox=False(GPT-J interleaved). The fused kernel ignoresthis flag for yarn and always rotates NeoX-style, which masked the wrong
value since the model landed (#6645); the unfused path honors the flag and
paired the rotary dims incorrectly.
Fix:
is_neox=True. No effect on the fused path (the flag is unusedthere).
modeling_mistral.pyalso declaresis_neox=Falsefor yarn and maydeserve the same audit.
Why both are required
Fixing only Bug 2 still double-rotates; fixing only Bug 1 leaves the single
rotation incorrectly paired. Either alone still produces garbage.
Evidence (GPT-OSS-20B)
every position (cos = 1.0, norm ratio = 1.0). Pre-fix it decayed to
cos = −0.18 by position 150 with a norm ratio equal to the yarn mscale
(1.3466) — the fingerprint of a second yarn rotation.
sparse-attention methods that require unfused RoPE.
Test Coverage
Two regression tests in
tests/unittest/_torch/modules/test_rotary_embedding.py(registered in
l0_h100.yml):cannot be applied twice);
convention on the same cos/sin table (bit-level comparison).
Summary by CodeRabbit
Bug Fixes
Tests