Stanford斯坦福 CS 224R: 深度强化学习 (4)

从人类监督中学习奖励函数

强化学习的目标是最大化环境提供的奖励信号。然而在现实任务中,人工设计一个合适的奖励函数往往难度很大。比如在自动驾驶中,我们需要权衡速度、安全、舒适等多个因素;在对话系统中,我们希望对话流畅、互动有趣、达成目标。手工定义一个数学化的奖励函数既费时费力,也难以准确捕捉人类需求。

本章我们将探讨一种更灵活、更自然的奖励定义范式——从人类监督中学习奖励函数。这里的"监督"可以是示范轨迹、成功状态标注、轨迹偏好比较等多种形式。通过人机交互,我们可以引导RL智能体学习符合人类意图的奖励函数,进而优化其决策行为。

1. 奖励来自何方?

传统上,RL研究主要聚焦于仿真环境,如Atari游戏、MuJoCo等。在这些环境中,奖励函数都是预先给定的,比如游戏分数、前进速度等。然而在真实世界中,奖励信号往往不那么明确。例如在机器人控制、自动驾驶、对话系统等任务中,我们很难直接给出一个精确的奖励函数。

除了直接定义奖励,我们还可以用其他形式的监督来指定任务。一个常见的做法是行为克隆(behavior cloning),即通过模仿人类专家的行为来学习策略。然而这种方法没有考虑环境动力学和目标信息,而且需要人类以与智能体相同的交互方式提供示教,限制了其应用范围。

因此,我们希望探索一种更一般、更灵活的任务指定机制。其核心思想是让智能体通过人类反馈来理解"什么是好的行为",从而归纳出隐含的奖励函数。接下来我们将介绍两大类主流方法:一是通过标注成功状态来学习目标判别器,二是通过比较轨迹偏好来学习隐式奖励。

2. 从示例状态中学习目标判别器

给定一组示例状态,我们可以训练一个分类器来判别它们是否满足目标。以机器人装配任务为例,我们可以收集一些成功和失败的状态图像,然后训练一个CNN将其二分类。这个分类器的输出概率可以作为RL的奖励函数。

形式化地,我们定义目标判别器为 f θ ( s ) f_{\theta}(s) fθ(s)。给定状态 s s s,它输出该状态是否满足目标的概率。假设我们收集了一批正例(成功状态) D + \mathcal{D}_{+} D+ 和反例(失败状态) D − \mathcal{D}_{-} D,那么可以通过监督学习来训练这个判别器:

min ⁡ θ E s ∼ D + [ log ⁡ f θ ( s ) ] + E s ∼ D − [ log ⁡ ( 1 − f θ ( s ) ) ] \min_{\theta} \mathbb{E}_{s \sim \mathcal{D}_{+}} [\log f_{\theta}(s)] + \mathbb{E}_{s \sim \mathcal{D}_{-}} [\log (1 - f_{\theta}(s))] θminEsD+[logfθ(s)]+EsD[log(1fθ(s))]

训练完成后,我们就得到了一个目标判别器 f θ ( s ) f_{\theta}(s) fθ(s),可以用它的输出概率作为RL的奖励。然而这里有一个问题:如果RL智能体访问到了一些训练数据中没有覆盖的状态,而这些状态恰好被 f θ f_{\theta} fθ 错判为正例,那么智能体就会被误导,导致学到一个次优策略。

一个自然的想法是在RL训练过程中动态地更新目标判别器,将智能体访问过的状态都添加到反例集 D − \mathcal{D}_{-} D 中,这样 f θ f_{\theta} fθ 就不会被这些状态"愚弄"。我们将整个流程总结如下:

  1. 人类标注一批正例 D + \mathcal{D}_{+} D+ 和反例 D − \mathcal{D}_{-} D
  2. 用公式(1)训练目标判别器 f θ f_{\theta} fθ
  3. r ( s , a ) = f θ ( s ) r(s,a)=f_{\theta}(s) r(s,a)=fθ(s) 作为RL的奖励函数,训练一个策略 π \pi π
  4. π \pi π 采集一批轨迹 τ 1 , … , τ N \tau_1,\dots,\tau_N τ1,,τN,将其中的状态添加到 D − \mathcal{D}_{-} D
  5. 重复2-4步,直到 π \pi π 收敛

这种思路不仅可以学习目标状态分类,还可以泛化到对完整轨迹的评判。后者也叫作对抗模仿学习(adversarial imitation learning),即用分类器区分示范轨迹和智能体轨迹,并将其输出作为智能体的奖励函数。形式上与GAN非常相似,所以被称为生成式对抗模仿学习(GAIL)。

用目标判别器进行机器人强化学习

Sharma等人(2023)将上述思路应用于机器人视觉强化学习。他们手动操纵机器人执行50个任务,并将执行过程录制下来。对于每个任务,取轨迹的最终状态作为正例,其他状态作为负例。另外还将完整的示教轨迹用于预填充RL算法的经验回放池。

实验发现,单纯对任务终止状态的分类准确率能达到95%,但RL训练时的成功率只有26%。这说明分类器虽然能判断状态的好坏,但其输出的稀疏奖励信号不足以指导RL智能体学习。而如果先用分类器预训练智能体,再用稀疏奖励进行finetune,最终成功率能提升到62%。可见引入示教数据辅助训练对于提高采样效率和泛化能力至关重要。

3. 从轨迹偏好中学习隐式奖励

除了对状态进行标注,人类还可以通过比较轨迹的优劣来提供反馈。轨迹(trajectory)在强化学习中指的是智能体与环境交互过程中产生的状态-动作序列,即 τ = ( s 0 , a 0 , s 1 , a 1 , …   ) \tau=(s_0,a_0,s_1,a_1,\dots) τ=(s0,a0,s1,a1,)。直观地说,轨迹记录了智能体从初始状态出发,根据当前策略选择动作,并最终到达目标状态的完整过程。不同的策略会产生不同的轨迹分布,体现了智能体的行为特征。形式上,给定两条轨迹 τ 1 \tau_1 τ1 τ 2 \tau_2 τ2,人类标注其偏好关系,记为 τ 1 ≻ τ 2 \tau_1 \succ \tau_2 τ1τ2 τ 2 ≻ τ 1 \tau_2 \succ \tau_1 τ2τ1。我们希望学习一个奖励函数 r θ ( τ ) r_{\theta}(\tau) rθ(τ),使其能够预测这种偏好关系:

