【强化学习】Policy Gradient算法详解

DeepMind公开课https://sites.google.com/view/deep-rl-bootcamp/lectures
David Silver教程 http://www0.cs.ucl.ac.uk/staff/d.silver/web/Teaching.html
morvanzhou课程https://morvanzhou.github.io/tutorials/machine-learning/reinforcement-learning/
李宏毅教授DRL Lecture https://www.youtube.com/watch?v=z95ZYgPgXOY

【强化学习】Policy Gradient算法详解

1、算法思想

之前的QLearning DQN Sarsa都是通过计算动作得分来决策的,我们是在确定了价值函数的基础上采用某种策略(贪婪-epsilon)的方式去选取动作。经过学习发现Policy Gradient并非我预料中的策略迭代,这种策略梯度的算法归类于策略优化算法中,而不是以迭代为基础的动态规划算法。
这里写图片描述
Policy Gradient不通过误差反向传播,它通过观测信息选出一个行为直接进行反向传播,当然出人意料的是他并没有误差,而是利用reward奖励直接对选择行为的可能性进行增强和减弱,好的行为会被增加下一次被选中的概率,不好的行为会被减弱下次被选中的概率。
举例如下图所示:输入当前的状态,输出action的概率分布,选择概率最大的一个action作为要执行的操作。
在这里插入图片描述而一个完整的策略 τ 代表的是一整个回合中,对于每个状态下所采取的的动作所构成的序列,而每个回合episode中每个动作的回报和等于一个回合的回报值 R = ∑ t = 1 T r t R =\sum_{t=1}^Tr_t R=t=1Trt
在这里插入图片描述通过以上可得知 π在参数为θ情况下时 τ 发生的概率:
在这里插入图片描述得到了概率之后我们就可以根据采样得到的回报值计算出数学期望,从而得到目标函数,然后用来更新我们的参数 θ
在这里插入图片描述

优点:

  • 连续的动作空间(或者高维空间)中更加高效;
  • 可以实现随机化的策略;
  • 某种情况下,价值函数可能比较难以计算,而策略函数较容易。

