优势演员-评论家(Advantage Actor-Critic,A2C)算法详解与实现
优势演员-评论家(Advantage Actor-Critic,A2C)算法详解与实现
- 0. 前言
 - 1. Advantage Actor-Critic (A2C) 算法原理
 - 2. A2C 算法流程
 - 3. 实现 A2C
 
0. 前言
在强化学习领域,演员-评论家 (Actor-Critic) 方法融合策略优化与价值评估,是解决复杂决策问题的重要框架。基于这一基础,优势演员-评论家 (Advantage Actor-Critic, A2C) 算法通过三个关键创新实现了性能提升:采用回合制更新替代在线学习,引入优势函数精准评估行动价值,并使用均方误差优化价值网络。此外,算法通过策略熵正则项促进探索,有效防止策略过早收敛。本节将深入解析 A2C 的理论基础,详述其与演员-评论家和 REINFORCE 算法的核心差异,并使用 Keras 实现 A2C。
1. Advantage Actor-Critic (A2C) 算法原理
在演员-评论家 (Actor-Critic) 方法中,其目标在于让价值函数能够准确评估状态价值。训练价值网络还存在其他技术,一种简单的方法是在价值函数优化中采用均方误差 (mean square error, MSE),这与Q学习中的算法类似。新的价值梯度等于回报 (RtR_tRt) 与状态价值之间均方误差的偏导数:
 ∇V(θv)=∂(Rt−𝑉(s,θv))2∂θv\nabla V(\theta_v) = \frac {\partial(R_t- 𝑉(s,\theta_v))^2}{\partial\theta_v} ∇V(θv)=∂θv∂(Rt−V(s,θv))2
 当 (Rt−𝑉(s,θv))→0(R_t- 𝑉(s,\theta_v)) \rightarrow 0(Rt−V(s,θv))→0 时,价值网络对给定状态回报的预测会越来越精确。我们将演员-评论员算法的这种变体称为优势演员-评论家 (Advantage Actor-Critic, A2C)。A2C 是异步优势演员-评论家 (Asynchronous Advantage Actor-Critic, A3C) 的单线程或同步版本。量值 (Rt−𝑉(s,θv))(R_t- 𝑉(s,\theta_v))(Rt−V(s,θv)) 称为优势量。
2. A2C 算法流程
以下算法流程总结了 A2C 方法。A2C 与演员-评论家 (Actor-Critic) 存在几点差异:演员-评论家采用在线学习方式,即基于每个经验样本进行训练;而 A2C 则与蒙特卡洛算法、REINFORCE 算法及带基线的 REINFORCE 算法类似,是在完成整个回合后才进行训练。演员-评论家从初始状态训练至终止状态,A2C 则从终止状态开始训练至初始状态。此外,A2C 的策略梯度和价值梯度不再使用 γt\gamma^tγt 进行折现计算。
 为增强智能体在训练过程中的探索能力,A3C 算法提出在梯度函数中引入策略函数加权熵值的梯度项 β∇θH(π(at∣st,θ))\beta\nabla_\theta H(\pi(a_t|s_t,\theta))β∇θH(π(at∣st,θ))。需要说明的是,熵是衡量事件信息量或不确定性的指标。
