機械学習周りのプログラミング中心。 イベント情報
ポケモンバトルAI本電子書籍通販中

【ポケモンバトルAI本】技術書典10/エアコミケ2 頒布予定【第3巻無料/物理本あり】

技術書典10は2020年12月26日から2021年1月6日まで開催される技術系同人誌の頒布イベントです。新型コロナウイルスの影響によりオンライン開催ですので、お祭り感のある通販のようなものとお考え下さい。 同時に、エアコミケ2にも出展します。こちらはWebカタログに掲載されるだけで、実際の頒布はBOOTHで行われます。

当サークル「ヤマブキ計算所」は技術書典10およびエアコミケ2へ出展いたします。ポケモンバトルAI本の既刊(第1巻~第4巻)を頒布します。 ポケモンバトルのルールだけから機械学習を中心とした人工知能技術により強い戦略を作り出すことをテーマとし、開発したアルゴリズムやその実験結果を掲載する本です。

技術書典10では、第1巻~第3巻の紙の本も頒布を予定しています。これは会期中のみ購入が可能です。

基本的にブログで掲載した内容と多少の書き下ろしですが、本1冊として一貫するように加筆修正しておりますので読みやすくなっていますし、過去の巻を読まなくてもわかるよう必要な情報を再掲しています。

頒布場所はこちらです。

techbookfest.org

価格について

巻数 電子版(PDF) 紙の本
#1 0 700
#2 0 700
#3 0 700
#4 500 設定なし

第3巻は刊行から1年経過し、無料化しました。正確には2020年12月31日に無料化予定でしたが、会期途中の価格変更は混乱を招くため2020年12月24日付で無料化します。第4巻についてはコロナ禍でまだ紙の本を一度も印刷できていない状況のため、無料化は刊行から3年後に設定しております。第5巻を出すときに合体して印刷する方針ですが、見通しは立っていません。

技術書典10には当サークルのような読み物だけでなく、仕事に使える実用書も多数出ていますので、ぜひ見に行ってみてください。

techbookfest.org

ゲーム木探索入門 part03 実験用パーティの選定【PokéAI】

前回に続き、ゲーム木探索の下準備をします。

従来行っていたような、ランダムに生成したパーティ1000個を戦わせるような実験が計算コスト上できない見通しです。ランダムなパーティ同士の対戦だと、ポケモンや技自体の強さが大きく離れている場合が多く、パーティ同士の組み合わせにより勝敗の大部分が決まってしまうため、行動選択のアルゴリズムの評価がしづらくなります。過去の実験で、強化学習したエージェントとランダムに行動するエージェントそれぞれにランダムなパーティを割り当てて対戦させると、強化学習側の勝率は7~8割となっていました。乱数による要因もありますが、プレイヤーとしての経験上もパーティ自体の良し悪しがバトルに与える要因が大きいことは間違いないでしょう。 そのため、行動選択のアルゴリズムを正しく評価するため、パーティ間の強さに大きな差がないこと、ランダムに行動を選ぶ場合と比べてちゃんと思考することで強さが向上するようなパーティを手動で選定することにしました。

実験用パーティの選定

パーティ間の強さをそろえるには、トップレベルのプレイヤーが採用しているパーティを選べばよいと考えられます。ポケモンバトルは対人戦が盛んであり、その中で洗練されたパーティの間では強さに大きな開きはないと考えられます。 プロジェクト全体の趣旨としてはパーティも自動で生成したいですが、バトル中の思考部分の強化に集中するため人間の知識を一時的に投入することを許容することとします。

まずパーティの候補として考えたのは任天堂による公式大会「ニンテンドウカップ2000」または「モバイルカップ2001」で代表選手が使用していたものです。しかしながらこれらの大会で使われたパーティの情報は、少なくともWeb上では見つけられませんでした。一部の試合のテレビ放送と思われる動画は見つかるものの、網羅的な情報とは言い難い状況です。

次に、ポケモン金銀のルールで対戦を楽しめる据え置き型ゲーム「ポケモンスタジアム金銀」のモードとして存在するニンテンドウカップに登場する敵プレイヤーのパーティが使えないか検討しました。しかしながら全ポケモンに「メロメロ」を覚えさせているパーティなど、そのパーティを用いるゲーム内のキャラクターのイメージに沿った構築がなされているようで強さのバランスが取れているとは言い難い内容でした。

上記のように公式情報からパーティを選定するのは難しいと判断したため、ファンサイトからパーティ構築を選定することとしました。 ここでは、ポケモン金銀バーチャルコンソール)の大会を開催されているゴールド氏の提示した構築例を用いることにします。ダメージ計算ツール等が普及した現代の環境で十分練られた構築であると考えられ、提示されているパーティ間に強さに大きな差はないと考えられます。また、様々な補助技も含まれておりこれらをうまく運用することが前提となっているため、行動選択の良し悪しが勝敗に大きく影響すると考えられます。

gold.hatenadiary.jp

11個の構築例が示されているため、そのうち先頭から10個を利用することとします。また、6匹*1から3匹を選出するルールを想定して記述されていますが、選出の機構は実装しないため、私が3匹を選んで固定することとします。必ずしも上から3匹ではなく、様々なポケモンが含まれるようにばらつきを加えています。以上の方法で構築したパーティを示します。当面はこれらのパーティを用いてアルゴリズムの評価を行います。

