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

640


刚刚举行的 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 经验。个人研究方向——融合 CLRS 与 DRL 两大技术体系,并行刷题和模型训练。专注于游戏智能、少儿趣味编程两大领域。

 

模拟环境


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


640?wx_fmt=gif

 未经训练的小笨鸟


先简要分析一下环境 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 状态转移概率矩阵,经常写成640?wx_fmt=png,其维度为 |S|×|A|×|S| 

  • R 回报函数,如果依赖于状态值函数 V,维度为 1×|S|,如果依赖于状态-动作值函数 Q,则维度为 |S|×|A| 

  • γ 折扣因子,用来计算带折扣的累计回报 G(t),维度为 1 


S、A、R、γ 均不难理解,可能部分同学对640?wx_fmt=png有疑问——既然 S 和 A 确定了,下一个状态 S' 不是也确定了吗?为什么会有概率转移矩阵呢?


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


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


640?wx_fmt=png

 图1. 迷宫寻宝


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


640?wx_fmt=png

 图2. 飞行棋


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


  • 策略 π(a∣s),维度为 |S|×|A|

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

640?wx_fmt=png

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值