Brief Reinforcement Learning 01 - Proximal Policy Optimization (PPO) 简单理解近端策略优化

First Post:

Last Update:

Word Count:
5.6k

Read Time:
22 min

Page View: loading...

写在前面

PPO 原文: https://arxiv.org/abs/1707.06347
TRPO 原文: https://arxiv.org/abs/1502.05477

目录

  1. 强化学习基础概念
  2. 从 Q-Learning 到 Policy Gradient
  3. PPO 是什么?
  4. PPO 算法详解
  5. 实例:用 PPO 玩转石头剪刀布
  6. 附录:数学推导

强化学习基础概念

在深入 PPO 之前,我们首先需要理解一些强化学习(Reinforcement Learning, RL)的基本构建块。想象一个智能体(Agent)在一个环境(Environment)中学习,它通过不断地试错来最大化自己获得的奖励。

  • 策略 (Policy):
    策略是智能体的大脑,它定义了智能体在特定状态下 会采取什么动作 。策略可以有两种形式:

    • 确定性策略 (Deterministic Policy): ,在每个状态下,动作是确定的。
    • 随机性策略 (Stochastic Policy): ,在每个状态下,策略会给出一个采取各个动作的概率分布。PPO 处理的是随机性策略。
  • 动作 (Action):
    智能体根据其策略在环境中执行的操作。例如,在游戏中是按下某个按钮,在机器人控制中是移动某个关节。

  • 奖励 (Reward):
    当智能体执行一个动作后,环境会反馈一个标量信号——奖励。这个信号评价了这个动作的好坏。智能体的最终目标是最大化累积奖励(Cumulative Reward)。

  • 轨迹 (Trajectory):
    智能体与环境交互产生的一系列状态、动作和奖励的序列,可以表示为

  • 价值函数 (Value Function) 与 Critic
    价值函数用来评估一个状态或一个状态-动作对的“好坏”程度,即从该点出发,预期未来能获得多少总奖励。

    • 状态价值函数 (State-Value Function) : 从状态 出发,遵循策略 ,所能获得的期望总回报。
    • 动作价值函数 (Action-Value Function) : 在状态 下,执行动作 ,然后遵循策略 ,所能获得的期望总回报。
      在 Actor-Critic 架构中,Critic(评论家) 的角色就是学习并输出价值函数,它的作用是“评价”当前 Actor 的表现好坏,但它自己不决定做什么动作。
  • 演员 (Actor)
    Actor(演员) 的角色是学习并执行策略 。它根据当前状态 ,决定要采取哪个动作 。Actor 的目标是调整策略,以获得更高的总回报。

  • 优势函数 (Advantage Function):
    优势函数是衡量在状态 下,采取动作 相对于遵循当前策略 的平均表现有多好。它的计算公式是:

    • 如果 , 说明动作 比平均水平要好。
    • 如果 , 说明动作 比平均水平要差。

    优势函数是 PPO 算法中的一个核心概念,它告诉我们策略更新应该朝哪个方向进行。

从 Q-Learning 到 Policy Gradient

传统的 Q-Learning 是一种基于价值的方法。它通过学习一个最优的动作价值函数 来间接得到最优策略。其策略通常是贪婪的:在状态 下,选择使 值最大的动作 。这种方法在处理连续动作空间或需要随机策略时会遇到困难。

为了解决这些问题,策略梯度 (Policy Gradient, PG) 方法应运而生。PG 不再学习价值函数,而是直接对策略 进行参数化( 是神经网络的参数),然后通过梯度上升来优化策略,以最大化期望总回报

PG 的核心思想很简单:如果一个动作带来了好的结果(即高的优势值),我们就增加这个动作被选择的概率;反之,则减少。

然而,朴素的 PG 算法存在一些问题:

  1. 高方差:梯度的估计可能非常不稳定,导致训练过程震荡。
  2. 更新步长难以确定:如果更新步长(学习率)太大,可能会导致策略“崩溃”,即更新后的策略表现急剧下降,且难以恢复。如果步长太小,则训练速度过慢。

PPO 是什么?

近端策略优化 (Proximal Policy Optimization, PPO) 是一种旨在解决策略梯度方法中更新步长问题的算法。它是对 信赖域策略优化 (Trust Region Policy Optimization, TRPO) 的一种简化,在实现上更简单,但效果同样出色。

PPO 流程示意图