パーティ0
カビゴン  55 すてみタックル じわれ     のろい     ねむる    
ガラガラ  50 じしん     いわなだれ   だいもんじ   こごえるかぜ 
サンダー  50 10まんボルト めざパこおり  でんじは    ねむる    
------------
パーティ1
ケンタロス 55 つのドリル   すてみタックル じしん     みがわり   
パルシェン 50 れいとうビーム なみのり    こごえるかぜ  だいばくはつ 
ナッシー  50 サイコキネシス やどりぎのタネ ねむりごな   だいばくはつ 
------------
パーティ2
ラプラス  55 れいとうビーム つのドリル   メロメロ    みがわり   
カビゴン  50 のしかかり   ばくれつパンチ ねごと     ねむる    
ナッシー  50 サイコキネシス やどりぎのタネ ねむりごな   だいばくはつ 
------------
パーティ3
ミルタンク 55 おんがえし   ばくれつパンチ のろい     ミルクのみ  
ナッシー  50 サイコキネシス めざパむし   ねむりごな   だいばくはつ 
ゴローニャ 50 じしん     だいもんじ   ほえる     だいばくはつ 
------------
パーティ4
スイクン  50 なみのり    ふぶき     ねごと     ねむる    
エアームド 50 ドリルくちばし どくどく    のろい     ねむる    
ライコウ  55 かみなり    めざパこおり  ねごと     ねむる    
------------
パーティ5
バンギラス 55 かみくだく   ばくれつパンチ だいもんじ   すなあらし  
ハピナス  50 ちきゅうなげ  れいとうビーム でんじは    タマゴうみ  
エアームド 50 ドリルくちばし ふきとばし   のろい     ねむる    
------------
パーティ6
ブラッキー 50 でんじほう   おいうち    あまえる    ねむる    
カビゴン  55 おんがえし   はらだいこ   みがわり    まもる    
ワタッコ  50 めざパひこう  やどりぎのタネ アンコール   ねむりごな  
------------
パーティ7
ミルタンク 52 かげぶんしん  まるくなる   ころがる    ミルクのみ  
ガラガラ  52 じしん     いわなだれ   だいもんじ   こごえるかぜ 
カイリキー 51 クロスチョップ いわなだれ   めざパむし   じわれ    
------------
パーティ8
ファイヤー 55 だいもんじ   めざパくさ   にほんばれ   ねごと    
サンダース 50 10まんボルト でんじは    リフレクター  ねむる    
ヘラクロス 50 メガホーン   めざパかくとう こらえる    きしかいせい 
------------
パーティ9
フーディン 55 サイコキネシス れいとうパンチ アンコール   じこさいせい 
ヘラクロス 50 メガホーン   じしん     ねごと     ねむる    
サイドン  50 じしん     いわなだれ   カウンター   のろい    
------------

ランダム行動での強さ比較

アルゴリズムを開発する前に、ランダムに行動を選択した場合でパーティごとの強さにどの程度差異があるかを確認します。

ランダム行動において、交代を選択する確率は10%としました。1パーティ当たりのバトル回数を{10, 100, 1000}に変えて、各2回試行することにより、レーティングバトル(イロレーティング)の実施方法によりどの程度ばらつくかについても確認します。

f:id:select766:20201210213533p:plain
各パーティのレート

上図に各パーティのレートを示します。横軸のパーティの番号は、前の章のパーティリスト上の番号に対応します。レートは概ね1300~1700の間に収まっています。過去の実験で極めて弱いパーティはレート1000以下という場合もあったため、パーティ間の強さに比較的バランスがとれているといえますが、強さが同じであるという仮定は置くべきではないと考えられます。平均的に一番強いのはパーティ0、一番弱いのはパーティ3のようです。バトル1000回(試行1)のときのレートは1651と1352で、レート差299はパーティ0の勝率が85%であることを示します。試行ごとに同じパーティでもレートにばらつきが無視できない幅で(強さの大小関係が変化する大きさで)変化しています。バトル回数が100回から1000回に増えても収束が良くなるというわけではありません。この要因について、以下に示すレーティングバトルの具体的なコードに即して検討します。

function ratingBattle(players: Player[], matchCount: number): number[] {
    // 全プレイヤーのレートを1500に初期化
    const rates: number[] = (new Array(players.length)).fill(1500);

    for (let i = 0; i < matchCount; i++) {
        const ratesWithRandom = rates.map((r) => r + rnorm() * 200); // rnormは正規乱数。
        const ranking = argsort(ratesWithRandom); // (現在のレート+正規乱数)をソートし、隣接するパーティ同士を対戦させる
        for (let j = 0; j < players.length; j += 2) {
            const left = ranking[j];
            const right = ranking[j + 1];
            const sim = Sim.fromParty([players[left].party, players[right].party]);
            // players[left]とplayers[right]が1回バトルを行う
            const { winner } = playout(sim, [players[left].agent, players[right].agent]);
            // winner: players[left]が勝利したら'p1'、players[right]が勝利したら'p2'
            if (winner) {
                // レート差からleftの期待勝率を求める
                const left_winrate = 1.0 / (1.0 + 10.0 ** ((rates[right] - rates[left]) / 400.0));
                let left_incr;
                if (winner === 'p1') {
                    left_incr = 32 * (1.0 - left_winrate);
                } else {
                    left_incr = 32 * (-left_winrate);
                }
                rates[left] += left_incr;
                rates[right] -= left_incr;
            }
        }
    }

    return rates;
}

基本的な考え方は、レートの近いパーティ同士を対戦させ、その結果に応じてレートを変動させるというものです。対戦結果に応じてレートを変動させる部分で、勝ったプレイヤーのレートは上昇し、負けたプレイヤーのレートは下降します。ここで、期待勝率と実際の結果の違いが大きいほど、大きくレートが変動するようになっています。コードからわかるように、期待勝率0%のプレイヤーが勝利した場合にレートが最も大きく変動し、その変化量は32に固定されています。プレイヤーがランダムに行動するため、補助技を連打し続けるなどのミスによりレート差にかかわらず弱い側が勝つことは頻繁に発生すると考えられます。その場合に今までのバトル数にかかわらずレートが一気に32変動するため、バトルを1000回行っても最後の数回の勝敗に大きく影響されてしまい、試行によって結果にばらつきが生じていると考えられます。バトル1回あたりの変動の大きさを減衰させるようなパラメータを導入すべきかもしれません。ただしばらくは、パーティ数を10しか用いず強さの幅も小さいため、ここで示したアルゴリズムでレートを逐次的に収束させるのではなく、総当たり戦を行ったうえですべての勝敗にもっともよくあてはまるレートを算出してもよいのではないかと考えています。参考サイトでは、最尤法による計算について考察がなされています。 最尤法によるレート推定と不確かさ : コンピュータ将棋基礎情報研究所

今回は、強さにばらつきが小さく行動選択の良し悪しが勝敗に影響するようなパーティの選定と、ランダムに行動させた場合の強さの評価結果を示しました。よりよい強さの評価手段は将来検討するとして、次はゲーム木探索を実装したいと思います。

*1:私はポケモンを数える単位に「匹」を使うことが多いのですが、テレビアニメだと「体」が使われているのでそちらに統一したほうがいいかもしれません。

ゲーム木探索入門 part02 シミュレータのパフォーマンス測定【PokéAI】

今回は、ゲーム木探索の下準備をします。実務上の泥臭い話で、AI的な話は出てこないので適当に読み飛ばしてください。

