Mario Tennis AI
目次
はじめに
こんにちは。はんぺんです。
前々から強化学習の勉強をしておりまして、何か創りたいと日々思っておりました。
既存の強化学習に使われているプラットフォームを使わず、独自性のある学習対象の選定から行い、環境の構築から始めようというコンセプトのもと色々試行錯誤を繰り返していました。
そしてこの度マリオテニスGCの強化学習モデルを生成し、モデルがある程度のレベルに達したので記事にいたします。
手法
強化学習
まず今回の試みで用いた強化学習という技術について説明いたします。
強化学習は機械学習の手法の一つで、教師あり学習、教師なし学習と並んで、試行錯誤を通じて価値を最大化するような行動を学習するのが強化学習です。

強化学習は主に①環境の状態を観測②行動③報酬の3つのステップでなされます。

この3ステップをマリオテニスに落とし込んで考えてみます。
最初にエージェントがテニスの試合でゲームを取得すると報酬がもらえると決めます。
初期だとエージェントはランダムに行動しますが、学習が進むと環境から状態を観測した結果から行動を起こし、ゲームを取得する行動を選択するようになります。
このサイクルを正しく設計をすることは、強化学習モデルを生成する上では欠かせません。
Deep Q-network
モデル生成のアルゴリズムとしてDeep Q-network(以下DQN)を用いました。
DQNは2015年にDeepMind社によって発表された手法で、深層学習と強化学習(Q学習)を組み合わせたアルゴリズムです。
行動価値関数の近似にニューラルネットワークを用いて行動価値関数を学習させており、画像を状態としてインプットに使用することもできます。
学習の際に、逐次的にサンプル取得と学習を行うのではなく、今までの経験をもとにトレーニングを行う「experience replay」と呼ばれるアルゴリズムを用いており、これが学習速度の向上に大きく貢献しています。
マリオテニスGC
キャラクター

マリオテニスGCはNintendoから2004年に発売されたゲームで、ハードはゲームキューブです。キャラはデフォルトで14体、隠しキャラ4体の合計18体が使用可能です。
今回の試みではマリオVSルイージで、マリオの強化学習モデルを生成しました。マリオとルイージを選んだ理由は、双方ともにオールラウンドのプレースタイルであり、癖が少なく学習しやすそうだと考えたからです。ルイージのレベルは選択できる中で最もレベルの番低い”やや弱い”を選択しています。

ステージ

学習の途中で試合が終わった場合、試合終了フラグを検知していったん学習をやめて次の試合を移る必要があります。
そのフラグを取得するための処理をしており、ステージはPEACH DOMEに固定しています。
あらかじめ上部にあるPEACH DOMEと書かれている箇所の画像を取得しており、それを検知することで次の試合に移る準備をしています。
モデル説明
状態の観測

状態としてゲーム画面を取得しており、取得した画面をグレースケール→リサイズ→畳み込みで最終的に20×20のデータを入力として扱っています。
画面取得時に、スコアの確認、どちらがサーバーか、試合が終わっていないかの確認をしております。
並列処理でこれらを連携させて且つ学習に耐えうるパフォーマンスを出せるようにすることが実装において一番大変なところでした。
行動

移動は停止、右移動と左移動の3種類、ショットはトップスピンを打つ・打たないの2種類で合計6つ通りの行動としています。
実際の行動には上下もあり、ショットにはスライスもありますが、行動数が多いとそれだけ学習に時間がかかってしまうと考えられるので、今回は行動を以上の6つに制限しました。
実際に自分で左右とトップスピンのみでプレーしてみましたが、ある程度のレベルまでなら十分に勝てることは確認しています。
報酬

ゲームを取得すると+1, 落とすと-1として報酬を設定しました。
他にあった案として、自分のスコア – 相手のスコア = スコア差で報酬決めるということも考えました。
例えば画像の様に40 – 15の状態でポイントを取った場合、40→3、15→1として、3 – 1 = 2 となり報酬は2となります。
このようにスコアの差で報酬に傾斜をつけることも考えましたが、一旦clippingをして報酬は-1と+1のみで学習を進めることにしました。
スコアの読み取りはあらかじめ取得したスコアの画像と、観測した状態からスコアの個所を切り取ってテンプレートマッチングを行い、閾値を超える類似度が算出されるとスコアを返すという処理を行っています。
学習過程
試合の様子
実際の試合の様子です。
学習初期はほとんどランダムに近い動きをして、テニスをしているという感じではありません。
初セット取得時の3試合目の1セット目ではリターンでのポイントの取り方を覚え、ブレイクをすることに成功しています。
そして11試合目は2セットアップでタイブレイクにもつれ込み、サーブはキープしつつレシーブでブレイクを狙い、結果7-6, 6-4, 7-6で初勝利を収めることに成功しました。
それにしてもリターンゲームでのポイントの取り方が、デュースサイドで回り込み片手バックのダウンザラインでリターンエース狙うという戦法とは見ていて笑みがこぼれてきました。
報酬の推移