下面是一个简化的 PPO 工作流程图:

1
2
3
4
5
6
7
8
9
10
11
12
graph TD
A[Actor: π_θ_old] -- "与环境交互" --> B(收集轨迹 τ);
B -- "计算每个时间步的优势 A_t" --> C;
C[Critic: V_φ] -- "计算V(s_t)辅助计算A_t" --> B;
B -- "将(s_t, a_t, A_t)存入缓冲区" --> D(经验缓冲区);
D -- "重复K个Epoch" --> E{优化循环};
E -- "采样一个Minibatch" --> F(计算PPO目标函数 L_CLIP);
F -- "计算梯度 ∇_θ L_CLIP" --> G(更新Actor网络参数 θ);
E -- "采样一个Minibatch" --> H(计算价值损失 L_VF);
H -- "计算梯度 ∇_φ L_VF" --> I(更新Critic网络参数 φ);
G & I -- "K个Epoch结束后" --> J[新策略 π_θ];
J -- "π_θ_old ← π_θ" --> A;

PPO 的核心思想

PPO 的核心思想是:在尝试最大化目标函数的同时,使用一个“惩罚”项来限制新旧策略之间的差异,确保每次更新不会让策略变得太离谱。

想象一下你在一个山坡上试图走到山顶(最大化奖励)。朴素的 PG 方法就像是你蒙着眼睛朝你认为最陡峭的方向迈出一大步,但你可能会不小心滚下悬崖(策略崩溃)。PPO 则是在你脚上绑了一根绳子,绳子的另一端固定在你之前的位置。你可以自由地向任何方向迈步,但如果步子迈得太大,绳子就会把你拉回来,防止你摔得太远。

这个“绳子”就是 PPO 中的 Clipping (裁剪) 机制。

PPO 的目标函数 (Objective Function)

PPO 的目标函数是其精髓所在,我们先来看最常用的 PPO-Clip 的目标函数:

让我们来拆解这个复杂的公式:

  • : 表示对一个批次(batch)中所有时间步 的样本取平均。
  • : 这是新旧策略之间的概率比率 (probability ratio)。
    • : 当前正在优化的新策略。
    • : 用于收集数据的旧策略。
    • 如果 , 说明新策略更倾向于采取动作
    • 如果 , 说明新策略不太倾向于采取动作
  • : 这是在时间步 的优势函数 Advantage 的估计值。
  • : 这个函数将概率比率 裁剪到一个范围 内。 是一个超参数,通常取 0.10.2
  • : PPO 的关键部分。它在两个项之间取最小值。

PPO 算法详解

Clipped Surrogate Objective Function

我们来详细分析 函数中的两项:

  1. : 这是标准的策略梯度目标函数。如果优势 是正的,我们会想要增大 (即增加 ),从而最大化这一项。如果 是负的,我们会想要减小

  2. : 这是被裁剪过的版本,是 PPO 的创新之处。

为什么要取

这是一种悲观主义的或者说保守的更新方式。

  • (好动作) 时:

    这意味着,我们希望增加好动作的概率 ( 变大),但是这个增加是有限度的。 最多只能增长到 。这防止了策略因为一个特别好的动作而过度更新,导致在其他状态下表现变差。

  • (坏动作) 时:

    (注意,因为 是负数, 实际上变成了 )。
    这意味着,我们希望减小坏动作的概率 ( 变小),但这个减小也是有限度的。 最少只能减小到 。这防止了策略因为一个坏动作而过度惩罚,导致策略完全放弃探索某些可能在未来有价值的动作。

通过这种方式,PPO 将策略更新限制在了一个“信赖域”内,使得训练过程更加稳定。

价值函数损失 (Value Function Loss)

在 PPO 这种 Actor-Critic 架构中,除了负责决策的 Actor (策略网络),还有一个负责“评价”的 Critic (价值网络)。Critic 的作用是学习状态价值函数 ,即评估处于某个状态 下有多好。这个评估值对于计算优势函数 至关重要,因为 直接指导了 Actor 的更新方向。

价值函数损失就是专门用来训练 Critic 网络的损失函数。它的目标是让 Critic 对状态价值的预测 (其中 是价值网络的参数) 尽可能地接近“真实”的价值。

1. 公式定义

价值函数损失通常是一个简单的均方误差 (Mean Squared Error, MSE):

