强化学习初探 DQN+PyTorch+gym倒立摆登山车

本文介绍了作者通过DQN算法使用PyTorch和gym环境解决倒立摆及登山车问题的思路与过程。文章详细讨论了为何选择DQN、环境采样、奖励设计、Q值近似计算和主循环等关键步骤,并提供了代码和训练模型的下载链接。此外,还分享了在设计奖励函数时的经验和技巧。
摘要由CSDN通过智能技术生成

1.随便说几句

疫情赋闲在家,就想着多学点东西吧。看了看GAN的东西,还看了看cs224的NLP,在做NLP作业的时候感觉虽然比单纯地刷准确率有意思点,但是a4的翻译作业竟然是翻译法语到英语的,我啥也分析不了,和刷准确率也差不多啊。
最后,我想去探索一下强化学习的领域了。强化学习可以用来玩游戏,而且也可以用于序列预测,和以后的方向有点关联还挺有意思的样子。以前听老师在AI导论课讲强化学习或者看CS231的强化学习,一般只有一节课,一堆概念乱糟糟的,也不怎么作为重点,所以学得一直很迷糊。然后在B站上看了David Silver的强化学习视频课,感觉收获很大。说老师讲得好确实有,但是可能更重要的是花了好多节课来学习,所以各个概念也弄得更清晰一点吧。老师确实很有耐心地解答问题,同学也很积极提问。
由于有读者想要倒立摆的源码,所以干脆就把这俩源码+训练好的模型打包放到这里了。训练好的模型放置于model目录下,其中带有goodmodel字样的是训练效果比较好的模型。
代码和训练完的模型下载地址

2.为什么选择DQN作为第一个入手的模型

这是在看到第5节课《免模型预测》后,想练练手解决个简单的问题。在这之前,课程讲了很多概念,也有挺多公式的。我对状态函数不是很感兴趣,我更倾向于使用Q值的估计,因为它更直观,哪个action的Q更大就选谁。但是在真正上手之后,有个问题摆在了我面前:课程里的Q(S,a)都是离散的(比方说走格子的游戏),但是许多游戏环境里的S是连续的(或者说实在太多了,不可能一一记录和遍历),怎么办呢,接着看下一节课呗。第6节课——值函数近似(也就是下一节课)老师就直白的说,“这节课过后,你们就可以将强化学习用于解决实际问题了”。这节课就是讲采用一些方法来近似估计连续的Q(S,a)。
在上CS231的强化学习课时,小姐姐就有说过:当你想要近似一个复杂函数的时候,你可以使用神经网络。当时还不太理解这句话,因为以为神经网络只能用来分类,对于拟合函数还没有太大的理解。
所以总结来说呢,采用DQN的原因就是:
1.使用神经网络估算Q值函数,普适性很强
2.策略就是取Q值最大的action,也就是贪婪方法,很直观
3.简单
依然是先讲解我一步一步思考问题的过程,然后再统一贴个代码。

2.工具准备

环境模拟器采用gym的简单小游戏:CartPole以及MountainCar
深度学习框架采用PyTorch
IDE嘛,这个随意了,我用的是VS2019(在写py这一块bug真不少)

3.实现思路

实现主要分为几个部分来讲解。第一个是环境采样部分,第二个是reward设计部分,第三个是Q值近似计算部分,第四个是主循环。

3.1.环境采样

数据肯定要从环境里采样。采样之前先要弄懂环境是什么样的,不然怎么指导zz模型学习呢:)
我先说CartPole的环境。这是一个倒立摆游戏,简单来说平衡得越久越好。
我们都知道gym每次step都会返回给我们四元组。(状态,奖励,游戏结束,额外信息)或者写作(state, reward, done, info)。其中,info是不能在学习中使用的,不然就是作弊了。接下来说的这些参数,都是gym内置的,并非我们规定的。
它的状态空间是4维的。具体是啥我就不细说了,因为好像这个问题里不需要特别地分析(分析的话可能更好),但是下面的几个就比较重要了。尤其和登山车对比来看,它涉及到对具体问题的具体分析。
reward:每活一个时间步,+1
done:游戏结束的标志,当倾角超过一定限度时或者到达200步后游戏结束
action:2维,[0,1],向左或者向右
CartPole环境图
接下来直接说登山车的环境,我们对比来看。
它的状态空间是2维的。第1维表示车现在的水平位置。很明显,位置越大越接近终点
reward:每一个时间步,-1
done:游戏结束的标志,当到达小旗时结束
action:3维,[0,1,2],依次是向左、不动、向右
MountainCar环境图
对比两个环境我们可以发现不同:
1.reward是不一样,一个是尽量活的时间长,一个是尽量快到达终点。
2.action不一样,登山车有不动这个选项
3.done不一样,倒立摆坚持够200回合或者坚持不住了都会结束,但是登山车只有墨迹超过200回合才结束
有个重要的事情一定要看到:到达200回合后,两个游戏都结束了。根据环境分析,进行reward设计。

3.2 Reward设计

不是环境已经给了我们reward了吗,为什么还要设计reward呢???
一开始我在玩登山车的时候就没意识到这个问题,所以导致小车在低谷荡来荡去根本没法爬上坡,最令人崩溃的是训练出来的Q值近似函数永远都选择一个策略(也就是某个策略的Q一直最大),所以小车一直朝着一个方向开,或者一直熄火作周期运动。
后来我明白了:对于登山车来说,每个时间步减少1个奖励,但是达到目标并没有奖励。即使说就算达到目标有奖励,如果一直没法探索到目标,我们的模型也不可能知道有个地方还有奖励。
再者,这和我的Q函数设计有关。我的Q是基于最基础的TD-0,也就是只迭代一步,只看得到一步的奖励,对于整个游戏获得的奖励总和的感觉没那么深刻。
因此参考了别的博主的文章,改进并且设计了一个简单的分段reward。首先要把从环境观测的state打印出来,看看小车的位置一般对应哪些数值(state[0])。比方说,半山腰是-0.2,3/4山腰是-0.1,1/4山腰是-0.3这样。所以我决定在它获取阶段性胜利的时候给点甜头尝尝。先观察小车随机运动的规律,还是比较容易达到>-0.2的范围的,所以我设计的是:
1.当小车在-0.2~-0.15时,每一步给0.2的额外reward
2.当小车在-0.15~-0.1时,每一步给0.5的额外reward
3.当小车在-0.1~*时,每一步给0.7的额外reward

我还尝试过线性的reward,也就是额外reward=当前位置,但是小车容易卡在低谷;还试过线性截断的reward,当位置大于某值时才有额外的线性位置奖励。但是好像最终还是上面的方案比较好。

对于倒立摆,设计的reward就更简单了,因为倒立摆很容易就探索完整个状态空间了,所以给的额外reward就是,如果游戏结束,给-10的reward。

奖赏的设计其实应该是八仙过海各显神通的地方。比方说倒立摆的reward可以设计成坚持越久即时奖赏越多之类的,不过我这里就没试啦=v=

3.3 Q值近似计算

由于我觉得游戏本身不难,所以设计的神经网络也比较简单。三层的线性层(也可以说成是两层隐藏层),每层的输入输出分别为(以登山车为例,2入3出):
输入层:(2,16)+ LeakyReLU
隐藏层:(16,64)+ LeakyReLU
输出层:(64,3)
Loss:MSE
输入层的维度是根据state的维度来的,环境观测到几个维度就几个输入。隐藏层随意,毕竟要拟合的函数应该比较简单。输出层维度根据action来。
也就是说,这个网络输入是state,输出是各个action的Q值。

3.4 主循环

大致说一下思路:每次循环,首先进行环境采样,然后将每一步的(s, a, r, s_)存入数组中。但是原始数据和PyTorch内的数据并不兼容,所以要进行转换。再则,由于采用了batch训练以及随机抽样,所以将收集来的几千个样本做成一个dataset,采用dataloader进行批量加载。最后再进行训练并保存。因此这部分有如下三个部分:
1.环境采集函数,采集一批样本
2.数据转换部分,将采集到的数据生成dataset和dataloader,便于后续训练
3.训练部分,采用双网络进行训练,这里是直接借用课程里老师的思想的,代码也有参考别的博客的
4.保存模型。如果模型效果很好,则保存为好模型。

4.代码

我觉得该说明的基本上我都没漏呀。我只贴登山车的代码,倒立摆的只有网络输入输出个数不一样,reward不一样,还有对goodmodel的定义不一样。
有几个细节再提一下:
1.state(代码里是observation_xxx)的数据类型为numpy的数组,reward和action皆为基本类型浮点数和整数。
2.在采样环境的时候,加入了一定的随机action概率,便于在刚开始的时候采取不一样的行为
3.训练网络的时候,采用了双网络,这是老师的说法,说不容易发散。还采用了gather函数,因为一次(S, a)只影响一个Q值,也就是网络的一个输出,另外的两个输出不使用贝尔曼方程进行迭代更新。
4.登山车大概不到100次主循环就会出现游戏成功,也就是200步之内到达山顶的情况
5.env.render()是进行图形渲染的函数,训练的时候需要将其注释,否则采样很慢。测试的时候取消注释看效果

#这是一堆初始化
import gym
import random
import torch
import torch.nn as nn
from torch.utils.data import Dataset
#env = gym.make('CartPole-v0')
env = gym.make('MountainCar-v0') #action = (0,1,2) = (left, no_act, right)
#env = gym.make('Hopper-v3')
print(env.observation_space)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值