
在大型语言模型(LLM)的发展历程中,我们见证了模型从简单的文本生成工具,逐渐演变为能够理解复杂指令、进行多轮对话、甚至展示创造性思维的智能系统。然而,这一进化并非仅仅依靠模型规模的增大和数据量的增加,更重要的是训练方法的创新。其中,人类反馈强化学习(Reinforcement Learning from Human Feedback, RLHF)作为一种革命性的训练范式,在2022年随着ChatGPT的问世而广受关注,并在随后的GPT-4、Claude、Gemini等先进模型中得到广泛应用。
RLHF通过将人类反馈融入强化学习流程,成功地解决了AI对齐问题,使得语言模型能够更好地理解人类意图,生成符合人类价值观的内容。本文将深入探讨RLHF的基本原理、实现方法、应用案例以及2025年的最新研究进展,为读者提供全面而深入的RLHF知识体系。
RLHF的概念最早可以追溯到2017年,当时OpenAI在论文《Deep Reinforcement Learning from Human Preferences》中首次提出了这一理念。然而,RLHF真正进入大众视野并展现其强大潜力,是在2022年底ChatGPT发布之后。
从2017年的概念提出到2025年的广泛应用,RLHF经历了以下几个关键发展阶段:
随着语言模型规模的不断扩大,我们面临着越来越严重的AI对齐问题。传统的监督微调方法虽然能够提高模型在特定任务上的性能,但存在以下局限性:
RLHF通过引入人类反馈,有效地解决了这些问题,使得模型能够:
本文将系统地介绍RLHF的理论基础、实现方法和应用案例,并探讨其未来发展趋势。主要内容包括:
通过本文的学习,读者将能够全面理解RLHF技术,并能够在实际项目中应用这一技术来训练和优化语言模型。
RLHF在AI对齐中的位置
预训练模型 → 监督微调(SFT) → RLHF → 人类偏好对齐的模型要理解RLHF,首先需要了解强化学习(Reinforcement Learning, RL)的基本概念。强化学习是一种通过与环境互动来学习最优行为的机器学习范式。
强化学习系统通常包含以下核心组件:
强化学习的目标是学习一个最优策略π*,使得智能体在与环境交互过程中获得的累积奖励最大化:
其中:
在强化学习中,常用的优化方法包括基于价值函数的方法(如Q-learning)和基于策略梯度的方法。对于大语言模型的RLHF,策略梯度方法更为常用,因为它能够直接优化策略,而不需要显式地学习价值函数。
策略梯度方法的核心思想是通过调整策略参数,使得累积奖励的期望增加。其更新公式为:
其中:
在传统强化学习中,奖励信号通常由环境直接提供,且定义明确。然而,在语言生成等复杂任务中,奖励信号难以直接定义,因为"好"的输出往往具有主观性和上下文依赖性。
在RLHF中,常见的人类反馈类型包括:
与自动奖励信号相比,人类反馈具有以下优势:
RLHF可以看作是传统强化学习的一个扩展,其核心区别在于奖励信号的来源。在RLHF中,我们首先训练一个奖励模型(Reward Model, RM)来预测人类的偏好,然后使用这个奖励模型来指导策略的优化。
奖励模型通常通过人类比较数据进行训练。假设我们有两个模型输出y1和y2,人类评估者认为y1比y2好,我们希望奖励模型fθ满足:
其中p^*是人类认为y1比y2好的概率。为了训练奖励模型,我们通常使用交叉熵损失:
其中σ是sigmoid函数。
在获得奖励模型后,我们使用策略梯度方法优化语言模型。目标函数为:
其中φ是语言模型的参数。使用PPO(近端策略优化)算法,我们可以通过以下方式更新策略:
其中:
RLHF与其他训练方法相比,具有独特的优势和适用场景:
训练方法 | 数据需求 | 对齐能力 | 适用场景 | 计算复杂度 |
|---|---|---|---|---|
监督微调(SFT) | 大量标注数据 | 有限 | 明确任务 | 低 |
模仿学习 | 专家示范 | 中等 | 特定行为学习 | 中低 |
RLHF | 人类反馈数据 | 强 | 复杂任务,价值对齐 | 高 |
DPO | 人类偏好数据 | 强 | 价值对齐,计算效率 | 中高 |
RLHF的主要优势在于能够解决复杂的对齐问题,使得模型能够更好地理解和遵循人类意图。然而,RLHF也存在计算复杂度高、依赖高质量人类反馈等挑战。
RLHF的理论框架
人类评估 → 偏好数据 → 奖励模型 → 强化学习优化 → 对齐模型RLHF是一个多阶段的复杂过程,通常包括以下四个主要步骤:
选择合适的预训练模型是RLHF成功的基础。预训练模型的选择应考虑以下因素:
不同的模型架构(如Transformer、GPT、LLaMA等)在RLHF中的表现可能有所不同。模型规模(参数量)也是一个重要考量因素,更大的模型通常具有更强的学习能力,但也需要更多的计算资源。
预训练数据的质量对最终模型性能有重要影响。优质的预训练数据应具有多样性、准确性和代表性。
在进行RLHF之前,通常需要对预训练模型进行以下准备:
监督微调是RLHF流程的第一步,其目标是让模型学习基本的任务格式和指令遵循能力。
SFT数据集通常包含高质量的指令-响应对,这些数据可以来自:
SFT的实现相对直接,主要包括以下步骤:
以下是使用HuggingFace Transformers库实现SFT的示例代码:
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
from datasets import load_dataset
def sft_training(model_name, dataset_path, output_dir):
# 加载模型和分词器
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 加载数据集
dataset = load_dataset("json", data_files=dataset_path)
# 数据预处理函数
def preprocess_function(examples):
texts = [f"### 指令:\n{instruction}\n### 回答:\n{output}"
for instruction, output in zip(examples["instruction"], examples["output"])]
return tokenizer(texts, truncation=True, max_length=1024)
# 预处理数据集
tokenized_dataset = dataset.map(preprocess_function, batched=True)
# 设置训练参数
training_args = TrainingArguments(
output_dir=output_dir,
learning_rate=2e-5,
per_device_train_batch_size=4,
per_device_eval_batch_size=4,
num_train_epochs=3,
weight_decay=0.01,
evaluation_strategy="steps",
save_steps=500,
eval_steps=500,
)
# 创建训练器
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["train"],
eval_dataset=tokenized_dataset["test"] if "test" in tokenized_dataset else None,
tokenizer=tokenizer,
)
# 开始训练
trainer.train()
# 保存模型
trainer.save_model(output_dir)
return model奖励模型是RLHF的核心组件,它负责将人类偏好转换为可用于强化学习的数值奖励信号。
收集人类偏好数据是训练奖励模型的关键步骤。常见的数据收集方法包括:
数据收集过程中,需要考虑以下因素:
奖励模型通常采用与基础语言模型相似的架构,但最后一层被替换为输出标量奖励的层。常见的奖励模型架构包括:
训练奖励模型的常用方法是基于比较学习的方法。给定一个输入x和两个输出y1、y2,如果人类评估者认为y1比y2好,我们希望奖励模型满足f(x,y1) > f(x,y2)。
以下是训练奖励模型的示例代码:
from transformers import AutoModelForSequenceClassification, AutoTokenizer, TrainingArguments, Trainer
from datasets import load_dataset
import torch
def train_reward_model(base_model_name, preference_data_path, output_dir):
# 加载模型和分词器
model = AutoModelForSequenceClassification.from_pretrained(
base_model_name,
num_labels=1, # 输出单个标量奖励
problem_type="regression"
)
tokenizer = AutoTokenizer.from_pretrained(base_model_name)
# 加载偏好数据集
dataset = load_dataset("json", data_files=preference_data_path)
# 数据预处理函数
def preprocess_function(examples):
# 假设数据格式为{"prompt": "...", "chosen": "...", "rejected": "..."}
chosen_inputs = tokenizer(
[f"{prompt}{chosen}" for prompt, chosen in zip(examples["prompt"], examples["chosen"])],
truncation=True,
max_length=1024
)
rejected_inputs = tokenizer(
[f"{prompt}{rejected}" for prompt, rejected in zip(examples["prompt"], examples["rejected"])],
truncation=True,
max_length=1024
)
# 合并数据
inputs = {}
for key in chosen_inputs:
inputs[f"{key}_chosen"] = chosen_inputs[key]
inputs[f"{key}_rejected"] = rejected_inputs[key]
return inputs
# 预处理数据集
tokenized_dataset = dataset.map(preprocess_function, batched=True)
# 定义对比损失函数
class RewardModelTrainer(Trainer):
def compute_loss(self, model, inputs, return_outputs=False):
# 提取chosen和rejected数据
chosen_input_ids = inputs.pop("input_ids_chosen")
chosen_attention_mask = inputs.pop("attention_mask_chosen")
rejected_input_ids = inputs.pop("input_ids_rejected")
rejected_attention_mask = inputs.pop("attention_mask_rejected")
# 获取chosen和rejected的奖励
chosen_outputs = model(
input_ids=chosen_input_ids,
attention_mask=chosen_attention_mask
)
chosen_rewards = chosen_outputs.logits.squeeze(-1)
rejected_outputs = model(
input_ids=rejected_input_ids,
attention_mask=rejected_attention_mask
)
rejected_rewards = rejected_outputs.logits.squeeze(-1)
# 计算对比损失
# 我们希望chosen_rewards > rejected_rewards
loss = -torch.nn.functional.logsigmoid(chosen_rewards - rejected_rewards).mean()
return (loss, chosen_outputs) if return_outputs else loss
# 设置训练参数
training_args = TrainingArguments(
output_dir=output_dir,
learning_rate=1e-5,
per_device_train_batch_size=4,
per_device_eval_batch_size=4,
num_train_epochs=3,
weight_decay=0.01,
evaluation_strategy="steps",
save_steps=500,
eval_steps=500,
)
# 创建自定义训练器
trainer = RewardModelTrainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["train"],
eval_dataset=tokenized_dataset["test"] if "test" in tokenized_dataset else None,
tokenizer=tokenizer,
)
# 开始训练
trainer.train()
# 保存模型
trainer.save_model(output_dir)
return model在获得奖励模型后,我们使用强化学习算法(通常是PPO)对SFT模型进行进一步优化,使其输出更符合人类偏好。
近端策略优化(Proximal Policy Optimization, PPO)是一种流行的策略梯度算法,它通过限制策略更新的幅度,确保训练的稳定性。PPO的目标函数为:
其中:
是概率比率
是优势估计
是裁剪参数(通常设置为0.1或0.2)
在RLHF中应用PPO时,需要考虑以下特殊因素:
以下是在RLHF中应用PPO的示例代码:
from transformers import AutoModelForCausalLM, AutoTokenizer
from trl import PPOTrainer, PPOConfig
from peft import LoraConfig, get_peft_model
import torch
def rlhf_ppo_training(sft_model_path, reward_model_path, dataset_path, output_dir):
# 加载SFT模型和分词器
model = AutoModelForCausalLM.from_pretrained(sft_model_path)
tokenizer = AutoTokenizer.from_pretrained(sft_model_path)
# 加载奖励模型
reward_model = AutoModelForSequenceClassification.from_pretrained(reward_model_path, num_labels=1)
# 可选:使用LoRA进行参数高效微调
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
# 加载数据集
dataset = load_dataset("json", data_files=dataset_path)
# 设置PPO配置
ppo_config = PPOConfig(
model_name=sft_model_path,
learning_rate=1e-5,
batch_size=4,
mini_batch_size=2,
gradient_accumulation_steps=4,
optimize_cuda_cache=True,
early_stopping=False,
target_kl=0.1,
kl_penalty="kl",
seed=42,
)
# 定义奖励函数
def reward_fn(samples, outputs):
# 将样本和输出格式化为奖励模型的输入
texts = [f"{sample['prompt']}{output['response']}" for sample, output in zip(samples, outputs)]
inputs = tokenizer(texts, padding=True, truncation=True, max_length=1024, return_tensors="pt")
# 移动到正确的设备
inputs = {k: v.to(reward_model.device) for k, v in inputs.items()}
# 获取奖励
with torch.no_grad():
rewards = reward_model(**inputs).logits.squeeze(-1)
return rewards
# 创建PPO训练器
ppo_trainer = PPOTrainer(
model=model,
ref_model=None, # 使用当前模型作为参考
tokenizer=tokenizer,
args=ppo_config,
dataset=dataset["train"],
data_collator=lambda x: x,
tokenizer_kwargs={"truncation": True, "max_length": 1024},
)
# 开始PPO训练
for epoch in range(3):
for batch in ppo_trainer.dataloader:
# 生成响应
response_tensors = []
for prompt in batch:
input_ids = tokenizer(prompt["prompt"], return_tensors="pt").input_ids.to(model.device)
response = model.generate(
input_ids=input_ids,
max_new_tokens=128,
temperature=0.7,
do_sample=True,
)
response_tensors.append(response.squeeze())
# 计算奖励
texts = [tokenizer.decode(response) for response in response_tensors]
rewards = reward_fn(batch, [{"response": text} for text in texts])
# 执行PPO步骤
stats = ppo_trainer.step(batch, response_tensors, rewards)
ppo_trainer.log_stats(stats, batch, rewards)
# 保存模型
ppo_trainer.save_pretrained(output_dir)
return model将以上四个步骤整合起来,RLHF的完整工作流如下:
预训练模型 → 监督微调(SFT) → 生成候选输出 → 人类偏好标注 → 奖励模型训练 → PPO优化 → 对齐模型在实际应用中,这一流程可能需要多次迭代,以不断改进模型性能。此外,还需要监控训练过程中的各种指标,如奖励值、KL散度、模型输出质量等,以确保训练的稳定性和有效性。
随着RLHF技术的广泛应用,各种开源框架和工具也随之发展起来,使得RLHF的实现变得更加便捷。以下是几个主流框架的实践指南:
TRL(Transformer Reinforcement Learning)是HuggingFace生态系统中的一个库,专为Transformer模型的强化学习设计。它提供了完整的RLHF工作流支持。
# 安装TRL库及其依赖
pip install trl transformers accelerate peft datasets bitsandbytesfrom transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, DataCollatorForSeq2Seq
from trl import SFTTrainer, RewardTrainer, PPOTrainer, PPOConfig
from trl.core import LengthSampler
from datasets import load_dataset
import torch
def full_rlhf_pipeline(base_model_name, sft_data_path, preference_data_path, output_dir):
# 步骤1: 监督微调(SFT)
print("Step 1: 开始监督微调...")
model = AutoModelForCausalLM.from_pretrained(base_model_name, torch_dtype=torch.float16, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(base_model_name)
# 加载SFT数据集
sft_dataset = load_dataset("json", data_files=sft_data_path)
# 定义格式化函数
def formatting_prompts_func(example):
output_texts = []
for i in range(len(example["instruction"])):
text = f"### 指令:\n{example['instruction'][i]}\n"
if example["input"][i]:
text += f"### 输入:\n{example['input'][i]}\n"
text += f"### 回答:\n{example['output'][i]}"
output_texts.append(text)
return output_texts
# 设置SFT训练参数
sft_args = TrainingArguments(
output_dir=f"{output_dir}/sft",
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-5,
logging_steps=10,
max_steps=500,
save_steps=100,
bf16=True,
)
# 创建SFT训练器
sft_trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
args=sft_args,
train_dataset=sft_dataset["train"],
formatting_func=formatting_prompts_func,
packing=False,
)
# 执行SFT
sft_trainer.train()
sft_trainer.save_model()
# 步骤2: 奖励模型训练
print("Step 2: 开始奖励模型训练...")
# 加载偏好数据集
preference_dataset = load_dataset("json", data_files=preference_data_path)
# 定义奖励模型训练器
class PairwiseRewardTrainer(RewardTrainer):
def compute_loss(self, model, inputs, return_outputs=False):
# 提取chosen和rejected数据
chosen_input_ids = inputs.pop("input_ids_chosen")
chosen_attention_mask = inputs.pop("attention_mask_chosen")
rejected_input_ids = inputs.pop("input_ids_rejected")
rejected_attention_mask = inputs.pop("attention_mask_rejected")
# 获取rewards
chosen_rewards = model(input_ids=chosen_input_ids, attention_mask=chosen_attention_mask).logits.squeeze(-1)
rejected_rewards = model(input_ids=rejected_input_ids, attention_mask=rejected_attention_mask).logits.squeeze(-1)
# 计算对比损失
loss = -torch.nn.functional.logsigmoid(chosen_rewards - rejected_rewards).mean()
return (loss, {"chosen_rewards": chosen_rewards, "rejected_rewards": rejected_rewards}) if return_outputs else loss
# 设置奖励模型训练参数
rm_args = TrainingArguments(
output_dir=f"{output_dir}/reward_model",
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=1e-5,
logging_steps=10,
max_steps=500,
save_steps=100,
bf16=True,
)
# 数据预处理函数
def preprocess_preference_data(examples):
# 假设数据格式为{"prompt": "...", "chosen": "...", "rejected": "..."}
chosen_inputs = tokenizer([f"{p}{c}" for p, c in zip(examples["prompt"], examples["chosen"])])
rejected_inputs = tokenizer([f"{p}{r}" for p, r in zip(examples["prompt"], examples["rejected"])])
# 合并数据
inputs = {}
for key in chosen_inputs:
inputs[f"{key}_chosen"] = chosen_inputs[key]
inputs[f"{key}_rejected"] = rejected_inputs[key]
return inputs
# 预处理偏好数据集
processed_preference_data = preference_dataset.map(preprocess_preference_data, batched=True)
# 创建奖励模型
reward_model = AutoModelForSequenceClassification.from_pretrained(
f"{output_dir}/sft",
num_labels=1,
torch_dtype=torch.float16,
device_map="auto"
)
# 创建奖励模型训练器
rm_trainer = PairwiseRewardTrainer(
model=reward_model,
tokenizer=tokenizer,
args=rm_args,
train_dataset=processed_preference_data["train"],
)
# 执行奖励模型训练
rm_trainer.train()
rm_trainer.save_model()
# 步骤3: PPO优化
print("Step 3: 开始PPO优化...")
# 加载SFT模型进行PPO
ppo_model = AutoModelForCausalLM.from_pretrained(
f"{output_dir}/sft",
torch_dtype=torch.float16,
device_map="auto"
)
# 加载奖励模型
reward_model = AutoModelForSequenceClassification.from_pretrained(
f"{output_dir}/reward_model",
torch_dtype=torch.float16,
device_map="auto"
)
# 设置PPO配置
ppo_config = PPOConfig(
model_name=f"{output_dir}/sft",
learning_rate=5e-6,
batch_size=4,
mini_batch_size=1,
gradient_accumulation_steps=4,
optimize_cuda_cache=True,
early_stopping=False,
target_kl=0.1,
kl_penalty="kl",
seed=42,
)
# 定义奖励函数
def reward_fn(samples, outputs):
texts = [f"{sample['text']}{output['response']}" for sample, output in zip(samples, outputs)]
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt").to(reward_model.device)
with torch.no_grad():
rewards = reward_model(**inputs).logits.squeeze(-1)
return rewards
# 创建PPO训练器
ppo_trainer = PPOTrainer(
model=ppo_model,
ref_model=None,
tokenizer=tokenizer,
args=ppo_config,
dataset=processed_preference_data["train"].select(range(100)), # 使用一小部分数据进行演示
)
# 定义生成响应的函数
def generate_responses(prompts, max_new_tokens=128):
responses = []
for prompt in prompts:
input_ids = tokenizer(prompt["text"], return_tensors="pt").input_ids.to(ppo_model.device)
response = ppo_model.generate(
input_ids=input_ids,
max_new_tokens=max_new_tokens,
temperature=0.7,
do_sample=True,
)
responses.append(response.squeeze())
return responses
# 执行PPO训练
for epoch in range(3):
for batch in ppo_trainer.dataloader:
# 生成响应
responses = generate_responses(batch)
# 计算奖励
rewards = reward_fn(batch, [{"response": tokenizer.decode(r)} for r in responses])
# 执行PPO步骤
stats = ppo_trainer.step(batch, responses, rewards)
ppo_trainer.log_stats(stats, batch, rewards)
print(f"Epoch {epoch}, Stats: {stats}")
# 保存最终模型
ppo_trainer.save_pretrained(f"{output_dir}/ppo_model")
print("RLHF流程完成!")
return ppo_model
# 使用示例
final_model = full_rlhf_pipeline(
base_model_name="meta-llama/Llama-2-7b-hf",
sft_data_path="data/alpaca_data.json",
preference_data_path="data/preference_data.json",
output_dir="./rlhf_output"
)LLaMA Factory是一个功能全面的大模型微调框架,支持多种模型架构和微调方法,包括RLHF。
# 安装LLaMA Factory
pip install llamafactoryLLaMA Factory使用配置文件来定义训练过程。以下是RLHF流程的配置文件示例:
1. SFT配置文件 (sft_config.yaml)
# 模型配置
model_name_or_path: meta-llama/Llama-2-7b-hf
# 数据集配置
dataset: alpaca_gpt4_en
dataset_dir: data/
template: llama2
# 训练配置
train_on_inputs: false
sequence_length: 1024
finetuning_type: lora
lora_target: q_proj,v_proj
# 优化器配置
lr_scheduler_type: cosine
learning_rate: 2e-5
epoch: 3
batch_size: 4
gradient_accumulation_steps: 4
# 输出配置
output_dir: ./sft_model
logging_steps: 102. 奖励模型配置文件 (rm_config.yaml)
# 模型配置
model_name_or_path: ./sft_model
# 数据集配置
dataset: hh_rlhf
dataset_dir: data/
template: llama2
# 训练配置
train_on_inputs: false
sequence_length: 1024
finetuning_type: lora
lora_target: q_proj,v_proj
# 优化器配置
lr_scheduler_type: cosine
learning_rate: 1e-5
epoch: 3
batch_size: 4
gradient_accumulation_steps: 4
# 输出配置
output_dir: ./reward_model
logging_steps: 103. PPO配置文件 (ppo_config.yaml)
# 模型配置
model_name_or_path: ./sft_model
reward_model: ./reward_model
# 数据集配置
dataset: alpaca_gpt4_en
dataset_dir: data/
template: llama2
# 训练配置
train_on_inputs: false
sequence_length: 1024
finetuning_type: lora
lora_target: q_proj,v_proj
# PPO配置
ppo_epochs: 4
chunk_size: 128
target_kl: 0.1
reward_baseline: true
# 优化器配置
lr_scheduler_type: cosine
learning_rate: 5e-6
batch_size: 4
gradient_accumulation_steps: 4
# 输出配置
output_dir: ./ppo_model
logging_steps: 10使用命令行工具执行RLHF流程:
# 步骤1: 执行SFT
llamafactory-cli train sft_config.yaml
# 步骤2: 训练奖励模型
llamafactory-cli train rm_config.yaml
# 步骤3: 执行PPO优化
llamafactory-cli train ppo_config.yamlEasyRLHF是一个专注于简化RLHF实现的轻量级框架,特别适合初学者和快速原型开发。
# 安装EasyRLHF
pip install easyrlhffrom easyrlhf import SFTTrainer, RewardModelTrainer, PPOTrainer
from easyrlhf.models import AutoModelForCausalLM, AutoTokenizer, AutoModelForScore
from easyrlhf.datasets import load_dataset
def easy_rlhf_example():
# 加载模型和分词器
model_name = "meta-llama/Llama-2-7b-hf"
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 步骤1: 监督微调
print("Step 1: 执行监督微调...")
sft_model = AutoModelForCausalLM.from_pretrained(model_name)
# 加载SFT数据集
sft_dataset = load_dataset("json", data_files="data/alpaca_data.json")
# 创建SFT训练器
sft_trainer = SFTTrainer(
model=sft_model,
tokenizer=tokenizer,
dataset=sft_dataset["train"],
instruction_key="instruction",
input_key="input",
output_key="output",
batch_size=4,
learning_rate=2e-5,
num_epochs=3,
output_dir="./sft_model"
)
# 执行SFT
sft_trainer.train()
# 步骤2: 训练奖励模型
print("Step 2: 训练奖励模型...")
# 加载偏好数据集
preference_dataset = load_dataset("json", data_files="data/preference_data.json")
# 创建奖励模型
reward_model = AutoModelForScore.from_pretrained(
model_name,
score_type="logit_bias"
)
# 创建奖励模型训练器
rm_trainer = RewardModelTrainer(
model=reward_model,
tokenizer=tokenizer,
dataset=preference_dataset["train"],
prompt_key="prompt",
chosen_key="chosen",
rejected_key="rejected",
batch_size=4,
learning_rate=1e-5,
num_epochs=3,
output_dir="./reward_model"
)
# 执行奖励模型训练
rm_trainer.train()
# 步骤3: PPO优化
print("Step 3: 执行PPO优化...")
# 加载SFT模型进行PPO
ppo_model = AutoModelForCausalLM.from_pretrained("./sft_model")
# 加载奖励模型
reward_model = AutoModelForScore.from_pretrained("./reward_model")
# 创建PPO训练器
ppo_trainer = PPOTrainer(
model=ppo_model,
tokenizer=tokenizer,
reward_model=reward_model,
dataset=sft_dataset["train"].select(range(100)), # 使用一小部分数据
prompt_key="instruction",
input_key="input",
batch_size=4,
learning_rate=5e-6,
ppo_epochs=4,
target_kl=0.1,
output_dir="./ppo_model"
)
# 执行PPO训练
ppo_trainer.train()
print("RLHF流程完成!")
return ppo_model
# 使用示例
final_model = easy_rlhf_example()不同的RLHF框架各有优势,适合不同的应用场景:
框架 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
TRL | 与HuggingFace生态完美集成,功能全面 | 资源消耗较大 | 研究和生产环境 |
LLaMA Factory | 支持多种模型,配置灵活,功能丰富 | 配置相对复杂 | 复杂项目和多模型场景 |
EasyRLHF | 使用简单,上手快,文档友好 | 功能相对有限 | 原型开发和学习 |
选择框架时,应考虑以下因素:
对于大多数应用场景,TRL和LLaMA Factory是较好的选择,它们提供了完整的功能支持和活跃的社区维护。而对于初学者或快速原型开发,可以考虑使用EasyRLHF。