見出し画像

Behavior Cloningによるソニックの攻略

1. Behavior Cloningによるソニックの攻略

Stable Baselines入門 / Behavior Cloning」で「MountainCar-v0」を攻略したので、今回は「Behavior Cloning」によるソニックの攻略に挑戦します。

2. 人間のデモの記録

はじめに、人間のデモを記録するコードを作成します。
5エピソード分記録し、「sonic_traj.npz」と「recorded_images」を出力します。

画像1

画像2

◎sonic_wrapper.py
CustomRewardAndDoneEnvラッパーを作成し、完了条件をライフ1減った時(2になった時)とクリアした時(X座標が9600以上になった時)とします。
SonicDiscretizer2ラッパーを作成し、行動空間をMultiBinary(12)からDiscrete(7)に変換します。

import numpy as np
import gym

# CustomRewardAndDoneラッパー
class CustomRewardAndDoneEnv(gym.Wrapper):
   # ステップ
   def step(self, action):
       state, rew, done, info = self.env.step(action)

       # 完了条件のカスタマイズ
       if info['lives'] == 2 or info['x'] > 9600:
           done = True
       return state, rew, done, info

# SonicDiscretizerラッパー
class SonicDiscretizer(gym.ActionWrapper):
   # 初期化
   def __init__(self, env):
       super(SonicDiscretizer2, self).__init__(env)
       buttons = ["B", "A", "MODE", "START", "UP", "DOWN", "LEFT", "RIGHT", "C", "Y", "X", "Z"]
       actions = [[], ['LEFT'], ['RIGHT'], ['LEFT', 'B'], ['RIGHT', 'B'],
           ['DOWN'], ['B']]
       self._actions = []
       for action in actions:
           arr = np.array([False] * 12)
           for button in action:
               arr[buttons.index(button)] = True
           self._actions.append(arr)
       self.action_space = gym.spaces.Discrete(len(self._actions))

   # 行動の取得
   def action(self, a):
       return self._actions[a].copy()

◎create_traj.py
「FrameStackラッパー」や「ScaledFloatFrameラッパー」は、追加すると画像出力できないので、ひとまずなしとします。

import random
import pyglet
import retro
import time
from pyglet.window import key
from stable_baselines.gail import generate_expert_traj
from baselines.common.retro_wrappers import Downsample, Rgb2gray, FrameStack, ScaledFloatFrame, TimeLimit
from sonic_wrappers import *

# 環境の生成
env = retro.make(game='SonicTheHedgehog-Genesis', state='GreenHillZone.Act1')
env = SonicDiscretizer2(env) # 行動空間を離散空間に変換
env = Downsample(env, 2) # ダウンサンプリング
env = Rgb2gray(env) # グレースケール
env = TimeLimit(env, max_episode_steps=4500) # 5分タイムアウト
env = CustomRewardAndDoneEnv(env)
env.reset()
env.render()

# キーイベント用のウィンドウの生成
win = pyglet.window.Window(width=300, height=100, vsync=False)
key_handler = pyglet.window.key.KeyStateHandler()
win.push_handlers(key_handler)
pyglet.app.platform_event_loop.start()

# キー状態の取得
def get_key_state():
   key_state = set()
   win.dispatch_events()
   for key_code, pressed in key_handler.items():
       if pressed:
           key_state.add(key_code)
   return key_state

# キー入力待ち
while len(get_key_state()) == 0:
   time.sleep(1.0/30.0)

# デモの行動の指定
def dummy_expert(_obs):
   # キー状態の取得
   key_state = get_key_state()

   # キープレス→行動
   action = 0
   if key.X in key_state:
       if key.LEFT in key_state:
           action = 3
       elif key.LEFT in key_state:
           action = 4
       else:
           action = 6
   elif key.DOWN in key_state:
       action = 5
   elif key.LEFT in key_state:
       action = 1
   elif key.RIGHT in key_state:
       action = 2

   # スリープ
   time.sleep(1.0/120.0)

   # 環境の描画
   env.render()

   # 行動の選択
   return action

# デモの記録
generate_expert_traj(dummy_expert, 'sonic_traj', env, n_episodes=5)

3. BCによる事前学習

人間のデモ「sonic_traj.npz」を使ってモデルを学習します。

◎train.py

import gym
import retro
import time
from stable_baselines import PPO2
from stable_baselines.common.policies import CnnPolicy
from stable_baselines.common.vec_env import DummyVecEnv
from stable_baselines.gail import ExpertDataset, generate_expert_traj
from baselines.common.retro_wrappers import Downsample, Rgb2gray, FrameStack, ScaledFloatFrame, TimeLimit
from sonic_wrappers import *

# 環境の生成
env = retro.make(game='SonicTheHedgehog-Genesis', state='GreenHillZone.Act1')
env = SonicDiscretizer2(env) # 行動空間を離散空間に変換
env = Downsample(env, 2) # ダウンサンプリング
env = Rgb2gray(env) # グレースケール
env = TimeLimit(env, max_episode_steps=4500) # 5分タイムアウト
env = CustomRewardAndDoneEnv(env)

# ベクトル環境の生成
env = DummyVecEnv([lambda: env])

# デモの読み込み
dataset = ExpertDataset(expert_path='sonic_traj.npz', traj_limitation=10, verbose=1)

# モデルの生成
model = PPO2(CnnPolicy, env, verbose=1)

# モデルの事前訓練
model.pretrain(dataset, n_epochs=100)

# モデルの学習(今回は必要なし)
# model.learn(total_timesteps=1000)

# モデルの保存
model.save('sonic')

# モデルのテスト
state = env.reset()
while True:
   time.sleep(1.0/120.0)
   env.render()
   action, _ = model.predict(state)
   state, reward, done, info = env.step(action)
   if done:
       env.reset()


この記事が気に入ったらサポートをしてみませんか?