Skip to content

fix(vllm): make Kimi-K3 AttnRes hidden-state capture invariant to the PP partition - #167

Merged
yubofredwang merged 3 commits into
mainfrom
fix/k3-attnres-pp-invariant
Aug 10, 2026
Merged

fix(vllm): make Kimi-K3 AttnRes hidden-state capture invariant to the PP partition#167
yubofredwang merged 3 commits into
mainfrom
fix/k3-attnres-pp-invariant

Conversation

@torchspec-bot

@torchspec-bot torchspec-bot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Two bugs made the exported Kimi-K3 aux hidden states depend on where the pipeline was cut. Both are in the patched vLLM image, both are fixed here, and both are verified bit-identical against a PP=1 run on GB300.

Boundary tap

Under AttnRes the feature for capture id k is a softmax mixture computed with layer k's self_attention_res_norm / _proj. When k is a non-last stage's end_layer, those weights live on the next rank. Upstream vllm falls back to the running prefix there, which is a different feature entirely — cosine 0.05 to 0.60 against the real mixture. Rejecting the id instead, which is what this patch did before, does not survive mostly-PP sharding: for the 93-layer stage-1 recipe every intermediate id is a stage end from pp=40 on.

Everything else the tap needs is already local, so a non-last AttnRes stage now keeps a copy of those two hidden-size vectors (~28KB, unsharded) and computes the mixture itself. A checkpoint that does not supply them fails at configuration time rather than exporting NaNs.

Kernel dispatch after a handoff

Found while measuring the above. attn_res only takes its fused native path when a delta is supplied, and the PP handoff folds the delta into the prefix. The first layer of every non-first stage was therefore running the Triton fallback, which differs from the native op on ~0.008% of elements and compounds through the rest of the stack — so the arithmetic, not just the boundary tap, depended on the partition. An explicit zero delta restores the dispatch, and is skipped for block-write layers, which never reach that path.

Verification

GB300, real kernel, 32 layers / block size 8: the boundary tap is bit-identical to the PP=1 capture at every split point, and end-to-end bit-identity across the whole two-stage run goes from 4 of 31 split points to 31 of 31.

tests/vllm_k3_tests.patch is new. test_pp_handoff.py fails without the zero-delta fix; test_eagle3.py picks up two fixture updates from the #50487 backport and now also asserts the tap passes no delta and no block write, which is what keeps it a pure read of state the next stage consumes.

Background and derivations are in docs/kimi_k3_attn_res_capture.md.

Test plan

  • Full patch stack applies clean to the pinned nightly tree
  • tests/models/kimi_k3/test_pp_handoff.py + test_eagle3.py: 7 passed in the pinned image
  • ruff check / ruff format --check clean on the patched files
  • GB300 equivalence harness against the real attn_res kernel

A capture id at a non-last stage's end_layer needs that layer's mixture
weights, which live on the next rank.  #50487 falls back to the running
prefix there, a different feature; rejecting the id instead, as this patch
previously did, does not survive mostly-PP sharding.  Keep a copy of the two
hidden-size vectors on the stage that taps them.

Separately, the handoff folds the delta into the prefix, which drops the
first layer of every non-first stage onto the Triton fallback and shifts the
arithmetic for everything after it.  Feed that layer a zero delta.

Both verified bit-identical against PP=1 on GB300 at every split point.

Signed-off-by: torchspec-bot <262938024+torchspec-bot@users.noreply.github.com>
test_pp_handoff.py fails without the zero-delta fix.  test_eagle3.py needed
two fixture updates from the #50487 backport, and now also asserts the tap
passes no delta and no block write, which is what makes it a pure read.

Signed-off-by: torchspec-bot <262938024+torchspec-bot@users.noreply.github.com>
Why the tap is a second kernel call, what the two PP bugs were, and what
capture and the handoff cost.

Signed-off-by: torchspec-bot <262938024+torchspec-bot@users.noreply.github.com>
@torchspec-bot
torchspec-bot force-pushed the fix/k3-attnres-pp-invariant branch from d583a7f to a20ec96 Compare August 10, 2026 02:58

@yubofredwang yubofredwang left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM! thx for the fix.

@@ -0,0 +1,251 @@
# Capturing Kimi-K3 Hidden States under AttnRes

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we can make this into a single recipe doc in the future.

@@ -28,6 +28,31 @@ logs the active mode once at configuration time:
Once the base image carries PR #50487, drop this patch but keep exporting

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

confirm this patch builds correctly

@torchspec-bot
torchspec-bot force-pushed the fix/k3-attnres-pp-invariant branch from a20ec96 to d20918d Compare August 10, 2026 03:03
@yubofredwang
yubofredwang merged commit f054862 into main Aug 10, 2026
2 checks passed
@yubofredwang
yubofredwang deleted the fix/k3-attnres-pp-invariant branch August 10, 2026 04:00
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.

2 participants