Repository navigation
Conversation
|
@claude review always |
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
9a32f70 to
25ac4f4
Compare
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
|
@claude review |
1fa6b28 to
df4214c
Compare
25ac4f4 to
ac61006
Compare
df4214c to
f8cd0e7
Compare
ac61006 to
9ec3639
Compare
f8cd0e7 to
2bf5e05
Compare
9ec3639 to
6b216e2
Compare
2bf5e05 to
2b84a30
Compare
6b216e2 to
1dac250
Compare
There was a problem hiding this comment.
Code review found no new issues
No new issues were found in this update; 1 finding from earlier reviews is still open above.
Still open from earlier reviews (1):
- 🔴
miles/backends/fsdp_utils/actor.py:410—Packed micro-batches whose pad tail is longer than every real document can now get uninitialized attention outputs or g…
If you have decided not to act on one of these findings, resolve its thread (a reply alone leaves it open) and the next review stops counting it. To review this commit again now, use Re-run on its "Claude Code Review" check.
…its own real_max_seqlen dropped the pad segment from max_length while cu_seqlens still carried it as one segment of up to 127 tokens; FlashAttention leaves rows past max_length unwritten, so pad rows could get uninitialized outputs and gradients. hf_attention_packing_kwargs now passes the documents, then each pad token as a 1-token segment, exactly what HF's position_ids path derives, so the longest real document covers every segment. It is built on the device from host lengths, without a sync. Qwen3.5 keeps get_batch's boundaries and max_seqlen as on main. Reported by claude[bot] on #4316. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its own real_max_seqlen dropped the pad segment from max_length while cu_seqlens still carried it as one segment of up to 127 tokens; FlashAttention leaves rows past max_length unwritten, so pad rows could get uninitialized outputs and gradients. hf_attention_packing_kwargs now passes the documents, then each pad token as a 1-token segment, exactly what HF's position_ids path derives, so the longest real document covers every segment. It is built on the device from host lengths, without a sync. Qwen3.5 keeps get_batch's boundaries and max_seqlen as on main. Reported by claude[bot] on #4316. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52990f6 to
e3fa3d7
Compare
Only the GatedDeltaNet adapters handed the model the boundaries get_batch records; every other arch left HF to re-derive them from position_ids in each attention layer. That fallback gives the kernel max_length as a 0-d tensor, which FlashAttention-2 tolerates and FlashAttention-4 rejects, so FSDP could not train on the FlashAttention-4 that SGLang installs, the only training-capable attention a pip install without a flash-attn build has. Adapters for stock HF modeling (Qwen3, Qwen3-MoE, Qwen3-VL, GLM-4.7-Flash) now opt in with passes_attention_packing_kwargs and send cu_seq_lens_q/k and max_length_q/k, with max_length a Python int. Remote code and unknown archs keep their stock inputs. Qwen3-VL, like Qwen3.5, keeps them out of its vision tower; that guard moves to packing.py beside the kwargs it drops. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
transformers resolves any *flash* attn_implementation to a FlashAttention kernel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With them, Qwen3 on FlashAttention-3 took HF's varlen-kwargs branch instead of re-deriving the boundaries from position_ids, and the true-on-policy e2e test lost bitwise parity with SGLang (log_probs -1.38827 vs rollout -1.38723). Only FlashAttention-4 rejects the re-derived boundaries, so only it gets them now; every other kernel keeps HF's path as on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
get_batch's max_seqlen also counts the trailing pad segment, which HF's own position_ids path never does, and FlashAttention picks its launch plan from max_seqlen. batch["max_seqlen"] itself is unchanged (Megatron reads it). Found by an adversarial review of this PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ntion-4 This reverts the FlashAttention-4-only gate. True-on-policy's FA3 bitwise break came from max_length counting the pad segment, not from the boundaries themselves: with the longest real document as max_length (previous commit) and the boundaries sent under every kernel, the true-on-policy e2e test is bit-identical again (H200, train_rollout_logprob_abs_diff 0.0 on all five rollouts). Without the gate, the kernels-community/flash-attn4 spelling of --attn-implementation gets the boundaries too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on-4 needs The actor test's pad segment was as long as its longest document, so it could not tell get_batch's max_seqlen from the real one. The docs now list every architecture that passes the boundaries and say the rest cannot use flash_attention_4 yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its own real_max_seqlen dropped the pad segment from max_length while cu_seqlens still carried it as one segment of up to 127 tokens; FlashAttention leaves rows past max_length unwritten, so pad rows could get uninitialized outputs and gradients. hf_attention_packing_kwargs now passes the documents, then each pad token as a 1-token segment, exactly what HF's position_ids path derives, so the longest real document covers every segment. It is built on the device from host lengths, without a sync. Qwen3.5 keeps get_batch's boundaries and max_seqlen as on main. Reported by claude[bot] on #4316. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
a53d9a6 to
9022cb2
Compare
e3fa3d7 to
cecb2b4
Compare
guapisolo
left a comment
There was a problem hiding this comment.
cc cmt
Approving #4316 at cecb2b4. No blocking findings in this increment. The review ran at e3fa3d7; this head is the same patch rebased, plus main's config-access-exempt comments on the moved keep_packing_kwargs_out_of_vision.
Verification: read-only review of this increment at e3fa3d7 with its green PR Test run (40553236168), and a comparison of the incremental diffs at both heads. Not covered: the checks still running at this head, a FlashAttention-4 end-to-end run with the final boundary logic, and bitwise parity of a single unpadded document between the dense and varlen FA2/FA3 paths.
Stack (merge in order): #4308 → #4315 → #4316 → #4311 (needs radixark/miles-wheels#4).
Problem
Only the GatedDeltaNet adapters passed the model the packed-document boundaries
get_batchrecords. For every other arch, HF re-derived them fromposition_idsin each attention layer, withmax_lengthas a 0-d tensor. FlashAttention-2 accepts that; FlashAttention-4 raisesExpected IntTuple, whose leaves are integers, but got 1223. FA4 is the only training-capable attention a pip install has without aflash-attnbuild: SGLang depends on it, and its own FA3 (insglang-kernel) is forward-only.Change
hf_attention_packing_kwargs:cu_seq_lens_q/k,max_length_q/k(an int).ArchAdapter.passes_attention_packing_kwargs, set on Qwen3, Qwen3-MoE, Qwen3-VL and GLM-4.7-Flash (stock HF modeling), sends them under every kernel. Remote code and archs without an adapter keep{}; NemotronH is unchanged.position_ids: the documents, then each pad token as its own 1-token segment, built on the device from host lengths (no sync).max_lengthis then the longest real document and covers every segment.get_batchkeeps the pad tail as one segment; sending that with its pad-inflatedmax_seqlenchanged FlashAttention's launch plan and broke true-on-policy's bitwise parity under FA3 (log_probs -1.38827 vs rollout -1.38723), and a real-document max with the one-segment tail would leave pad rows unwritten. Qwen3.5 keepsget_batch's boundaries andmax_seqlenas onmain.packing.py; Qwen3-VL applies it like Qwen3.5.--attn-implementation flash_attention_4, and which architectures can use it.With FlashAttention-2/3 these archs now take HF's varlen-kwargs branch instead of re-deriving the boundaries per layer, with the same boundaries for real tokens.
Testing
On an H200 devbox with the miles CI image, at this PR's head:
tests/e2e/fsdp/test_qwen3_0_6b_fsdp_sampling_support_replay_true_on_policy.py(FlashAttention-3, boundaries sent) passes:train_rollout_logprob_abs_diff0.0 on all 5 rollouts.test_fsdp_hf_compat.py,test_fsdp_hub_kernels.py,fsdp_utils/test_actor.py,test_fsdp_attn_bridge.pyandtests/fast-gpu/test_fsdp_gated_deltanet_packing.py: 94 pass. Three CPU-tensor Qwen3.5 tests fail identically on unmodifiedmainin that image (its Triton /causal_conv1dkernels reject CPU tensors); the hosted CPU stage passes them.max_length; attention boundaries equal transformers' ownprepare_fa_kwargs_from_position_ids(pad 0, 1, 7); the actor gives stock HF attention each pad token as its own segment, without a device sync (GPU); Qwen3-VL's tower never sees them.flash_attention_4(exit 0, log-prob gap 0.0199 → 0.0157, grad norm 0.36 / 0.43), matching a FlashAttention-2 run. That run predates the real-max change.run-ci-fsdpbefore merge (label on).🤖 Generated with Claude Code