現在ゲーム木探索のもっとも単純な手法として、原始モンテカルロ法(次回以降に説明)の実装を進めています。処理が非常に重いため実験コストの見積もりと有意義な実験条件の設定を考える必要が生じました。今回は実験コストの見積もりについてです。次回、有意義な実験条件の設定について書きます。

実験コストの見積もり

前回、ランダムプレイヤーのバトル1回で20~30msかかると書きましたが、ターン数などを含めた測定を行いました。またプロファイリングでボトルネックを探してみましたが見つからなかったという話をします。

環境はIntel Core i5-7600K CPU @ 3.80GHz, Windows 10, node v14.15.1です。シミュレータのリビジョンは4cecf1117aade118e4bb64768951e87bf5a75029です。

ランダムに生成したパーティ同士の対戦を1000回行い、所要時間などを測定しました。交代を選ぶ確率は0.1としました。その結果、18014msかかり、20428ターン、44296回の行動選択(1プレイヤーが1回選択したら1インクリメントされる。ターン開始時には2インクリメントされ、片方だけ倒れた際の交代先選択では1インクリメントされる)がなされました。おおむね、1ターン1ms、1バトル当たり20ターンかかり、両方のプレイヤーが思考する場合は44回の思考が発生するとして計算時間を見積もる必要がありそうです。

測定前にnodeをv10.16.3からv14.15.1にアップグレードしたのですが、約10%の高速化になりました。

一応、node.js標準機能でプロファイリングを行ってみました。

結果の一部を表示します。

 [Summary]:
   ticks  total  nonlib   name
    209   18.3%   98.1%  JavaScript
      0    0.0%    0.0%  C++
     21    1.8%    9.9%  GC
    926   81.3%          Shared libraries
      4    0.4%          Unaccounted

 [C++ entry points]:
   ticks    cpp   total   name

 [Bottom up (heavy) profile]:
  Note: percentage shows a share of a particular caller in the total
  amount of its parent calls.
  Callers occupying less than 1.0% are not shown.

   ticks parent  name
    878   77.1%  C:\Program Files\nodejs\node.exe
    320   36.4%    C:\Program Files\nodejs\node.exe
    144   45.0%      LazyCompile: *findPokemonEventHandlers D:\dev\pokeai\pokeai\Pokemon-Showdown\.sim-dist\battle.js:787:26
    144  100.0%        LazyCompile: *findEventHandlers D:\dev\pokeai\pokeai\Pokemon-Showdown\.sim-dist\battle.js:742:19
    142   98.6%          LazyCompile: *runEvent D:\dev\pokeai\pokeai\Pokemon-Showdown\.sim-dist\battle.js:556:10
     25   17.6%            LazyCompile: *tryMoveHit D:\dev\pokeai\pokeai\Pokemon-Showdown\data\mods\gen2\scripts.js:148:12
     14    9.9%            LazyCompile: *useMoveInner D:\dev\pokeai\pokeai\Pokemon-Showdown\data\mods\gen3\scripts.js:22:14

読み方は詳しく理解できていないのですが、一定時間ごとにどの処理が実行されているかがサンプリングされるようです。node.exe内の処理を実行中に取られたサンプルが878個で、そのうち144個がLazyCompile: *findPokemonEventHandlersの処理中だったようです。所要時間の大きい順にソートされているにもかかわらず最大所要時間の関数が全体の16%しか時間を消費していないということで、負荷の大部分を占める特定の処理があるわけではないようです。よって、その処理をC言語で作成したライブラリで置き換えて高速化ということはできなさそうでした。当面は1ターン1msかかるという前提で実験計画を立てる必要があります。

ゲーム木探索入門 part01 構想と予備実験【PokéAI】

今まで私が開発してきたポケモンバトルAIは、モデルフリー強化学習に基づいてバトル中の行動を選択するものでした。

先日まで1vs1バトルでうまくいった強化学習手法を3vs3に拡張する実験をしていたのですが、学習結果がいまいちという問題に苦労しており(忘れないうちに記事を書いておきたいですが)、ゲームAIの実現方法として全く違う手法を試してみようと思い立ちました。 select766.hatenablog.com

  • ゲーム木を探索するタイプのゲームAI技術をポケモンバトルに応用したい
  • 囲碁でうまくいった「モンテカルロ木探索」を応用したいが、ゲームの性質の違い(同時手番ゲーム)に対応する必要がある
  • Lanctotらによる比較的単純な手法を実装したい
  • ゲームのシミュレータにおいて、上記手法を実装するために必要な機能が使えることを確認した

モデルフリー強化学習では、現在の状態からある技を選んだ時の勝率を単純に回帰するようなモデルを学習していました。今回からしばらくは、「もし技Aを選んだとき、相手が技Xなら状態s1になって、相手が技Yなら状態s2になって…」というように将来の状態を明示的に考えて最適な行動を選ぶ方法を考えます。ゲームAIの内部でバトル中の状態をノード、行動(技または交代)をエッジとしたゲーム木を考え、その木に対する処理を行うことでどの行動が最適なのか決定します。より具体的には、囲碁で2000年代後半から使われているモンテカルロ木探索に近いものを実現したいと考えています。AlphaGoはモンテカルロ木探索に機械学習ベースの評価関数を組み合わせたものですが、その登場以前の機械学習不要の手法にまずは取り組む予定です。

囲碁ポケモンバトルの大きな違いは、ポケモンバトルが不完全情報ゲームである点です。ポケモンバトルにあって囲碁にない要素として、相手側のパーティ構成が不明であること、全プレイヤーが同時に行動を決定すること(同時手番ゲーム)、プレイヤーの行動が同じでも乱数により結果が変わることがあります。モンテカルロ木探索ベースの手法をポケモンバトルに応用するにあたりこれらの課題に対応する必要があるのですが、最初に問題になるのは同時手番ゲームであるという点です。パーティ構成や乱数は最初は固定してしまえばいいのですが、手番が交互である囲碁の手法そのままだと、先手として扱うプレイヤーの手に応じて後手として扱うプレイヤーは都合のいい手を選べてしまうという仮定を置くことになり非対称性が生じてしまうという問題が生じます。

この点は不完全情報ゲームでのモンテカルロ木探索を扱う"Information Set Monte Carlo Tree Search" (Cowling et al.)でも論じられています。

Under a simple determinization approach, the first player is overly pessimistic (assuming the opponent can observe the chosen move and select the best response to it) while the second player is overly optimistic (assuming the first player’s move is fixed at the point of the second player’s decision, and thus determinizing it randomly)

