系列 · 强化学习 · 第 11 篇

强化学习(十一):层次化强化学习与元学习

层次化强化学习(Options、MAXQ、Feudal Networks、目标条件策略)与元强化学习(MAML、FOMAML、RL²)的系统讲解:时序抽象、半马尔可夫过程、Manager-Worker 架构、二阶元梯度与循环式元学习器,附带 PyTorch 实现。

标准强化学习将每个问题视为一系列原子级别的决策:观察状态、选择动作、接收奖励,然后重复。这种方法在任务时间跨度较短、奖励密集时效果不错,但面对人类能轻松完成的任务时就会失效。“做早餐”显然不是单次决策,而是一棵由多个子任务组成的树——煮咖啡煎蛋烤面包装盘上桌——每个子任务本身都是一套小型策略。层次化强化学习(HRL) 的核心思想是将宏动作视为一等公民,让智能体能在多个时间尺度上进行推理和行动。

标准强化学习的另一个短板是:每次遇到新任务都得从零开始学。现实中,一个会骑自行车的人只需一下午就能学会骑摩托车,而不是花上千万步环境交互。元强化学习(Meta-RL) 正是为解决这一问题而生:它在一个任务分布上进行训练,使得智能体面对未见过的新任务时,仅需几个回合(甚至只需一次循环神经网络的前向传播)就能快速适应。

本文将这两种思路统一起来:层次化带来时间维度的抽象,元学习带来任务维度的抽象。二者都能有效降低学习问题的维度,而当前前沿方法(如 FuN、HIRO、MAML、RL²)正积极地将它们结合起来。


你将学到什么#

  • Options 框架 —— 半马尔可夫决策过程与 intra-option Q-learning
  • MAXQ —— 沿任务层级分解值函数
  • Feudal RL(FuN、HIRO)—— 基于 Manager-Worker 架构的连续子目标方法
  • 目标条件 RL —— 通用值函数与 HER(事后经验回放)
  • MAML / FOMAML —— 学习一个只需几步梯度更新就能快速适应的初始化参数
  • RL² —— 将内层 RL 算法“折叠”进 RNN 的隐藏状态
  • 可运行代码 —— Four Rooms 环境中的 intra-option Q-learning 与 2D 导航任务上的 MAML 策略梯度

