Actor-Critic方法演进:从QAC到DDPG的数学原理与实践
1. Actor-Critic方法的核心思想
Actor-Critic方法本质上是一种结合了策略梯度(Policy Gradient)和价值函数逼近(Value Function Approximation)的强化学习框架。它的独特之处在于将策略更新和价值评估两个过程分离,分别由"Actor"和"Critic"两个组件来完成。
想象一下你在学习骑自行车:Actor就像你的身体,负责实际做出蹬踏板、保持平衡等动作;Critic则像你的大脑,不断评估当前动作的效果,告诉你"这个角度太危险"或"速度保持得不错"。两者协同工作,才能快速掌握骑行技巧。
从数学角度看,策略梯度定理给出了目标函数J(θ)的梯度表达式:
∇J(θ) = E[∇logπ(a|s) * Q(s,a)]其中:
- π(a|s)是参数化策略
- Q(s,a)是动作价值函数
- 期望E[...]表示在策略π下的状态-动作分布
这个公式揭示了Actor和Critic的分工:
- Actor:负责策略π的更新(公式中的∇logπ部分)
- Critic:负责估计Q值(公式中的Q(s,a)部分)
在实际实现中,我们通常用神经网络来参数化这两个组件。例如,可以这样定义:
# Actor网络:输入状态,输出动作概率分布 class Actor(nn.Module): def forward(self, state): return torch.distributions.Categorical(logits=self.net(state)) # Critic网络:输入状态,输出状态价值估计 class Critic(nn.Module): def forward(self, state): return self.net(state)2. 从QAC到A2C的演进
2.1 最基础的QAC方法
Q Actor-Critic(QAC)是最简单的Actor-Critic实现,其核心流程如下:
- 用Critic(通常采用SARSA算法)估计Q值
- 用这些Q值计算策略梯度
- 更新Actor的参数
具体算法步骤:
for episode in episodes: state = env.reset() while not done: action = actor.select_action(state) next_state, reward, done = env.step(action) # Critic更新(TD学习) q_value = critic(state, action) next_q = critic(next_state, actor.select_action(next_state)) td_error = reward + gamma * next_q - q_value critic.update(td_error) # Actor更新(策略梯度) log_prob = actor.log_prob(state, action) actor_loss = -log_prob * q_value.detach() # 停止梯度传播 actor.update(actor_loss) state = next_stateQAC虽然简单,但存在明显问题:Q值的估计方差较大,导致训练不稳定。这就引出了Advantage Actor-Critic(A2C)的改进。
2.2 A2C的改进思路
A2C的核心创新是引入优势函数(Advantage Function):
A(s,a) = Q(s,a) - V(s)其中V(s)是状态价值函数,可以理解为当前状态的"平均表现"。优势函数衡量的是特定动作相对于平均水平的优势。
这个改进带来了三个关键好处:
- 降低方差:减去基线V(s)后,梯度估计更稳定
- 更合理的更新:关注动作的相对优势而非绝对值
- 计算效率:只需估计V(s)而非Q(s,a),减少了一半的网络参数
实际实现时,我们常用TD误差作为优势函数的近似:
# 在A2C中,Critic只需估计V值 value = critic(state) next_value = critic(next_state) advantage = reward + gamma * next_value - value # TD误差作为优势估计 # Actor更新使用优势函数而非Q值 actor_loss = -log_prob * advantage.detach()3. Off-policy扩展与重要性采样
3.1 为什么需要Off-policy?
On-policy方法(如QAC、A2C)有个致命弱点:它们只能用当前策略产生的数据来更新自己。这就像学做饭时,每次尝试新配方都必须重新买所有食材,效率极低。Off-policy方法则允许我们重复使用历史经验,大幅提升数据效率。
实现Off-policy的关键技术是重要性采样(Importance Sampling)。其数学本质是:
E_p0[f(X)] = E_p1[f(X) * p0(X)/p1(X)]这让我们可以用p1分布下的样本来估计p0分布下的期望。
3.2 Off-policy Actor-Critic实现
在Actor-Critic框架中应用重要性采样时,需要注意两个地方:
- 策略梯度中的动作概率比
- 价值估计中的状态分布校正
具体算法调整如下:
# 行为策略β与目标策略π的概率比 importance_weight = actor.prob(state, action) / behavior_prob(state, action) # 带重要性权重的Actor更新 actor_loss = -log_prob * advantage.detach() * importance_weight # Critic更新也需要调整(这里展示简单版本) critic_loss = (importance_weight * td_error**2).mean()实际应用中,为了数值稳定性,我们常对重要性权重进行裁剪(如PPO算法中的clip操作)。此外,还需要特别注意:
- 当行为策略与目标策略差异过大时,重要性权重的方差会急剧增大
- 长期轨迹的重要性权重乘积会导致数值不稳定
- 需要设计适当的价值函数更新规则来抵消分布偏移
4. 确定性策略梯度(DPG/DDPG)
4.1 从随机策略到确定性策略
前三种方法都假设策略是随机的(stochastic),这在离散动作空间很自然。但对于连续控制任务(如机器人操控),确定性策略(deterministic policy)往往更合适。
确定性策略表示为:
a = μ(s)其中μ是从状态空间到动作空间的确定性映射。这种表示的优势在于:
- 天然适合连续动作空间
- 策略输出的维度等于动作维度,而非动作概率分布
- 训练过程中不需要处理高维概率分布
4.2 DPG的数学形式
确定性策略梯度定理给出了新的梯度表达式:
∇J(θ) = E[∇μ(s) * ∇a Q(s,a)|a=μ(s)]与随机策略梯度的关键区别:
- 梯度通过策略网络μ传播
- 需要计算Q函数对动作的梯度
- 天然具备off-policy特性
4.3 DDPG的实现技巧
深度确定性策略梯度(DDPG)是DPG的深度学习版本,结合了DQN的优秀实践。其核心组件包括:
class DDPG: def __init__(self): # 四个网络:Actor/Critic及其目标网络 self.actor = ActorNetwork() self.critic = CriticNetwork() self.target_actor = copy.deepcopy(self.actor) self.target_critic = copy.deepcopy(self.critic) # 经验回放缓冲区 self.buffer = ReplayBuffer(capacity=1e6) def update(self, batch): # 计算目标Q值 next_actions = self.target_actor(next_states) target_q = rewards + gamma * self.target_critic(next_states, next_actions) # 更新Critic current_q = self.critic(states, actions) critic_loss = F.mse_loss(current_q, target_q.detach()) # 更新Actor(注意符号) actor_loss = -self.critic(states, self.actor(states)).mean() # 软更新目标网络 self.soft_update(self.target_actor, self.actor, tau=0.005) self.soft_update(self.target_critic, self.critic, tau=0.005)实际训练时还需要以下技巧:
- 动作噪声探索(如OU噪声)
- 目标网络的软更新(而非硬更新)
- 适当的网络初始化(如最后一层缩小初始化范围)
- Critic网络的梯度裁剪
在机器人控制等连续动作任务中,DDPG表现出色。例如在MuJoCo的Ant环境中,DDPG可以让六足机器人快速学会行走和转向。
