Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
dae6334
feat(csd): add cross-tokenizer distillation and sub-token preparation
avenkateshha Oct 12, 2026
252eb43
refactor(csd): use the shared same-tokenizer KD helper
avenkateshha Oct 15, 2026
6f282b2
refactor(csd): build CSD batches with the shared cross-tokenizer coll…
avenkateshha Oct 15, 2026
da6fd8b
fix(csd): repair CSD test, recipe and suite configuration
avenkateshha Oct 15, 2026
6db2544
fix(csd): add the Automodel checkpoint block to CSD configs
avenkateshha Oct 15, 2026
badb142
fix(csd): pad CSD CP=2 recipe sequences to a multiple of 2
avenkateshha Oct 15, 2026
297bb2e
fix(csd): update tests that run only with the Automodel and Megatron …
avenkateshha Oct 15, 2026
75a3393
fix(csd): set refit offload keys on CSD example teachers
avenkateshha Oct 15, 2026
3aaa43b
feat(csd): run the CSD example on Megatron
avenkateshha Oct 15, 2026
5689406
docs(csd): describe the Megatron backend of the CSD example
avenkateshha Oct 15, 2026
0c6ec39
fix(csd): shift chunk predictors by default
avenkateshha Oct 15, 2026
414950a
feat(csd): make JSD the default CSD divergence
avenkateshha Oct 15, 2026
f7f77c5
feat(csd): add realized-only scoring for mismatch chunks
avenkateshha Oct 15, 2026
11a5ba6
fix(xtoken): mark alignment pairs over tokenizer padding invalid
avenkateshha Oct 16, 2026
99a6af0
test(csd): cover fixed and dynamic KD/CE weighting
avenkateshha Oct 16, 2026
6bf7b8f
chore(csd): remove the Moonlight router-replay recipe
avenkateshha Oct 16, 2026
c7694c4
refactor(csd): remove the position-0 mismatch term
avenkateshha Oct 16, 2026
b9cf3ad
feat(csd): weight mismatch chunks by 5 by default
avenkateshha Oct 16, 2026
8f5db56
feat(csd): clip overlength text rows and run CSD recipes nightly
avenkateshha Oct 16, 2026
010dd19
test(csd): add a Megatron TP2xCP2 recipe to the nightly suite
avenkateshha Oct 16, 2026
ce38f6b
feat(distributed): add vocab-parallel selected log-probs and sparse t…
avenkateshha Oct 16, 2026
3ef5ec1
feat(megatron): stream sparse top-k teacher rows with two forced labels
avenkateshha Oct 16, 2026
3709118
feat(csd): read requested teacher rows from sparse and dense IPC
avenkateshha Oct 16, 2026
5e366a8
feat(csd): evaluate cross-tokenizer KD on context-parallel owner ranks
avenkateshha Oct 16, 2026
ab14ab2
feat(csd): route eligible Megatron runs to owner-local evaluation
avenkateshha Oct 16, 2026
e247ca2
fix(csd): reduce same-tokenizer KD across Megatron context parallelism
avenkateshha Oct 16, 2026
bd984b0
feat(csd): send sparse teacher top-128 by default
avenkateshha Oct 16, 2026
6fd0dda
docs(csd): describe owner-local evaluation and teacher transports
avenkateshha Oct 16, 2026
a281128
fix(csd): apply the CP divisor check to Automodel entities only
avenkateshha Oct 19, 2026
aefe0ed
fix(csd): limit chat CE to assistant content and end-of-turn
avenkateshha Oct 19, 2026
dd864cf
docs(csd): add a CSD cross-tokenizer distillation guide
avenkateshha Oct 19, 2026
44889c4
docs(csd): merge the CSD guide into the cross-tokenizer guide
avenkateshha Oct 19, 2026
c516f03
docs(xtoken): rename the guide to cross-tokenizer-distillation.md
avenkateshha Oct 19, 2026
9946ac4
test(xtoken): pin the strict exact-map rule without the -1 sentinel
avenkateshha Oct 21, 2026
3f92c61
test(csd): add the copyright header to test_subtoks_tables.py
avenkateshha Oct 21, 2026
7e79fde
test: fix test-side failures and gaps in the Megatron and Automodel t…
avenkateshha Oct 21, 2026
d1af5c2
test(csd): trim the CSD nightlies and raise the nightly GPU-hour cap
avenkateshha Oct 21, 2026
dae117b
fix(megatron): shard the router padding mask in the unpacked-CP branch
avenkateshha Oct 21, 2026
00b688a
fix(csd): give the multi-teacher Phi-4-mini teacher its own table paths
avenkateshha Oct 21, 2026
f9a2db5
fix(megatron): skip the dense causal mask in the unpacked-CP branch
avenkateshha Oct 21, 2026
c560131
fix(megatron): apply freeze_parameter_patterns on the Megatron backend
avenkateshha Oct 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 81 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ For detailed information on backend selection, configuration, and examples, see
- 🔜 **On-Policy Cross-Tokenizer Distillation** - cross-tokenizer support for the on-policy (MOPD) recipe (today MOPD is same-tokenizer; cross-tokenizer xToken is off-policy)
- 🔜 **New Models** - Qwen3-Next, Minimax

