# Ray-based Megatron RLHF examples (GKD & GRPO) GRPO/GKD on top of Megatron, orchestrated by Ray. The student/actor is trained with Megatron, generates completions with vLLM, and — for GKD — is distilled with a teacher model. ## How to run ```bash # via the helper scripts CUDA_VISIBLE_DEVICES=0,1,2,3 bash examples/ray/gkd/run.sh # or directly megatron rlhf --use_ray true --config examples/ray/gkd/rollout_colocate_teacher_colocate.yaml ``` The YAML is split into a top-level section (shared args) and per-role groups (`train`, `rollout`, and optionally `teacher`). Each group's `gpus:` field sets how many GPUs that role uses; `CUDA_VISIBLE_DEVICES` must expose at least the total number of GPUs the chosen placement needs (see below). The `gkd/` folder ships three ready-to-run configs. The file name encodes the two independent choices — **rollout placement** and **teacher mode**: | file | rollout | teacher | |------|---------|---------| | `rollout_colocate_teacher_colocate.yaml` | colocate (shares train GPUs) | colocated (shares train GPUs) | | `rollout_separate_teacher_colocate.yaml` | separate (own GPUs) | colocated (shares train GPUs) | | `rollout_colocate_teacher_standalone.yaml` | colocate (shares train GPUs) | standalone vLLM replicas (own GPUs) | --- ## 1. GPU placement: colocate vs separate This is controlled by `colocate_groups` plus each role's `gpus`. | Placement | `colocate_groups` | GPUs needed | When to use | |-----------|-------------------|-------------|-------------| | **colocate** | `[[train, rollout]]` | `train.gpus` — all roles in the group **must** set the same `gpus` (one shared set) | default; fewer GPUs, train and rollout time-share the same devices | | **separate** | *omit* | `train.gpus + rollout.gpus` (disjoint sets) | more GPUs, rollout overlaps with training | - **colocate** — train and rollout live on the *same* devices and take turns. Set `offload_model`/`offload_optimizer` (+ `offload_teacher_model` for GKD) and `sleep_level: 1` so the idle role releases GPU memory to the active one. Example: `train.gpus=4`, `rollout.gpus=4`, `colocate_groups: [[train, rollout]]` → 4 GPUs total, with TP2 giving **DP2**. - **separate** — train and rollout occupy *disjoint* GPU sets; weights are pushed to the rollout engine every step. --- ## 2. Teacher modes (GKD only) Pick exactly one. `gkd_logits_topk: K` selects top-k distillation; omit it for full-vocab distillation. | Mode | How to configure | top-k | full-vocab | Status | |------|------------------|:-----:|:----------:|--------| | **Colocated `teacher_model`** | set top-level `teacher_model:` (+ `offload_teacher_model: true`) | ✅ | ✅ | supported | | **Standalone teacher replicas** | add a `teacher:` group with `gpus`, `model`, and `vllm_engine_kwargs.max_logprobs` | ✅ | ❌ | supported | ### 2a. Colocated teacher (`rollout_colocate_teacher_colocate.yaml`, `rollout_separate_teacher_colocate.yaml`) The teacher shares the **train** GPUs and is offloaded to CPU between teacher forwards. It is the only mode that supports full-vocab distillation, and it works with both colocate and separate rollout placements. ```yaml teacher_model: Qwen/Qwen3.5-4B offload_teacher_model: true gkd_logits_topk: 64 # omit for full-vocab ``` ### 2b. Standalone teacher replicas (`rollout_colocate_teacher_standalone.yaml`) The teacher runs as its own set of Ray-managed vLLM replicas on **separate** GPUs and returns prompt top-k logprobs; the driver fetches them per step. ```yaml gkd_logits_topk: 64 # REQUIRED — replicas are top-k only # do NOT set top-level teacher_model here (that would also load a colocated teacher) teacher: gpus: 4 model: Qwen/Qwen3.5-4B # the teacher checkpoint these replicas serve vllm_engine_kwargs: {"max_logprobs": 64} # MUST be >= gkd_logits_topk ``` - `max_logprobs` must be `>= gkd_logits_topk`, or vLLM rejects the `prompt_logprobs` request. - GPUs needed = colocated train+rollout set **+** `teacher.gpus`. --- ## 3. top-k vs full-vocab distillation - **top-k** (`gkd_logits_topk: K`): the teacher exposes only the top-K logprobs per position. Much lower memory, works for every teacher mode. - **full-vocab** (omit `gkd_logits_topk`): distill the full vocabulary distribution. Colocated teacher only, and **memory-heavy** (caches per-rank vocab-sharded teacher logits). If you OOM: switch to top-k, lower `micro_batch_size` --- ## 4. OPSD (On-Policy / privileged Distillation) OPSD lets the teacher see a *different* (privileged) prompt than the student while scoring the **same** on-policy response — e.g. the teacher sees the problem + a reference solution. A dataset preprocessor (loaded via `external_plugins`) emits a per-row `teacher_prompt`; the loss aligns the shared response tokens by mask. ```yaml external_plugins: examples/train/rlhf/opsd/opsd_plugin.py # registers teacher_prompt teacher_model: Qwen/Qwen3.5-4B gkd_logits_topk: 64 ``` - Supported in Ray with **top-k** (`gkd_logits_topk`) for both a **colocated teacher** and **standalone teacher replicas** (`teacher.gpus > 0`). - No extra flag is needed: OPSD activates automatically when rows carry a non-empty `teacher_prompt`; otherwise training falls back to plain GKD. --- ## 5. Things to know (common knobs & pitfalls) - **Sequence length**: the encoder budget is `max_length + max_completion_length` (prompt is capped at `max_length`, the on-policy completion adds up to `max_completion_length`). Size `vllm_max_model_len` accordingly. - **`padding_free: true`** packs a micro-batch into one sequence; pair with `sequence_parallel: true` when `tensor_model_parallel_size > 1`. - **Parallelism / DP**: data parallel size = `gpus / (TP * PP * CP)`. e.g. 4 GPUs with `tensor_model_parallel_size: 2` → DP2. - **Memory release (colocate)**: `offload_model`, `offload_optimizer`, `offload_teacher_model`, and `sleep_level: 1` are what let colocated roles fit. - **GRPO specifics**: rewards via `reward_funcs` + `external_plugins`; sampling via `num_generations` / `steps_per_generation`; no `teacher_*` settings.