Repository navigation
[WS1][CUDA][Qwen3-Next] TP distributed logprob parity: fixed reduction order, selected-token logprob exact across NCCL settings (RFC #428 stack 9/11) - #549
Conversation
…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>
Not changed. |
Same point as 544-S1, 549-S7, 557-S3; not changed. Under |
Same point as 468-S4, 503-S9, 543-S5, 549-S1; not changed. |
Not changed: the ungated hook is also keyword-only and takes no mask, and the only caller, the C4 harness, passes keywords. |
Not changed. The plain and gated bindings ship in the same |
Same point as 503-S7, 549-S2, 557-I4383087967; not changed. |
Same point as 469-S4, 507-S1, 544-S4; not changed. Both hooks return per-row contributions on purpose: the C4 harness keys them per logical token, checks the row count and folds them itself in fixed fp32 order. It always passes 2-D |
Same point as 507-S3, 507-S2; not changed. The hook and the backward share |
Same point as 549-S3, 543-S3; not changed. pip merges the base and extra specifiers, so |
Same point as 543-S4; not changed. |
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>
…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>
…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>
|
One OpenCodeReview summary item:
|
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>
| tests/models/qwen3_next/test_qwen3_next_failure.py \ | ||
| tests/models/qwen3_next/test_qwen3_next_imported_binary.py \ | ||
| tests/models/qwen3_next/test_qwen3_next_installed_provider_identity.py \ | ||
| tests/models/qwen3_next/test_qwen3_next_l2.py \ |
There was a problem hiding this comment.
This 28-module qwen3_next block was appended to the "Run Mocked Hardware Discovery Tests" step, which does not build the rl_engine._C extension and is CPU-only. Several of the newly listed modules (e.g. test_qwen3_next_imported_binary.py, test_qwen3_next_installed_provider_identity.py, test_qwen3_next_storage.py, test_qwen3_next_training_checkpoint.py, test_qwen3_next_l2.py) exercise compiled-extension, vLLM-import or on-disk binary/provider evidence paths. Any module that imports those at module scope without pytest.importorskip/skip markers will fail collection here, turning the required CI job red instead of skipping. Please confirm each newly added module is import-safe on a runner without the extension/vLLM (or split these into their own step with the appropriate skip guard).
Flink-ddd
left a comment
There was a problem hiding this comment.
LGTM, Thank for you push it. also cc @inaniloquentee
What
docs/operators/qwen3-next-distributed-logprob.md): every TP4 point where ranks combine values -- embedding, row-parallel GDN/attention/MoE outputs, column-parallel input gradients, the vocabulary-parallel selected logprob / LSE / entropy, sampling logits -- with its operation, order, dtype and transport (NCCL all-gather for bytes only; RL-Kernel's fixed-order collectivecuda_ipc_fixed_treefor sums).tools/validation/models/qwen3_next/qwen3_next_logprob_parity.py, 4 GPUs, real weights): SHA-256 of every point's output and gradient per rank, a TP1 reference, and a raw-NCCL negative control;qwen3_next_logprob_parity_compare.pychecks one digest per rank across NCCL settings.tests/models/qwen3_next/test_qwen3_next_tp_reductions.py): no rawtorch.distributedreduction in Qwen3-Next model, engine or VIME modules; the TP reduction must use the fixed-order collective.rl_engine/validation/models/qwen3_next/, scripts undertools/validation/models/qwen3_next/, comparison benchmarks and plots in the benchmark PR ([WS1][CUDA][Qwen3-Next] Comparison benchmarks and plots for the Qwen3-Next stack: MoE, attention, logprob, EP (RFC #428 stack 11/11) #551), raw JSON as release ZIPs with summaries inreports/experiments/qwen3_next/. The earlier PRs of the stack now follow the same layout themselves.Prior art & reuse decision
Same official-LM-head logits for every measured candidate (TP4 shards are slices of one full-vocabulary product), 1024 tokens:
shared_logprob(both engines here)log_softmaxlog_softmax(srt/layers/logits_processor.py)vocab_parallel_cross_entropycalculate_log_probs_and_entropyradixark/miles@23d3d38)fused_log_probs_and_entropy, imported unmodifiedvolcengine/verl@e5a627c)linear_cross_entropy, imported unmodified (fuses the LM-head GEMM; own logits, FP64 reference of its own product)atomic_addruns only forreductionsum/mean); backwardd_hidden/d_weightusetl.atomic_addbut are repeat-stable (20/20), not batch invariant (probe rows 1/10 cells)The measured implementations differ from each other by up to 9.5e-7 (Megatron and VIME agree with each other). vLLM's path is exact for rollout, but the training side has no counterpart that reproduces it; Megatron/VIME, Miles and verl (all measured) reduce max and sum-exp with NCCL all-reduce, so they move with NCCL settings. Decision: both engines keep RL-Kernel's WS2 provider -- the only measured way to equal bits on both sides. Its cost is latency (4.5× Megatron at this shape); a faster tile-stats kernel can keep the same merge order and is follow-up work.
Results (4 × B200, official checkpoint)
Top: digest of every TP4 point under each NCCL setting vs NCCL defaults; the last row is the raw-NCCL negative control. Bottom: prior-art invariance, largest pairwise difference, latency.
o_projpartials, NCCLall_reduceNCCL 2.29 has no Tree all-gather, so the Tree settings restrict all-reduce only (
NCCL_ALGO=allreduce:tree). Summary, tested commits and commands:reports/experiments/qwen3_next/qwen3-next-distributed-logprob-b200.md; raw reports ZIP (SHA-256a48bf29d…2cd9), parity measured at04db726, prior art at33495ad. Post-review GPU rerun atb10b6616(ZIP): all 233 mandatory operator cases and four norm gates passed; all 17 points invariant across the 13 settings; selected logprob / LSE equal TP1; the negative control again gave five digests per rank.Status
3f7cf6ec, on top of [WS1][CUDA][Qwen3-Next] Batch-invariance matrix for the full model, 97/97 cells bitwise (RFC #428 stack 8/11) #544 (db1eb37f). CI is green on this head: lint, unit-tests, docs, DCO and the bot review pass;providerandws1-gtestskip because no self-hosted runner is attached.3927fad7); stdlib-only launcher runtime.90c09164): the EP1 chain passed throughl2,train1,train2andtrain(L2 artifacts bitwise identical to thec67ec14run) and the full BI suite passed 97 / 97 cells (see [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 and [WS1][CUDA][Qwen3-Next] Batch-invariance matrix for the full model, 97/97 cells bitwise (RFC #428 stack 8/11) #544).History
pull_requestpaths were missing Qwen3-Next modules that its checks import; merged the additions of [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 and [WS1][CUDA][Qwen3-Next] Batch-invariance matrix for the full model, 97/97 cells bitwise (RFC #428 stack 8/11) #544 (3f7cf6ec). Workflow-only change; shared infrastructure such asrl_engine/opsandrl_engine/platformsstays out of the filter.5ffd4c31runstest_file_digest.pyonce in the CPU job. The fixes of the PRs below it are merged in; new head5ffd4c31. Kernel arithmetic is unchanged, so the measured results stand.test-qwennextafter [WS1][CUDA][Qwen3-Next] C1: zero-centred RMSNorm references and CUDA kernel (RFC #428 stack 2/4) #467 landed (c382dd4b), through [WS1][CUDA][Qwen3-Next] Batch-invariance matrix for the full model, 97/97 cells bitwise (RFC #428 stack 8/11) #544's new headeb04b15f, infe6ed386. This PR moves the norm workload, manifest and evidence scripts underqwen3_next/, so [WS1][CUDA][Qwen3-Next] Gated RMSNorm CUDA kernel for the GDN block (RFC #428 stack 3/4) #468's later changes to them were taken at those paths, and [WS1][CUDA][Qwen3-Next] Gated RMSNorm CUDA kernel for the GDN block (RFC #428 stack 3/4) #468's reuse check (new here) reads the moved manifest.Tests
ci.yml+ digest testsall_reduce/reduce_scatter_tensoris reported0b88a839)Scope
CUDA, TP4 × EP1 × CP1, one node of four B200. Expert parallelism is #557; ROCm is a separate claim.
Results (H100 / Hopper, 4 GPUs, official checkpoint)
Run at this PR's head
8e88cd82. 4 × NVIDIA H100 80GB, torch 2.13.0+cu130, vLLM 0.30.0, NCCL 2.29.7, checkpoint revision9c7f2fbe. Raw data:hopper-qwen3-next/pr549.tests/models/qwen3_next/test_*.py+check_*.py(4 GPUs)deterministic_points_invariant: true).tp4_equals_tp1: true); entropy differs between TP4 and TP1 as documented (entropy_tp4_equals_tp1: false).all_reduceof theo_projpartials gives 8 distinct results over the 13 settings, the fixed-order collective gives 1.Logprob prior-art on H100 (1024 tokens, TP4 vs TP1, 10 repeats; runner at
77d59a59):rl_kernel_ws2vllm_gathermegatron_cevime_defaultmiles_fused,verl_fusedReport:
pr549_logprob/report.json(alsoparity/report.jsonfor the gate parity).