この問題の対応策についてサーベイした中で、Lanctotらによる比較的単純な手法("Monte Carlo Tree Search for Simultaneous Move Games: A Case Study in the Game of Tron"(Marc Lanctot et al.))がありましたのでまずはそれを試してみたいと考えています。手法説明は次回以降に行います。この手法を実装するうえで課題となるのが、ゲームのルールを実装したシミュレータ上で状態を行ったり来たりする必要がある点です。今までの強化学習の際のシミュレータは、ゲーム開始時点から行動を選んでいって勝敗を得る、という通常のゲームプレイに沿った動作ができれば十分でした。しかしこの手法を含めモンテカルロ木探索系の手法を実装するためには、実際に選択する最適な行動を選ぶために、現在の状態から仮に行動Aをとった場合の次の状態や、仮に行動Bをとった場合の次の状態など複数の将来の状態を生成する必要があります。このために最低限必要なシミュレータの機能は、ゲームの状態をコピーする機能です。実際のゲームの状態を変化させることなく、そのコピーに対して様々な行動パターンを試したうえで最善の行動を選び、実際のゲームはその行動によって進めるという流れになります。

実装方法の概略を述べます。

完全なコードはリンク先をご覧ください。Pokemon Showdownでシミュレータの状態を復元するテスト ライブラリバージョン4cecf1117 · GitHub

従来実験に使用していたポケモンバトルシミュレータPokémon-Showdownで状態のコピー機能があるか探したところ、シリアライズ機能を用いることで実現可能なことがわかりました。Pokémon-ShowdownはTypeScript(JavaScriptに型定義を付与した言語)で実装されています。 以下のようにBattleクラスのメソッドを使うことで、現在のバトルの状態をコピーできます。乱数のシードを含めた内部状態のコピーが可能です。関数オブジェクト等も含まれていないため、JSON.stringify()を使って文字列化し、ファイルに保存することも可能です。(2020-12-12修正:ディープコピーライブラリを使用)

const clone = require('rfdc')();
const serialized = clone(battle.toJSON());
const copied = Battle.fromJSON(serialized);

rfdcはオブジェクトのディープコピーを行うライブラリです。ディープコピーしないと、コピー元とコピー先でBattleオブジェクト内の配列が共有されてしまい問題があります。JSON.parse(JSON.stringify(obj))でも実装可能ですが、実行回数が非常に多いため速度ベンチマークを参照し、高速なライブラリを選びました。

JavaScriptのディープコピー速さ比較 〜7つの手法/ライブラリを比べてみた〜 - Qiita

また、従来はシミュレータ本体であるBattleクラスをラップして文字列入出力によりゲームを進めることができるBattleStreamクラスを使い、この入出力をpythonで実装したエージェントへプロセス間通信で接続する実装を用いていました。しかしこの手段のままでは状態のコピーが使えないので、自前のコードでBattleクラスを直接制御するようにしました。特に難しい点はなく、むしろ文字列のパースなどが不要になりシンプルになったといえます。従来エージェント部分はpythonで実装していましたが、しばらくニューラルネットワークは使用しないため、プロセス間通信が不要となるようTypeScriptのみで実装してみることにします。モンテカルロ木探索では一度の行動選択のためにシミュレータを膨大な回数呼び出す必要があるため、プロセス間通信がボトルネックになる可能性があると考えたためです。

まずはシミュレータの操作方法確認を兼ねて、ランダムプレイヤーとレーティングバトルの機構をTypeScriptで実装しました。コードはリンク先を参照ください。 pokeai/ratingBattle.ts at 6e5369b78cac3c7f81487874d7b22b723fc5c105 · select766/pokeai · GitHub AI間での強さの比較の簡単な例として、ランダムプレイヤーが技と交代を選ぶ比率を変えた場合を実験できるようにしました。技と交代の両方が選べる場面において、まず技か交代のどちらかを設定された確率により選択し、技の場合は技の候補から等確率に選択、交代の場合は交代先の候補から等確率に選択するという仕様です。ランダムに生成した(ポケモン3匹からなる)パーティ1,000個に対し、交代選択確率0%, 10%, 50%の3種類のエージェントを組み合わせて3000個のプレイヤーを生成し、これらを相互に対戦させてレートを得ました。

レート最上位、最下位プレイヤーを5個ずつ示します。

---
レート: 1974
交代確率0%
レアコイル ['とっしん', 'どくどく', '10まんボルト', 'かげぶんしん']
エンテイ ['はかいこうせん', 'ふみつけ', 'かえんほうしゃ', 'かげぶんしん']
ゴローニャ ['どろかけ', 'どくどく', 'ほのおのパンチ', 'ばくれつパンチ']
---
レート:1949
交代確率0%
サンダー ['どろかけ', 'そらをとぶ', '10まんボルト', 'スピードスター']
シャワーズ ['バブルこうせん', 'ずつき', 'なみのり', 'ロケットずつき']
レアコイル ['はかいこうせん', 'かみなり', '10まんボルト', 'とっしん']
---
レート: 1936
交代確率10%
カイリュー ['だいもんじ', 'かえんほうしゃ', 'スピードスター', 'おんがえし']
ドククラゲ ['ロケットずつき', 'おんがえし', 'ギガドレイン', 'どくどく']
ゲンガー ['かみなりパンチ', 'はかいこうせん', '10まんボルト', 'でんじほう']
---
レート: 1935
交代確率10%
ベトベトン ['かみなりパンチ', 'どろかけ', 'どくどく', 'はかいこうせん']
ゲンガー ['ナイトヘッド', 'ロケットずつき', 'ばくれつパンチ', 'おんがえし']
バンギラス ['ずつき', 'だいもんじ', 'れいとうビーム', 'ほのおのパンチ']
---
レート: 1934
交代確率0%
ライチュウ ['かみなり', 'ころがる', '10まんボルト', 'なみのり']
ゲンガー ['ギガドレイン', 'おんがえし', 'ずつき', 'でんじほう']
カイロス ['いあいぎり', 'のしかかり', 'どくどく', 'とっしん']
---
レート: 958
交代確率50%
フシギバナ ['かげぶんしん', 'どろかけ', 'いあいぎり', 'とっしん']
ヨルノズク ['はがねのつばさ', 'スピードスター', 'どくどく', 'かげぶんしん']
ラッタ ['かみなり', 'ふぶき', 'すてみタックル', 'いわくだき']
---
レート: 986
交代確率50%
バタフリー ['かげぶんしん', 'どくのこな', 'はかいこうせん', 'ギガドレイン']
ギャラドス ['すなあらし', 'ロケットずつき', 'かげぶんしん', 'ふぶき']
アリアドス ['ギガドレイン', 'ナイトヘッド', 'サイケこうせん', 'サイコキネシス']
---
レート: 1000
交代確率50%
カイロス ['ずつき', 'いあいぎり', 'かげぶんしん', 'とっしん']
デリバード ['どくどく', 'スピードスター', 'ずつき', 'かげぶんしん']
デンリュウ ['スピードスター', 'いわくだき', 'とっしん', 'でんじほう']
---
レート: 1002
交代確率50%
ウツボット ['どくのこな', 'ソーラービーム', 'はかいこうせん', 'のしかかり']
トゲチック ['いわくだき', 'かげぶんしん', 'どくどく', 'はがねのつばさ']
エンテイ ['かいりき', 'すなあらし', 'どくどく', 'どろかけ']
---
レート: 1028
交代確率50%
ニョロボン ['たきのぼり', 'れいとうパンチ', 'おんがえし', 'バブルこうせん']
ツボツボ ['かいりき', 'かげぶんしん', 'いわくだき', 'どろかけ']
アーボック ['のしかかり', 'ロケットずつき', 'はかいこうせん', 'かげぶんしん']

