Skip to content
Merged
Show file tree
Hide file tree
Changes from 166 commits
Commits
Show all changes
215 commits
Select commit Hold shift + click to select a range
6983b6f
Pin the distillation objective before refactoring
qgallouedec Jul 19, 2026
d443d3b
Pin on-policy and off-policy training end to end
qgallouedec Jul 19, 2026
a8bb14c
Document the num_items_in_batch denominator bug
qgallouedec Jul 19, 2026
98eef79
Move IW-OPD to a dedicated experimental trainer
qgallouedec Jul 19, 2026
b65f8a7
Extract the teacher-server path into ServerDistillationTrainer
qgallouedec Jul 19, 2026
f75cd7e
Remove the local sparse top-1 loss path from the base trainer
qgallouedec Jul 19, 2026
6458636
Remove top-k support from the base generalized JSD loss
qgallouedec Jul 19, 2026
166808b
Validate the teacher by vocab size instead of tokenizer identity
qgallouedec Jul 19, 2026
952b0c3
Deprecate `lmbda` on/off-policy mixing
qgallouedec Jul 19, 2026
55e5973
Point the GKD paper reproduction at GKDTrainer
qgallouedec Jul 19, 2026
0b72a4e
Remove `lmbda` and the off-policy training branch
qgallouedec Jul 19, 2026
2527d3d
style
qgallouedec Jul 20, 2026
1c5bdea
Merge branch '04-move-iw-opd' into 05-extract-server-distillation
qgallouedec Jul 20, 2026
f232c18
Merge branch '05-extract-server-distillation' into 06-remove-local-sp…
qgallouedec Jul 20, 2026
7aab597
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
6efeb9f
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
0a4a3d6
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
5eabac4
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
aa0b5fb
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
e058764
style
qgallouedec Jul 20, 2026
4c65faf
Merge branch '05-extract-server-distillation' into 06-remove-local-sp…
qgallouedec Jul 20, 2026
3500348
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
de167a9
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
1908e5f
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
5a4f715
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
f270c1f
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
456df91
Fix IW-OPD paper metadata used in the model card
qgallouedec Jul 20, 2026
9ecf348
Merge branch '04-move-iw-opd' into 05-extract-server-distillation
qgallouedec Jul 20, 2026
28382eb
Merge branch '05-extract-server-distillation' into 06-remove-local-sp…
qgallouedec Jul 20, 2026
c4acfb4
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
d95c977
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
f64f96c
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
614bb6b
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
5cd0e91
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
26038dd
Remove stale on/off-policy comments after the off-policy removal
qgallouedec Jul 20, 2026
3515b22
Accept a `prompt` column alongside `messages`
qgallouedec Jul 20, 2026
4e5d06f
Accept a `prompt` column alongside `messages`
qgallouedec Jul 20, 2026
dfbf0e5
style
qgallouedec Jul 20, 2026
89494f2
Relax self-distillation train-loss assertion to tolerate fp noise
qgallouedec Jul 20, 2026
9b5ad81
Fix server-config construction to only copy dataclass init fields
qgallouedec Jul 20, 2026
d616372
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
1341b51
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
33667d3
Merge branch 'main' into 01-pin-distillation-objective
qgallouedec Jul 20, 2026
041e337
Merge branch '01-pin-distillation-objective' into 02-pin-on-and-off-p…
qgallouedec Jul 20, 2026
9e989d1
Merge branch '02-pin-on-and-off-policy-training' into 03-document-num…
qgallouedec Jul 20, 2026
b2c2b73
Merge branch '03-document-num-items-in-batch-bug' into 04-move-iw-opd
qgallouedec Jul 20, 2026
97cb164
Merge branch '04-move-iw-opd' into 05-extract-server-distillation
qgallouedec Jul 20, 2026
7db5120
Merge branch '05-extract-server-distillation' into 06-remove-local-sp…
qgallouedec Jul 20, 2026
2d2d32f
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
e63069d
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
e4764cc
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
800b68b
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
b290c1a
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
cad0c5e
Merge branch '11-remove-lmbda-offpolicy' into 12-accept-prompt-column
qgallouedec Jul 20, 2026
c978997
0.5 -> 0.25
qgallouedec Jul 20, 2026
acc70cc
Merge branch 'main' into 01-pin-distillation-objective
qgallouedec Jul 20, 2026
854d89d
Merge branch '01-pin-distillation-objective' into 02-pin-on-and-off-p…
qgallouedec Jul 20, 2026
b9f99f1
Diverge the teacher in the on/off-policy param-update pin
qgallouedec Jul 20, 2026
911b0e5
Merge branch 'main' into 01-pin-distillation-objective
qgallouedec Jul 20, 2026
6e8a528
Merge branch '01-pin-distillation-objective' into 02-pin-on-and-off-p…
qgallouedec Jul 20, 2026
fd67ed4
Merge branch '02-pin-on-and-off-policy-training' into 03-document-num…
qgallouedec Jul 20, 2026
a4831c6
Merge branch '03-document-num-items-in-batch-bug' into 04-move-iw-opd
qgallouedec Jul 20, 2026
222615d
Merge branch '04-move-iw-opd' into 05-extract-server-distillation
qgallouedec Jul 20, 2026
15a7f6f
Merge branch '05-extract-server-distillation' into 06-remove-local-sp…
qgallouedec Jul 20, 2026
34e801a
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
0a79977
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
cff3b68
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
1f8690a
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
4871948
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
8057ca4
Merge branch '11-remove-lmbda-offpolicy' into 12-accept-prompt-column
qgallouedec Jul 20, 2026
a0d5328
Merge branch 'main' into 02-pin-on-and-off-policy-training
qgallouedec Jul 20, 2026
f750ddd
Merge branch '02-pin-on-and-off-policy-training' into 03-document-num…
qgallouedec Jul 20, 2026
d0d7de3
Merge branch '03-document-num-items-in-batch-bug' into 04-move-iw-opd
qgallouedec Jul 20, 2026
e8ac1df
Merge branch '04-move-iw-opd' into 05-extract-server-distillation
qgallouedec Jul 20, 2026
0b4fa84
Merge branch '05-extract-server-distillation' into 06-remove-local-sp…
qgallouedec Jul 20, 2026
b4f7d75
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
f7d9dc8
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
5914158
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
b8f85a4
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
1492b20
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
d8892e4
Merge branch '11-remove-lmbda-offpolicy' into 12-accept-prompt-column
qgallouedec Jul 20, 2026
26eba3c
remove unused import
qgallouedec Jul 20, 2026
f51acd6
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
0462f03
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
ce31b5d
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
989ae4d
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
15e24cc
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
3cbd70f
Merge branch '11-remove-lmbda-offpolicy' into 12-accept-prompt-column
qgallouedec Jul 20, 2026
24b235c
Merge remote-tracking branch 'origin/main' into pr/qgallouedec/6452
qgallouedec Jul 20, 2026
5e05b9d
Rework the num_items_in_batch xfail: applied denominator, on-policy
qgallouedec Jul 20, 2026
23784c3
Use a non-strict xfail for the num_items_in_batch pin
qgallouedec Jul 20, 2026
7615bfe
Merge branch '03-document-num-items-in-batch-bug' into 04-move-iw-opd
qgallouedec Jul 20, 2026
82a2017
Merge branch '04-move-iw-opd' into 05-extract-server-distillation
qgallouedec Jul 20, 2026
3eaabc7
Merge branch '05-extract-server-distillation' into 06-remove-local-sp…
qgallouedec Jul 20, 2026
4d9ac2b
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
e881f07
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
7632074
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
4b3c62a
Merge branch 'main' into 04-move-iw-opd
qgallouedec Jul 20, 2026
685d3f5
Merge branch '04-move-iw-opd' into 05-extract-server-distillation
qgallouedec Jul 20, 2026
7bf9d07
Merge branch '05-extract-server-distillation' into 06-remove-local-sp…
qgallouedec Jul 20, 2026
40f96ed
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
40ee117
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
821d875
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
9ad8c2a
Merge remote-tracking branch 'origin/main' into pr/qgallouedec/6454
qgallouedec Jul 20, 2026
fc5b481
Merge branch '05-extract-server-distillation' into 06-remove-local-sp…
qgallouedec Jul 20, 2026
6f8c4a7
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
59a804d
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
f23fc4f
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
d3be590
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
ba3aa35
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
6a2be12
Deprecate `messages`-format datasets
qgallouedec Jul 20, 2026
a41d5df
Merge remote-tracking branch 'origin/main' into pr/qgallouedec/6455
qgallouedec Jul 20, 2026
f069c1e
Merge branch '06-remove-local-sparse-top1' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
58c13be
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
01b6f67
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
3faa04b
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
1375800
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
43c42f4
Merge remote-tracking branch 'origin/11-remove-lmbda-offpolicy' into …
qgallouedec Jul 20, 2026
1a58484
Merge remote-tracking branch 'origin/main' into 07-remove-topk-from-jsd
qgallouedec Jul 20, 2026
45fdb23
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
0bca659
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
939143d
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
0a08547
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
901b155
Merge branch '11-remove-lmbda-offpolicy' into 12-accept-prompt-column
qgallouedec Jul 20, 2026
a056303
Merge branch '12-accept-prompt-column' into 13-deprecate-messages-dat…
qgallouedec Jul 20, 2026
93f6f55
Drop the loss_top_k usage-tips bullet from the docs
qgallouedec Jul 20, 2026
dc4c01b
Merge branch '07-remove-topk-from-jsd' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
356eaab
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
bca4b35
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
825de01
Merge branch 'main' into 08-teacher-vocab-validation
qgallouedec Jul 20, 2026
6d09aa1
Merge branch '08-teacher-vocab-validation' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
5b99699
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
e185842
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
4365c60
Merge branch '11-remove-lmbda-offpolicy' into 12-accept-prompt-column
qgallouedec Jul 20, 2026
a5fa96c
Merge branch '12-accept-prompt-column' into 13-deprecate-messages-dat…
qgallouedec Jul 20, 2026
94a185d
Merge branch 'main' into 09-deprecate-lmbda
qgallouedec Jul 20, 2026
e9365a6
Merge branch '09-deprecate-lmbda' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
a320f99
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
16ec8c3
Merge branch '11-remove-lmbda-offpolicy' into 12-accept-prompt-column
qgallouedec Jul 20, 2026
e6b1d37
Merge branch '12-accept-prompt-column' into 13-deprecate-messages-dat…
qgallouedec Jul 20, 2026
8567f94
Merge branch 'main' into 10-move-gkd-paper-repro
qgallouedec Jul 20, 2026
9ef74d9
Merge branch '10-move-gkd-paper-repro' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
109333e
Merge branch '11-remove-lmbda-offpolicy' into 12-accept-prompt-column
qgallouedec Jul 20, 2026
0d76047
Merge branch '12-accept-prompt-column' into 13-deprecate-messages-dat…
qgallouedec Jul 20, 2026
782f088
Merge branch 'main' into 11-remove-lmbda-offpolicy
qgallouedec Jul 20, 2026
88795b0
Merge branch '11-remove-lmbda-offpolicy' into 12-accept-prompt-column
qgallouedec Jul 20, 2026
749efd6
Merge branch '12-accept-prompt-column' into 13-deprecate-messages-dat…
qgallouedec Jul 20, 2026
ddcb836
Drop leftover lmbda=1.0 from the num_items xfail test
qgallouedec Jul 20, 2026
d36d174
Merge branch '11-remove-lmbda-offpolicy' into 12-accept-prompt-column
qgallouedec Jul 20, 2026
c077758
Merge branch '12-accept-prompt-column' into 13-deprecate-messages-dat…
qgallouedec Jul 20, 2026
71883b9
Merge remote-tracking branch 'origin/main' into 12-accept-prompt-column
qgallouedec Jul 21, 2026
ff9a39a
Merge branch '12-accept-prompt-column' into 13-deprecate-messages-dat…
qgallouedec Jul 21, 2026
46d1c26
Fix num_items_in_batch to count generated completion tokens
qgallouedec Jul 21, 2026
010f250
Revert "Fix num_items_in_batch to count generated completion tokens"
qgallouedec Jul 21, 2026
6c60211
Fix num_items_in_batch to count generated completion tokens
qgallouedec Jul 21, 2026
fbf4c3b
style
qgallouedec Jul 21, 2026
fa5e277
Normalize the num_items loss correctly for DDP and grad-accumulation
qgallouedec Jul 21, 2026
8351cb0
Normalize the num_items loss correctly for DDP and grad-accumulation
qgallouedec Jul 21, 2026
289c40c
Switch tests, docs, and example to prompt-only datasets
qgallouedec Jul 21, 2026
b02741c
remove pr desc
qgallouedec Jul 21, 2026
4a9273f
Qualify expected dataset as conversational prompt-only
qgallouedec Jul 21, 2026
2b5b737
Remove messages-format support and prompt-length config
qgallouedec Jul 21, 2026
4f91a90
Pin signature columns to GRPO's [prompt, image, images]
qgallouedec Jul 21, 2026
3c42827
Emit completion_mask alongside labels in the generated batch
qgallouedec Jul 21, 2026
6497bc5
Switch the loss to consume completion_mask instead of labels
qgallouedec Jul 21, 2026
b38280e
Emit prompt_ids/prompt_mask/completion_ids in the batch
qgallouedec Jul 21, 2026
790e9eb
Merge remote-tracking branch 'origin/main' into 13-deprecate-messages…
Jul 21, 2026
db068b1
Merge branch '13-deprecate-messages-datasets' into 14-fix-num-items
qgallouedec Jul 21, 2026
5f60751
Merge branch '14-fix-num-items' into 15-switch-tests-docs-prompt-only
qgallouedec Jul 21, 2026
14bb155
Merge branch '15-switch-tests-docs-prompt-only' into 16-remove-messag…
qgallouedec Jul 21, 2026
df5112e
Merge branch '16-remove-messages-support' into 17-pin-signature-columns
qgallouedec Jul 21, 2026
58514ce
Merge branch '17-pin-signature-columns' into 18-emit-completion-mask
qgallouedec Jul 21, 2026
1962b77
Merge branch '18-emit-completion-mask' into 19-loss-consumes-completi…
qgallouedec Jul 21, 2026
54ecc8b
Merge branch '19-loss-consumes-completion-mask' into 20-emit-prompt-c…
qgallouedec Jul 21, 2026
5d9178a
Merge branch 'main' into 14-fix-num-items
qgallouedec Jul 21, 2026
194481e
Merge branch '14-fix-num-items' into 15-switch-tests-docs-prompt-only
qgallouedec Jul 21, 2026
5aac5aa
Merge branch '15-switch-tests-docs-prompt-only' into 16-remove-messag…
qgallouedec Jul 21, 2026
c0c999a
Merge branch '16-remove-messages-support' into 17-pin-signature-columns
qgallouedec Jul 21, 2026
a35c66d
Merge branch '17-pin-signature-columns' into 18-emit-completion-mask
qgallouedec Jul 21, 2026
16ecfbd
Merge branch '18-emit-completion-mask' into 19-loss-consumes-completi…
qgallouedec Jul 21, 2026
3de49f6
Merge branch '19-loss-consumes-completion-mask' into 20-emit-prompt-c…
qgallouedec Jul 21, 2026
9378f79
Merge branch 'main' into 15-switch-tests-docs-prompt-only
qgallouedec Jul 21, 2026
76115bf
Merge branch '15-switch-tests-docs-prompt-only' into 16-remove-messag…
qgallouedec Jul 21, 2026
e044b15
Merge branch '16-remove-messages-support' into 17-pin-signature-columns
qgallouedec Jul 21, 2026
a0e4aad
Merge branch '17-pin-signature-columns' into 18-emit-completion-mask
qgallouedec Jul 21, 2026
f030767
Merge branch '18-emit-completion-mask' into 19-loss-consumes-completi…
qgallouedec Jul 21, 2026
77712c0
Merge branch '19-loss-consumes-completion-mask' into 20-emit-prompt-c…
qgallouedec Jul 21, 2026
f1d4896
Remove stale teacher-server section from the distillation doc
qgallouedec Jul 21, 2026
7cd12e0
Merge branch '15-switch-tests-docs-prompt-only' into 16-remove-messag…
qgallouedec Jul 21, 2026
431f1da
Merge branch '16-remove-messages-support' into 17-pin-signature-columns
qgallouedec Jul 21, 2026
a9d882d
Merge branch '17-pin-signature-columns' into 18-emit-completion-mask
qgallouedec Jul 21, 2026
7fa5fcd
Merge branch '18-emit-completion-mask' into 19-loss-consumes-completi…
qgallouedec Jul 21, 2026
66d058d
Merge branch '19-loss-consumes-completion-mask' into 20-emit-prompt-c…
qgallouedec Jul 21, 2026
fe497cd
Merge branch 'main' into 15-switch-tests-docs-prompt-only
qgallouedec Jul 21, 2026
9f68612
Merge branch '15-switch-tests-docs-prompt-only' into 16-remove-messag…
qgallouedec Jul 21, 2026
34f6eb1
Merge branch '16-remove-messages-support' into 17-pin-signature-columns
qgallouedec Jul 21, 2026
3bf52d7
Merge branch '17-pin-signature-columns' into 18-emit-completion-mask
qgallouedec Jul 21, 2026
d59a130
Merge branch '18-emit-completion-mask' into 19-loss-consumes-completi…
qgallouedec Jul 21, 2026
8de3282
Merge branch '19-loss-consumes-completion-mask' into 20-emit-prompt-c…
qgallouedec Jul 21, 2026
f07dd4e
Merge remote-tracking branch 'origin/main' into 16-remove-messages-su…
qgallouedec Jul 22, 2026
532ba1e
Merge branch '16-remove-messages-support' into 17-pin-signature-columns
qgallouedec Jul 22, 2026
7837ea4
Merge branch '17-pin-signature-columns' into 18-emit-completion-mask
qgallouedec Jul 22, 2026
292a17a
Merge branch '18-emit-completion-mask' into 19-loss-consumes-completi…
qgallouedec Jul 22, 2026
095502a
Merge branch '19-loss-consumes-completion-mask' into 20-emit-prompt-c…
qgallouedec Jul 22, 2026
ac1f71f
Drop stale local-teacher loss comment
qgallouedec Jul 22, 2026
ea143ae
Merge branch 'main' into 17-pin-signature-columns
qgallouedec Jul 22, 2026
a934541
Merge branch '17-pin-signature-columns' into 18-emit-completion-mask
qgallouedec Jul 22, 2026
40ec499
Merge branch '18-emit-completion-mask' into 19-loss-consumes-completi…
qgallouedec Jul 22, 2026
752c9b3
Merge branch '19-loss-consumes-completion-mask' into 20-emit-prompt-c…
qgallouedec Jul 22, 2026
a33b289
Merge branch 'main' into 18-emit-completion-mask
qgallouedec Jul 22, 2026
f263644
Merge branch '18-emit-completion-mask' into 19-loss-consumes-completi…
qgallouedec Jul 22, 2026
be286b1
Merge branch '19-loss-consumes-completion-mask' into 20-emit-prompt-c…
qgallouedec Jul 22, 2026
80d20fb
Merge branch 'main' into 19-loss-consumes-completion-mask
qgallouedec Jul 22, 2026
79cc62c
Merge branch '19-loss-consumes-completion-mask' into 20-emit-prompt-c…
qgallouedec Jul 22, 2026
69bbafc
Merge branch 'main' into 20-emit-prompt-completion-ids
qgallouedec Jul 22, 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
44 changes: 17 additions & 27 deletions docs/source/distillation_trainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ The `DistillationTrainer` is designed for distilling teacher models of all sizes
from datasets import load_dataset
from trl.experimental.distillation import DistillationConfig, DistillationTrainer

