Tensorflow实现策略网络(深度强化学习)之cartPole

所谓策略网络

  即建立一个神经网络模型,它可以通过观察环境状态,直接预测出目前最应该执行的策略(Policy),执行这个策略可以获得最大的期望收益(包括现在和未来的Reward)。

  到这里了, 相信你也了解什么是cartPloe,也了解他的原理是什么, 我这里就不再细说了。

实现cartPole需要使用的模块-gym

在这里插入图片描述
 gym现在只能在ubuntu上使用,安装如下:

sudo pip install gym

费话不多说,直接上代码:

import numpy as np
import tensorflow as tf
import gym

# 创建环境
env = gym.make('CartPole-v0')

# 初始化环境
env.reset()

# 隐藏层节点数
H = 50
# 批次数量
batch_size = 25
learning_rate = 0.1
D = 4
gamma = 0.99

# 创建卷积层并输出
#这里输入为observation ,最后输出为action向左或向右的概率
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)


# 计算潜在分数(这里包含的不只是一步action的得分,而是现在及以后所有
# 步骤的action的得分,每次预测会乘以gamma系数(0.99)
def discount_rewards(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
    # 返回一个矩阵,每一行是每个回合的得分数据,
    #每行形如[s1, s2+s1*gamma, s3+s2*gamma+s1*gamma*gamma]    
    return discounted_r

# 虚拟的label值,用以对已完成的action的纠正
input_y = tf.placeholder(tf.float32, [None, 1], name='input_y')

# 每个action的潜在分数
advantages = tf.placeholder(tf.float32, name='reward_signal')

#定义损失函数
	# loglik当前 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()
# 按tvars中的每个变量对loss求导,and
# return A list of sum(dy/dx) for each x in xs.
newGrads = tf.gradients(loss, tvars)

# 使用adam优化器
adam = tf.train.AdamOptimizer(learning_rate=learning_rate)
w1Grad = tf.placeholder(tf.float32, name='batch_grad1')
w2Grad = tf.placeholder(tf.float32, name='batch_grad2')
batchGrad = [w1Grad, w2Grad]
# 使用tvars中的参数计算梯度,并将计算结果更新至tvars参数中
# [apply_gradents具体用法见](https://www.cnblogs.com/marsggbo/p/10056057.html)
updateGrads = adam.apply_gradients(zip(batchGrad, tvars))

# xs observation环境实例列表
# ys label列表
# drs 每一个action的reward
xs, ys, drs = [], [], []
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()

    # 收集训练需要的参数,值全部置0,装在buffer中
    gradBuffer = sess.run(tvars)
    for ix, grad in enumerate(gradBuffer):
        gradBuffer[ix] = grad * 0

    # 杆倒一次,episode加1,共完成10000次
    while episode_number <= total_episodes:
    	# 当得分大于100,说明训练有一定的成就,
    	# 渲染出图像,render()
        if reward_sum > 100 or rendering ==True:
            env.render()
            rendering = True

		# observation的实质是一个一行四列的数组
        x = np.reshape(observation, [1, D])
		
		# 生成环境后(observat),将环境装入神经网络输入端,运行得到action取值为1概率
        tfprob = sess.run(probability, feed_dict={observations:x})
        
        # 此处需要注意,tfprob是取值为1的概率,不能因为是大于0.5,就取值1,小于0.5就取值0
        # 例tfprob=0.8,说明他还有0.2的概率是取值为0的,只有如下方式可以完美的表达这个问题        
        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)
	
		# 如下杆倒下或超出2.4单位的距离
        if done:
            episode_number += 1
            # 把这回合的环境等数据压入更大的矩阵列表            
            epx = np.vstack(xs)
            epy = np.vstack(ys)
            epr = np.vstack(drs)
            xs, ys, drs = [], [], []

			# 每个回合的潜在分数(已进行归一化,即均值为0, 方差为1)
            discounted_epr = discount_rewards(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})
            # 将每回合的每个函数的梯度添加到gradBuffer
            for ix,grad in enumerate(tGrad):
                gradBuffer[ix] += grad
                
                # batch_size的整数倍时
                if episode_number % batch_size == 0:
                	# 升级参数,参数缓冲器置零
                    sess.run(updateGrads, feed_dict={w1Grad:gradBuffer[0],
                                                     w2Grad:gradBuffer[1]})
                    for ix,grad in enumerate(gradBuffer):
                        gradBuffer[ix] = grad * 0

                    print('average reward for episode %d: %f'%\
                          (episode_number, reward_sum/batch_size))
					
					# 当平均得分大于200时,结束程序。
                    if reward_sum/batch_size > 200:
                        print('Task solved in', episode_number, 'episodes')
                        break

                    reward_sum = 0
				# 环境重置
                observation = env.reset()

猜你喜欢

转载自blog.csdn.net/qq_30934313/article/details/86148956