2024年1月

引言

强化学习是蛋糕顶上缀着的一颗樱桃,这不是我说的,而是深度学习领域Yann LeCun教授在CoRL 2017大会上做的演讲时提及的。他著名的“蛋糕”理论。“真正的”强化学习好比蛋糕上的樱桃,监督学习好比蛋糕上的糖衣,而蛋糕本身是非监督学习(预测学习)。这里LeCun也表示,这一比喻对做强化学习的兄弟可能不太友好。

cake theory.jpeg

认识下“樱桃”

什么是强化学习呢?举个通俗的例子,强化学习就好比一个女猎手(为啥是女猎手,因为我下面用了阿塔兰忒的图像,哈哈)进入了一个迷雾森林,里面充满了各种挑战和奖励。她得自己摸索,判断哪个方向更有“糖果”,哪个方向有“陷阱”。在这个过程中,她会慢慢学会,哦,原来这样做能得到糖果,那样做会掉进陷阱。

不过,这个魔法森林可不是那么容易走的。有时候,她会走错路,掉进陷阱,或者绕着同一个地方转圈圈。这时候,就需要神出手啦,给她点提示,让她知道哪个方向可能更有糖果。这就是我们常说的“智能体(agent)”和“环境(evironment)”之间的互动。

通过这样的摸索和学习,阿塔兰忒最终会走出迷雾森林,这就是强化学习的魅力所在啦!

atalanta.png

小姐姐好看吧,也是我用AIGC生成的,嘿嘿。

其实上面简单通俗的语言,就已经把强化学习的原理展露出来了,强化学习(Reinforcement Learning,RL)是一种通过试错来学习的方法。在深度学习中,强化学习用于训练智能体(agent)在环境(evironment)中采取行动,以最大化累积奖励。与监督学习不同,强化学习没有明确的输入输出对,智能体需要通过与环境的交互来学习最佳策略。

深度学习中的强化学习原理涉及到状态(state)、动作(action)、奖励(reward)等核心概念。状态是指环境的当前状态,动作是智能体可以执行的操作,奖励是智能体采取某个动作后获得的正面或负面反馈。智能体在环境中不断尝试不同的动作,根据奖励信号来调整策略,以期获得最大的累积奖励。

深度强化学习在许多应用领域取得了显著的成果,例如自动驾驶、游戏AI、机器人控制等。在实际应用中,智能体需要与环境进行大量的交互来学习最佳策略,这通常需要大量的计算资源和时间。

实践环节

当然只知道上面的原理是不够的,实践出真知,这块怎么去实验呢?我想起了2017年,Deepmind公司发表在nature科学杂志上的AlphaGoZero论文,当时也是通过在围棋比赛上战胜人类冠军而出圈,零人类经验,其自我训练的时间仅为3天,自我对弈的棋局数量为490万盘。但它以100:0的战绩击败前辈。围棋显然我没法找到足够算力支持,但是找个简单的游戏,还是可行的,那么我想到了一个简单好玩的小游戏《flappy bird》,我首先做了一个通过玩家控制的版本:

录屏2024-01-20 15.17.25.gif

是不是很熟悉,画面不够精致,但是也够用了,小白球作为小鸟,需要往前飞,又不能碰到白色障碍物。我自己来控制,还是比较难掌控的,很快就会死了。

那么怎么实现AI控制小鸟,就是我要完成的事情。首先上面说的环境(evironment)在这个游戏中就是这个游戏本身,智能体(agent)就是这个小鸟的大脑,控制小鸟的行动。关于环境(evironment),如何抽象状态(state)是关键,我想到有好几种方法:

  1. 整个游戏画面作为state,画面的每个像素点就是state,智能体(agent)需要自己理解这个画面意味着什么,障碍物的距离,小鸟的位置等等;
  2. 计算某一帧时环境变量,最近的障碍物顶部占据画面高度的比例,小鸟离最近障碍物的距离占画面宽度的比例,小鸟的垂直方向的位置,小鸟的速度等等;

显然不管环境(evironment)如何抽象,智能体(agent)都应该可以学会如何应对某一个具体的state,我在这篇文章中,先尝试了2这个方法,定义了5个变量:

environment[0] = closest.x / (WIN_WIDTH - bird.x) # 最近的障碍物的横坐标 = closest.x,小鸟的横坐标 = bird.x,屏幕的宽度 = WIN_WIDTH
environment[1] = closest.top / WIN_HEIGHT # 最近的障碍物上半部分下沿 = closest.top,屏幕的高度 = WIN_HEIGHT
environment[2] = closest.bottom / WIN_HEIGHT # 最近的障碍物下半部分上沿 = closest.bottom,屏幕的高度 = WIN_HEIGHT
environment[3] = bird.y / WIN_HEIGHT # 小鸟的纵坐标 = bird.y,屏幕的高度 = WIN_HEIGHT
environment[4] = bird.velocity / 10 # 小鸟的往前的速度 = bird.velocity

智能体(agent)简单定义为一个深度神经网络(4层的全连接网络),输入就是上面的evironment数组变量,输出为action,在这个游戏中就是两种行为:1、向上飞;2、保持不动,所以神经网络最终输出为2。

brain = Sequential(
    Linear(5, 16, name='linear1'),
    ReLU(name='relu1'),
    Linear(16, 64, name='linear2'),
    ReLU(name='relu2'),
    Linear(64, 16, name='linear2'),
    ReLU(name='relu3'),
    Linear(16, 2, name='linear2'),
)

那么就来到了最难设计的部分,奖励(reward)如何设计,这里又必须展开一些强化学习训练细节来讲下。强化学习的训练数据,是通过智能体(agent)和环境(evironment)不停的交互,产生的一系列动作(action)概率和一系列奖励(reward)来进行训练的。所以奖励(reward)的设计尤为关键,简单讲就是在迷雾森林中,你要准确的告诉阿塔兰忒往左是陷阱,会被扣分,往右是糖果,是个奖励,会加分。所以在每个具体游戏中,都需要去明确的制定合理的奖励(reward)规则,最后智能体(agent)才会做出利益最大化的动作(action),那么我这里是这样定义的:

for pipe in self.pipes:
    if pipe.hits(bird):
        reward = -450 # 撞到障碍物 pipe,扣450分
        done = True
        break
    elif pipe.avoid(bird):
        reward = 60 # 躲避障碍物 pipe,得60分

if bird.hitBottom():
    reward = -450 # 小鸟撞到底部,扣450分
elif bird.hitTop():
    reward = -450 # 小鸟撞到底部,扣450分

别小看这几句代码,简单但是扣分和得分是会影响智能体(agent)学习的速度的。我这里是调试了不少时间,才完成了整个训练,如果有朋友有兴趣,我可以详细来讲下这部分的训练实现和调试过程,这篇文章里我不进行展开。

结论

展示下最终的效果:
mmexport1705740885312 (1).gif

感觉效果还是十分nice的,视频转gif没处理好,感觉gif图的质量一般,我自己看AI玩的效果是真的6,我想下次可以再继续使用图片作为环境(environment),改一下模型结构(可能需要换成resnet等cnn作为backbone),硬train一发,也能得到类似的效果,这个就留作后续的任务,挖个小坑。