时间:2024-05-26 16:50
人气:
作者:admin
强化学习的目标是最大化环境提供的奖励信号。然而在现实任务中,人工设计一个合适的奖励函数往往难度很大。比如在自动驾驶中,我们需要权衡速度、安全、舒适等多个因素;在对话系统中,我们希望对话流畅、互动有趣、达成目标。手工定义一个数学化的奖励函数既费时费力,也难以准确捕捉人类需求。
本章我们将探讨一种更灵活、更自然的奖励定义范式——从人类监督中学习奖励函数。这里的"监督"可以是示范轨迹、成功状态标注、轨迹偏好比较等多种形式。通过人机交互,我们可以引导RL智能体学习符合人类意图的奖励函数,进而优化其决策行为。
传统上,RL研究主要聚焦于仿真环境,如Atari游戏、MuJoCo等。在这些环境中,奖励函数都是预先给定的,比如游戏分数、前进速度等。然而在真实世界中,奖励信号往往不那么明确。例如在机器人控制、自动驾驶、对话系统等任务中,我们很难直接给出一个精确的奖励函数。
除了直接定义奖励,我们还可以用其他形式的监督来指定任务。一个常见的做法是行为克隆(behavior cloning),即通过模仿人类专家的行为来学习策略。然而这种方法没有考虑环境动力学和目标信息,而且需要人类以与智能体相同的交互方式提供示教,限制了其应用范围。
因此,我们希望探索一种更一般、更灵活的任务指定机制。其核心思想是让智能体通过人类反馈来理解"什么是好的行为",从而归纳出隐含的奖励函数。接下来我们将介绍两大类主流方法:一是通过标注成功状态来学习目标判别器,二是通过比较轨迹偏好来学习隐式奖励。
给定一组示例状态,我们可以训练一个分类器来判别它们是否满足目标。以机器人装配任务为例,我们可以收集一些成功和失败的状态图像,然后训练一个CNN将其二分类。这个分类器的输出概率可以作为RL的奖励函数。
形式化地,我们定义目标判别器为 fθ(s)f_{\theta}(s)fθ(s)。给定状态 sss,它输出该状态是否满足目标的概率。假设我们收集了一批正例(成功状态)D+\mathcal{D}_{+}D+ 和反例(失败状态)D−\mathcal{D}_{-}D−,那么可以通过监督学习来训练这个判别器:
minθEs∼D+[logfθ(s)]+Es∼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))] θminEs∼D+[logfθ(s)]+Es∼D−[log(1−fθ(s))]
训练完成后,我们就得到了一个目标判别器 fθ(s)f_{\theta}(s)fθ(s),可以用它的输出概率作为RL的奖励。然而这里有一个问题:如果RL智能体访问到了一些训练数据中没有覆盖的状态,而这些状态恰好被 fθf_{\theta}fθ 错判为正例,那么智能体就会被误导,导致学到一个次优策略。
一个自然的想法是在RL训练过程中动态地更新目标判别器,将智能体访问过的状态都添加到反例集 D−\mathcal{D}_{-}D− 中,这样 fθf_{\theta}fθ 就不会被这些状态"愚弄"。我们将整个流程总结如下:
这种思路不仅可以学习目标状态分类,还可以泛化到对完整轨迹的评判。后者也叫作对抗模仿学习(adversarial imitation learning),即用分类器区分示范轨迹和智能体轨迹,并将其输出作为智能体的奖励函数。形式上与GAN非常相似,所以被称为生成式对抗模仿学习(GAIL)。
Sharma等人(2023)将上述思路应用于机器人视觉强化学习。他们手动操纵机器人执行50个任务,并将执行过程录制下来。对于每个任务,取轨迹的最终状态作为正例,其他状态作为负例。另外还将完整的示教轨迹用于预填充RL算法的经验回放池。
实验发现,单纯对任务终止状态的分类准确率能达到95%,但RL训练时的成功率只有26%。这说明分类器虽然能判断状态的好坏,但其输出的稀疏奖励信号不足以指导RL智能体学习。而如果先用分类器预训练智能体,再用稀疏奖励进行finetune,最终成功率能提升到62%。可见引入示教数据辅助训练对于提高采样效率和泛化能力至关重要。
除了对状态进行标注,人类还可以通过比较轨迹的优劣来提供反馈。轨迹(trajectory)在强化学习中指的是智能体与环境交互过程中产生的状态-动作序列,即 τ=(s0,a0,s1,a1,… )\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≻τ2⇒rθ(τ1)>rθ(τ2)
其中 rθr_{\theta}rθ 可以表示为某种参数化形式,如神经网络。一种常见的做法是对轨迹的每个状态-动作对打分,再求和得到整体轨迹奖励:
rθ(τ)=∑t=1Trθ(st,at) r_{\theta}(\tau) = \sum_{t=1}^T r_{\theta}(s_t,a_t) rθ(τ)=t=1∑Trθ(st,at)
其中 TTT 为轨迹长度。为了刻画轨迹优劣的概率,我们定义:
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[logP(τ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[logP(τ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θ,从而让隐式奖励越来越符合人类偏好。整个训练流程如下:
可以看到,这是一个策略学习和奖励学习的交替迭代过程。策略学习使得智能体能够在当前奖励下优化行为策略,而奖励学习则根据人类偏好修正奖励函数本身。二者相辅相成,最终收敛到一个与人类意图一致的策略。
与目标分类相比,偏好学习的优势在于:
当然,这种方法也有一些局限性,比如:
总的来说,从偏好中学习隐式奖励是一种非常灵活、实用的范式,为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作为偏好预测器。这种做法大大降低了人工标注成本,提高了方法的可扩展性。
从人类监督中学习奖励函数是一种极具潜力的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):生成器逐渐提出更具挑战性但仍可达成的目标,执行器则不断提升自己的能力来适应新目标。
形式化地,该方法可以定义为一个两玩家游戏:
可以看出,生成器和执行器的目标是对立的:前者希望选择更具挑战性的目标以让后者难以完成,从而减少支付的奖励;后者则试图学习更强的策略以快速完成目标,从而获得更多奖励。通过这种竞争机制,生成器会逐步提出适合当前执行器能力的目标,形成渐进式的课程表。同时执行器的策略也会随着目标难度的增加而不断进步。
本章我们将详细介绍非对称自博弈的动机、原理和实现,探讨如何通过这种机制让AI系统自主学习和创新。
在传统的强化学习设定中,环境奖励通常是预先定义好的,用于引导智能体学习特定的任务。然而在开放环境中,预设一个恰当的奖励函数非常困难,因为我们无法预见智能体可能面临的所有情况。而且即便奖励函数设计合理,对于复杂的长期任务来说,也很难通过随机探索来高效地优化策略。
事实上,婴儿在学习过程中往往表现出很强的主动性和目的性,他们似乎并不单纯依赖外部的奖励,而是由内在动机驱动去探索世界。这种内在动机可能来自于对新奇事物的偏好、对不确定性的兴趣,或者掌控感和胜任感的满足。从计算机科学的角度看,内在动机可以形式化为一些信息论量度,如预测误差、信息增益、因果熵、互信息等。
一个理想的内在激励机制应该具备以下特点:
非对称自博弈恰好满足了这些要求。下面我们将详细分析其工作机制。
非对称自博弈的关键在于目标生成器和执行器之间的竞争与协作。生成器的目标是最小化自己支付的奖励,因此它需要平衡两个因素:
因此,生成器需要解决一个约束优化问题:在保证目标可达的前提下,最大化目标难度。这个过程可以用以下公式表示:
maxgEs0,π[D(sT,g)]s.t.Es0,π[D(s0,g)−D(sT,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)]≥α
其中 s0s_0s0 和 sTs_TsT 分别表示执行器的初始状态和终止状态,π\piπ 表示执行器的策略,α\alphaα 表示进展阈值。约束条件确保执行器能够在 TTT 步内取得足够的进展,排除了不可达目标。
为了求解这个优化问题,生成器可以采用梯度上升的方法来更新其参数 ϕ\phiϕ:
ϕ←ϕ+η∇ϕEs0,π[D(sT,gϕ(s0))] \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ϕ(s0)g_{\phi}(s_0)gϕ(s0) 表示参数化的目标生成函数,它将初始状态 s0s_0s0 映射为一个目标状态 ggg。
实践中,我们还需要引入一些技巧来稳定训练过程:
下面我们用一个简单的代码示例来演示目标生成器的实现:
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 映射为目标 goal。compute_reward 方法根据欧氏距离计算奖励,sample_goal 方法生成随机扰动的目标。我们将其封装为 Keras 模型,以便进行参数学习。
有了由生成器提出的目标,执行器的任务就是学习一个策略 π(a∣s,g)\pi(a|s,g)π(a∣s,g) 来快速完成这些目标。与标准RL不同的是,这里的策略不仅取决于当前状态 sss,还取决于时变的目标信息 ggg。因此执行器面临一个条件马尔可夫决策过程(CMDP),需要学习一个universal policy来应对不同的目标。
具体来说,执行器的目标是最大化如下的期望奖励:
J(π)=Es0,g∼G,π[∑t=0T−1r(st,at,g)]=Es0,g∼G,π[∑t=0T−1[D(st,g)−D(st+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,g∼G,π[t=0∑T−1r(st,at,g)]=Es0,g∼G,π[t=0∑T−1[D(st,g)−D(st+1,g)]]
即在生成器给定的目标分布 g∼Gg\sim Gg∼G 下,最大化状态进展程度的累积和。
为了优化这个目标函数,我们可以使用任意的强化学习算法,如策略梯度、Q学习、Actor-Critic等。以策略梯度为例,假设执行器的策略为 πθ\pi_{\theta}πθ,参数为 θ\thetaθ。每个episode的采样过程为:
其中梯度项 ∇θlogπθ(τ)\nabla_{\theta} \log \pi_{\theta}(\tau)∇θlogπθ(τ) 表示轨迹 τ\tauτ 在策略 πθ\pi_{\theta}πθ 下的对数似然。
为了让执行器适应不同难度的目标,我们可以在每个episode开始时重置环境状态,让生成器提出一个新的目标,然后让执行器尝试完成它。这个过程不断重复,形成一个自动课程表。随着训练的进行,执行器的策略会变得越来越universal,能够灵活地应对各种类型的目标。
值得一提的是,为了加速收敛,我们还可以让执行器与多个生成器并行交互,从不同难度的目标中进行学习。这相当于从目标分布 GGG 中采样出一个目标池,供执行器择优选择。
下面我们用一个简单的代码示例来演示执行器的实现:
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πθ(τ) 进行加权,鼓励执行器产生能获得高回报的动作。
通过这种博弈机制,目标生成器和执行器能够互相促进,不断挑战彼此的极限。生成器倾向于提出恰好匹配执行器当前能力的目标,而执行器则努力学习新技能来适应这些目标。从整体看,系统展现出了渐进式学习和开放式创新的能力。
Sukhbaatar等人在多个连续控制任务上测试了非对称自博弈算法,包括Point Mass、Ant、Half Cheetah等。结果表明,该算法能够在没有外部奖励的情况下自主学习复杂技能。与随机探索、内在动机(如好奇心)等基线相比,自博弈学到的策略具有更好的探索性、稳定性和鲁棒性。
展示了自博弈算法在Ant环境中的学习过程。随着训练的进行,生成器提出的目标(红点)变得越来越远,而执行器的轨迹(黄线)也在不断延伸。右图对比了不同算法学到的策略。可以看出,用随机目标训练的Archer策略倾向于原地打转,而用自博弈训练的Archer策略能够快速奔向目标。
这项工作为构建通用智能系统提供了一个全新的视角。传统方法往往专注于单个智能体与环境的交互,忽略了智能体内部各组分的互动。而自博弈框架则将探索与利用、规划与控制等功能划分给不同模块,通过内部博弈来实现整体智能的涌现。这种范式不仅在技术上具有优势,也与人类认知的模块化组织更加契合。
当然,自博弈算法还有许多值得进一步探索的问题:
这需要计算机科学、认知科学、心理学等学科的协同创新。相信随着研究的深入,自主学习和内在动机将在未来AI系统中扮演越来越重要的角色。让我们拭目以待!
本章我们介绍了一种名为非对称自博弈的内在动机学习范式。与传统RL依赖外部奖励信号不同,该方法让智能体自己学习设置目标和优化策略。这是通过智能体内部的两个子模块实现的:目标生成器和执行器。生成器负责提出适合当前能力的目标,执行器则努力学习完成目标的策略。两个模块在训练过程中不断博弈,最终实现技能的渐进式提升。
自博弈框架的优势在于:
我们详细分析了目标生成器和执行器的优化目标及实现方式,并给出了完整的算法伪代码。在连续控制任务中,自博弈算法展现出了优于随机探索等基线的性能,学到了更有探索性和适应性的策略。
展望未来,自主学习和内在动机有望成为构建通用人工智能的关键。一方面,我们可以进一步扩展自博弈框架,纳入更多功能模块,实现更高级的认知和推理能力。另一方面,我们可以探索自博弈与其他学习范式(如元学习、迁移学习)的结合,实现跨域技能的复用与创新。同时,人类知识也可以以互动的方式引入博弈过程,形成人机协同进化的新模式。
总之,内在动机和自主学习代表了人工智能的一个新的研究方向。它为我们理解和模拟人类智能提供了新的视角,也为未来自适应、可解释、安全的AI系统奠定了基础。让我们携手探索这片充满想象力的领域,创造更加美好的未来!
除了生成器和执行器,自博弈框架还可以引入哪些功能模块?它们分别负责什么任务?
如何将语言指令整合到目标生成过程中?这对执行器策略学习有何帮助?
多个执行器之间可以通过什么机制互相学习?这种社会学习如何影响整体性能?
自博弈范式能否推广到模仿学习、强化学习、无监督学习等其他任务中?需要做哪些改进?
自主学习智能体的行为是否符合人类伦理道德?如何对其进行约束和引导?
Sukhbaatar S, Kostrikov I, Szlam A, et al. Intrinsic motivation and automatic curricula via asymmetric self-play. arXiv preprint arXiv:1703.05407, 2017.
Florensa C, Held D, Wulfmeier M, et al. Reverse curriculum generation for reinforcement learning. arXiv preprint arXiv:1707.05300, 2017.
Pathak D, Agrawal P, Efros A A, et al. Curiosity-driven exploration by self-supervised prediction. arXiv preprint arXiv:1705.05363, 2017.
Burda Y, Edwards H, Storkey A, et al. Exploration by random network distillation. arXiv preprint arXiv:1810.12894, 2018.
Campero A, Raileanu R, Kuttler H, et al. Learning with amig os: Adversarially motivated intrinsic goals. arXiv preprint arXiv:2006.12122, 2020.
下面我们用一个自动驾驶的例子来形象地说明奖励学习(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
这里我们根据车速、距离道路中心的距离、航向误差等状态特征,以及加速度、转向角等动作特征,分别计算了不同方面的奖励分量。最后将它们加权求和得到总的即时奖励。
问题是,这些权重 w1,w2,…w_1, w_2, \dotsw1,w2,… 很难手工调试。不同的权重会导致不同的驾驶策略,而我们无法预先知道哪种权重最适合实际驾驶环境。
奖励学习提供了一种更灵活、更自适应的替代方案。我们可以让人类专家示范一些优秀的驾驶轨迹 Ddemo={τ1,τ2,… }\mathcal{D}_{demo} = \{\tau_1, \tau_2, \dots\}Ddemo={τ1,τ2,…},然后训练一个神经网络 Rϕ(τ)R_{\phi}(\tau)Rϕ(τ) 来评估任意轨迹 τ\tauτ 的优劣。其优化目标是最大化示范轨迹的分数,同时最小化随机轨迹的分数:
maxϕEτ∼Ddemo[Rϕ(τ)]minϕEτ∼πrand[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)∼Ddemo×Drand[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是一种非常灵活、实用的人机协同范式。它让我们可以将人类经验和偏好无缝地融入到智能系统中,既降低了算法设计的难度,又提高了系统性能的上限。