第二十八章 | 2024年更新

强化学习与RLHF

从马尔可夫决策到大语言模型的人类反馈优化

强化学习 RLHF PPO DPO

学习目标

  • 理解强化学习的基本概念:智能体、环境、奖励、策略
  • 掌握Q-Learning、策略梯度等核心算法原理
  • 了解深度强化学习的发展与应用
  • 深入理解RLHF的完整训练流程
  • 掌握奖励模型的训练方法
  • 了解PPO在大语言模型中的具体应用
  • 对比DPO与RLHF的优缺点
  • 能够使用TRL库进行RLHF训练实践

前置知识

  • 机器学习基础概念
  • 深度学习基础(神经网络、反向传播)
  • 大语言模型基础概念
  • 监督学习的基本流程
强化学习与RLHF训练流程图
图28-1 强化学习与RLHF:智能体-环境交互循环及人类反馈优化流程

28.1 强化学习基础概念

强化学习(Reinforcement Learning, RL)是机器学习的一个重要分支,它通过让智能体(Agent)在环境(Environment)中采取行动,根据获得的奖励(Reward)来学习最优策略。与监督学习不同,强化学习没有明确的标签,而是通过试错来学习。

强化学习基本框架

智能体 (Agent)
学习决策
状态 (s)

动作 (a)
环境 (Environment)
执行并反馈

马尔可夫决策过程(MDP)

强化学习问题通常被形式化为马尔可夫决策过程(Markov Decision Process, MDP),它由五元组 $(S, A, P, R, \gamma)$ 定义:

MDP五元组

状态空间 S:所有可能状态的集合

动作空间 A:所有可能动作的集合

转移概率 P:在状态 s 采取动作 a 后转移到状态 s' 的概率

奖励函数 R:在状态 s 采取动作 a 获得的即时奖励

折扣因子 γ:介于0到1之间,决定未来奖励的重要性

核心概念

  • 策略(Policy):从状态到动作的映射,表示为 π(a|s)
  • 价值函数(Value Function):从某个状态开始的期望累积奖励
  • 动作价值函数(Q-Function):在某个状态采取某个动作后的期望累积奖励
  • 回报(Return):从当前时刻开始的累积折扣奖励:$G_t = \sum_{k=0}^{\infty} \gamma^k r_{t+k}$
强化学习与监督学习的区别

监督学习:有明确的标签,目标是最小化预测误差

强化学习:没有明确标签,目标是最大化长期累积奖励

28.2 核心算法:Q-Learning与策略梯度

强化学习算法主要分为两大类:基于价值的方法和基于策略的方法。Q-Learning是典型的基于价值的方法,而策略梯度则是基于策略的方法的代表。

Q-Learning算法

Q-Learning是一种无模型的强化学习算法,它通过学习一个Q值函数来找到最优策略。Q-Learning的核心思想是:在状态 s 采取动作 a 的价值等于即时奖励加上折扣后的下一个状态的最大Q值。

Python Q-Learning算法实现
import numpy as np
import random
from collections import defaultdict

class QLearningAgent:
    """Q-Learning智能体"""
    
    def __init__(self, state_size, action_size, learning_rate=0.1, 
                 discount_factor=0.99, epsilon=0.1):
        self.state_size = state_size
        self.action_size = action_size
        self.lr = learning_rate
        self.gamma = discount_factor
        self.epsilon = epsilon
        
        # 初始化Q表
        self.q_table = np.zeros((state_size, action_size))
    
    def get_action(self, state):
        """ε-贪婪策略选择动作"""
        if random.random() < self.epsilon:
            # 探索:随机选择动作
            return random.randint(0, self.action_size - 1)
        else:
            # 利用:选择Q值最大的动作
            return np.argmax(self.q_table[state])
    
    def update(self, state, action, reward, next_state, done):
        """更新Q值"""
        if done:
            target = reward
        else:
            target = reward + self.gamma * np.max(self.q_table[next_state])
        
        # Q-Learning更新公式
        self.q_table[state][action] += self.lr * (target - self.q_table[state][action])
    
    def train(self, env, episodes=1000):
        """训练智能体"""
        rewards_per_episode = []
        
        for episode in range(episodes):
            state = env.reset()
            total_reward = 0
            done = False
            
            while not done:
                action = self.get_action(state)
                next_state, reward, done, _ = env.step(action)
                
                self.update(state, action, reward, next_state, done)
                
                state = next_state
                total_reward += reward
            
            rewards_per_episode.append(total_reward)
            
            # 每100个episode打印一次
            if (episode + 1) % 100 == 0:
                avg_reward = np.mean(rewards_per_episode[-100:])
                print(f"Episode {episode + 1}, Average Reward: {avg_reward:.2f}")
        
        return rewards_per_episode

