本文共 2819 字,大约阅读时间需要 9 分钟。
DQN算法可以用于解决离散的动作问题,而FlappyBird的操作正好是离散的。
FlappyBird的游戏状态一般可以通过图像加卷积神经网络(CNN)来进行强化学习。但是通过图像分析会比较麻烦,因为每次只输入一帧图像可能是不够的,因为一帧的图像分析不出小鸟的速度信息,所以通常需要几帧图像一起送入CNN分析。这样的方法麻烦又复杂,仔细观察一下游戏。
发现有三个信息对于小鸟能够顺利飞过水管比较重要:
- 小鸟的水平速度。
- 小鸟与它前面一对水管中下面那根水管的水平距离。
- 小鸟与它前面一对水管中下面那根水管的顶端的垂直距离。
而其他的信息,比如:已经飞过了的水管等信息就不重要了。
好了,思路已经有了,开始准备环境。
一、安装FlappyBird
ntasfi/PyGame-Learning-Environmentgithub.com提供了一个FlappyBird游戏的实现,按照着文档中Installation部分的提示安装就可以了。安装完了后还不能直接使用,原因如下:
- 需要根据游戏的状态提取上面提到的那三个重要的状态信息。
- 封装成和gym环境类似的接口,使用起来也方便一下。
封装好后的核心代码及注释如下:
def _get_obs(self): # 获取游戏的状态 state = self.game.getGameState() # 小鸟与它前面一对水管中下面那根水管的水平距离 dist_to_pipe_horz = state["next_pipe_dist_to_player"] # 小鸟与它前面一对水管中下面那根水管的顶端的垂直距离 dist_to_pipe_bottom = state["player_y"] - state["next_pipe_top_y"] # 获取小鸟的水平速度 velocity = state['player_vel'] # 将这些信息封装成一个数据返回 return np.array([dist_to_pipe_horz, dist_to_pipe_bottom, velocity])
完整FlappyBird状态获取封装的代码在:
flappybird_wrapper.pygithub.com二、实现DQN算法
因为最终实现的代码比较长,这里只贴算法实现中最核心的learn代码及注释:
def learn(self, writer): # 根据经验进行学习 # 确保经验池里的经验以及足够多时,才进行学习 assert WARMUP_SIZE >= BATCH_SIZE if len(self.memory) < WARMUP_SIZE: return # 从经验池中选取BATCH_SIZE条经验出来 batch = random.sample(self.memory, BATCH_SIZE) batch = Transition(*(zip(*batch))) # 把这些经验都转换位Tensor s0 = torch.FloatTensor(batch.state).to(device) a0 = torch.LongTensor(batch.action).to(device).unsqueeze(1) r1 = torch.FloatTensor(batch.reward).to(device) s1 = torch.FloatTensor(batch.next_state).to(device) d1 = torch.LongTensor(batch.done).to(device) # DQN算法 q_pred = self.model(s0).gather(1, a0).squeeze() with torch.no_grad(): if USE_DBQN: acts = self.model(s1).max(1)[1].unsqueeze(1) q_target = self.target_model(s1).gather(1, acts).squeeze(1) else: q_target = self.target_model(s1).max(1)[0] q_target = r1 + GAMMA * (1 - d1) * q_target loss = self.loss_func(q_pred, q_target) self.optimizer.zero_grad() loss.backward() self.optimizer.step() # 记录每次学习的loss writer.add_scalar('train/value_loss', loss.item(), self.update_count) self.update_count += 1 # 每MODEL_SYNC_COUNT同步一下目标模型 if self.update_count % MODEL_SYNC_COUNT == 0: self.target_model.load_state_dict(self.model.state_dict())
在这段代码中,可以通过设置变量USE_DBQN为true和false来控制是否使用DQN的变种算法Double-Q Learning来训练模型。同时,代码还借助tensorboard来记录在训练过程中:完成步骤数(finish_step)、每局获得奖励的总数(total_reward)以及每次学习时loss的值(value_loss)来观察训练的过程。
从tensorboard的截图中可以看出,随着训练的进行,每局游戏结束时的步骤数(finish_step)越来越多,表明算法在正确的进行训练和提高。
最后,所有的代码都可以在github中查看(包括tensorboard的记录数据):
dqn_flappybirdgithub.com转载地址:https://blog.csdn.net/weixin_34214135/article/details/113067587 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!