第一次接触Actor-Critic方法时,我也被这个看似复杂的名字唬住了。后来在实际项目中反复使用才发现,它的核心理念其实非常直观。想象你在训练一个机器人打乒乓球,"演员"负责挥拍动作,"评论家"则实时评价这个动作的好坏 - 这就是Actor-Critic最生动的写照。
策略(Actor)和价值(Critic)的协同工作是这个方法的精髓。我常跟团队新人说,可以把Actor看作是个"行动派",它根据当前状态做出决策;而Critic则是个"分析师",不断评估这些决策的长期价值。这种分工带来的最大好处是:Critic提供的价值评估能显著降低策略更新的方差,使训练过程更稳定。
在具体实现上,Actor和Critic通常用两个神经网络表示。记得我第一次用PyTorch实现时,犯了个典型错误 - 让两个网络共享底层特征提取层。结果训练时梯度更新相互干扰,效果惨不忍睹。后来才明白,虽然两个网络输入相同,但应该保持相对独立的结构。
python复制# 典型的Actor-Critic网络结构示例
class ActorCritic(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
# Actor网络
self.actor = nn.Sequential(
nn.Linear(state_dim, 64),
nn.ReLU(),
nn.Linear(64, action_dim),
nn.Softmax(dim=-1)
)
# Critic网络
self.critic = nn.Sequential(
nn.Linear(state_dim, 64),
nn.ReLU(),
nn.Linear(64, 1)
)
QAC(Q Actor-Critic)是我推荐给初学者的最佳切入点。这个算法巧妙地将SARSA的价值估计与策略梯度结合,代码实现不到50行却能清晰展示核心机制。我在教学时发现,很多同学对如何计算q值存在困惑 - 其实可以用简单的时序差分(TD)来近似:
python复制# QAC中的q值估计
state_value = critic(next_state)
target = reward + gamma * state_value
td_error = target - critic(current_state)
实践中的常见陷阱是Critic网络的学习率设置。太大会导致价值估计不稳定,太小又会使策略更新缓慢。我的经验法则是:Critic的学习率应该是Actor的3-5倍。因为准确的价值评估是策略优化的基础,就像盖楼要先打好地基。
Advantage Actor-Critic(A2C)是我在实际项目中最常用的变体。它引入的优势函数(Advantage)概念,让算法能区分"动作绝对好"和"相对当前策略更好"。这就像考试评分时不仅看绝对分数,还要考虑班级平均分。
实现A2C时有个关键技巧:用TD误差近似优势函数。这样只需维护一个价值网络,既节省资源又提升稳定性。下面是核心代码片段:
python复制# A2C优势函数计算
values = critic(states) # 当前状态值估计
next_values = critic(next_states) # 下一状态值估计
advantages = rewards + gamma * next_values - values # TD误差作为优势估计
在机器人控制项目中,我发现A2C对超参数相当敏感。特别是折扣因子γ,设置0.99和0.95可能带来完全不同的收敛效果。建议新手先用网格搜索确定合适范围,再微调。
离线策略(Off-policy)训练是提升数据效率的关键。还记得我第一次尝试实现时,被重要性采样(Importance Sampling)的数学公式绕晕了。后来用抛硬币的类比才想明白:就像用灌铅硬币的实验结果,来推算公平硬币的统计特性。
重要性权重的计算是核心难点。在连续动作空间,两个策略的概率密度比需要特殊处理:
python复制# 连续动作空间的重要性权重计算
def importance_ratio(target_policy, behavior_policy, state, action):
# target_policy和behavior_policy返回概率密度
return target_policy.pdf(state,action) / behavior_policy.pdf(state,action)
将离线策略应用到Actor-Critic会产生一些微妙变化。最大的区别在于:策略梯度现在需要考虑行为策略的分布。这就像用别人的实验数据来做自己的研究,必须考虑数据收集方式的偏差。
实现时常见的错误是忽略重要性权重的裁剪。当目标策略和行为策略差异太大时,未经裁剪的权重会导致梯度爆炸。我的解决方案是使用梯度惩罚:
python复制# 带裁剪的重要性权重
ratio = importance_ratio(...)
clipped_ratio = torch.clamp(ratio, 0.8, 1.2)
actor_loss = -torch.log(probs) * advantages * clipped_ratio
在无人机路径规划项目中,离线策略训练使数据利用率提升了3倍。但要注意,行为策略的探索性必须足够,否则容易陷入局部最优。
当动作空间连续时(如机械臂控制),传统的随机策略效率低下。确定性策略梯度(DPG)就像把"概率性试探"变成了"精准打击"。我首次在工业机械臂项目应用DPG时,控制精度直接提升了40%。
DPG的核心思想是用确定性映射代替概率分布。实现时要注意探索-利用的平衡,通常的做法是在确定性策略上添加噪声:
python复制# DPG探索策略
def explore_action(state):
mean_action = actor(state)
noise = torch.randn_like(mean_action) * exploration_noise
return torch.clamp(mean_action + noise, action_low, action_high)
Deep DPG(DDPG)将深度学习与DPG结合,是处理高维状态空间的利器。记得实现时四个网络(Actor/Critic及其目标网络)的协同更新需要精心设计:
python复制# DDPG的核心更新逻辑
# 更新Critic
target_q = reward + gamma * target_critic(next_state, target_actor(next_state))
critic_loss = F.mse_loss(critic(state, action), target_q.detach())
# 更新Actor
actor_loss = -critic(state, actor(state)).mean()
# 软更新目标网络
soft_update(target_actor, actor, tau)
soft_update(target_critic, critic, tau)
在自动驾驶项目中,DDPG对方向盘转角这类连续控制表现出色。但要注意,经验回放缓冲区的大小对性能影响很大,太小会导致训练不稳定,太大又会减慢学习速度。