定义可微参数化目标策略网络 π(at∣st,θ)\pi(a_t|s_t,\theta)π(at∣st,θ) 与可微参数化价值网络 V(st,θv)V(s_t,\theta_v)V(st,θv);设定折扣因子 γ∈[0,1]\gamma∈[0,1]γ∈[0,1],性能梯度学习率 α\alphaα,价值梯度学习率 αv\alpha_vαv,以及熵权重 β\betaβ;初始化策略网络参数 θ0\theta_0θ0 与价值网络参数 θv0\theta_{v_0}θv0
重复执行
依据策略 π(at∣st,θ)\pi(a_t|s_t,\theta)π(at∣st,θ) 生成完整轨迹 (s0a0r1s1,s1a1r2s2,...,st−1at−1rtst)(s_0a_0r_1s_1, s_1a_1r_2s_2, ..., s_{t-1}a_{t-1}r_ts_t)(s0a0r1s1,s1a1r2s2,...,st−1at−1rtst)
计算终止状态回报:Rt={0sT为终止状态V(sT,θv)对于非终止状态sT,从最终状态开始进行自举法估计R_t=\begin{cases}0 & s_T为终止状态\\ V(s_T,θ_v) & 对于非终止状态 s_T, 从最终状态开始进行自举法估计 \end{cases}Rt={0V(sT,θv)sT为终止状态对于非终止状态sT,从最终状态开始进行自举法估计
从最后一步 t=T−1t=T-1t=T−1 反向遍历至初始状态 t=0t=0t=0:
计算累计回报:Rt=rt+γRtR_t = r_t + \gamma R_tRt=rt+γRt
计算价值梯度:∇V(θv)=∂(Rt−V(s,θv))2∂θv\nabla V(\theta _v) = \frac {\partial (R_t - V(s,\theta _v))²}{\partial \theta _v}∇V(θv)=∂θv∂(Rt−V(s,θv))2
累积价值梯度更新:θv=θv+αv∇V(θv)\theta _v = \theta _v + \alpha _v\nabla V(\theta _v)θv=θv+αv∇V(θv)
计算策略梯度:∇J(θ)=∇θlnπ(at∣st,θ)(Rt−V(s,θv))+β∇θH(π(at∣st,θ))\nabla J(\theta) = \nabla _\theta ln\pi(a_t|s_t,\theta)(R_t - V(s,\theta _v)) + \beta \nabla _\theta H(\pi(a_t|s_t,\theta))∇J(θ)=∇θlnπ(at∣st,θ)(Rt−V(s,θv))+β∇θH(π(at∣st,θ))
执行梯度上升:θ=θ+α∇J(θ)\theta = \theta + \alpha \nabla J(\theta)θ=θ+α∇J(θ)
3. 实现 A2C
接下来,使用 Keras 实现 A2CAgent 类。与两种 REINFORCE 方法不同,本算法从最终经验单元反向计算至初始状态。在每个经验单元处,目标函数网络 logp_model 和价值函数网络 value_model 分别通过调用 fit() 方法进行优化。需要注意的是,在对象实例化时,熵损失权重 beta 设置为 0.9 以启用熵损失函数,且 value_model 采用均方误差损失函数进行训练。
class A2CAgent(PolicyAgent):def __init__(self,env):super().__init__(env)#beta of entropy used in A2Cself.beta = 0.9#loss function of A2C value_model is mseself.loss = 'mse'def train_by_episode(self,last_value=0):#implements A2C training from the last state#to the first state#discount factorgamma = 0.95r = last_value#the memory is visited in reversefor item in self.memory[::-1]:[step,state,next_state,reward,done] = item#compute the returnr = reward + gamma * ritem = [step,state,next_state,r,done]#train pre step#a2c reward has been discountedself.train(item)def train(self,item,gamma=1.0):[step,state,next_state,reward,done] = item#must save state for entropy computationself.state = statediscount_factor = gamma ** step#a2c: delta = discounted_reward - valuedelta = reward - self.value(state)[0]discounted_delta = delta * discount_factordiscounted_delta = np.reshape(discounted_delta,[-1,1])verbose = 1 if done else 0#train the logp model (implies training of actor model # as well) since they share exactly the same set of parametersself.logp_model.fit(np.array(state),discounted_delta,batch_size=1,epochs=1,verbose=verbose)#in A2C, the target value is the return (reward# replaced by return in train_by_episode function)discounted_delta = rewarddiscounted_delta = np.reshape(discounted_delta,[-1,1])#train the value network (critic)self.value_model.fit(np.array(state),discounted_delta,batch_size=1,epochs=1,verbose=verbose)
