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

2023-10-26

在这里插入图片描述
获取更多资讯,赶快关注上面的公众号吧!

【强化学习系列】

第十二章 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(as,θ)π(as)

第二组是价值函数的近似,对于状态价值和动作价值函数分别是:
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算法中,策略的参数更新公式是:
θ = θ + α ∇ θ l o g π θ ( s t , a t ) v t \theta = \theta + \alpha \nabla_{\theta}log \pi_{\theta}(s_t,a_t) v_t θ=θ+αθlogπθ(st,at)vt

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

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

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

12.2 Actor-Critic框架引出

在上一章中我们已经得到策略梯度的更新公式如下:
∇ θ J ( θ ) ≈ 1 N ∑ n = 1 N ∑ t = 1 T n ( ∑ t = t ′ T n γ t ′ − t r t ′ n − b ) ∇ log ⁡ π θ ( a t n ∣ s t n ) \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(θ)N1n=1Nt=1Tn(t=tTnγttrtnb)logπθ(atnstn)
这里将 ∑ t = t ′ T n γ t ′ − t r t ′ n \sum_{t=t'}^{T_{n}} \gamma^{t'-t} r_{t'}^{n} t=tTnγttrtn记为 G t n G_t^n Gtn,由于 G t n G_t^n Gtn通过交互得到,其值非常不稳定(由于环境的动态性, G t n G_t^n Gtn本身也是一个分布),方差会比较大,因此需要寻找减少方差的办法。一种方法就是在上一章中采用的添加基线b, 这个b会使得 G t − b G_t-b Gtb的期望不变,但是方差会变小,常用的baseline函数就是 V ( s t ) V(s_t) V(st),在此基础上,为了进一步降低 G t G_t Gt的随机性,我们用 G t n G_t^n Gtn的期望 E ( G t n ) E(G_t^n) E(Gtn)替代 G t n G_t^n Gtn,这样上面的更新公式变为:
∇ θ J ( θ ) ≈ 1 N ∑ n = 1 N ∑ t = 1 T n ( E ( G t n ) − V ( s t n ) ) ∇ log ⁡ π θ ( a t n ∣ s t n ) \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(θ)N1n=1Nt=1Tn(E(Gtn)V(stn))logπθ(atnstn)

在根据Q学习部分(),可知期望 E ( G t n ) E(G_t^n) E(Gtn)就是在状态 s t s_t st下执行动作 a t a_t at,并遵循策略 π \pi π所能得到的Q值,即 E ( G t ) E(G_t) E(Gt)= Q π θ ( s t n , a t n ) Q^{\pi_{\theta} }\left(s^n_t,a^n_t\right) Qπθ(stn,atn),由此得到下式:
∇ θ J ( θ ) ≈ 1 N ∑ n = 1 N ∑ t = 1 T n ( Q π θ ( s t n , a t n ) − V ( s t n ) ) ∇ log ⁡ π θ ( a t n ∣ s t n ) \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(θ)N1n=1Nt=1Tn(Qπθ(stn,atn)V(stn))logπθ(atnstn)

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

Q π θ ( s t n , a t n ) = E [ r t n + V π ( s t + 1 n ) ] 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 π θ ( s t n , a t n ) = r t n + V π θ ( s t + 1 n ) 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 ( θ ) ≈ 1 N ∑ n = 1 N ∑ t = 1 T n ( r t n + V π θ ( s t + 1 n ) − V ( s t n ) ) ∇ log ⁡ π θ ( a t n ∣ s t n ) \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(θ)N1n=1Nt=1Tn(rtn+Vπθ(st+1n)V(stn))logπθ(atnstn)

这样只需要一个网络就可以估算出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网络参数θ:

θ = θ + α ∇ θ l o g π θ ( S t , 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 collections

if "../" not in sys.path:
    sys.path.append("../")
from Lib.envs.cliff_walking import CliffWalkingEnv
from Lib import plotting

matplotlib.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 estimator
            state_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.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.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 loss


class 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 estimator
            state_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 loss


def 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 statistics
    stats = 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] += reward
            stats.episode_lengths[i_episode] = t

            # 计算TD目标
            value_next = estimator_value.predict(next_state)
            td_target = reward + discount_factor * value_next
            td_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:
                break

            state = next_state

    return stats


tf.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)

结果如下:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • <七>、Hadoop Web项目--HDFS文件管理

    本博客参考 http blog csdn net fansy1990 article details 51356583 一 项目介绍 推荐系统的web项目已经完成 现在在此基础上增加HDFS文件管理功能 便于管理HDFS上的文件数据 本文基

