欢迎光临
我们一直在努力

强化学习 PPO 算法详解:原理、公式与核心代码

强化学习 PPO 算法详解:原理、公式与核心代码

一、PPO 是什么

PPO 全称为:

Proximal Policy Optimization

中文通常称为:

近端策略优化算法。

PPO 是一种经典的策略梯度强化学习算法,属于:

On-Policy 算法。

也就是说,PPO 主要使用当前策略采集的数据进行训练,然后重新与环境交互获取新的数据。

PPO 可以用于:

离散动作空间

连续动作空间

因此在机器人控制、自动驾驶、游戏智能体等任务中都有较广泛的应用。

PPO 最核心的思想是:

策略可以更新,但是一次不能变化得太大。

如果策略一次更新幅度过大,可能导致训练过程变得不稳定。

因此 PPO 引入了:

Clipping(裁剪)机制

限制新策略和旧策略之间的变化幅度。

整体思想可以概括为:

当前策略与环境交互

采集一批数据

计算 Advantage

比较新策略和旧策略

Clip 限制策略更新幅度

更新 Actor 和 Critic


二、PPO 的 Actor-Critic 结构

PPO 通常采用 Actor-Critic 结构。

其中:

Actor:负责选择动作

Critic:负责评价当前状态

Actor 根据状态输出一个动作概率分布:

πθ(a∣s)\\pi_\\theta(a|s)πθ(as)

其中:

s:当前状态

a:动作

θ:Actor 网络参数

PPO 的 Actor 通常使用随机策略。

例如在离散动作空间中:

向左:0.2

直行:0.6

向右:0.2

然后根据这个概率分布采样一个动作。

整体过程为:

State

Actor

Action Distribution

Sample

Action

Critic 根据当前状态输出:

V(s)V(s)V(s)

整体过程:

State

Critic

V(s)

其中 V(s) 表示:

从当前状态开始,按照当前策略继续执行时,未来累计回报的期望。

因此:

Actor:决定应该做什么

Critic:评价当前状态有多好


三、为什么需要 PPO

普通策略梯度算法的基本思想是:

某个动作表现得好

提高以后选择这个动作的概率

某个动作表现得差

降低以后选择这个动作的概率

但是存在一个问题:

如果策略一次更新幅度太大,训练可能变得不稳定。

例如:

旧策略采集了一批数据

使用这批数据更新 Actor

Actor 参数变化过大

新策略与旧策略差距过大

训练稳定性下降

PPO 的解决方法就是:

允许策略学习

但是限制一次更新的幅度

因此 PPO 引入新旧策略的:

Probability Ratio

再利用:

Clip

对这个比例进行限制。


四、PPO 的概率比率

假设旧策略为:

πθold(at∣st)\\pi_{\\theta_{old}}(a_t|s_t)πθold(atst)

当前正在优化的新策略为:

πθ(at∣st)\\pi_\\theta(a_t|s_t)πθ(atst)

PPO 定义新旧策略的概率比率:

ρt(θ)=πθ(at∣st)πθold(at∣st)\\rho_t(\\theta)=\\frac{\\pi_\\theta(a_t|s_t)}{\\pi_{\\theta_{old}}(a_t|s_t)}ρt(θ)=πθold(atst)πθ(atst)

这个比例反映:

新策略选择当前动作的概率,相比旧策略发生了多大变化。

例如:

旧策略选择动作 a 的概率:

0.4

新策略选择动作 a 的概率:

0.44

那么:

ratio = 0.44 / 0.4

= 1.1

如果:

ratio = 1

表示新旧策略对这个动作的选择概率没有变化。

如果:

ratio > 1

表示新策略更倾向于选择这个动作。

如果:

ratio < 1

表示新策略降低了这个动作的选择概率。

实际代码中通常使用 Log Probability 计算:

ratio = torch.exp(
new_log_prob old_log_prob
)

因为:

πθ(a∣s)πθold(a∣s)=exp⁡(log⁡πθ(a∣s)−log⁡πθold(a∣s))\\frac{\\pi_\\theta(a|s)}{\\pi_{\\theta_{old}}(a|s)}=\\exp\\left(\\log\\pi_\\theta(a|s)-\\log\\pi_{\\theta_{old}}(a|s)\\right)πθold(as)πθ(as)=exp(logπθ(as)logπθold(as))