τ 1 ≻ τ 2 ⇒ r θ ( τ 1 ) > r θ ( τ 2 ) \tau_1 \succ \tau_2 \Rightarrow r_{\theta}(\tau_1) > r_{\theta}(\tau_2) τ1τ2rθ(τ1)>rθ(τ2)

其中 r θ r_{\theta} rθ 可以表示为某种参数化形式,如神经网络。一种常见的做法是对轨迹的每个状态-动作对打分,再求和得到整体轨迹奖励:

r θ ( τ ) = ∑ t = 1 T r θ ( s t , a t ) r_{\theta}(\tau) = \sum_{t=1}^T r_{\theta}(s_t,a_t) rθ(τ)=t=1Trθ(st,at)

其中 T T T 为轨迹长度。为了刻画轨迹优劣的概率,我们定义:

P ( τ 1 ≻ τ 2 ) = σ ( r θ ( τ 1 ) − r θ ( τ 2 ) ) P(\tau_1 \succ \tau_2) = \sigma(r_{\theta}(\tau_1) - r_{\theta}(\tau_2)) P(τ1τ2)=σ(rθ(τ1)rθ(τ2))

其中 σ ( ⋅ ) \sigma(·) σ() 为sigmoid函数。这个概率越大,表示 τ 1 \tau_1 τ1 τ 2 \tau_2 τ2 更优的可能性越大。因此,给定一批人类标注的偏好数据 D = { ( τ 1 , τ 2 ) } \mathcal{D}=\{(\tau_1,\tau_2)\} D={(τ1,τ2)},我们可以通过最大化下式来训练隐式奖励函数:

max ⁡ θ E ( τ 1 , τ 2 ) ∼ D [ log ⁡ P ( τ 1 ≻ τ 2 ) ] \max_{\theta} \mathbb{E}_{(\tau_1,\tau_2) \sim \mathcal{D}} [\log P(\tau_1 \succ \tau_2)] θmaxE(τ1,τ2)D[logP(τ1τ2)]

其梯度为:

∇ θ E ( τ 1 , τ 2 ) ∼ D [ log ⁡ P ( τ 1 ≻ τ 2 ) ] = E ( τ 1 , τ 2 ) [ σ ( r θ ( τ 2 ) − r θ ( τ 1 ) ) ∇ θ ( r θ ( τ 1 ) − r θ ( τ 2 ) ) ] \nabla_{\theta} \mathbb{E}_{(\tau_1,\tau_2) \sim \mathcal{D}} [\log P(\tau_1 \succ \tau_2)] = \mathbb{E}_{(\tau_1,\tau_2)} [\sigma(r_{\theta}(\tau_2) - r_{\theta}(\tau_1)) \nabla_{\theta} (r_{\theta}(\tau_1) - r_{\theta}(\tau_2)) ] θE(τ1,τ2)D[logP(τ1τ2)]=E(τ1,τ2)[σ(rθ(τ2)rθ(τ1))θ(rθ(τ1)rθ(τ2))]

基于这个梯度,我们就可以用梯度上升优化 r θ r_{\theta} rθ 的参数 θ \theta θ,从而让隐式奖励越来越符合人类偏好。整个训练流程如下:

  1. 随机初始化奖励函数 r θ r_{\theta} rθ
  2. r θ r_{\theta} rθ 作为RL智能体的奖励信号,训练一个策略 π θ \pi_{\theta} πθ
  3. π θ \pi_{\theta} πθ 采集一批轨迹 T = { τ i } \mathcal{T} = \{\tau_i\} T={τi}
  4. T \mathcal{T} T 中随机抽取轨迹对 ( τ 1 , τ 2 ) (\tau_1,\tau_2) (τ1,τ2),形成数据集 D \mathcal{D} D
  5. 让人类对 D \mathcal{D} D 中每个轨迹对标注偏好
  6. 基于公式(6)优化 r θ r_{\theta} rθ
  7. 重复2-6步,直到策略和奖励都收敛

可以看到,这是一个策略学习和奖励学习的交替迭代过程。策略学习使得智能体能够在当前奖励下优化行为策略,而奖励学习则根据人类偏好修正奖励函数本身。二者相辅相成,最终收敛到一个与人类意图一致的策略。

与目标分类相比,偏好学习的优势在于:

  • 不需要人工定义明确的奖励或标注具体的状态,大大降低了人类监督的成本。
  • 通过轨迹比较,隐式地考虑了时序信息和长期影响,对复杂任务更加友好。
  • 在线交互使得奖励函数能与策略同步优化,两者在智能体探索新状态时动态调整。

当然,这种方法也有一些局限性,比如:

  • 轨迹采样和偏好询问都比较耗时,数据效率有待进一步提高。
  • 学习到的奖励函数依赖于采样策略,可能只在特定状态分布下有效。

总的来说,从偏好中学习隐式奖励是一种非常灵活、实用的范式,为RL在更广泛领域的应用带来了可能。

从人类反馈中学习对话奖励

近年来,大型语言模型(LLM)在自然语言处理领域取得了巨大成功。然而如何确保LLM生成的文本符合人类意图,避免产生有害内容,仍是一个巨大挑战。Bai等人(2022)提出了一种基于人类反馈的奖励学习框架(RLAIF),用于优化LLM的生成策略。

具体来说,他们先用LLM生成一批回复,然后让人类标注回复的好坏。接着训练一个奖励模型来拟合这些偏好标注。奖励模型的输入为对话历史和候选回复,输出为该回复的优劣分数。训练时最大化奖励分数排序与人类偏好排序的一致性:

max ⁡ ϕ E ( τ 1 , τ 2 ) ∼ D [ log ⁡ σ ( r ϕ ( τ 1 ) − r ϕ ( τ 2 ) ) ] \max_{\phi} \mathbb{E}_{(\tau_1,\tau_2) \sim \mathcal{D}} [\log \sigma(r_{\phi}(\tau_1) - r_{\phi}(\tau_2))] ϕmaxE(τ1,τ2)D[logσ(rϕ(τ1)rϕ(τ2))]

