概述
- 所用技术:强化学习(Deep Reinforcement Learning),属于一种无监督学习,利用奖励
r
e
w
a
r
d
reward
reward教会智能体
A
g
e
n
t
Agent
Agent在合适的场景做合适的决策。
- 采用算法:试过两种算法D3QN和离散版本的PPO算法,最终采用离散版本PPO算法+GAE(PPO是我用过的性能最好的算法之一)
- 编程语言与深度学习框架:Python3.8 + torch
构建问题(强化学习求解的一般步骤)
环境
贪食蛇的环境参考了https://www.cnblogs.com/dengfaheng/p/9241267.html,在其基础上进行改动和封装,写成了符合强化学习标准的环境接口,满足如下最基本操作:
.step(action) ,即对环境执行动作。.reset() ,重置环境。.render() ,渲染图像,可视化训练。
窗口设定为600*600像素,其中50*50像素格为一个单元,即整个游戏场景为12*12方格(也可以设置大,训练难度和时间会相应非线性增加)。 食物:一个单元尺寸大小。 贪食蛇:n个单元构成(n为当前贪食蛇长度)
动作定义
对于贪食蛇定义动作如下:
A
c
t
i
o
n
∈
{
0
,
1
,
2
,
3
}
Action\in \{0,1,2,3\}
Action∈{0,1,2,3} 分别代表上下左右移动蛇头。其实更合理的是三个方向,因为蛇不能倒退,但是DRL对这个bug还是有忍耐度的。
状态定义
这个问题我试了很多种:
- 将游戏当前帧作为RGB图像(或者二值化图像),用卷积网络提取特征,这里图像就是强化学习的state。结果发现不可行,其一是网络参数因卷积而增加,而Actor网络是需要有快速回归能力的,其二是图像必须resize,太大了训练慢,太小了特征不明显(蛇都糊了…)。
- 将12*12的界面当成12*12的矩阵,其中蛇头位置取2,蛇身位置取1,食物位置取-1,其余位置取0,然后把这个矩阵要么当图像用卷积,要么直接flatten为向量作为特征。结果发现效果比较差,向量维度太大,强化学习难以学习到策略。
- 将当前蛇头和食物的相对x坐标和y坐标作为state,实验发现效果还行,但是由于state中没有蛇的身子的信息和游戏边界的信息,蛇很容易自杀。
- 蛇头和食物的相对x坐标和y坐标,蛇头上、下、左、右是否有自身身体或者游戏边界作为state,效果很好,训练后AI超过普通玩家水平:
s
t
a
t
e
=
[
x
f
o
o
d
?
x
h
e
a
d
,
y
f
o
o
d
?
y
h
e
a
d
,
k
1
,
k
2
,
k
3
,
k
4
]
,
k
i
∈
{
0
,
1
}
state=[x_{food}-x_{head},y_{food}-y_{head},k_1,k_2,k_3,k_4],k_i \in\{0,1\}
state=[xfood??xhead?,yfood??yhead?,k1?,k2?,k3?,k4?],ki?∈{0,1} 其中当
k
i
=
1
k_i=1
ki?=1时表明蛇头的第
i
i
i个方向上存在障碍,另外
x
f
o
o
d
?
x
h
e
a
d
,
y
f
o
o
d
?
y
h
e
a
d
x_{food}-x_{head},y_{food}-y_{head}
xfood??xhead?,yfood??yhead?最好归一化。
目前暂时使用第四种方案。
奖励设计
奖励是强化学习的灵魂,常起画龙点睛之作用。
- 初始化
reward=0 ; - 如果当前state蛇吃到了食物,
reward+=2 - 计算蛇头和食物的距离d,如果d<t,则
reward += (t-d)/t (这里t取一个小正数即可比如2); - 如果当前state蛇自杀,
reward -= 0.5 ;
其中第3条可以引导贪食蛇找食物,否则可能由于稀疏奖励导致训练出一个只会“苟且偷生”的蛇,但是如果你的算法性能够好,第三条可以不要。
训练奖励值收敛图
采用第4种状态定义方法
家用电脑半小时内训练完毕(横轴游戏训练回合数,纵轴累计奖励回报值):
初步训练效果
下面这张图是初步训练的策略,其实挺像我小时候玩这个游戏时到后期的做法,但最后太长了它也没想到把自己堵死了…
最终训练效果
经过一系列优化,得到了一个较为满意的策略: 可以看到贪食蛇是会躲避自己的身体的!并且有自己的路径规划策略!
模型泛化迁移能力
在小尺寸地图上训练好的模型可直接迁移到大尺寸地图策略依旧可行:
代码
整个项目的所有代码和中间结果甚至是权重均已push到github,欢迎star/fork,你的星星是对我最大的帮助: DRL4SnakeGame:一个使用强化学习快速让AI学会玩贪食蛇游戏的项目 what you need to do is to run the main.py and then run the env4Snake to test your mdoel! 这个项目还有很多改进的点,会不时更新~
|