# 示例使用
# env = gym.make('FrozenLake-v1')
# agent = QLearningAgent(state_size=16, action_size=4)
# rewards = agent.train(env, episodes=5000)
print("Q-Learning算法示例代码")

策略梯度方法

策略梯度方法直接优化策略函数,通过梯度上升来最大化期望回报。与Q-Learning不同,策略梯度方法可以处理连续动作空间,并且能够学习随机策略。

Python 策略梯度核心思想
import torch
import torch.nn as nn
import torch.optim as optim
from torch.distributions import Categorical

class PolicyNetwork(nn.Module):
    """策略网络:输入状态,输出动作概率分布"""
    
    def __init__(self, state_size, action_size, hidden_size=64):
        super(PolicyNetwork, self).__init__()
        self.network = nn.Sequential(
            nn.Linear(state_size, hidden_size),
            nn.ReLU(),
            nn.Linear(hidden_size, hidden_size),
            nn.ReLU(),
            nn.Linear(hidden_size, action_size),
            nn.Softmax(dim=-1)
        )
    
    def forward(self, state):
        return self.network(state)

class PolicyGradientAgent:
    """策略梯度智能体"""
    
    def __init__(self, state_size, action_size, lr=0.001):
        self.policy = PolicyNetwork(state_size, action_size)
        self.optimizer = optim.Adam(self.policy.parameters(), lr=lr)
        self.gamma = 0.99
        
        # 存储轨迹
        self.states = []
        self.actions = []
        self.rewards = []
    
    def get_action(self, state):
        """根据策略网络选择动作"""
        state_tensor = torch.FloatTensor(state).unsqueeze(0)
        action_probs = self.policy(state_tensor)
        
        # 从概率分布中采样
        dist = Categorical(action_probs)
        action = dist.sample()
        
        # 记录状态和动作
        self.states.append(state_tensor)
        self.actions.append(action)
        
        return action.item()
    
    def store_reward(self, reward):
        """存储奖励"""
        self.rewards.append(reward)
    
    def update(self):
        """使用策略梯度更新网络"""
        # 计算折扣回报
        returns = []
        G = 0
        for reward in reversed(self.rewards):
            G = reward + self.gamma * G
            returns.insert(0, G)
        
        returns = torch.FloatTensor(returns)
        
        # 标准化回报(减少方差)
        if len(returns) > 1:
            returns = (returns - returns.mean()) / (returns.std() + 1e-8)
        
        # 计算策略梯度损失
        policy_loss = []
        for log_prob, G in zip(
            [torch.log(prob) for prob in self.policy(torch.cat(self.states)).gather(1, torch.stack(self.actions).unsqueeze(1)).squeeze()],
            returns
        ):
            policy_loss.append(-log_prob * G)
        
        policy_loss = torch.stack(policy_loss).sum()
        
        # 更新网络
        self.optimizer.zero_grad()
        policy_loss.backward()
        self.optimizer.step()
        
        # 清空轨迹
        self.states = []
        self.actions = []
        self.rewards = []
        
        return policy_loss.item()

print("策略梯度算法示例代码")
注意事项

策略梯度方法的方差通常很大,因此需要使用各种方差减少技术,如基线(baseline)、优势函数(advantage function)等。

算法对比

特性 Q-Learning 策略梯度
方法类型 基于价值 基于策略
动作空间 离散 离散/连续
收敛性 需要满足某些条件 局部最优
样本效率 较低 较高

28.3 深度强化学习

深度强化学习(Deep Reinforcement Learning, Deep RL)是将深度学习与强化学习相结合的研究领域。它使用深度神经网络来近似价值函数或策略函数,从而能够处理高维状态空间的问题。

DQN

深度Q网络

2013-2015

A3C

异步优势Actor-Critic

2016

PPO

近端策略优化

2017

SAC

软演员-评论家

2018

DQN(深度Q网络)

DQN是深度强化学习的里程碑工作,它使用深度神经网络来近似Q值函数,并引入了经验回放(Experience Replay)和目标网络(Target Network)来稳定训练。

