演员评论家 Actor-Critic 算法
Actor-Critic 算法是强化学习中一种经典且高效的方法,它巧妙地将策略梯度(Policy Gradient)和值函数估计(Value Function Estimation)结合起来。简单来说,它通过两个网络协同工作:一个负责行动(Actor),另一个负责评价(Critic)。
核心概念理解
1. 角色设定
想象你正在训练一个机器人爬山,目标是到达山顶获得最高奖励。
- Actor(演员):相当于冒险家,负责根据当前状态决定下一步怎么走(选择动作)。它的策略可能不完美,需要不断调整。
- Critic(评论家):相当于导师,站在旁边观察并评估 Actor 的表现。它会告诉 Actor:'这一步走得好'或者'离目标更远了'。
2. 协作机制
两者的协作过程非常直观:
- Actor 观察环境状态,根据当前策略选择一个动作。
- 环境反馈新的状态和奖励。
- Critic 根据反馈计算价值(Value),评估刚才那个动作的好坏。
- Actor 利用 Critic 的评价来更新自己的策略参数,让下一次选择更优。
这种分工使得 Actor 专注于决策,而 Critic 专注于提供低方差的梯度信号,两者互补,比单独使用任何一种方法效果更好。
3. 为什么叫 Actor-Critic?
名字直接反映了功能分工:Actor 负责执行动作,Critic 负责评判价值。结合后的优势在于,Critic 提供的基准线(Baseline)可以有效降低策略梯度的方差,从而加速收敛。
算法背景与数学推导
1. 优化目标
强化学习的核心目标是最大化累积折扣奖励的期望: $$J(\theta) = \mathbb{E}{\pi\theta} \left[ \sum_{t=0}^\infty \gamma^t r_t \right]$$ 其中 $\gamma$ 是折扣因子,$r_t$ 是即时奖励,$\pi_\theta(a|s)$ 是策略函数。
2. 策略梯度定理
为了优化策略参数 $\theta$,我们计算目标函数的梯度: $$\nabla_\theta J(\theta) = \mathbb{E}{\pi\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \cdot A^\pi(s, a) \right]$$ 这里的 $A^\pi(s, a)$ 是优势函数,衡量动作相对于平均水平的优劣。直接使用环境反馈会导致高方差问题,这就是引入 Critic 的原因。
3. Critic:值函数估计
Critic 的目标是学习状态值函数 $V^\pi(s)$,通常用神经网络近似。它通过最小化时间差分(TD)误差来更新: $$\delta_t = r_t + \gamma V^\pi(s_{t+1}) - V^\pi(s_t)$$ Critic 的网络参数 $w$ 更新方向为: $$\nabla_w L(w) = \delta_t \cdot \nabla_w V^\pi(s)$$
4. Actor:策略优化
Actor 利用 Critic 计算的 TD 误差 $\delta$ 来指导策略更新: $$\theta \leftarrow \theta + \alpha \cdot \nabla_\theta \log \pi_\theta(a|s) \cdot \delta$$ 这意味着如果 Critic 认为某个动作比预期好($\delta > 0$),Actor 就增加该动作的概率;反之则减少。
实战代码实现
下面是一个基于 PyTorch 的完整 Actor-Critic 实现示例。我们将分别构建策略网络(Actor)和价值网络(Critic),并在 CartPole 环境中进行训练。
网络结构定义
首先定义 Actor 和 Critic 的网络类。Actor 输出动作概率分布,Critic 输出状态价值。
import torch
from torch import nn
from torch.nn import functional F
numpy np
(nn.Module):
():
(PolicyNet, ).__init__()
.fc1 = nn.Linear(n_states, n_hiddens)
.fc2 = nn.Linear(n_hiddens, n_actions)
():
x = .fc1(x)
x = F.relu(x)
x = .fc2(x)
F.softmax(x, dim=)
(nn.Module):
():
(ValueNet, ).__init__()
.fc1 = nn.Linear(n_states, n_hiddens)
.fc2 = nn.Linear(n_hiddens, )
():
x = .fc1(x)
x = F.relu(x)
x = .fc2(x)
x