这里 τ 1 , τ 2 \tau_1,\tau_2 τ1,τ2 为人类标注了偏好关系的两条对话轨迹, r ϕ r_{\phi} rϕ 为待学习的奖励模型。

在得到奖励模型后,作者们用其指导LLM进行PPO策略优化。每次迭代中,他们先用LLM生成候选回复,然后用奖励模型打分,基于分数对LLM的策略网络进行PPO更新。多次迭代后,LLM的生成策略就会与人类偏好对齐。

实验表明,基于人类反馈学习的LLM在减少有害语言生成、提高事实准确性、保持对话连贯性等方面明显优于监督微调的基线模型。这验证了奖励学习在对话生成中的有效性。值得一提的是,他们在奖励建模时没有训练专门的打分模型,而是复用了另一个LLM作为偏好预测器。这种做法大大降低了人工标注成本,提高了方法的可扩展性。

4. 小结与思考

从人类监督中学习奖励函数是一种极具潜力的RL范式。通过示范轨迹、状态标注、偏好比较等多模态人机交互,我们可以更高效、更准确地指定复杂任务,并引导智能体学习到符合人类意图的策略。总结一下:

  • 目标判别器从正负状态示例中学习二分类奖励,但需在训练过程中将智能体访问的状态动态加入反例集,以防止分类器被愚弄。
  • 轨迹偏好学习通过比较式反馈来优化隐式奖励函数,避免了对状态的绝对标注,非常灵活实用。
  • 近年来,偏好学习被用于机器人操纵、自动驾驶、对话生成等复杂场景,取得了喜人的进展。

然而,当前的奖励学习方法仍面临不少挑战:

  • 如何减少人类标注的成本,提高交互数据的利用率?主动学习等思路值得进一步探索。
  • 如何确保学到的奖励函数具有泛化性,而不过度依赖有限的训练分布?这需要更强大的归纳偏置。
  • 如何在连续学习中保持奖励函数的一致性?当环境或目标变化时,如何高效地适应新的偏好?
  • 如何应对人类偏好的模棱两可和非一致性?置信度估计和多样性搜索或许可以缓解这一问题。

展望未来,人类监督有望与其他学习范式相结合,实现更加智能、高效、可解释的目标规划。例如:

  • 将语言指令转化为奖励函数,实现人机协作的自然交互。
  • 用因果推断揭示奖励函数背后的任务逻辑,增强策略的泛化和鲁棒性。
  • 通过元学习和迁移学习复用已有的奖励函数,实现跨任务、跨领域的知识继承。

总之,奖励学习代表了一种全新的RL问题表征和求解范式。它为未来更加智能、更加通用的自主系统开辟了一条充满想象力的道路。让我们共同期待这一领域的蓬勃发展!

下面我们用几个简单的代码例子来演示目标分类和偏好学习的核心思想。

目标分类器示例

首先导入需要的库:

import numpy as np 
import tensorflow as tf

然后定义一个二维连续控制环境,目标状态为(0,0):

class GoalEnv:
    def __init__(self):
        self.state_dim = 2
        self.action_dim = 2
        self.goal = np.array([0, 0])
        
    def reset(self):
        self.state = np.random.randn(2)
        return self.state
    
    def step(self, action):
        self.state += 0.1 * action
        done = np.linalg.norm(self.state - self.goal) < 0.5
        reward = 1.0 if done else 0.0
        return self.state, reward, done

接着我们定义目标分类器,用于预测状态是否接近目标:

class GoalClassifier(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.dense1 = tf.keras.layers.Dense(128, activation='relu')
        self.dense2 = tf.keras.layers.Dense(1, activation='sigmoid') 
        
    def call(self, state):
        x = self.dense1(state)
        x = self.dense2(x)
        return x

现在我们可以训练分类器了:

env = GoalEnv()
goal_classifier = GoalClassifier()
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)

pos_states = []
neg_states = []

# 收集正负样本
for _ in range(1000):  
    state = env.reset()
    done = False
    while not done:
        action = np.random.randn(2)  
        next_state, _, done = env.step(action)
        if done:
            pos_states.append(next_state)
        else:
            neg_states.append(next_state)
        state = next_state
        
pos_states = np.array(pos_states)
neg_states = np.array(neg_states)

# 训练分类器
for _ in range(1000):
    with tf.GradientTape() as tape:
        pos_logits = goal_classifier(pos_states)
        neg_logits = goal_classifier(neg_states)
        loss = tf.reduce_mean(tf.math.log(pos_logits)) + tf.reduce_mean(tf.math.log(1 - neg_logits))
    grads = tape.gradient(loss, goal_classifier.trainable_variables)
    optimizer.apply_gradients(zip(grads, goal_classifier.trainable_variables))

最后我们用学到的分类器奖励来训练RL智能体:

# 定义RL算法(这里用简单的Policy Gradient)
class PolicyNet(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.dense1 = tf.keras.layers.Dense(128, activation='relu')
        self.dense2 = tf.keras.layers.Dense(2, activation='tanh')
        
    def call(self, state):
        x = self.dense1(state)
        x = self.dense2(x)
        return x

policy_net = PolicyNet()
rl_optimizer = tf.keras.optimizers.Adam(learning_rate=0.0001)

# 训练Policy Gradient
for _ in range(100):
    with tf.GradientTape() as tape:
        state = env.reset()
        done = False
        while not done:
            action = policy_net(np.expand_dims(state, 0))[0]
            next_state, _, done = env.step(action)
            
            # 用分类器输出作为RL奖励
            reward = goal_classifier(np.expand_dims(next_state, 0))[0][0]
            
            policy_loss = -tf.math.log(reward)
            
            state = next_state
    
    grads = tape.gradient(policy_loss, policy_net.trainable_variables)       
    rl_optimizer.apply_gradients(zip(grads, policy_net.trainable_variables)) 
    
    # 将RL访问的状态加入分类器的负例集
    pos_states = np.concatenate([pos_states, next_state[np.newaxis]], axis=0)

这个例子展示了如何用分类器学习目标奖励并指导RL训练。关键在于要将RL探索到的状态动态加入分类器的训练集,避免分类器被愚弄。同时RL也会利用新的奖励函数来优化策略,二者交替进行,最终收敛到最优解。

偏好学习示例

我们接着上一个例子,展示如何从轨迹偏好中学习隐式奖励。为了简化问题,我们直接比较两条轨迹在终止状态上距离目标的远近,将更近的一条判为优。

首先定义轨迹采样函数和奖励网络:

def sample_trajectory(env, policy):
    states = []
    state = env.reset()
    done = False 
    while not done:
        states.append(state)
        action = policy(state)
        state, _, done = env.step(action)
    states.append(state)
    return np.array(states)

class RewardNet(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.dense1 = tf.keras.layers.Dense(128, activation='relu') 
        self.dense2 = tf.keras.layers.Dense(1)
        
    def call(self, states):  
        x = self.dense1(states)
        x = self.dense2(x) 
        return tf.reduce_sum(x, axis=0)

采样一批轨迹,并根据终止状态模拟偏好标注:

batch_size = 32

states1 = []
states2 = []
preferences = []

for _ in range(batch_size):
    traj1 = sample_trajectory(env, policy_net)
    traj2 = sample_trajectory(env, policy_net)
    
    # 比较两条轨迹的终止状态,将更接近目标的一条判为优  
    dist1 = np.linalg.norm(traj1[-1] - env.goal)
    dist2 = np.linalg.norm(traj2[-1] - env.goal)
    pref = 1.0 if dist1 < dist2 else -1.0
    
    states1.append(traj1) 
    states2.append(traj2)
    preferences.append(pref)

states1 = np.array(states1) 
states2 = np.array(states2)
preferences = np.array(preferences)  

接下来训练奖励网络来预测偏好:

reward_net = RewardNet()
pref_optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)

# 训练奖励网络  
for _ in range(1000):
    with tf.GradientTape() as tape:
        
        # 计算两条轨迹在当前奖励网络下的累积奖励
        rewards1 = reward_net(states1) 
        rewards2 = reward_net(states2)
        
        # 计算奖励差异与偏好标签的交叉熵损失
        logits = rewards1 - rewards2
        pref_loss = tf.reduce_mean(tf.math.log(1 + tf.math.exp(-preferences * logits)))
        
    grads = tape.gradient(pref_loss, reward_net.trainable_variables)
    pref_optimizer.apply_gradients(zip(grads, reward_net.trainable_variables))

最后用学到的奖励函数训练RL智能体:

# 重新定义Policy Gradient的损失函数  
for _ in range(100):  
    with tf.GradientTape() as tape:
        states = []
        state = env.reset()
        done = False
        while not done:
            states.append(state)
            action = policy_net(np.expand_dims(state, 0))[0]
            state, _, done = env.step(action)
        states.append(state)
        states = np.array(states)
        
        # 用奖励网络计算轨迹的累积奖励
        traj_reward = reward_net(states)
        policy_loss = -tf.reduce_mean(traj_reward)
    
    grads = tape.gradient(policy_loss, policy_net.trainable_variables)
    rl_optimizer.apply_gradients(zip(grads, policy_net.trainable_variables))   
    
    # 将新采样的轨迹与过去的轨迹进行偏好比较,生成新的训练数据
    ...

这里我们实现了一个简单的偏好学习算法。它交替地训练奖励网络来拟合人类偏好,以及训练策略网络来优化累积奖励。新采集到的轨迹数据会与历史数据进行配对比较,用于优化和更新奖励函数。整个过程反复迭代,最终得到一个与人类偏好一致的策略。

当然,这只是一个最简单的例子,实际应用中还有很多改进空间,比如主动学习、数据重要性采样、多样性搜索等。但核心思想是利用人类反馈来指导奖励学习和策略优化,用机器学习的方法来提炼人类意图,最终实现人机协同。

希望这两个例子能让你对奖励学习的基本原理和实现有一个直观的认识。建议你动手实践,在更复杂的环境中探索和优化这些算法。

人工智能如何提出自己的目标?

在前面的章节中,我们讨论了如何从人类监督中学习奖励函数,包括目标状态分类、轨迹偏好比较等方式。这些方法都依赖于人类提供的监督信号,用于指导智能体的策略学习。然而从更长远的角度看,我们希望AI系统能够自主地探索环境、提出目标、优化行为,而不依赖人工设定明确的任务。

Sukhbaatar等人(2018)提出了一种基于非对称自博弈(asymmetric self-play)的内在动机学习方法。其核心思想是将单个智能体划分为两个子网络:目标生成器(goal setter)和目标执行器(goal executor)。生成器负责在当前状态下提出合适的子目标,执行器则负责优化策略来完成这些子目标。两个网络在训练过程中相互博弈,形成自动课程学习(automatic curriculum):生成器逐渐提出更具挑战性但仍可达成的目标,执行器则不断提升自己的能力来适应新目标。

形式化地,该方法可以定义为一个两玩家游戏:

  • 玩家1(生成器):在状态 s t s_t st 处选择一个目标状态 g t g_t gt,得到负奖励(代价) − D ( s t , g t ) -D(s_t,g_t) D(st,gt)。函数 D D D 衡量 s t s_t st g t g_t gt 之间的距离。
  • 玩家2(执行器):执行一个策略 π ( a ∣ s , g ) \pi(a|s,g) π(as,g) 使当前状态 s t s_t st 向目标状态 g t g_t gt 移动,得到正奖励 D ( s t , g t ) − D ( s t + 1 , g t ) D(s_t,g_t) - D(s_{t+1},g_t) D(st,gt)D(st+1,gt)。这个奖励体现了执行器的进展程度。
  • 游戏终止条件:当 D ( s t , g t ) < ϵ D(s_t,g_t) < \epsilon D(st,gt)<ϵ 时,表示执行器已完成当前目标,游戏重新开始。

可以看出,生成器和执行器的目标是对立的:前者希望选择更具挑战性的目标以让后者难以完成,从而减少支付的奖励;后者则试图学习更强的策略以快速完成目标,从而获得更多奖励。通过这种竞争机制,生成器会逐步提出适合当前执行器能力的目标,形成渐进式的课程表。同时执行器的策略也会随着目标难度的增加而不断进步。

本章我们将详细介绍非对称自博弈的动机、原理和实现,探讨如何通过这种机制让AI系统自主学习和创新。

1. 自动课程学习与内在动机

在传统的强化学习设定中,环境奖励通常是预先定义好的,用于引导智能体学习特定的任务。然而在开放环境中,预设一个恰当的奖励函数非常困难,因为我们无法预见智能体可能面临的所有情况。而且即便奖励函数设计合理,对于复杂的长期任务来说,也很难通过随机探索来高效地优化策略。

事实上,婴儿在学习过程中往往表现出很强的主动性和目的性,他们似乎并不单纯依赖外部的奖励,而是由内在动机驱动去探索世界。这种内在动机可能来自于对新奇事物的偏好、对不确定性的兴趣,或者掌控感和胜任感的满足。从计算机科学的角度看,内在动机可以形式化为一些信息论量度,如预测误差、信息增益、因果熵、互信息等。

一个理想的内在激励机制应该具备以下特点:

  1. 随着智能体能力的提高,激励的对象会动态变化,形成适应性的探索。
  2. 激励的内容和强度应与当前的学习进度相匹配,既不会太过简单导致停滞,也不会太过困难导致挫败。
  3. 激励信号应鼓励智能体学习可迁移、可复用的技能,而不仅仅是环境特定的行为模式。
  4. 多个智能体或智能体的多个子模块之间应形成良性互动,促进整体能力的提升。

非对称自博弈恰好满足了这些要求。下面我们将详细分析其工作机制。

2. 博弈目标生成的机制

非对称自博弈的关键在于目标生成器和执行器之间的竞争与协作。生成器的目标是最小化自己支付的奖励,因此它需要平衡两个因素:

  1. 目标的难度:选择更具挑战性的目标,执行器完成的可能性越小,生成器支付的奖励就越少。
  2. 目标的可达性:如果目标完全不可达,执行器就无法获得进展,生成器也无法得到反馈来调整策略。

因此,生成器需要解决一个约束优化问题:在保证目标可达的前提下,最大化目标难度。这个过程可以用以下公式表示:

max ⁡ g E s 0 , π [ D ( s T , g ) ] s . t . E s 0 , π [ D ( s 0 , g ) − D ( s T , g ) ] ≥ α \max_{g} \mathbb{E}_{s_0,\pi}[D(s_T,g)] \\ s.t. \mathbb{E}_{s_0,\pi}[D(s_0,g)-D(s_T,g)] \geq \alpha gmaxEs0,π[D(sT,g)]s.t.Es0,π[D(s0,g)D(sT,g)]α

其中 s 0 s_0 s0 s T s_T sT 分别表示执行器的初始状态和终止状态, π \pi π 表示执行器的策略, α \alpha α 表示进展阈值。约束条件确保执行器能够在 T T T 步内取得足够的进展,排除了不可达目标。

为了求解这个优化问题,生成器可以采用梯度上升的方法来更新其参数 ϕ \phi ϕ:

ϕ ← ϕ + η ∇ ϕ E s 0 , π [ D ( s T , g ϕ ( s 0 ) ) ] \phi \leftarrow \phi + \eta \nabla_{\phi} \mathbb{E}_{s_0,\pi}[D(s_T,g_{\phi}(s_0))] ϕϕ+ηϕEs0,π[D(sT,gϕ(s0))]

其中 η \eta η 是学习率, g ϕ ( s 0 ) g_{\phi}(s_0) gϕ(s0) 表示参数化的目标生成函数,它将初始状态 s 0 s_0 s0 映射为一个目标状态 g g g

实践中,我们还需要引入一些技巧来稳定训练过程:

  1. 用蒙特卡洛估计来近似梯度,即通过采样执行器轨迹 ( s 0 , s 1 , … , s T ) (s_0,s_1,\dots,s_T) (s0,s1,,sT) 来计算目标难度。
  2. 给生成器添加熵正则化项,鼓励其产生多样化的目标。这可以防止执行器过度专精于特定类型的目标。
  3. 给目标添加随机扰动,增加其不确定性。这迫使执行器学习更鲁棒的策略。
  4. 让多个生成器并行工作,产生不同难度的目标,供执行器择优选择。这形成了一个"目标市场"。

下面我们用一个简单的代码示例来演示目标生成器的实现:

import numpy as np
import tensorflow as tf

class GoalGenerator(tf.keras.Model):
    def __init__(self, state_dim, goal_dim, hidden_dim=256):
        super().__init__()
        
        self.state_dim = state_dim
        self.goal_dim = goal_dim
        
        self.hidden_dim = hidden_dim
        
        self.dense1 = tf.keras.layers.Dense(hidden_dim, activation='relu')
        self.dense2 = tf.keras.layers.Dense(hidden_dim, activation='relu') 
        self.dense3 = tf.keras.layers.Dense(goal_dim)
    
    def call(self, state):
        x = self.dense1(state)
        x = self.dense2(x)
        goal = self.dense3(x) 
        return goal
    
    def compute_reward(self, state, goal, next_state):
        # 计算状态之间的欧氏距离
        d_start = tf.linalg.norm(state - goal, axis=1)
        d_end = tf.linalg.norm(next_state - goal, axis=1)  
        
        reward = d_start - d_end  # 距离越小,奖励越大
        
        return reward
    
    def sample_goal(self, state, compute_grad=True):
        if not compute_grad:
            # 在验证/测试时关闭梯度计算
            tf.keras.backend.set_learning_phase(0) 
        
        goal = self(state)
        goal = goal + tf.random.normal(tf.shape(goal), stddev=0.1)  # 添加随机噪声
        
        if not compute_grad:
            # 恢复训练模式
            tf.keras.backend.set_learning_phase(1)
        
        return goal

这里我们定义了一个简单的前馈神经网络GoalGenerator,它将状态 state 映射为目标 goalcompute_reward 方法根据欧氏距离计算奖励,sample_goal 方法生成随机扰动的目标。我们将其封装为 Keras 模型,以便进行参数学习。

3. 博弈执行器的策略学习

有了由生成器提出的目标,执行器的任务就是学习一个策略 π ( a ∣ s , g ) \pi(a|s,g) π(as,g) 来快速完成这些目标。与标准RL不同的是,这里的策略不仅取决于当前状态 s s s,还取决于时变的目标信息 g g g。因此执行器面临一个条件马尔可夫决策过程(CMDP),需要学习一个universal policy来应对不同的目标。

具体来说,执行器的目标是最大化如下的期望奖励:

J ( π ) = E s 0 , g ∼ G , π [ ∑ t = 0 T − 1 r ( s t , a t , g ) ] = E s 0 , g ∼ G , π [ ∑ t = 0 T − 1 [ D ( s t , g ) − D ( s t + 1 , g ) ] ] \begin{aligned} J(\pi) &= \mathbb{E}_{s_0,g\sim G,\pi}[\sum_{t=0}^{T-1} r(s_t,a_t,g)] \\ &= \mathbb{E}_{s_0,g\sim G,\pi}[\sum_{t=0}^{T-1} [D(s_t,g)-D(s_{t+1},g)]] \end{aligned} J(π)=Es0,gG,π[t=0T1r(st,at,g)]=Es0,gG,π[t=0T1[D(st,g)D(st+1,g)]]

即在生成器给定的目标分布 g ∼ G g\sim G gG 下,最大化状态进展程度的累积和。

为了优化这个目标函数,我们可以使用任意的强化学习算法,如策略梯度、Q学习、Actor-Critic等。以策略梯度为例,假设执行器的策略为 π θ \pi_{\theta} πθ,参数为 θ \theta θ。每个episode的采样过程为:

  1. 初始化状态 s 0 s_0 s0
  2. 目标生成器根据 s 0 s_0 s0 提出一个目标 g g g
  3. 执行器与环境交互 T T T 步,得到轨迹 τ = ( s 0 , a 0 , r 0 , s 1 , a 1 , r 1 , … , s T , a T , r T ) \tau=(s_0,a_0,r_0,s_1,a_1,r_1,\dots,s_T,a_T,r_T) τ=(s0,a0,r0,s1,a1,r1,,sT,aT,rT)
  4. 计算轨迹的回报(return) R ( τ ) = ∑ t = 0 T − 1 r ( s t , a t , g ) R(\tau)=\sum_{t=0}^{T-1} r(s_t,a_t,g) R(τ)=t=0T1r(st,at,g)
  5. 更新执行器参数: θ ← θ + η ∇ θ log ⁡ π θ ( τ ) R ( τ ) \theta \leftarrow \theta + \eta \nabla_{\theta} \log \pi_{\theta}(\tau) R(\tau) θθ+ηθlogπθ(τ)R(τ)

其中梯度项 ∇ θ log ⁡ π θ ( τ ) \nabla_{\theta} \log \pi_{\theta}(\tau) θlogπθ(τ) 表示轨迹 τ \tau τ 在策略 π θ \pi_{\theta} πθ 下的对数似然。

为了让执行器适应不同难度的目标,我们可以在每个episode开始时重置环境状态,让生成器提出一个新的目标,然后让执行器尝试完成它。这个过程不断重复,形成一个自动课程表。随着训练的进行,执行器的策略会变得越来越universal,能够灵活地应对各种类型的目标。

值得一提的是,为了加速收敛,我们还可以让执行器与多个生成器并行交互,从不同难度的目标中进行学习。这相当于从目标分布 G G G 中采样出一个目标池,供执行器择优选择。

下面我们用一个简单的代码示例来演示执行器的实现:

class GoalConditionedPolicy(tf.keras.Model):
    def __init__(self, state_dim, goal_dim, action_dim, hidden_dim=256):
        super().__init__()
        
        self.state_dim = state_dim
        self.goal_dim = goal_dim
        self.action_dim = action_dim
        
        self.hidden_dim = hidden_dim
         
        self.dense1 = tf.keras.layers.Dense(hidden_dim, activation='relu')
        self.dense2 = tf.keras.layers.Dense(hidden_dim, activation='relu')
        self.dense3 = tf.keras.layers.Dense(action_dim)
    
    def call(self, state, goal):
        x = tf.concat([state, goal], axis=1)
        x = self.dense1(x)   
        x = self.dense2(x)
        action = self.dense3(x)
        return action
    
    def sample_action(self, state, goal):
        action = self(state, goal)
        action = tf.tanh(action)  # 将动作映射到[-1, 1]范围内
        return action

这里我们定义了一个目标条件策略GoalConditionedPolicy,它接受状态 state 和目标 goal 作为输入,输出一个连续动作 action。我们将状态和目标拼接在一起作为策略网络的输入,这样策略就能根据不同的目标生成不同的行为。sample_action 方法对动作进行随机采样,以实现探索。

有了目标生成器和执行器,我们就可以实现完整的非对称自博弈算法了。伪代码如下:

# 初始化目标生成器和执行器
goal_generator = GoalGenerator(state_dim, goal_dim)
goal_conditioned_policy = GoalConditionedPolicy(state_dim, goal_dim, action_dim)

# 初始化优化器
generator_optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)
executor_optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)