DQN的关键创新

经验回放:存储历史经验,随机采样进行训练,打破数据相关性

目标网络:使用独立的网络计算目标值,减少训练不稳定

Actor-Critic方法

Actor-Critic方法结合了基于价值和基于策略的方法,Actor负责选择动作,Critic负责评估动作的价值。

Actor-Critic架构

Actor:策略网络,输入状态,输出动作分布

Critic:价值网络,输入状态(或状态-动作对),输出价值估计

优势:Actor的梯度由Critic提供,减少了方差

28.4 RLHF详解

RLHF(Reinforcement Learning from Human Feedback,基于人类反馈的强化学习)是近年来大语言模型训练中的重要技术。它通过人类的偏好反馈来优化模型,使其生成的内容更符合人类的期望和价值观。

RLHF训练流程

1. 收集数据
人类标注偏好对
2. 训练奖励模型
学习人类偏好
3. PPO优化
用奖励模型优化策略
4. 评估与迭代
持续改进模型

为什么需要RLHF?

传统的监督学习方法存在以下问题:

  • 标注不一致:不同标注者可能给出不同的标签
  • 难以定义"好"的回答:主观性强,难以用简单标签表示
  • 安全和对齐问题:模型可能生成有害或偏见内容

RLHF通过以下方式解决这些问题:

  • 比较学习:让人类比较两个回答的好坏,比直接打分更容易
  • 间接优化:通过奖励模型间接优化人类偏好
  • 灵活调整:可以根据不同场景调整偏好方向
RLHF的挑战

标注成本高:需要大量人类标注数据

奖励模型偏差:如果标注数据有偏差,奖励模型也会学习到偏差

训练不稳定:PPO训练可能不稳定,需要仔细调参

28.5 奖励模型训练

奖励模型(Reward Model)是RLHF的核心组件之一。它的作用是学习人类的偏好,将人类的主观判断转化为可以用于优化的数值信号。

奖励模型的输入输出

  • 输入:一个问题(prompt)和一个回答(response)
  • 输出:一个标量分数,表示这个回答的质量

训练数据格式

奖励模型的训练数据通常由偏好对(preference pairs)组成:

偏好对格式

每个样本包含:问题 q、回答 r₁、回答 r₂、偏好标签 y

其中 y = 1 表示 r₁ 优于 r₂,y = 0 表示 r₂ 优于 r₁

训练目标

奖励模型通常使用 Bradley-Terry 模型进行训练,目标是最大化正确偏好对的似然概率:

Python 奖励模型训练示例
import torch
import torch.nn as nn
from transformers import AutoModelForSequenceClassification, AutoTokenizer

class RewardModel(nn.Module):
    """奖励模型:基于预训练语言模型"""
    
    def __init__(self, model_name="gpt2", hidden_size=768):
        super(RewardModel, self).__init__()
        self.reward_model = AutoModelForSequenceClassification.from_pretrained(
            model_name, num_labels=1
        )
        self.tokenizer = AutoTokenizer.from_pretrained(model_name)
        if self.tokenizer.pad_token is None:
            self.tokenizer.pad_token = self.tokenizer.eos_token
    
    def forward(self, input_ids, attention_mask):
        """前向传播,返回奖励分数"""
        outputs = self.reward_model(input_ids, attention_mask=attention_mask)
        return outputs.logits.squeeze(-1)

def reward_loss(reward_chosen, reward_rejected):
    """Bradley-Terry偏好损失"""
    # 希望 chosen 的奖励高于 rejected
    loss = -torch.log(torch.sigmoid(reward_chosen - reward_rejected))
    return loss.mean()

def train_reward_model(model, train_dataloader, optimizer, epochs=3):
    """训练奖励模型"""
    model.train()
    
    for epoch in range(epochs):
        total_loss = 0
        
        for batch in train_dataloader:
            # 编码 chosen 和 rejected 回答
            chosen_input = model.tokenizer(
                batch['chosen'], 
                padding=True, 
                truncation=True, 
                return_tensors='pt'
            )
            rejected_input = model.tokenizer(
                batch['rejected'], 
                padding=True, 
                truncation=True, 
                return_tensors='pt'
            )
            
            # 计算奖励
            reward_chosen = model(**chosen_input)
            reward_rejected = model(**rejected_input)
            
            # 计算损失
            loss = reward_loss(reward_chosen, reward_rejected)
            
            # 更新模型
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            
            total_loss += loss.item()
        
        avg_loss = total_loss / len(train_dataloader)
        print(f"Epoch {epoch + 1}, Average Loss: {avg_loss:.4f}")

