PPO
Proximal Policy Optimization Algorithms
两阶段循环
为什么可以“多轮”
通常情况下,如果对同一批数据进行多轮优化,策略会因为更新过头而崩溃。但 PPO 引入了 Clipped Objective(裁剪目标函数):
- 安全护栏:在每一轮优化中,PPO 会计算新策略和采样时的旧策略的概率比。如果这个比值超出了设定的范围(比如 ),梯度就会被“截断”。
- 效果:这确保了即使在这一批数据上反复“薅羊毛”优化,新策略也不会跑得离旧策略太远,从而保证了训练的稳定性。
1. 采样阶段 (Sampling Phase)
- 动作:让当前的策略 在环境中运行一段时间。
- 产出:收集一批轨迹数据(包括状态 、动作 、奖励 等)。
- 性质:这些数据是“新鲜”的,反映了当前策略的行为模式。
在这个阶段,神经网络的参数是固定不动的(即 )。Actor (策略网络):在环境中根据概率分布选择动作。数据收集:把 存入一个临时的 Buffer。目标:收集足够数量的轨迹(比如 2048 个时间步)。
1.1. 计算“标签” (Preprocessing)
在开始训练前,利用收集到的数据计算两个关键值:
- (Advantage):优势函数,用来衡量这个动作比平均水平好多少。
- (Returns):这一步动作带来的累积奖励。
注意到
- :新旧策略概率比(用于 Actor)。
- :优势估计(用于 Actor,决定更新方向)。
- :回报目标值(用于 Critic,提升估值精度)。
如果只用即时奖励 作为目标,Critic 就会变得非常“短视”。即时奖励 :只代表当前这一秒好不好。回报目标 :代表了“做出这个动作后,直到最后我一共拿了多少分”。目的:我们希望 Critic 能够预判未来。所以我们要让 去拟合这个 。
(Returns):作为 Critic 网络的监督信号(标签)。
- 计算逻辑:通过 (优势)与采样时旧的 相加得到:。
- 物理意义:它代表了在当前策略下,从状态 开始预期能获得的折现总奖励。Critic 的优化目标就是让预测值 尽可能接近这个 。
这意味着:
- 先用 GAE 算出了优势估计 。
- 通过 ,你就反向推导出了这一步动作对应的“目标回报” 。
- 价值损失 (Value Loss) 就变成了:。
总结
- Actor:利用 (相对好坏)来决定 的更新方向。
- Critic:利用 (绝对得分)来修正自己对世界的认知。
2. 优化阶段 (Optimization Phase)
多轮优化 (Several Epochs):
- 动作:将刚才采样的这一批数据反复输入神经网络进行多次梯度更新。
- 关键点:在传统的 On-policy 算法(如普通的策略梯度)中,这批数据更新一次就必须扔掉。但 PPO 允许你在同一批数据上跑 3 轮、5 轮甚至 10 轮(Epochs)。
要把 Buffer 里的数据,分成更小的 Mini-batches,重复训练 个 Epochs(比如 )。在每一个 Epoch 里的微观操作:计算概率比 :用当前正在更新的 计算动作概率,除以采样时的 计算的概率。应用裁剪 :如果 偏离 1 太远(比如超过 20%),就强行截断。梯度更新:通过反向传播更新参数 。
为什么 允许“多轮更新”。PPO 能够从 On-policy 转向近乎 Off-policy 的理论支柱,PPO 本质上是利用了重要性采样技术。
- 理论背景:我们想优化新策略 ,但手里只有旧策略 采到的数据。
- 补偿机制:通过概率比率 ,我们修正了数据分布的偏差。
- 约束:重要性采样要求两个分布不能差太远,否则方差会爆炸。这正是 存在的根本原因——它在数学上维护了重要性采样的有效区间。
2.1. 优势估计
通常采用 GAE (Generalized Advantage Estimation)。
简单来说,优势函数 的目标是回答:“在状态 下采取动作 ,比平均情况(即 Baseline)好多少?”
2.1.1. 计算时序差分残差(Temporal Difference Error)
首先计算每一个时间步的即时偏差 。它衡量了“实际观测到的奖励 + 下一步的估值”与“当前估值”之间的差距:
- :当前步获得的奖励。
- :神经网络(Critic)对下一步状态的估值。
- :神经网络(Critic)对当前状态的估值。
2.1.2. 累加衰减
[0, T)
优势估计 不是只看当前这一步,而是要把未来的 都考虑进来,但要进行指数衰减。公式如下:
这里有两个关键的超参数:
- (Gamma):折扣因子(通常 0.99),决定了对远期奖励的重视程度。
- (Lambda):GAE 因子(通常 0.95),用于在偏差(Bias)和方差(Variance)之间做权衡。
实现时,逆序(t)计算
-
如果 :。这叫 1-step TD。它很稳定(方差小),但如果你的 函数估值不准,它就会错得离谱(偏差大)。
-
如果 : 变成了从当前步到截断点 的所有奖励累加。这很真实(无偏差),但环境随机性太强,导致数值跳变剧烈(方差大)。
这就是 用于在偏差(Bias)和方差(Variance)之间做权衡的物理意义。PPO 选取 它在“相信神经网络的估值”和“相信实际观测到的奖励”之间取了一个折中。
2.1.3. 标准化 (Advantage Normalization)
在算出 个时间步的所有 后,工程上通常会进行一次标准化处理:
- 稳定梯度:在一个 Batch 中,优势值的数值跨度可能很大。标准化后,它们的均值为 0,标准差为 1。
- 逻辑闭环:这确保了在一个 Batch 里,大约有一半的动作会被认为是“好于平均”(正值,增加概率),另一半是“差于平均”(负值,减小概率)。这对于 Adam 优化器的稳定收敛极其重要。
总结计算流程
- 运行 步采样,收集所有的 概率比例和 状态价值。
- 从后往前计算(这样可以用 算出 ):
- 对整个 Batch 进行标准化。
- 将算好的 输入 进行优化。
2.2. 损失函数
优势估计 和概率比率 都准备好了,进入 PPO 执行阶段构建 Loss 函数并进行参数更新
Adam 优化器并不是只优化策略,它其实是在同时优化三个目标。
总损失函数 通常长这样:
这三个部分分工明确:
- (策略损失):利用 和 进行裁剪优化。它负责告诉 Actor:“哪些动作该多做,但别改得太猛。”
- (价值损失):通常是均方误差 。它负责告诉 Critic:“你的预言(估值)要更准一点。”
- (熵奖励):鼓励策略保持一定的随机性。它负责告诉模型:“别太早固定死某一个动作,多去探索其他可能性。”
MSE 均方误差
2.2.1. 执行 Adam 更新
Adam 优化器, 梯度下降 (Gradient Descent)
有了总损失后,流程如下:
- 计算梯度:对总损失关于参数 求导(即之前提到的 )。
- 反向传播:将梯度传回神经网络。
- 参数更新:Adam 优化器根据动量和自适应学习率微调 。
进入 个 Epoch 的循环
针对同一批采样数据(那 个样本),反复进行 次上述的“计算 Loss -> 更新参数”过程。
- 在第 1 遍时:,大家都在正常学习。
- 在第 遍时:由于参数已经改了好几次,新旧策略的偏差 可能会很大。这时候 Clipping(裁剪) 就会大显身手,强行把那些偏移过大的梯度归零,防止模型跑飞。
注:虽然 PPO 的理论目标是最大化奖励,但在代码实现中,我们通过对总目标函数取负值,将其转化为一个最小化损失的问题,从而利用 Adam 优化器进行参数更新。
2.2.2. 更新旧策略 ()
当 次迭代结束,这一批数据的价值就被“榨干”了。
此时,我们将当前的最新参数 赋值给 。然后清空缓存的数据,回到环境里,开启下一轮 的数据采集。
3. Hyperparameters 参考
| 参数 | 常用值 | 作用 |
|---|---|---|
| 裁剪阈值,限制单次更新步长 | ||
| 长期奖励折扣因子 | ||
| GAE 平衡因子 | ||
| 价值损失权重(MSE 权重) | ||
| 熵系数(鼓励探索,防止过早收敛) | ||
| 每个 Batch 的重复训练次数(Epochs) |