Skip to content

fix(deepseek-v4): main θ=10000 rope on sliding_attention layers (was θ=160000) - #1

Closed
SeedSource wants to merge 1 commit into
feat/v4-flash-compressed-kv-decode-inc3from
fix/v4-sliding-layer-rope-theta
Closed

fix(deepseek-v4): main θ=10000 rope on sliding_attention layers (was θ=160000)#1
SeedSource wants to merge 1 commit into
feat/v4-flash-compressed-kv-decode-inc3from
fix/v4-sliding-layer-rope-theta

Conversation

@SeedSource

Copy link
Copy Markdown
Owner

fix(deepseek-v4): main θ=10000 rope on sliding_attention layers (was θ=160000)

Stacked on Avarok-Cybersecurity#275 (feat/v4-flash-compressed-kv-decode-inc3) — this touches the V4-Flash attention
rope, which lands via Avarok-Cybersecurity#275; it's meaningless without the port under it. Retarget to main once Avarok-Cybersecurity#275 merges.

The bug

DeepSeek-V4 uses two RoPE bases, per layer type:

  • sliding_attention layers (compress_ratios[L]==0) → main rope, rope_theta=10000, no YaRN;
  • compressed_sparse_attention / heavily_compressed_attentioncompress rope, compress_rope_theta=160000 + YaRN.

Reference modular_deepseek_v4.py (config): "yarn is applied ONLY to layers with a compressor (CSA/HCA); …
main = pure."
Attention selects rope_layer_type = "main" if layer_type=="sliding_attention" else "compress".

Atlas builds a single shared yarn_inv_freq (θ=160000 + YaRN, ensure_yarn_inv_freq) and applies it to the
Q/K rope and the eq.26 output de-rotation on every layer. So the 3 sliding layers (indices 0, 1, 42 in this
checkpoint) rotate with θ=160000 where they must use plain θ=10000.

The error is layer-type-dependent and position-growing (a base-θ difference, not YaRN interpolation), which is
why it was invisible to short-context probes:

decode position max per-dim angle error (θ=160000 vs θ=10000) |Δcos|
150 14.5 rad
240 23.2 rad
330 31.9 rad up to 1.85 (of 2.0 max)

The fix

Add main_inv_freq (plain θ=10000, mscale=1) to MlaWeights; select it over yarn_inv_freq when
mla.compressor.is_none() (== sliding layer) at all four raw-arm rope sites — rope-in and the eq.26
de-rotation, in both prefill (cache_skip_v4.rs) and single-token decode (attention_forward_v4.rs)
. The
de-rotation must match the rope-in inv_freq or the output is scrambled. CSA/HCA layers are unchanged (still
θ=160000 + YaRN). Non-V4 (mistral) loader sets main_inv_freq = yarn_inv_freq (no split). 6 files, +77/−8.

Measured (fp8-KV EP=2, greedy, RoCE-verified; q3/q8 futures risk-sizing gates)

gate before (θ=160000 all layers) after (this fix)
q3 (max size) "10 points / $10,000" — wrong "1 contract … take the trade" — correct (matches NVIDIA NIM reference)
q8 (revenge) fabricates a "$5,000 margin" not in the scenario recalls the real $1,600 / $2,000; verdict still "valid" (should be not-valid)
coherence onset (280-tok non-arithmetic probe) ~150 tok ~150 tok (unchanged)

Scope of the claim: this fixes the sliding-layer rope fault — q3 flips to the correct answer, q8 stops
fabricating numbers. It is not a full task fix: q8's multi-step breach reasoning still errs, and the ~150-token
coherence ceiling is unmoved by this change (measured above) — a separate, still-open issue, not the rope.

Coverage gap (batched / MTP)

This PR splits the rope only on the single-token decode + prefill paths. The batched decode
(trait_impl/multi_seq/mla.rs) and MTP verify paths still apply yarn_inv_freq (θ=160000) to sliding layers.

Observable consequence: single-token (--max-batch-size 1) output on layers 0/1/42 is now correct; batched
decode and MTP-verify output will differ on those layers until they get the same compressor.is_none() split.
A
follow-up will cover them; flagged here so the partial coverage is explicit, not silent.

cargo check + clippy (deny-all) + fmt clean.

🤖 Generated with Claude Code

DeepSeek-V4 uses two RoPE bases: main (rope_theta=10000, no YaRN) for
sliding_attention layers (compress_ratios[L]==0), and compress
(compress_rope_theta=160000 + YaRN) for CSA/HCA. Atlas applied a single
shared yarn_inv_freq (θ=160000) to Q/K rope AND the eq.26 de-rotation on
every layer, so the ratio-0 sliding layers rotated with θ=160000 where
they need plain θ=10000 (angle error 14-32 rad at decode pos 150-330).

Add main_inv_freq (plain θ=10000, mscale=1); select it when
compressor.is_none() at all four raw-arm rope sites (rope-in + eq.26
de-rotate, prefill + single-token decode). CSA/HCA unchanged.

Fixes q3 risk-sizing (was "10 points/$10,000", now "1 contract" = NIM
reference); q8 stops fabricating numbers. Scope: single-token decode +
prefill only — batched (multi_seq/mla.rs) + MTP still apply θ=160000 to
sliding layers (follow-up).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014Txq7YrQQBMeWAs5yFQxQ1
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Thanks for the contribution. Before we can merge, please sign our Contributor License Agreement by replying to this comment with exactly:

I have read the CLA Document and I hereby sign the CLA


Thanks for the contribution. Before we can merge, please sign our Contributor License Agreement by replying to this comment with exactly:

I have read the CLA Document and I hereby sign the CLA


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@SeedSource

Copy link
Copy Markdown
Owner Author

Wrong target — this was against our own fork (SeedSource), invisible to Avarok maintainers. inc3 (base) exists only on the fork, so a cross-fork stacked PR to Avarok can't target it. Holding the rope fix on branch fix/v4-sliding-layer-rope-theta (pushed, verified: 6 files, +77/-8, fmt+clippy-deny-all+compile clean); will open against Avarok-Cybersecurity/atlas base=main once Avarok-Cybersecurity#275 lands inc3→main (one-command retarget was the plan anyway). Body/evidence/stack-note carry over.

@SeedSource SeedSource closed this Jul 6, 2026
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