You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -30,14 +31,14 @@ This page covers the math and the configurable algorithmic components: the algor
30
31
31
32
A training algorithm in `prime-rl` is configured under `[orchestrator.algo]`, where **`type` names the algorithm** (`grpo`, `opd`, `sft`, …) and the class defaults are its vetted setting. It has two parts:
32
33
33
-
1.**Sampling** (`algo.sampling`) — how train rollouts are produced: which model generates them. `source` is a [model reference](#model-references): `"policy"` (the live policy, the default) or an inline frozen hosted model. Group sizing stays on the env config (`group_size`).
34
+
1.**Sampling** (`algo.sampling`) — how train rollouts are produced. `source` is `"policy"` (the live policy, the default), an inline frozen hosted model, or a static supervised dataset. Group sizing stays on the env config (`group_size`).
34
35
2.**The per-token training signal** — credit assignment and loss routing, fused; the algorithm's own parameters sit directly on `algo`. One mapping from a finalized rollout to per-token *(loss component, weight)* pairs — the credit a token gets and the loss that consumes it are two coordinates of the same output. Group-relative algorithms compute credit on the orchestrator and ship per-token advantage streams; reference-KL algorithms query a reference model at batch-ship time (bounded concurrency) and ship its prefill logprobs for the trainer to evaluate against the live policy. The `type` determines which loss component consumes the action tokens (`rl` / `ce` / `ref_kl`) and what happens to env-provided observation tokens in multi-turn rollouts (masked out by default; `echo` trains on them with weighted CE).
35
36
36
37
The trainer is algorithm-blind: the loss is a sum of three components (rl, ce, ref_kl), each normalized by its own global token count; per-token streams ship on the wire (the `rl_weights` / `ce_weights` / `ref_kl_weights` component weights plus the `advantages` stream on each training sample) and the trainer just executes them. Adding an algorithm never touches the dispatcher, packer, or trainer hot path.
37
38
38
39
### Model References
39
40
40
-
`prime-rl` hosts exactly one model: the trainable policy (`[orchestrator.model]`). Every other model an algorithm uses is an external OpenAI-compatible endpoint, declared *inline on the component that uses it*. A model reference is either the string `"policy"` (the live policy) or a frozen hosted model (`name` + `base_url`):
41
+
`prime-rl` hosts exactly one model: the trainable policy (`[orchestrator.model]`). Every other model an algorithm uses is an external OpenAI-compatible endpoint, declared *inline on the component that uses it*. A model reference is either the string `"policy"` (the live policy) or a frozen hosted model (`name` + `base_url`); static datasets are rollout sources, not model references:
Model *roles* are labels the algorithm itself declares over these references — the distillation algorithms declare their reference's role as `teacher`, so `[orchestrator.algo.teacher]` is the shorthand for that slot and validation errors speak the same language ("algorithm 'opd' needs a teacher"). No role exists outside the algorithm that declares it: the dispatcher, sink, and trainer branch on liveness alone, never on what an algorithm calls a model.
52
53
53
-
`algo.teacher` is shorthand for the slot the algorithm declares for its reference — `algo.model` for `opd` / `opsd`, `sampling.source` for `sft` (its teacher is the sampling source). A slot you didn't set takes the shorthand; an explicit reference that already equals it is accepted, a disagreeing one is an error. For `opd` / `opsd` you can also set `algo.model` directly; set the component fields directly for multi-model setups.
54
+
`algo.teacher` is shorthand for the slot the algorithm declares for its reference — `algo.model` for `opd` / `opsd`, `sampling.source` for `sft`'s frozen-teacher form. A slot you didn't set takes the shorthand; an explicit reference that already equals it is accepted, a disagreeing one is an error. For `opd` / `opsd` you can also set `algo.model` directly; set `algo.sampling.source`directly for dataset sources and multi-model setups.
54
55
55
-
Liveness is a property of the reference, not of any role: rollouts sampled from `"policy"` get version-salted prefix caches, carry sampling logprobs for importance ratios, and age off-policy as weights update; rollouts and scores from frozen models get a stable prefix cache and never go stale. Frozen models are externally hosted (`base_url` is required) — `prime-rl` never launches or updates them, and each env's algorithm builds its own client pool to the endpoints it declares.
56
+
Liveness is a property of the source, not of any role: rollouts sampled from `"policy"` get version-salted prefix caches, carry sampling logprobs for importance ratios, and age off-policy as weights update; rollouts and scores from frozen models get a stable prefix cache and never go stale; dataset-sourced rollouts are local message replay with no env or client. Frozen models are externally hosted (`base_url` is required) — `prime-rl` never launches or updates them, and each env's algorithm builds its own client pool to the endpoints it declares.
56
57
57
58
### The Algorithms
58
59
@@ -68,12 +69,45 @@ type = "grpo" # the default
68
69
|`grpo`| policy |`rl` on actions | Standard group-relative RL. |
69
70
|`max_rl`| policy |`rl` on actions | MaxRL ([arXiv:2602.02710](https://arxiv.org/abs/2602.02710)): GRPO's centered reward normalized by the group **mean** instead of the standard deviation — the gradient is unbiased for the order-`group_size` truncation of the maximum-likelihood objective, upweighting hard examples like `1/p`. |
70
71
|`opd`| policy |`ref_kl` on actions | On-policy distillation ([Thinking Machines](https://thinkingmachines.ai/blog/on-policy-distillation/)): the policy samples, per-token reverse KL against a reference model as the gradient signal. Needs a `teacher`. |
71
-
|`sft`|*(the teacher)*|`ce` on actions |Hard distillation: a frozen model generates rollouts, the policy trains with CE on its tokens. Needs a `teacher` (folds into `sampling.source`). |
72
+
|`sft`|*(teacher or dataset)*|`ce` on actions |Supervised fine-tuning: CE on a non-policy source's target tokens. Source picks the flavor — a frozen `teacher` model (distillation on fresh rollouts) or a static `dataset` (replay of stored traces). Assigns no credit. |
72
73
|`opsd`| policy |`ref_kl` on actions | SDFT ([arXiv:2601.19897](https://arxiv.org/abs/2601.19897)): the model is its own reference, conditioned on an expert demonstration. Defaults to the live policy (the paper's setting, no extra deployment); set an inline `model` to score under a frozen copy instead. |
73
74
|`echo`| policy |`rl` on actions + weighted `ce` on observations | ECHO: standard GRPO plus a cross-entropy loss on env-provided tokens already present in the rollout, selected by message role (needs the renderer's role attribution). Defaults to tool-response bodies at `alpha = 0.1` (ECHO's λ); set `roles` to train other roles, each at its own weight. |
74
75
|`reward`| policy |`rl` on actions | REINFORCE-style: advantage = raw reward, no group baseline. |
75
76
|`custom`| policy |`rl` on actions | Your own advantage function (`import_path`), per-token advantages per rollout — see [Custom Advantage](#custom-advantage). |
76
77
78
+
#### SFT Sources
79
+
80
+
`sft` always trains cross-entropy on non-policy target tokens. A frozen teacher source samples those targets from an externally hosted model:
81
+
82
+
```toml
83
+
[orchestrator.algo]
84
+
type = "sft"
85
+
86
+
[orchestrator.algo.teacher] # alias for sampling.source on sft
87
+
name = "teacher-model"
88
+
base_url = ["http://teacher:8000/v1"]
89
+
```
90
+
91
+
A static dataset source replays stored targets locally. Set `type = "dataset"` explicitly so the source table is read as a dataset, not a model reference:
Static dataset rows use either a `messages` column or `prompt` + `completion` columns. The dataset path does not start a Verifiers env or select a model client.
110
+
77
111
### Customizing Components
78
112
79
113
Every key beyond `type` is visibly your own assembly — there is no preset layer to diverge from. The vetted setting is the class defaults; what you set is what runs:
Component compatibility is validated at config time: frozen-model sampling can only feed the `ce` loss component — the `rl` and `ref_kl` components need the live policy's own sampling logprobs for importance ratios — `opd` pointed at `"policy"` is rejected as degenerate (zero KL), `sft`without a frozen source is rejected (CE on the policy's own tokens is not a distillation target). A group-relative algorithm with `group_size = 1` produces all-zero advantages; the resulting empty batch is caught at runtime (the orchestrator warns and aborts after repeated zero-trainable batches), not at config time.
148
+
Component compatibility is validated at config time: non-policy sampling can only feed the `ce` loss component — the `rl` and `ref_kl` components need the live policy's own sampling logprobs for importance ratios — `opd` pointed at `"policy"` is rejected as degenerate (zero KL), and `sft`with the policy as its source is rejected (CE on the policy's own tokens is not a supervision target). A group-relative algorithm with `group_size = 1` produces all-zero advantages; the resulting empty batch is caught at runtime (the orchestrator warns and aborts after repeated zero-trainable batches), not at config time.
115
149
116
150
### Per-Env Algorithms
117
151
@@ -140,7 +174,7 @@ At runtime, each env's resolved config builds two objects: a `Sampler` (`prime_r
140
174
|`max_rl`|`MaxRLAlgorithm`|`score_group`: mean-normalized group credit |
141
175
|`opd`|`OPDAlgorithm`|`score_batch`: own-context prefill under the teacher |
142
176
|`opsd`|`OPSDAlgorithm`|`score_batch`: demo-conditioned prefill under the teacher |
|`sft`|`SFTAlgorithm`|*(no hook — CE on the source's target tokens, no credit)*|
144
178
|`reward`|`RewardAlgorithm`|`score_rollout`: raw reward |
145
179
|`custom`|`CustomAlgorithm`|`score_group`: your function |
146
180
@@ -178,7 +212,7 @@ $$
178
212
$$
179
213
180
214
-`rl` — the configured RL loss (`[trainer.loss]`): DPPO + KL by default, or a [custom loss](#custom-loss). Fed by the group-relative advantage strategies (`grpo`, `max_rl`, `reward`, `custom`, and `echo`'s action tokens).
181
-
-`ce` — masked NLL. Used for frozen-model tokens (`sft`) and env-observation tokens (`echo`).
215
+
-`ce` — masked NLL. Used for supervised target tokens (`sft`) and env-observation tokens (`echo`).
182
216
-`ref_kl` — the per-token reverse KL to a reference model ($\log \pi_{\text{ref}} - \log \pi$) as the policy-gradient signal, importance-ratio corrected with a one-sided trust region (`opd`, `opsd`). Requires `ref_logprobs` from a [reference scoring](#reference-scoring); the scoring model must be a vLLM server (it's the only one that exposes `prompt_logprobs`).
183
217
184
218
The orchestrator stamps each sample's component membership as per-token weight streams (`rl_weights` / `ce_weights` / `ref_kl_weights` on the wire): a weight scales that component's per-token loss, `0.0` leaves the token out of the component entirely (mask *and* denominator), and components may overlap on the same token — their gradients sum. Each $N$ is the global (all-reduced) count of that component's member tokens, so the components don't dilute each other: adding echo observation tokens never changes the rl term's effective per-token learning rate, and an sft env packed next to a GRPO env doesn't soften its gradient. Tokens of different components pack freely into the same micro batch, and a plain GRPO run ships no weight streams at all (absent streams mean rl weight 1.0 on every trainable token — the unchanged hot path). Advantages always ship per token (`advantages` on the wire), assigned as per-token streams from the start — uniform group credit is broadcast over completion tokens at assignment; algorithms with no rl credit (opd, opsd) ship none.
@@ -283,7 +317,7 @@ The per-token training signal is set by `algo.type` and the [algorithm](#the-alg
283
317
|`reward`|`rl`| Advantage = raw reward, no baseline. |
284
318
|`opd`|`ref_kl`| On-policy distillation: per-token reverse KL to a reference model (`model`, an inline frozen hosted model), evaluated in the trainer from shipped reference logprobs. No credit — rollouts keep `advantages = None` (advantage-based filters never fire) and ship no advantage stream; `group_size` only fans out sampling. |
285
319
|`opsd`|`ref_kl`| SDFT: per-token reverse KL to a demo-conditioned reference. No credit — rollouts keep `advantages = None` (advantage-based filters never fire) and ship no advantage stream. |
286
-
|`sft`|`ce`| Cross-entropy on the sampled tokens. Assigns no advantage — trains on every sampled token. |
320
+
|`sft`|`ce`| Cross-entropy on the source's target tokens (a frozen teacher's rollouts or a static dataset's traces). Assigns no advantage — trains on every target token. |
287
321
|`custom`|`rl`| Your function (below); per-token advantages per rollout. |
Copy file name to clipboardExpand all lines: docs/training.md
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -59,7 +59,7 @@ A condensed view of the knobs you'll most often tune. For trainer-side paralleli
59
59
|`orchestrator.batch_size`| Tasks per trainer step. |
60
60
|`orchestrator.group_size`| Rollouts generated per task. |
61
61
|`orchestrator.max_off_policy_steps`| How many distinct policies may have contributed to one rollout before it's discarded (default 8). The main off-policy dial on long agentic rollouts — bump for throughput, lower for tighter on-policyness. Watch `errored_rollouts` and `mismatch_kl/all/mean` when tuning. |
62
-
|`[orchestrator.algo]`| Training algorithm — the advantage `type` names it (`grpo` default, `max_rl`, `opd`, `opsd`, `sft`, `echo`, `reward`, `custom`). See [Algorithms](#algorithms). |
62
+
|`[orchestrator.algo]`| Training algorithm — `type` names it (`grpo` default, `max_rl`, `opd`, `opsd`, `sft`, `echo`, `reward`, `custom`). See [Algorithms](#algorithms). |
63
63
|`[[orchestrator.train.env]]`| Training environments. List multiple tables for multi-env training; weight them via `ratio`. See [Configuration § Environments](configuration.md#environments-orchestratortrainenv). |
64
64
|`[[orchestrator.eval.env]]` + `orchestrator.eval.interval`| Eval environments and cadence (default every 100 steps). |
65
65
@@ -85,25 +85,25 @@ A condensed view of the knobs you'll most often tune. For trainer-side paralleli
85
85
86
86
The RL entrypoint supports several training algorithms, switched via `[orchestrator.algo]`'s `type` (see [Algorithms](algorithms.md#the-algorithm-abstraction) for the full reference, model references, and per-algorithm customization):
87
87
88
-
|`algo.type`|Frozen model (`algo.teacher`)| Use case |
88
+
|`algo.type`|Source| Use case |
89
89
|---|---|---|
90
90
|`grpo` (default) | None | Standard group-relative RL |
91
91
|`max_rl`| None |[MaxRL](https://arxiv.org/abs/2602.02710): GRPO with mean-normalized advantages (maximum-likelihood RL) |
92
92
|`opd`| Required, must be vLLM (needs `prompt_logprobs`) |[On-policy distillation](https://thinkingmachines.ai/blog/on-policy-distillation/): the policy generates rollouts, the trainer minimizes per-token reverse KL to a reference model |
93
-
|`sft`|Required, any OpenAI-compatible endpoint | Hard-distill: a frozen model generates rollouts, the policy trains on its tokens|
93
+
|`sft`|Frozen teacher endpoint or `sampling.source.type = "dataset"`| Supervised fine-tuning: train CE on non-policy target tokens from fresh teacher rollouts or static dataset traces|
94
94
|`opsd`|`"policy"` (the default, no deployment) or a vLLM endpoint serving a frozen copy |[SDFT](https://arxiv.org/abs/2601.19897): the model is its own reference conditioned on expert demonstrations |
95
95
|`echo`| None | GRPO plus cross-entropy on env-observation tokens |
96
96
97
97
`reward` (raw-reward credit, no baseline) and `custom` (your own advantage function) complete the set — see [Algorithms § The Algorithms](algorithms.md#the-algorithms).
98
98
99
-
Frozen models are declared inline on the algorithm (`[orchestrator.algo.teacher]` with `name` + `base_url`). The `rl` entrypoint only manages policy inference — start frozen-model servers yourself and point `base_url` at them:
99
+
Frozen models are declared inline on the algorithm (`[orchestrator.algo.teacher]` with `name` + `base_url`). Static SFT uses `[orchestrator.algo.sampling.source] type = "dataset"` with dataset fields such as `name` and `split`. The `rl` entrypoint only manages policy inference — start frozen-model servers yourself and point `base_url` at them:
100
100
101
101
```bash
102
102
CUDA_VISIBLE_DEVICES=1 uv run inference \
103
103
--model.name <frozen-model> --server.port 8001
104
104
```
105
105
106
-
The standalone `uv run sft` entrypoint is the more traditional SFT path — pure dataset-based, no orchestrator. Use the `sft` algorithm only when you want a frozen model to generate the supervision on the fly.
106
+
The standalone `uv run sft` entrypoint remains the dedicated dataset SFT trainer. Use the `sft` algorithm inside `uv run rl`when you want SFT-shaped CE training to share the orchestrator/trainer pipeline with other rollout sources or algorithms.
0 commit comments