print("奖励模型训练示例代码")
奖励模型的评估

准确率:在测试集上预测偏好的准确率

奖励分数分布:检查奖励分数是否符合预期

与人类评估的相关性:奖励模型的分数是否与人类评分相关

28.6 PPO在大语言模型中的应用

PPO(Proximal Policy Optimization,近端策略优化)是目前RLHF中最常用的强化学习算法。它通过限制策略更新的幅度来保证训练的稳定性。

PPO的核心思想

PPO的核心是 clipped surrogate objective,它限制了策略更新的幅度,防止更新过大导致训练不稳定:

Python PPO算法实现
import torch
import torch.nn as nn
import torch.optim as optim
from torch.distributions import Categorical
import numpy as np

class PPOAgent:
    """PPO智能体:用于大语言模型的RLHF训练"""
    
    def __init__(self, policy_model, ref_model, reward_model, 
                 lr=1e-5, clip_range=0.2, gamma=0.99):
        self.policy_model = policy_model  # 被优化的策略模型
        self.ref_model = ref_model        # 参考模型(SFT模型)
        self.reward_model = reward_model  # 奖励模型
        
        self.optimizer = optim.Adam(self.policy_model.parameters(), lr=lr)
        self.clip_range = clip_range
        self.gamma = gamma
        
        self.kl_coef = 0.1  # KL散度惩罚系数
    
    def compute_kl_penalty(self, policy_logits, ref_logits):
        """计算KL散度惩罚"""
        policy_dist = torch.distributions.Categorical(logits=policy_logits)
        ref_dist = torch.distributions.Categorical(logits=ref_logits)
        
        # KL(policy || ref)
        kl = torch.distributions.kl_divergence(policy_dist, ref_dist)
        return kl
    
    def ppo_loss(self, old_log_probs, new_log_probs, advantages, clip_range):
        """PPO损失函数"""
        # 比率:新策略 / 旧策略
        ratio = torch.exp(new_log_probs - old_log_probs)
        
        # 裁剪的目标函数
        clipped_ratio = torch.clamp(ratio, 1 - clip_range, 1 + clip_range)
        
        # 取两者中的最小值
        surrogate1 = ratio * advantages
        surrogate2 = clipped_ratio * advantages
        
        return -torch.min(surrogate1, surrogate2).mean()
    
    def compute_advantages(self, rewards, values, gamma=0.99, lam=0.95):
        """计算优势函数(GAE)"""
        advantages = []
        gae = 0
        
        for reward, value in zip(reversed(rewards), reversed(values)):
            next_value = values[values.index(value) + 1] if values.index(value) < len(values) - 1 else 0
            delta = reward + gamma * next_value - value
            gae = delta + gamma * lam * gae
            advantages.insert(0, gae)
        
        advantages = torch.FloatTensor(advantages)
        
        # 标准化
        if len(advantages) > 1:
            advantages = (advantages - advantages.mean()) / (advantages.std() + 1e-8)
        
        return advantages
    
    def update(self, rollout):
        """PPO更新"""
        states = rollout['states']
        actions = rollout['actions']
        old_log_probs = rollout['log_probs']
        rewards = rollout['rewards']
        
        # 计算当前策略的log概率
        new_log_probs = []
        policy_logits_list = []
        ref_logits_list = []
        
        for state in states:
            # 当前策略
            state_tensor = torch.FloatTensor(state).unsqueeze(0)
            policy_output = self.policy_model(state_tensor)
            policy_logits = policy_output['logits']
            policy_dist = torch.distributions.Categorical(logits=policy_logits)
            new_log_prob = policy_dist.log_prob(torch.LongTensor([actions[states.index(state)]]))
            new_log_probs.append(new_log_prob)
            policy_logits_list.append(policy_logits)
            
            # 参考模型
            with torch.no_grad():
                ref_output = self.ref_model(state_tensor)
                ref_logits_list.append(ref_output['logits'])
        
        new_log_probs = torch.stack(new_log_probs)
        old_log_probs = torch.FloatTensor(old_log_probs)
        
        # 计算优势函数
        values = torch.zeros(len(rewards))  # 简化:假设value=0
        advantages = self.compute_advantages(rewards, values)
        
        # PPO损失
        ppo_loss = self.ppo_loss(old_log_probs, new_log_probs, advantages, self.clip_range)
        
        # KL惩罚
        kl_penalties = []
        for policy_logits, ref_logits in zip(policy_logits_list, ref_logits_list):
            kl_penalty = self.compute_kl_penalty(policy_logits, ref_logits)
            kl_penalties.append(kl_penalty)
        kl_penalty = torch.stack(kl_penalties).mean()
        
        # 总损失
        total_loss = ppo_loss + self.kl_coef * kl_penalty
        
        # 更新模型
        self.optimizer.zero_grad()
        total_loss.backward()
        self.optimizer.step()
        
        return ppo_loss.item(), kl_penalty.item()