レート上位プレイヤーは比較的良い技を覚えているパーティおよび交代確率0%,10%のエージェントの組み合わせになっています。最下位は交代確率50%のエージェントが並んでいます。

各エージェントを用いたプレイヤーの平均レートを算出しました。

エージェント 平均レート
交代確率0% 1631
交代確率10% 1570
交代確率50% 1297

相手との相性などを考慮せずランダムに交代するのは実質的にパスと同じなので、交代はできるだけ選ばないほうがいいという当たり前の結果が得られたといえます。

気づいた点として、シミュレータの計算がかなり遅いです。ランダムプレイヤー同士の対戦1回に20~30ms程度かかります。モンテカルロ木探索ベースの手法では1回の行動を決めるのに百回以上のシミュレーション(現在の状態からゲームの決着がつくまでの試行)が必要なので、ごく弱いエージェントでも数秒かかってしまいそうです。ポケモンバトルはもともと8bitCPUのゲームボーイで実装されており、(メッセージ表示に数秒かかるので正確なことはわかりませんが)1ターンの計算は0.1秒もかかっていないはずです。その1万倍オーダーの性能がある現代のCPUで計算しているにしては遅すぎると思われます。アルゴリズムの実装ができたとして、計算時間をかければかけるほど強くなるという状況であれば速度を重視したシミュレータを自作することが大事になってくるかもしれません。

次は、モンテカルロ木探索の実装に着手したいと思います。

【ポケモンバトルAI本】技術書典9 頒布予定

技術書典9は2020年9月12日から22日まで開催される技術系同人誌の頒布イベントです。新型コロナウイルスの影響によりオンライン開催ですので、お祭り感のある通販のようなものとお考え下さい。

当サークル「ヤマブキ計算所」は技術書典9へ出展いたします。新刊となるポケモンバトルAI本の第4巻を頒布します。 ポケモンバトルのルールだけから機械学習を中心とした人工知能技術により強い戦略を作り出すことをテーマとし、開発したアルゴリズムやその実験結果を掲載する本です。 本巻の内容は、1つのモデルでどんなパーティの行動選択も行える「汎用行動選択モデル」の開発となります。 基本的にブログで掲載した内容と多少の書き下ろしですが、本1冊として一貫するように加筆修正しておりますので読みやすくなっていますし、過去の巻を読まなくてもわかるよう必要な情報を再掲しています。 (ブログ記事を連結すれば終わりの簡単なお仕事だと思ってたら大変な目にあいました…)

頒布場所はこちらです。9月12日から会期終了後も購入が可能です。

techbookfest.org

今回は電子書籍(PDF)のみ、1冊500円です。既刊もあります。残念ながら3月のイベントで紙媒体の売れ行きが極めて悪かったため、紙媒体の頒布は行わないこととしました。将来リアルイベントが復活した際にはその際の新刊との合本版を印刷することも検討しています。

f:id:select766:20200911182814j:plain
新刊表紙
f:id:select766:20200911182830j:plain
新刊目次1
f:id:select766:20200911182848j:plain
新刊目次2
f:id:select766:20200911183636j:plain
新刊本文1
f:id:select766:20200911183706j:plain
新刊本文2

技術書典9には当サークルのような読み物だけでなく、仕事に使える実用書も多数出ていますので、ぜひ見に行ってみてください。

techbookfest.org

汎用行動選択モデルの学習 part13 行動の強化学習とパーティ生成の交互実行(結果)【PokéAI】

前回、バトル中の行動の強化学習と、そこで得られたモデルのQ関数を用いて強いパーティを生成するステップを交互に反復する手法を提案しました。 今回はそれを実際に動作させた結果を示します。

実験条件

  • 反復回数 10
  • パーティ数
    • Q関数を用いて生成するパーティ数 871
    • ランダム生成するパーティ数 129
  • パーティの生成条件
    • ポケモンの制限 最終進化系129種類(ミュウツードーブル等除く)
    • 技の制限 効果が見込める52種類(高威力攻撃技主体)
    • 類似パーティ生成抑制のペナルティ 1
  • 強化学習
    • 探索: epsilon-greedy
      • ランダム行動する確率epsilon: 0.3
      • epsilon decay: 2.0 \times 10^{-6}
    • 報酬割引率: 0.95
    • バッチサイズ: 32
    • 最初に学習するまでのステップ数(replay bufferのサンプル数): 500
    • Nサンプル収集するたびにoptimize: 1
    • N optimizeごとにtarget networkのアップデート: 100
    • replay bufferサイズ: 100,000
    • optimizer (Adam)の学習率: 0.0004
    • バトル数: 100,000

強化学習のハイパーパラメータは、以前Optunaで最適化したものを丸めました。

各反復の結果

各反復ではパーティが1,000個生成されます。それらに含まれるポケモン・技の分布(それぞれ出現回数トップ10)を示します。

反復0 (ランダム生成)

要素 出現回数
ピクシー 14
ツボツボ 12
マタドガス 12
ライコウ 12
モルフォン 11
ピジョット 11
キレイハナ 11
ゴローニャ 11
エアームド 11
トゲチック 11
要素 出現回数
どくどく 246
かげぶんしん 229
おんがえし 219
はかいこうせん 170
とっしん 161
ずつき 143
どろかけ 138
すてみタックル 137
スピードスター 137
いわくだき 115

