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

1. 策略网络(Actor)设计要点
策略网络在 actor-critic 架构中负责生成动作分布,设计时需要考虑几个关键点:
-
输出层设计 :对于连续动作空间,通常使用 tanh 作为输出层激活函数,将动作限制在[-1,1] 范围内,再通过线性变换映射到实际动作空间
-
熵正则项:在损失函数中加入策略熵项可以鼓励探索,防止策略过早收敛到局部最优。通常设置一个较小的熵系数(如 0.01)来平衡探索与利用
-
对数概率计算:对于连续动作,通常假设输出服从高斯分布,需要正确计算动作的对数概率用于策略梯度更新
2. 价值网络(Critic)实现方式
Critic 网络用于评估状态或状态 - 动作对的价值,主要有两种实现形式:
-
状态价值 V(s):评估当前状态的价值,实现简单但可能缺乏动作维度的信息
-
动作价值 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 中常用三种计算方式:
-
蒙特卡洛 (MC):使用完整 episode 的回报作为 Q(s,a) 的估计
-
TD(n):n 步时序差分,平衡偏差与方差
-
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 时,新手常会遇到以下几个问题:
-
学习率设置:Actor 和 Critic 网络通常需要不同的学习率。Critic 需要更快收敛(如 3e-4),而 Actor 需要更保守(如 1e-4)
-
梯度问题:
- 使用梯度裁剪(torch.nn.utils.clip_grad_norm_)
- 合适的权重初始化
- 批归一化层
- 残差连接
-
学习率预热
-
可视化调试:
- 绘制价值函数曲线,观察是否收敛
- 监控策略熵,确保足够的探索
- 记录平均 episode 长度和奖励
6. 扩展到多智能体场景
将 actor-critic 扩展到多智能体场景(如足球游戏、群体机器人)时,可以考虑:
- 集中式训练分散式执行(CTDE)框架
- 为每个智能体维护独立的 actor,共享或部分共享 critic 网络
- 引入通信机制或注意力机制来处理智能体间的协作
最后,建议读者尝试在 CartPole 环境中实现这个架构,观察不同超参数对训练效果的影响。强化学习需要大量实践,祝大家训练愉快!