print("PPO算法实现示例")
PPO训练技巧

学习率调度:使用较小的学习率(如1e-5到5e-5)

KL惩罚:防止策略偏离参考模型太远

mini-batch更新:使用mini-batch进行更新以提高稳定性

28.7 DPO与RLHF的对比

DPO(Direct Preference Optimization,直接偏好优化)是近年来提出的一种替代RLHF的方法。它直接优化策略模型,不需要单独训练奖励模型。

DPO的核心思想

DPO的核心思想是:将奖励模型的优化目标直接转化为策略优化目标,从而跳过奖励模型的训练步骤。

Python DPO损失函数
import torch
import torch.nn.functional as F

def dpo_loss(policy_chosen_logps, policy_rejected_logps,
             reference_chosen_logps, reference_rejected_logps,
             beta=0.1):
    """
    DPO损失函数
    
    Args:
        policy_chosen_logps: 策略模型对chosen回答的log概率
        policy_rejected_logps: 策略模型对rejected回答的log概率
        reference_chosen_logps: 参考模型对chosen回答的log概率
        reference_rejected_logps: 参考模型对rejected回答的log概率
        beta: 温度参数,控制与参考模型的偏离程度
    
    Returns:
        DPO损失
    """
    # 计算log比率
    chosen_log_ratio = policy_chosen_logps - reference_chosen_logps
    rejected_log_ratio = policy_rejected_logps - reference_rejected_logps
    
    # DPO损失
    logits = beta * (chosen_log_ratio - rejected_log_ratio)
    loss = -F.logsigmoid(logits).mean()
    
    return loss

# 计算log概率的辅助函数
def compute_log_probs(model, input_ids, attention_mask):
    """计算模型对输入的log概率"""
    outputs = model(input_ids, attention_mask=attention_mask)
    logits = outputs.logits
    
    # 使用log_softmax计算log概率
    log_probs = F.log_softmax(logits, dim=-1)
    
    # 取token级别的log概率并求和
    token_log_probs = torch.gather(
        log_probs[:, :-1], 
        dim=2, 
        index=input_ids[:, 1:].unsqueeze(2)
    ).squeeze(2)
    
    return token_log_probs.sum(dim=-1)

print("DPO损失函数示例")

DPO vs RLHF对比

特性 RLHF (PPO) DPO
训练流程 奖励模型 → PPO优化 直接优化策略
计算复杂度 高(需要多个模型) 低(只需策略和参考模型)
稳定性 需要仔细调参 更稳定
效果 通常更好 接近RLHF
内存需求
如何选择?

选择RLHF:当计算资源充足,追求最佳效果时

选择DPO:当计算资源有限,需要快速迭代时

28.8 动手实践:TRL库

TRL(Transformer Reinforcement Learning)是Hugging Face提供的一个库,它简化了RLHF训练流程。TRL提供了SFTTrainer、RewardTrainer、PPOTrainer等组件,使得在大语言模型上进行RLHF训练变得更加容易。

安装与配置

Bash 安装TRL库
# 安装TRL及其依赖
pip install trl
pip install transformers
pip install datasets
pip install peft  # 用于LoRA

SFT(监督微调)阶段

Python SFT训练示例
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
from trl import SFTTrainer
from datasets import load_dataset

# 加载模型和分词器
model_name = "gpt2"
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

# 加载数据集
dataset = load_dataset("imdb", split="train[:1000]")

def preprocess_function(examples):
    """预处理数据集"""
    return tokenizer(
        examples["text"],
        truncation=True,
        padding="max_length",
        max_length=512
    )

tokenized_dataset = dataset.map(preprocess_function, batched=True)