# 1. Load dataset and format as prompt-only chat messages
# 1. Load dataset and format as a prompt-only column
dataset = load_dataset("openai/gsm8k", "main", split="train")
dataset = dataset.map(
lambda x: {"messages": [{"role": "user", "content": x["question"]}]},
lambda x: {"prompt": [{"role": "user", "content": x["question"]}]},
remove_columns=dataset.column_names,
)

Expand All @@ -35,7 +35,6 @@ config = DistillationConfig(
bf16=True,
save_strategy="no",
# Distillation
lmbda=1.0, # fully on-policy (student generates)
beta=1.0, # reverse KL
# Teacher
teacher_model_init_kwargs={"dtype": "bfloat16"},
Expand All @@ -54,14 +53,13 @@ trainer.save_model()

## Usage tips

The [`experimental.distillation.DistillationTrainer`] needs two key parameters set via [`experimental.distillation.DistillationConfig`]:
The [`experimental.distillation.DistillationTrainer`] trains the student fully on-policy: the student generates its own completions and learns to match the teacher's next-token distribution on them. The key parameter is set via [`experimental.distillation.DistillationConfig`]:

* `lmbda`: controls the student data fraction, i.e., the proportion of on-policy student-generated outputs. When `lmbda=0.0`, training is fully off-policy (dataset completions only). When `lmbda=1.0`, training is fully on-policy (student generates all completions). For values in between, each gradient accumulation slice is randomly assigned as on- or off-policy based on `lmbda`.
* `beta`: controls the interpolation in the Generalized Jensen-Shannon Divergence. When `beta=0.0` the loss approximates forward KL divergence, while `beta=1.0` approximates reverse KL divergence. Values in between interpolate.

### On-policy vs. off-policy
### On-policy generation

Setting `lmbda=1.0` (fully on-policy) generally outperforms off-policy distillation because the student learns from its own mistakes rather than imitating trajectories it may never produce. The generation buffer ensures on-policy training stays efficient: prompts across gradient accumulation steps are batched into a single vLLM call.
Fully on-policy training generally outperforms off-policy distillation because the student learns from its own mistakes rather than imitating trajectories it may never produce. The generation buffer keeps this efficient: prompts across gradient accumulation steps are batched into a single vLLM call.

### Using an external teacher server

Expand All @@ -74,7 +72,6 @@ config = DistillationConfig(
teacher_model_server_url="http://teacher-host:8000",
loss_top_k=1, # required with teacher server when beta > 0
beta=1.0,
lmbda=1.0,
)

trainer = DistillationTrainer(
Expand All @@ -93,50 +90,43 @@ When using the teacher server:

### Expected dataset type

The dataset should be formatted as a [conversational](dataset_formats#conversational) [language modeling](dataset_formats#language-modeling) dataset:
The dataset should be formatted as a [conversational](dataset_formats#conversational) [prompt-only](dataset_formats#prompt-only) dataset. The student generates its own completions on-policy, so only the prompt is needed:

```python
{"messages": [{"role": "user", "content": "What color is the sky?"},
{"role": "assistant", "content": "It is blue."}]}
```

When using fully on-policy distillation (`lmbda=1.0`), the assistant turn can be omitted since the student will generate its own completions:

```python
{"messages": [{"role": "user", "content": "What color is the sky?"}]}
{"prompt": [{"role": "user", "content": "What color is the sky?"}]}
```

## Example script

Use [`examples/scripts/distillation.py`](https://github.com/huggingface/trl/blob/main/examples/scripts/distillation.py) to launch distillation training from the command line. The script supports full training, mixed on/off-policy, and LoRA via the standard `ModelConfig` flags.
Use [`examples/scripts/distillation.py`](https://github.com/huggingface/trl/blob/main/examples/scripts/distillation.py) to launch distillation training from the command line. The script supports full training and LoRA via the standard `ModelConfig` flags.

```bash
# Full training (off-policy only, lmbda=0):
# Full training:
python examples/scripts/distillation.py \
--model_name_or_path Qwen/Qwen2.5-0.5B-Instruct \
--teacher_model_name_or_path Qwen/Qwen2.5-1.5B-Instruct \
--dataset_name trl-lib/chatbot_arena_completions \
--dataset_name trl-lib/ultrafeedback-prompt \
--learning_rate 2e-5 \
--per_device_train_batch_size 4 \
--gradient_accumulation_steps 8 \
--lmbda 0.0 \
--output_dir distilled-model \
--num_train_epochs 1
```

```bash
# Mixed on/off-policy (lmbda=0.5):
# LoRA:
python examples/scripts/distillation.py \
--model_name_or_path Qwen/Qwen2.5-0.5B-Instruct \
--teacher_model_name_or_path Qwen/Qwen2.5-1.5B-Instruct \
--dataset_name trl-lib/chatbot_arena_completions \
--learning_rate 2e-5 \
--dataset_name trl-lib/ultrafeedback-prompt \
--learning_rate 2e-4 \
--per_device_train_batch_size 4 \
--gradient_accumulation_steps 8 \
--lmbda 0.5 \
--beta 0.5 \
--output_dir distilled-model \
--num_train_epochs 1
--num_train_epochs 1 \
--use_peft \
--lora_r 64 \
--lora_alpha 16
```

## DistillationTrainer
Expand Down
23 changes: 3 additions & 20 deletions examples/scripts/distillation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,15 @@

# docstyle-ignore
"""
# Full training (off-policy only, lmbda=0):
# Full training:
```
python examples/scripts/distillation.py \
--model_name_or_path Qwen/Qwen2.5-0.5B-Instruct \
--teacher_model_name_or_path Qwen/Qwen2.5-1.5B-Instruct \
--dataset_name trl-lib/chatbot_arena_completions \
--dataset_name trl-lib/ultrafeedback-prompt \
--learning_rate 2e-5 \
--per_device_train_batch_size 4 \
--gradient_accumulation_steps 8 \
--lmbda 0.0 \
--output_dir distilled-model \
--num_train_epochs 1
```

# Mixed on/off-policy (lmbda=0.5):
```
python examples/scripts/distillation.py \
--model_name_or_path Qwen/Qwen2.5-0.5B-Instruct \
--teacher_model_name_or_path Qwen/Qwen2.5-1.5B-Instruct \
--dataset_name trl-lib/chatbot_arena_completions \
--learning_rate 2e-5 \
--per_device_train_batch_size 4 \
--gradient_accumulation_steps 8 \
--lmbda 0.5 \
--beta 0.5 \
--output_dir distilled-model \
--num_train_epochs 1
```
Expand All @@ -57,11 +41,10 @@
python examples/scripts/distillation.py \
--model_name_or_path Qwen/Qwen2.5-0.5B-Instruct \
--teacher_model_name_or_path Qwen/Qwen2.5-1.5B-Instruct \
--dataset_name trl-lib/chatbot_arena_completions \
--dataset_name trl-lib/ultrafeedback-prompt \
--learning_rate 2e-4 \
--per_device_train_batch_size 4 \
--gradient_accumulation_steps 8 \
--lmbda 0.0 \
--output_dir distilled-model \
--num_train_epochs 1 \
--use_peft \
Expand Down
115 changes: 86 additions & 29 deletions tests/experimental/test_distillation_trainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ def _make_args(self, **kwargs):
"disable_tqdm": True,
"use_cpu": True,
"bf16": False,
"max_length": 128,
"max_completion_length": 32,
"model_init_kwargs": {"dtype": "float32", "device_map": None},
"teacher_model_init_kwargs": {"dtype": "float32", "device_map": None},
Expand All @@ -207,7 +206,7 @@ def _make_args(self, **kwargs):
return DistillationConfig(**args)

def _make_local_trainer(self, **kwargs):
dataset = load_dataset("trl-internal-testing/zen", "conversational_language_modeling", split="train")
dataset = load_dataset("trl-internal-testing/zen", "conversational_prompt_only", split="train")
return DistillationTrainer(
model=self.model_id,
teacher_model=self.model_id,
Expand All @@ -216,14 +215,6 @@ def _make_local_trainer(self, **kwargs):
processing_class=self.tokenizer,
)

def _make_batch(self, trainer):
examples = [trainer.train_dataset[i] for i in range(2)]
return trainer.data_collator(examples)

@staticmethod
def _move_batch_to_device(batch, device):
return {key: value.to(device) for key, value in batch.items()}

def test_distillation_trainer_train_runs_with_local_teacher(self):
training_args = self._make_args(
dataloader_drop_last=True,
Expand All @@ -234,7 +225,7 @@ def test_distillation_trainer_train_runs_with_local_teacher(self):
save_steps=2,
per_device_eval_batch_size=2,
)
dataset = load_dataset("trl-internal-testing/zen", "conversational_language_modeling")
dataset = load_dataset("trl-internal-testing/zen", "conversational_prompt_only")
trainer = DistillationTrainer(
model=self.model_id,
teacher_model=self.model_id,
Expand Down Expand Up @@ -274,12 +265,21 @@ def test_train_updates_params(self):
for name, param in previous_params.items():
assert not torch.equal(param, trainer.model.get_parameter(name)), f"Parameter {name} has not changed."

@pytest.mark.xfail(
reason="On-policy, num_items_in_batch is computed by transformers from the raw dataloader labels before "
"generation replaces the completions, and _RepeatBatchDataLoader repeats one generation batch across the "
"accumulation window, so the denominator the loss divides by does not equal the completion tokens actually "
"trained on. Un-xfail when the count moves to the GRPO-style _prepare_inputs (plan 5.6).",
)
def test_train_runs_with_prompt_only_dataset(self):
"""The forward-looking prompt-only format trains end to end: the student generates, the teacher scores."""
dataset = load_dataset("trl-internal-testing/zen", "conversational_prompt_only", split="train")
trainer = DistillationTrainer(
model=self.model_id,
teacher_model=self.model_id,
args=self._make_args(max_steps=1, learning_rate=0.1),
train_dataset=dataset,
processing_class=self.tokenizer,
)

trainer.train()

assert all(torch.isfinite(param).all() for param in trainer.model.parameters())

def test_num_items_in_batch_counts_the_tokens_trained_on(self, monkeypatch):
"""`num_items_in_batch` is the loss denominator, so it must count the completion tokens actually trained on.

Expand All @@ -290,13 +290,18 @@ def test_num_items_in_batch_counts_the_tokens_trained_on(self, monkeypatch):
recorded = [] # (denominator applied, completion tokens in this microbatch)
original = DistillationTrainer._reduce_divergence_loss

def _recording(jsd, labels=None, reduction="batchmean", num_items_in_batch=None):
recorded.append((num_items_in_batch, int((labels != -100).sum())))
return original(jsd, labels=labels, reduction=reduction, num_items_in_batch=num_items_in_batch)
def _recording(jsd, completion_mask=None, reduction="batchmean", num_items_in_batch=None):
# `generalized_jsd_loss(reduction="none")` also routes through here with `completion_mask=None`; only the
# loss-reducing call (with a mask) carries the denominator under test.
if completion_mask is not None:
recorded.append((num_items_in_batch, int(completion_mask.sum())))
return original(
jsd, completion_mask=completion_mask, reduction=reduction, num_items_in_batch=num_items_in_batch
)

monkeypatch.setattr(DistillationTrainer, "_reduce_divergence_loss", staticmethod(_recording))

dataset = load_dataset("trl-internal-testing/zen", "conversational_language_modeling", split="train")
dataset = load_dataset("trl-internal-testing/zen", "conversational_prompt_only", split="train")
trainer = DistillationTrainer(
model=self.model_id,
teacher_model=self.model_id,
Expand Down Expand Up @@ -326,14 +331,14 @@ def _recording(jsd, labels=None, reduction="batchmean", num_items_in_batch=None)
],
)
def test_init_with_eval_dataset(self, eval_dataset_type):
train_dataset = load_dataset("trl-internal-testing/zen", "conversational_language_modeling", split="train")
train_dataset = load_dataset("trl-internal-testing/zen", "conversational_prompt_only", split="train")

if eval_dataset_type == "none":
eval_dataset = None
else:
streaming = "iterable" in eval_dataset_type
eval_split = load_dataset(
"trl-internal-testing/zen", "conversational_language_modeling", split="test", streaming=streaming
"trl-internal-testing/zen", "conversational_prompt_only", split="test", streaming=streaming
)
if eval_dataset_type in ("dataset", "iterable_dataset"):
eval_dataset = eval_split
Expand Down Expand Up @@ -373,11 +378,25 @@ def test_loss_normalizes_by_num_items_in_batch(self):
for p in trainer.teacher_model.parameters():
p.add_(0.5 * torch.randn_like(p))

batch = self._move_batch_to_device(self._make_batch(trainer), trainer.accelerator.device)
# The collator is prompt-only (completions come from on-policy generation); build a batch with completion
# tokens directly to exercise the loss reduction.
device = trainer.accelerator.device
prompt_length, completion_length = 4, 3
seq_length = prompt_length + completion_length
input_ids = torch.randint(0, trainer.model.config.vocab_size, (2, seq_length), device=device)
labels = input_ids.clone()
labels[:, :prompt_length] = -100
batch = {
"input_ids": input_ids,
"attention_mask": torch.ones_like(input_ids),
"labels": labels,
"completion_mask": (labels != -100).int(),
"prompts": input_ids[:, :prompt_length],
"prompt_attention_mask": torch.ones(2, prompt_length, dtype=torch.long, device=device),
}

# Number of valid (non-ignored) tokens in the local batch, sliced the same way `compute_loss` does.
prompt_length = trainer._compute_prompt_length(batch)
num_valid = (batch["labels"][:, prompt_length:] != -100).sum()
num_valid = (labels[:, prompt_length:] != -100).sum()

trainer.model.eval()
with torch.no_grad():
Expand All @@ -390,13 +409,51 @@ def test_loss_normalizes_by_num_items_in_batch(self):
# Doubling the global count exactly halves the loss (sum / num_items is linear in 1/num_items).
torch.testing.assert_close(loss_double, loss_mean / 2, rtol=1e-4, atol=1e-6)

def test_generated_batch_emits_completion_mask(self, monkeypatch):
"""The generated batch emits `completion_mask`, equal to `labels != -100` (added ahead of the loss switch)."""
trainer = self._make_local_trainer()
captured = {}
original = DistillationTrainer.compute_loss

def _capturing(self, model, inputs, *args, **kwargs):
captured.setdefault("inputs", {k: v.clone() if torch.is_tensor(v) else v for k, v in inputs.items()})
return original(self, model, inputs, *args, **kwargs)

monkeypatch.setattr(DistillationTrainer, "compute_loss", _capturing)
trainer.train()

inputs = captured["inputs"]
assert "completion_mask" in inputs
assert torch.equal(inputs["completion_mask"].bool(), inputs["labels"] != -100)

def test_generated_batch_emits_prompt_and_completion_ids(self, monkeypatch):
"""The generated batch emits GRPO-style `prompt_ids`/`prompt_mask`/`completion_ids` alongside the old keys."""
trainer = self._make_local_trainer()
captured = {}
original = DistillationTrainer.compute_loss

def _capturing(self, model, inputs, *args, **kwargs):
captured.setdefault("inputs", {k: v.clone() if torch.is_tensor(v) else v for k, v in inputs.items()})
return original(self, model, inputs, *args, **kwargs)

monkeypatch.setattr(DistillationTrainer, "compute_loss", _capturing)
trainer.train()

inputs = captured["inputs"]
for key in ("prompt_ids", "prompt_mask", "completion_ids"):
assert key in inputs
# cat(prompt_ids, completion_ids) reconstructs input_ids; the new keys mirror the existing prompt tensors.
assert torch.equal(torch.cat([inputs["prompt_ids"], inputs["completion_ids"]], dim=1), inputs["input_ids"])
assert torch.equal(inputs["prompt_ids"], inputs["prompts"])
assert torch.equal(inputs["prompt_mask"], inputs["prompt_attention_mask"])

@require_liger_kernel
@require_torch_accelerator
def test_distillation_trainer_with_liger(self):
import importlib

training_args = self._make_args(use_liger_kernel=True, use_cpu=False)
dataset = load_dataset("trl-internal-testing/zen", "conversational_language_modeling", split="train")
dataset = load_dataset("trl-internal-testing/zen", "conversational_prompt_only", split="train")

trainer = DistillationTrainer(
model=self.model_id,
Expand All @@ -416,7 +473,7 @@ def test_distillation_trainer_with_liger(self):
def test_teacher_vocab_size_mismatch_raises(self):
# The local-teacher loss compares full next-token distributions, so student and teacher must share a
# vocabulary. A teacher with a different vocab_size is rejected (use GOLD for cross-tokenizer distillation).
dataset = load_dataset("trl-internal-testing/zen", "conversational_language_modeling", split="train")
dataset = load_dataset("trl-internal-testing/zen", "conversational_prompt_only", split="train")
with pytest.raises(ValueError, match="vocab_size"):
DistillationTrainer(
model=self.model_id,
Expand All @@ -429,7 +486,7 @@ def test_teacher_vocab_size_mismatch_raises(self):
def test_teacher_model_init_kwargs_with_instantiated_teacher_raises(self):
# `teacher_model_init_kwargs` only applies when the teacher is a model id; passing it alongside an already
# instantiated teacher is a mistake worth surfacing.
dataset = load_dataset("trl-internal-testing/zen", "conversational_language_modeling", split="train")
dataset = load_dataset("trl-internal-testing/zen", "conversational_prompt_only", split="train")
with pytest.raises(ValueError, match="teacher_model_init_kwargs"):
DistillationTrainer(
model=self.model_id,
Expand Down
14 changes: 2 additions & 12 deletions tests/experimental/test_server_distillation_trainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,8 @@ def _canned_teacher_logprobs(**kwargs):
def _variable_length_dataset():
return Dataset.from_list(
[
{"messages": [{"role": "user", "content": "What's 2+2?"}, {"role": "assistant", "content": "4."}]},
{
"messages": [
{"role": "user", "content": "Name three primary colors."},
{
"role": "assistant",
"content": "Red, green, and blue are the three primary colors commonly used in additive color mixing.",
},
]
},
{"prompt": [{"role": "user", "content": "What's 2+2?"}]},
{"prompt": [{"role": "user", "content": "Name three primary colors."}]},
]
)

Expand Down Expand Up @@ -272,8 +264,6 @@ def _run_one_step(self, bs, ga, monkeypatch):
per_device_train_batch_size=bs,
gradient_accumulation_steps=ga,
learning_rate=1e-4,
max_length=64,
max_prompt_length=32,
max_completion_length=32,
teacher_model_server_url="http://fake-teacher.invalid:8000",
loss_top_k=1,
Expand Down
Loading
Loading