最初はランダムなので、ポケモンは均等に出現、技は覚えるポケモンの数が多いどくどく・かげぶんしんなどが上位に来ています。

反復1

要素 出現回数
カイリュー 87
ミルタンク 63
ケンタロス 45
サンダー 43
ゲンガー 39
ファイヤー 38
ガルーラ 38
メガニウム 36
キングドラ 33
カビゴン 29
要素 出現回数
10まんボルト 121
じしん 113
なみのり 102
れいとうビーム 98
だいもんじ 94
おんがえし 91
かえんほうしゃ 89
ハイドロポンプ 87
サイコキネシス 83
かみなり 83

強化学習結果からパーティ生成を経ることで、強そうなポケモンが上位に来ています。

反復2

要素 出現回数
カビゴン 99
サンダー 76
ハピナス 64
スターミー 51
ガルーラ 51
マンタイン 41
ケンタロス 41
ヤドキング 39
サンダース 38
ライコウ 29
要素 出現回数
おんがえし 129
10まんボルト 113
サイコキネシス 104
かみなり 103
すてみタックル 102
じしん 101
れいとうビーム 99
のしかかり 98
なみのり 92
ハイドロポンプ 90

ここで、ポケモン金銀最強と言われたカビゴンがトップとなりました。カイリューはトップ10から消えています。この理由を推察すると、反復0の時点では氷タイプの強力な技を持つポケモンが少なかったため上位に来て、氷タイプの技で対策すればあまり強くないということが学習された可能性があります。

(途中省略)

反復9(最終)

要素 出現回数
カビゴン 104
サンダー 83
キングドラ 66
ライコウ 47
ガルーラ 46
メガニウム 43
デンリュウ 39
ベトベトン 34
バリヤード 34
ラプラス 30
要素 出現回数
10まんボルト 126
おんがえし 115
なみのり 114
かみなり 108
れいとうビーム 100
じしん 98
サイコキネシス 95
どくどく 92
のしかかり 91
ふぶき 88

反復によって若干順位が入れ替わりますが、カビゴンは不動の1位でした。技はサンダー・ライコウに欠かせない10まんボルト(かみなりも選択しうる)が最上位となりました。

それらを(当該反復で学習した行動選択モデルを用いて)レーティングバトルさせ、上位10パーティを示します。

反復0

レート パーティ
1997 カビゴン,LV55,おんがえし,はかいこうせん,ほのおのパンチ,すなあらし
1935 サンダー,LV55,はかいこうせん,ドリルくちばし,どろかけ,10まんボルト
1917 サンダー,LV55,おんがえし,かみなり,いわくだき,すなあらし
1896 ライコウ,LV55,どろかけ,かいりき,10まんボルト,かみなり
1892 ライコウ,LV55,ずつき,10まんボルト,すなあらし,でんじほう
1891 リングマ,LV55,ばくれつパンチ,いわくだき,おんがえし,じしん
1884 リングマ,LV55,じしん,はかいこうせん,おんがえし,ずつき
1865 バンギラス,LV55,ずつき,れいとうビーム,じしん,10まんボルト
1863 サンダー,LV55,どろかけ,はかいこうせん,ドリルくちばし,10まんボルト
1853 ランターン,LV55,かげぶんしん,10まんボルト,ハイドロポンプ,れいとうビーム

最初の時点でカビゴン・サンダーが強いということは学習の結果として現れています。

反復1

レート パーティ
1869 カビゴン,LV55,バブルこうせん,かえんほうしゃ,おんがえし,ロケットずつき
1861 カビゴン,LV55,かえんほうしゃ,すてみタックル,かみなり,れいとうパンチ
1858 カビゴン,LV55,ばくれつパンチ,かえんほうしゃ,のしかかり,バブルこうせん
1848 カビゴン,LV55,かえんほうしゃ,ばくれつパンチ,のしかかり,バブルこうせん
1842 カビゴン,LV55,のしかかり,ふぶき,でんじほう,かえんほうしゃ
1829 ライコウ,LV55,どろかけ,10まんボルト,どくどく,いあいぎり
1824 カビゴン,LV55,れいとうパンチ,だいもんじ,のしかかり,かみなり
1817 カビゴン,LV55,のしかかり,だいもんじ,なみのり,かいりき
1812 カビゴン,LV55,なみのり,ソーラービーム,ふぶき,すてみタックル
1811 カビゴン,LV55,ふぶき,ころがる,すてみタックル,かみなり

カビゴンのパーティへの採用頻度はまだ最大ではありませんが、すでに上位をカビゴンがほとんど占めています。

反復2

レート パーティ
1899 カビゴン,LV55,のしかかり,なみのり,ロケットずつき,ころがる
1887 カビゴン,LV55,じしん,だいもんじ,のしかかり,すてみタックル
1868 カビゴン,LV55,ころがる,ソーラービーム,かみなりパンチ,のしかかり
1862 カビゴン,LV55,のしかかり,ちきゅうなげ,どろかけ,ソーラービーム
1841 カビゴン,LV55,のしかかり,ほのおのパンチ,れいとうビーム,ふぶき
1831 ラプラス,LV55,つのドリル,ソーラービーム,ハイドロポンプ,10まんボルト
1831 カビゴン,LV55,ばくれつパンチ,のしかかり,でんじほう,はかいこうせん
1825 カビゴン,LV55,なみのり,かいりき,のしかかり,ちきゅうなげ
1819 カビゴン,LV55,ソーラービーム,どくどく,かえんほうしゃ,のしかかり
1814 ケンタロス,LV55,つのドリル,ふみつけ,じしん,のしかかり

つのドリルを覚えたラプラスケンタロスが登場しています。

(途中省略)

反復9

レート パーティ
1875 カビゴン,LV55,ほのおのパンチ,おんがえし,ソーラービーム,すなあらし
1866 カビゴン,LV55,とっしん,バブルこうせん,すてみタックル,だいもんじ
1838 カビゴン,LV55,すてみタックル,でんじほう,だいもんじ,ソーラービーム
1834 カビゴン,LV55,ずつき,じしん,ちきゅうなげ,おんがえし
1817 カビゴン,LV55,じしん,すなあらし,のしかかり,れいとうパンチ
1814 カビゴン,LV55,ばくれつパンチ,のしかかり,れいとうビーム,ころがる
1812 カビゴン,LV55,おんがえし,だいもんじ,すなあらし,なみのり
1810 カビゴン,LV55,すてみタックル,ころがる,ソーラービーム,どろかけ
1806 カビゴン,LV55,ふぶき,のしかかり,どろかけ,じしん
1801 カビゴン,LV55,ちきゅうなげ,おんがえし,かげぶんしん,かえんほうしゃ

