Actor-Critic强化学习框架入门指南:从理论到PyTorch实战

1次阅读
没有评论

共计 2392 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

为什么需要 Actor-Critic?

强化学习新手常会遇到两个经典算法的局限:

Actor-Critic 强化学习框架入门指南:从理论到 PyTorch 实战

  • Policy Gradient:直接优化策略函数,但依赖蒙特卡洛采样导致梯度估计方差大,训练过程像坐过山车一样不稳定。
  • Q-Learning:通过价值函数间接学习策略,但处理连续动作空间时(比如方向盘转角),需要遍历所有动作计算 Q 值,计算量爆炸。

Actor-Critic 就像把两个算法拼成瑞士军刀:用 Actor 网络解决动作选择问题(Policy Gradient 的强项),用 Critic 网络评估状态价值降低方差(Q-Learning 的优势)。

算法横向对比

方法 收敛性 适用场景 缺点
Monte Carlo 高方差慢收敛 完整回合的离散任务 必须等回合结束才能更新
TD Learning 中等方差 连续决策场景 价值估计可能偏颇
Actor-Critic 低方差快收敛 连续 / 离散动作空间 需要调两个网络参数

PyTorch 实现核心代码

1. 网络结构定义

import torch
import torch.nn as nn

class Actor(nn.Module):
    """策略网络,输出动作概率分布"""
    def __init__(self, state_dim: int, action_dim: int):
        super().__init__()
        self.fc = nn.Sequential(nn.Linear(state_dim, 64),
            nn.LayerNorm(64),  # 缓解梯度消失
            nn.ReLU(),
            nn.Linear(64, action_dim),
            nn.Softmax(dim=-1)  # 动作概率归一化
        )

    def forward(self, state: torch.Tensor) -> torch.Tensor:
        # state 形状: [batch_size, state_dim]
        return self.fc(state)

class Critic(nn.Module):
    """价值网络,评估状态价值"""
    def __init__(self, state_dim: int):
        super().__init__()
        self.fc = nn.Sequential(nn.Linear(state_dim, 64),
            nn.LayerNorm(64),
            nn.ReLU(),
            nn.Linear(64, 1)  # 输出标量价值
        )

    def forward(self, state: torch.Tensor) -> torch.Tensor:
        # 输出形状: [batch_size, 1]
        return self.fc(state)

2. 关键训练逻辑

def compute_advantages(rewards: List[float], 
    values: torch.Tensor,
    gamma: float = 0.99
) -> torch.Tensor:
    """计算优势函数:实际回报 - 预估价值"""
    returns = []
    R = 0
    # 反向计算折扣回报
    for r in reversed(rewards):
        R = r + gamma * R
        returns.insert(0, R)
    returns = torch.tensor(returns)
    # 形状对齐并归一化
    advantages = returns - values.squeeze()
    return (advantages - advantages.mean()) / (advantages.std() + 1e-8)

# 在训练循环中
for _ in range(epochs):
    # 采样轨迹数据
    states, actions, rewards = env.sample(batch_size)

    # Critic 评估状态价值
    values = critic(states)

    # 计算策略梯度(含熵正则项)probs = actor(states)
    dist = torch.distributions.Categorical(probs)
    entropy = dist.entropy().mean()  # 鼓励探索

    advantages = compute_advantages(rewards, values)
    policy_loss = -(dist.log_prob(actions) * advantages).mean() - 0.01 * entropy

    # 价值函数损失(MSE)value_loss = F.mse_loss(values.squeeze(), torch.tensor(rewards))

六大避坑经验

  1. 学习率设置
  2. Actor 网络通常需要比 Critic 更小的学习率(如 1e-4 vs 3e-4)
  3. 可以先用 Adam 优化器自动适应,后期转 SGD 精调

  4. 梯度消失对策

  5. 在 MLP 层后添加 LayerNorm(如代码示例)
  6. 慎用 ReLU,可尝试 Swish 激活函数

  7. 折扣因子 γ

  8. CartPole 这类短期任务用 0.99
  9. 长期规划任务可降到 0.9~0.95

  10. 批次大小

  11. 简单任务 batch_size=32 足够
  12. 复杂环境需要增大到 256 以上

  13. 探索策略

  14. 初期用 epsilon-greedy(如从 1.0 衰减到 0.1)
  15. 后期依赖策略网络自身的概率分布

  16. 监控指标

  17. 每轮记录 episode_reward 和 entropy
  18. 如果 entropy 趋近 0,说明探索不足

在 CartPole 中的表现

不同 batch_size 下的训练曲线对比:
– batch_size=32:100 轮后收敛,但后期波动大
– batch_size=128:150 轮稳定收敛
– 加入熵正则项后:探索更充分,最高分可达 500

扩展连续动作空间

若要处理像机器人控制这类连续动作空间,需要:
1. 修改 Actor 网络输出高斯分布的均值和方差
2. 使用 PPO 算法限制策略更新幅度
3. 在计算 log_prob 时考虑概率密度函数

完整代码已开源在 GitHub(伪代码示例需替换为真实链接),包含更多工程实践细节如:
– 经验回放 (Replay Buffer) 实现
– 多环境并行采样
– 自动学习率调整

希望这篇笔记能帮你少走弯路,如果有问题欢迎在评论区交流!

正文完
 0
评论(没有评论)