随机推荐

  • 面试题创作0009,请问Linux kernel中的spinlock_t 是如何实现互斥访问同一数据的?

    面试题创作0007 请问Linux kernel中的spinlock t 是如何实现互斥访问同一数据的 在单核多线程 多核多线程 多cpu多线程中 spinlock t实现互斥的机制有区别么 分别是什么呢 进一步列举一些使用spinlock
  • PLC是如何控制伺服电机的?

    在回答这个问题之前 首先要清楚伺服电机的用途 相对于普通的电机来说 伺服电机主要用于精确定位 因此大家通常所说的伺服控制 其实就是对伺服电机的位置控制 其实 伺服电机还用另外两种工作模式 那就是速度控制和转矩控制 不过应用比较少而已 速度控
  • Java通过反射模拟冰蝎免杀功能

    一 Java反射 java反射算是java学习过程中不可绕过的一关 java 反射 反射允许运行中的Java程序获取自身的信息 并且可以操作类或对象的内部属性 反射的核心是JVM在运行时动态加载类或调用方法或访问属性 class 类 我们正
  • 前端模块化:匿名闭包、CommonJS、ES6模块化

    ES5时 用匿名函数实现的模块化 通过将代码放在闭包当中 使得命名不会冲突 每一个js文件都成为独立的模块 需要复用代码时 将闭包中的结构返回到全局作用域即可 通过模块名 方法 属性的方法使用 a js var moduleA functi
  • 2022年第十四届“华中杯”大学生数学建模挑战赛

    2022年第十三届 华中杯 大学生数学建模挑战赛 为了推广我国高校数学建模实践教学 培养学生的创新意识及运用数学方法和计算机技术解决实际问题的能力 第十四届 华中杯 大学生数学建模挑战赛 以下简称竞赛 将于2022年3月开始 举办竞赛的目的
  • 【无标题】力扣链表总结

    k个一组反转链表 25 前置知识1 2 反转整个链表 反转以 a 为头结点的链表 ListNode reverse ListNode a ListNode pre cur nxt pre null cur a nxt a while cur
  • 1.网络工程基础知识

    目录 1 1 网络工程的定义 1 可以通过以下几个方面加强对工程的了解 2 网络工程属于IT集成工程 1 2 网络工程实施原则 1 从网络整体性能上考虑 IT工程实施需要遵守以下原则 2 从企业成本考虑 IT工程实施则需要遵守以下一些原则
  • Windows下自定义文件类型如何双击打开,如何双击文件后都在一个实例中打开

    1 要实现文件双击打开 需要在注册表中将文件类型与要打开文件的程序相关联 在HKEY CURRENT USER Software Classes 或者 HKEY LOCAL MACHINE Software Classes 下创建 xxxx
  • 【贪心算法】最优服务次序问题

    算法实现题 4 6 最优服务次序问题 设有n个顾客同时等待一项服务 顾客i需要的服务时间为ti 应如何安排n个顾客的服务次序才能使平均等待时间达到最小 平均等待时间是n个顾客等待直到完成服务的时间总和除以n 对于给定的n个顾客需要的服务时间
  • gp 索引列表查询,表字段类型,字段注释查询

    所有索引列表 SELECT n nspname as Schema c relname as Name c2 relname as Table FROM pg catalog pg class c JOIN pg catalog pg ro
  • 解决v-for轮播图中图片无法显示

    v fo中src拿不到img的地址 图片无法显示 view可以打印出list data中的img值 说明数组没问题 已经拿到图片值 将src直接赋值地址 有图片显示 那么就是src没有拿到图片地址 网页元素检查中也发现 这里的图片img中没
  • 无盘服务器2018,2018无盘服务器配置

    2018无盘服务器配置 内容精选 换一换 华为云帮助中心 为用户提供产品简介 价格说明 购买指南 用户指南 API参考 最佳实践 常见问题 视频帮助等技术文档 帮助您快速上手使用华为云服务 源端服务器数据收集声明 源端服务器上安装和配置完迁
  • Nerd Font 字体安装

    一 Nerd Font 是什么 Nerd Font 是为开发人员准备的 具有大量字形 图标 的字体 特别是从流行的 标志性字体 中添加大量额外的字形 如Font Awesome Devicons Octicons等 二 安装步骤 1 克隆仓
  • React 下 message组件属性设置

    式子 message info content React ReactNode duration number gt void onClose configonClose 例子 message info 提示内容 自动关闭的延时 单位秒 设
  • MATLAB实现PSO-DBN算法优化深度置信网络的多输入单输出回归预测

    MATLAB实现PSO DBN算法优化深度置信网络的多输入单输出回归预测 随着数据分析和机器学习技术的不断发展 深度学习作为一种强大的分析工具广泛应用于各个领域 在时间序列预测领域中 深度置信网络 Deep Belief Network D
  • c/c++基础(二十三) GDB调试入门

    用GDB调试程序 GDB概述 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具 或许 各位比较喜欢那种图形界面方式的 像VC BCB等IDE的调试 但如果你是在UNIX平台下做软件 你会发现GDB这个调试工具有比VC BCB的
  • Testing ovn manually based on LXD (by quqi99)

    作者 张华 发表于 2022 05 27 版权声明 可以任意转载 转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 准备两个LXD容器 lxc list NAME STATE IPV4 IPV6 TYPE SNAPSHOTS
  • 通过 Git 将代码提交到 GitHub

    通过 Git 将代码提交到 GitHub 文章目录 通过 Git 将代码提交到 GitHub 第一种 本地没有 Git 仓库 clone GitHub 上已有的仓库 第二种 将本地普通仓库变成 Git 仓库 并推送到 GitHub 第三种
  • Win7 计算机中丢失api-ms-win-core-path-

    背景 win7安装软件时提示 无法启动此程序 因为计算机中丢失api ms win core path 1 1 0 dll 问题原因 缺少api ms win core path 1 1 0 dll 解决方式 下载dll并放到指定路径 下载
  • 第十二章 演员评论家(Actor-Critic)-强化学习理论学习与代码实现(强化学习导论第二版)

    获取更多资讯 赶快关注上面的公众号吧 强化学习系列 第一章 强化学习及OpenAI Gym介绍 强化学习理论学习与代码实现 强化学习导论第二版 第二章 马尔科夫决策过程和贝尔曼等式 强化学习理论学习与代码实现 强化学习导论第二版 第三章 动