获取更多资讯,赶快关注上面的公众号吧!

【强化学习系列】

  • 第一章 强化学习及OpenAI Gym介绍-强化学习理论学习与代码实现(强化学习导论第二版)
  • 第二章 马尔科夫决策过程和贝尔曼等式-强化学习理论学习与代码实现(强化学习导论第二版)
  • 第三章 动态规划-基于模型的RL-强化学习理论学习与代码实现(强化学习导论第二版)
  • 第四章 蒙特卡洛方法-强化学习理论学习与代码实现(强化学习导论第二版)
  • 第五章 基于时序差分和Q学习的无模型预测与控制-强化学习理论学习与代码实现(强化学习导论第二版)
  • 第六章 函数逼近-强化学习理论学习与代码实现(强化学习导论第二版)
  • 第七章 深度强化学习-深度Q网络系列1(Deep Q-Networks,DQN)
  • 第八章 深度强化学习-Nature深度Q网络(Nature DQN)
  • 第九章 深度强化学习-Double DQN
  • 第十章 深度强化学习-Prioritized Replay DQN
  • 第十一章 策略梯度(Policy Gradient)-强化学习理论学习与代码实现(强化学习导论第二版)
  • (本文)第十二章 演员评论家(Actor-Critic)-强化学习理论学习与代码实现(强化学习导论第二版)

    文章目录

    • 第十二章 Actor-Critic演员评论家
      • 12.1 Actor-Critic算法简介
      • 12.2 Actor-Critic框架引出
      • 12.3 Actor-Critic算法流程
      • 12.4 代码练习

第十二章 Actor-Critic演员评论家

我们在上一章中介绍了策略梯度(Policy Gradient)方法,并代码练习了蒙特卡罗策略梯度reinforce算法。但是由于该算法需要完整的状态序列,同时单独对策略函数进行迭代更新,不太容易收敛。
在本章我们将讨论一种将策略(Policy Based)和价值(Value Based)相结合的方法:Actor-Critic算法,在强化学习领域最受欢迎的A3C算法,DDPG算法,PPO算法等都是AC框架,所以AC重要性不言而喻。

12.1 Actor-Critic算法简介

Actor-Critic从名字上看包括两部分,演员(Actor)和评价家(Critic)。其中Actor使用的是上一章讲到的策略函数,负责生成动作(Action)并和环境交互。而Critic使用我们之前讲到了的价值函数,负责评估Actor的表现,并指导Actor下一阶段的动作。

回想上一篇的策略梯度,策略函数就是我们的Actor,但是那里是没有Critic的,当时使用了蒙特卡罗法来计算每一步的价值部分替代了Critic的功能,但是场景比较受限。因此现在我们使用类似DQN中用的价值函数来替代蒙特卡罗法,作为一个比较通用的Critic。

也就是说在Actor-Critic算法中,我们需要做两组近似,第一组是策略函数的近似:
πθ(s,a)=P(a∣s,θ)≈π(a∣s)\pi_{\theta}(s,a) = P(a|s,\theta)\approx \pi(a|s)πθ​(s,a)=P(a∣s,θ)≈π(a∣s)

第二组是价值函数的近似,对于状态价值和动作价值函数分别是:
v^(s,w)≈vπ(s)\hat{v}(s, w) \approx v_{\pi}(s)v^(s,w)≈vπ​(s)
q^(s,a,w)≈qπ(s,a)\hat{q}(s,a,w) \approx q_{\pi}(s,a)q^​(s,a,w)≈qπ​(s,a)

对于我们上一节讲到的蒙特卡罗策略梯度reinforce算法,需要进行改造才能变成Actor-Critic算法,将会在下一节中详细介绍。

首先,在蒙特卡罗策略梯度reinforce算法中,策略的参数更新公式是:
θ=θ+α∇θlogπθ(st,at)vt\theta = \theta + \alpha \nabla_{\theta}log \pi_{\theta}(s_t,a_t) v_tθ=θ+α∇θ​logπθ​(st​,at​)vt​

梯度更新部分中,∇θlogπθ(st,at)\nabla_{\theta}log \pi_{\theta}(s_t,a_t)∇θ​logπθ​(st​,at​)是得分函数,无需改变,要变成Actor的话改动的是vtv_tvt​,这块不能再使用蒙特卡罗法来得到,而应该从Critic得到。

