This post is Private. Only a writer or those who know its URL can access this post.

ゲームの強化学習ハンズオン -- OpenAI Gymで強化学習入門 その2(機械学習名古屋第16回勉強会)

More than 1 year has passed since last update.

初めに


おさらい:強化学習とは


reinforcement_2.png


強化学習とは

  • 変化する 環境 下で判断・ 行動 し課題を解決する問題を扱う
  • (一連の)行動に対して得られる 報酬 を元に、ある 状態 における 次の行動学習 して獲得していく

事例:自動運転


Duckietown_self_driving_car_simulator_environments_for_OpenAI_Gym_by_hardmaru.png


事例:ゲーム

vlcsnap-2018-04-16-22h38m05s417.png


基礎概念

  • 状態:S(Observation の略で obs とすることも)
  • モデル:TT(s,a,s')
  • 行動:AA(s)
  • 報酬:RR(s)/R(s,a)/R(s,a,s')

おさらい:OpenAI Gym


OpenAI Gym

  • OpenAI Gym
  • 強化学習用ツールキット。統一インターフェースを提供
  • いくつかのシミュレーション環境(ゲーム等)を用意

OpenAI Gym の 環境 (Env)

env = gym.make(env_name)  # 環境構築(読込)
env.reset()               # 初期化 状態を取得
env.render()              # 可視化
env.step(action)          # 行動を行う 状態・報酬などを取得
env.close()               # 終了

大事なのは↓の2つ

  • 環境から状態(Sobs)を取得
  • 環境に対して行動(step) → 結果の状態(obs)と報酬(R)を返す

OpenAI Gym で強化学習

  • モデル T を構築
  • 行動 A を選択
  • Gym の環境に対して 行動 A を送り、状態 S や 報酬 R を受け取って、モデル T を学習

ハンズオン


ハンズオン環境

  • Python 3.5以上(3.6以上推奨)
  • OpenAI Gym(CartPole-v0 環境)
  • ChainerRL

ハンズオン環境補足

  • Linux / macOS:基本的に OpenAI Gym の README の手順通りに環境を作成できていればOK
  • Windows:以下のいずれかの方法
    • VirtualBox 等の仮想環境上に Linux 環境を構築
    • WSL(+ Linux) + XServer 環境を構築(補足資料
    • Docker(制限あり)

ハンズオン0:準備

  • OpenAI Gym 等の準備は省略(別資料等参照ください)
  • 今回も 勉強会用 Git リポジトリ を用意しています(↓適当なディレクトリで以下のコマンドを実行して clone してください)
$ git clone https://github.com/mlnagoya/MLN_201806

動作確認。

python -V の実行結果が Python 3.x.x と表示されるなら(その環境下に OpenAI Gym をインストールしていれば)以下の python3python と読み替えてください。

$ python3 handson_dqn.py --train-episodes=20 --outdir=_output20

エラーが起きたら後述の「トラブルシューティング」参照


ハンズオン1:パラメータ調整

$ python3 handson_dqn.py -h
usage: handson_dqn.py [-h] [--outdir OUTDIR] [--gamma GAMMA]
                      [--final-exploration-steps FINAL_EXPLORATION_STEPS]
                      [--start-epsilon START_EPSILON]
                      [--end-epsilon END_EPSILON]
                      [--replay-buffer REPLAY_BUFFER]
                      [--replay-start-size REPLAY_START_SIZE]
                      [--target-update-interval TARGET_UPDATE_INTERVAL]
                      [--update-interval UPDATE_INTERVAL]
                      [--train-episodes TRAIN_EPISODES]
                      [--max-episode-len MAX_EPISODE_LEN]
                      [--test-episodes TEST_EPISODES]

optional arguments:
  -h, --help            show this help message and exit
  --outdir OUTDIR       出力ファイル保存先ディレクトリ。 存在しなければ自動生成されます。 (default: _output)
  --gamma GAMMA         割引率 (default: 0.95)
  --final-exploration-steps FINAL_EXPLORATION_STEPS
                        探索ステップ数 (default: 10000)
  --start-epsilon START_EPSILON
                        ε-greedy法 の開始ε値 (default: 1.0)
  --end-epsilon END_EPSILON
                        ε-greedy法 の終了ε値 (default: 0.1)
  --replay-buffer REPLAY_BUFFER
                        Experience Replay のバッファサイズ (default: 1000000)
  --replay-start-size REPLAY_START_SIZE
                        replay-start-size (default: 500)
  --target-update-interval TARGET_UPDATE_INTERVAL
                        target-update-interval (default: 100)
  --update-interval UPDATE_INTERVAL
                        update-interval (default: 1)
  --train-episodes TRAIN_EPISODES
                        訓練エピソード数 (default: 200)
  --max-episode-len MAX_EPISODE_LEN
                        1回のエピソードの最大ステップ数 (default: 2000)
  --test-episodes TEST_EPISODES
                        検証エピソード数 (default: 10)

コマンドライン引数で各種パラメータを弄ってみる。

例:

  • --gamma=0.99(割引率)
  • --train-episodes=500(訓練エピソード数)

ハンズオン2:実装修正

  • handson_dqn.py(本体)
  • util
    • qfunctions.py(Q関数)
    • explorers.py(戦略)
    • replay_buffer.py(リプレイバッファ)

qfunctions.py(抜粋)

qfunctions.py(抜粋)
# :

class MyQFunction(chainer.Chain):
    """
    Q^*をDNNを使って近似する(別実装)
    """
    def __init__(self, obs_size, n_actions):
        # TODO: 必要なら引数を追加して、QFunction3LP の実装を参考にネットワークを構築する
        raise NotImplementedError

    def __call__(self, obs, test=False):
        # TODO: QFunction3LP の実装を参考にネットワーク適用を実装する
        raise NotImplementedError
  • 自分で実装してみる!

explorers.py(抜粋)

explorers.py(抜粋)
# :

class ConstantEpsilonGreedy(explorer.Explorer):
    """ε-greedy 法(ε固定)"""

    def __init__(self, epsilon, random_action_func):
        assert epsilon >= 0 and epsilon <= 1
        self.epsilon = epsilon
        self.random_action_func = random_action_func

    def select_action(self, t, greedy_action_func, action_value=None):
        return select_action_epsilon_greedily(
            self.epsilon, self.random_action_func, greedy_action_func)

    def __repr__(self):
        return 'ConstantEpsilonGreedy(epsilon={})'.format(self.epsilon)
  • 実装を弄ってみる!

replay_buffer.py(抜粋)

replay_buffer.py(抜粋)
# :

class BestReplayBuffer(SimpleReplayBuffer):
    """報酬の高いものを優先的に記憶する ReplayBuffer"""

    def __init__(self, capacity=1000):
        super().__init__(capacity)

    # TODO: より報酬の高いものを優先的に残すような実装をする
    # def append(self, state, action, reward, next_state=None, next_action=None, is_state_terminal=False):
    #     pass
  • 自分で実装してみる!

handson_dqn.py(抜粋)

from util.qfunctions import QFunction3LP as QFunction
# from util.qfunctions import MyQFunction as QFunction
# ↑ココ

# : 《中略》

def get_agent(env, args):
    # : 《中略》

    # Use epsilon-greedy for exploration
    # explorer = ConstantEpsilonGreedy(
    #     epsilon=args.start_epsilon,
    #     random_action_func=env.action_space.sample)
    explorer = LinearDecayEpsilonGreedy(
        args.start_epsilon, args.end_epsilon, args.final_exploration_steps,
        random_action_func=action_space.sample)
    # ↑ココ

    # Experience Replayの設定
    replay_buffer = SimpleReplayBuffer(capacity=args.replay_buffer)
    # replay_buffer = BestReplayBuffer(capacity=args.replay_buffer)
    # ↑ココ

# : 《後略》

  • 実装変更を反映して、学習させてみる!

ハンズオン(その後)

  • ChainerRL に用意されている他のアルゴリズム・手法等も試してみる
  • OpenAI Gym の他の環境でも試してみる
  • Gym に登録されていない環境(例:自動運転シミュレータとか)も試してみる

補足


Q関数(おさらい)

  • $Q^*(s,a)$:状態$s$で行動$a$をとったときの割引累積報酬の最大値
  • Q学習:このQ関数を機械学習で学習(≒モデルを学習)
  • DQN:Q関数をDNNで近似(して学習)

ε-greedy 法

  • 行動選択戦略:
    • $0.0 \le \varepsilon \le 1.0$
    • $\varepsilon$ の確率で行動をランダムに選択
    • $1-\varepsilon$ の確率で Q値 が最大となる(過去の)行動を選択
  • $\varepsilon$ を固定化(例:$\varepsilon=0.3$)するも良し、減衰(例:初期値$\varepsilon=1.0$、10000ステップ後に$\varepsilon=0.1$、線形に変化)するも良し
    • ConstantEpsilonGreedy/LinearDecayEpsilonGreedy

Experience Replay(経験再生)

  • データごとの相関をなくすための手法:
    • 過去の経験(≒「状態」「行動」「報酬」(など)の組合せ)を記憶しておく
    • その中からランダムに選択して学習に利用する
  • SimpleReplayBuffer:過去の経験を出来るだけ多く記憶、制限を超えたら古いものから忘却、記憶している「経験」を乱択
  • 少し賢く:
    • BestReplayBuffer:成績の良い経験を優先的に記憶、経験の乱択を従来通り
    • PrioritizedReplayBuffer:成績で優先順位を付けておき、乱択時に優先順位の高いものが高確率で選択されるようにする

トラブルシューティング


学習・テストの様子がGUIで表示されない

  • Docker 利用の場合:仕様です
  • Windows + WSL 利用時:
    • エラーが出ている:XServer との連携設定がうまくいってない可能性が高いです。DISPLAY 環境変数の値を見直してみましょう
    • 固まっている:Python と OpenGL との相性問題かも。XServer 起動時に「ネイティブの OpenGL(WinGL)を利用しない」設定にして再度試してみてください
  • Linux / macOS の場合:Python / OpenAI Gym / その他依存ライブラリの再インストールが必要かも…

学習はうまくいくがテスト開始時にエラーで落ちる

  • gym.wrappers.Monitor を利用して動画保存するために必要な ffmpeg がたぶんインストールされていません。
    • Linux(Ubuntu)の場合:sudo apt install ffmpeg(他のディストリビューションでも同様)(バージョンによっては sudo add-apt-repository ppa:〜 が必要、詳細はググってくださいm(_ _)m)
    • macOSの場合:brew install ffmpeg
    • もし Anaconda を利用していたら:conda install ffmpeg
  • ffmpeg 入ってるのにうまくいかない:ffmpeg へのパスが通っているか確認しましょう
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.