# 训练参数
training_args = TrainingArguments(
    output_dir="./sft_model",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    learning_rate=2e-5,
    warmup_steps=100,
    logging_steps=10,
    save_strategy="epoch",
)

# SFT训练器
trainer = SFTTrainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset,
    tokenizer=tokenizer,
    max_seq_length=512,
)

# 开始训练
trainer.train()
print("SFT训练完成!")

RLHF训练流程

Python RLHF完整训练流程
from trl import PPOTrainer, PPOConfig, AutoModelForCausalLMWithValueHead
from transformers import AutoTokenizer
import torch

# 1. 加载SFT模型(作为初始策略)
model_name = "gpt2"
model = AutoModelForCausalLMWithValueHead.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

# 2. 加载参考模型(SFT模型的副本)
ref_model = AutoModelForCausalLMWithValueHead.from_pretrained(model_name)

# 3. PPO配置
ppo_config = PPOConfig(
    learning_rate=1e-5,
    batch_size=16,
    mini_batch_size=4,
    ppo_epochs=4,
    kl_penalty="kl",  # 或 "abs", "full"
    init_kl_coef=0.2,
    target_kl=6.0,
)

# 4. 创建PPO训练器
ppo_trainer = PPOTrainer(
    config=ppo_config,
    model=model,
    ref_model=ref_model,
    tokenizer=tokenizer,
)

# 5. 加载奖励模型(示例:使用简单的启发式奖励)
def reward_function(response):
    """简单的奖励函数(实际应使用训练好的奖励模型)"""
    # 示例:奖励包含特定关键词的回答
    good_keywords = ["helpful", "accurate", "clear"]
    reward = sum(1 for word in good_keywords if word in response.lower())
    return reward

# 6. 准备训练数据
prompts = [
    "What is machine learning?",
    "Explain neural networks",
    "What is reinforcement learning?",
]

# 7. RLHF训练循环
for epoch in range(3):
    print(f"\n=== Epoch {epoch + 1} ===")
    
    for prompt in prompts:
        # 编码prompt
        query_tensors = tokenizer.encode(prompt, return_tensors="pt")[0]
        
        # 生成回答
        response_tensors = ppo_trainer.generate(
            query_tensors.unsqueeze(0),
            max_new_tokens=128,
            do_sample=True,
            top_k=50,
            top_p=0.95,
        )
        
        # 解码回答
        response = tokenizer.decode(response_tensors[0], skip_special_tokens=True)
        
        # 计算奖励
        reward = reward_function(response)
        reward_tensors = [torch.tensor([reward])]
        
        # PPO更新
        stats = ppo_trainer.step(
            [query_tensors],
            [response_tensors[0]],
            reward_tensors
        )
        
        print(f"Prompt: {prompt[:30]}...")
        print(f"Reward: {reward:.2f}")
        print(f"KL: {stats['ppo/kl']:.2f}")
        print(f"Entropy: {stats['ppo/entropy']:.2f}")

print("\nRLHF训练完成!")

评估与监控

Python 模型评估示例
TRL库的优势

集成度高:SFT、奖励模型、PPO训练一站式解决

易于使用:提供简洁的API,快速开始训练

灵活可扩展:支持自定义训练流程和奖励函数

生态丰富:与Hugging Face其他库无缝集成

练习题

练习1:Q-Learning实现

实现一个Q-Learning智能体,在FrozenLake环境中训练,并绘制训练曲线。

提示:使用gym库创建环境,实现ε-贪婪策略,记录每个episode的奖励。

练习2:奖励模型训练

使用给定的偏好对数据,训练一个奖励模型,并评估其准确率。

提示:使用Bradley-Terry模型,计算chosen和rejected回答的奖励差异。

练习3:DPO vs RLHF对比实验

在相同的数据集上分别使用DPO和RLHF训练模型,比较两者的效果和训练效率。

提示:使用TRL库,记录训练时间、GPU内存使用、最终效果等指标进行对比。

本章小结

  • 强化学习通过智能体与环境的交互来学习最优策略
  • Q-Learning和策略梯度是两种核心的强化学习算法
  • 深度强化学习使用神经网络来近似价值函数或策略
  • RLHF通过人类反馈来优化大语言模型
  • 奖励模型学习人类偏好,将主观判断转化为数值信号
  • PPO是RLHF中最常用的优化算法
  • DPO提供了一种更简单、更稳定的替代方案
  • TRL库简化了RLHF训练流程,提供了完整的工具链