LLM-RLHF-Tuning-with-PPO-and-DPO
从零实现RLHF三阶段训练管线,支持PPO和DPO双算法,配套LoRA参数高效微调,适合深入学习大模型对齐技术
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
从零实现RLHF三阶段训练管线,支持PPO和DPO双算法,配套LoRA参数高效微调,适合深入学习大模型对齐技术
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
当你第一次和一个大语言模型对话时,可能会遇到这样的困惑:模型明明能生成语法正确的句子,但回答却答非所问、逻辑混乱,甚至带有一丝"毒舌"气质。这是因为大多数 LLM 在预训练阶段只学习了"如何续写文本",而非"如何成为合格的助手"。
RLHF(Reinforcement Learning from Human Feedback,人类反馈强化学习) 就是解决这个问题的核心技术。它最早由 OpenAI 在 InstructGPT 论文(2022)中提出,通过引入人类偏好信号,让模型学会"说得好"——不仅答案正确,还要符合人类价值观和表达习惯。
整个 RLHF 流程分为三个阶段:SFT(监督微调) → Reward Model(奖励模型训练) → RL 优化(PPO 或 DPO)。每一阶段的输出都是下一阶段的输入,任何一环出现问题都会影响最终效果。训练一个完整的 RLHF pipeline,在没有现成工具的情况下,需要熟悉分布式训练、PEFT(参数高效微调)、强化学习等多个领域的知识。
今天要介绍的这个开源项目——LLM-RLHF-Tuning-with-PPO-and-DPO,正是为零基础但想深入 RLHF 实践的研究者和工程师量身打造的参考实现。它从零开始手写了 RLHF 各阶段的核心训练代码,注释详尽,适合作为学习材料。
本项目的作者是 GitHub 用户 raghavc,目前积累 191 颗星和 19 个 Fork。虽然 stars 数量不算特别高,但这个项目的价值不在于热度和流量,而在于代码的完整性和可读性——它真正做到了一步一步还原 RLHF 的每个环节,没有任何黑箱封装。
项目支持 LLaMA 和 LLaMA2 两种基础模型,提供了 PPO 和 DPO 两种对齐算法的完整训练脚本。这两种算法的选择背后有着深刻的工程考量:PPO 是 OpenAI 主推的传统方法,理论基础扎实但实现复杂;DPO 则是斯坦福大学 2023 年提出的新范式,将 RL 问题巧妙转化为分类问题,大大降低了训练难度。
作者在 README 中明确表示,项目的主要目的是帮助社区理解 RLHF 的实现过程,因此代码中包含了详细的实现说明文档,欢迎社区讨论和贡献。
RLHF 的第一步是监督微调(Supervised Fine-Tuning, SFT)。在这个阶段,使用人工标注的 instruction-response 数据对预训练模型进行微调,让模型学会"按指令回答"的基本能力。
本项目的 SFT 模块位于 script/sft/ 目录,核心脚本是 run_sft_with_peft.py。它基于 HuggingFace Transformers 框架和 PEFT 库(Parameter-Efficient Fine-Tuning,参数高效微调),使用了 LoRA(Low-Rank Adaptation) 技术来降低微调成本。
LoRA 的核心思想是:冻结预训练模型的原始权重,只在每层 Transformer 中引入两个低秩矩阵 A 和 B,通过训练这两个小矩阵来调整模型行为。这样一来,即使模型参数量达到数十亿,GPU 显存占用也只需原始的全参数微调的几分之一。配置参数中的 lora_rank=128 和 lora_alpha=32 决定了 LoRA 适配器的秩,数值越高表达能力越强,但显存占用也越大。
训练脚本使用了 torchrun(PyTorch 2.0 原生的分布式启动工具),支持单机多卡场景。如果你的机器有多张 GPU,可以通过 --nproc_per_node 参数指定并行进程数,实现数据并行。
SFT 之后的模型已经具备基本的指令跟随能力,但还不够"智能"——它不知道什么样的回答才算"好"。RLHF 的第二步是训练一个奖励模型(Reward Model),让它学会给回答打分。
本项目的 Reward Model 模块位于 script/rm/,核心是 run_rm_with_peft.py。训练数据来自 rm_data/ 目录,其中包含人工标注的偏好数据——同一个问题的两个回答,按优劣顺序排列。
Reward Model 的训练方式很有意思:它本质上是一个二分类器,接收 prompt + response 的拼接序列,输出一个标量奖励分数。训练时,对于同一个 prompt,让模型分别对"被选中的回答"和"被拒绝的回答"打分,通过 Bradley-Terry 模型最大化两者之间的差距。
代码中的关键配置 --clm_loss_weight 1.0 表示同时使用语言模型损失函数,--use_last_reward 则指定只取序列最后一个 token 的隐状态作为奖励值。这些都是 RLHF 训练中的常见工程细节。
这是 RLHF 最核心、也是最复杂的阶段。项目同时支持两种对齐算法:
PPO(Proximal Policy Optimization,近端策略优化):这是强化学习的经典算法,由 OpenAI 在 2017 年提出。PPO 的核心是通过"裁剪(clip)"机制防止策略更新幅度过大,确保训练稳定。InstructGPT 就使用了 PPO 来做最后的对齐优化。
本项目的 PPO 模块位于 script/ppo/,实现了三种不同的模型架构配置:
accelerate 分布式训练,适合多卡场景。accelerate + DeepSpeed ZeRO 优化。PPO 的训练代码在 script/utils/ppo_trainer_with_peft.py 中实现了 PPOModel 类,它将 Actor(策略模型)和 Critic(价值模型)封装在一起。Actor 负责根据 prompt 生成 response,Critic 则评估每个 token 的价值 Advantage,最终 PPO 算法通过裁剪的代理损失函数同时优化两个网络。
DPO(Direct Preference Optimization,直接偏好优化):这是斯坦福大学 2023 年提出的新方法,核心思想是绕过 Reward Model,直接用偏好数据优化策略。DPO 将 RLHF 的三阶段简化为两阶段——不再单独训练 Reward Model,而是把偏好对(chosen, rejected)的对比关系直接编码到损失函数中。
从数学上看,DPO 的目标函数本质上是 RLHF 中 Reward Model 和 PPO 损失的隐式组合。由于不再需要单独运行 PPO roll-out 过程(生成 response),DPO 的实现和调参都更简单,但效果在某些场景下已接近 PPO。
这个项目构建在一个成熟的 ML 工具链之上:
| 依赖包 | 版本 | 作用 |
|---|---|---|
torch | 2.0.1 | 深度学习框架 |
transformers | 4.31.0 | 模型架构(Llama、Llama2) |
peft | 0.4.0 | LoRA/QLoRA 参数高效微调 |
trl | 0.5.0 | 强化学习训练器(DPO 核心依赖) |
accelerate | 0.21.0 | 分布式训练抽象 |
deepspeed | 0.10.0 | ZeRO 显存优化 |
datasets | 2.13.1 | 数据集处理 |
scikit-learn | 1.3.0 | Reward Model 评估指标 |
wandb | 0.15.8 | 训练过程可视化 |
tqdm | 4.65.0 | 进度条 |
值得注意的是,TRL(Transformer Reinforcement Learning)库是这个生态的核心,它由 HuggingFace 团队维护,提供了从 SFT 到 DPO 的完整训练管线。项目使用 trl==0.5.0 表明它参考了较早期的 TRL API 设计。
这个项目不适合零基础用户。要跑通整个训练流程,你需要具备以下条件:
硬件门槛:至少一块显存 ≥24GB 的 NVIDIA GPU(RTX 3090、A100、L40S 等)。如果用 QLoRA 模式,理论上 16GB 显存也可运行,但 batch size 会被大幅压缩。系统内存建议 32GB 以上,硬盘预留 50GB 用于模型权重和数据集缓存。
软件门槛:需要手动安装 CUDA 11.7+ / CUDA 12.1+、cuDNN 8.x、NVIDIA Driver 525+。项目没有提供 Docker 镜像或 conda 环境文件,所有依赖需要自行通过 pip 安装,CUDA 版本的 torch、transformers 与 CPU 版本不能混用。
知识门槛:建议至少了解以下概念之一:LoRA 微调原理、PPO 算法流程、分布式训练基础。没有这些背景知识,直接跑脚本大概率会卡在各种报错上。
适合人群:LLM 研究者、高校 NLP 方向的研究生、想深入理解 RLHF 而不只是调用 API 的工程师。
LLM-RLHF-Tuning-with-PPO-and-DPO/
├── README.md
├── requirements.txt
├── script/
│ ├── sft/ # 监督微调(SFT)
│ │ ├── run_sft.sh
│ │ └── run_sft_with_peft.py
│ ├── rm/ # 奖励模型(Reward Model)
│ │ ├── run_rm.sh
│ │ └── run_rm_with_peft.py
│ ├── ppo/ # PPO 强化学习训练
│ │ ├── run_ppo.sh
│ │ ├── run_ppo_co.sh # 单基座共享 LoRA
│ │ ├── run_ppo_co_multi_adapters.sh # 多 LoRA 适配器
│ │ ├── run_ppo_with_peft.py
│ │ ├── default_config.yaml # accelerate 默认配置
│ │ └── ds_config.yaml # DeepSpeed 配置
│ ├── dpo/ # DPO 直接偏好优化
│ │ ├── run_dpo.sh
│ │ ├── run_dpo_with_peft.py
│ │ └── default_config.yaml
│ └── utils/ # 共享工具模块
│ ├── ppo_trainer_with_peft.py # PPO 训练器(核心)
│ ├── data_collator.py # 数据批处理
│ ├── metrics.py # 评估指标
│ ├── parser_args.py # 命令行参数解析
│ ├── ppo_models.py # Actor/Critic 模型定义
│ ├── trainer.py # 基础训练器
│ └── utils.py # 工具函数(含 prompt 模板)
├── sft_data/ # SFT 训练数据目录
├── rm_data/ # Reward Model 训练数据目录
└── pt_data/ # 预训练(PT)数据目录
最值得关注的文件是 script/utils/ppo_trainer_with_peft.py,其中 PPOPeftTrainer 类继承自 HuggingFace Trainer,封装了完整的 PPO 训练循环。PPOModel 类则将 Actor 和 Critic 包装在一起,方便在前向传播中同时获取 logits(用于生成)和 values(用于 Advantage 估计)。
script/utils/utils.py 中定义了 LLaMA 和 LLaMA2 的 prompt 模板,这些模板决定了模型接收 instruction 的格式。如果你要用自己的数据集,必须确保数据格式与这里的模板一致,否则模型可能完全无法理解输入。
客观来说,这个项目有几个明显的不足:
缺乏持续维护:最后一次更新是 2024 年 5 月,距今已超过一年,TRL 库已更新到 0.9+ 版本,API 变化较大,直接 pip install -r requirements.txt 可能会遇到依赖冲突。
不支持 QLoRA 原生训练:虽然用了 PEFT,但没有集成 bitsandbytes 的 4-bit/8-bit 量化,对于没有 A100 的用户来说门槛偏高。
缺少自动化脚本:SFT → RM → PPO/DPO 的完整流程需要手动按顺序执行,没有提供一键启动脚本,参数调优也不够灵活。
文档以英文为主:代码注释不够详细,中文资料几乎为零,对非英语母语的学习者不够友好。
尽管存在上述局限,LLM-RLHF-Tuning-with-PPO-and-DPO 依然是中文互联网上少数能够完整、清晰地展示 RLHF 全流程的参考实现。对于想要真正理解大模型对齐原理的学习者来说,与其去看 OpenAI/HuggingFace 封装的 API,不如从这些"手写版"代码入手,把每个环节的数学公式对应到代码实现上。
RLHF 是 2023-2024 年大模型能力的核心推动力,ChatGPT、Claude、DeepSeek-R1 的"好脾气"背后都有 RLHF 的影子。掌握这项技术,意味着你不仅会用别人的模型,还能训练出自己的"听话"模型——这才是真正有壁垒的能力。