算法实战篇(二),Tensorflow实现Actor-Critic框架下的经典PPO算法

本篇是我们算法实战的第二篇,针对的是我们在“基础算法篇(六),基于AC框架的PPO算法”中提出的相关算法,具体算法中部分参考了莫烦老师的相关代码,在这里向莫烦老师表示感谢。

一、基础游戏背景介绍

在这次代码实现中,为了体现与前面离散型输出的不同,我们特意选择了Gym中的转动杆游戏,如下图:
在这里插入图片描述

游戏的目标就是给转动杆一个力,最终让它能够稳定的立起来。这个游戏与DQN中使用的“活动杆小车”游戏不同的是,这个游戏的输入action_space是一个Box(1,)类型,即一个float的连续值。同时,这个游戏的输出observation_space是一个Box(3,)类型,是三个float的数组。
其他关于编程环境的搭建,请大家参考“番外篇,强化学习基础环境搭建
下面我们正式进入我们的程序。

二、主函数

同样的,让我们先看main()函数:

def main():
    # first, create the envrioment of 'Pendulum-v0'
    # the game Pendulum-v0's observation_space is Box(3,), it means the observation has three var and each one is float
    # the action_space is Box(1,), it means the action has one var and is float
    # the output of the game is continuous, not discrete
    env = gym.make(ENV_NAME).unwrapped
    # second, create the PPO agent. it is based the AC arch, so it has two type of network
    # the critic which give the value of the state
    # the actor which give the action
    agent = PPO(env.observation_space, env.action_space)
    for episode in range(EPISODES):
        # every episode reset the memory
        agent.resetMemory()
        # get the initial state
        state = env.reset()
        # this is the total reward
        ep_r = 0
        for step in range(STEPS):
            # show the game window
            env.render()
            # output the action
            action = agent.Choose_Action(state)
            # process the action and get the info
            next_state, reward, done, info = env.step(action)
            # store the date to update the model
            agent.Store_Data(state, action, reward, next_state, done)
            # train the agent every BATCH_SIZE
            if (step + 1) % BATCH_SIZE == 0 or step == STEPS - 1:
                agent.Train(next_state)
            # set the new state
            state = next_state
            # record the reward
            ep_r += reward
            if step == STEPS - 1:
                agent.UpdateActorParameters()
        # caculate the total reward in every episode
        if episode == 0:
            all_ep_r.append(ep_r)
        else:
            all_ep_r.append(all_ep_r[-1] * 0.9 + ep_r * 0.1)
        print(
            'Ep: %i' % episode,
            "|Ep_r: %i" % ep_r,
            ("|Lam: %.4f" % METHOD['lam']) if METHOD['name'] == 'kl_pen' else '',
        )

上述主函数主要分为以下几步(针对每一行代码):

  • 1.生成环境对象env
  • 2.生成PPO对象agent
  • 3.开始每一幕(Episode)循环
  • 4.首先重置agent存储的数据,将上一幕存储的数据清零
  • 5.得到环境的初始状态
  • 6.设置记录这一幕reward的变量
  • 7.开始这一幕中每一步(Step)的循环
  • 8.首先显示游戏窗口
  • 9.基于状态state,利用agent生成行动action
  • 10.将action输入环境,得到下一个状态next_state和实时收益reward等数据
  • 11.存储相关数据
  • 12.如果满足训练条件,则进行agent的训练,用梯度下降更新相关Critic和Actor网络参数
  • 13.将最新得到的下一个状态,改为现有状态
  • 14.判断是否是最后一个step,如果是,则执行两个actor参数的拷贝更新,否则继续执行步循环,直到走完设计的步数
  • 15.后续的代码是记录每个Episode的总得分,并将其存储和打印出来

我们可以看出,从主函数角度来讲,与DQN的函数基本一致,区别在于这里是每个Episode直接打印结果。
下面,我们来详细介绍基于Actor-Critic框架的PPO类。

三、Agent类

在“基础算法篇(六),基于AC框架的PPO算法”中我们介绍了相关算法,这里我们是严格按照算法进行的实现,其中网络构建了两类三个:

  • 价值网络(Critic),一个网络,输入是环境的状态,输出是这个状态的价值;
  • 策略网络(Actor),两个网络,一个用来与环境交互,另一个进行参数更新,这种方式主要用来解决经典PG算法中的“采集数据不能够重复使用的问题”。

下面我们详细介绍相关代码实现部分。

(一)PPO类的初始化函数

PPO类的初始化主要是导入观测空间和行动空间的大小,并根据这两个量生成相应的策略和价值网络,具体代码如下:

def __init__(self, observation_space, action_space):
    # the state is the input vector of network, in the game of 'Pendulum-v0', it has three dimensions
    self.state_dim = observation_space.shape[0]
    # the action is the output vector and  in the game of 'Pendulum-v0', it has one dimensions
    self.action_dim = action_space.shape[0]
    # it is the input, which come from the env
    self.state_input = tf.placeholder(tf.float32, [None, self.state_dim], 'state')
    # create the network to represent the state value
    self.Create_Critic()
    # create two networks to output the action, and update the networks
    self.Create_Actor_with_two_network()
    # Init session
    self.sess = tf.Session()
    self.sess.run(tf.global_variables_initializer())

具体每一步的含义,我在代码中做了注释。我们在这里可以看到,创建价值网络和创建策略网络使用了两个独立的函数,下面我们具体来讲各个函数情况。

(二)建立Critic深度神经网络(价值网络)

我们在“基础算法篇(六),基于AC框架的PPO算法”第一节中介绍了,Actor-Critic框架是通过在策略梯度中引入价值函数,实现两个网络的结合。因此,价值网络主要是对状态价值的评估,同时它也需要在不断的训练中通过梯度下降来更新参数,下面我们详细介绍两部分的代码。

1. 价值网络的建立

我们在这里建立的价值网络,输入是游戏的状态,输出是状态的价值,中间包含两个隐藏层,具体代码如下:

# first, create the parameters of networks
W1 = self.weight_variable([self.state_dim, 100])
b1 = self.bias_variable([100])
W2 = self.weight_variable([100, 50])
b2 = self.bias_variable([50])
W3 = self.weight_variable([50, self.action_dim])
b3 = self.bias_variable([self.action_dim])
# second, create the network with two hidden layers
# hidden layer one
h_layer_one = tf.nn.relu(tf.matmul(self.state_input, W1) + b1)
# hidden layer two
h_layer_two = tf.nn.relu(tf.matmul(h_layer_one, W2) + b2)
# the output of current_net
self.v = tf.matmul(h_layer_two, W3) + b3

其中self.state_dim为输入状态,self.v即为价值网络的输出。

2. 更新方法的定义

对于价值网络的更新,我们在这里使用优势函数作为其损失,具体代码如下:

# the input of discounted reward
self.tfdc_r = tf.placeholder(tf.float32, [None, 1], 'discounted_r')
# the advantage value, use to update the critic network
self.advantage = self.tfdc_r - self.v
# the loss of the network
self.closs = tf.reduce_mean(tf.square(self.advantage))
# the training method of critic
self.ctrain_op = tf.train.AdamOptimizer(Critic_LR).minimize(self.closs)

其中self.tfdc_r为我们后面需要计算的折扣收益,self.ctrain_op为Critic网络的更新操作,在后续进行更新时,输入相关参数,调用这一操作即可。

(三)建立Actor深度神经网络(策略网络)

我们在“基础算法篇(六),基于AC框架的PPO算法”中介绍了,为了解决原有策略梯度(PG)算法中数据不能够重复利用的问题,我们使用了Importance Sampling的思路,即利用一个网络与环境进行交互,而另外一个网络负责进行更新,在这里我们就实现了pi和oldpi两个网络,并定义了相关的更新策略。

1. 策略网络的建立

我们建立的pi和oldpi两个网络中,其中oldpi负责与环境进行交互,pi负责进行参数更新,具体代码如下:

# create the actor that update the parameters
pi, pi_params = self.build_actor_net('pi', trainable=True)
# create the actor that interact with env
oldpi, oldpi_params = self.build_actor_net('oldpi', trainable=False)
# sample the action from the distribution
with tf.variable_scope('sample_action'):
     self.sample_from_oldpi = tf.squeeze(oldpi.sample(1), axis=0)

这里构建网络的具体方法,我们借鉴了莫烦老师的代码,也是构建了包含两个隐藏层的网络,具体代码如下:

# the function that create the actor network
# it has two hidden layers
# the method of creating actor is different  from the critic
# the output of network is a distribution
def build_actor_net(self, name, trainable):
    with tf.variable_scope(name):
         l1 = tf.layers.dense(self.state_input, 100, tf.nn.relu, trainable=trainable)
         l2 = tf.layers.dense(l1, 50, tf.nn.relu, trainable=trainable)
         mu = 2 * tf.layers.dense(l2, self.action_dim, tf.nn.tanh, trainable=trainable)
         sigma = tf.layers.dense(l2, self.action_dim, tf.nn.softplus, trainable=trainable)
         norm_dist = tf.distributions.Normal(loc=mu, scale=sigma)
    params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=name)
    return norm_dist, params

由这里可以看出,这个网络与DQN中离散输出不同的是,这个网络输出的其实是一个分布norm_dist(其中mu是这个分布的均值,sigma为这个分布的方差),因此最终的网络输出则是从这个分布中随机sample一个值即可。

