深度强化学习实战:从零构建actor-critic架构的避坑指南

1次阅读
没有评论

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

image.webp

在连续动作空间的控制任务中,actor-critic 架构展现出了独特的优势。与 DQN 这类基于值的方法相比,actor-critic 不需要维护庞大的动作值函数表,特别适合高维连续动作空间。而相比于 PPO 等策略梯度方法,actor-critic 通过引入 critic 网络来评估状态价值,显著降低了策略更新的方差,使训练过程更加稳定。这种优势使得 actor-critic 成为机器人控制、自动驾驶等连续控制任务的首选架构。

深度强化学习实战:从零构建 actor-critic 架构的避坑指南

1. 策略网络(Actor)设计要点

策略网络在 actor-critic 架构中负责生成动作分布,设计时需要考虑几个关键点:

  • 输出层设计 :对于连续动作空间,通常使用 tanh 作为输出层激活函数,将动作限制在[-1,1] 范围内,再通过线性变换映射到实际动作空间

  • 熵正则项:在损失函数中加入策略熵项可以鼓励探索,防止策略过早收敛到局部最优。通常设置一个较小的熵系数(如 0.01)来平衡探索与利用

  • 对数概率计算:对于连续动作,通常假设输出服从高斯分布,需要正确计算动作的对数概率用于策略梯度更新

2. 价值网络(Critic)实现方式

Critic 网络用于评估状态或状态 - 动作对的价值,主要有两种实现形式:

  1. 状态价值 V(s):评估当前状态的价值,实现简单但可能缺乏动作维度的信息

  2. 动作价值 Q(s,a):评估特定动作在给定状态下的价值,信息更丰富但实现复杂度稍高

实践中,V(s)更常用于基础的 actor-critic 实现,而 Q(s,a)更多用于类似 DDPG 这类算法。

3. Advantage 计算的三种方法

Advantage 函数 A(s,a)=Q(s,a)-V(s)是 actor-critic 的核心,衡量当前动作比平均表现好多少。PyTorch 中常用三种计算方式:

  1. 蒙特卡洛 (MC):使用完整 episode 的回报作为 Q(s,a) 的估计

  2. TD(n):n 步时序差分,平衡偏差与方差

  3. GAE(广义优势估计):通过引入 λ 参数,优雅地结合多步 TD 估计

GAE 通常能取得最好的效果,下面是一个 GAE 实现的代码示例:

def compute_gae(next_value, rewards, masks, values, gamma=0.99, tau=0.95):
    values = values + [next_value]
    gae = 0
    returns = []
    for step in reversed(range(len(rewards))):
        delta = rewards[step] + gamma * values[step + 1] * masks[step] - values[step]
        gae = delta + gamma * tau * masks[step] * gae
        returns.insert(0, gae + values[step])
    return returns

4. 完整训练循环实现

下面给出一个包含经验回放的完整训练循环。注意这里使用了线程安全的 deque 实现经验回放:

import torch
import torch.optim as optim
from collections import deque
import threading

class ReplayBuffer:
    def __init__(self, capacity):
        self.buffer = deque(maxlen=capacity)
        self.lock = threading.Lock()

    def push(self, transition):
        with self.lock:
            self.buffer.append(transition)

    def sample(self, batch_size):
        with self.lock:
            return random.sample(self.buffer, batch_size)

    def __len__(self):
        return len(self.buffer)

# 训练循环关键部分
def train(env, actor, critic, buffer, epochs=1000, batch_size=64, gamma=0.99):
    actor_optim = optim.Adam(actor.parameters(), lr=1e-4)
    critic_optim = optim.Adam(critic.parameters(), lr=3e-4)

    for epoch in range(epochs):
        state = env.reset()
        episode_reward = 0

        while True:
            action, log_prob = actor.select_action(state)
            next_state, reward, done, _ = env.step(action)
            buffer.push((state, action, log_prob, reward, done))

            if len(buffer) >= batch_size:
                batch = buffer.sample(batch_size)
                # 计算 Advantage 和更新网络
                update_networks(batch, actor, critic, actor_optim, critic_optim, gamma)

            state = next_state
            episode_reward += reward

            if done:
                break

        print(f"Epoch {epoch}, Reward: {episode_reward}")

5. 避坑指南

在实现 actor-critic 时,新手常会遇到以下几个问题:

  1. 学习率设置:Actor 和 Critic 网络通常需要不同的学习率。Critic 需要更快收敛(如 3e-4),而 Actor 需要更保守(如 1e-4)

  2. 梯度问题

  3. 使用梯度裁剪(torch.nn.utils.clip_grad_norm_)
  4. 合适的权重初始化
  5. 批归一化层
  6. 残差连接
  7. 学习率预热

  8. 可视化调试

  9. 绘制价值函数曲线,观察是否收敛
  10. 监控策略熵,确保足够的探索
  11. 记录平均 episode 长度和奖励

6. 扩展到多智能体场景

将 actor-critic 扩展到多智能体场景(如足球游戏、群体机器人)时,可以考虑:

  1. 集中式训练分散式执行(CTDE)框架
  2. 为每个智能体维护独立的 actor,共享或部分共享 critic 网络
  3. 引入通信机制或注意力机制来处理智能体间的协作

最后,建议读者尝试在 CartPole 环境中实现这个架构,观察不同超参数对训练效果的影响。强化学习需要大量实践,祝大家训练愉快!

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