《tensorflow实战》6——强化学习之策略网络

策略网络和估值网络是强化学习两种重要的方法。强化学习和有监督学习、无监督学习不同,它的学习目标是变化的、不明确的,甚至可能不存在绝对正确的标签。AlphaGo就是结合了策略网络,估值网络和蒙特卡洛搜索树实现对战程序的。
强化学习中有环境状态(Environment State)、动作(Action)和奖励(Reward)。模型的载体是Agent。
策略网络的实质是建立一个神经网络模型,通过观察环境状态预测出目前应该执行的策略,执行这个策略,并获取可以获得最大的奖励是多少。和普通的监督学习不同,策略网络不是通过feature预测label,而是根据对观察的环境状态进入模型,得到action,执行这个action后得到reward,通过reward的加权衰减并叠加后计算梯度,通过梯度优化网络参数。
强化学习与其他两类学习还有一个很不同的点——它需要一个环境生成工具,生成问题对应的环境和模型载体Agent。Gym是OpenAI退出的开源的强化学习环境。通过pip install gym即可安装。
选择gym下的Cartpole问题来完成强化学习初体验。
CartPole的环境中有一辆小车,在一个一维无阻力轨道上行驶,在车上连接着不太结实的杆,这个杆会左右摇晃,我们的任务是让车不偏离中心超过2.4个单位距离并且杆的倾角小于15度,否则,表示任务失败。环境和agent如下:
这里写图片描述
环境信息Observation是一个4值的数组,包含小车的位置、速度、杆的角度等。
在运行过程中,小车每坚持一步,reward加1,每次失败后,reward清0. 当reward大于200后任务完成,退出学习。

以带有一个隐含层的MLP为神经网络模型,完成本次任务。整个计算图如下
这里写图片描述

其中,虚线框内是圣经网络计算子图,绿色部分是小车每动作一步都会计算的,橙色是一次迭代(从开始运行到任务失败算一次迭代)执行一次,红色是一个batch执行一次。
Input_y = 1-action;
epr = reward * discount
advantage = epr – mean(epr) / std(epr), mean为均值,std为标准差。

程序如下:

#coding:utf-8

import numpy as np
import tensorflow as tf
import gym

env = gym.make('CartPole-v0')

H = 50
batch_size = 25
learning_rate = 1e-1
D = 4
gamma = 0.99

"""
以observation为输入,建立MLP。
一个隐藏层用relu激活,一个全连接层接输出,因为是action,所以,输出只有一个。
输出用sigmoid激活
"""
observations = tf.placeholder(tf.float32, [None, D], name = "input_x")
W1 = tf.get_variable('W1', shape = [D, H], initializer = tf.contrib.layers.xavier_initializer())
layer1 = tf.nn.relu(tf.matmul(observations, W1))
W2 = tf.get_variable('W2', shape = [H, 1], initializer = tf.contrib.layers.xavier_initializer())
score = tf.matmul(layer1, W2)
probability = tf.nn.sigmoid(score)

"""
reward的逐步衰减。
"""
def discount_rewasrd(r):
    discounted_r = np.zeros_like(r)
    running_add = 0
    for t in reversed(range(r.size)):
        running_add = running_add * gamma + r[t]
        discounted_r[t] = running_add
    return discounted_r

"""

"""
input_y = tf.placeholder(tf.float32, [None, 1], name="input_y")
advantages = tf.placeholder(tf.float32, name="reward_singal")
#实际上是对action做对数似然
loglik = tf.log(input_y * (input_y - probability) + (1 - input_y) * (input_y + probability))
loss = -tf.reduce_mean(loglik * advantages)

tvars = tf.trainable_variables()
newGrads = tf.gradients(loss, tvars)

"""
梯度更新模块
每个Batch计算完成后才做一次更新
apply_gradients的更新原理?
"""
adam = tf.train.AdamOptimizer(learning_rate = learning_rate)
W1Grad = tf.placeholder(tf.float32, name = "batch_grade1")
W2Grad = tf.placeholder(tf.float32, name = "batch_grade2")
batchGrad = [W1Grad, W2Grad]
updateGrads = adam.apply_gradients(zip(batchGrad, tvars))

"""

"""
xs, ys, drs = [], [], [] #xs是环境信息的观察列表, ys是label列表, drs是每一个action的reward
reward_sum = 0
episode_number = 1
total_episodes = 10000

with tf.Session() as sess:
    rendering = False
    init = tf.global_variables_initializer()
    sess.run(init)
    observation = env.reset()

    gradBuffer = sess.run(tvars)
    for ix,grad in enumerate(gradBuffer):
        gradBuffer[ix] = grad * 0

    #因为循环层次不同,整个计算图被分成几个子图执行。
    while episode_number <= total_episodes:

        if reward_sum/batch_size > 100 or rendering == True:
            env.render()
            rendering = True

        x = np.reshape(observation, [1,D])

        tfprob = sess.run(probability, feed_dict={observations: x})

        action = 1 if np.random.uniform() < tfprob else 0

        xs.append(x)
        y = 1 - action
        ys.append(y)

        observation, reward, done, info = env.step(action)
        reward_sum += reward

        drs.append(reward)

        if done:
            episode_number += 1
            epx = np.vstack(xs)
            epy = np.vstack(ys)
            epr = np.vstack(drs)
            xs, ys, drs = [], [], []

            discounted_epr = discount_rewasrd(epr)
            discounted_epr -= np.mean(discounted_epr)
            discounted_epr /= np.std(discounted_epr)

            tGrad = sess.run(newGrads, feed_dict={observations: epx, input_y: epy, advantages: discounted_epr})
            for ix, grad in enumerate(tGrad):
                gradBuffer[ix] += grad

            if episode_number % batch_size == 0:
                #运行图中的优化子图,将梯度缓存中一个batch的梯度输入到图中。
                sess.run(updateGrads, feed_dict={W1Grad: gradBuffer[0], W2Grad: gradBuffer[1]})

                for ix, grad in enumerate(gradBuffer):
                    gradBuffer[ix] = grad * 0   #一个batch结束后,将所有的梯度缓存清空。

                print "Average reward for episode %d : %f." % (episode_number, reward_sum / batch_size)

                if reward_sum / batch_size > 200:
                    print "Task solved in", episode_number, 'episodes!'
                    break

                reward_sum = 0

            observation = env.res

执行结果很尴尬的是,reward最大值刚好只能达到200.000,一直都不退出。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值