fix(deepseek-v4): main θ=10000 rope on sliding_attention layers (was θ=160000) - #1
Conversation
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
|
Thanks for the contribution. Before we can merge, please sign our Contributor License Agreement by replying to this comment with exactly:
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 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. |
|
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. |
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 attentionrope, which lands via Avarok-Cybersecurity#275; it's meaningless without the port under it. Retarget to
mainonce Avarok-Cybersecurity#275 merges.The bug
DeepSeek-V4 uses two RoPE bases, per layer type:
sliding_attentionlayers (compress_ratios[L]==0) → main rope,rope_theta=10000, no YaRN;compressed_sparse_attention/heavily_compressed_attention→ compress 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 theQ/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:
The fix
Add
main_inv_freq(plain θ=10000, mscale=1) toMlaWeights; select it overyarn_inv_freqwhenmla.compressor.is_none()(== sliding layer) at all four raw-arm rope sites — rope-in and the eq.26de-rotation, in both prefill (
cache_skip_v4.rs) and single-token decode (attention_forward_v4.rs). Thede-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)
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 applyyarn_inv_freq(θ=160000) to sliding layers.Observable consequence: single-token (
--max-batch-size 1) output on layers 0/1/42 is now correct; batcheddecode and MTP-verify output will differ on those layers until they get the same
compressor.is_none()split. Afollow-up will cover them; flagged here so the partial coverage is explicit, not silent.
cargo check+clippy(deny-all) +fmtclean.🤖 Generated with Claude Code