Hello,大家好,这里是糖葫芦喵喵~!
经过了几个月的奋斗,大家是不是对炼丹已经有所体会了呢?从今天起我们要进入机器学习的一个非常引人注目的领域——强化学习(reinforcement learning)啦!强化学习部分理论较强,不是很好理解。但是不要怕,相信只要读懂了代码就能够理解了!那么,从这里开始为大家带来伯克利深度强化学习CS294 Fall 2017以及斯坦福强化学习CS234 2017的Assginment解析,还请大家多多指教~!
那么,继续我们的炼丹旅程吧~!
Part 0 CS294与CS234 Assignment简介与环境准备
1. CS294
在Fall 2017的课程组织上有了非常重大的改进!(以前喵喵是不会直接推荐这门课程的,现在强烈推荐!)
CS294 Fall 2017 基本可以分为DRL介绍+模仿学习、model free、model based、Exploration+迁移+多任务+Meta-learning等四大部分。课程需要有一点强化学习和机器学习基础,建议先看完
CS294一共有四个很有趣的assignment,分别是:模仿学习(行为克隆和DAgger)、策略梯度(AC算法)、DQN和基于模型的Model Predictive Control(MPC)。assignment代码量不大,但是很具有探索性,能够在帮助你理解相关算法的同时让你对强化学习环境
2. CS234
CS234: Reinforcement Learning,是斯坦福大学的强化学习课程,该课程从强化学习介绍与基础知识(MDP、MC、TD)开始,主要讲解了model free、Exploration和策略梯度。前半部分和
CS234有三个assignment,分别是:R-max。其中assignment 1恰好是CS294 assignment所没有体现的部分,可以作为补充。assignment 2 的DQN框架写的很漂亮(虽然一部分是借鉴CS294的2333),值得详细阅读!
3. 环境准备
建议使用ubuntu,windows[all]模式未安装成功(简易模式无法进行atari实验)。
首先安装以下包:
apt-get install -y python-numpy python-dev cmake zlib1g-dev libjpeg-dev xvfb libav-tools xorg-dev python-opengl libboost-all-dev libsdl2-dev swig
然后安装Gym:
pip install gym[all]
Joint dynamics with Contact)是一个模拟机器人,生物力学,图形和动画等领域的物理引擎。建议使用linux,CS294要求安装版本为mjpro131 linux。
MuJoCo需要注册才能免费使用30天,请尽量保证在30天内完成作业。注册后通过邮箱接收到mjkey.txt,将这个文件放在mjpro131同级目录下即可。具体位置可参考示例:
/home/username/.mujoco/mjpro131
/home/username/.mujoco/mjkey.txt
其中username是你的用户名(用过linux应该都能明白吧),.mujoco可以手动建立一个。mjpro131是你下载并解压的MuJoCo文件夹,mjkey.txt是注册接收的key。、
至此,复杂的环境配置完毕,可以尝试运行一些demo看看有没有问题。
4. 文章组织与学习资料
喵喵这里为了便于理解,打乱了两门课程的作业顺序,分别按照模仿学习(CS294 assignment 1)、值迭代和策略迭代(CS234 assignment 1 部分)、DQN(CS294 assignment 3 \ CS234 assignment 2)、策略梯度(CS294 assignment 2)和基于模型的强化学习(CS294 assignment 4和CS234 assignment 1 部分)的顺序进行讲解。
推荐学习资料:
喵喵的代码实现:Observerspy/CS294github.comObserverspy/CS234github.com
强化学习原理与技术详解:强化学习知识大讲堂
CS234 2017 课件:某云链接:1dFPlzvr 密码:rsai
开篇讲了这么多,现在让我们愉悦地开始第一个作业模仿学习(CS294 assignment 1)吧!
Part 1 Behavioral Cloning
Behavioral Cloning,行为克隆,其实本质上就是一个标准的监督学习过程,如下图所示:
显然我们是要学习一个输入是观测o,输出是动作a的策略网络。所谓策略就是在给定当前(观测)状态下你所做出的动作选择。于是,明确了我们的数据(观测o,动作a),整个监督学习任务就很清晰了。
我们的实验一共有6个任务:
Hopper,Ant,HalfCheetah,Humanoid,Reacher,Walker2d。
如果你环境配置好了运行demo.bash就能看到6个任务的效果了:单足跳的UMA,四条腿的蚂蚁,两条腿的豹子, 跌跌撞撞的人,够小球的机械臂,两条腿的神奇生物。
先不吐槽这些神奇生物,我们先来运行专家策略run_expert.py生成训练数据,对6个任务分别生成20个rollouts的数据用于训练(每个rollouts默认走1000步,当然有的任务不到1000步就结束了,具体任务具体分析即可)。所以我们拥有20000个训练数据啦!
专家策略的return均值和标准差如下:
Hopper-v1(input_dim: 11, output_dim: 3)
mean return 3776.51785877 std of return 3.45247967435
Ant-v1 (input_dim: 111, output_dim: 8)
mean return 4832.13478595 std of return 86.6941336401
HalfCheetah-v1 (input_dim: 17, output_dim: 6)
mean return 4132.24798316 std of return 74.760867223
Humanoid-v1 (input_dim: 376, output_dim: 17)
mean return 10401.7386441 std of return 40.9353971034 need more iter
Reacher-v1 (input_dim: 11, output_dim: 2, max_step = 50)
mean return -4.16785312879 std of return 1.74762339869
Walker2d-v1 (input_dim: 17, output_dim: 6)
mean return 5515.55381623 std of return 37.8541602931
然后就是模型,这里喵喵随便弄了一个三层的网络,结构如下:
with tf.name_scope('layer1'):
hidden1 = tf.contrib.layers.fully_connected(self.input_placeholder,
num_outputs=128, activation_fn=tf.nn.relu)
with tf.name_scope('layer2'):
hidden2 = tf.contrib.layers.fully_connected(hidden1,
num_outputs=256, activation_fn=tf.nn.relu)
with tf.name_scope('layer3'):
hidden3 = tf.contrib.layers.fully_connected(hidden2,
num_outputs=64, activation_fn=tf.nn.relu)
with tf.name_scope('output'):
pred = tf.contrib.layers.fully_connected(hidden3,
num_outputs=Config.n_classes, activation_fn=None)
参数设置:
epoch=20,itera(迭代次数,为了和DAgger对比)=20,batch_size = 256,lr = 0.0005
每一次itera后我们都以学习到的策略运行20个rollouts,并记录returns的均值AverageReturn和标准差StdReturn。
(题外话:其实CS294整个作业下来有两个工具类特别好用,就是logz.py和plot.py,记录画图一气呵成,已经成为喵喵的常备工具了233
画图如下:(其中hopper-big是将网络第二层节点数提高到512个)
毕竟其实只训练了itera * epoch = 400(epoch),所以效果也就这样了(为了和DAgger对比)。对比专家策略,也就Ant和HalfCheetah任务勉强接近,其他任务基本上可以说差得很远了,当总epoch更大时Ant和HalfCheetah任务效果更好一些。当然,在我们提高网络节点数量,增强模型表达能力的时候,我们还是可以看到有一个明显的提升的(Hopper)。
Part 2 DAgger
看来上述简单的方法不太行,问题出在哪里呢?
我们的训练数据分布记为
,我们通过模型学习到的策略记为
。当我们执行我们学习到的策略得到的实际数据分布应为
,这个分布通常与
不一致,除非实际数据分布和训练数据分布完美的一致。因此,我们的Behavioral Cloning在某些任务下很快就偏移了:
那么为了解决这个问题,一个很简单的想法就是让
能去贴近
。那么,我们每次在执行完策略
后对获得的观测
重新人为给出标记
不就行了?这样我们把新获得的数据加入到原来的data中重新训练,不断地让
去贴近
。这就是我们的DAgger算法思想:
很简单,只是比Behavioral Cloning多了两步:
1. 从已抽取的data中训练策略网络
2. 运行学习策略
后获得的
3. 对获得的
执行专家策略得到其label:
;
4. 将获得的(
,
) 加入data重新训练策略。
核心部分实现:
for _ in range(10):
_, o = run_env(env, nn, session) #执行学习到的策略,获得新的观测o
observations.extend(o)
action = policy_fn(o) #对新观测的o执行专家策略,获得a作为label
actions.extend(action)
参数设置:
网络结构同上,epoch=20,itera=20,batch_size = 256,lr = 0.0005
初始依然是20 rollouts数据,每个itera加入10 rollouts的新数据。
对比结果如下(DA for DAgger, BC for Behavioral Cloning):
可以看到DAgger基本上在同样的参数下都能接近专家策略的return了。
关于更多DAgger算法的问题,请详细的学习CS294第二节。
好了,这就是我们本次对模仿学习的讲解,我们正式踏入了强化学习的门框233。强化学习里非常重要的算法我们后续也都会接触到,不要着急哦。
では、おやすみ~!
下期预告:CS234 Assignment1 值迭代和策略迭代作业详解