一試合5セット6ゲームマッチで、学習は合計19試合、総ゲーム数は730回で学習を行いました。
サーブ時とレシーブ時で分けて移動平均を取って報酬の推移を確認してみました。X軸がゲーム数で、Y軸が報酬です。
初期のランダムでの行動の結果でサーブ時にポイントを取ることが多く、結果としてモデルがサーブでのゲーム取得結果を過剰に学習してしまっているとも考えられます。
しかし、動画を見る限りサーブとレシーブである程度異なる挙動を見せており、サーブとレシーブの区別はついていますが、レシーブの方が学習をすることが難しく、まだ報酬が収束していないだけかもしれません。
ゲームの内訳

こちらが学習した合計730ゲームの内訳です。
レシーブゲームを落とすことが多く過半数を超えており、次点でサーブでのゲーム取得が多いです。
時折ゲーム終了のフラグを検知できず、スコアと報酬を記録できないということがあり、サーブとレシーブのゲーム数に差異があるのはそのためです。
課題と解決策
リターンゲーム取得率の低さ
最も大きな課題は、リターンゲームが取れないことだと認識しています。
確かに回り込み片手バックのダウンザラインでリターンエース狙うという戦法はかっこいいですし憧れますが、実世界のテニスと同様になかなか安定していません。
テニスは一般的にレシーブの方がサーブよりゲームが取りにくく、730ゲームでは安定してゲーム取得するには不十分だったのかもしれません。
もう少し学習回数を増やしてみて、それでもレシーブをうまく学習できないのであれば、サーブとレシーブでモデルの切り替えを行おうと思います。
行動の制限によるワンパターン戦法
学習をしやすくするために行動を6種類に制限していますが、やはり動きのバリエーションが乏しく、ワンパターンな動きをしてしまいがちです。
そこで、移動に関しては上移動と下移動、ショットに関してはスライスを追加してモデル生成していきたいです。
スコア読み取り精度の低さ
これは処理に関しての課題ですが、時折スコアを読み飛ばして報酬を反映できないことがあります。
特にサーブ時にスコアが出現する前にマリオがサーブを開始してしまったためにスコアを読み取れないということが後半になるとしばしば起きてきます。
これの解決策については、ポイント取得時にセンターに現れるスコアは必ず毎回出現するので、そちらを読み取ることで精度が上がる可能性があります。
もしくはスコアが格納されているメモリのアドレスを特定して、画像からではなく生データからスコア情報を読み取るという方法もありますが、これに関しては人間が参照できない情報にアクセスすることになり、今後人間と試合していくときに不平等性が出てくるので要検討です。
その他これからやること
現時点ではやっと環境構築ができて学習のサイクルを回すことができたという状況でして、まだまだ試してみたいことは山の様にあります。
- フレームを同期させて学習を行う
- 画像を複数枚スタックして入力にする
- 他の手法(Ape-x DQN、R2D2)を試す
- 他のキャラを試す
- 敵キャラのレベルを上げる
- ダブルスも試してみる
- 例えばボレーで点を決めると報酬を大きくするなどして様々なプレースタイルのモデルを創る
- 他のステージも試す
- 自キャラ、敵キャラ、ステージによらずある程度戦えるような汎用性の高いモデルを生成する
- トーナメントで優勝するまで強くする
- メモリからを抜き取った情報を入力として学習する
まとめ
いかがでしたでしょうか。
マリオテニスGCにおいて強化学習モデルの生成を行い、且つコンピュータに勝つまで成長させることができました。
強化学習は問題設定や報酬設定が難しく、且つ実装も大変なところが多かったですが、実際のアウトプットが動画で見られるので分析していても非常に面白かったです。
この点はテーブルデータの分析にはない魅力だと思いました。
そして実際に強化学習のモデルを学習するための環境の構築を行う上で、今まで中身を知らず何となく使っていたことがあまりにも多かったことに気づき、大変勉強になりました。
今後も強化学習を続けていこうと思います。
最後まで読んでいただき、ありがとうございました。
参考
Using Deep Q-Learning in FIFA 18 to perfect the art of free-kicks
pythonでマルチスレッドで処理して各スレッドの結果を受け取る
Pythonでテンプレートマッチング、OpenCVサンプルコードと解説
追記
記事を解説動画にしました。
内容は本記事とほとんど同じですが、作成者の嗜好がより濃く反映されています。
もしご興味を持っていただければ、見ていただけると嬉しいです。
[…] 【RL】マリオテニスGCの強化学習モデルを生成してみた【DQN】 […]