Repository navigation
Fix internlm3 dynamic-NTK RoPE: wrong seq axis, scale/factor conflation - #1553
Closed
robertlangdonn wants to merge 1 commit into
Closed
robertlangdonn wants to merge 1 commit into
robertlangdonn wants to merge 1 commit into
Conversation
3 tasks done
Four related bugs in DynamicNTKScalingRoPE and its construction: - Position scale defaulted to 2.0 whenever scaling wasn't "linear", doubling every position for "dynamic" and no-scaling configs alike. Only "linear" should scale positions (1/factor); default is 1.0. - The dynamic-NTK base formula reused that same (wrong) 2.0 instead of the config's `factor`, so a real config (e.g. factor=6.0) never reached the base recomputation. - seq_len was read from x.shape[1], the head-count axis post-transpose ([B, n_heads, L, head_dim]) -- not the sequence axis (shape[2]). The dynamic recompute could never fire at prefill regardless of prompt length. - The base recompute wasn't gated on rope_type, so "linear" scaling also rewrote the base past max_position_embeddings, when it should stay static and only the position scale should apply.
robertlangdonn
force-pushed
the
fix-internlm3-rope-dynamic-ntk
branch
from
July 11, 2026 21:28
326163d to
62fc2c7
Compare
Member
|
Thanks for the PR but at the moment the number of PRs is way beyond our capacity to review so I'm closing the non-essential ones so we can actually work on this repo. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix internlm3 dynamic-NTK RoPE: wrong seq axis, scale/factor conflation
Summary
Fixes #1545. Credit to @magicnight for the full root-cause diagnosis in the issue (checked against InternLM's reference
modeling_internlm3.py) — this PR independently verifies each of the four defects against the real code and adds regression tests.Four related bugs in
internlm3.py'sDynamicNTKScalingRoPEand its construction inAttention.__init__:"linear"— including the common case of norope_scalingat all — doubling every position index fed intomx.fast.rope. Only"linear"should scale positions (1/factor); the default should be1.0.factor, so a real config (e.g.factor=6.0) never reached the base recomputation.seq_lenwas read fromx.shape[1]— the head-count axis post-transpose ([B, n_heads, L, head_dim]) — not the sequence axis (shape[2]). The dynamic recompute could never fire at prefill regardless of prompt length (head count is typically far belowmax_position_embeddings).rope_type—"linear"scaling also rewrote the base once pastmax_position_embeddings, when it should stay static and only the position scale should apply.Fix
scaleintoscale(position scale,mx.fast.rope'sscale=) and a newntk_factor(the configfactor, used only in the base-growth formula).rope_typeis now threaded intoDynamicNTKScalingRoPEand gates the base recompute (if self.rope_type == "dynamic" and seq_len > self.max_position_embeddings).seq_len = x.shape[2] + offsetinstead ofx.shape[1].Total change: +23/−9 in
mlx_lm/models/internlm3.py.Verification
Falsified all four defects against the pre-fix code directly (no checkpoint needed — these are pure position-math bugs reproducible with tiny synthetic tensors), then verified each is fixed:
rope_scaling→self.rope.scalewas2.0, now1.0.{"factor": 6.0, "rope_type": "dynamic"}→self.rope.scalewas2.0(factor discarded), nowscale=1.0/ntk_factor=6.0.(1, 4, 100, 8)(4 heads, 100 real sequence positions,max_position_embeddings=64) — pre-fix,seq_lenread as4and the dynamic recompute never fired; post-fix,seq_len=100correctly triggers it."linear"mode withreal seq_len=50 > max_position_embeddings=8— pre-fix, the base was rewritten anyway; post-fix, output is identical to a run wheremax_position_embeddingsis never exceeded (base provably stayed static).internlm3.Model(tiny synthetic config,rope_scaling={"factor": 4.0, "rope_type": "dynamic"}), prefill pastmax_position_embeddingsthen several decode steps — runs cleanly.Test plan
test_internlm3_dynamic_ntk_rope— covers all four defects (scale defaults, factor threading, correct seq axis via an actual-effect comparison rather than just checking it doesn't crash, and linear-mode base staying static). Confirmed it fails on pre-fix code (2.0 != 1.0) and passes post-fix.python -m unittest discover tests/— pre-existing unrelated import errors only (datasets/lm_eval/requests, optional deps not installed locally).pre-commit run --files mlx_lm/models/internlm3.py tests/test_models.py— clean.Note
internlm2.pyhas an identical copy-pastedDynamicNTKScalingRoPEwith the same four bugs. Filing that as a separate PR against that file rather than bundling it here, to keep this one scoped to the reported issue.