PaddlePaddle版Flappy-Bird—使用DQN算法实现游戏智能

本文介绍了使用PaddlePaddle的PARL库实现DQN算法来训练Flappy Bird游戏的智能体。通过分析游戏环境、DQN算法的发展和原理,以及代码实现过程,展示了如何运用深度强化学习让小鸟避开柱子飞行。文章还讨论了经验回放、参数化逼近等关键概念,并提供了训练和测试的示例。
摘要由CSDN通过智能技术生成

刚刚举行的 WAVE SUMMIT 2019 深度学习开发者峰会上,PaddlePaddle 发布了 PARL 1.1 版本,这一版新增了 IMPALA、A3C、A2C 等一系列并行算法。作者重新测试了一遍内置 example,发现卷积速度也明显加快,从 1.0 版本的训练一帧需大约 1 秒优化到了 0.15 秒(配置:win8,i5-6200U,GeForce-940M,batch-size=32)。

 

嘿嘿,超级本实现游戏智能的时代终于来临!废话不多说,我们赶紧试试 PARL 的官方 DQN 算法,玩一玩 Flappy-Bird。

 

关于作者:曹天明(kosora),2011 年毕业于天津科技大学,7 年的 PHP+Java 经验。于2018年9月报名加入光环国际人工智能周末转型班进行学习提升。个人研究方向——融合 CLRS 与 DRL 两大技术体系,并行刷题和模型训练。专注于游戏智能、少儿趣味编程两大领域。

模拟环境

 

相信大家对于这个游戏并不陌生,我们需要控制一只小鸟向前飞行,只有飞翔、下落两种操作,小鸟每穿过一根柱子,总分就会增加。由于柱子是高低不平的,所以需要想尽办法躲避它们。一旦碰到了柱子,或者碰到了上、下边缘,都会导致 game-over。下图展示了未经训练的小笨鸟,可以看到,他处于人工智障的状态,经常撞柱子或者撞草地:

 

 

 

 未经训练的小笨鸟

 

先简要分析一下环境 Environment 的主要代码。

 

BirdEnv.py 继承自 gym.Env,实现了 init、reset、reward、render 等标准接口。init 函数,用于加载图片、声音等外部文件,并初始化得分、小鸟位置、上下边缘、水管位置等环境信息:

 

def __init__(self):
    if not hasattr(self,'IMAGES'):
        print('InitGame!')
        self.beforeInit()
    self.score = self.playerIndex = self.loopIter = 0
    self.playerx = int(SCREENWIDTH * 0.3)
    self.playery = int((SCREENHEIGHT - self.PLAYER_HEIGHT) / 2.25)
    self.baseShift = self.IMAGES['base'].get_width() - self.BACKGROUND_WIDTH
    newPipe1 = getRandomPipe(self.PIPE_HEIGHT)
    newPipe2 = getRandomPipe(self.PIPE_HEIGHT)
    #...other code

 

step 函数,执行两个动作,0 表示不采取行动(小鸟会自动下落),1 表示飞翔;step 函数有四个返回值,image_data 表示当前状态,也就是游戏画面,reward 表示本次 step 的即时奖励,terminal 表示是否是吸收状态,{} 表示其他信息:

 

def step(self, input_action=0):
    pygame.event.pump()
    reward = 0.1
    terminal = False
    if input_action == 1:
        if self.playery > -2 * self.PLAYER_HEIGHT:
            self.playerVelY = self.playerFlapAcc
            self.playerFlapped = True
   #...other code

   image_data=self.render()
   return image_data, reward, terminal,{}

 

奖励 reward;初始奖励是 +0.1,表示小鸟向前飞行一小段距离;穿过柱子,奖励 +1;撞到柱子,奖励为 -1,并且到达 terminal 状态:

 

#飞行一段距离,奖励+0.1
reward = 0.1
#...other code