THE カビゴン 無双。ただし、最上位のカビゴンでもかえんほうしゃだいもんじではなくほのおのパンチを覚えている(当時はすべて特殊技、ほのおのパンチのメリットはない)ので、技構成がパーフェクトかというとまだ疑問が残ります。とはいえ対戦の結果なので、これで差がつく場面はほとんどなかったという結果だと考えられます。

全反復でのパーティ混合での対戦結果

反復的な学習によって強くなっていっているのかを確認します。各反復内でのレーティングバトル結果の上位100パーティを抽出し、それを10反復分混合し、合計1000パーティでレーティングバトルさせます。上位を抽出する理由は、各反復で学習対象としているパーティ群にはランダム生成パーティを混合していることおよび多様性確保のために強さが劣るパーティも混合されているためです。各パーティは、その反復で学習した行動選択モデルを用いて行動選択させます。

1000パーティのレーティングバトルの結果として得られる各パーティのレートを、それが所属する反復ごとに平均した結果を示します。

f:id:select766:20200831201702p:plain
反復(iteration)ごとのパーティの平均レート

反復0はもちろんランダム生成パーティなので弱いのは当然ですが、パーティ・行動双方が最適化された反復1でも飽和せず、反復2のほうがより強くなっています。しかし、それ以上は強くなっていないようで、学習手法の限界に達しているようです。改良の余地は残りますが、反復的なパーティ生成と強化学習により、戦略が改善できることがわかりました。

レーティングバトル上位10パーティを示します。

レート パーティ
1795 ドンファン,LV55,じしん,げんしのちから,ころがる,つのでつく
1776 バンギラス,LV55,じしん,かいりき,げんしのちから,ばくれつパンチ
1775 ドンファン,LV55,つのでつく,じしん,いわくだき,げんしのちから
1764 ドンファン,LV55,ころがる,げんしのちから,じしん,つのでつく
1747 ドンファン,LV55,じしん,ころがる,つのでつく,げんしのちから
1744 カビゴン,LV55,れいとうパンチ,すなあらし,のしかかり,ばくれつパンチ
1742 ドンファン,LV55,じしん,ころがる,かいりき,げんしのちから
1732 カビゴン,LV55,どろかけ,おんがえし,バブルこうせん,ばくれつパンチ
1729 ニドクイン,LV55,じしん,つのドリル,はかいこうせん,だいもんじ
1722 カビゴン,LV55,じしん,のしかかり,かみなり,ソーラービーム

驚くべきことに、最上位はカビゴンではなくドンファンという結果になりました。ドンファンは1000パーティ中7パーティでしか登場していないのですが、そのうち5パーティが上位10パーティに入るという極めて良い結果を出しています。次の章で定性的に考察します。

なお、下位10パーティは次のようになりました。

レート パーティ
1054 ニョロトノ,LV55,はかいこうせん,なみのり,サイコキネシス,いわくだき
1080 カメックス,LV55,ばくれつパンチ,ハイドロポンプ,でんじほう,たきのぼり
1114 スターミー,LV55,おんがえし,たきのぼり,かみなり,すてみタックル
1115 ポリゴン2,LV55,かみなり,でんじほう,10まんボルト,ふぶき
1119 スイクン,LV55,バブルこうせん,いわくだき,たきのぼり,おんがえし
1125 ゴルダック,LV55,ハイドロポンプ,スピードスター,はなびらのまい,れいとうパンチ
1129 ヤドキング,LV55,サイコキネシス,じしん,とっしん,のしかかり
1132 オーダイル,LV55,おんがえし,かいりき,ハイドロポンプ,げんしのちから
1143 カイリュー,LV55,かみなり,れいとうパンチ,どろかけ,どくどく
1148 エレブー,LV55,いわくだき,でんじほう,どくどく,すてみタックル

いずれも反復0で生成されたパーティで、技構成だけでなくバトル中の行動もよくなかったものと考えられます。

バトル中の行動の分析

上位のパーティが、バトル中にどんな行動をとっていたのか定性的に確認します。

ドンファン,LV55,じしん,げんしのちから,ころがる,つのでつく

1位のパーティです。 基本的にはじしんを連打し、飛行タイプのサンダーにはげんしのちから(岩タイプ)を使い分けていました。他の技はほぼ使われません。ラプラスゴルダックなど水タイプの相手と対面すると、なみのり等でなすすべなく負けてしまいます。ずつき・おんがえしを連打してくるケンタロスに対しても攻め勝てています。

カビゴン,LV55,れいとうパンチ,すなあらし,のしかかり,ばくれつパンチ

6位のパーティです。 基本的にのしかかりを使い、のしかかりが半減となるバンギラスにはばくれつパンチカイリューには4倍弱点を突けるれいとうパンチを使っていました。

バンギラス,LV55,げんしのちから,10まんボルト,ばくれつパンチ,かえんほうしゃ

11位のパーティです。 4タイプの攻撃技を覚えています。げんしのちからはサンダー・ラプラスに、10まんボルトはゴルダックオーダイルニョロトノ(いずれも水単タイプで、入力特徴量上は区別がつかない)に、ばくれつパンチ(格闘タイプ)はカビゴンバンギラスに、かえんほうしゃライコウに使うという形でうまく使い分けができていました。なお、ライコウには攻め負けます。

ケンタロス,LV55,つのドリル,のしかかり,どくどく,つのでつく

12位のパーティです。 ほぼすべてのバトルでつのドリル(命中率30%の一撃必殺技)を連打するという恐ろしい戦法でした。この環境では、強力な格闘技を受けたり、相手がゴーストタイプでつのドリルが効かないという状況がほとんどありませんでした。ほとんどのバトルで相手に倒される前に3回以上つのドリルを試行する機会があり、試行回数2回で51%、3回で66%の確率で相手を倒せるという計算になります。1vs1バトルなので交代でゴーストタイプが出てくることを一切考慮しなくて済むため、極めて単純ながら強力な戦法といえます。

