Features
π KTO is now a stable trainer
After many cycles of KTOTrainer β DPOTrainer alignment work, KTO graduates from trl.experimental.kto to the top-level trl package. Same API as DPO/GRPO/SFT β imports move from experimental, tests move to the main test tree, docs no longer flag it as experimental. The experimental path still works and emits a FutureWarning (removal in v2.0.0).
# Before
from trl.experimental.kto import KTOConfig, KTOTrainer
# Now
from trl import KTOConfig, KTOTrainerPer our telemetry, KTO is the 4th most used trainer in TRL β this graduation was overdue.
by @albertvillanova in #6175, #6287 and #6345
Environment-owned rewards & multi-environment support
Three interrelated changes make agentic RL training with environments substantially more ergonomic.
Environment-owned reward. If your environment_factory env defines a reserved get_reward() method (no args β float), it's called once per completed rollout and treated as a reward source. reward_funcs becomes optional β no more leaking env state back out to trainer-owned reward funcs.
class WordleEnv:
def reset(self, **kwargs):
self._target = sample(words); self._solved = False
def get_reward(self) -> float: # optional, reserved (not a tool)
return 1.0 if self._solved else 0.0
def guess(self, word: str) -> str: # exposed as a tool
self._solved = word == self._target; ...
trainer = GRPOTrainer(
model=model,
train_dataset=dataset,
environment_factory=WordleEnv, # no reward_funcs needed
)Multi-environment support. environment_factory now accepts dict[str, factory] in addition to a single callable. Each dataset row selects its environment via an environment column, and only that env's tools are exposed in that row's prompt β so a coding task and a game can train together in one run without leaking each other's tool schemas. Single-callable usage is unchanged.
Same wiring lands in GRPO, AsyncGRPO, DPPO, and GRPO-with-replay-buffer.
Env-owned reward by @qgallouedec in #6238; multi-env in #6001 and #6002
Entropy regularization for GRPO
GRPOConfig now supports both static and adaptive entropy regularization (Skywork-OR1). The bonus encourages exploration and helps prevent premature policy collapse.
GRPOConfig(
entropy_coef=0.01, # static
# or:
use_adaptive_entropy=True, # adjust to target entropy
entropy_target=1.5,
entropy_coef_delta=0.01,
entropy_coef_min=0.0,
entropy_coef_max=0.1,
)Adaptive mode adjusts the coefficient once per optimizer step from window-aggregated entropy (gradient accumulation-aware) and persists entropy_coef in the checkpoint for resume. Not compatible with the Liger kernel.
by @albertvillanova in #6140
quantization_config trainer argument (streamlined QLoRA)
QLoRA no longer requires reaching into model_init_kwargs or pre-loading the model manually.
SFTTrainer(
model="meta-llama/Llama-2-7b-hf",
quantization_config=BitsAndBytesConfig(load_in_4bit=True),
peft_config=LoraConfig(),
train_dataset=dataset,
)Added to SFTTrainer, DPOTrainer, GRPOTrainer, RLOOTrainer, RewardTrainer, and KTOTrainer. Sits next to peft_config (the other non-serializable QLoRA ingredient), flows into from_pretrained, and raises if also set in args.model_init_kwargs. Also drops the redundant get_kbit_device_map() line β QLoRA trains identically without it across all tested configurations.
by @qgallouedec in #6157 and #6276
MoE aux loss extends to DPO and KTO
v1.7 added the router load-balancing auxiliary loss to GRPOTrainer / RLOOTrainer / AsyncGRPOTrainer. It's now on DPOTrainer and KTOTrainer too, so post-training MoE models with preference data keeps experts balanced.
by @qgallouedec in #6208 and #6275
Neuron-friendly chunked_nll via static-shape token packing
The chunked NLL path had data-dependent indexing that broke XLA/Neuron compilation. This PR reworks it to pack valid tokens to the front via a stable argsort on the validity mask, iterate over ceil(n_valid / chunk_size) * chunk_size whole chunks (a tensor, no Python-int sync), and use ignore_index=-100 inside each chunk. GPU behavior is unchanged; Neuron now works too β same tiny memory footprint (~1.33 GiB vs the naive 5.94 GiB alternative) with no per-mask recompilation.
by @michaelbenayoun in #6314
Packing-aware dynamic batching in AsyncGRPO
AsyncGRPO micro-batching becomes packing-aware and token-bounded on top of the padding-free path from v1.7:
- Ξ£ Lα΅’Β² row balancing β a greedy longest-first assignment gives every DP row the same Ξ£ Lα΅’Β² instead of the same token count (attention is O(LΒ²), FFN is O(L), so equal token counts don't equalize wall-clock). Cross-rank stragglers vanish; +19% MFU at 4B in the benchmark.
- Token-budget packing (opt-in) β cap each row at
token_budgettokens with a variable sample count, decoupling peak memory fromper_device_train_batch_size. Useful in memory-bound regimes (no gradient checkpointing, long context, very large models).
Both ride HF Trainer's existing gradient accumulation β no training-loop surgery, FSDP/EP collectives stay in lockstep.
by @AmineDiro in #6092
VLM support in GOLDTrainer
GOLDTrainer now supports vision-language models end-to-end.
by @Strongich in #5969
Support tool calling in KTO
by @qgallouedec in #6259
Support PEFT + Liger in DPO and KTO
by @albertvillanova in #6159 and #6277
Per-dataset fraction in dataset mixtures
You can now weight a DatasetMixtureConfig by fraction instead of only by explicit counts.
by @qgallouedec in #6199
SFT: truncate during dataset preparation
Continuing the label-refactor from v1.7 (#6037), truncation moves out of the collator and into dataset preparation. SFTTrainer and DPOTrainer now truncate consistently at the same phase.
by @qgallouedec in #6155
Simplify tokenization [1-5/N]
A big refactor pass merging DPO / SFT / Reward / KTO tokenization into one shared implementation:
- Remove redundant
is_vlmparameter β #6298 - Make
_tokenizea module-level function β #6301 - Factor
_tokenizeinto a single shared function β #6302 - Bundle
apply_chat_templatekwargs β #6305 - Pass
chat_templateasapply_chat_template_kwargsβ #6315
All by @albertvillanova. Related: align collators across DPO / SFT / Reward / KTO by @qgallouedec in #6178.
Other
- Support
DatasetDictandIterableDatasetDictaseval_datasetin trainers by @albertvillanova in #6322 - Auto-load
processing_classin CPO/ORPO trainers when omitted by @DaoyuanLi2816 in #6087 - Add
trust_remote_codetoGRPOConfigby @muupan in #4186 - Integrate the new response parsing API by @qgallouedec in #5791
- Raise a clear error when the ChatML collator truncates the whole prompt by @qgallouedec in #6310
- Raise a clear error when GKD student and teacher vocab sizes differ by @sergiopaniego in #6252
- Add prompt-learning guard for PEFT with Liger in GRPO by @albertvillanova in #6186
[async GRPO]Per-generationreset()observation by @qgallouedec in #6072- Default AsyncGRPO
token_budgetto vLLMmax_model_lenby @AmineDiro in #6218 - Drop vLLM 0.14 support by @qgallouedec in #6209
- Drop vLLM 0.15 support by @qgallouedec in #6239
- Log
entropyandnum_tokensmetrics in KTO by @qgallouedec in #6257 and #6256 - Standardize
TrainerCallbackimport to the public top-level path by @qgallouedec in #6249 - Remove redundant
get_kbit_device_map()by @qgallouedec in #6158 - Factorize
get_dataset_column_namesfrom core and experimental trainers by @albertvillanova in #6272 and #6273
Deprecations and removals
- Remove
GFPOTrainerby @qgallouedec in #6309 β no known usage, and its behavior can be reproduced by adjustingreward_funcs. - Remove
PAPOTrainerby @qgallouedec in #6235 - Remove post-training-toolkit integration by @qgallouedec in #6308
- Remove
sft_video_llm.pyscript by @qgallouedec in #6193
Fixes
- Fix GRPO + vLLM colocate + PEFT hang on non-NVLink hardware by @albertvillanova in #6139 and #6187
- Align CPO / ORPO / BCO / Distillation / TPO with DPO: fix ZeRO-3 + PEFT mixed-dtype error by @DaoyuanLi2816 in #6192
- Fix
chunked_nllpatch hiding VLM kwargs fromgenerateby @Strongich in #6156 - Fix vLLM server-mode generation in
OnlineDPOTrainerby @qgallouedec in #6228 - Fix activation offload storage dedupe reuse by @winglian in #6241
- Update merged probability computation to follow Bayes' rule by @vman049 in #5905
- Fix dataset fingerprinting in DPO/SFT tokenization by @qgallouedec in #6206
- Fix data types for PPO models by @albertvillanova in #6202
- Fix
precompute_ref_log_probsguard for iterable datasets nested in a dict by @albertvillanova in #6307 - Fix teacher quantization kwargs and guard eval callback in GKD example by @sergiopaniego in #6251
- Raise on
quantization_config+ already-instantiated model inDPOTrainer/KTOTrainerby @qgallouedec in #6312 - Fix incorrect examples in distillation docs by @sergiopaniego in #6334
- Fix
KTOTrainer._prepare_datasettype hint by @qgallouedec in #6207 - Fix PEFT
ensure_weight_tyingwarning in liger + PEFT GRPO tests by @albertvillanova in #6188 - Fix spurious liger token_accuracy CI warnings in SFT tests by @albertvillanova in #6189
- Fix
add_response_schematests for the newparse_responseprefix requirement by @qgallouedec in #6236 - Fix tiny DeepSeek-V3 configs for MLA:
num_key_value_heads = num_attention_headsby @albertvillanova in #6268 - Raise
ValueErrorinstead ofNotImplementedErrorfor Liger DPO with PEFT by @albertvillanova in #6225
Documentation and Examples
- Docs: fix Jobs requirement β positive credit balance, not a Pro/Team/Enterprise plan by @davanstrien in #6306
- Docs: clarify dtype defaults between transformers v5 and TRL by @casinca in #5457
- Document that
max_stepsis required for iterable train datasets by @albertvillanova in #6333 - Align KTO doc with DPO and fix Logged-metrics wording by @qgallouedec in #6258
- Align
epsilonhelp/docstring wording by @qgallouedec in #6014 (v1.7 window) - Fix KTO
max_lengthdocstring (truncation direction) by @qgallouedec in #6254 - Fix KTO
compute_metricstype hint (EvalLoopOutputβEvalPrediction) by @qgallouedec in #6253
CI
- Liger teardown in experimental tests by @cmpatino in #6203
- Sort conditional imports by @qgallouedec in #6180
- Align format of versions in CI workflows by @albertvillanova in #6223
- Update CI
huggingface/doc-builderby @albertvillanova in #6304 - Fix Upload PR Documentation: bump
doc-builderpin by @mishig25 in #6317 - Fix / set explicit owner in CI Sync TRL skills by @albertvillanova in #6200 and #6201
- Fix CI
test_chatml_collator_truncates_keeping_completion_endby @albertvillanova in #6318 - Test DPO / KTO init fails with
compute_metricsand Liger by @albertvillanova in #6231 and #6232 - Add
TestKTOTrainerSlowwithtest_train_vlm_gemma_3nby @albertvillanova in #6162 - Test
DataCollatorForChatMLraises when completion fills window by @albertvillanova in #6319 - Improve consistency of Liger Kernel initialization in DPO by @albertvillanova in #6242
- Align Liger loss naming across core and experimental trainers by @albertvillanova in #6243, #6245 and #6244
- Bump the actions group with 3 updates by @dependabot[bot] in #6214, #6285
New Contributors
- @vman049 made their first contribution in #5905
- @Strongich made their first contribution in #5969
- @michaelbenayoun made their first contribution in #6314
What's Changed
- β¬οΈ Bump dev version by @qgallouedec in #6185
- Fix GRPO + vLLM colocate + PEFT hang on non-NVLink hardware by @albertvillanova in #6139
- Remove RUNNING_NAME from KTO by @qgallouedec in #6179
- Align CPO/ORPO/BCO/Distillation/TPO with DPO: fix ZeRO-3 + PEFT mixed-dtype error by @DaoyuanLi2816 in #6192
- Align KTO collator keys with the DPO convention by @qgallouedec in #6182
- Move
_get_kl_completion_idsinto_get_kl_datasetby @qgallouedec in #6181 - Align experimental KTOTrainer docstring and signature with DPOTrainer by @qgallouedec in #6183
- Add packing-aware dynamic batching to AsyncGRPO by @AmineDiro in #6092
- Liger Teardown in Experimental Tests by @cmpatino in #6203
- Sort conditional imports by @qgallouedec in #6180
- Align TPO with DPO: Add evaluate() override by @DaoyuanLi2816 in #6195
- Auto-load
processing_classin CPO/ORPO trainers when omitted by @DaoyuanLi2816 in #6087 - Fix dataset fingerprinting in DPO/SFT tokenization by @qgallouedec in #6206
- Pass GPU device_ids to barrier fix in GRPO + vLLM colocate + PEFT by @albertvillanova in #6187
- Fix PEFT ensure_weight_tying warning in liger + PEFT GRPO tests by @albertvillanova in #6188
- Fix spurious liger token_accuracy CI warnings in SFT tests by @albertvillanova in #6189
- Fix deprecation in CI Sync TRL skills by @albertvillanova in #6200
- Set explicit owner in CI Sync TRL skills by @albertvillanova in #6201
- Fix data types for PPO models by @albertvillanova in #6202
- Fix: update merged probability computation to follow Bayes' rule by @vman049 in #5905
- Bump the actions group across 1 directory with 3 updates by @dependabot[bot] in #6214
- Remove sft_video_llm.py script by @qgallouedec in #6193
- Drop vLLM 0.14 support by @qgallouedec in #6209
- Integrate the new response parsing API by @qgallouedec in #5791
- [docs] Clarify dtype defaults between trf v5 and TRL by @casinca in #5457
- Align format of versions in CI workflows by @albertvillanova in #6223
- Align KTO with DPO: Align validation of liger and compute_metrics by @albertvillanova in #6224
- Raise ValueError instead of NotImplementedError for Liger DPO with PEFT by @albertvillanova in #6225
- Support multiple environments [1/2]: Pool and build environment tool dicts at batch time by @qgallouedec in #6001
- Test DPO init fails with compute_metrics and Liger by @albertvillanova in #6231
- Align KTO with DPO: Test init fails with compute_metrics and Liger by @albertvillanova in #6232
- [async GRPO] Per-generation reset() observation by @qgallouedec in #6072
- Fix
add_response_schematests for the newparse_responseprefix requirement by @qgallouedec in #6236 - Align KTO with DPO: Add TestKTOTrainerSlow with test_train_vlm_gemma_3n by @albertvillanova in #6162
- Support PEFT with Liger in DPO by @albertvillanova in #6159
- Drop
policy_prefix from KTO loss-internal logps/logits by @qgallouedec in #6204 - Fix KTOTrainer._prepare_dataset type hint by @qgallouedec in #6207
- Improve consistency of Liger Kernel initialization in DPO by @albertvillanova in #6242
- Align Liger loss naming across core trainers by @albertvillanova in #6243
- Align Liger loss naming across experimental trainers by @albertvillanova in #6245
- Align KTO with DPO: Align _tokenize by @albertvillanova in #6212
- Align KTO with DPO: Align error for Liger with PEFT by @albertvillanova in #6226
- Remove redundant
get_kbit_device_map()by @qgallouedec in #6158 - Fix vLLM server-mode generation in
OnlineDPOTrainerby @qgallouedec in #6228 - Use trl's guarded
is_liger_kernel_availablein DPOTrainer by @qgallouedec in #6247 - Default AsyncGRPO token_budget to vLLM max_model_len by @AmineDiro in #6218
- Fix tiny DeepSeek-V3 configs for MLA: num_key_value_heads =num_attention_heads by @albertvillanova in #6268
- Align KTO with DPO: Align Liger loss naming by @albertvillanova in #6244
- Raise a clear error when GKD student and teacher vocab sizes differ by @sergiopaniego in #6252
- SFT: Truncate during dataset preparation, not collation by @qgallouedec in #6155
- Add prompt-learning guard for PEFT with Liger in GRPO by @albertvillanova in #6186
- Add MoE load-balancing auxiliary loss to
DPOTrainerby @qgallouedec in #6208 - Add
quantization_configtrainer argument (streamline QLoRA) by @qgallouedec in #6157 - Align KTO with DPO: Support tool calling by @qgallouedec in #6259
- Align KTO with DPO: Align error for Liger with precompute_ref_logps by @albertvillanova in #6270
- Remove unused get_dataset_column_names from DPO by @albertvillanova in #6271
- Factorize get_dataset_column_names from core trainers by @albertvillanova in #6272
- Factorize get_dataset_column_names from experimental trainers by @albertvillanova in #6273
- Align KTO with DPO: Log
entropymetric by @qgallouedec in #6257 - Align KTO doc with DPO and fix Logged metrics wording by @qgallouedec in #6258
- Align KTO with DPO: Validate Liger kernel configuration before trainer initialization by @albertvillanova in #6227
- Align KTO with DPO: Remove stray misplaced comment in KTO
_get_train_samplerby @qgallouedec in #6255 - Align KTO with DPO: Fix KTO
max_lengthdocstring (truncation direction) by @qgallouedec in #6254 - Align KTO with DPO: Fix KTO
compute_metricstype hint (EvalLoopOutputβEvalPrediction) by @qgallouedec in #6253 - Align KTO with DPO: Align models import by @qgallouedec in #6248
- Align KTO with DPO: Align
Fimport with the rest of the repo by @qgallouedec in #6246 - Fix teacher quantization kwargs and guard eval callback in GKD example by @sergiopaniego in #6251
- Align experimental TPO _tokenize with core trainers by @albertvillanova in #6213
- Align KTO with DPO: Support PEFT with Liger by @albertvillanova in #6277
- Align KTO with DPO: clarify dtype default in
modeldocstring by @qgallouedec in #6278 - Align KTO with DPO: Log
num_tokensmetric by @qgallouedec in #6256 - Standardize
TrainerCallbackimport to the public top-level path by @qgallouedec in #6249 - Fix activation offload storage dedupe reuse by @winglian in #6241
- Align KTO with DPO: MoE load-balancing auxiliary loss by @qgallouedec in #6275
- Align data collators across DPO / SFT / Reward / KTO by @qgallouedec in #6178
- Drop vLLM 0.15 support by @qgallouedec in #6239
- Add entropy regularization to GRPO by @albertvillanova in #6140
- Bump the actions group with 3 updates by @dependabot[bot] in #6285
- Remove KTO shims from stable by @albertvillanova in #6287
- Promote KTO to stable API by @albertvillanova in #6175
- [GOLD] VLM support for GOLDTrainer by @Strongich in #5969
- Docs: fix Jobs requirement β positive credit balance, not a Pro/Team/Enterprise plan by @davanstrien in #6306
- Simplify tokenization [1/N]: Remove redundant is_vlm parameter by @albertvillanova in #6298
- Update CI huggingface/doc-builder by @albertvillanova in #6304
- Simplify tokenization [2/N]: Make _tokenize a module-level function by @albertvillanova in #6301
- Raise clear error when ChatML collator truncates the whole prompt by @qgallouedec in #6310
- Remove the PAPO trainer by @qgallouedec in #6235
- Add trust_remote_code to GRPOConfig by @muupan in #4186
- Simplify tokenization [3/N]: Factor _tokenize into a single shared function by @albertvillanova in #6302
- Simplify tokenization [4/N]: Bundle apply_chat_template kwargs by @albertvillanova in #6305
- Fix precompute_ref_log_probs guard for iterable datasets nested in a dict by @albertvillanova in #6307
- Fix Upload PR Documentation: bump doc-builder pin by @mishig25 in #6317
- Removes GFPOTrainer by @qgallouedec in #6309
- Fix CI test_chatml_collator_truncates_keeping_completion_end: no prompt tokens left after truncation by @albertvillanova in #6318
- Add per-dataset
fractionto dataset mixtures by @qgallouedec in #6199 - Test DataCollatorForChatML raises when completion fills window by @albertvillanova in #6319
- Simplify tokenization [5/N]: Pass chat_template as apply_chat_template_kwargs by @albertvillanova in #6315
- Support multiple environments [2/2]: Per-example environment selection by @qgallouedec in #6002
- Remove post-training-toolkit integration by @qgallouedec in #6308
- Environment-owned reward by @qgallouedec in #6238
- Align KTO with DPO:
quantization_configtrainer argument by @qgallouedec in #6276 - Support DatasetDict and IterableDatasetDict as eval_dataset in trainers by @albertvillanova in #6322
- Document that max_steps is required for iterable train datasets by @albertvillanova in #6333
- Raise on
quantization_config+ already-instantiated model inDPOTrainer/KTOTrainerby @qgallouedec in #6312 - Fix chunked_nll patch hiding VLM kwargs from generate by @Strongich in #6156
- Neuron-friendly
chunked_nllvia static-shape token packing by @michaelbenayoun in #6314 - Fix incorrect examples in distillation docs by @sergiopaniego in #6334
- Docs: treat KTO as a stable trainer by @qgallouedec in #6345
- Release: v1.8 by @qgallouedec in #6346
Full Changelog: v1.7.0...v1.8.0