强化学习-PPO损失函数
一、定义
-
蒙特卡洛方法
-
时序方法
-
多步时序差分方法 (n-step TD)
-
GAE 广义优势估计方法
-
方差高/低的意义
-
PPO 损失函数
二、实现
-
蒙特卡洛方法
核心点:从经验中学习,学习每个时刻状态的价值。即必须完成一个完整的回合(直到终止状态),然后根据整个序列的实际回报来更新这个序列中经过的所有状态的价值。
案例过程:
假设我们采样了一个回合(Episode):
起始状态 9 -> (向右) -> 状态10 (奖励-1) -> (向上) -> 状态6 (奖励-1) -> (向右) -> 状态7 (奖励-1) -> (向下) -> 状态11 (奖励-1) -> (向左) -> 状态10 (奖励-1) -> (向下) -> 状态14 (奖励-1) -> (向右) -> 状态15 (奖励0,终止)这个回合的总回报 G = (-1) + (-1) + (-1) + (-1) + (-1) + (-1) + 0 = -6我们从后往前看,对这个序列中第一次出现的每个状态,用总回报 G 来更新其价值估计:V(9) = V(9) + α * (G - V(9)) (α是学习率,假设为0.1)V(10) = V(10) + α * (G - V(10)) (注意:状态10在序列中出现了两次,但我们只更新它第一次出现时的价值)V(6) = V(6) + α * (G - V(6))V(7) = V(7) + α * (G - V(7))V(11) = V(11) + α * (G - V(11))V(14) = V(14) + α * (G - V(14))
-
时序方法
核心:学习每个时刻状态的价值。它不需要等到回合结束,每一步都可以进行更新。它用当前的估计(TD目标)来更新当前的估计。
需要的参数: 当前动作的奖励、下一个状态的价值估计。
案例过程:
起始状态 9 -> (向右) -> 状态10 (奖励-1) -> (向上) -> 状态6 (奖励-1) -> (向右) -> 状态7 (奖励-1) -> (向下) -> 状态11 (奖励-1) -> (向左) -> 状态10 (奖励-1) -> (向下) -> 状态14 (奖励-1) -> (向右) -> 状态15 (奖励0,终止)步骤1: 状态9 -> (动作:右) -> 状态10,奖励 = -1TD目标 = R + γ * V(10) = -1 + 1 * V(10)TD误差 = TD目标 - V(9) = (-1 + V(10)) - V(9)更新: V(9) = V(9) + α * ( (-1 + V(10)) - V(9) )注意:我们使用了下一个状态 10 的价值估计值 V(10),这就是“自举”。步骤2: 状态10 -> (动作:上) -> 状态6,奖励 = -1TD目标 = -1 + V(6)TD误差 = (-1 + V(6)) - V(10)更新: V(10) = V(10) + α * ( (-1 + V(6)) - V(10) )步骤3: 状态6 -> (动作:右) -> 状态7,奖励 = -1更新: V(6) = V(6) + α * ( (-1 + V(7)) - V(6) )... 以此类推,直到终止状态 15。对于终止状态前的步骤(例如进入15):TD目标 = 0 + γ * V(终止状态)通常约定终止状态的价值为0,所以 TD目标 = 0。
3.多步时序差分方法 (n-step TD)
核心思想: 是MC和TD(0)的折中。它等待 n
步之后,再用 n
步的实际奖励加上第 n
步时的价值估计来共同构造目标。当 n=1 时,就是TD(0);当 n 大到覆盖整个回合时,就是MC。
算法: 以 n=3 为例案例过程:
同样从状态 9 开始。时间t=0: 在状态 S_t = 9执行3步:t=0: 状态9 -> (右) -> 状态10,奖励 R_t+1 = -1t=1: 状态10 -> (上) -> 状态6,奖励 R_t+2 = -1t=2: 状态6 -> (右) -> 状态7,奖励 R_t+3 = -1t=3: 现在位于状态 S_t+3 = 7我们现在有足够的信息来构造 3步回报(3-step return):G_t:t+3 = R_t+1 + γ * R_t+2 + γ² * R_t+3 + γ³ * V(S_t+3)代入 γ=1: G_t:t+3 = (-1) + (-1) + (-1) + V(7) = -3 + V(7)用这个多步回报来更新状态 9 的价值:更新: V(9) = V(9) + α * ( (-3 + V(7)) - V(9) )
-
GAE 广义优势估计方法
4.1 优势函数 A(s, a):
-
衡量在状态
s
下执行动作a
比遵循当前策略的平均行为好多少。 -
公式:
A(s, a) = Q(s, a) - V(s)
-
如果 A(s, a) > 0:说明动作
a
比平均动作好,应该被加强。 -
如果 A(s, a) < 0:说明动作
a
比平均动作差,应该被抑制。 -
GAE(λ):将 n-step 的优势估计通过一个参数 λ 指数加权平均起来,在偏差和方差之间取得了完美的权衡。
A_t^GAE(λ) = Σ (γλ)^l * δ_{t+l}
(从l=0到∞),l 代表步数。
**目标:计算每个时间步的优势估计 **A_t
输入参数: 当前步骤的奖励、下一刻状态的价值评估。
智能体的一次游戏轨迹(episode)如下:
S0 -> S1 -> S2 -> S3 -> S4 (终止)我们需要为轨迹中的每一个状态计算其优势估计 A_t。第一步:计算每个时间步的TD误差 (δ_t)
TD误差的公式是:δ_t = r_t + γ * V(s_{t+1}) - V(s_t)让我们计算每个时间步的 δ_t:时间步 (t) 状态 (s_t) 奖励 (r_t) 下一状态 (s_{t+1}) V(s_t) V(s_{t+1}) TD误差 (δ_t) 计算 δ_t
0 S0 -1 S1 5.0 6.0 -1 + 0.9*6.0 - 5.0 -1 + 5.4 - 5.0 = -0.6
1 S1 -1 S2 6.0 7.0 -1 + 0.9*7.0 - 6.0 -1 + 6.3 - 6.0 = -0.7
2 S2 -1 S3 7.0 8.0 -1 + 0.9*8.0 - 7.0 -1 + 7.2 - 7.0 = -0.8
3 S3 +9 S4 8.0 0.0 9 + 0.9*0.0 - 8.0 9 + 0 - 8.0 = +1.0
注意:在 t=3,奖励是 -1 (移动) + 10 (到达终点) = +9。现在我们有了所有的基础材料:[δ_0, δ_1, δ_2, δ_3] = [-0.6, -0.7, -0.8, +1.0]第二步:计算GAE(λ)优势估计 (A_t)
GAE的公式是:A_t^GAE(λ) = Σ (γλ)^l * δ_{t+l},我们需要从后往前(backwards) 计算。给定 γ=0.9, λ=0.9 -> γλ = 0.81计算 A_3 (最后一步):
A_3 = Σ (0.81)^l * δ_{3+l},l 从 0 到 ∞,但 l>=1 时 δ 不存在,所以:
A_3 = (0.81)^0 * δ_3 = 1 * (+1.0) = +1.0计算 A_2:
A_2 = Σ (0.81)^l * δ_{2+l} for l=0, 1
A_2 = (0.81)^0 * δ_2 + (0.81)^1 * δ_3
A_2 = (1 * -0.8) + (0.81 * +1.0)
A_2 = -0.8 + 0.81 = +0.01计算 A_1:
A_1 = Σ (0.81)^l * δ_{1+l} for l=0, 1, 2
A_1 = (0.81)^0 * δ_1 + (0.81)^1 * δ_2 + (0.81)^2 * δ_3
A_1 = (1 * -0.7) + (0.81 * -0.8) + (0.6561 * +1.0) (0.81^2=0.6561)
A_1 = -0.7 - 0.648 + 0.6561 = -0.6919计算 A_0:
A_0 = Σ (0.81)^l * δ_{0+l} for l=0, 1, 2, 3
A_0 = (0.81)^0 * δ_0 + (0.81)^1 * δ_1 + (0.81)^2 * δ_2 + (0.81)^3 * δ_3
A_0 = (1 * -0.6) + (0.81 * -0.7) + (0.6561 * -0.8) + (0.5314 * +1.0) (0.81^3≈0.5314)
A_0 = -0.6 - 0.567 - 0.5249 + 0.5314 = -1.1605最终,我们得到GAE优势估计:
[A_0, A_1, A_2, A_3] = [-1.16, -0.69, +0.01, +1.0]
λ 值 | 优势估计 | 特点 | 对策略更新的影响 |
---|---|---|---|
λ = 0 | [-0.6, -0.7, -0.8, +1.0] | 短视,方差最低,偏差最高。 | 会强烈抑制所有移动动作,只鼓励最后一步。学习可能不稳定,因为它忽略了动作的长期价值。 |
λ = 1 | [-1.149, -0.61, +0.1, +1.0] | 长远,方差最高,偏差最低。 | 能识别出最后两步的价值。但估计值波动大,因为一次成功的轨迹可能包含很多运气。 |
λ = 0.9 | [-1.16, -0.69, +0.01, +1.0] | 聪明的折中。 | 结果更接近MC(λ=1),但方差更低。它正确地指出早期动作有负优势(因为价值函数高估了它们),而S2 的动作功过相抵。 |
- 方差高/低的意义
方差小 (Low Variance)
表现:你的所有弹孔都紧密地聚集在一起,形成了一个又小又密的弹孔群。但它们可能离靶心很远。
意味着什么:
- 一致性高:你的表现非常稳定。每次射击的结果都差不多,可重复性很强。
- 可能不准确:虽然很稳定,但如果所有弹孔都偏左下角,说明你的枪有系统性的偏差(Bias)。你每次都稳定地打出了8环,但永远打不到10环。
方差大 (High Variance)
表现:你的弹孔分散在靶子的各个地方,有的甚至脱靶。它们没有一个集中的区域。
意味着什么:
- 不一致性:你的表现极其不稳定,缺乏可预测性。这次可能蒙中10环,下次可能打到2环。
- 可能准确:在所有这些分散的弹孔中,平均位置可能恰好就在靶心附近。这意味着你没有系统性偏差(低偏差),纯属运气问题。
-
PPO损失函数
组成:策略损失 + 价值损失 + 熵损失
策略损失:advantages * ratio
advantages = rollout_data.advantages #策略奖励
# Normalization does not make sense if mini batchsize == 1, see GH issue #325
if self.normalize_advantage and len(advantages) > 1:advantages = (advantages - advantages.mean()) / (advantages.std() + 1e-8)# ratio between old and new policy, should be one at the first iteration
ratio = th.exp(log_prob - rollout_data.old_log_prob)
# 新策略和旧策略产生同一动作的概率之比
# clipped surrogate loss
policy_loss_1 = advantages * ratio
policy_loss_2 = advantages * th.clamp(ratio, 1 - clip_range, 1 + clip_range)
policy_loss = -th.min(policy_loss_1, policy_loss_2).mean()
#这个min操作构成了一个悲观(pessimistic) 的估计,确保了最终的损失函数是原始目标函数的下界。
def compute_returns_and_advantage(self, last_values: th.Tensor, dones: np.ndarray) -> None:# Convert to numpylast_values = last_values.clone().cpu().numpy().flatten()last_gae_lam = 0for step in reversed(range(self.buffer_size)):if step == self.buffer_size - 1:next_non_terminal = 1.0 - donesnext_values = last_valueselse:next_non_terminal = 1.0 - self.episode_starts[step + 1]next_values = self.values[step + 1]delta = self.rewards[step] + self.gamma * next_values * next_non_terminal - self.values[step]last_gae_lam = delta + self.gamma * self.gae_lambda * next_non_terminal * last_gae_lamself.advantages[step] = last_gae_lam# TD(lambda) estimator, see Github PR #375 or "Telescoping in TD(lambda)"# in David Silver Lecture 4: https://www.youtube.com/watch?v=PnHCvfgC_ZAself.returns = self.advantages + self.values
价值损失:
# Value loss using the TD(gae_lambda) target
value_loss = F.mse_loss(rollout_data.returns, values_pred)rollout_data.returns: 这是目标值,是通过广义优势估计(GAE)计算得到的折扣累积回报,
可以看作是价值函数想要逼近的“真实值”或“标签”。它是通过实际采样得到的轨迹计算出来的,
比网络的预测更接近真实期望。
values_pred: 这是预测值,即经过上述(可能裁剪过的)当前价值网络的预测。#self.returns = self.advantages + self.values
熵损失:
entropy = distribution.entropy()
entropy_loss = -th.mean(entropy)
熵的定义: -sum(pi * log(pi))
每个事件的信息量乘以该事件发生的概率,然后求和
换句话说:熵是信息量的期望值(平均值)
log(p_i)
源于信息论中的一个基本概念:一个事件的信息量。事件发生的概率越小,它发生时包含的信息量就越大。