Policy Gradient

本文深入浅出地介绍了 Policy Gradient 方法的基本概念及其在强化学习中的应用。从策略的概念出发,逐步解析 Policy Gradient 的算法原理,包括其如何通过直接调整策略参数来优化动作选择,以实现对连续动作空间的有效探索。
摘要由CSDN通过智能技术生成

简介

强化学习是一个通过奖惩来学习正确行为的机制。 家族中有很多种不一样的成员,有学习奖惩值,根据自己认为的高价值选行为, 比如 Q learning, Deep Q Network, 也有不通过分析奖励值,直接输出行为的方法,这就是今天要说的 Policy Gradient 了。甚至我们可以为 Policy Gradients 加上一个神经网络来输出预测的动作。对比起以值为基础的方法,Policy Gradients 直接输出动作的最大好处就是,它能在一个连续区间内挑选动作,而基于值的,比如 Q-learning,它如果在无穷多的动作中计算价值,从而选择行为,这,它可吃不消。

1.什么是Policy

在这里插入图片描述
如上图,一个由 Agent(相当于我们的模型)和 Environment(所处状态)组成的结构。Agent 通过观察当前环境的状态 s t s_t st,得出当前应当执行的动作 a t a_t at。Agent 执行完动作之后环境对应发生了改变,并且环境会给予 Agent 一个反馈 reward r t r_t rt。此时又会是一个新的环境状态 s ′ s' s,基于本次的环境状态,Agent 又会执行对应的动作… 以此类推持续进行下去,直到无法继续。如下图所示,Env 表示环境,Actor 即为 Agent:
在这里插入图片描述

上面实际上就是对一系列操作进行了抽象描述。以玩游戏为例说明,我们(Agent)通过观察游戏(Environment)
的运行情况(State),选择接下来要执行的操作(Action),游戏往往还会反馈给我们我们的得分(Rewards)。

2、算法思想

Policy Gradient 不通过误差反向传播,它通过观测信息选出一个行为直接进行反向传播,当然出人意料的是他并没有误差,而是利用 reward 奖励直接对选择行为的可能性进行增强和减弱,好的行为会被增加下一次被选中的概率,不好的行为会被减弱下次被选中的概率。
举例如下图所示:输入当前的状态,输出 action 的概率分布,选择概率最大的一个 action 作为要执行的操作。在不同的状态(State)采取的动作 Action 也就是我们所说的策略 Policy 。 常用符号 π π π 来表示策略。
在这里插入图片描述
而一个完整的策略 τ τ τ 代表的是一整个回合中,对于每个状态下所采取的的动作所构成的序列,而每个回合 episode 中每个动作的回报和等于一个回合的回报值 R = ∑ t = 1 T r t R = ∑ _{t = 1} ^T r_t R=t=1Trt
在这里插入图片描述
Trajectory τ τ τ :行动 action 和状态 state 的序列
p θ ( τ ) p_θ(τ) pθ(τ) π π π 在参数为 θ θ θ 情况下时 τ τ τ 发生的概率得到了概率之后我们就可以根据采样
得到的回报值计算出数学期望,从而得到目标函数,然后用来更新我们的参数 θ
在这里插入图片描述
得出目标函数之后,就需要根据目标函数求解目标函数最大值以及最大值对应的 policy 的参数 θ。类比深度学习中的梯度下降求最小值的方法,由于我们这里需要求的是目标函数的最大值,因此需要采取的方法是梯度上升。也就是说,思想起点是一样的,即需要求出目标函数的梯度。

优点:

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

缺点:

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

3.策略函数

  • [1] 在 Policy Based 强化学习方法下,我们对策略进行近似表示。此时策略 π π π 可以被描述为一个包含参数 θ θ θ 的函数,即:

π θ ( s , a ) = P ( a ∣ s , θ ) ≈ π ( a ∣ s ) π_θ(s,a)=P(a|s,θ)≈π(a|s) πθ(s,a)=P(as,θ)π(as)

  • [2] 我们现在来看策略函数 π θ ( s , a ) π_θ(s,a) πθ(s,a) 的设计: 最常用的策略函数就是 softmax 策略函数了,它主要应用于离散空间中,softmax 策略使用描述状态和行为的特征 ϕ ( s , a ) ϕ(s,a) ϕ(s,a) 与参数 θ θ θ
    的线性组合来权衡一个行为发生的几率,即:

π θ ( s , a ) = e ϕ ( s , a ) T θ ∑ b e ϕ ( s , b ) T θ π_θ(s,a)=\frac{e^{ϕ(s,a)^Tθ}}{ \sum_{b}e^{ϕ(s,b)^Tθ}} πθ(s,a)=beϕ(s,b)Tθeϕ(s,a)Tθ

  • [3] 对于 ∇ θ l o g π θ ( s , a ) ∇_θlogπ_θ(s,a) θlogπθ(s,a),我们一般称为分值函数,则通过求导很容易求出分值函数为:

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

4.策略梯度的优化目标

通常情况下目标策略有三种方式(V 是价值函数):

  • [1] 最简单的优化目标就是初始状态收获的期望,即优化目标为:
    J 1 ( θ ) = V π θ ( s 1 ) = E π θ [ v 1 ] = E ( r 1 + γ r 2 + γ 2 r 3 + . . . . . . . ∣ π θ ) J_1(θ)=V_{π_θ}(s_1)=E_{π_θ}[v_1]=E(r_1+γr_2+γ^2r_3+.......∣π_θ) J1(θ)=Vπθ(s1)=Eπθ[v1]=E(r1+γr2+γ2r3+.......πθ)
  • [2] 但是有的问题是没有明确的初始状态的,那么我们的优化目标可以定义平均价值,即:
    J a v V ( θ ) = ∑ s d π θ ( s ) V π θ ( s ) J_{avV}(θ)=\sum_{s}d_{π_θ}(s)V_{π_θ}(s) JavV(θ)=sdπθ(s)Vπθ(s)
    其中, d π θ ( s ) d_{π_θ}(s) dπθ(s) 是基于策略 π θ π_θ πθ 生成的马尔科夫链关于状态的静态分布。
  • [3] 还有就是定义为每一时间步的平均奖励,即:
    J a v R ( θ ) = = ∑ s d π θ ( s ) ∑ a π θ ( s , a ) R s a J_{avR}(θ)==\sum_sd_{π_θ}(s)\sum_aπ_θ(s,a)R^a_s JavR(θ)==sdπθ(s)aπθ(s,a)Rsa
    无论我们是采用 J 1 , J a v V J_1,J_{avV} J1,JavV 还是 J a v R J_{avR} JavR 来表示优化目标,最终对 θ θ θ 求导的梯度都可以表示为:
    ∇ θ 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)]

详细推导可以参考原论文:https://homes.cs.washington.edu/~todorov/courses/amath579/reading/PolicyGradient.pdf

5.代码实现

这里使用了 OpenAI Gym 中的 CartPole-v0 游戏来作为我们算法应用。CartPole-v0 游戏的介绍参见这里。它比较简单,基本要求就是控制下面的 cart 移动使连接在上面的 pole 保持垂直不倒。这个任务只有两个离散动作,要么向左用力,要么向右用力。而 state 状态就是这个 cart 的位置和速度, pole 的角度和角速度,4 维的特征。坚持到 200 分的奖励则为过关。

import gym
import tensorflow as tf
import numpy as np
import random
from collections import deque

# Hyper Parameters
GAMMA = 0.95 # discount factor
LEARNING_RATE=0.01