前置知识#

  • Q-learning、策略梯度和值函数(第 1 到 6 部分
  • 熟悉 RNN 展开和二阶自动微分
  • 掌握 PyTorch

一、层次化:Options 框架#

为什么时序抽象至关重要#

扁平策略在每个环境步都做一次决策,因此在长度为 $T$ 的任务中,信用分配路径长达 $T$ ,探索树的叶节点数量高达 $|\mathcal{A}|^T$ ,两者均呈指数增长。若引入平均长度为 $\bar k$ 的宏动作,决策次数可降至 $T/\bar k$ ,探索树规模也缩减至 $|\mathcal{O}|^{T/\bar k}$ ,其中 $\mathcal{O}$ 是一个通常很小的选项集合。下图对比了两种视角。

Options 框架:时间线视图与三元组 (I, π, β)

除了渐近复杂度优势,层次化还带来三大实际好处:

  1. 模块化 —— 在一个任务上学到的选项可迁移到其他任务(例如 走到门口 可泛化到各类导航问题)。
  2. 可解释性 —— 高层策略足够小,便于检查;决策点也落在语义上有意义的关键位置。
  3. 奖励塑形 —— 即使外部奖励稀疏,子目标也能提供密集的内在奖励。

Option 三元组#

$$o = \langle \mathcal{I}, \pi_o, \beta \rangle,$$

其中 $\mathcal{I} \subseteq \mathcal{S}$ 是该选项可被启动的状态集合,$\pi_o(a \mid s)$ 是其内部策略,$\beta(s) \in [0, 1]$ 是终止概率。一旦引入选项,底层 MDP 就变成了半马尔可夫决策过程(semi-MDP):高层策略 $\mu(o \mid s)$ 选择一个选项,该选项持续执行直至 $\beta$ 触发,此时才进行下一次高层决策。

Intra-option Q-learning#

$$Q(s, o) \leftarrow Q(s, o) + \alpha \big[r + \gamma U(s', o) - Q(s, o)\big],$$ $$U(s', o) = (1 - \beta(s'))\, Q(s', o) + \beta(s')\, \max_{o'} Q(s', o').$$

延续值的设计十分巧妙:若选项继续执行,则保留其 Q 值;若在 $s'$ 终止,则交还控制权给高层策略,并取最优替代选项。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import numpy as np
from collections import defaultdict

class IntraOptionQLearning:
    """离散选项集合上的 intra-option Q-learning。

    每一条原始转移都会更新:
    (1) 当前选项的高层 Q(s, o);
    (2) 该选项的内部 Q 表,从而隐式修正其内部策略。
    """

    def __init__(self, env, options, alpha=0.5, gamma=0.99, epsilon=0.1):
        self.env, self.options = env, options
        self.alpha, self.gamma, self.epsilon = alpha, gamma, epsilon
        self.Q = defaultdict(lambda: np.zeros(len(options)))     # Q(s, o)
        self.Q_prim = defaultdict(lambda: np.zeros(env.n_actions))

    def _select_option(self, state):
        available = [i for i, o in enumerate(self.options)
                     if o.can_initiate(state)]
        if not available:
            return None
        if np.random.rand() < self.epsilon:
            return int(np.random.choice(available))
        q = self.Q[state][available]
        return int(available[np.argmax(q)])

    def train_episode(self, max_steps=1000):
        state = self.env.reset()
        total_reward = 0.0
        for _ in range(max_steps):
            oid = self._select_option(state)
            if oid is None:
                break
            option = self.options[oid]

            while not option.should_terminate(state):
                action = option.act(state, self.epsilon)
                next_state, reward, done = self.env.step(action)
                total_reward += reward

                # 计算延续值 U(s', o)
                if option.should_terminate(next_state):
                    U = np.max(self.Q[next_state])
                else:
                    U = self.Q[next_state][oid]

                # 更新高层 Q 值
                self.Q[state][oid] += self.alpha * (
                    reward + self.gamma * U - self.Q[state][oid])

                # 更新内部策略(基于原始动作的扁平 Q 表)
                td = (reward + self.gamma
                      * np.max(self.Q_prim[next_state])
                      - self.Q_prim[state][action])
                self.Q_prim[state][action] += self.alpha * td
                option.policy[state] = int(np.argmax(self.Q_prim[state]))

                state = next_state
                if done:
                    return total_reward
        return total_reward

在经典的 Four Rooms 基准测试中,使用四个手工设计的“穿过门口”选项后,intra-option Q-learning 的收敛速度比扁平 Q-learning 快 3–5 倍,且学到的选项能直接迁移到新目标位置。

MAXQ:沿任务树分解值函数#

$$Q_i(s, a) = V_a(s) + C_i(s, a),$$

其中 $V_a(s)$ 是完成子任务 $a$ 的价值,$C_i(s, a)$完成函数——即子任务结束后继续完成父任务 $i$ 所带来的额外价值。由于 $V_a$ 仅依赖于 $a$ ,所有调用 $a$ 的父任务均可复用同一份 $V_a$ ,这正是样本效率提升的来源。

MAXQ 任务层次:原语在多个父任务间共用

但 MAXQ 的代价是只保证递归最优性而非全局最优性:其策略是在给定任务分解下的最优解。若任务图无法表达真正的最优策略,MAXQ 便无法找到它。

二、Feudal RL:用连续子目标替代离散选项#

Feudal RL:manager 输出隐式目标,worker 基于该目标行动。

离散选项难以扩展:在连续控制或像素输入场景中,我们无法手工枚举出有用的选项集合。Feudal Networks(FuN,Vezhnevets 等,2017)和 HIRO(Nachum 等,2018)提出用高层 Manager 输出的连续目标向量取代离散选项。

Feudal RL:Manager 每 c 步设一次目标,Worker 每步执行

$$r^{\text{int}}_t = \cos\!\big(s_{t+c} - s_t,\, g_t\big),$$

而 Manager 则基于环境的外部奖励进行训练。这种解耦设计正是 Feudal 架构的优势所在:Worker 在稠密、几何化的内在奖励上学习运动控制,Manager 则专注于长时程信用分配,有效时序长度缩短为 $T/c$

HIRO 的子目标重标注技巧#

$$\tilde g_t = \arg\max_{g} \log \pi_\phi(a_{t:t+c} \mid s_{t:t+c},\, g).$$

此举确保 Worker 的训练数据始终与其当前参数保持一致,显著提升了 Manager 的离线学习稳定性。

三、目标条件 RL 与 HER#

目标条件策略 $\pi(a \mid s, g)$ 值得单独讨论,因为它是连接层次化与元学习的桥梁:同一网络可追求多种目标,而目标 $g$ 仅是一个额外输入。

目标条件策略与 4 条来自同一网络的轨迹

经典形式是 通用值函数逼近器(UVFA,Schaul 等,2015):学习 $V(s, g)$$Q(s, a, g)$ 而非传统的 $V(s)$$Q(s, a)$ 。但若无额外技巧,UVFA 在稀疏奖励下表现极差——大多数目标在探索中从未达成,奖励信号几乎为零。

$$(s_t, a_t, r, s_{t+1}, g) \;\longrightarrow\; (s_t, a_t, r', s_{t+1},\, g' = s_T).$$

结合离线策略算法(DDPG、SAC),HER 将稀疏奖励下的目标达成任务从“几乎不可能”变为“常规操作”。

四、Meta-RL:学会学习#

强化学习(十一):层次化强化学习与元学习 — 章节小结图

Meta-RL 不再假设单一 MDP,而是考虑一个任务分布 $p(\mathcal{T})$ 。元训练阶段,智能体接触大量任务 $\mathcal{T}_i \sim p(\mathcal{T})$ ;元测试阶段,面对新任务时需以最少交互完成适应。

任务分布与新任务上的适应曲线

主流方法分为两类:

  • 基于优化(MAML、Reptile、ANIL):适应 = 在测试任务上执行几步梯度更新。
  • 基于上下文 / 循环(RL²、PEARL):适应 = 数据流入时更新 RNN 隐藏状态,测试时无需梯度计算。

MAML —— 学习一个良好的初始化#

$$ \theta_i' = \theta - \alpha \nabla_\theta \mathcal{L}_{\mathcal{T}_i}(\theta), \qquad \theta \leftarrow \theta - \beta \nabla_\theta \sum_{i} \mathcal{L}_{\mathcal{T}_i}(\theta_i'). $$

外层梯度需穿过内层更新反向传播,因此包含 Hessian 项 $\nabla^2 \mathcal{L}$ ,这也是 MAML 计算昂贵的原因。FOMAML 直接忽略二阶项,实证表明其每次外层更新快约 $10\times$ ,最终回报损失不到 5%。

MAML 在参数空间中的几何意义与两层循环算法

左图提供了最直观的理解:元训练并非寻找对单个任务最优的初始化,而是寻找一个“甜区”——从这里出发,一步梯度即可接近各任务的特定最优解。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import torch
import torch.nn as nn

class GaussianPolicy(nn.Module):
    """连续控制下的对角高斯策略"""

    def __init__(self, state_dim=2, action_dim=2, hidden=64):
        super().__init__()
        self.trunk = nn.Sequential(
            nn.Linear(state_dim, hidden), nn.ReLU(),
            nn.Linear(hidden, hidden), nn.ReLU(),
        )
        self.mean = nn.Linear(hidden, action_dim)
        self.log_std = nn.Parameter(torch.zeros(action_dim))

    def sample(self, state):
        h = self.trunk(state)
        mean = torch.tanh(self.mean(h))
        std = self.log_std.exp().clamp(1e-3, 1.0)
        dist = torch.distributions.Normal(mean, std)
        a = dist.rsample()
        return a, dist.log_prob(a).sum(-1)

class MAML:
    """REINFORCE 风格策略梯度的一阶或二阶 MAML"""

    def __init__(self, policy, inner_lr=0.1, outer_lr=1e-3,
                 first_order=False):
        self.policy = policy
        self.inner_lr = inner_lr
        self.first_order = first_order
        self.opt = torch.optim.Adam(policy.parameters(), lr=outer_lr)

    def _rollout(self, env, max_steps=50):
        state = env.reset()
        rewards, log_probs = [], []
        for _ in range(max_steps):
            s = torch.as_tensor(state, dtype=torch.float32).unsqueeze(0)
            a, lp = self.policy.sample(s)
            state, r, done = env.step(a.detach().numpy()[0])
            rewards.append(r)
            log_probs.append(lp)
            if done:
                break
        return rewards, log_probs

    @staticmethod
    def _returns(rewards, gamma=0.99):
        G, out = 0.0, []
        for r in reversed(rewards):
            G = r + gamma * G
            out.insert(0, G)
        out = torch.as_tensor(out, dtype=torch.float32)
        return (out - out.mean()) / (out.std() + 1e-8)

    def _loss(self, rewards, log_probs):
        returns = self._returns(rewards)
        return -(torch.stack(log_probs) * returns).mean()

    def adapt(self, env):
        """在 env 上做一步内层更新,返回适应后的参数列表"""
        rewards, log_probs = self._rollout(env)
        loss = self._loss(rewards, log_probs)
        grads = torch.autograd.grad(
            loss, self.policy.parameters(),
            create_graph=not self.first_order,
        )
        return [p - self.inner_lr * g
                for p, g in zip(self.policy.parameters(), grads)]

    def meta_step(self, task_envs):
        meta_loss = 0.0
        for env in task_envs:
            adapted = self.adapt(env)
            # 暂存原参数,将适应后的参数装入网络进行评估前向
            backup = [p.detach().clone() for p in self.policy.parameters()]
            for p, a in zip(self.policy.parameters(), adapted):
                p.data = a.data
            rewards, log_probs = self._rollout(env)
            meta_loss += self._loss(rewards, log_probs)
            for p, b in zip(self.policy.parameters(), backup):
                p.data = b
        meta_loss /= len(task_envs)

        self.opt.zero_grad()
        meta_loss.backward()
        self.opt.step()
        return meta_loss.item()

上述实现通过替换权重后执行前向传播完成元评估,而非使用函数式前向传播。这是最简洁易读的版本,对小型网络已足够。若用于研究级 MAML,建议使用 highertorch.func.functional_call 等函数式 API。

RL² —— 将算法折叠进 RNN#

$$x_t = (s_t,\, a_{t-1},\, r_{t-1},\, d_{t-1}),$$

即状态加上前一步的动作、奖励和终止标志。在元试验的多个回合中,隐藏状态 $h_t$ 不断累积当前任务信息——本质上隐式执行贝叶斯信念更新。元训练时,外层优化器(PPO 或 A2C)调整 RNN 权重,使这套“内置 RL 算法”在 $p(\mathcal{T})$ 上具备高效样本利用率。

RL² 在跨多个回合的元试验上的展开

RL² 有两大优势:(i) 测试时无需梯度计算,每步适应仅需一次前向传播;(ii) 适应过程是学出来的,原则上可在训练分布上超越任何手工设计的优化器。代价是元训练时信用分配困难——梯度需流经横跨多回合的数百个循环步骤。

五、常见问题#

Options 框架为何能加速学习?
三重效应叠加:(i) 有效时序长度从 $T$ 缩至约 $T/\bar k$ ;(ii) 高层分支因子 $|\mathcal{O}|$ 通常远小于 $|\mathcal{A}|$ ;(iii) intra-option 学习使每条原始转移都能贡献给所有兼容选项的价值,而非仅当前控制的那个。

层次化最优与全局最优有何区别?
层次化最优策略是在给定分解(选项集或任务图)下的最优解;全局最优策略是底层扁平 MDP 上的最优解。只要分解无法表达真正最优策略,二者就会偏离——例如,一个至少运行 10 步的选项无法实现每 3 步切换行为的策略。

MAML 为何需要二阶梯度?FOMAML 损失有多大?
元损失为 $\mathcal{L}_{\mathcal{T}_i}(\theta_i')$ ,其中 $\theta_i' = \theta - \alpha \nabla_\theta \mathcal{L}_{\mathcal{T}_i}(\theta)$ 。对 $\theta$ 求导得 $(I - \alpha \nabla^2_\theta \mathcal{L}_{\mathcal{T}_i})\, \nabla_{\theta_i'} \mathcal{L}_{\mathcal{T}_i}(\theta_i')$ ,包含 Hessian。FOMAML 忽略 $-\alpha \nabla^2 \mathcal{L}$ 项,将 $\theta_i'$ 视为 stop-gradient。原论文报告,在标准小样本基准上性能损失 <5%。

何时用 MAML,何时用 RL²?
若适应时可计算梯度且任务分布较广(固定策略无法覆盖所有任务),选 MAML;若任务族较窄、偏向利用(如 arms 动态变化的多臂老虎机),或测试时无法计算梯度,选 RL²。PEARL 通过独立编码器推断任务嵌入,常是不错的折中。

HER 为何仅适用于离线策略算法?
HER 修改了转移对应的目标,违反了在线策略算法的假设:生成数据的动作分布依赖于原始目标,而非重标注后的目标。离线策略算法(DQN、DDPG、SAC)只需在更新时知道 $\pi(a \mid s, g')$ ,而该值可计算,因此重标注无害。


参考文献#

  1. Sutton, Precup & Singh. Between MDPs and semi-MDPs: A framework for temporal abstraction in reinforcement learning. Artificial Intelligence, 1999.
  2. Dietterich. Hierarchical Reinforcement Learning with the MAXQ Value Function Decomposition. JAIR, 2000.
  3. Vezhnevets et al. FeUdal Networks for Hierarchical Reinforcement Learning. ICML 2017. arXiv:1703.01161 .
  4. Nachum et al. Data-Efficient Hierarchical Reinforcement Learning (HIRO). NeurIPS 2018. arXiv:1805.08296 .
  5. Schaul et al. Universal Value Function Approximators. ICML 2015.
  6. Andrychowicz et al. Hindsight Experience Replay. NeurIPS 2017. arXiv:1707.01495 .
  7. Finn, Abbeel & Levine. Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks. ICML 2017. arXiv:1703.03400 .
  8. Duan et al. RL$^2$ : Fast Reinforcement Learning via Slow Reinforcement Learning. 2016. arXiv:1611.02779 .
  9. Wang et al. Learning to reinforcement learn. 2016. arXiv:1611.05763 .
  10. Rakelly et al. Efficient Off-Policy Meta-RL via Probabilistic Context Variables (PEARL). ICML 2019.
本系列

强化学习 12 篇

  1. 01 强化学习(一):基础与核心概念
  2. 02 强化学习(二):Q-Learning 与深度 Q 网络(DQN)
  3. 03 强化学习(三):Policy Gradient 与 Actor-Critic 方法
  4. 04 强化学习(四):探索策略与好奇心驱动学习
  5. 05 强化学习(五):Model-Based 强化学习与世界模型
  6. 06 强化学习(六):PPO 与 TRPO —— 信任域策略优化
  7. 07 强化学习(七):模仿学习与逆强化学习
  8. 08 强化学习(八):AlphaGo 与蒙特卡洛树搜索
  9. 09 强化学习(九):多智能体强化学习
  10. 10 强化学习(十):离线强化学习
  11. 11 强化学习(十一):层次化强化学习与元学习 当前
  12. 12 强化学习(十二):RLHF 与大语言模型应用

读有所得?

GitHub 关注我 → 新文周更

GitHub