過去の学習ではタイプ相性的に「こうかはいまひとつ」の技を選んでしまうことも多々あり難がありましたが、今回は攻撃技の選択に関して明らかな間違いはほとんどなく、十分な学習結果となっていました。相手のポケモンによって選ぶ技はほぼ固定されており、状況に応じた選択はなされていませんでしたが、攻撃技を使うだけであれば適切な戦略の範疇です。どくどく等の補助技はほとんど使えていない状況は依然として続きます。1vs1バトルでは交代の隙というのがないので、能力アップよりひたすら攻撃することの有効性が高いとも考えられます。

なぜドンファンが最上位だったか

ドンファンは各反復内でのレーティングバトルでは上位10パーティに入っていなかったにもかかわらず、全体混合のレーティングバトルでは1位になりました。この理由を考察します。

全体混合のレーティングバトルでの、1000パーティ中のポケモンの出現回数上位10種類を示します。

要素 出現回数
カビゴン 468
ケンタロス 92
ライコウ 75
サンダー 69
ラプラス 61
バンギラス 51
ガルーラ 28
カイリュー 19
リングマ 16
エーフィ 12

全体の40%以上をカビゴンが占めるという状況になっています。この環境では、カビゴンに勝てるか否かが決定的な差になります。

ドンファンの主力技じしんと、カビゴンの主力技のしかかりでダメージ計算を行い、相手を何発で倒せるかを示します。

↓攻撃側\防御側→ カビゴン ドンファン
ドンファン(じしん) 3~4発 3~4発
カビゴン(のしかかり) 4発 4~5発

素早さはドンファンのほうが速いことを加味すると、急所・のしかかりによる麻痺が生じない限りドンファンが勝ちということがわかります。 仮にカビゴンドンファンに対して効果抜群となるなみのりを使用すると3発、れいとうパンチを使用すると3~4発です。これらの技を選択すれば、確定ではありませんがドンファンに勝てる可能性はあります。 ただ依然として乱数で勝敗が決まるので、単純にのしかかりを連打して麻痺に賭けるほうが単純で汎用性が高そうです。 この環境においては、ドンファンカビゴンを上回っているといえそうです。なお、人間同士のポケモンバトルの公式大会のルールでドンファンが日の目を浴びたことはないと思われますが、それは同じタイプのガラガラのほうが持ち物「ふといホネ」によって攻撃力が高くなるためです。持ち物なしのルールになっているために絶妙な攻撃力と防御力のバランスで注目対象になったといえます。 逆に各反復内のレーティングバトルではドンファンが上位に来なかった理由は、水タイプの相手に対して勝ち目がなく、水タイプのポケモンが出てくる確率が相対的に高い環境で順位が下がったのだと考えられます。 結論として、ドンファンが最上位に来た理由は、カビゴンの出現頻度が極めて高い、かつ天敵となる水タイプが相対的に少ない環境となっていたこと、その中でカビゴンに攻め勝てる性能を持っていたためだといえるでしょう。 同時に、環境内のポケモンの出現頻度によってどのポケモンが統計的に強いかが変わるというのは根本的な難題だといえそうです。

ところで、人間同士の対戦ではカビゴンに対してどう対処するのが正解なのでしょうか。ポケモンバトルに関する非公式の考察本から引用します。

(カビゴンについて) 第二世代の任天堂公式ルール『ニンテンドウカップ2000』における絶対王者と呼べるポケモン

(対策の節) まず、カビゴン対策の筆頭候補となるポケモンムウマである。 (中略)これはムウマカビゴン対策の役割しか担当しない場合の話である。 ムウマカビゴンを殴り倒せるポケモンではなく、「ほろびのうた」や「みちづれ」の効果によって共倒れにすることで、カビゴン対策の仕事をこなすことができる。

ポケットモンスター赤緑ピカチュウ&金銀クリスタル マップ&ずかん&対戦考察本『ポケモンバトルノスタルジアDX』上巻 (発行:つうしんケーブルクラブ)より

ということで、共倒れ前提の戦法が薦められています。つまり、今回採用している1vs1ルールではそもそも実行不可能です。今回は相手のポケモンごとに決まった1つの技を連打するという戦略が有効で、あまり賢いAIにはなりませんでした。その中で、ドンファンカビゴンに対抗できるということは筆者は予想しておらず、興味深い結果が得られたとも考えられます。カビゴンでとにかく攻撃技を打ちまくるという単純な戦略に対して有効な賢い手段を学習するには、3vs3ルールへと移行することが必須のようです。

汎用行動選択モデルの学習 part12 行動の強化学習とパーティ生成の交互実行(手法)【PokéAI】

前回、強化学習のハイパーパラメータを調整し、疑似教師データを使った教師あり学習よりも強い汎用行動選択モデルを学習させることに成功しました。 これと、汎用行動選択モデルを用いたパーティ生成手法を組み合わせて強いパーティとその適切な運用法を学習します。

学習システムの構成を下図に示します。

f:id:select766:20200830192708p:plain
パーティ生成と強化学習を交互に行うシステムの構成

目的を単純に言えば、人間同士の対戦界において、ある戦略が普及すればそれに対抗するメタ戦略が考案され、戦略が進歩していくのと同様のことをAIの中で実現しようとしています。 このシステムでは、パーティ生成と強化学習を交互に反復して行います。最初の反復(t=0)では、Q関数がないのでランダムにパーティを1000個生成します。 次に、このパーティ群上でバトル中の行動選択モデルを強化学習により学習します。ここで学習されたモデルと、対象にしたパーティ群をプレイヤーリポジトリに保存します。プレイヤーとは、パーティ1個と行動選択モデルの組です。 次の反復(t=1)では、t=0で学習した行動選択モデルのQ関数を用いて871個のパーティを生成し、これとランダムなパーティ129個(全最終進化系ポケモン1匹ずつ、技はランダム)を合わせて強化学習を行います。強化学習モデルのパラメータは、前回の反復で学習したものを初期値として用います。以上の手順を反復し、洗練されたプレイヤーを生成します。最終的に、プレイヤーリポジトリに蓄積されたプレイヤーから強いものを抽出し、システム全体の出力とします。第3巻では、ランダムなパーティにランダムな行動させた結果を用いてパーティを生成し、強化学習するだけで終わっていました。今回の手法により、(1)強化学習によりパーティを適切に運用したときに効果が大きい技を次の反復でのパーティ生成で優先的に組み込むことができるため運用法が難しい技を含めた最適なパーティを生成すること、(2)ある反復で強いとされたパーティに対する対抗手段を学習することで弱点の少ない運用法を学習することを目指します。

次回、実際に反復学習した結果を示します。