- ✅ **CSD** - Cross-tokenizer distillation using bidirectional sub-token tables; see the [preparation and training guide](docs/guides/cross-tokenizer-distillation.md#csd-common-support-distillation).
- ✅ **X-Token Off-Policy Distillation** - Distillation across mismatched (student, teacher) tokenizers via a precomputed projection matrix.
- ✅ **Muon Optimizer** - Emerging Optimizer support for SFT/RL
- ✅ **Megatron Inference** - Improved performance for Megatron Inference (avoid weight conversion).
Expand Down Expand Up @@ -151,7 +152,7 @@ For detailed information on backend selection, configuration, and examples, see
|-|-|-|
|[GRPO](#grpo)|[GRPO Single Node](#grpo-single-node)|[GRPO Multi-node](#grpo-multi-node): [GRPO Qwen2.5-32B](#grpo-qwen25-32b), [GRPO Multi-Turn](#grpo-multi-turn)|
|[On-policy Distillation](#on-policy-distillation)|[Distillation Single Node](#on-policy-distillation-single-node)|[Distillation Multi-node](#on-policy-distillation-multi-node)|
|[X-Token Off-Policy Distillation](#x-token-off-policy-distillation)|[X-Token Off-Policy Distillation Single Node](#x-token-off-policy-distillation-single-node)|[X-Token Off-Policy Distillation Multi-node](#x-token-off-policy-distillation-multi-node)|
|[Cross-Tokenizer Distillation](#cross-tokenizer-distillation)|[X-Token Single Node](#x-token-off-policy-distillation-single-node), [CSD Single Node](#csd-single-node)|[X-Token Multi-node](#x-token-off-policy-distillation-multi-node), [CSD Multi-node](#csd-multi-node)|
|[SFT](#supervised-fine-tuning-sft)|[SFT Single Node](#sft-single-node)|[SFT Multi-node](#sft-multi-node)|
|[DPO](#dpo)|[DPO Single Node](#dpo-single-node)|[DPO Multi-node](#dpo-multi-node)|
|[RM](#rm)|[RM Single Node](#rm-single-node)|[RM Multi-node](#rm-multi-node)|
Expand Down Expand Up @@ -425,12 +426,13 @@ uv run python examples/run_grpo_sliding_puzzle.py

## Distillation

NeMo RL supports two distillation recipes:
NeMo RL supports three distillation recipes:

| Recipe | Multi-teacher | Asynchronous | Policy | Loss | Tokenizer | Backend |
|---|---|---|---|---|---|---|
| MOPD | Yes | Yes | On-policy | Top-1 sampled (RL-style) | Same | Megatron |
| xToken | Yes | No (sync) | Off-policy | Full-logit (KL) | Same or different | DTensor |
| CSD | Yes | No (sync) | Off-policy | Common-support top-K (JSD) | Same or different | DTensor or Megatron |

## On-policy Distillation

Expand Down Expand Up @@ -475,11 +477,18 @@ sbatch \
> [!NOTE]
> For GB200 systems with 4 GPUs per node, use `--gres=gpu:4` instead.

## X-Token Off-Policy Distillation
## Cross-Tokenizer Distillation

We support off-policy distillation between a student and a teacher that **do not share a tokenizer** (cross-tokenizer, or "x-token", distillation) — for example, distilling a `Qwen/Qwen3-4B` teacher into a `meta-llama/Llama-3.2-1B` student. The reference recipe trains on the ungated, CC-BY-4.0 [Nemotron-Pretraining-Specialized-v1.1](https://huggingface.co/datasets/nvidia/Nemotron-Pretraining-Specialized-v1.1) corpus (`Nemotron-Pretraining-Formal-Logic` subset).
Cross-tokenizer distillation trains a student from a teacher that **does not share its tokenizer** — for example, distilling a `Qwen/Qwen3-4B` teacher into a `meta-llama/Llama-3.2-1B` student. The two models split the same text into different tokens, so their next-token distributions cover different vocabularies and cannot be compared directly. NeMo RL supports two off-policy methods that bridge this gap:

You can read about the details of the x-token distillation implementation [here](docs/guides/xtoken-off-policy-distillation.md) and [here](https://arxiv.org/abs/2605.21699), including how the (student, teacher) projection matrix is built and how the loss modes work.
1. **[X-Token](#x-token-off-policy-distillation)** projects the student's logits into the teacher's vocabulary through a precomputed (student, teacher) projection matrix. It runs on the DTensor backend.
2. **[CSD](#csd-common-support-distillation)** (Common-Support Distillation) aligns the two tokenizations into chunks and compares the models only on the token and token-chain events that both tokenizers can express, using bidirectional sub-token tables. It runs on the DTensor or Megatron backend, chosen per model.

Both methods share the off-policy trainer, token alignment, and colocated CUDA IPC teacher transport, and both support multiple teachers, including teachers that share the student's tokenizer. Their reference recipes train on the ungated, CC-BY-4.0 [Nemotron-Pretraining-Specialized-v1.1](https://huggingface.co/datasets/nvidia/Nemotron-Pretraining-Specialized-v1.1) corpus (`Nemotron-Pretraining-Formal-Logic` subset). The [cross-tokenizer distillation guide](docs/guides/cross-tokenizer-distillation.md) covers both methods.

### X-Token Off-Policy Distillation

X-Token handles the vocabulary mismatch by projecting the student into the teacher's vocabulary. You can read about the details of the x-token distillation implementation [here](docs/guides/cross-tokenizer-distillation.md#x-token) and [here](https://arxiv.org/abs/2605.21699), including how the (student, teacher) projection matrix is built and how the loss modes work.

Before launching a run, build the projection matrix for your (student, teacher) tokenizer pair:

Expand All @@ -494,7 +503,7 @@ Before launching a run, build the projection matrix for your (student, teacher)
> [!NOTE]
> X-token distillation runs on the DTensor backend only, and the student and teacher must be colocated on the same node (teacher logits travel via CUDA IPC).

### X-Token Off-Policy Distillation Single Node
#### X-Token Off-Policy Distillation Single Node

To run x-token distillation on a single node using `meta-llama/Llama-3.2-1B` as the student and `Qwen/Qwen3-4B` as the teacher:

Expand All @@ -513,7 +522,7 @@ uv run python examples/run_xtoken_off_policy_distillation.py \
cluster.gpus_per_node=8
```

### X-Token Off-Policy Distillation Multi-node
#### X-Token Off-Policy Distillation Multi-node

```sh
# Run from the root of NeMo RL repo
Expand All @@ -535,6 +544,71 @@ sbatch \
> [!NOTE]
> For GB200 systems with 4 GPUs per node, use `--gres=gpu:4` instead.

### CSD (Common-Support Distillation)

CSD compares the student and teacher on events that both tokenizers can express — a shared token, or a shared chain of tokens — and keeps the remaining probability mass in a REST category. You can read about the details of the CSD implementation [here](docs/guides/cross-tokenizer-distillation.md#csd-common-support-distillation), including how the sub-token tables are built and how the loss treats each chunk type.

Before launching a run, build both sub-token tables for your (student, teacher) tokenizer pair and validate them:

```sh
uv run python -m tools.csd.build_subtoks_table \
--source-tokenizer meta-llama/Llama-3.2-1B \
--destination-tokenizer Qwen/Qwen3-4B \
--output cross_tokenizer_data/csd/student_to_teacher.pt

uv run python -m tools.csd.build_subtoks_table \
--source-tokenizer Qwen/Qwen3-4B \
--destination-tokenizer meta-llama/Llama-3.2-1B \
--output cross_tokenizer_data/csd/teacher_to_student.pt

uv run python -m tools.csd.validate_subtoks_tables \
--student-tokenizer meta-llama/Llama-3.2-1B \
--teacher-tokenizer Qwen/Qwen3-4B \
--student-to-teacher cross_tokenizer_data/csd/student_to_teacher.pt \
--teacher-to-student cross_tokenizer_data/csd/teacher_to_student.pt
```

> [!NOTE]
> Each CSD model runs on the DTensor or Megatron backend (the exemplar uses Megatron for both), and the student and teachers must be colocated on the same node (teacher logits travel via CUDA IPC).

#### CSD Single Node

To run CSD on a single node using `meta-llama/Llama-3.2-1B` as the student and `Qwen/Qwen3-4B` as the teacher:

```sh
uv run python examples/run_csd.py
```

By default, this uses the configuration in `examples/configs/csd.yaml`, whose table paths point at the files built above. Tables stored elsewhere are passed per teacher (`teachers.0.aligner.student_to_teacher_table_path=...` and `teachers.0.aligner.teacher_to_student_table_path=...`). You can customize other parameters with command-line overrides. For example, to send dense teacher logits instead of the default top-128 and train for 100 steps:

```sh
uv run python examples/run_csd.py \
loss_fn.teacher_topk_ipc_k=0 \
distillation.max_num_steps=100
```

#### CSD Multi-node

```sh
# Run from the root of NeMo RL repo
NUM_ACTOR_NODES=2

COMMAND="uv run ./examples/run_csd.py --config examples/configs/csd.yaml cluster.num_nodes=2 cluster.gpus_per_node=8 checkpointing.checkpoint_dir='results/csd_2nodes' logger.wandb_enabled=True logger.wandb.name='csd-2nodes'" \
CONTAINER=YOUR_CONTAINER \
MOUNTS="$PWD:$PWD" \
sbatch \
--nodes=${NUM_ACTOR_NODES} \
--account=YOUR_ACCOUNT \
--job-name=YOUR_JOBNAME \
--partition=YOUR_PARTITION \
--time=4:0:0 \
--gres=gpu:8 \
ray.sub
```

> [!NOTE]
> On more than one node, every teacher must use the student's data-parallel size and tensor × context × pipeline parallel group size, with each group inside one node. For GB200 systems with 4 GPUs per node, use `--gres=gpu:4` instead.

## Supervised Fine-Tuning (SFT)

We provide example SFT experiments using various datasets including [SQuAD](https://rajpurkar.github.io/SQuAD-explorer/), OpenAI format datasets (with tool calling support), and custom JSONL datasets. For detailed documentation on supported datasets and configurations, see the [SFT documentation](docs/guides/sft.md).
Expand Down
Loading
Loading