2. 更新方法的定义

根据上面的代码我们可以看出,pi是可以更新的,具体的更新逻辑我们这里也借鉴了莫烦老师的思路,做了PPO和PPO2两种实现,代码如下:

# the actions in memory
self.tfa = tf.placeholder(tf.float32, [None, self.action_dim], 'action')
# the advantage value
self.tfadv = tf.placeholder(tf.float32, [None, 1], 'advantage')
with tf.variable_scope('loss'):
     with tf.variable_scope('surrogate'):
          # the ration between the pi and oldpi, this is importance sampling part
          ratio = pi.prob(self.tfa) / (oldpi.prob(self.tfa) + 1e-5)
          # the surrogate
          surr = ratio * self.tfadv
     # this is the method of PPO
     if METHOD['name'] == 'kl_pen':
         self.tflam = tf.placeholder(tf.float32, None, 'lambda')
         kl = tf.distributions.kl_divergence(oldpi, pi)
         self.kl_mean = tf.reduce_mean(kl)
         self.aloss = -(tf.reduce_mean(surr - self.tflam * kl))
     else:  # this is the method of PPO2
         self.aloss = -tf.reduce_mean(tf.minimum(
              surr,
              tf.clip_by_value(ratio, 1. - METHOD['epsilon'], 1. + METHOD['epsilon']) * self.tfadv)
              )
# define the method of training actor
with tf.variable_scope('atrain'):
     self.atrain_op = tf.train.AdamOptimizer(Actor_LR).minimize(self.aloss)

上面的代码中,其中self.tfa为输入的行动序列,self.tfadv为输入的优势函数,在具体的损失计算中,首先按照Importance Sampling的思路计算出相关目标函数,然后再判断是使用PPO算法还是使用PPO2算法,最终形成用来更新的损失函数self.aloss
最后,定义了Actor的更新操作self.atrain_op,这个与Critic一样,在更新时输入参数,然后调用即可。

(四)利用策略网络(Actor)生成行为

前面讲了,利用策略网络网络生成行为,就是利用self.sample_from_oldpi操作,从oldpi网络的输出分布中sample一个值出来即可,具体代码如下:

# output the action with state, the output is from oldpi
def Choose_Action(self, s):
    s = s[np.newaxis, :]
    a = self.sess.run(self.sample_from_oldpi, {self.state_input: s})[0]
    return np.clip(a, -2, 2)

这里将输出值限定在 ( − 2 , 2 ) (-2,2) (2,2)的范围内。

(五)存储与更新数据

我们在这里使用的存储策略在每个Episode开始时初始化存储列表,然后在Episode的每个Step都存储数据,具体代码如下:

 # reset the memory in every episode
def resetMemory(self):
    self.buffer_s, self.buffer_a, self.buffer_r = [], [], []

# store the data of every steps
def Store_Data(self, state, action, reward, next_state, done):
    self.buffer_s.append(state)
    self.buffer_a.append(action)
    self.buffer_r.append(reward)

上面两个函数,是在主函数main()中相关位置进行调用的。

(六)利用数据更新策略网络(Actor)和价值网络(Critic)

最后,我们讲一下两个网络的更新操作,我们的策略是每隔BATCH_SIZE步进行一次更新,具体的更新代码如下:

# the train function that update the network
def Train(self, next_state):
    # caculate the discount reward
    v_s_ = self.get_v(next_state)
    discounted_r = []
    for r in self.buffer_r[::-1]:
        v_s_ = r + GAMMA * v_s_
        discounted_r.append(v_s_)
    discounted_r.reverse()
    bs, ba, br = np.vstack(self.buffer_s), np.vstack(self.buffer_a), np.array(discounted_r)[:, np.newaxis]
    # this the main function of update
    self.update(bs, ba, br)

上面是更新的主函数,在这里我们首先利用价值网络获得下一状态的价值,然后计算每一步的折扣收益,然后将相关数据输入update函数,进行更新,update函数代码如下:

# the function that update the actor and critic
def update(self, s, a, r):
    adv = self.sess.run(self.advantage, {self.state_input: s, self.tfdc_r: r})
    # update actor
    if METHOD['name'] == 'kl_pen':
       for _ in range(ACTOR_UPDATE_TIMES):
           _, kl = self.sess.run(
                [self.atrain_op, self.kl_mean],
                {self.state_input: s, self.tfa: a, self.tfadv: adv, self.tflam: METHOD['lam']})
           if kl > 4 * METHOD['kl_target']:  # this in in google's paper
                break
       if kl < METHOD['kl_target'] / 1.5:  # adaptive lambda, this is in OpenAI's paper
            METHOD['lam'] /= 2
       elif kl > METHOD['kl_target'] * 1.5:
            METHOD['lam'] *= 2
       METHOD['lam'] = np.clip(METHOD['lam'], 1e-4, 10)  # sometimes explode, this clipping is my solution
    else:  # clipping method, find this is better (OpenAI's paper)
       [self.sess.run(self.atrain_op, {self.state_input: s, self.tfa: a, self.tfadv: adv}) for _ in range(ACTOR_UPDATE_TIMES)]
    # update critic
    [self.sess.run(self.ctrain_op, {self.state_input: s, self.tfdc_r: r}) for _ in range(CRITIC_UPDATE_TIMES)]

