Skip to content

Add AsyncDistillationTrainer - #7

Open
kashif wants to merge 147 commits into
mainfrom
async-distillation-trainer
Open

Add AsyncDistillationTrainer#7
kashif wants to merge 147 commits into
mainfrom
async-distillation-trainer

Conversation

@kashif

@kashif kashif commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Async on-policy distillation, architected like AsyncGRPOTrainer: a background rollout worker generates the student's own completions and scores them against a teacher served over HTTP, so generation and training overlap instead of alternating. The teacher is never loaded locally, just a vLLM server URL.

Also supports MOPD (multi-teacher on-policy distillation) — pass more than one entry in teacher_server_urls and route each sample to a teacher via a teacher_id column (e.g. a math teacher and a code teacher, each served independently).

Ported from a staging fork where it went through several rounds of GPU validation and review, and was cross-checked against how NeMo RL, verl, and miles do the same kind of per-sample multi-teacher routing.

Adds:

  • trl/experimental/async_distillation/ (config, trainer, rollout worker, vLLM client, weight transfer)
  • tests/experimental/test_async_distillation_trainer.py
  • examples/scripts/async_distillation.py (single-teacher) and async_distillation_mopd.py (math+code MOPD demo)
  • docs/source/async_distillation_trainer.md + toctree entry, one-line cross-ref from distillation_trainer.md

make precommit passes. Test suite passes (26 passed / 8 GPU-gated skipped without a GPU); ran the GPU-gated tests via srun --gres=gpu:1 too — one pre-existing failure unrelated to this PR reproduces both here and on unmodified async_grpo tests on the same node (a tiny test-fixture/environment issue, not something this PR introduces).

albertvillanova and others added 30 commits July 23, 2026 11:39
Co-authored-by: Sergio Paniego Blanco <sergiopaniegoblanco@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Quentin Gallouédec <45557362+qgallouedec@users.noreply.github.com>
)

Co-authored-by: Kashif Rasul <kashif.rasul@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Quentin Gallouédec <45557362+qgallouedec@users.noreply.github.com>
…_completions` (unwired) (huggingface#6521)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: quentin.gallouedec@huggingface.co <quentin_gallouedec@ip-10-53-86-250.ec2.internal>
…_generation != gradient_accumulation_steps (huggingface#6024)

Co-authored-by: Behrooz Azarkhalili <ermiaazarkhalili@gmail.com>
Co-authored-by: Quentin Gallouédec <45557362+qgallouedec@users.noreply.github.com>
Co-authored-by: Quentin Gallouédec <quentin.gallouedec@huggingface.co>
Co-authored-by: Quentin Gallouédec <45557362+qgallouedec@users.noreply.github.com>
…e#6121)

Co-authored-by: Quentin Gallouédec <45557362+qgallouedec@users.noreply.github.com>
qgallouedec and others added 30 commits August 13, 2026 13:20
…#6727)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…utput (huggingface#6686)

Co-authored-by: Albert Villanova del Moral <8515462+albertvillanova@users.noreply.github.com>
`trl vllm-serve`'s custom app, and with it `/get_sequence_logprobs/`, goes
away in huggingface#6765, so the rollout worker teacher-forces the
student's completion through vLLM's own endpoint instead: `max_tokens=1`
with `prompt_logprobs=teacher_top_k`, sliced from `len(prompt_ids)`. Same
request `VLLMClient.get_sequence_logprobs` issues for the synchronous
server-teacher trainers.

The response is parsed here rather than through that client: it truncates
each position to exactly `top_logprobs` after rank-sorting and reports the
realized token in separate fields, which would drop that token wherever it
ranks below k, zeroing the teacher signal there at `beta=1.0`. Parsing the
raw `prompt_logprobs` mapping keeps it at any rank, so the candidate rows
stay `teacher_top_k + 1` wide and `_narrow_top1_actual_support` keeps
finding what it indexes.

`/v1/completions` names the model it addresses and, under MOPD, every
teacher serves a different one, so each teacher's served id is resolved
from its `/v1/models` at worker startup. That doubles as the teachers'
readiness wait.

Teacher servers are now plain `vllm serve` and need `--logprobs-mode
processed_logprobs` (or `teacher_temperature` never reaches their
logprobs) and `--max-logprobs -1` (or `teacher_top_k > 20` is rejected).
Documented, along with the pre-existing requirement that every teacher
share the student's tokenizer, since teacher candidate ids index the
student's vocabulary directly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Upstream huggingface#6715 reworked what AsyncGRPO measures; huggingface#6674 reworked how the sync
distillation trainer reads a model's logit post-processing. Both apply here.

Metrics, following huggingface#6715's namespaces (`rollout/`, `completions/`, `sample/`,
`batch/`, `perf/`) and its reduction rule — the value's shape and the key's
suffix pick the reduction, so a rate is stored as a `(num, den)` pair and
reduced as Σnum/Σden instead of as a mean of ratios:

- the worker gets a `metrics_queue` the trainer drains in `log()`, so it can
  report what only it can see: `rollout/duration_s`, `rollout/score_s`,
  `rollout/generated_tok_s` (windowed), `rollout/inflight`,
  `rollout/backpressure_s`, `rollout/vllm_retry_total` and the
  `completions/*` family.
- per-sample gauges no longer ride on `RolloutSample.metrics` and are no
  longer NaN-padded into the batch, broadcast to every rank and reduced back
  to compute a number rank 0 already had. The collator logs the sample and
  packing metrics directly; `sample.enqueued_at` gives the trainer
  `sample/time_in_queue_s`.
- new per-step accounting (`perf/step_s`, `fwd_bwd_s`, `fwd_s`,
  `optimizer_s`, `rollout_wait_s`, the three weight-sync phases) plus
  throughput and MFU on both a compute and a wall-clock basis, which is what
  separates a slow trainer from a starved one.
- trainer-side queue metrics (`sample/rollout_queue_size`,
  `staleness_*`, `dropped_stale_total`, `batch/dropped_oversize_total`).
- traces are sampled per policy version rather than per N samples, which at
  a few hundred samples/step buried the real metrics under empty rows.

Two metrics are distillation's own, since the teacher call sits on the
critical path of every rollout rather than in a separate scoring loop:
`rollout/score_s`, and `teacher_score_s/{teacher_id}` under MOPD — one slow
expert throttles only the rollouts routed to it, which the blended mean
hides. `docs/source/async_distillation_trainer.md` documents every metric.

Also in this commit:

- read `logit_scale` / `final_logit_softcapping` through `get_text_config()`
  and fall back to Muse Glimmer's `output_multiplier`, matching
  `DistillationTrainer`.
- drop `# docstyle-ignore` from `AsyncDistillationConfig` (huggingface#6785) and let the
  styler reflow it. Two pre-existing line-break artifacts it exposed — a
  broken markdown link and a broken class reference — are fixed rather than
  reflowed into literal spaces.
- raise `AsyncRolloutWorker`'s vLLM gate from 0.17.1 to 0.22.0, which is what
  `weight_transfer.py` and the docs already require and which is above TRL's
  own supported floor.
- drop a stale `trl vllm-serve` mention left over from the huggingface#6765 migration.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.