五、Advantage 优势函数

仅仅知道新旧策略的变化还不够。

PPO 还需要知道:

当前执行的这个动作,到底比原本预期更好还是更差?

这就是:

Advantage Function

优势函数。

记作:

AtA_tAt

可以简单理解为:

Advantage > 0

说明这个动作表现比预期更好

应该提高这个动作的概率

Advantage < 0

说明这个动作表现比预期更差

应该降低这个动作的概率

PPO 中通常使用 GAE:

Generalized Advantage Estimation

来计算 Advantage。

首先计算 TD Error:

δt=rt+γ(1−dt)V(st+1)−V(st)\\delta_t=r_t+\\gamma(1-d_t)V(s_{t+1})-V(s_t)δt=rt+γ(1dt)V(st+1)V(st)

然后从后向前计算:

At=δt+γλ(1−dt)At+1A_t=\\delta_t+\\gamma\\lambda(1-d_t)A_{t+1}At=δt+γλ(1dt)At+1

其中:

r_t:当前奖励

γ:折扣因子

λ:GAE 参数

d_t:当前状态是否终止

得到 Advantage 后,可以进一步计算 Critic 的学习目标:

Rt=At+V(st)R_t=A_t+V(s_t)Rt=At+V(st)


六、PPO 最核心的 Clip 机制

PPO 最重要的部分就是:

Clipped Objective

定义:

LCLIP(θ)=Et[min⁡(ρt(θ)At,clip⁡(ρt(θ),1−ϵ,1+ϵ)At)]L^{CLIP}(\\theta)=E_t\\left[\\min\\left(\\rho_t(\\theta)A_t,\\operatorname{clip}(\\rho_t(\\theta),1-\\epsilon,1+\\epsilon)A_t\\right)\\right]LCLIP(θ)=Et[min(ρt(θ)At,clip(ρt(θ),1ϵ,1+ϵ)At)]

其中:

ρ_t:

新旧策略概率比率

A_t:

Advantage

ε:

Clip 范围

例如:

clip_epsilon = 0.2

那么裁剪范围就是:

[0.8, 1.2]

即:

[1−ϵ,1+ϵ][1-\\epsilon,1+\\epsilon][1ϵ,1+ϵ]


为什么需要 Clip?

假设某个动作:

Advantage > 0

说明这个动作表现得比较好。

因此我们希望:

提高以后选择这个动作的概率

但是不能无限提高。

如果:

ratio = 1.5

而:

epsilon = 0.2

那么 PPO 的裁剪边界为:

1.2

这样可以避免策略为了追求更高收益而一次改变过大。

同样,当:

Advantage < 0

PPO 也会限制动作概率下降得过多。

所以 PPO 的核心思想可以记成:

策略应该学习

但是每次不要走得太远


七、PPO 的 Actor 和 Critic Loss

1. Actor Loss

PPO 希望最大化:

LCLIP(θ)L^{CLIP}(\\theta)LCLIP(θ)

但是 PyTorch 优化器默认执行的是最小化 Loss,因此:

Lactor=−LCLIP(θ)L_{actor}=-L^{CLIP}(\\theta)Lactor=LCLIP(θ)

对应代码:

ratio = torch.exp(
new_log_prob old_log_prob
)

surr1 = ratio * advantages

surr2 = torch.clamp(
ratio,
1 self.clip_epsilon,
1 + self.clip_epsilon
) * advantages

actor_loss = torch.min(
surr1,
surr2
).mean()

其中:

surr1:

没有进行裁剪的策略目标

surr2:

经过 Clip 限制后的策略目标


2. Critic Loss

Critic 负责预测:

V(st)V(s_t)V(st)

目标值为:

RtR_tRt

因此最基本的 Critic Loss 为:

Lcritic=(V(st)−Rt)2L_{critic}=\\left(V(s_t)-R_t\\right)^2Lcritic=(V(st)Rt)2

对应代码:

values = self.critic(states)

critic_loss = F.mse_loss(
values,
returns
)

