Repository navigation
Bind one DFlash2 draft embedding layout on every Qwen Flash rank - #250
Merged
Merged
Conversation
Tensor-parallel export of Qwen3.8 Flash Next with DFlash2 speculation cannot complete. Tensor-parallel ranks compile each forward once and every rank binds the same compiled artifact; the compiled-forward bindings compare each input's shape, strides, storage offset, dtype, device and alias. Every rank holds the full replicated target embedding table (248320 x 2560 BF16), and the DFlash2 draft received a column view of that table for its sharded lookup. That view starts at element offset 1280 on TP2 rank 1 (640, 1280 and 1920 on TP4 ranks 1-3), so rank 1 rejects the speculative32x4 forward with BindingMismatch during "Load and warm compiled forwards". Giving each rank a contiguous copy of its columns gives every rank the same layout at offset zero, the layout the shared sharded-embedding lookup receives from recipes that load embedding columns as separate per-rank tensors. Previously SpeculativePreparation in ignition/recipes/qwen38/dflash.py sliced embed_tokens.weight[:, first:last] itself. Now draft_embedding() returns the rank's columns as a contiguous tensor; Qwen bootstrap creates it beside the draft head conversion, inside the core preparation pool, and passes it to SpeculativePreparation. With one rank the column range covers the contiguous table and draft_embedding() returns the target table without copying, so TP1 DFlash2 and MTP preparation are unchanged. Each tensor-parallel rank holds an additional copy of its embedding columns: 0.64 GB per rank at TP2 and 0.32 GB at TP4, alongside the replicated 1.27 GB target table. Result: TP2 and TP4 DFlash2 exports of Qwen3.8 Flash Next complete on DGX Spark, and the TP2 core serves. Validation: tests/recipes/test_qwen38_dflash_embedding.py checks at TP1, TP2 and TP4 that every rank's draft embedding holds that rank's columns at storage offset zero and that all ranks produce one compiled-input signature (ignition.preparation.aot._signature), and that TP1 reuses the target storage. The previous column view produces two distinct signatures at TP2 and four at TP4. The Qwen and DFlash2 CPU recipe tests show the same 24 failures with and without this change (478 passed on unmodified main, 482 with this change including the four added tests). On DGX Spark (GB10, SM121), exports of nvidia/Qwen3.8-Flash-Next-FP4-Local at recipe defaults with --speculative-method dflash2 and the incoai/Qwen3.8-Flash-Next-DFlash2 draft at a22a1744: - TP2 on two Sparks, before this change on 8c2e782: failed in "Load and warm compiled forwards" with BindingMismatch on speculative32x4 input 59, a (248320, 1280) BF16 view expected at storage offset 0 and supplied at 1280. - TP2 with this change: warmed 76/76 compiled forwards, captured 112 graphs and committed its core. - TP4 on four Sparks with this change: warmed 76/76 compiled forwards, captured 112 graphs and committed its core. The TP2 core served at concurrency 32 and answered a chat request correctly, accepting 33 draft tokens over 15 draft rounds. Serving it required a runtime that also carries the RoCE proxy ABI 11 change of PR #232, because main's Helios loads only cores recording proxy ABI 9 or 10. The TP4 core has not been served, and DFlash2 throughput and acceptance have not been compared with MTP. Design-Signed-Off-By: flare-02; design-review=cfcf
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.
Why
Tensor-parallel export of Qwen3.8 Flash Next with
--speculative-method dflash2cannot complete. Tensor-parallel ranks compile each forward once and every rank binds the same compiled artifact, and the compiled-forward bindings compare each input's shape, strides, storage offset, dtype, device and alias. Every Qwen rank holds the full replicated target embedding table (248320 × 2560 BF16), and the DFlash2 draft received a column view of that table (embed_tokens.weight[:, first:last]) for its sharded lookup. That view starts at element offset 1280 on TP2 rank 1, and at 640, 1280 and 1920 on TP4 ranks 1–3. Rank 1 therefore rejects thespeculative32x4forward withBindingMismatchduring "Load and warm compiled forwards", and the export stops. Commit d68ed8f, which added Qwen Flash Next DFlash2, was GPU-validated at TP1 only.A contiguous per-rank copy of the draft's embedding columns starts at offset zero on every rank. Other recipes that use the shared sharded-embedding lookup already pass it embedding columns loaded as separate per-rank tensors, which have that layout.
What changed
ignition/recipes/qwen38/dflash.py:SpeculativePreparationpreviously sliced the target embedding itself. It now takes adraft_embeddingargument, and the newdraft_embedding()function returns the rank's columns as a contiguous tensor. With one rank the column range covers the whole contiguous table, sodraft_embedding()returns the target table without copying.ignition/recipes/qwen38/bootstrap.py: creates the draft embedding next to the draft-head conversion, inside the core preparation pool, and passes it toSpeculativePreparation.tests/recipes/test_qwen38_dflash_embedding.py: covers the per-rank layout and the shared binding signature.TP1 DFlash2 and MTP preparation are unchanged. Each tensor-parallel rank holds one extra copy of its embedding columns: 0.64 GB per rank at TP2 and 0.32 GB at TP4, in addition to the replicated 1.27 GB target table.
Result
TP2 and TP4 DFlash2 exports of Qwen3.8 Flash Next complete on DGX Spark, and the TP2 core serves and generates. This is a correctness fix. No throughput or acceptance claim is made.
Evidence
ignition.preparation.aot._signature), and that TP1 reuses the target storage. The previous column view produces two distinct signatures at TP2 and four at TP4.mainhas 478 passing; this branch has 482, the extra four being the added tests.nvidia/Qwen3.8-Flash-Next-FP4-Localat recipe defaults with theincoai/Qwen3.8-Flash-Next-DFlash2draft at revisiona22a1744:8c2e782d, before this change: failed in "Load and warm compiled forwards" withBindingMismatchonspeculative32x4input 59, a(248320, 1280)BF16 view expected at storage offset 0 and supplied at offset 1280.Limitations
mainexports multi-host cores that record proxy ABI 11, but its Helios loads only cores recording ABI 9 or 10. That mismatch is independent of this change and affects every multi-host RoCE core exported frommain.