让我们来解析这个公式:

  • : 表示对一个批次(batch)中所有时间步 的样本取平均。
  • : 这是 Critic 网络对状态 的预测价值。
  • : 这是我们在该时间步观测到的“目标价值”或“真实价值”。它是一个我们希望 Critic 网络输出的目标。

2. 目标价值 是什么?

既然 本身就是对未来总回报的期望,那么最直接的“真实价值”就是我们在该轮游戏中,从状态 开始实际获得的累积回报(也称为 Monte Carlo Return)。

在实际操作中, 通常就是我们计算 GAE (Generalized Advantage Estimation) 时用到的回报估计值。简单来说,它可以是:

这个公式看起来可能有点循环引用,但在计算时, 是从旧的网络中得到的值(value.detach()),而 是已经基于这批数据计算好的优势估计。所以,我们实际上是让新的价值网络去拟合一个更精确的、结合了实际奖励和旧价值估计的目标。

3. 为什么需要这个损失项?

训练 Critic 的目的就是为了给 Actor 提供一个准确的优势函数估计

  • 一个准确的 Critic 能够提供低方差的优势估计,这使得 Actor 的更新更加稳定和高效。如果 Critic 对价值的评估是胡乱猜测的,那么计算出的优势信号也会充满噪声,误导 Actor 的学习方向。
  • 通过最小化 ,我们不断地用实际观测到的回报来校准 Critic 的判断力,让它成为一个越来越可靠的“评论家”。

4. 在 PPO 中的作用

在 PPO 的整体优化目标中,价值损失 是作为辅助损失项存在的。它与 Actor 的策略损失 结合在一起,形成一个总的损失函数:

其中 是价值损失的系数,用于平衡策略学习和价值学习的重要性。这两个网络通常会一起训练,但它们的目标不同:Actor (参数 ) 负责最大化 ,而 Critic (参数 ) 负责最小化

多轮次更新 (Multiple Epochs of Minibatch Updates)

PPO 的另一个重要特点是它可以在同一批数据上进行多次(K个Epoch)的梯度更新。这大大提高了样本的利用效率。传统的 A2C (Advantage Actor-Critic) 算法每收集一批数据只能更新一次网络,而 PPO 可以用这批数据训练好几个 Epoch,只要策略更新不偏离旧策略太远(由 Clip 机制保证)。

PPO 算法流程

下面是 PPO 算法更具体的伪代码:

  1. 初始化: 初始化 Actor 网络 和 Critic 网络 的参数
  2. 循环 (for iteration = 1, 2, …):
    a. 数据收集: 使用当前策略 ,与环境交互 N 个时间步,收集一批轨迹
    b. 优势计算: 对收集到的每个时间步 ,计算优势函数 。通常使用 GAE (Generalized Advantage Estimation) 方法来平衡偏差和方差。

    其中
    c. 优化循环 (for epoch = 1, 2, …, K):

    • 中随机采样一个小批量(Minibatch)数据。
    • 计算 Actor 的损失
    • 计算 Critic 的损失 (均方误差)。 通常是
    • (可选)计算熵损失 ,鼓励探索。
    • 更新 Actor 和 Critic 的网络参数:
  3. 结束

实例:用 PPO 玩石头剪刀布

让我们看一个简单的例子:训练一个 AI 来玩石头剪刀布。

环境设定

  • 对手: 不是完全随机的,而是一个有特定偏好的对手。比如,他出“石头”的概率是 50%,出“剪刀”和“布”的概率各是 25%。
  • 状态 (State): 为了简单起见,我们可以将状态设为对手上一次出的手势。如果游戏是独立的,状态也可以是一个常数。
  • 动作 (Action): 我们的 AI 可以选择出“石头”(0)、“剪刀”(1) 或“布”(2)。
  • 奖励 (Reward):
    • 赢: +1
    • 平: 0
    • 输: -1

模型设计

  • Actor: 一个简单的神经网络。输入是状态(对手上一次的手势,独热编码),输出是三个动作(石头、剪刀、布)的概率分布(通过 Softmax 层)。
  • Critic: 另一个简单的神经网络。输入是状态,输出是一个标量,代表当前状态的价值