Critic 的作用就是:

让预测的 V(s)

逐渐接近真实的 Return


八、Entropy 的作用

PPO 中通常还会使用:

Entropy Bonus

也就是熵奖励。

如果 Actor 很快变成:

动作 A:0.99

动作 B:0.005

动作 C:0.005

说明策略几乎只会选择动作 A。

如果过早出现这种情况:

探索能力下降

可能过早收敛

难以发现更好的策略

因此可以利用 Entropy 鼓励 Actor 保留一定随机性。

常见的总体损失形式为:

L=Lactor+c1Lcritic−c2H(π)L=L_{actor}+c_1L_{critic}-c_2H(\\pi)L=Lactor+c1Lcriticc2H(π)

其中:

L_actor:Actor Loss

L_critic:Critic Loss

H(π):策略熵

c1:Critic Loss 系数

c2:Entropy 系数

Entropy 越大,通常说明策略分布越具有随机性,因此可以帮助智能体保持一定探索能力。


九、PPO 完整训练流程

PPO 一般不会像 DDPG、TD3 那样长期使用 Replay Buffer 保存大量历史数据。

它通常先使用当前策略采集一批 Rollout 数据,然后利用这一批数据进行若干轮优化。

完整流程可以表示为:

1. 使用当前 Actor 与环境交互

2. 保存 State、Action、Reward

Done、Log Probability、Value

3. 获得一批 Rollout 数据

4. 计算 Advantage 和 Return

5. 使用当前策略重新计算 Log Probability

6. 计算新旧策略 Probability Ratio

7. 使用 Clip 计算 Actor Loss

8. 计算 Critic Loss

9. 计算 Entropy

10. 更新 Actor 和 Critic

11. 对当前数据训练若干 Epoch

12. 重新与环境交互采集新数据

核心过程:

State


Actor


Action


Environment


Reward


Advantage


Probability Ratio


Clip


Actor Loss


十、PPO 核心 PyTorch 训练代码

下面给出 PPO 最核心的更新逻辑。

假设已经计算得到:

states

actions

old_log_probs

returns

advantages

核心代码如下:

def update(
self,
states,
actions,
old_log_probs,
returns,
advantages
):

# Advantage 标准化
advantages = (
advantages advantages.mean()
) / (
advantages.std() + 1e-8
)

# 对当前 Rollout 数据训练多个 Epoch
for _ in range(self.update_epochs):

# =========================
# Actor
# =========================

dist = self.actor(states)

new_log_probs = dist.log_prob(actions)

# 连续多维动作时对动作维度求和
if new_log_probs.dim() > 1:
new_log_probs = new_log_probs.sum(
dim=1,
keepdim=True
)

# 新旧策略概率比率
ratio = torch.exp(
new_log_probs old_log_probs
)

# PPO Clip
surr1 = ratio * advantages

surr2 = torch.clamp(
ratio,
1 self.clip_epsilon,
1 + self.clip_epsilon
) * advantages

# Entropy
entropy = dist.entropy()

if entropy.dim() > 1:
entropy = entropy.sum(dim=1)

entropy = entropy.mean()

# Actor Loss
actor_loss = (
torch.min(
surr1,
surr2
).mean()
self.entropy_coef * entropy
)

# =========================
# Critic
# =========================

values = self.critic(states)

critic_loss = F.mse_loss(
values,
returns
)

# =========================
# 更新 Actor
# =========================

self.actor_optimizer.zero_grad()

actor_loss.backward()

self.actor_optimizer.step()

# =========================
# 更新 Critic
# =========================

self.critic_optimizer.zero_grad()

critic_loss.backward()

self.critic_optimizer.step()

这段代码对应 PPO 最核心的几个过程:

torch.exp(new_log_probs – old_log_probs)

→ 计算新旧策略 Probability Ratio

torch.clamp(…)

→ 限制策略更新幅度

torch.min(surr1, surr2)

→ PPO Clip Objective

advantages

→ 判断动作比预期更好还是更差

critic_loss

→ 更新状态价值函数

entropy

→ 保持一定探索能力


十一、PPO 与 DDPG、TD3 的区别

