用tensorflow 创建一个基于策略网络的Agent来解决CartPole问题
2018-01-17 10:57
459 查看
所谓的策略网络,即建立一个神经网络模型,它可以通过观察环境状态,直接预测出目前最应该执行的策略(policy),执行这个策略可以获得最大的期望收益(包括现在的和未来的reward)。和之前的任务不同,在强化学习中可能没有绝对正确的学习目标,样本的feature和label也不在一一对应。我们的学习目标是期望价值,即当前获得的reward和未来潜在的可获取的reward。所以在策略网络中不只是使用当前的reward作为label,而是使用Discounted
Future Reward,即把所有未来奖励一次乘以衰减系数γ。这里的衰减系数是一个略小于但接近1的数,防止没有损耗地积累导致Reward目标发散,同时也代表了对未来奖励的不确定性的估计。
我们先安装OpenAI Gym。-----------------------> pip install gym
接着我们载入Numpy,Tensorflow和gym,这里用gym.make('CartPole-v0')创建CartPole问题的环境env。
我们的策略网络使用简单的带有一个隐含层的MLP。先设置网络的各个超参数,这里的隐含节点数H设为50,batch_size设为25,学习速率learning_rate为0.1,环境信息observation的维度Dwei 4,gamma即Reward的discount比例设为0.99.在估算Action的期望价值(即估算样本的学习目标)时会考虑Delayed Reward,会将某个Action之后获得的所有Reward 做Discount并累加起来,这样可让模型学习到未来可能出现的潜在Reward。注意,一般discount比例要小于1,防止Reward被无损耗的不断累加导致发散,这样也可以区分当前reward和未来reward的价值(当前Action直接带来的reward不需要discount,而未来的reward因存在不确定性所以需要discount)
我们定义人工设置的虚拟label(取值为0或1)的placeholder---input_y,以及每个action的潜在价值的placeholder-advantages。这里loglik定义略显复杂,我们来看一下Loglik到底代表什么。action取值为1的概率为probability(即策略网络输出的概率),action取值为0的概率为1-probability,label的取值与action想法,即label=1-action。当action为1时,label为0,此时loglik=tf.log(probability),action取值为1的概率的对数;当action为0是,label为1,此时Loglik=tf.log(1-probability),即action取值为0的概率的对数。所以loglik其实就是当前action对应的概率的对数,我们将loglik与潜在机制advantages相乘,并取负数作为损失,即优化目标。我们使用优化器优化时,会让能获得较多advantages的action的概率变大,并让能获得较少advantages的action的概率变小,这样能让损失变小。通过不断的训练,我们便能持续加大能获得较多advantages的action的概率,即学习到一个能获得更多潜在价值的策略。最后,使用tf.trainable_variables()获取策略网络中全部可训练的参数tvars,并使用tf.gradients求解模型参数关于loss的梯度。
我们创建默认的Session,初始化全部参数,并在一开始将render的标志关闭。因为render会带来比较大的延迟,所以一开始不太成熟的模型还没必要去观察。县初始化CartPole的环境并获得初始状态。然后使用sess.run执行tvars获取所有模型参数,用来创建储存参数梯度的缓冲器gradBuffer,并把gradBuffer全部出池化为0.接下来的每次试验中,我们将手机参数的梯度存储到gradBuffer中,直到完成了一个batch_size的试验,再将汇总的梯度更新到模型参数。
然后将输入的环境信息observation添加到列表xs中。这里我们制造虚拟的Lable-y,它取值与action相反,即y=1-action,并将其添加到列表ys中,然后使用env.step执行一次action,获取observation,reward,done和info,并将reward累加到reward_sum,同时将reward添加到列表drs中。
将done为True,即一次试验结束时,将episode_number加1.同时使用np.vstack将几个列表xs,ys,drs中的元素纵向堆叠起来,得到epx,epy和epr,并将xs,ys,drs清空以备下次试验使用。这里注意,epx,epy,drs即为一次试验中获得的所有observation、label、reward的列表。我们使用前面定义好的discount_rewards函数计算每一步action的潜在价值,并进行标准化(减去均值再除以标准差),得到一个零均值标准差为1的分布。这么做是因为discount_reward会参与到模型损失的计算,而分布稳定的discount_reward有利于训练的稳定。
我们将epx,epy和discounted_epr输入神经网络,并使用操作newGrads求解梯度。再将获得的梯度累加到gradBuffer中去。
Future Reward,即把所有未来奖励一次乘以衰减系数γ。这里的衰减系数是一个略小于但接近1的数,防止没有损耗地积累导致Reward目标发散,同时也代表了对未来奖励的不确定性的估计。
我们先安装OpenAI Gym。-----------------------> pip install gym
接着我们载入Numpy,Tensorflow和gym,这里用gym.make('CartPole-v0')创建CartPole问题的环境env。
import numpy as np import tensorflow as tf import gym env=gym.make('CartPole-v0')先测试在CartPole环境中使用随机ACTION的表现,作为接下来对比的Baseline。首先,我们使用env.reset()初始化环境,然后进行10次随机试验,这里调用env.render()将CartPole问题的图像渲染出来。使用np.random.randint(0,2)产生随机的Action,然后用env.step()执行随机的Action,并获取返回的observation,reward和done。如果done标记为True,则代表这次试验结束,即倾角超过15度或者偏离中心过远导致任务失败。在一次试验结束后,我们展示这次演示累计的奖励reward_sum并重启环境。
env.reset() random_episodes=0 reward_sum=0 while random_episodes<10: env.render() observation,reward,done,_=env.step(np.random.randint(0,2)) reward_sum+=reward if done: random_episodes+=1 print 'Reward for this episode was:',reward_sum reward_sum=0 env.reset()
我们的策略网络使用简单的带有一个隐含层的MLP。先设置网络的各个超参数,这里的隐含节点数H设为50,batch_size设为25,学习速率learning_rate为0.1,环境信息observation的维度Dwei 4,gamma即Reward的discount比例设为0.99.在估算Action的期望价值(即估算样本的学习目标)时会考虑Delayed Reward,会将某个Action之后获得的所有Reward 做Discount并累加起来,这样可让模型学习到未来可能出现的潜在Reward。注意,一般discount比例要小于1,防止Reward被无损耗的不断累加导致发散,这样也可以区分当前reward和未来reward的价值(当前Action直接带来的reward不需要discount,而未来的reward因存在不确定性所以需要discount)
H=50 batch_size=25 learning_rate=1e-1 D=4 gamma=0.99下面定义策略网络的具体结构。这个网络将接受observation作为输入信息,最后输出一个概率值用以选择action(我们只有两个action,向左施加力或者向右施加力,因此可以通过一个概率值决定)。我们创建输入信息observation的placeholder,其维度为[D,H]。接着用tf.matmul将环境信息observation乘上W1再使用RELU激活函数处理得到隐含层输出layer1,这里注意我们并不需要加偏置。同样用xavier_initializer算法创建最后sigmoid输出层的权重W2,将隐含层输出layer1乘以W2后,使用sigmoid激活函数处理得到最后的输出概率。
observation=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)这里模型的优化器使用Adam算法。我们分别设置两层神经玩过参数的梯度的placeholder------W1Grad和W2Grad,并使用adam.apply_gradients定义我们更新模型参数的操作updateGrads。之后计算参数的梯度,当积累到一定样本量的梯度,就传入W1Grad和W2Grad,并执行updateGrads更新模型参数。这里注意,深度强化学习的训练和其他神经网络一样,也使用batch training的方式。累计到一个batch_size的样本的梯度再更新参数,防止单一样本随机扰动的噪声对模型带来不良影响。
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] updateGrads=adam.apply_gradients(zip(batchGrad,tvars))下面定义函数discount_rewards,用来估算每一个Action对应的潜在价值discount_r。每次获得的reward都和前面的action有关,属于delayed_reward。我们定义每个action除直接获得的reward外的潜在价值为running_add,running_add是从后向前累计的,并且需要经过discount衰减。而每一个action的潜在价值,即为后一个action的潜在价值乘以衰减系数gamma再加上它直接获得的reward,即running_add*gamma+r[t]。这样从最后一个action开始不断向前累计计算,即可获得全部action的潜在价值。这种对潜在价值的估算方法符合我们的期望,越靠前的action潜在价值越大。
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 return discounted_r
我们定义人工设置的虚拟label(取值为0或1)的placeholder---input_y,以及每个action的潜在价值的placeholder-advantages。这里loglik定义略显复杂,我们来看一下Loglik到底代表什么。action取值为1的概率为probability(即策略网络输出的概率),action取值为0的概率为1-probability,label的取值与action想法,即label=1-action。当action为1时,label为0,此时loglik=tf.log(probability),action取值为1的概率的对数;当action为0是,label为1,此时Loglik=tf.log(1-probability),即action取值为0的概率的对数。所以loglik其实就是当前action对应的概率的对数,我们将loglik与潜在机制advantages相乘,并取负数作为损失,即优化目标。我们使用优化器优化时,会让能获得较多advantages的action的概率变大,并让能获得较少advantages的action的概率变小,这样能让损失变小。通过不断的训练,我们便能持续加大能获得较多advantages的action的概率,即学习到一个能获得更多潜在价值的策略。最后,使用tf.trainable_variables()获取策略网络中全部可训练的参数tvars,并使用tf.gradients求解模型参数关于loss的梯度。
input_y=tf.placeholder(tf.float32,[None,1],name='input_y') advantages=tf.placeholder(tf.float32,name='reward_signal') 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.grandients(loss,tvars)在正式进入训练过程前,我们先定义一些参数,xs为环境信息observation的列表,ys为我们定义的label的列表,drs为我们记录的每一个action的reward,我们定义累计的reward为reward_sum,总试验次数total_episodes为10000,直到达到获取200的reward才停止训练。
xs,ys,drs=[],[],[] reward_sum=0 episode_number=1 total_episodes=10000
我们创建默认的Session,初始化全部参数,并在一开始将render的标志关闭。因为render会带来比较大的延迟,所以一开始不太成熟的模型还没必要去观察。县初始化CartPole的环境并获得初始状态。然后使用sess.run执行tvars获取所有模型参数,用来创建储存参数梯度的缓冲器gradBuffer,并把gradBuffer全部出池化为0.接下来的每次试验中,我们将手机参数的梯度存储到gradBuffer中,直到完成了一个batch_size的试验,再将汇总的梯度更新到模型参数。
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下面进入实验的循环,最大循环次数即为total_episodes。当某个batch的平均reward达到100以上时,即agent表现良好时,调用env.render()对试验环境进行展示。先使用tf.reshape将observation变形为策略网络输入的格式,然后传入网络中,使用sess.run执行probability获得网络出书的概率tfprob,即action取值为1的概率。接下来我们在(0,1)间随机抽样,若随机值小于tfprob,则令action取值为1,否则令action取值为0,即代表action取值为1的概率为tfprob。
while episode_number<=total_episodes: if reward_sum/batch_size > 100 or rendering==True: env.render() redering=True x=np.reshape(observation,[1,D]) tfprob=sess.run(probability,feed_dict={observations:x}) action= 1 if np.random.uniform() < tfprob else 0
然后将输入的环境信息observation添加到列表xs中。这里我们制造虚拟的Lable-y,它取值与action相反,即y=1-action,并将其添加到列表ys中,然后使用env.step执行一次action,获取observation,reward,done和info,并将reward累加到reward_sum,同时将reward添加到列表drs中。
xs.append(x) y=1-action ys.append(y) observation,reward,done,info=env.step(action) reward_sum+=reward drs.append(reward)
将done为True,即一次试验结束时,将episode_number加1.同时使用np.vstack将几个列表xs,ys,drs中的元素纵向堆叠起来,得到epx,epy和epr,并将xs,ys,drs清空以备下次试验使用。这里注意,epx,epy,drs即为一次试验中获得的所有observation、label、reward的列表。我们使用前面定义好的discount_rewards函数计算每一步action的潜在价值,并进行标准化(减去均值再除以标准差),得到一个零均值标准差为1的分布。这么做是因为discount_reward会参与到模型损失的计算,而分布稳定的discount_reward有利于训练的稳定。
if done: episode_num+=1 epx=np.vstack(xs) epy=np.vstack(ys) epr=np.vstack(drs) xs,ys,drs=[],[],[] discounted_epr = discount_rewards(epr) discounted_epr -= np.mean(discounted_epr) discounted_epr /= np.std(discounted_epr)
我们将epx,epy和discounted_epr输入神经网络,并使用操作newGrads求解梯度。再将获得的梯度累加到gradBuffer中去。
tGrad=sess.run(newGrads,feed_dict={observations:epx,input_y:epy,advantages:discounted_epr}) for ix,grad in enumerate(tGrad): gradBuffer[ix] += grad当进行试验的次数达到batch_size的整倍数时,gradBuffer中就累计了足够多的梯度,因此使用updateGrads操作将gradBuffer中的梯度更新到策略网络的模型参数中,并清空gradBuffer,为计算下一个batch的梯度做准备。这里注意,我们是使用一个batch的梯度更新参数,但是每一个梯度是使用一次试验中全部样本(一个action对应一个样本)计算出来的,因此一个batch中的样本数实际上使25(batch_size)次试验的样本数之和。同时,我们展示当前的试验次数episode_number,和batch内每次试验平均获得的reward。当我们batch内的每次试验的平均reward大于200时,我们的策略网络就成功完成了任务,并将终止循环。如果没有达到目标,则清空reward_sum,中心累计下一个batch的总reward。同时,在每次试验结束后,将任务环境env重置,方便下一次试验。
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) if reward_sum/batch_size > 200: print 'Task solved in ',episode_number,'episodes' break reward_sum=0 observation=env.reset()
相关文章推荐
- 基于Tensorflow的神经网络解决用户流失概率问题
- 一个网络问题的解决
- 关于创建一个输入端和两个输出端遇到问题的解决
- 一个我很长时间才解决的关于xp与2000共享的网络问题
- VS2005无法创建或打开”智能设备”项目的一个问题的解决方法
- VS2005 无法创建或打开“智能设备”项目的一个问题的解决方法
- 关于WIN7下,DELPHI利用RAS去创建拨号网络的问题解决
- 关于Windows 7启动后网络一直转的问题的一个解决方法
- 一个古怪的VISTA网络问题解决的坎坷经历
- 程序猿基于解决复杂问题设计的一个APP
- 解决网络问题,提供解决方案,全力打造一个辉煌而有趣的网络安全交流群。
- "Visual studio .net 无法创建或打开应用程序" 问题的一个解决思路
- (Relax 贪心1.4)POJ 2325 Persistent Numbers(使用贪心策略解决这么一个问题: 给定一个数n,求一个最小的数m,使得m的各位的乘积==n)
- 一个组策略无法打开的问题(已解决)和大家分享下经
- [原创]SQL Server 2005:一个使用新创建的User的问题和解决方法
- 分享一个在XP系统的无线网络问题解决方法
- 今天在网络上找到了一个比较好的解决Rhythmbox中文乱码的问题的方法
- 网络打印机提示的“功能地址0x造成了一个保护错误”问题解决方案
- 一个网络问题的解决