上面的代码中,首先计算优势函数,然后判断是PPO还是PPO2,如果是PPO,还要对KL散度的参数进行计算,之后再调用self.atrain_op进行策略网络pi的更新,最后再调用self.ctrain_op进行价值网络的更新。
最后还要说明一点的是,我们这里设计的是每个Episode的最后一步,将pi网络的参数更新到oldpi网络上,具体代码如下:

# ths dunction the copy the pi's parameters to oldpi
def UpdateActorParameters(self):
    self.sess.run(self.update_oldpi_from_pi)

总结

本篇介绍了Actor-Critic框架下的经典PPO算法相关代码实现部分,如果大家感兴趣,完整的代码可以从我的Github中下载。

  • 8
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: ppo(proximal policy optimization)是一种用于强化学习的策略优化算法,其基本思想是在策略更新函数的优化过程中,使用了一些新的技巧来提高学习效率和稳定性。 actor-critic是一种深度强化学习算法,其中actorcritic分别负责学习决策策略和估计价值函数。actor-critic算法通过训练actorcritic模型来实现策略优化。 pp actor-critic算法结合了ppoactor-critic的两种算法,是一种新的策略优化算法。它通过使用ppo算法对策略进行优化,并使用actor-critic算法来学习和估计策略价值。在这种模型中,actor负责生成动作,critic负责评估策略价值,pp算法保证了策略更新的稳定性和效率。 pp actor-critic算法具有许多优点,例如可以有效地解决强化学习中出现的稀疏奖励和高维空间问题,能够在没有先验知识的情况下自动学习和适应。不过,它的训练过程比较复杂,需要选择合适的超参数,并且需要较长的训练时间来获得最佳效果。 尽管存在一些挑战,但pp actor-critic算法仍被广泛应用于各种强化学习任务,例如游戏、机器人控制等。它的发展也为解决实际应用中的问题提供了新的思路和方法。 ### 回答2: PPO Actor-Critic是深度强化学习领域中的一个算法。它是基于Actor-Critic方法的一种改进。Actor-Critic算法将决策策略和价值函数相结合,以达到更准确的评估和更新。而PPO算法则是为了解决常规Policy Gradient算法的训练不稳定性而提出的一种策略优化算法PPO Actor-Critic算法的核心思想是通过对策略的更新,不断改善训练的效果。该算法是由Proximal Policy Optimization(PPO算法Actor-Critic算法结合而成。在训练过程中,PPO Actor-Critic会利用现有的经验,通过Actor-Critic算法更新策略和价值函数。其更新策略的过程中,会采用PPO算法进行优化,从而能够根据实际情况平衡策略更新和训练效果。 PPO Actor-Critic算法的优点是能够同时利用线性和非线性的函数逼近器来最小化优势函数的误差。从而避免了传统策略梯度算法的过拟合问题,大大增强了该算法的鲁棒性。此外,PPO Actor-Critic也能够避免过多的数据采样和重复推断,大大提升了算法的效率。 综上所述,PPO Actor-Critic是一种结合了PPO算法Actor-Critic算法强化学习算法,可用于训练智能代理以达到更精确的评估和更新。 ### 回答3: PPO Actor-Critic 是指一种深度强化学习算法。在这种算法中,通过两个模型一起工作来提高决策过程的效率。 其中,Actor 模型用于执行动作。它使用一系列状态来计算每个可能的策略,并选择相应的行动方案。这个过程被看作是一个正则化的过程。这意味着在执行过程中,Actor 模型不断从环境中获取反馈信息,并根据这些反馈信息进行优化。 相反,Critic 模型则用于评估 Actor 模型的表现。它通过测量实际的奖励和预测的奖励之间的差距来判断 Actor 模型是否做决策。如果结果不好,则系统会通过重新计算 Actor 模型的策略来提出新的决策方案。 PPO Actor-Critic 算法通过优化 Actor 模型的过程来提高决策的效率。这通常会导致更好的策略和更好的结果。此外,由于 Critic 模型的存在,系统可以更好地理解和评估策略的表现。这使得 PPO Actor-Critic 算法成为适用于机器人控制、游戏策略和金融交易等领域的一种流行算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值