playerMidPos = self.playerx + self.PLAYER_WIDTH / 2
for pipe in self.upperPipes:
    pipeMidPos = pipe['x'] + self.PIPE_WIDTH / 2
    #穿过一个柱子奖励加1
    if pipeMidPos <= playerMidPos < pipeMidPos + 4:             
        self.score += 1
        reward = self.reward(1)
#...other code

if isCrash:
    #撞到边缘或者撞到柱子,结束,并且奖励为-1
    terminal = True
    reward = self.reward(-1)

 

reward 函数,返回即时奖励 r:

 

def reward(self,r):
    return r

 

reset 函数,调用 init,并执行一次飞翔操作,返回 observation,reward,isOver:

 

def reset(self,mode='train'):
    self.__init__()
    self.mode=mode
    action0 = 1
    observation, reward, isOver,_ = self.step(action0)
    return observation,reward,isOver

 

render 函数,渲染游戏界面,并返回当前画面:

 

def render(self):
    image_data = pygame.surfarray.array3d(pygame.display.get_surface())
    pygame.display.update()
    self.FPSCLOCK.tick(FPS)
    return image_data

 

至此,强化学习所需的状态、动作、奖励等功能均定义完毕。接下来简单推导一下 DQN (Deep-Q-Network) 算法的原理。

 

DQN的发展过程

 

DQN 的进化历史可谓源远流长,从最开始 Bellman 在 1956 年提出的动态规划,到后来 Watkins 在 1989 年提出的的 Q-learning,再到 DeepMind 的 Nature-2015 稳定版,最后到 Dueling DQN、Priority Replay Memory、Parameter Noise 等优化算法,横跨整整一个甲子,凝聚了无数专家、教授们的心血。如今的我们站在先贤们的肩膀上,从以下角度逐步分析:

 

  • 贝尔曼(最优)方程与 VQ 树
  • Q-learning
  • 参数化逼近
  • DQN 算法框架

 

贝尔曼 (最优) 方程与VQ树

 

我们从经典的表格型强化学习(Tabular Reinforcement Learning)开始,回忆一下马尔可夫决策(MDP)过程,MDP 可由五元组 (S,A,P,R,γ) 表示,其中:

 

  • S 状态集合,维度为 1×|S|
  • A 动作集合,维度为 1×|A|
  • P 状态转移概率矩阵,经常写成

,其维度为 |S|×|A|×|S|

  • R 回报函数,如果依赖于状态值函数 V,维度为 1×|S|,如果依赖于状态-动作值函数 Q,则维度为 |S|×|A|
  • γ 折扣因子,用来计算带折扣的累计回报 G(t),维度为 1

 

S、A、R、γ 均不难理解,可能部分同学对

有疑问——既然 S 和 A 确定了,下一个状态 S' 不是也确定了吗?为什么会有概率转移矩阵呢?

 

其实我初学的时候也曾经被这个问题困扰过,不妨通过如下两个例子以示区别:

 

1.

恒等于 1.0 的情况。如图 1 所示,也就是上一次我们在策略梯度算法中所使用的迷宫,假设机器人处于左上角,这时候你命令机器人向右走,那么他转移到红框所示位置的概率就是 1.0,不会有任何异议:

 

 

 

 图1. 迷宫寻宝

 

2.

不等于 1.0 的情况。假设现在我们下一个飞行棋,如图 2 所示。有两种骰子,第一种是普通的正方体骰子,可以投出 1~6,第二种是正四面体的骰子,可以投出 1~4。现在飞机处于红框所示的位置,现在我们选择投掷第二种骰子这个动作,由于骰子本身具有均匀随机性,所以飞机转移到终点的概率仅仅是 0.25。这就说明,在某些环境中,给定 S、A 的情况下,转移到具体哪一个 S' 其实是不确定的:

 

 

 

 图2. 飞行棋

 

除了经典的五元组外,为了研究长期回报,还经常加入三个重要的元素,分别是:

 

  • 策略 π(a∣s),维度为 |S|×|A|
  • 状态值函数

,维度为 1×|S|,表示当智能体采用策略 π 时,累积回报在状态 s 处的期望值:

 

 

 图3. 状态值函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值