Repository navigation
[OPD] Add the Qwen3.6-35B-A3B multi-teacher OPD launcher (reasoning_gym, B200/GB300) - #4493
Draft
maocheng23 wants to merge 3 commits into
Draft
maocheng23 wants to merge 3 commits into
maocheng23 wants to merge 3 commits into
Conversation
…oning_gym scripts/run_qwen3_6_35b_a3b_mopd.py distills Qwen3.6-35B-A3B from two reasoning_gym GRPO teachers (caesar_cipher, simple_geometry) with sampled-token reverse-KL OPD, 20 updates x 128 x 1 at 30,720-token responses, on two B200 or GB300 nodes: synchronous (colocated) or one-step overlap (train_async.py). Token-mean loss is on by default, MTP speculative decoding is an option, and the fused log-prob backend avoids a 28 GiB logits copy. examples/on_policy_distillation/mopd_reasoning_gym/ holds the data prep, the rollout hooks (Miles' OPD reward plus timing stamps and the held-out verifier), the teacher server, and optional analysis/report tooling. The example README is mirrored into the docs site. Compared with the recipe validated on 8xGB300, the launcher drops the custom Megatron init hook (FA4 causal window, FusedAdam chunking) and the reward hook's teacher-reply extraction, which the stacked fixes now cover, and adds --skip-actor-forward-only to the sync layouts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 28, 2026
Draft
The reasoning_gym MOPD example now presents its two setups as first-class recipes, each with its GPU split on B200 and GB300, the exact teacher, Ray and launch commands, and the results expected from the 8xGB300 validation. The synchronous setup without --mtp-spec-decode is the matched baseline; the one-step-overlap setup with --mtp-spec-decode is the recommended one. The async section spells out the cross-node Ray cluster (trainer node at the lower IP, rollout GPUs only on the worker) and NCCL_IB_GID_INDEX=3 for RoCE clusters across subnets. The launcher docstring follows the same split. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The async layouts' trainer-node check imported ray into the launcher, which tests/fast/utils/workers/test_ray_communication_boundary.py rejects: launchers reach Ray through command_utils, as the Nemotron launcher does with `ray status`. The check now runs a one-line ray.nodes() listing through the backend's exec_command_cpu and sorts the result with Miles' own placement sort_key, so the launcher process stays free of ray. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Adds an official launcher for multi-teacher on-policy distillation of Qwen3.6-35B-A3B on two reasoning_gym tasks, ported from a standalone recipe validated on 8×GB300. The stack below it lets the launcher drop that recipe's workarounds.
What it trains
Qwen/Qwen3.6-35B-A3B. Two frozen GRPO teachers:semianalysisai/Qwen3.6-35B-A3B-caesar-cipher-GRPO-20260924@dfedf677andsemianalysisai/Qwen3.6-35B-A3B-simple-geometry-GRPO-20260925@679d4b66.--opd-teacher-urls,--opd-teacher-key task).<answer>after</think>.Changes
scripts/run_qwen3_6_35b_a3b_mopd.py:ScriptArgsonExecuteTrainConfig, withprepareandexecuteentrypoints and--layoutfrom a frozen table. It ships two first-class setups:train.py --colocate), the matched baseline when run without--mtp-spec-decode:b200-sync(the default): 8 B200 shared by the trainer (EP8) and 8 TP1 engines; each teacher DP4 on node B.gb300-sync: the same on 2 × 4 GB300.train_async.pywithout--fully-async, nothing dropped), the recommended setup with--mtp-spec-decode:b200-async: trainer EP8 on node A; 6 engines and 1 GPU per teacher on node B.gb300-async: the same on 2 × 4 GB300.preparedownloads the student and both teachers (pinned revisions), builds the prompts, and converts the student.MILES_SCRIPT_EXTERNAL_RAY=1. Before submitting,executechecks that the trainer node sorts first. It lists the cluster's GPU nodes with a one-lineray.nodes()call through the backend (launchers reach Ray only throughcommand_utils) and sorts them with Miles' own placementsort_key.--calculate-per-token-loss),--log-probs-backend fused, no CPU offload.--mtp-spec-decodeturns on EAGLE with Qwen3.6's MTP head. The eval config is passed inline (encode_pseudo_file).examples/on_policy_distillation/mopd_reasoning_gym/:prepare_data.py: builds the train pool and held-out sets.hooks.py: callsmiles.rollout.on_policy_distillation.reward_funcand adds timing stamps. The reward is the reasoning_gym verifier score, logged asrollout/raw_reward.post_process_rewardsdelegates to the stock hook, so the objective stays pure OPD.serve_teachers.py: SGLang DP teachers, each on a fixed per-task port, with staggered starts.analyze.py,make_report.py: optional tooling that turns a--dump-dirrun into tables, plots and an HTML page. They need matplotlib.README.md: one section per setup, each with the GPU split on B200 and GB300, the exact teacher, Ray and launch commands (trainer node at the lower IP;NCCL_IB_GID_INDEX=3on RoCE clusters across subnets), and the expected results. It is mirrored todocs/examples/on-policy-distillation/mopd-reasoning-gym.mdbyscripts/tools/sync_example_docs.py, with the nav entries regenerated.docs/models/qwen/qwen3-6-moe.md: points to the launcher.tests/fast/launch_scripts/test_run_qwen3_6_35b_a3b_mopd.py: sync vs async flags, the external-Ray requirement, teacher routing, MTP, and the node-order check (numeric IP order, rejection).tests/fast/examples/on_policy_distillation/test_mopd_reasoning_gym_hooks.py: the verifier, routed teacher scoring under [OPD] Keep a scalar reward: store teacher log-probs when scoring returns (supersedes #3266) #4466's scalar-reward contract, the eval path, and post-processing.prepareandexecute.What the stack removes from the validated recipe
I recorded the validated standalone recipe's launcher and this launcher under the snapshot harness and compared the
train.pyargv as a flag → values multiset, plus the Ray runtime env, for all four layouts with and without MTP. These are every difference:--custom-megatron-init-path mopd_rg.init_trainerremovedinitialize.init(). Qwen3.6's full-attention layers go through TEDotProductAttention(get_gpt_decoder_block_spec(use_transformer_engine=True)), and TE looks the FA4 functions up as module globals at call time, so #4465 covers this model. Its FusedAdam chunking is replaced by #4467.--custom-rm-path/--custom-reward-post-process-path/--custom-generate-function-pathnow point atexamples.on_policy_distillation.mopd_reasoning_gym.hooks.*teacher_log_probsfrom a returned dict, because #4466'sreward_funcstores them and returns a scalar. Timing stamps and the verifier reward are unchanged.--skip-actor-forward-onlyadded (sync layouts only)--use-rollout-logprobsand run no forward-only pass, so they are unchanged.--no-skip-actor-forward-onlyrestores the validated sync configuration.--eval-configinline instead of a JSON file written into the data dirdefaults.--attention-dropout/--hidden-dropout0→0.0; TB/W&B project names; recipe dir no longer onPYTHONPATHGPU validation
On 8×GB300 (2 trays × 4),
radixark/miles:latest(TE 2.17.0+miles, flash-attn-4 4.0.0b35, SGLang 0.5.23) with this branch checked out atbac0b1a344, no recipe-side workarounds.c571c4bchanges only the launcher's Ray-node listing; that check was rerun against the same live two-node cluster (passes forgb300-async, refuses a mismatched layout).gb300-sync --mtp-spec-decode(default--skip-actor-forward-only)ppo_kl=pg_clipfrac= 0; training accuracy 0.44 → 0.71gb300-async --extra-args "--fully-async --max-weight-staleness 1 --async-max-concurrent-samples 256"gb300-async --mtp-spec-decode, eval at 0/10/20The one-step async result matches the pre-stack run of the same recipe with its workarounds (78.5% / 99.6%, 173 s) within eval noise (128 prompts × 4 samples, about ±2–3 points).
train/train_rollout_logprob_abs_diffwas 0.014–0.020 in every run.Not run at this head: the 20-update sync layout, the B200 layouts, and any layout with TP, CP or PP > 1. In async layouts Ray may place the rollout manager on node B, and
--dump-dirmust then be on storage both nodes share foranalyze.pyto findrollout_data/.The README and docs page report only our own GB300 runs and the teacher cards' public accuracies; no third-party comparison numbers are in the repo.
Tests
All runs on macOS, CPU, Python 3.12. Nothing here can run on GPU.
test_run_qwen3_6_35b_a3b_mopd.py: 11 passed.test_mopd_reasoning_gym_hooks.py: 11 passed. Putting back the validated recipe's dict-extraction workaround makes 2 of them fail.pytest tests/fast/launch_scripts tests/manual/launch_scripts: 525 passed, 42 failed, 86 errors. The 128 failures and errors are identical onorigin/main, which has 510 passing./proc.run_deepseek_v4_1,run_qwen3_0_6b_torchtitan,amd/run_gpt_oss_20b_lora,run_glm5_3_flash_lora, model-args snapshots)./rootis read-only, so a local-only pytest plugin stubbedconvert_checkpoint's lock and stamp writes there. CI runs as root on Linux and needs no stub. Without the stub, 46 more errors come from that lock, on main as well.prepare.txtandexecute.txtwere recorded withMILES_UPDATE_LAUNCH_SCRIPT_SNAPSHOTS=1and verified stable.tests/fast/backendsat this head: 3,469 passed, 16 failed. The same 16 fail onorigin/main(3,436 passed there): loss-snapshot tolerances on macOS, torchtitan on-disk optimizer state, actor-init checkpoint scope, checkpoint transfer, and one order-dependent weight-update test that passes alone.tests/fast/{rollout,ray,utils,examples,doc},test_train_async.py,test_megatron_cli_flags.py: 12,810 passed, 35 failed, 4 errors.origin/main: agentic and session benchmarks, mock SGLang servers, disk-backed tensors, helm snapshots, git state.test_hot_restart::...raises_what_it_last_sawis timing-flaky; it fails onorigin/mainin the same environment too.test_transport::...proxy_stop_closes_idle_connectionspassed when rerun.test_ray_communication_boundarycaught the launcher importingray; fixed in c571c4b and now passing.pre-commit run: clean on every changed file.🤖 Generated with Claude Code