而对于Critic来说,完全可以参考之前DQN的做法,即用一个Q网络来做为Critic, 这个Q网络的输入可以是状态,而输出是每个动作的价值或者最优动作的价值。

总体上来说,就是Critic通过Q网络计算状态的最优价值vt, 而Actor利用vtv_tvt​这个最优价值迭代更新策略函数的参数θ,进而选择动作,并得到反馈和新的状态,Critic使用反馈和新的状态更新Q网络参数w, 在后面Critic会使用新的网络参数w来帮Actor计算状态的最优价值vtv_tvt​。

12.2 Actor-Critic框架引出

在上一章中我们已经得到策略梯度的更新公式如下:
∇θJ(θ)≈1N∑n=1N∑t=1Tn(∑t=t′Tnγt′−trt′n−b)∇log⁡πθ(atn∣stn)\nabla_{\theta} J(\theta)\approx \frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}}\left(\sum_{t=t'}^{T_{n}} \gamma^{t'-t} r_{t'}^{n}-b\right) \nabla \log \pi_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)∇θ​J(θ)≈N1​n=1∑N​t=1∑Tn​​(t=t′∑Tn​​γt′−trt′n​−b)∇logπθ​(atn​∣stn​)
这里将∑t=t′Tnγt′−trt′n\sum_{t=t'}^{T_{n}} \gamma^{t'-t} r_{t'}^{n}∑t=t′Tn​​γt′−trt′n​记为GtnG_t^nGtn​,由于GtnG_t^nGtn​通过交互得到,其值非常不稳定(由于环境的动态性,GtnG_t^nGtn​本身也是一个分布),方差会比较大,因此需要寻找减少方差的办法。一种方法就是在上一章中采用的添加基线b, 这个b会使得Gt−bG_t-bGt​−b的期望不变,但是方差会变小,常用的baseline函数就是V(st)V(s_t)V(st​),在此基础上,为了进一步降低GtG_tGt​的随机性,我们用GtnG_t^nGtn​的期望E(Gtn)E(G_t^n)E(Gtn​)替代GtnG_t^nGtn​,这样上面的更新公式变为:
∇θJ(θ)≈1N∑n=1N∑t=1Tn(E(Gtn)−V(stn))∇log⁡πθ(atn∣stn)\nabla_{\theta} J(\theta)\approx \frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}}\left(E(G_t^n)-V(s_t^n)\right) \nabla \log \pi_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)∇θ​J(θ)≈N1​n=1∑N​t=1∑Tn​​(E(Gtn​)−V(stn​))∇logπθ​(atn​∣stn​)

在根据Q学习部分(),可知期望E(Gtn)E(G_t^n)E(Gtn​)就是在状态sts_tst​下执行动作ata_tat​,并遵循策略π\piπ所能得到的Q值,即E(Gt)E(G_t)E(Gt​)=Qπθ(stn,atn)Q^{\pi_{\theta} }\left(s^n_t,a^n_t\right)Qπθ​(stn​,atn​),由此得到下式:
∇θJ(θ)≈1N∑n=1N∑t=1Tn(Qπθ(stn,atn)−V(stn))∇log⁡πθ(atn∣stn)\nabla_{\theta} J(\theta)\approx \frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}}\left(Q^{\pi_{\theta} }\left(s^n_t,a^n_t\right)-V(s_t^n)\right) \nabla \log \pi_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)∇θ​J(θ)≈N1​n=1∑N​t=1∑Tn​​(Qπθ​(stn​,atn​)−V(stn​))∇logπθ​(atn​∣stn​)

上式中存在的问题是,需要两个网络来分别预测Q和V,这就无形中增加了误差来源,考虑到贝尔曼等式,即:

Qπθ(stn,atn)=E[rtn+Vπ(st+1n)]Q^{\pi_{\theta} }\left(s^n_t,a^n_t\right)=E\left[ r_t^n+V^\pi(s_{t+1}^n)\right]Qπθ​(stn​,atn​)=E[rtn​+Vπ(st+1n​)]

这里将期望去掉(个人理解,虽然去掉期望会导致有偏,但是最终还是会收敛到真实值):

Qπθ(stn,atn)=rtn+Vπθ(st+1n)Q^{\pi_{\theta} }\left(s^n_t,a^n_t\right)= r_t^n+V^{\pi_\theta}(s_{t+1}^n)Qπθ​(stn​,atn​)=rtn​+Vπθ​(st+1n​)

