所谓策略网络
即建立一个神经网络模型,它可以通过观察环境状态,直接预测出目前最应该执行的策略(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()