共计 1671 个字符,预计需要花费 5 分钟才能阅读完成。
背景与痛点
在强化学习中,策略梯度方法(Policy Gradient)直接优化策略网络,但存在两个主要问题:
- 高方差:蒙特卡洛采样导致梯度估计波动大
- 收敛慢:需要大量样本才能稳定更新
Actor-Critic 框架通过引入 Critic 网络评估状态价值,显著降低了梯度方差。就像教练(Critic)指导运动员(Actor)调整动作,二者协同提升训练效率。
核心原理
双网络架构
- Actor(策略网络):输出动作概率分布
\pi_\theta(a|s) - Critic(价值网络):评估状态价值
V_\phi(s)
优势函数
关键公式:
A(s,a) = Q(s,a) - V(s)
实际实现常采用 TD 误差近似:
\delta = r + \gamma V(s') - V(s)
PyTorch 实现
网络定义(模块化设计)
class Actor(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.fc1 = nn.Linear(state_dim, 64)
self.fc2 = nn.Linear(64, action_dim)
def forward(self, state):
x = F.relu(self.fc1(state))
return F.softmax(self.fc2(x), dim=-1)
class Critic(nn.Module):
def __init__(self, state_dim):
super().__init__()
self.fc1 = nn.Linear(state_dim, 64)
self.fc2 = nn.Linear(64, 1)
def forward(self, state):
x = F.relu(self.fc1(state))
return self.fc2(x)
训练核心代码
def update(self, state, action, reward, next_state, done):
# 计算 TD 误差
value = self.critic(state)
next_value = self.critic(next_state).detach()
td_error = reward + (1 - done) * self.gamma * next_value - value
# Actor 更新(带日志概率技巧)probs = self.actor(state)
log_prob = torch.log(probs.gather(1, action))
actor_loss = -(log_prob * td_error.detach()).mean()
# Critic 更新(MSE 损失)critic_loss = td_error.pow(2).mean()
...
优化技巧
超参数调优
- 学习率:
- Actor 网络建议 0.0001-0.001
- Critic 网络建议比 Actor 大 3 -10 倍
-
使用
torch.optim.lr_scheduler动态调整 -
折扣因子 γ :
- 短期任务:0.9-0.95
-
长期任务:0.98-0.99
-
经验回放:
- CartPole 等简单环境:buffer_size=1e4
- Atari 游戏等复杂环境:buffer_size=1e6
常见陷阱与解决方案
- 梯度消失:
- 对策:网络初始化用
nn.init.xavier_normal_ -
检查:添加梯度范数监控
-
探索不足:
- 对策:在 softmax 前添加高斯噪声
-
替代方案:使用熵正则项
-
训练不稳定:
- 对策:定期同步目标网络
- 技巧:梯度裁剪(
torch.nn.utils.clip_grad_norm_)
实验效果
在 CartPole-v1 环境中的训练曲线:
- 100 回合后平均奖励达到 195+(满分 200)
- 相比纯策略梯度方法,收敛速度提升 3 倍

开放性问题
- 如何改造网络结构以适应连续动作空间(如 MuJoCo 环境)?
- 当状态维度极高时(如图像输入),怎样设计高效的特征提取模块?
- 多智能体场景下,如何避免 Critic 网络出现信用分配问题?
希望通过这篇实践指南,能帮助你快速掌握 Actor-Critic 的核心实现技巧。在实际项目中,建议先从简单环境验证算法正确性,再逐步迁移到复杂场景。
正文完
发表至: 人工智能
近一天内