训练过程

  1. 初始化: 随机初始化 Actor 和 Critic 网络的权重。我们的 AI 一开始是胡乱出拳的。
  2. 收集数据: 让我们的 AI (Actor) 和有偏好的对手玩,比如玩 100 局。记录下每一局的状态、我们出的动作、以及获得的回报。例如,记录 (= 对手出石头 , = 我出剪刀, = -1)。
  3. 计算优势:
    • 用 Critic 网络预测每一局开始时的状态价值
    • 因为石头剪刀布是单步游戏,优势函数可以简化为
    • 例如,在 (对手上把出石头)时,我们出了“布”赢了 ()。假设 Critic 预测 。那么优势 。这是一个很大的正优势。
  4. PPO 更新:
    • 我们使用收集到的 100 局数据,进行多轮(比如 K=4)优化。
    • 在每一轮中,我们计算 PPO 的 \mathcal{L}CLIP 损失。
    • 对于刚才那个例子,因为 是正的,算法会尝试提高在 状态下出“布”的概率。
    • clip 机制会确保这个概率的提升不会太大,比如 不会超过 1.2。
    • 同时,我们也更新 Critic 网络,让它的预测 更接近实际获得的回报
  5. 重复: 不断地重复步骤 2-4。

结果

经过多轮训练后:

  • Actor 会学到,当对手有 50% 的概率出“石头”时,我应该提高出“布”的概率,这样胜率最高。它的策略会逐渐收敛到一个最优解(高概率出布)。
  • Critic 会学到,在面对这个对手时,游戏的初始状态价值是正的,因为我们有优势。

这个例子展示了 PPO 如何通过与环境交互,稳定地学习到一个能利用环境特性(对手偏好)的策略。


附录:数学推导

这里提供了一些核心概念的数学推导,以供深入理解。

[策略梯度定理推导]

策略梯度定理是策略梯度方法的基础,它表明了目标函数 的梯度可以被写成一个期望的形式,从而可以用蒙特卡洛采样来估计。我们的目标是找到能最大化期望总回报 的策略参数

1. 目标函数定义

首先,我们定义目标函数 为遵循策略 时,所有可能轨迹 的期望总回报。

其中, 是轨迹 的总回报, 是在参数为 的策略下,轨迹 发生的概率。

2. 求目标函数的梯度

我们对目标函数求关于 的梯度:

3. 应用对数导数技巧 (Log-Derivative Trick)

直接计算 很困难。这里我们使用一个关键技巧:。将其应用到 上:

将这个技巧代入梯度公式中:

这个形式正好是某个期望值的定义,所以可以写成:

4. 展开轨迹概率

现在我们来处理 。一条轨迹的概率是初始状态概率和一系列动作概率与状态转移概率的乘积:

对其取对数:

再对其求关于 的梯度。注意到,环境的状态转移概率 和初始状态概率 都与策略参数 无关,所以它们的梯度为零。因此:

5. 得到策略梯度的基本形式

将上式代入第3步的期望公式中,我们得到:

这个公式虽然正确,但方差很大,因为括号里的回报项 会同时乘以过去和未来的所有动作的梯度。

6. 利用因果关系并引入基线以减小方差

一个重要的观察是:在时间步 的决策 只会影响从 时刻开始的未来回报,而不会影响过去已经获得的回报。因此,我们可以将回报项替换为从当前时刻开始的未来回报总和

为了进一步减小方差,我们可以从回报中减去一个不依赖于动作 的基线(baseline)。最常用的基线是状态价值函数 。减去基线不会改变梯度的期望值(因为 ),但可以显著减小梯度的方差。

7. 最终形式:优势函数

我们发现, 正是优势函数 的一个估计。因此,策略梯度定理最终可以写成我们熟悉的形式:

这个形式直观地告诉我们:如果一个动作的优势 是正的,我们就调整参数 来增加这个动作的对数概率 ;反之亦然。这就是策略梯度方法的核心。

[信赖域方法推导]

TRPO (PPO 的前身) 的目标函数可以写成:

这里的 是 KL 散度,用来衡量新旧策略的差异。这个约束确保了策略更新不会偏离旧策略太远,从而保证了训练的稳定性。然而,求解这个带约束的优化问题非常复杂,需要计算二阶导数(Hessian矩阵)。

PPO 通过 clip 函数来近似这个带约束的优化问题,将其转化为一个无约束的、更容易求解的优化问题。PPO 的目标函数可以看作是 TRPO 目标函数的一阶近似的、加了惩罚项的版本,从而大大简化了计算,同时保留了信赖域方法的稳定性。