缺点:

  • 通常收敛到局部最优而非全局最优
  • 评估一个策略通常低效(这个过程可能慢,但是具有更高的可变性,其中也会出现很多并不有效的尝试,而且方差高

2、公式推导

在本篇文章将会使用参数θ逼近拟合状态值函数 V π ( s ) V_π(s) Vπ(s)和状态动作值函数 Q π ( s , a ) Q_π(s,a) Qπ(s,a) 可以理解为我们使用比如神经网络的的function来逼近拟合状态值函数 V π ( s ) V_π(s) Vπ(s)和状态动作值函数 Q π ( s , a ) Q_π(s,a) Qπ(s,a) 的分布。
V θ ( s ) ≈ V π ( s ) V_θ(s)≈V_π(s) Vθ(s)Vπ(s)
Q θ ( s , a ) ≈ Q π ( s , a ) Q_θ(s,a)≈Q_π(s,a) Qθ(s,a)Qπ(s,a)
并且将策略Policy参数化为 π θ ( s , a ) = P ( a ∣ s , θ ) π_\theta(s,a) = P(a|s,\theta) πθ(s,a)=P(as,θ),使用model-free的方法,不借助与agent做决策而是将agent丢入不确定的动态环境下,不提供动态环境的信息,让agent自己瞎溜达根据所获得的策略信息更新参数。
通常情况下目标策略有三种方式

  • 使用初始价值来判断: J 1 ( θ ) = V π θ ( s 1 ) = E π θ [ v 1 ] J_1(θ)=V^{π_θ}(s1)=E_{π_θ}[v_1] J1(θ)=Vπθ(s1)=Eπθ[v1]
  • 使用平均价值: J a v V ( θ ) = ∑ s d π θ ( s ) V π θ ( s ) J_{av}V(θ)=∑_sd^{π_θ}(s)V^{π_θ}(s) JavV(θ)=sdπθ(s)Vπθ(s)
  • 使用每次time-step的平均奖励: J a v R ( θ ) = ∑ s d π θ ( s ) ∑ a π θ ( s , a ) R s a J_{av}R(θ)=∑_sd^{π_θ}(s)∑_aπ_θ(s,a)R^a_s JavR(θ)=sdπθ(s)aπθ(s,a)Rsa

我们暂定使用初始值法做目标策略

J ( θ ) = V π θ ( s 1 ) = E π θ [ v 1 ] = E ( r 1 + γ r 2 + γ 2 r 3 + . . . . . . . ∣ π θ ) J(\theta)=V^{π_θ}(s1)=E_{π_θ}[v_1]=E(r_1+\gamma r_2 +\gamma^2r_3+.......|\pi_\theta) J(θ)=Vπθ(s1)=Eπθ[v1]=E(r1+γr2+γ2r3+.......πθ)

对该目标函数进行最大化也就是在搜索一组参数向量 θ \theta θ ,使得目标函数最大。这实际上做的是改变策略概率而非改变行动轨迹的工作,所以根据套路我们接下来就要使用梯度下降求解 ∇ θ J ( θ ) ∇_θJ(θ) θJ(θ)

∇ θ J ( θ ) = ( ∂ J ( θ ) ∂ θ 1 ⋮ ∂ J ( θ ) ∂ θ n ) ∇_θJ(θ) = \begin{pmatrix}\frac{∂J(θ)}{∂θ_1 }\\ ⋮ \\\frac{∂J(θ)}{∂θ_n }\end{pmatrix} θJ(θ)=θ1J(θ)θnJ(θ)

在连续策略上选用Gaussian Policy在离散策略下采用softmax Policy

策略梯度定理(The policy gradient theorem)

由于我们是基于model-free的所以无法事先知道动态环境的状态分布,而奖励函数有依赖于动作和状态分布,所以无法进行求导,所以我们需要把奖励采用无偏估计的方法计算出来,首先随机采样然后取均值来估计

假设一个只有一步的MDP,对它使用策略梯度下降。 π θ ( s , a ) π_θ(s,a) πθ(s,a)表示关于参数θ的函数,映射是 P ( a ∣ s , θ ) P(a|s,θ) P(as,θ)。它在状态s所执行一a动作的奖励即为 r = R ( s , a ) r=R(s,a) r=R(s,a)。那么选择行动a的奖励为 π θ ( s , a ) R s , a π_θ(s,a)R_{s,a} πθ(s,a)Rs,a,在状态 s 的加权回报为 ∑ a ∈ A π θ ( s , a ) R ( s , a ) ∑_{a∈A}π_θ(s,a)R(s,a) aAπθ(s,a)R(s,a),推导如下

J ( θ ) = E π θ [ R ( s , a ) ] J(θ)=E_{π_θ}[R(s,a)] J(θ)=Eπθ[R(s,a)]
J ( θ ) = ∑ s ∈ S d ( s ) ∑ a ∈ A π θ ( s , a ) R ( s , a ) J(θ)=∑_{s∈S}d(s)∑_{a∈A}π_θ(s,a)R(s,a) J(θ)=sSd(s)aAπθ(s,a)R(s,a)

梯度为:
∇ θ J ( θ ) = ∇ θ ∑ s ∈ S d ( s ) ∑ a ∈ A π θ ( s , a ) R ( s , a ) ∇_θJ(θ)=∇_θ∑_{s∈S}d(s)∑_{a∈A}π_θ(s,a)R(s,a) θJ(θ)=θsSd(s)aAπθ(s,a)R(s,a)
∇ θ J ( θ ) = ∑ s ∈ S d ( s ) ∑ a ∈ A ∇ θ π θ ( s , a ) R ( s , a ) ∇_θJ(θ)=∑_{s∈S}d(s)∑_{a∈A}∇_θπ_θ(s,a)R(s,a) θJ(θ)=sSd(s)aAθπθ(s,a)R(s,a)

假设策略 π θ π_θ πθ为零的时候可微,并且已知梯度 ∇ θ π θ ( s , a ) ∇_θπ_θ(s,a) θπθ(s,a),应用似然比(likelihood ratio)的技巧定义 ∇ θ l o g π θ ( s , a ) ∇_θlogπ_θ(s,a) θlogπθ(s,a)为得分函数(score function)。二者关系如下:
∇ θ π θ ( s , a ) = π θ ( s , a ) ∇ θ π θ ( s , a ) π θ ( s , a ) = π θ ( s , a ) ∇ θ l o g π θ ( s , a ) ∇_θπ_θ(s,a)=π_θ(s,a)\frac{∇_θπ_θ(s,a)}{π_θ(s,a)}=π_θ(s,a)∇_θlogπ_θ(s,a) θπθ(s,a)=πθ(s,a)πθ(s,a)θπθ(s,a)=πθ(s,a)θlogπθ(s,a)

∇ θ J ( θ ) = ∑ s ∈ S d ( s ) ∑ a ∈ A π θ ( s , a ) ∇ θ l o g π θ ( s , a ) R ( s , a ) ∇_θJ(θ)=∑_{s∈S}d(s)∑_{a∈A}π_θ(s,a)∇_θlogπ_θ(s,a)R(s,a) θJ(θ)=sSd(s)aAπθ(s,a)θlogπθ(s,a)R(s,a)

根据上文d(s)是策略中的状态分布, π ( s , a ) \pi(s,a) π(s,a)是当前状态的动作概率分布,所以可将策略梯度恢复成期望形式:

∇ θ J ( θ ) = E π θ [ ∇ θ l o g π θ ( s , a ) R ( s , a ) ] ∇_θJ(θ)=E_{π_θ}[∇_θlogπ_θ(s,a)R(s,a)] θJ(θ)=Eπθ[θlogπθ(s,a)R(s,a)]

然后再将似然率方式的策略梯度方法应用到多步MDPs上,此时的因为回报值应该为过程中的多步回报值之和,在这里使用 Q π ( s , a ) Q_π(s,a) Qπ(s,a)代替奖励值R单步(s,a),对于任意可微的策略梯度如下(策略价值计算公式):

∇ θ J ( θ ) = E π θ [ ∇ θ l o g π θ ( s , a ) Q π θ ( s , a ) ] ∇_θJ(θ)=E_{π_θ}[∇_θlogπ_θ(s,a)Q^{π_θ}(s,a)] θJ(θ)=Eπθ[θlogπθ(s,a)Qπθ(s,a)]

策略梯度定理详细推导过程如下
这里写图片描述

蒙特卡洛梯度策略强化算法Monte-Carlo Policy Gradient

(不带基数)蒙特卡洛策略梯度通过情节采样,使用随机梯度上升法更新参数,使用策略梯度法,返回 v t v_t vt作为 Q π θ ( s t , a t ) 的 无 偏 估 计 Q^{π_θ}(s_t,a_t)的无偏估计 Qπθ(st,at)

Δ θ t = α ∇ θ l o g π θ ( s t , a t ) v t Δθ_t=α∇_θlogπ_θ(s_t,a_t)v_t Δθt=αθlogπθ(st,at)vt

所以可得更新公式

θ t + 1 ← θ + α ∇ θ l o g π θ ( s t , a t ) v t \theta_{t+1} ← \theta + \alpha∇_θlogπ_θ(s_t,a_t)v_t θt+1θ+αθlogπθ(st,at)vt

算法伪代码如下
这里写图片描述

带基数的蒙特卡洛梯度策略强化算法ERINFORCE with baseline

在某些情况下可能会出现每一个动作的回报值都是正数但是由于我们是通过采样的方式进行更新的所以这时候可以引入一个基数b
则原式需要修改为
∇ θ J ( θ ) = E π θ [ ∇ θ l o g π θ ( s , a ) [ Q π θ ( s , a ) − b ( s ) ] ] ∇_θJ(θ)=E_{π_θ}[∇_θlogπ_θ(s,a)[Q^{π_θ}(s,a)-b(s)]] θJ(θ)=Eπθ[θlogπθ(s,a)[Qπθ(s,a)b(s)]]

3、算法实现

class PolicyGradient:
    def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95, output_graph=True):
        self.n_actions = n_actions
        self.n_features = n_features
        self.lr = learning_rate  # 学习率
        self.gamma = reward_decay  # reward 递减率

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []  # 这是我们存储 回合信息的 list

        self._build_net()  # 建立 policy 神经网络

        self.sess = tf.Session()

        if output_graph:  # 是否输出 tensorboard 文件
            # $ tensorboard --logdir=logs
            # http://0.0.0.0:6006/
            # tf.train.SummaryWriter soon be deprecated, use following
            tf.summary.FileWriter(r'D:\logs', self.sess.graph)

        self.sess.run(tf.global_variables_initializer())

    def _build_net(self):
        with tf.name_scope('inputs'):
            self.tf_obs = tf.placeholder(tf.float32, [None, self.n_features], name="observations")  # 接收 observation
            self.tf_acts = tf.placeholder(tf.int32, [None, ], name="actions_num")  # 接收我们在这个回合中选过的 actions
            self.tf_vt = tf.placeholder(tf.float32, [None, ],
                                        name="actions_value")  # 接收每个 state-action 所对应的 value (通过 reward 计算)

        # fc1
        layer = tf.layers.dense(
            inputs=self.tf_obs,
            units=10,  # 输出个数
            activation=tf.nn.tanh,  # 激励函数
            kernel_initializer=tf.random_normal_initializer(mean=0, stddev=0.3),
            bias_initializer=tf.constant_initializer(0.1),
            name='fc1'
        )
        # fc2
        all_act = tf.layers.dense(
            inputs=layer,
            units=self.n_actions,  # 输出个数
            activation=None,  # 之后再加 Softmax
            kernel_initializer=tf.random_normal_initializer(mean=0, stddev=0.3),
            bias_initializer=tf.constant_initializer(0.1),
            name='fc2'
        )

        self.all_act_prob = tf.nn.softmax(all_act, name='act_prob')  # 激励函数 softmax 出概率

        with tf.name_scope('loss'):
            # 最大化 总体 reward (log_p * R) 就是在最小化 -(log_p * R), 而 tf 的功能里只有最小化 loss
            neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=all_act,
                                                                          labels=self.tf_acts)  # 所选 action 的概率 -log 值
            # 下面的方式是一样的:
            # neg_log_prob = tf.reduce_sum(-tf.log(self.all_act_prob)*tf.one_hot(self.tf_acts, self.n_actions), axis=1)
            loss = tf.reduce_mean(neg_log_prob * self.tf_vt)  # (vt = 本reward + 衰减的未来reward) 引导参数的梯度下降

        with tf.name_scope('train'):
            self.train_op = tf.train.AdamOptimizer(self.lr).minimize(loss)

    def choose_action(self, observation):
        prob_weights = self.sess.run(self.all_act_prob, feed_dict={self.tf_obs: observation[np.newaxis, :]})    # 所有 action 的概率
        action = np.random.choice(range(prob_weights.shape[1]), p=prob_weights.ravel())  # 根据概率来选 action
        return action

    def store_transition(self, s, a, r):
        self.ep_obs.append(s)
        self.ep_as.append(a)
        self.ep_rs.append(r)

    def learn(self):
        # 衰减, 并标准化这回合的 reward
        discounted_ep_rs_norm = self._discount_and_norm_rewards()  # 功能再面

        # train on episode
        self.sess.run(self.train_op, feed_dict={
            self.tf_obs: np.vstack(self.ep_obs),  # shape=[None, n_obs]
            self.tf_acts: np.array(self.ep_as),  # shape=[None, ]
            self.tf_vt: discounted_ep_rs_norm,  # shape=[None, ]
        })

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []  # 清空回合 data
        return discounted_ep_rs_norm  # 返回这一回合的 state-action value

    def _discount_and_norm_rewards(self):
        # discount episode rewards
        discounted_ep_rs = np.zeros_like(self.ep_rs)
        running_add = 0
        for t in reversed(range(0, len(self.ep_rs))):
            running_add = running_add * self.gamma + self.ep_rs[t]
            discounted_ep_rs[t] = running_add

        # normalize episode rewards
        discounted_ep_rs -= np.mean(discounted_ep_rs)
        discounted_ep_rs /= np.std(discounted_ep_rs)
        return discounted_ep_rs