for episode in range(num_episodes):
    state = env.reset()
    goal_state = env.sample_goal()  # 随机采样一个初始目标状态
    
    # 目标生成器生成新目标
    with tf.GradientTape() as tape:
        goal = goal_generator.sample_goal(state)
        
        # 让执行器执行目标
        rewards = []
        states = []
        actions = []
        for t in range(max_steps):
            action = goal_conditioned_policy.sample_action(state, goal)
            next_state, _, done, _ = env.step(action)
            
            states.append(state)
            actions.append(action)
            
            reward = goal_generator.compute_reward(state, goal, next_state)
            rewards.append(reward)
            
            state = next_state
            
            if done:
                break
        
        # 计算生成器损失
        generator_loss = -tf.reduce_mean(rewards)
    
    # 更新生成器参数
    generator_grads = tape.gradient(generator_loss, goal_generator.trainable_variables)
    generator_optimizer.apply_gradients(zip(generator_grads, goal_generator.trainable_variables))
    
    # 更新执行器参数
    with tf.GradientTape() as tape:
        log_probs = []
        for state, action in zip(states, actions):
            action_probs = goal_conditioned_policy(state, goal)
            log_prob = tf.math.log(action_probs + 1e-8)
            log_probs.append(log_prob)
        
        # 计算执行器损失  
        returns = tf.reduce_sum(rewards)
        executor_loss = -tf.reduce_sum(log_probs) * returns
    
    executor_grads = tape.gradient(executor_loss, goal_conditioned_policy.trainable_variables)  
    executor_optimizer.apply_gradients(zip(executor_grads, goal_conditioned_policy.trainable_variables))

