Skip to content

[WS1][CUDA][Qwen3-Next] EP4 distributed logprob parity: expert-parallel MoE, full-model L2 bitwise on TP4 x EP4 (RFC #428 stack 10/11) - #557

Open
fusheng-ji wants to merge 155 commits into
RL-Align:test-qwennextfrom
fusheng-ji:feat/ws1-qwen3-next-distributed-logprob-ep
Open

fusheng-ji wants to merge 155 commits into
RL-Align:test-qwennextfrom
fusheng-ji:feat/ws1-qwen3-next-distributed-logprob-ep

Conversation

@fusheng-ji

@fusheng-ji fusheng-ji commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Stack: #466 (merged) → #467 → #468 → #469 → #503 → #507 → #543 → #544 → #549 → this PR → benchmarks (#551), base test-qwennext; merges after #549. This PR's own diff. RFC #428 row distributed_logprob_parity, CUDA, EP part; the TP part is #549.

What

  • EP4 MoE layer (rl_engine/models/qwen3_next/qwen3_next_ep.py): expert parallel 4 over the TP4 group, expert tensor parallel 1. Rank r owns experts [128r, 128r + 128) at full width; attention, GDN, embedding, LM head and the shared expert stay TP4.
    • Dispatch is a local selection, since the MoE input is already replicated and every rank computes the same routes.
    • Each rank evaluates its own routes with the fixed-config grouped GEMM of [WS1][CUDA][Qwen3-Next] MoE route/combine contract with a batch-invariant grouped expert GEMM (RFC #428 stack 5/11) #503. The rows are exchanged with the fixed-order collective's all_gather, which is a byte copy with no arithmetic.
    • Every rank then applies combine_routes (FP32, route order) locally.
    • Backward: weight gradients only on the owning rank; per-route input gradients exchanged and summed in ascending expert order, as EP1 does.
    • A route slot owned by no rank, or by two, fails closed.
  • vLLM rollout: enable_expert_parallel with linear placement; SharedVLLMMoE uses the EP path and checks that vLLM's expert_map is exactly [128r, 128r + 128).
  • VIME replay: Megatron expert_model_parallel_size 4, expert_tensor_parallel_size 1. SharedVIMEEPMoE asserts that the expert-parallel rank equals the TP rank, and the HF loader returns only local experts.
  • Launcher and gates: qwen3_next_run.py --ep {1,4} records the topology in run.json, and every later stage checks it. The layers stage runs the new EP4 MoE gate (moe_ep) in place of the TP4 MoE gate.
  • Fail closed: both engines, the scheduler gate and the L2 report accept only TP4 / PP1 / CP1 with EP 1 (expert tensor parallel 4) or EP 4 (expert tensor parallel 1). The training actor and HF export reject EP4.
  • Contract (docs/operators/qwen3-next-distributed-logprob.md): new EP section, one row per cross-rank point.
  • Chain report: names the measured EP size in its disclaimer and backend profile.
  • Real tests, not stand-ins: the vLLM model contract builds a real VllmConfig from vLLM's own config classes (tests/models/qwen3_next/vllm_real.py), and check_qwen3_next_vllm_real_model.py builds RL-Kernel's wrapper around vLLM's actual Qwen3NextForCausalLM on four real ranks at EP1 and EP4 (weights allocated, not loaded): drift rejected before any model memory is allocated; 48 layers hold the shared classes and shapes; the routed-expert parameters keep vLLM's native weight loaders; at EP4 vLLM's own expert_map equals [128r, 128r + 128) and every expert is held once. Both run in preflight's device guards, which previously ran only the multi-GPU guard.
  • Layout as reviewed on [WS1][CUDA][Qwen3-Next] TP distributed logprob parity: fixed reduction order, selected-token logprob exact across NCCL settings (RFC #428 stack 9/11) #549 from the start: runners under tools/validation/models/qwen3_next/, the comparison benchmark in [WS1][CUDA][Qwen3-Next] Comparison benchmarks and plots for the Qwen3-Next stack: MoE, attention, logprob, EP (RFC #428 stack 11/11) #551, raw evidence as a release ZIP.

Prior art & reuse decision

Measured on the same layer-0 weights and replicated input, EP4 under 13 NCCL settings and EP1, 4 × B200, 1024 tokens (summary, runner in #551, measured at 45719cb3):

Library Implementation Fwd EP4 == EP1 Fwd NCCL-setting invariant Fwd batch invariant Backward: batch invariant / EP4 == EP1 Max abs vs FP64 EP4 fwd / bwd latency
RL-Kernel qwen3_next_ep (this PR, both engines) yes yes (1 result) yes yes / yes 1.8e-5 2.27 / 51 ms
vLLM 0.30.0 fused_experts + expert_map + vLLM's all-reduce (default or VLLM_BATCH_INVARIANT=1) no yes (1) yes no backward 8.7e-4 0.48 / – ms
vLLM 0.30.0 same expert kernel + NCCL all_reduce no no (5) no no backward 8.7e-4 0.52 / – ms
FlashInfer 0.6.18.post1 / CUTLASS cutlass_fused_moe with ep_size/ep_rank + vLLM's all-reduce no yes (1) yes no backward 8.7e-4 0.39 / – ms
SGLang 0.5.21 FusedMoE, EP ranks combined by tensor_model_parallel_all_reduce (fused_moe_triton/layer.py:1597) no backward not measured: sgl_kernel does not load next to torch 2.13, and the only machine available for the follow-up check has 2 B200 (EP4 needs 4); same structure as vLLM
Megatron-core 0.16 (Vime's training path) MoELayer, alltoall / allgather dispatcher no no (13) no no / no 2.5e-5 - 4.2e-5 13-15 / 37-41 ms
Megatron-core 0.16 same under torch.use_deterministic_algorithms(True), alltoall yes yes (1) yes no / no 4.2e-5 15.4 / 42 ms
Megatron-core 0.16 same, allgather no yes (1) yes no / no 2.5e-5 14.3 / 40 ms
Miles (radixark/miles@23d3d38) miles/kernels/moe/fused_experts{,_bwd}.py (SGLang forward, own backward), imported unmodified; layer-0 weights at EP1, 20 launches no, measured: dx, dW gate/up, dW down equal the first in 1 / 20 launches (BF16 tl.atomic_add); dx probe rows 0 / 10 batch cells 10 / – ms (EP1)
verl (volcengine/verl@e5a627c) no MoE kernel (searched verl/); Megatron-core, HF/FSDP or VeOmni for training, vLLM/SGLang for rollout covered by those rows
FlashAttention — N/A: no MoE

Qwen3-Next EP MoE prior art

Batch invariance: 8 probe tokens alone vs inside batches of 8 / 64 / 256 / 1024 at the first, middle and last position, on the output and (backward) the input gradient.

Decision: write our own EP4 path, reusing the #503 MoE contract and RL-Kernel's fixed-order collective.

  • vLLM and FlashInfer are batch- and NCCL-setting-invariant when they use vLLM's own all-reduce, but they are inference-only: training needs the same bits with a backward, and neither has one. They also route in BF16, 8.7e-4 away from the FP32-routed candidates, and EP4 differs from their own EP1.
  • Megatron-core, VIME's training path, is the only measured stack with a backward. Under deterministic algorithms its alltoall forward passes every check, but its backward input gradient changes with the batch and differs from EP1. That is a non-performance reason not to reuse it. It would also only cover the training side; vLLM workers cannot run Megatron's dispatcher.
  • Miles' backward accumulates in BF16 with tl.atomic_add, and over 20 identical launches on the real weights dx, dW gate/up and dW down equal the first in only 1 of 20 (measured, EP1 as Miles has no EP kernel path); at EP1 it is 15× faster than our EP1 path (10 vs 158 ms forward + backward, 1024 tokens); RL-Kernel's EP4 forward + backward is about 53 ms (2.3 + 51).
  • Ours passes every forward and backward check at EP4 and equals its own EP1 bit for bit. Our EP4 forward is 4.7× slower than vLLM's at 1024 tokens (2.27 vs 0.48 ms); the backward is 1.2× Megatron's (51 vs 42 ms).

Results (4 × B200, official checkpoint, TP4 × EP4)

EP4 evidence summary and raw results (ZIP) (SHA-256 c7530d29…ba53). Measured at 1c4ae265 from clean clones in the same environment as the TP4 × EP1 chain.

Stage Checks Result
preflight operator gates, device guards, TP4 NCCL probe, checkpoint identity, rollout smoke passed
layers GDN, attention, adapters, head TP4 gates; EP4 MoE gate on layer 0; native scheduler on 16 cases passed
l2 vLLM rollout (EP4) vs VIME recompute (EP4): tokens, BF16 logits, FP32 logprobs, 48 layer, sub-node and state digests 16 / 16 raw-bit

Chain-gate report: config_fingerprint.ep 4, 16 cells, passed: true, first_drift: null.

EP4 MoE gate, every rank, bitwise:

Case Checks
hf-load-export-each-expert-once each of the 512 experts loaded and exported by exactly one rank, equal to the checkpoint
ep4-vs-ep1-chunk-reorder-train-{8,64,256,1024} identical routes on every rank; routed rows, input gradient and owned experts' weight gradients equal all 512 experts on one GPU (EP1); full == chunked; reordered tokens; training forward == no-grad
empty-rank-participation a batch in which one rank owns no route equals EP1

EP4 is not TP4 × EP1.

Status

  • Head 88c4f02e, on top of [WS1][CUDA][Qwen3-Next] TP distributed logprob parity: fixed reduction order, selected-token logprob exact across NCCL settings (RFC #428 stack 9/11) #549 (3f7cf6ec). CI is green on this head: lint, unit-tests, docs, DCO and the bot review pass; provider and ws1-gtest skip because no self-hosted runner is attached.
  • Ready for review for EP4 up to the full-model L2.
  • Not covered: training on EP4 (Megatron expert-parallel optimizer state, checkpoint export and reload, the train* stages). The training actor and export fail closed on EP4; follow-up PR.
  • Hopper (@Flink-ddd's change request of 2026-10-19): the four-GPU preflight and gpu_probe accept exactly four B200, H100 or H200 GPUs (a705d287; H200 accepted, not tested). On 4 × H100, at a705d287 (not rerun at the head 88c4f02e), the Qwen3-Next test_*.py and check_*.py suites (814 passed) and the six gates passed. The full-model EP4 chain has not been run on H100 with this PR's code yet. See "Results (4 × H100; no full-model run)" at the end of this description.
  • Rerun at the aligned stack top (clean clone of 90c09164, 4 × B200): preflight, layers (with moe_ep) and l2 passed, 16/16 raw-bit, and the 32 L2 artifacts are bitwise identical to the 1c4ae265 run; the standalone EP4 MoE gate passed on all four ranks. The full batch-invariance suite then ran at EP4: 97 / 97 cells bitwise (same cell definitions as at EP1), raw results ZIP, SHA-256 b3012ab6…fe4d. EP4 training stays fail-closed, so no EP4 training stage is claimed. At 17ba4a4c the EP4 preflight passed again with the new device guards (27 tests, 0 skipped, 0 failed).
  • The EP4 gate checks EP4 against EP1 bit for bit and its exchange uses no NCCL arithmetic; the prior-art run above additionally measured it under the 13 NCCL settings of [WS1][CUDA][Qwen3-Next] TP distributed logprob parity: fixed reduction order, selected-token logprob exact across NCCL settings (RFC #428 stack 9/11) #549 (one result).

History

Tests

python -m pytest -q tests/models/qwen3_next/test_qwen3_next_ep.py tests/models/qwen3_next/test_qwen3_next_chain_report.py
TRITON_F32_DEFAULT=ieee torchrun --nproc-per-node 4 tools/validation/models/qwen3_next/qwen3_next_ep_moe_check.py \
    --checkpoint <ckpt> --output <dir>
python tools/validation/models/qwen3_next/qwen3_next_run.py --stage all --until l2 --ep 4 \
    --runs-root <runs> --checkpoint <ckpt> --cuda-home <cuda-13.0> --python <venv>/bin/python
Check Result
Qwen3-Next CPU list in ci.yml (includes the new test_qwen3_next_ep.py) + digest tests 463 passed (99 CUDA-only skips)
evidence redaction test 80 passed
vLLM model contract + real four-rank model check, EP1 and EP4, 4 × B200 21 passed
preflight device guards at EP4 (multi-GPU + contract + real model) 27 tests, 0 skipped, 0 failed
pre-commit on all files, mkdocs build --strict clean

Scope

CUDA, TP4 × EP4 × ETP1 × CP1, one node of four B200, rollout and replay up to L2. EP training, other EP sizes, ROCm and multi-node are out of scope.

Results (4 × H100; no full-model run)

4 × NVIDIA H100 (driver 580.173.02 in the gates run), torch 2.13.0+cu130, vLLM 0.30.0, NCCL 2.29.7. The comparison run does not record the Megatron-core version.

Tests and gates, at a705d287 on this PR's branch (not rerun at the head 88c4f02e). gates/info.txt and the EP4 MoE, TP4 attention, TP4 GDN and TP4 MoE gate files record 2a8f18e4, the id of this commit before the branch was rewritten. Both ids have the tree 4102963e2673c15b8a5e807f7ea4223173630370; git rev-parse a705d287^{tree} gives it. The GDN engine adapter and TP4 embedding / LM head gate files record no commit. gates/pytest.log is a quiet-mode log (progress marks and the final line) and does not record the command line.

Check Result Raw data
tests/models/qwen3_next/test_*.py and check_*.py 814 passed, 0 failed gates/pytest.log, gates/info.txt
GDN engine adapter, EP4 MoE, TP4 attention, TP4 GDN, TP4 embedding / LM head and TP4 MoE gates all six passed on all four ranks adapter, ep_moe, tp_attention, tp_gdn, tp_head, tp_moe (each gate also has rank-1.json to rank-3.json and a .log in the same folder)

The EP4 MoE gate (script at a705d287; its rank files record the pass status and output hashes, not the individual comparisons) checks bit for bit, at 8, 64, 256 and 1024 tokens, that the EP4 routed-expert rows (before combine_routes), their input gradient dx and each rank's own experts' dW equal the same experts evaluated on one GPU (EP1) on the same routes. For the EP4 block alone it checks that the full batch equals the concatenated chunks, that reordered tokens give the reordered output, that the first row alone matches, and that the training forward equals the no-grad forward. It does not compare the combined block output with EP1, and it does not differentiate through combine_routes or the router.

Not run on H100 yet: the full-model EP4 chain (preflight, layers, l2: vLLM rollout against VIME recompute) with this PR's code.

Comparison with existing implementations (same runner and columns as "Prior art & reuse decision" above). Layer-0 MoE with the checkpoint's layer-0 weights on one fixed random 1024-token input: EP4 on four GPUs under each of the 13 NCCL settings of #549, and EP1 on one GPU. Measured at 58aa50c7, which is on the #551 branch (that branch contains this PR's head 88c4f02e), with #551's EP benchmark runner (moe_ep_candidates.py, qwen3_next_moe_ep_prior_art.py). The report records 77d59a59, the id of this commit before the branch was rewritten. Both ids have the tree 67a6c5c8a30c1351b05beb9b9f509976f8dff45c; git rev-parse 58aa50c7^{tree} gives it. The EP4 == EP1 and backward dx / dW equalities of RL-Kernel appear as flags in ep_matrix/report.json under candidates.rl_kernel_ep (ep4_equals_ep1, backward.dx_ep4_equals_ep1, backward.dw_ep4_equals_ep1).

Qwen3-Next EP MoE prior art on H100

In the "Fwd NCCL-setting invariant" column, the number in parentheses is the count of distinct EP4 outputs across the 13 NCCL settings.

Implementation Fwd EP4 == EP1 Fwd NCCL-setting invariant Fwd batch invariant Backward: batch invariant / EP4 == EP1 Max abs vs FP64 EP4 fwd / fwd + bwd latency
RL-Kernel qwen3_next_ep yes yes (1) yes yes¹ / yes 1.8e-5 2.77 / 94 ms
vLLM fused_experts + vLLM all-reduce no yes (1) no no backward 8.7e-4 0.88 / – ms
vLLM fused_experts + vLLM all-reduce, VLLM_BATCH_INVARIANT=1 (identical outputs) no yes (1) no no backward 8.7e-4 0.99 / – ms
vLLM fused_experts + NCCL all_reduce no no (8) no no backward 8.7e-4 0.90 / – ms
FlashInfer CUTLASS not measured² – – – – –
Megatron-core MoELayer, alltoall no no (13) no no / no 3.3e-5 32 / 87 ms
Megatron-core MoELayer, allgather no no (13) no no / no 2.5e-5 30 / 81 ms
Megatron-core MoELayer, alltoall, torch.use_deterministic_algorithms(True) yes yes (1) yes no / no 4.2e-5 33.8 / 91 ms
Megatron-core MoELayer, allgather, torch.use_deterministic_algorithms(True) no yes (1) yes no / no 2.5e-5 31.9 / 86 ms

¹ Measured on one fixed random input with the stock combine_routes, which is unchanged from 58aa50c7 to the head. Its autograd backward reduces the route-weight gradient over the hidden dimension with torch.sum. In #503's H100 diagnostics (results.txt), on synthetic inputs, that reduction was not batch invariant from batch 16 upward and made dx differ. This cell therefore holds for the measured input only.
² The JIT build of FlashInfer 0.6.18.post1's fused_moe_90 module failed at link time on the H100 machine (/usr/bin/ld: cannot find -lnvrtc, Ninja build failed; see candidates.flashinfer_cutlass_ep.unavailable in ep_matrix/report.json). #503's H100 run linked it through a libnvrtc.so symlink, which this run did not have. The candidate is therefore recorded as unavailable, and this table has no FlashInfer numbers.

Batch invariance: the probe of 8 tokens is compared alone and inside batches of 8, 64, 256 and 1024 tokens, at the first, middle and last position (cell 1024@508 is the 1024-token batch with the probe at position 508), on the output and, for the backward, on the input gradient. With vLLM's all-reduce (default and VLLM_BATCH_INVARIANT=1), vLLM differs only in the 1024-token batch (cells 1024@0, 1024@508 and 1024@1016); with NCCL all_reduce it differs in every cell except 8@0.

Latency: the benchmark runner takes one warm-up call, then the median of 20 timed forward calls at 1024 tokens and, for the second number, the median of 5 timed forward + backward calls. The EP4 value in the table is the largest of the four ranks' values (latency_us_ep4 in the report), in the run with default NCCL settings. The published run files hold rank 0 only. Report: ep_matrix/report.json; run files: ep_matrix/runs/.

…rouped expert GEMM

RFC RL-Align#428 moe_route_combine_contract (CUDA).

- Routing: FP32 router through the pinned vLLM batch-invariant GEMM, a
  fixed-order softmax, stable descending argsort (ties go to the lower
  expert id) and FP32 renormalisation of the ten selected weights.
- Experts: per-route gate_up and down projections through vLLM 0.30.0's
  fused_moe Triton kernel with the batch-invariant tile passed explicitly
  (BLOCK 64/64/32, SPLIT_K=1); no routed-weight multiply and no sum inside
  the kernel, so every (token, route) row has one writer. Bitwise equal to
  the previous per-expert GEMM loop at TP4 and TP1 widths; fails closed if
  VLLM_TRITON_USE_TD is enabled.
- Combine: ten ordered FP32 multiply-adds and one BF16 cast; no atomics.
- Backward: per-expert pinned GEMMs into one dense gradient buffer; dx is
  summed in ascending expert order.
- TP4 block: HF load/export for all 512 experts, replicated router and
  shared-expert gate, Megatron-style copy/reduce autograd boundaries moved
  into qwen3_next_tp.py.
- Prior-art runner and plot comparing HF transformers, vLLM fused_moe
  (BI=0/1) and FlashInfer cutlass_fused_moe; TP4 real-weight gate script.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Prep for RFC RL-Align#428 full_model_chain; serves the gdn_state_bridge row.

- GDN: packed recurrent prefill/decode through the pinned vLLM 0.30.0
  provider with an explicit state boundary (qwen3_next_gdn.py), the
  depthwise causal convolution with cache handoff (qwen3_next_conv.py),
  their combined shared core (qwen3_next_provider.py) and the TP4 block
  with HF GQA-interleaved weight mapping (qwen3_next_tp_gdn.py), now on the
  shared TP boundaries in qwen3_next_tp.py.
- Attention: the deterministic CUDA attention kernel accepts head dim 256
  (ROCm stays 128) and validates backward inputs; shared_attention and
  TP4FullAttention with the KV head replicated on each rank pair, partial
  RoPE at absolute positions and explicit per-slot KV state.
- Real-weight TP4 gates for GDN (layer 0) and attention (layer 3), sharing
  scripts/qwen3_next_gate_common.py with the MoE gate.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…nce (B200, 2e950f3)

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Compares RL-Kernel's deterministic attention with torch SDPA, vLLM FlashAttention-2 (num_splits auto and 1), vLLM's Triton unified attention and FlashInfer's ragged prefill: batch, chunked-prefill and decode invariance, backward repeatability, accuracy against FP64 and latency.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…nce (B200, 9e6c4f2/6517077)

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
RFC RL-Align#428 full_model_chain (CUDA).

- Engine adapters: the native vLLM rollout (exact-prefill scheduler, paged
  KV, traced response rows), the VIME/Megatron replay and training actor,
  engine weight import/export and the logprob adapter, all on the shared
  TP4 providers.
- Stage runners (preflight, layers, l2, train1, train2, train) with the
  validated acceptance contract (version 4) and scripts/qwen3_next_run.py,
  a launcher that works inside any four-GPU allocation: each stage gets a
  clean clone, an immutable run.json identified by a fresh execution_id,
  and refuses a predecessor that did not pass or pins another identity.
  Scheduler-independent helpers live in scripts/qwen3_next_runtime.py.
- Sub-node digests: both engines observe the normed mixer input, the mixer
  output, the normed MLP input, the selected expert ids and the MoE output
  of every layer, plus the embedding; the first divergence names the layer
  and sub-node.
- scripts/qwen3_next_chain_report.py writes a ChainGateReport-compatible
  report (schema qwen3-next-chain-v1, compatible with ws1-c10-c11-v5) with
  first_drift_family/layer/cell; scripts/qwen3_next_publish_evidence.py
  publishes a chain's records without site paths, hosts or users.
- Native rollout caps raised to 64 sequences, 16384 batched tokens and a
  4 GiB KV budget so the batch-invariance matrix runs under the same
  certified profile; the exact-prefill scheduler still fixes every chunk.
- The operator-case registry is regenerated from collection by
  scripts/qwen3_next_operator_cases.py.
- Packaging: transformers may be 5.13.1-5.17.0; a qwen3-next extra pins the
  audited runtime.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
RFC RL-Align#428 batch_invariance_ci (CUDA).

- Stage bi (after a passed l2, same certified profile): 97 pinned cells in
  rl_engine/testing/qwen3_next_bi_cases.py / qwen3_next_bi_manifest.json.
  concurrency (1-64 requests, target first or last), interference
  (companion content, lengths, arrival during prefill/decode, generation
  lengths), chunk boundaries (prompts 63-1024 around 64/128/528/1024, chunk
  64/128, first chunk 1/63/65, compared with the replay recompute) and
  replay THD packing (1-7 neighbours, target first or last). A quick CI
  subset runs one cell per family plus 64 concurrent requests.
- Native rollout: version 2 requests run one traced target next to
  untraced companions; the exact-prefill scheduler admits each request at
  its arrival step, pins the target's planned chunk at every step and
  fails on any preemption; the trace records only the target.
- Replay: packed_layout() packs variable-length neighbours with the traced
  target in one THD batch.
- bi-matrix.json names each failing cell's first divergent layer, sub-node
  and layer family; the chain report gains a batch_invariance section, and
  the evidence publisher takes the bi run with --also.
- gtest: bitwise judgments compare raw bits (signed zero, NaN/Inf and
  dtype now count), not allclose with zero tolerance.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…lout profile

Batch-invariance chunk cells use prompts such as 129 tokens; the state-shape check only admitted the four L2 lengths, which their own validators already pin.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Editable sources, base interpreters and build directories in package metadata now keep only their last path component; cgroup paths keep only their file name. The leftover check matches absolute paths only, so package paths such as vllm/.../cpu/data/ are not flagged, and any mention of the batch scheduler blocks publication.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…r-art runner

- Megatron-core 0.16 MoELayer with Transformer Engine grouped GEMM and fused
  permute, configured as VIME runs Qwen3-Next (FP32 softmax router, top-10,
  all-to-all dispatcher), including its backward.
- SGLang 0.5.21 Triton fused_moe in default and deterministic-inference mode.
  sgl_kernel cannot load next to torch 2.13, so its two kernels on this path
  are replaced by SGLang's own Triton moe_sum_reduce and JIT
  moe_align_block_size; any other sgl_kernel call fails loudly.
- --only and --merge combine reports from different Python environments.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…ured (B200, c58816b)

Every library in the reuse table is now measured: Megatron-core 0.16 + TE 2.16 as VIME configures Qwen3-Next, and SGLang 0.5.21 in default and deterministic-inference mode. The TP4 gate evidence is unchanged (2e950f3, identical MoE code).

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…gatron-core attention

Add three engines to the attention prior-art runner:
- FlashAttention-4 (CuTe DSL) varlen as vendored by vLLM, forward and backward.
- Transformer Engine DotProductAttention on THD-packed sequences, in
  inference mode (cuDNN fused) and in training mode (on SM100 TE has no
  fused head-dim-256 backward and falls back to its unfused path).
- Megatron-core's local DotProductAttention, one launch per sequence.

The backward check now compares the target's dq/dk/dv alone against the
same sequence packed first and last, so engines with a packed backward are
checked for batch invariance rather than repeatability. A prefill/decode
crash is recorded per candidate without skipping its other checks.
--only and --merge combine reports from different Python environments.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
The decode and forward+backward latency sections are keyed by candidate
directly, the prefill section by size first; merge them at any depth.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…p as E402-exempt

The gate scripts insert the repo root into sys.path before importing
rl_engine and tools, which flake8 reports as E402. Mark those imports
with noqa, as the other tools/ scripts do.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…p as E402-exempt

The gate scripts insert the repo root into sys.path before importing
rl_engine and tools, which flake8 reports as E402. Mark those imports
with noqa, as the other tools/ scripts do.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Annotate the latency samples and accept the default-argument lambdas used as
timed calls. No behaviour change.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
… runner

Annotate the latency samples and accept the default-argument lambdas used as
timed calls. No behaviour change.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Merge the migrated TP4 mixers (and through them the refactored
test-qwennext) and move the full-model chain into the new layout:

- model-level TP4 pieces (embedding, engine weights, logprob, sub-node
  observations) into rl_engine/models/qwen3_next/;
- vLLM adapters and the native rollout into
  rl_engine/integrations/engines/rollout/vllm/;
- VIME providers into rl_engine/integrations/orchestrators/vime/providers/
  and the native VIME lifecycle (recompute, training, workers, profile)
  into rl_engine/integrations/orchestrators/vime/experiments/qwen3_next/;
- the provider identity into rl_engine/integrations/common/;
- chain report, L2/case fixtures and manifests into
  rl_engine/validation/models/;
- stage runners and the launcher into tools/validation/models/, CI scripts
  into ci/scripts/, tests into tests/models/qwen3_next/.

Imports point at canonical modules; the provider-source digest list names
the canonical RMSNorm backend instead of its compatibility alias. Recorded
contract identities (e.g. sample_counter_owner) are unchanged.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…nce matrix

Merge the migrated full-model chain and move the batch-invariance work into
the new layout: the case generator and manifest into
rl_engine/validation/models/, the stage runner into tools/validation/models/,
its tests into tests/models/qwen3_next/. The raw-bit comparison for bitwise
judgments now lives in the canonical
rl_engine/validation/operators/forward_invariance.py (the old module is a
compatibility alias). The evidence README gives the commands in the current
layout and says where the runners were at the measured commit; no measured
file changed (SHA256SUMS verified).

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…ouched

The published chain evidence is a byte-exact copy covered by SHA256SUMS; a
pytest JUnit XML without a final newline would otherwise be rewritten by
end-of-file-fixer and break the checksum. Same treatment as reports/archive/.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…ouched

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
@fusheng-ji

Copy link
Copy Markdown
Contributor Author

OpenCodeReview · .github/workflows/qwen3-next-provider-gpu.yml (L130-L130): The stale-extension guard only asserts the loaded _C lives under GITHUB_WORKSPACE.

Same point as 543-S5; not changed. rl_engine is a regular package, so a _C loaded from the checkout means every rl_engine submodule was loaded from it, and actions/checkout fetches exactly the given SHA.

@fusheng-ji

Copy link
Copy Markdown
Contributor Author

OpenCodeReview · rl_engine/backends/cuda/norm/rmsnorm.py (L330-L330): Arity mismatch: forward(ctx, x, weight, gate, eps=1e-6, weight_offset=0.0, activation=0) has 5 differentiable inputs (x, weight, gate, eps, weight_offset, activation → 5 non-ctx args that map to grads = x, weight, gate, eps, weight_offset, activation is 6).

Not changed: forward(ctx, x, weight, gate, eps, weight_offset, activation) has six inputs and backward returns six values, dx, dw, dgate, None, None, None.

fusheng-ji added a commit to fusheng-ji/RL-Kernel that referenced this pull request Oct 27, 2026
The chain preflight, layers and l2 records were produced with local changes
that are not part of the pull request and cannot be checked from any public
commit. The RL-Align#557 description no longer reports them. The gates and ep_matrix
records, which the description links, are unchanged.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
fusheng-ji added a commit to fusheng-ji/RL-Kernel that referenced this pull request Oct 29, 2026
…-Align#543/RL-Align#544, with the two candidate RL-Align#543 patches

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Flink-ddd and others added 10 commits November 8, 2026 23:38
a203719 parametrised test_cuda_gated_parameter_vjp_contributions_match_the_fold
over shape and added four norm tests, but the registry still pinned the old
ids, so the preflight operator gate reported them as not found. Regenerated
with qwen3_next_operator_cases.py --write.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…ecompute

create_actor(training=False) built the full actor through
setup_model_and_optimizer, which wraps the model in DDP and allocates
optimizer state. The recompute/logprob path never steps, and on 80 GB GPUs
that state does not fit. With training=False the model is now built through
get_model(wrap_with_ddp=False) and loaded without an optimizer, and
(args, model, None, None) is returned. The training=True path is unchanged.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
VIME's load_checkpoint requires skip_load_to_model_and_opt; both
create_actor calls omitted it, so the full-model l2 recompute failed with a
TypeError before any model work. The stub in the actor test now requires it.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
fusheng-ji added a commit to fusheng-ji/RL-Kernel that referenced this pull request Nov 13, 2026
fusheng-ji added a commit to fusheng-ji/RL-Kernel that referenced this pull request Nov 13, 2026
fusheng-ji added a commit to fusheng-ji/RL-Kernel that referenced this pull request Nov 13, 2026
…RL-Align#495 and RL-Align#491 at their current heads

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…t.toml, gate the remaining new tests

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…k, not assert

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
fusheng-ji added a commit to fusheng-ji/RL-Kernel that referenced this pull request Nov 13, 2026
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
…issing TP group

run_qwen3_next_chain_gate.sh read the report with a bare open() and
indexed JSON-only keys, so a truncated file, a non-object report or one
without first_drift_family raised a traceback and exited 1, the code
reserved for a failed gate. Read it in a with-block, require an object
and the payload-only first_drift_family, and send every such failure
through invalid() (exit 2).

The TP reduce dereferenced collective_for_group(...), which returns None
for a missing group; raise a clear RuntimeError as the EP exchange does.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>
@fusheng-ji

Copy link
Copy Markdown
Contributor Author

Replies to the three OpenCodeReview summary items:

  1. run_qwen3_next_chain_gate.sh L26: fixed in 4e2c33af (merge f935bf3a); see the [WS1][CUDA][Qwen3-Next] Full-model chain: vLLM rollout vs VIME recompute, raw-bit through two updates and a reload (RFC #428 stack 7/11) #543 reply.
  2. qwen3_next_tp.py L18-L19, collective_for_group can return None: fixed in 4e2c33af. The function returns None only for group is None; _reduce now raises RuntimeError: Qwen3-Next TP reduction needs a process group, as the EP exchange does (qwen3_next_ep.py:99-100), instead of an AttributeError.
  3. qwen3_next_tp_blocks.py L107, zero-initialised RMSNorm gain: not changed. These norms are zero-centred: the module applies Qwen3NextRMSNormCudaOp, y = x * rstd * (1 + weight) (rmsnorm.py:178-186, weight_offset = 1.0; used at qwen3_next_tp_blocks.py:240), and the Qwen3-Next checkpoint stores q_norm.weight and k_norm.weight in that form. Zero is the identity here. The GDN block's norm is the gated RMSNorm, which multiplies by the plain weight, so it starts at ones.

fusheng-ji added a commit to fusheng-ji/RL-Kernel that referenced this pull request Nov 14, 2026
Provider job, chain preflight (failed at rollout-smoke), logprob prior art over
13 NCCL settings, EP matrix at 2c699e3, RL-Align#557 gates at f935bf3, RL-Align#549 parity
at 30c0e5a, RL-Align#543/RL-Align#544 preflight at their own heads. Redacted.

Signed-off-by: Wenbo Ji <36562829+fusheng-ji@users.noreply.github.com>

@Flink-ddd Flink-ddd 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.

The layout follows #497, but Hopper validation is still incomplete. Please fix the known batch-dependent combine_routes backward reduction, cover the router and combine path in the EP4 gradient tests, and run full EP4 rollout and replay parity on four H100 and H200 GPUs using the submitted code before merging.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new-model platform: cuda Specific optimizations or bugs in NVIDIA graphics cards (such as FlashInfer, TMA optimizations) qwen WS1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants