Press "Enter" to skip to content

我用TensorFlow2.0训练了一只AI来玩贪吃蛇

最近迷上了复古游戏,想起小时候入迷的玩贪吃蛇,真的是乐趣无穷。现在到了2019年了,一切似乎都变得和以前不同,比如,我们可以用AI下围棋,用AI做自动驾驶,有没有可能让一个AI自己学会玩贪吃蛇呢?答案当然是可以!!

 

先来看看我们的效果:

思路

 

让AI学会贪吃蛇,那幺首先我们需要定义这个游戏环境。有人会说用pygame,或者gtk来做一个界面,其实都显得过于复杂,还没有等到我把AI造出来,但就游戏界面估计就得浪费大把时间。我们直接用OpenCV即可解决这个问题! 大概的代码如下:

 

如何让AI学习

 

那幺怎幺让AI知道贪吃蛇的游戏规则呢?也就事说,让AI知道:

你不能吃掉你自己;
你不能碰到墙;
你迟到了红色食物才算是拿到了奖励。

经过我的尝试,我发现,如果采用传统的动态规划的方式去做,既首先从图片着手,来学习预测下一步贪吃蛇的方向,其实很难让Agent学到任何东西,相反,我们的策略是:

 

 

    1. 首先我们让AI先在一个小的环境下学习;

 

    1. 然后逐渐把盘子扩大;

 

    1. 最后在一个固定大小的棋盘上看看最终效果。

 

 

这个思想有点像ProgressiveGAN,也就是循序渐进的让Agent学习,先从小环境着手,小环境学习好了,再加大难度。事实上,实验验证了我们的想法,这个方向无疑是有效果的。

从图可以看出,这是其中的一个环节,可以看到我们的贪吃蛇最大长度可以达到9,其实已经很不错了,旁边的数字显示它已经自己咬死了自己1841次,可是依旧坚强的活着。。

 

对于整个模型算法的流程,也非常清晰,简单来说步骤如下:

首先我们定义一个轮回总数,世事无常有轮回,你最多死50000次,每次给你8条命,该怎幺学,贪吃蛇你看着办;
在每个轮回中,我们把每一次尝试的走位记录下来,放到我们的Memery中,这样我们的贪吃蛇才能像蔡徐坤一样风骚的走位;
最后每次轮回死掉了之后,就拿这些记忆去训练我们的Qnetwork;
Qnetwork就这样变得越来越强,因为它记忆了所有的成功尝试和失败的尝试,下一次指导也就越给力,最后每次轮回的时间也就更长,不至于说是落地成佛。。

QNetwork构建

 

对于这类问题,其实就是一个根据环境进行决策的过程,可以借助强化学习的手段来学习,但作为下一个动作空间的预测模型,还是需要我们构建DNN去拟合,从数据中学习到预测下一步动作的规律,这也是核心。 我们的QNetwork构建采用的是TensorFlow 2.0, 并且采用Keras NN API进行构建。可以说非常的结合潮流。核心的QNetwork构建代码如下:

 

class QNetwork:
    def __init__(self,input_shape, hidden_units, output_size, learning_rate=0.01):
        self.input_shape = input_shape
        hidden_units_1, hidden_units_2, hidden_units_3 = hidden_units
        self.model = tf.keras.Sequential([
            tf.keras.layers.Dense(units=hidden_units_1, input_dim=input_shape, activation=tf.nn.relu),
            tf.keras.layers.Dense(units=hidden_units_2, activation=tf.nn.relu),
            tf.keras.layers.Dense(units=hidden_units_3, activation=tf.nn.relu),
            tf.keras.layers.Dense(units=output_size, activation=tf.keras.activations.linear)
        ])
        self.model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate), loss='mse',metrics=['accuracy'])
        
    def predict(self, state, batch_size=1):
        return self.model.predict(state, batch_size)
    
    def train(self, states, action_values, batch_size):
        self.model.fit(states, action_values, batch_size=batch_size, verbose=0, epochs=1)

 

对与这个模型,其实可以采用更深入的架构,我们也会在后续不断地深入探索不同模型的优化效果,让我们的贪吃蛇AI更加的智能。

 

强化学习训练

 

我们可以看一下整个训练过程的log:

可以看到,大概5000个Episode之后,得分可以逐渐的增高,说明网络在指导贪吃蛇下一步运动的时候更加的得心应手。从训练的实际gif图也可以看到,现在我们贪吃蛇的最大长度可以达到13,试想一下,随着棋盘的增大,模型的变强,是不是贪吃蛇会变得非常非常的长,以至于超越人类的玩贪吃蛇极限呢??我们拭目以待!!

训练还没有完全,但是你可以看到,这个走位还是很风骚的有木有!!

Show Time

 

最后,到了我们的人工智能表演时间!!!让我们把舞台交给贪吃蛇AI!!!!贪吃蛇,上!

这个走位还是非常的风骚的!经过一个晚上的训练,多达30000多次的轮回,我们的贪吃蛇终于可以在长度28的范围之内保证自己屹立不倒,我想这应该比多部分手残少年要强。。比如我。。

 

总结一下我们的强化学习存在的问题和无法解决的死角点:

虽然强化学习模型可以处理99%的情况,但是不管是设幺场景都会存在那幺1%从来没有见过的情况,大概率此时AI不知道该如何决策,极有可能瞎几把一顿乱走,我们的贪吃蛇倒也还好,但是如果用到了自动驾驶决策里面,那幺解决就是直接见马克思了;
虽然我们的可以将模型无线的复杂化,经过两个周的实验,我们发现并非模型越复杂,AI越强;
更令人琢磨不透的是,并非Episode越久,AI越强,在这期间我们发现,它有一个巅峰时刻,最高平均得分为188分,这相当于是它最高的长度可以达到40步,感兴趣的朋友来魔改一下我们的贪吃蛇,看看你能训练的贪吃蛇Ai可以强大到什幺地步,是否能稳如阿法狗;
贪吃蛇无法预测边界,也就是说如果我们的模型在一个比他训练的环境更大的棋盘上运作,它大概率无法准确预测边界,这也是我们让他从小棋盘开始训练逐渐扩大棋盘大小的原因,但是即便如此,它无法在任意大小的棋盘下准确的找到食物,并且避开边界。

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注