这个算法交替地更新生成器和执行器的参数。对于生成器,我们计算采样轨迹的平均奖励作为损失函数,并最小化这个损失。这鼓励生成器提出更有挑战性的目标。对于执行器,我们计算动作在采样轨迹上的对数似然,并最大化似然与累积奖励的乘积。这相当于对梯度项 ∇ θ log ⁡ π θ ( τ ) \nabla_{\theta} \log \pi_{\theta}(\tau) θlogπθ(τ) 进行加权,鼓励执行器产生能获得高回报的动作。

通过这种博弈机制,目标生成器和执行器能够互相促进,不断挑战彼此的极限。生成器倾向于提出恰好匹配执行器当前能力的目标,而执行器则努力学习新技能来适应这些目标。从整体看,系统展现出了渐进式学习和开放式创新的能力。

4. 实验结果与讨论

Sukhbaatar等人在多个连续控制任务上测试了非对称自博弈算法,包括Point Mass、Ant、Half Cheetah等。结果表明,该算法能够在没有外部奖励的情况下自主学习复杂技能。与随机探索、内在动机(如好奇心)等基线相比,自博弈学到的策略具有更好的探索性、稳定性和鲁棒性。

展示了自博弈算法在Ant环境中的学习过程。随着训练的进行,生成器提出的目标(红点)变得越来越远,而执行器的轨迹(黄线)也在不断延伸。右图对比了不同算法学到的策略。可以看出,用随机目标训练的Archer策略倾向于原地打转,而用自博弈训练的Archer策略能够快速奔向目标。