class Policy_Gradient():
    def __init__(self, env):
        # init some parameters
        self.time_step = 0
        self.state_dim = env.observation_space.shape[0]
        self.action_dim = env.action_space.n
        self.ep_obs, self.ep_as, self.ep_rs = [], [], []
        self.create_softmax_network()

        # Init session
        self.session = tf.InteractiveSession()
        self.session.run(tf.global_variables_initializer())

    def create_softmax_network(self):
        # network weights
        W1 = self.weight_variable([self.state_dim, 20])
        b1 = self.bias_variable([20])
        W2 = self.weight_variable([20, self.action_dim])
        b2 = self.bias_variable([self.action_dim])
        # input layer
        self.state_input = tf.placeholder("float", [None, self.state_dim])
        self.tf_acts = tf.placeholder(tf.int32, [None, ], name="actions_num")
        self.tf_vt = tf.placeholder(tf.float32, [None, ], name="actions_value")
        # hidden layers
        h_layer = tf.nn.relu(tf.matmul(self.state_input, W1) + b1)
        # softmax layer
        self.softmax_input = tf.matmul(h_layer, W2) + b2
        #softmax output
        self.all_act_prob = tf.nn.softmax(self.softmax_input, name='act_prob')
        self.neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.softmax_input,
                                                                      labels=self.tf_acts)
        self.loss = tf.reduce_mean(self.neg_log_prob * self.tf_vt)  # reward guided loss

        self.train_op = tf.train.AdamOptimizer(LEARNING_RATE).minimize(self.loss)

    def weight_variable(self, shape):
        initial = tf.truncated_normal(shape)
        return tf.Variable(initial)

    def bias_variable(self, shape):
        initial = tf.constant(0.01, shape=shape)
        return tf.Variable(initial)

    def choose_action(self, observation):
        prob_weights = self.session.run(self.all_act_prob, feed_dict={self.state_input: observation[np.newaxis, :]})
        action = np.random.choice(range(prob_weights.shape[1]), p=prob_weights.ravel())  # select action w.r.t the actions prob
        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):

        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 * GAMMA + self.ep_rs[t]
            discounted_ep_rs[t] = running_add

        discounted_ep_rs -= np.mean(discounted_ep_rs)
        discounted_ep_rs /= np.std(discounted_ep_rs)

        # train on episode
        self.session.run(self.train_op, feed_dict={
             self.state_input: np.vstack(self.ep_obs),
             self.tf_acts: np.array(self.ep_as),
             self.tf_vt: discounted_ep_rs,
        })

        self.ep_obs, self.ep_as, self.ep_rs = [], [], []    # empty episode data
# Hyper Parameters
ENV_NAME = 'CartPole-v0'
EPISODE = 3000 # Episode limitation
STEP = 3000 # Step limitation in an episode
TEST = 10 # The number of experiment test every 100 episode

def main():
  # initialize OpenAI Gym env and dqn agent
  env = gym.make(ENV_NAME)
  agent = Policy_Gradient(env)

  for episode in range(EPISODE):
    # initialize task
    state = env.reset()
    # Train
    for step in range(STEP):
      action = agent.choose_action(state) # e-greedy action for train
      next_state,reward,done,_ = env.step(action)
      agent.store_transition(state, action, reward)
      state = next_state
      if done:
        #print("stick for ",step, " steps")
        agent.learn()
        break

    # Test every 100 episodes
    if episode % 100 == 0:
      total_reward = 0
      for i in range(TEST):
        state = env.reset()
        for j in range(STEP):
          env.render()
          action = agent.choose_action(state) # direct action for test
          state,reward,done,_ = env.step(action)
          total_reward += reward
          if done:
            break
      ave_reward = total_reward/TEST
      print ('episode: ',episode,'Evaluation Average Reward:',ave_reward)

if __name__ == '__main__':
  main()

运行结果:
在这里插入图片描述

6.参考

1.https://blog.csdn.net/qq_30615903/article/details/80747380

2.https://zhuanlan.zhihu.com/p/42055115

3.https://mofanpy.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值