TRL v1.0:紧跟领域发展的后训练库

Hugging Face Blog 工具

摘要

Hugging Face 发布 TRL v1.0,这是其训练后库的重大更新,将其从一个研究代码库转变为稳定、生产就绪的工具,支持 PPO 和 DPO 等超过 75 种训练方法。

暂无内容
查看原文 导出为 Word 导出为 PDF
查看缓存全文

缓存时间: 2026/05/08 09:14

TRL v1.0:与领域同步演进的后训练库

来源:https://huggingface.co/blog/trl-v1 返回文章列表 (https://huggingface.co/blog)

  • 1. 移动的目标:后训练作为一个不断变化的领域 (https://huggingface.co/blog/trl-v1#1-a-moving-target-post-training-as-a-shifting-field)
  • 2. 从项目到库:TRL 的混沌自适应设计 (https://huggingface.co/blog/trl-v1#2-from-project-to-library-trl-has-a-chaos-adaptive-design)
    • 本质转变:从代码到契约 (https://huggingface.co/blog/trl-v1#a-shift-in-nature-from-code-to-contract)
    • 稳定与实验,共存于同一屋檐下 (https://huggingface.co/blog/trl-v1#stable-and-experimental-under-the-same-roof)
    • 刻意限制抽象 (https://huggingface.co/blog/trl-v1#deliberately-limiting-abstractions)
    • 更明确,但更灵活 (https://huggingface.co/blog/trl-v1#more-explicit-but-more-adaptable)
  • 3. TRL 的定位 (https://huggingface.co/blog/trl-v1#3-where-trl-fits)
    • 生态系统 (https://huggingface.co/blog/trl-v1#ecosystem)
    • 训练方法 (https://huggingface.co/blog/trl-v1#training-methods)
    • 项目健康度 (https://huggingface.co/blog/trl-v1#project-health)
  • 4. 未来展望 (https://huggingface.co/blog/trl-v1#4-whats-next)
    • 异步 GRPO (https://huggingface.co/blog/trl-v1#asynchronous-grpo)
    • 方法从实验层毕业到稳定层 (https://huggingface.co/blog/trl-v1#graduating-methods-to-stable)
    • 规模化 (https://huggingface.co/blog/trl-v1#scaling)
    • 让训练对智能体可读 (https://huggingface.co/blog/trl-v1#making-training-legible-to-agents)
  • 5. 结论 (https://huggingface.co/blog/trl-v1#5-conclusion)

我们发布了 TRL v1.0,这标志着 TRL 的本质发生了真正的转变。它最初是一个研究代码库,如今已发展成为人们可以依赖的可靠库,对稳定性有了更明确的预期。这不仅仅是版本号的提升,它反映了 TRL 现已支撑生产系统的现实,并勇于承担这一责任。

TRL 目前已实现超过 75 种后训练方法 (https://huggingface.co/docs/trl/en/paper_index)。但覆盖范围本身并非目标。重要的是让这些方法易于尝试、比较,并真正在实践中使用。库的设计并非预先决定,而是多年迭代的结果——首次提交可追溯至六年前——它由该领域抛出的 everything 塑造而成:新算法、新模型、范式转移。久而久之,这种压力迫使代码库走向了一种非常特定的设计。其中某些部分初看可能有些不寻常,但如同许多进化而来的代码库一样,它们的存在自有其道理。

TRL 是为一个不断变化的领域而构建的。因此,问题不是如何设计完美的抽象,而是如何在一个不断推翻自身假设的领域中构建稳定的软件。这正是我们在 TRL v1.0 中尝试解决的问题,本文将解释我们是如何做到的。

1. 移动的目标:后训练作为一个不断变化的领域

后训练并非平滑地沿着单一配方演进,而是经历了一系列的重心转移,每一次不仅改变了目标,也改变了技术栈的形态。

PPO [Schulman et al., (2017) (https://huggingface.co/papers/1707.06347); Ziegler et al., (2019) (https://huggingface.co/papers/1909.08593)] 确立了一种看似标准的架构:策略模型、参考模型、学习得到的奖励模型、采样 rollout,以及 RL 循环。

随后 DPO 类方法如原始 DPO [Rafailov et al., (2023) (https://huggingface.co/papers/2305.18290)]、ORPO [Hong et al., (2024) (https://huggingface.co/papers/2403.07691)] 和 KTO [Ethayarajh et al., (2024) (https://huggingface.co/papers/2402.01306)] 打破了这一架构:偏好优化无需单独的奖励模型、价值模型或任何在线 RL。曾经看似基础的组件突然变得可选。

RLVR 类方法如 GRPO [Shao et al., (2024) (https://huggingface.co/papers/2402.03300)] 再次转移了重心。在数学、代码和工具使用等任务中,奖励通常来自验证器或确定性检查,而非学习得到的奖励模型。采样和 rollout 再次变得重要,但循环中的对象已不再是 PPO 库所围绕设计的那些。

教训不仅在于方法会变化,更在于核心定义也随之不断变化。在这里,强烈的假设往往寿命很短。这或许就是为何至今没有后训练库真正稳定下来。

2. 从项目到库:TRL 的混沌自适应设计

那么,为一个不愿静止的领域构建库意味着什么?答案是反直觉的:不要试图捕捉当今稳定的本质,而是围绕可能的变化来设计。奖励模型 说明了原因:它们在 PPO 中看似必不可少,在 DPO 中变得可选,在 RLVR 方法中又以验证器的形式回归——这些结构可能是确定性函数而非学习模型。任何围绕其原始形式构建的抽象到现在已经过时两次了。库的存活之道在于认识到强烈假设寿命短暂,并将这种可变性置于代码库组织的核心。

这就是 TRL 每月被下载 300 万次、主要下游项目将其视为稳定基础设施的环境。领域不断动摇根基,同时这些用户又需要事物保持稳定。

本质转变:从代码到契约

TRL 并非刻意决定成为库,而是发现自己已经是了。Unsloth (https://github.com/unslothai/unsloth) 和 Axolotl (https://github.com/axolotl-ai-cloud/axolotl) 等项目——拥有数千用户——直接基于 TRL 的 trainer 和 API 构建。TRL 的破坏性变更会瞬间传导至它们的技术栈。重命名的参数、偏移的默认值、重构的输出——任何一项都可能成为别人的事故。转变已然发生,v1.0 是 TRL 明确承认这一点的时刻。

稳定与实验,共存于同一屋檐下

TRL 稳定性模型的独特之处不在于它保证什么,而在于它同时容忍什么。稳定与实验共存于同一包内,但有着明确不同的契约。稳定核心遵循语义化版本控制。实验层不做此类承诺——这是新方法在评估期间落脚的地方,API 可以快速跟进领域的发展。

这不是妥协,而是对特定约束的回应:领域产生新方法的速度快于任何方法获得稳定性的速度。拒绝添加不成熟的方法会让 TRL 在数月内变得无关紧要。将它们全部加入稳定层则会在每次算法表现不如预期时破坏每个下游项目。

from trl import SFTTrainer  # ⚖️ 稳定
from trl.experimental.orpo import ORPOTrainer  # 🧪 实验

从实验到稳定的晋升不是自动的。关键在于维护成本与实际使用量的比率。有些方法因社区大量使用而获得位置,另一些则因为我们能将其维护成本降到足够低而变得可行——而代码库的设计正是实现这一点的关键。

实践中,稳定表面包括 SFT、DPO、Reward modeling、RLOO 和 GRPO 及其近缘变体的 trainer。实验表面更广、变化更快;最新参考请见 TRL 文档 (https://huggingface.co/docs/trl)。

达到 v1.0 所需的破坏性变更被刻意分散在 0.x 版本中。从最后一个 0.x 版本迁移的工作量很小——详见迁移指南 (https://github.com/huggingface/trl/blob/main/MIGRATION.md)。

刻意限制抽象

在模式不断变化的领域中,诱惑是构建能容纳一切的灵活抽象。我们的答案恰恰相反:将抽象限制在严格最小——同时认识到这个“最小“几乎总是被高估的

实践中,这转化为非常本地化的代码方法:

  • 避免泛型类层次结构
  • 倾向于显式实现
  • 接受甚至鼓励重复

目标并非完全消除结构——共享工具仍然存在——而是避免在领域本身尚未稳定时强加抽象。例如,与其为离线 trainer 定义通用基类,我们更倾向于在它们未来演化不确定时采用独立实现。

# ❌ 不要这样
class OfflineTrainer(Trainer):
    def some_common_method(self): ...

class DPOTrainer(OfflineTrainer): ...

class KTOTrainer(OfflineTrainer): ...

# ✅ 更好
class DPOTrainer(Trainer):
    def some_common_method(self): ...

class KTOTrainer(Trainer):
    def some_common_method(self): ...

另一个例子:

# ❌ 不要这样
# collator.py
class TRLCollator: ...

# dpo_trainer.py
class DPOTrainer:
    def __init__(self, ...):
        self.collator = TRLCollator(...)

# kto_trainer.py
class KTOTrainer:
    def __init__(self, ...):
        self.collator = TRLCollator(...)

# ✅ 更好
# dpo_trainer.py
class DataCollatorForPreference: ...

class DPOTrainer:
    def __init__(self, ...):
        self.collator = DataCollatorForPreference(...)

# kto_trainer.py
class DataCollatorForUnpairedPreference: ...

class KTOTrainer:
    def __init__(self, ...):
        self.collator = DataCollatorForUnpairedPreference(...)

Judges (https://github.com/huggingface/trl/blob/main/trl/experimental/judges/judges.py) 是我们未遵循这一原则时的良好例证。早期我们引入了 Judge 抽象来统一评估模型输出的各种方式。当时看起来合理。实践中,它从未真正被使用——该抽象与人们实际处理评估的方式不匹配,增加了间接层却没有增加价值。它仍存在于仓库中, mostly 作为遗留代码。事后看来,直接提供具体实现而不带统一抽象,会对用户更有帮助。

更明确,但更灵活

这种方法倾向于显式且可修改的使用方式,而非僵化的框架:更少的魔法,更多的控制。这有一个明显的代价:代码重复。虽然常被视为反模式,但在此情境中它不仅可接受,而且有效。与直觉相反,实践中它仍然可控,只需一个小而一致的纪律:保持实现之间的差异最小化,避免不必要的分歧。如同 Transformers 设计哲学 (https://huggingface.co/blog/transformers-design-philosophy#3-machine-learning-is-evolving-at-a-neck-breaking-speed) 中一样,我们设计上接受重复和局部显式性。动机大体一致,只是侧重点略有不同。

这看起来比描述更容易。比较 RLOO 和 GRPO:它们实现的大部分代码几乎逐行重复。这不是偶然的,也不是死重。这些方法足够接近,保持代码路径对齐使它们更易读、更易演化、更廉价维护。

3. TRL 的定位

这次比较的目的不是论证 TRL 应在每个维度上都做到最好。不应该。有些系统为最大吞吐量而构建(如 PipelineRL (https://github.com/ServiceNow/PipelineRL)),有些针对更窄的问题切片优化(如 LLaMA-Factory (https://github.com/hiyouga/LLaMA-Factory)),有些在特定环境中提供更固执己见的开发体验(如 Tinker (https://github.com/thinking-machines-lab/tinker))。TRL 在生态系统中占据不同的位置:它是一个通用后训练库,试图在领域允许的范围内保持 API 和代码尽可能简单,同时结合广泛的方法覆盖、深度的 Hugging Face 集成、相对较低的基础设施负担,以及明确的稳定性契约。

Unsloth (https://github.com/unslothai/unsloth) 和 Axolotl (https://github.com/axolotl-ai-cloud/axolotl) 等库未包含在此,因为它们构建于 TRL 之上而非并列比较;从这个意义上说,它们的许多用户间接也是 TRL 用户。

生态系统

TRL (https://github.com/huggingface/trl)OpenRLHF (https://github.com/OpenRLHF/OpenRLHF)veRL (https://github.com/volcengine/verl)PRIME-RL (https://github.com/PrimeIntellect-ai/prime-rl)PipelineRL (https://github.com/ServiceNow/PipelineRL)OAT (https://github.com/sail-sg/oat)Tinker (https://github.com/thinking-machines-lab/tinker)LLaMA-Factory (https://github.com/hiyouga/LLaMA-Factory)torchtune (https://github.com/meta-pytorch/torchtune)
Hugging Face Hub 集成🟢 完整🟡 不支持 push🟡 仅模型加载🟡 不支持 push🟡 不支持 push🟡 不支持 push🟡 不支持数据集加载🟢 完整🟡 仅数据集加载
PEFT / LoRA / QLoRA 支持🟢 LoRA + QLoRA🟢 LoRA + QLoRA🟡 仅 LoRA(QAT 而非 QLoRA)🟡 仅 LoRA🔴 不支持🟢 LoRA + QLoRA🟡 仅 LoRA🟢 LoRA + QLoRA🟢 LoRA + QLoRA(torchao,非 bitsandbytes)
实验追踪器灵活性任意(通过 report_to🟡 wandb + tensorboard🟢 wandb, mlflow, swanlab, tensorboard🔴 仅 wandb🔴 仅 wandb🔴 仅 wandb🟡 需 DIY(指标通过 API 返回,无内置追踪器)🟢 任意(通过 report_to)+ swanlab🟡 wandb + tensorboard(手动配置)
基础设施负担🟢 低(单 GPU,标准栈)🟠 高(需要 Ray)🔴 很高(Ray + rollout 引擎)🟠 高(独立 vLLM 服务器 + ZMQ)🟠 高(异步 vLLM 流水线)🟡 中(RL 需要 vLLM)🟢 低(托管云服务)🟢 低(单脚本)🟢 低(单脚本)

训练方法

TRL (https://github.com/huggingface/trl)OpenRLHF (https://github.com/OpenRLHF/OpenRLHF)veRL (https://github.com/volcengine/verl)PRIME-RL (https://github.com/PrimeIntellect-ai/prime-rl)PipelineRL (https://github.com/ServiceNow/PipelineRL)OAT (https://github.com/sail-sg/oat)Tinker (https://github.com/thinking-machines-lab/tinker)LLaMA-Factory (https://github.com/hiyouga/LLaMA-Factory)torchtune (https://github.com/meta-pytorch/torchtune)
VLM 支持🟢 是(SFT, DPO, GRPO)🔴 否🟢 是(SFT + PPO trainer 中)🟡 部分(仅 Qwen3-VL)🟢 是(通过 processor_factory)🔴 否🔴 否🟢 是(通过 mm_plugin)🟡 部分(仅 Llama Vision)
监督后训练🟢 是(通过 SFTTrainer)🟢 是(通过 SFTTrainer)🟢 是(通过 SFTTrainer)🟢 是(通过 SFT 入口)🔴 否🟢 是(通过 SFTLearner)🔴 否(仅低级原语)🟢 是(通过 SFT trainer)🟢 是(通过 finetune recipes)
蒸馏后训练🟢 是(GKD, SDFT, SDPO)🔴 否🟢 是(专用蒸馏 trainer)🟢 是(on-policy 蒸馏)🔴 否🔴 否🔴 否(仅低级原语)🔴 否🟢 是(原生 KD recipes)
偏好后训练🟢 是(DPO, KTO, ORPO, CPO, SimPO, IPO, …)仅 DPO🔴 否🔴 否🔴 否🟢 是(DPO, SimPO, IPO, XPO)🔴 否(仅低级原语)🟡 DPO, KTO, ORPO(通过 TRL)🟡 仅 DPO
RL 后训练🟢 是(PPO, GRPO, RLOO, …)🟢 是(PPO, REINFORCE++, GRPO, RLOO)🟢 是(PPO, GRPO)

相似文章

保持 Token 流动:16 个开源 RL 库的经验教训

Hugging Face Blog

Hugging Face 发布了对 16 个开源强化学习库的全面分析,研究异步 RL 训练的架构模式,并为 TRL 的异步训练器设计经验教训,以解决生成瓶颈和权重同步挑战。

LeRobot v0.5.0:全面扩展

Hugging Face Blog

LeRobot v0.5.0 是一个重大版本,支持 Unitree G1 人形机器人、新的策略架构(Pi0-FAST VLAs、实时分块)、用于提升 3 倍训练速度的流式视频编码,以及用于从 Hugging Face Hub 加载仿真环境的 EnvHub。