这项工作为构建通用智能系统提供了一个全新的视角。传统方法往往专注于单个智能体与环境的交互,忽略了智能体内部各组分的互动。而自博弈框架则将探索与利用、规划与控制等功能划分给不同模块,通过内部博弈来实现整体智能的涌现。这种范式不仅在技术上具有优势,也与人类认知的模块化组织更加契合。

当然,自博弈算法还有许多值得进一步探索的问题:

  • 如何设计更复杂的生成器和执行器架构,实现更高级的规划和推理能力?
  • 如何在多智能体场景中应用自博弈,实现群体涌现智能?
  • 如何将人类知识引入博弈过程,实现人机协同创新?
  • 如何建立更广泛的内在动机框架,涵盖技能学习、因果推断、社会交互等方面?

这需要计算机科学、认知科学、心理学等学科的协同创新。相信随着研究的深入,自主学习和内在动机将在未来AI系统中扮演越来越重要的角色。让我们拭目以待!

5. 总结

本章我们介绍了一种名为非对称自博弈的内在动机学习范式。与传统RL依赖外部奖励信号不同,该方法让智能体自己学习设置目标和优化策略。这是通过智能体内部的两个子模块实现的:目标生成器和执行器。生成器负责提出适合当前能力的目标,执行器则努力学习完成目标的策略。两个模块在训练过程中不断博弈,最终实现技能的渐进式提升。

自博弈框架的优势在于:

  • 不依赖人工设定的奖励函数,适用于开放环境。
  • 展现出自主探索和创新能力,能够适应环境变化。
  • 通过目标生成实现自动课程学习,匹配当前学习进度。
  • 通过内部竞争与合作实现整体智能的涌现。

我们详细分析了目标生成器和执行器的优化目标及实现方式,并给出了完整的算法伪代码。在连续控制任务中,自博弈算法展现出了优于随机探索等基线的性能,学到了更有探索性和适应性的策略。

展望未来,自主学习和内在动机有望成为构建通用人工智能的关键。一方面,我们可以进一步扩展自博弈框架,纳入更多功能模块,实现更高级的认知和推理能力。另一方面,我们可以探索自博弈与其他学习范式(如元学习、迁移学习)的结合,实现跨域技能的复用与创新。同时,人类知识也可以以互动的方式引入博弈过程,形成人机协同进化的新模式。

总之,内在动机和自主学习代表了人工智能的一个新的研究方向。它为我们理解和模拟人类智能提供了新的视角,也为未来自适应、可解释、安全的AI系统奠定了基础。让我们携手探索这片充满想象力的领域,创造更加美好的未来!

思考题

  1. 除了生成器和执行器,自博弈框架还可以引入哪些功能模块?它们分别负责什么任务?

  2. 如何将语言指令整合到目标生成过程中?这对执行器策略学习有何帮助?

  3. 多个执行器之间可以通过什么机制互相学习?这种社会学习如何影响整体性能?

  4. 自博弈范式能否推广到模仿学习、强化学习、无监督学习等其他任务中?需要做哪些改进?

  5. 自主学习智能体的行为是否符合人类伦理道德?如何对其进行约束和引导?

参考文献

  1. Sukhbaatar S, Kostrikov I, Szlam A, et al. Intrinsic motivation and automatic curricula via asymmetric self-play. arXiv preprint arXiv:1703.05407, 2017.

  2. Florensa C, Held D, Wulfmeier M, et al. Reverse curriculum generation for reinforcement learning. arXiv preprint arXiv:1707.05300, 2017.

  3. Pathak D, Agrawal P, Efros A A, et al. Curiosity-driven exploration by self-supervised prediction. arXiv preprint arXiv:1705.05363, 2017.

  4. Burda Y, Edwards H, Storkey A, et al. Exploration by random network distillation. arXiv preprint arXiv:1810.12894, 2018.

  5. Campero A, Raileanu R, Kuttler H, et al. Learning with amig os: Adversarially motivated intrinsic goals. arXiv preprint arXiv:2006.12122, 2020.

