オッサンはDesktopが好き

自作PCや機械学習、自転車のことを脈絡無く書きます

tensorflow + kerasで強化学習してみる

 こんにちは.changです.

 今回は強化学習をやってみます. ディープ・ラーニングにも少し飽きてきたので...(笑).

 作ったのはよくあるインベーダー的なやつです. やってみると意外と大変でした(汗). kerasの環境が整っていなくて,tensorflow単独に先祖返りする感じです.

0. 今回の目的

 冒頭にも触れたように,ディープ・ラーニングにも大分飽きて底が見えてきました. 原理的な探求には区切りをつけ,実用性を重視したアプリケーション開発に移行するタイミングだと思っています. 本来はここからが仕事(=営利活動)なのですが,こればかりをやっていると直ぐに時代遅れになってしまいます. 次の素材に手を出し始めようと考えました. で,AIつながりで浅はかですが,強化学習をやってみます.

 情報の少ないアルゴリズムを動かすときに大切なのが,ベースとなり,かつ整然と書かれたサンプルを持つことだと考えています. ディープ・ラーニングではmnist*1とU-Net*2がそれでした. 僕の書くソースのほとんどはこの2つのソースの派生になっています. 単に裾野が狭いとも言える...(汗).

 ベースが出来てしまうと,そこからの派生や応用は案外簡単にできるものです. また,立ち返る原点が定まっていれば,迷っても初めからやり直しできます. 「やり直し」を「出戻り」と読んで避難するヒトもいますが,,,同じ条件でもう一度やり直せば,必ず一度目よりも速く,賢くゴールに辿り着く筈です.

 今回の目的は,このベースを強化学習について構築することです.

1. 強化学習

 あちこちで紹介されているので,詳しい説明は省きます. というより,僕自身が勉強不足で詳しい説明が出来ません(笑).

 イメージだけで話しますが,強化学習は所謂「教師無し学習」です. Alpha GOがプロ棋士を負かしたという話はあまりにも有名ですが,Alpha GOの凄いところはヒトの対戦を真似るのではなく,自身で対局を繰り返して勝手に強くなることです.

 少し前に,藤井聡太君が50万円の自作PCで将棋ソフトを使っているという記事が話題になりました. 将棋ソフトについて,彼が「予想のしない手を打ってくる」と発言していた記憶があります(羽生さんだったかも). これは,ヒト(=教師)の模倣ではない強化学習ならでは特徴だと言えます.

 ヒトが発想出来なかったアイデア創発することが,僕が強化学習に期待することです.

2. keras

 一年位前からkerasを使い始めました. 「モデルを書くのが楽」という声をよく聞きますが,最大の恩恵はデバッグのしやすさです. tensorflow単独でのプログラミングはPlaceholderの中身を追えない為,非常に厄介です. kerasを使うと,C言語的というか,ひとつながりのデータの流の中で自分の書いたソースを追いかけることが出来ます. 強化学習でも,このメリットを生かしたいと考えました.

3. プログラム

(1) 参考にしたソース

 いくつかの簡易版がシンプルに動作しますが,tensorflow単独で書かれていました. この方*3はkerasを使われていますが,ご本人もおっしゃっているようにkerasを使うことによって逆にソースが煩雑になっています. この方*4のソースは,モデルの記述にのみkerasを使っています. また,簡易版ではしばしば省略されているtarget network等も丁寧に書かれていて,発展性が高いと思いました. ただ,表示部が無い(公開されていない?)のです. 理想を満たすサンプルはなかなか見つかりません...(>.<). 結局,これらのソースを自分で統合することにしました.

(2) ルール

 参考にしたソースそのままです.

  • 爆弾(?)をキャッチしたら報酬1
  • 爆弾を落としたら報酬-1 & ゲーム終了
  • 右に動く,左に動く,動かないの3パターンの中からアクションを選択
  • フィールドは8 × 8または16 × 16から選んで設定

(3) ネットワーク

 シンプルな全結合版と,少し複雑な畳み込み版の2パターンを書きました.

シンプルな全結合版

def build_model(input_shape, nb_output):
    model = Sequential()
    inputs = tf.placeholder(dtype=tf.float32, shape=[None,input_shape[0]*input_shape[1]], name="input")
    model.add(InputLayer(input_shape=(input_shape[0]*input_shape[1],)))
    model.add(Dense(64, activation="relu"))
    model.add(Dense(nb_output))
    outputs = model(inputs)
    return inputs, outputs, model

少し複雑な畳み込み版

def build_model_cnn(input_shape, nb_output):
    model = Sequential()
    inputs = tf.placeholder(dtype=tf.float32, shape=[None,input_shape[0]*input_shape[1]], name="input")
    model.add(InputLayer(input_shape=(input_shape[0], input_shape[1], 1)))
    model.add(Convolution2D(16, 4, 4, border_mode='same', activation='relu', subsample=(2, 2)))
    model.add(Convolution2D(32, 2, 2, border_mode='same', activation='relu', subsample=(1, 1)))
    model.add(Convolution2D(32, 2, 2, border_mode='same', activation='relu', subsample=(1, 1)))
    model.add(Flatten())
    model.add(Dense(128, activation='relu'))
    model.add(Dense(nb_output, activation='linear'))
    outputs = model(tf.reshape(inputs, shape=[-1, input_shape[0], input_shape[1], 1]))
    return inputs, outputs, model

(4) 最適化関数

 最適化には,tensorflow標準のRMSPropを使いました. ここ*5で紹介されているのように,論文発表者の改変版を使のがベターの様です.

optimizer = tf.train.RMSPropOptimizer(learning_rate=self.learning_rate)

4. 学習結果

(1) 8×8フィールド

 2000スペック&全結合版でもそこそこの学習効果がありました.

f:id:changlikesdesktop:20201218052206g:plain:w400
8 × 8, 全結合版での学習結果

f:id:changlikesdesktop:20201218052747p:plain:w400
縦軸: 1ゲームで得られた報酬.横軸: エポック数

 ネットワークを畳み込み版に変えると,更に良くなります.

f:id:changlikesdesktop:20201218054054g:plain:w400
8 × 8, 畳み込み版での学習結果

f:id:changlikesdesktop:20201218054134p:plain:w400
縦軸: 1ゲームで得られた報酬.横軸: エポック数

(2) 16×16フィールド

 2000スペック & 全結合版では,爆弾をほとんどキャッチしませんでした.

f:id:changlikesdesktop:20201218055527g:plain:w400
16×16, 全結合版での学習結果

f:id:changlikesdesktop:20201218055629p:plain:w400
縦軸: 1ゲームで得られた報酬.横軸: エポック数

 2000スペック & 畳み込み版でそれなりな動きになりました. 未だ未だ,工夫が必要な感じがしますね.

f:id:changlikesdesktop:20201216145405g:plain:w400
16×16, 畳み込み版での学習結果

f:id:changlikesdesktop:20201218055735p:plain:w400
縦軸: 1ゲームで得られた報酬.横軸: エポック数

5. 結び

 新しい素材に触れるのは楽しいですね.

 今回残念だったのが,kerasのメリットをほとんど活かせ無かった事です. モデルの記述にはkerasを使いましたが,ネットワークへの入力にはPlaceholderを使いました(使わざるを得ませんでした). これでは,tensorflow単独でのプログラミングとほぼ変わりません. 新しいkerasやtensorflow ver. 2では改善されているのかも...?

 今回のソースが,強化学習を作っていく上でのベースとして機能するか未だ判りませんが,取り敢えずの起点は作れたと思います. 自分なりの工夫を加えて遊んでみるつもりです.

 今回書いたソースはここ*6です.