好的,下面我将为您介绍一个简单的强化学习 policy gradient 的实例。 假设我们有一个小车在一条直线上移动,小车只能向左或向右移动一格,并且每次移动会消耗一定的能量。我们的目标是让小车尽可能快地到达终点,同时尽量少地消耗能量。 为了解决这个问题,我们可以使用 policy gradient 方法。具体来说,我们可以定义一个策略网络,它的输入是当前小车所处的位置,输出是一个概率分布,表示小车向左或向右移动的概率。我们使用该策略网络来生成小车的移动轨迹,并计算每个轨迹的总能量消耗和到达终点所需的步数。然后,使用 policy gradient 方法来更新策略网络的参数,使得总能量消耗最小化。 下面是具体的步骤: 1. 定义策略网络。假设我们使用一个简单的全连接神经网络,它的输入是当前小车所处的位置,输出是一个两维向量,表示小车向左或向右移动的概率。 2. 定义损失函数。我们使用交叉熵作为损失函数,即将策略网络的输出与实际移动方向的 one-hot 向量进行比较,并计算交叉熵损失。 3. 生成轨迹。使用当前的策略网络生成小车的移动轨迹,并计算每个轨迹的总能量消耗和到达终点所需的步数。 4. 计算梯度。使用 policy gradient 方法计算梯度。具体来说,对于每个轨迹,我们计算其总能量消耗和到达终点所需的步数与所有轨迹中的平均值的差异,并将该差异乘以该轨迹的梯度。最终,将所有轨迹的梯度进行平均,得到策略网络的梯度。 5. 更新策略网络参数。使用梯度下降或其他优化算法来更新策略网络的参数,使得总能量消耗最小化。 6. 重复步骤 3-5,直到策略网络收敛。 以上就是一个简单的强化学习 policy gradient 的实例。当然,在实际应用中,还需要考虑许多细节和优化,如使用基线来减小方差、使用函数逼近器来处理高维状态空间等。
评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值