Q&A

下面我们用一个自动驾驶的例子来形象地说明奖励学习(reward learning)的应用。

假设我们要开发一个自动驾驶系统,目标是让车辆安全、高效、舒适地行驶。传统的强化学习方法需要手工设计一个奖励函数,例如:

def reward_function(state, action):
    # 状态特征
    speed = state['speed'] 
    distance_to_center = state['distance_to_center']
    heading_error = state['heading_error']
    
    # 动作特征  
    acceleration = action['acceleration']
    steering_angle = action['steering_angle']
    
    # 计算奖励分量  
    speed_reward = -abs(speed - target_speed) 
    center_reward = -abs(distance_to_center)
    heading_reward = -abs(heading_error)
    acceleration_reward = -abs(acceleration)
    steering_reward = -abs(steering_angle)
    
    # 加权求和
    reward = w1 * speed_reward + w2 * center_reward + w3 * heading_reward + w4 * acceleration_reward + w5 * steering_reward
    
    return reward

这里我们根据车速、距离道路中心的距离、航向误差等状态特征,以及加速度、转向角等动作特征,分别计算了不同方面的奖励分量。最后将它们加权求和得到总的即时奖励。

问题是,这些权重 w 1 , w 2 , … w_1, w_2, \dots w1,w2, 很难手工调试。不同的权重会导致不同的驾驶策略,而我们无法预先知道哪种权重最适合实际驾驶环境。

奖励学习提供了一种更灵活、更自适应的替代方案。我们可以让人类专家示范一些优秀的驾驶轨迹 D d e m o = { τ 1 , τ 2 , …   } \mathcal{D}_{demo} = \{\tau_1, \tau_2, \dots\} Ddemo={τ1,τ2,},然后训练一个神经网络 R ϕ ( τ ) R_{\phi}(\tau) Rϕ(τ) 来评估任意轨迹 τ \tau τ 的优劣。其优化目标是最大化示范轨迹的分数,同时最小化随机轨迹的分数:

max ⁡ ϕ E τ ∼ D d e m o [ R ϕ ( τ ) ] min ⁡ ϕ E τ ∼ π r a n d [ R ϕ ( τ ) ] \begin{aligned} \max_{\phi} & \mathbb{E}_{\tau \sim \mathcal{D}_{demo}}[R_{\phi}(\tau)] \\ \min_{\phi} & \mathbb{E}_{\tau \sim \pi_{rand}}[R_{\phi}(\tau)] \end{aligned} ϕmaxϕminEτDdemo[Rϕ(τ)]Eτπrand[Rϕ(τ)]

直观地说,这鼓励奖励函数对人类示范的轨迹给出高分,对随机采样的轨迹给出低分。我们还可以通过对比学习(contrastive learning)来加强这种区分能力:

max ⁡ ϕ E ( τ i , τ j ) ∼ D d e m o × D r a n d [ log ⁡ σ ( R ϕ ( τ i ) − R ϕ ( τ j ) ) ] \max_{\phi} \mathbb{E}_{(\tau_i, \tau_j) \sim \mathcal{D}_{demo} \times \mathcal{D}_{rand}} [\log \sigma(R_{\phi}(\tau_i) - R_{\phi}(\tau_j))] ϕmaxE(τi,τj)Ddemo×Drand[logσ(Rϕ(τi)Rϕ(τj))]

其中 σ ( ⋅ ) \sigma(·) σ() 是 Sigmoid 函数。这个目标函数达到最大值时,示范轨迹的分数会远高于随机轨迹。

我们用如下代码来实现这个轨迹评分器:

import torch
import torch.nn as nn

class TrajectoryScorer(nn.Module):
    def __init__(self, input_dim, hidden_dim):
        super().__init__()
        self.lstm = nn.LSTM(input_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, 1) 
        
    def forward(self, trajectories):
        """
        trajectories: tensor of shape (batch_size, seq_len, input_dim)
        """
        h, _ = self.lstm(trajectories)  
        scores = self.fc(h[:, -1, :]) # 取最后一个时间步的隐状态
        return scores

这里我们用 LSTM 网络来处理变长的轨迹序列,并用最后一个时间步的隐状态来表示整个轨迹的质量分数。

有了学到的奖励函数,我们就可以用它指导强化学习,得到一个安全、高效、舒适的自动驾驶策略:

import gym

# 加载预训练的奖励函数
reward_function = TrajectoryScorer(...)  
reward_function.load_state_dict(torch.load('reward.pth'))

# 定义强化学习环境  
env = gym.make('Highway-v0') 

# 定义 actor-critic 算法
actor = ... 
critic = ...

# 训练
for episode in range(num_episodes):
    state = env.reset()
    trajectory = []
    
    while not done:
        action = actor.get_action(state)
        next_state, _, done, _ = env.step(action)
        
        # 记录轨迹
        trajectory.append((state, action, next_state))
        state = next_state
        
    # 计算轨迹奖励  
    trajectory = torch.tensor([t for t in trajectory], dtype=torch.float32)
    reward = reward_function(trajectory)
    
    # 更新 actor 和 critic
    ...

主要思路是,我们先用人类示范数据训练出一个轨迹评分器,作为奖励函数。然后在强化学习训练过程中,将智能体与环境交互产生的轨迹数据输入到这个评分器中,得到轨迹的整体奖励。之后就可以用任意的RL算法(如Actor-Critic)来更新策略网络了。

可以看到,奖励学习将人类知识自然地注入到了自动驾驶系统的开发流程中。我们不需要手工调试奖励函数,只需要给出示范轨迹,算法就能自动归纳出人类偏好,并用它来指导策略优化。这大大降低了reward shaping的难度,也让最终策略更加贴近实际需求。

当然,轨迹奖励只是reward learning的一种形式。我们还可以学习根据状态、动作、环境反馈来打分的奖励函数,得到更细粒度的评估。但无论哪种形式,其核心思想都是利用人类知识来引导智能体学习,自适应地调整优化目标。

总之,reward learning是一种非常灵活、实用的人机协同范式。它让我们可以将人类经验和偏好无缝地融入到智能系统中,既降低了算法设计的难度,又提高了系统性能的上限。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值