那么最终就得到:
∇θJ(θ)≈1N∑n=1N∑t=1Tn(rtn+Vπθ(st+1n)−V(stn))∇log⁡πθ(atn∣stn)\nabla_{\theta} J(\theta)\approx \frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}}\left(r_t^n+V^{\pi_\theta}(s_{t+1}^n)-V(s_t^n)\right) \nabla \log \pi_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)∇θ​J(θ)≈N1​n=1∑N​t=1∑Tn​​(rtn​+Vπθ​(st+1n​)−V(stn​))∇logπθ​(atn​∣stn​)

这样只需要一个网络就可以估算出V值了,而估算V的网络正是我们在Q-learning 中做的,所以我们就把这个网络叫做Critic。这样就在Policy Gradient算法的基础上引进了Q-learning 算法了。

12.3 Actor-Critic算法流程

Critic使用神经网络来计算TD误差并更新网络参数,Actor将TD误差作为输入,也使用神经网络来更新网络参数

算法输入:迭代轮数T,状态特征维度n, 动作集A, 步长α,β,衰减因子γ, 探索率ϵ, Critic网络结构和Actor网络结构。

输出:Actor 网络参数θ, Critic网络参数w
1.随机初始化所有的状态和动作对应的价值Q
2.for i from 1 to T,进行迭代。

  a)初始化S为当前状态序列的第一个状态, 得到其特征向量ϕ(S)\phi(S)ϕ(S)

  b)在Actor网络中使用ϕ(S)\phi(S)ϕ(S)作为输入,输出动作A,基于动作A得到新的状态S′,奖励r。

  c)在Critic网络中分别使用ϕ(S)\phi(S)ϕ(S),ϕ(S’)\phi(S’)ϕ(S’)作为输入,得到Q值输出V(S),V(S′)

  d)计算TD误差δ=R+γV(S’)−V(S)\delta = R +\gamma V(S’) -V(S)δ=R+γV(S’)−V(S)

  e)使用均方差损失函数∑(R+γV(S’)−V(S,w))2\sum\limits(R +\gamma V(S’) -V(S,w))^2∑(R+γV(S’)−V(S,w))2作Critic网络参数w的梯度更新

  f)更新Actor网络参数θ:

θ=θ+α∇θlogπθ(St,A)δ\theta = \theta + \alpha \nabla_{\theta}log \pi_{\theta}(S_t,A)\deltaθ=θ+α∇θ​logπθ​(St​,A)δ

对于Actor的得分函数∇θlogπθ(St,A),可以选择softmax或者高斯分值函数。

12.4 代码练习

代码针对的环境的是 CliffWalkingEnv,在该环境中智能体在一个 4x12 的网格中移动,状态编号如下所示:

[[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11],[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23],[24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35],[36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]]

在任何阶段开始时,初始状态都是状态 36,状态 47 是唯一的终止状态,悬崖对应的是状态 37 到 46。智能体有 4 个可选动作(UP = 0,RIGHT = 1,DOWN = 2,LEFT = 3)。智能体每走一步都会得到-1 的奖励,跌入悬崖会得到-100 的奖励并重置到起点,当达到目标时,片段结束。

AC完整的代码如下:

import gym
import itertools
import matplotlib
import numpy as np
import sys
import tensorflow as tf
import collectionsif "../" not in sys.path:sys.path.append("../")
from Lib.envs.cliff_walking import CliffWalkingEnv
from Lib import plottingmatplotlib.style.use('ggplot')env = CliffWalkingEnv()class PolicyEstimator():"""策略函数逼近"""def __init__(self, learning_rate=0.01, scope="policy_estimator"):with tf.variable_scope(scope):self.state = tf.placeholder(tf.int32, [], "state")self.action = tf.placeholder(dtype=tf.int32, name="action")self.target = tf.placeholder(dtype=tf.float32, name="target")# This is just table lookup estimatorstate_one_hot = tf.one_hot(self.state, int(env.observation_space.n))self.output_layer = tf.contrib.layers.fully_connected(inputs=tf.expand_dims(state_one_hot, 0),num_outputs=env.action_space.n,activation_fn=None,weights_initializer=tf.zeros_initializer)self.action_probs = tf.squeeze(tf.nn.softmax(self.output_layer))self.picked_action_prob = tf.gather(self.action_probs, self.action)self.loss = -tf.log(self.picked_action_prob) * self.targetself.optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)self.train_op = self.optimizer.minimize(self.loss, global_step=tf.contrib.framework.get_global_step())def predict(self, state, sess=None):sess = sess or tf.get_default_session()return sess.run(self.action_probs, {self.state: state})def update(self, state, target, action, sess=None):sess = sess or tf.get_default_session()feed_dict = {self.state: state, self.target: target, self.action: action}_, loss = sess.run([self.train_op, self.loss], feed_dict)return lossclass ValueEstimator():"""值函数逼近器"""def __init__(self, learning_rate=0.1, scope="value_estimator"):with tf.variable_scope(scope):self.state = tf.placeholder(tf.int32, [], "state")self.target = tf.placeholder(dtype=tf.float32, name="target")# This is just table lookup estimatorstate_one_hot = tf.one_hot(self.state, int(env.observation_space.n))self.output_layer = tf.contrib.layers.fully_connected(inputs=tf.expand_dims(state_one_hot, 0),num_outputs=1,activation_fn=None,weights_initializer=tf.zeros_initializer)self.value_estimate = tf.squeeze(self.output_layer)self.loss = tf.squared_difference(self.value_estimate, self.target)self.optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)self.train_op = self.optimizer.minimize(self.loss, global_step=tf.contrib.framework.get_global_step())def predict(self, state, sess=None):sess = sess or tf.get_default_session()return sess.run(self.value_estimate, {self.state: state})def update(self, state, target, sess=None):sess = sess or tf.get_default_session()feed_dict = {self.state: state, self.target: target}_, loss = sess.run([self.train_op, self.loss], feed_dict)return lossdef actor_critic(env, estimator_policy, estimator_value, num_episodes, discount_factor=1.0):"""Actor Critic 算法.通过策略梯度优化策略函数逼近器参数:env: OpenAI环境.estimator_policy: 待优化的策略函数estimator_value: 值函数逼近器,用作评论家num_episodes: 回合数discount_factor: 折扣因子返回值:EpisodeStats对象,包含两个numpy数组,分别存储片段长度和片段奖励"""# Keeps track of useful statisticsstats = plotting.EpisodeStats(episode_lengths=np.zeros(num_episodes),episode_rewards=np.zeros(num_episodes))Transition = collections.namedtuple("Transition", ["state", "action", "reward", "next_state", "done"])for i_episode in range(num_episodes):state = env.reset()episode = []for t in itertools.count():action_probs = estimator_policy.predict(state)action = np.random.choice(np.arange(len(action_probs)), p=action_probs)next_state, reward, done, _ = env.step(action)episode.append(Transition(state=state, action=action, reward=reward, next_state=next_state, done=done))stats.episode_rewards[i_episode] += rewardstats.episode_lengths[i_episode] = t# 计算TD目标value_next = estimator_value.predict(next_state)td_target = reward + discount_factor * value_nexttd_error = td_target - estimator_value.predict(state)# 更新值函数逼近estimator_value.update(state, td_target)# 更新策略逼近# 使用TD误差作为优势估计estimator_policy.update(state, td_error, action)print("\rStep {} @ Episode {}/{} ({})".format(t, i_episode + 1, num_episodes, stats.episode_rewards[i_episode - 1]), end="")if done:breakstate = next_statereturn statstf.reset_default_graph()global_step = tf.Variable(0, name="global_step", trainable=False)
policy_estimator = PolicyEstimator()
value_estimator = ValueEstimator()with tf.Session() as sess:sess.run(tf.initialize_all_variables())stats = actor_critic(env, policy_estimator, value_estimator, 300)plotting.plot_episode_stats(stats, smoothing_window=10)

结果如下:

第十二章 演员评论家(Actor-Critic)-强化学习理论学习与代码实现(强化学习导论第二版)相关推荐

  1. 程序员编程艺术第一 二十二章集锦与总结(教你如何编程)

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 程序员编 ...

  2. 程序员编程艺术第一~二十二章集锦与总结(教你如何编程)

    程序员编程艺术第一~二十二章集锦与总结(教你如何编程) 作者:July.编程艺术室. 出处:http://blog.csdn.net/v_JULY_v . 题记 好久没更新博客了,虽只有一个月,但对我 ...

  3. 价格奥秘-在超市遇见亚当斯密--第十二章 生活与价格有关,生命不靠金钱决定

    第十二章生活与价格有关,生命不靠金钱决定 在毕业典礼这一天,鲁思醒得很早.她查了一下电子邮件,看了助理前一天深夜发来的活动日程.要和鲍勃.巴克曼及艺术与科学系的系主任一起共进早餐.她不知道该怎么办.就 ...

  4. stm32l0的停止模式怎么唤醒_探索者 STM32F407 开发板资料连载第二十二章 待机唤醒实验

    1)实验平台:alientek 阿波罗 STM32F767 开发板 2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第二十二章 待机唤醒实 ...

  5. 构建之法第十,十一,十二章阅读

    第十章经典用户和场景 虽说经典场景和经典用户很有必要去研究去效仿,但是随着时间发展,新的用户新的需求不断涌现,那该怎么平衡? 第十一章软件设计与实现 软件设计过程中,如何管理设计变更呢? 第十二章用户 ...

  6. 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条

    http://blog.csdn.net/terryzero/article/details/3797782 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条 标签: swing编程 ...

  7. stm32 文件系统dma大小_「正点原子NANO STM32F103开发板资料连载」第二十二章 DMA 实验...

    1)实验平台:[正点原子] NANO STM32F103 开发板 2)摘自<正点原子STM32 F1 开发指南(NANO 板-HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 ...

  8. 系统架构师学习笔记_第十二章_连载

    第十二章  系统安全架构设计 12.1  信息系统安全架构的简单描述 信息安全的特征 是为了保证信息的 机密性.完整性.可用性.可控性.不可抵赖性. 以风险策略为基础. 12.1.1  信息安全的现状 ...

  9. 《c++ templates》学习笔记(9)——第十二章 特化与重载

    1       第十二章 特化与重载 1.1    重载函数模板 和一般的函数重载类似,函数模板也可以进行重载,比如下面的两个f,这是两个同名函数,1和2并没有关系,2不是1的局部特化.2是1的一个重 ...

  10. 开发日记-20190915 关键词 汇编语言王爽版 第十二章

    第十二章 内中断 任何一个通用的CPU,比如8086,都具备一种能力,可以在执行完当前正在执行的指令之后,检测到从CPU外部传送过来或内部产生的一种特殊信息,并且可以立即对所接收的信息进行处理.这种特 ...

最新文章

  1. Java数据结构与算法:二叉树
  2. 【模型解读】从2D卷积到3D卷积,都有什么不一样
  3. 科大讯飞智慧医疗再出重磅,“智医助理”机器人顺利通过临床执业医师综合笔试...
  4. Atitit. 高级软件工程师and 普通的区别 高级编程的门槛总结
  5. Arrays.asList(arr)使用注意事项
  6. OAG – WhoIsWho 同名消歧竞赛发布 | 10万元奖金双赛道
  7. 数论-朴素卢卡斯(Lucas)模板
  8. php与c有什么区别,.c与.cpp文件的一点区别
  9. python学习第三十二节(进程间通信、进程池、协程)
  10. 算法训练营 重编码_编码训练营之后该做什么-以及如何获得成功
  11. 英语学习笔记2019-11-15
  12. Centos7 把php5.4升级到php5.6
  13. python动态心形代码_父亲节,程序员几条代码硬核示爱
  14. Ubuntu 安装 typora
  15. C++ 虚函数表解析(转)
  16. 重温马尔科夫随机过程
  17. 安装Windows10操作系统
  18. 最新传奇游戏公司网站模板源码+带手机端/易优CMS内核
  19. gitter 卸载_最佳Gitter渠道:学习编码
  20. 计算机软件实习每日学习打卡(1)20201130

热门文章

  1. 经典排序算法(十六)--珠排序Bead Sort
  2. C++ 实现反射机制(转载)
  3. python 反传播_Python:反向传播 (六十八)
  4. python可选参数定义_Python中函数的参数定义和可变参数用法实例分析
  5. Error: Invalid or corrupt
  6. python mysql 连接超时时间_一段时间后MySQL连接超时(Python、MySQL、FLASK)
  7. flash动画制作成品_Flash如何制作雪糕被吃掉的动画
  8. java 生成条形码_Springboot生成二维码,怎么搞?
  9. verilog设计一个补码加减法运算器_一文搞懂:计算机中为什么用补码来存储数据?...
  10. 软件测试测试用例编写 不超过7步骤_软件测试(功能、接口、性能、自动化)详解...