PPO、DDPG 和 TD3 都可以用于连续控制,但是训练方式存在明显区别。

对比内容PPODDPGTD3
算法类型 On-Policy Off-Policy Off-Policy
策略 随机策略 确定性策略 确定性策略
Actor
Critic V(s) Q(s,a) Twin Q(s,a)
长期 Replay Buffer 不使用 使用 使用
核心机制 Clip 确定性策略梯度 Twin Critic + Delay + Smoothing
主要探索方式 策略分布采样 Action Noise Action Noise

PPO 最核心的特点是:

限制策略每次更新的幅度

DDPG 的核心是:

Actor 直接生成连续动作

TD3 则是在 DDPG 的基础上,通过双 Critic、延迟策略更新和目标策略平滑进一步提高训练稳定性。


十二、PPO 核心公式总结

PPO 最重要的公式可以总结为以下几个。

1. Probability Ratio

ρt(θ)=πθ(at∣st)πθold(at∣st)\\rho_t(\\theta)=\\frac{\\pi_\\theta(a_t|s_t)}{\\pi_{\\theta_{old}}(a_t|s_t)}ρt(θ)=πθold(atst)πθ(atst)


2. TD Error

δt=rt+γ(1−dt)V(st+1)−V(st)\\delta_t=r_t+\\gamma(1-d_t)V(s_{t+1})-V(s_t)δt=rt+γ(1dt)V(st+1)V(st)


3. GAE

At=δt+γλ(1−dt)At+1A_t=\\delta_t+\\gamma\\lambda(1-d_t)A_{t+1}At=δt+γλ(1dt)At+1


4. PPO Clip Objective

LCLIP(θ)=Et[min⁡(ρt(θ)At,clip⁡(ρt(θ),1−ϵ,1+ϵ)At)]L^{CLIP}(\\theta)=E_t\\left[\\min\\left(\\rho_t(\\theta)A_t,\\operatorname{clip}(\\rho_t(\\theta),1-\\epsilon,1+\\epsilon)A_t\\right)\\right]LCLIP(θ)=Et[min(ρt(θ)At,clip(ρt(θ),1ϵ,1+ϵ)At)]


5. Actor Loss

Lactor=−LCLIP(θ)L_{actor}=-L^{CLIP}(\\theta)Lactor=LCLIP(θ)


6. Critic Loss

Lcritic=(V(st)−Rt)2L_{critic}=\\left(V(s_t)-R_t\\right)^2Lcritic=(V(st)Rt)2


十三、总结

PPO 是一种经典的 On-Policy 策略优化算法。

它采用 Actor-Critic 结构:

Actor

负责产生动作概率分布

Critic

负责估计状态价值 V(s)

PPO 最核心的问题是:

如何在优化策略的同时,避免新策略一次偏离旧策略太远?

PPO 的解决方法是:

计算新旧策略概率比率

Probability Ratio

结合 Advantage 判断更新方向

使用 Clip 限制更新幅度

更新 Actor

PPO 最核心的目标函数为:

LCLIP(θ)=Et[min⁡(ρt(θ)At,clip⁡(ρt(θ),1−ϵ,1+ϵ)At)]L^{CLIP}(\\theta)=E_t\\left[\\min\\left(\\rho_t(\\theta)A_t,\\operatorname{clip}(\\rho_t(\\theta),1-\\epsilon,1+\\epsilon)A_t\\right)\\right]LCLIP(θ)=Et[min(ρt(θ)At,clip(ρt(θ),1ϵ,1+ϵ)At)]

整个 PPO 的训练过程可以概括为:

当前策略采集数据

计算 Advantage

计算新旧策略 Probability Ratio

使用 Clip 限制更新范围

更新 Actor

更新 Critic

重新采集数据

理解 PPO 最重要的是理解三个问题:

Advantage 表示什么?

为什么需要比较新策略和旧策略?

为什么 PPO 要使用 Clip 限制策略更新?

理解这三个问题以及 PPO 的完整训练流程,就基本掌握了 PPO 的核心原理。

赞(0)
未经允许不得转载:171主机测评 » 强化学习 PPO 算法详解:原理、公式与核心代码
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址