見出し画像

Gym Retro入門 / ゲームインテグレーション

1. ゲームインテグレーション

「ゲームインテグレーション」は、ビデオゲームのROMに、次の3つの情報を付加して、OpenAI GymのGym環境としてゲームを利用できるようにすることです。

・開始状態
・完了条件
・報酬関数

「開始条件」は、環境をリセット時のゲームの開始位置、「完了条件」は、エピソード完了となるタイミング、「報酬関数」はエージェントが報酬を最大化するための単純な数値目標を提供します。

2. サポートROM

新しいゲームをインテグレーションするには、サポートされているROMが必要です。サポートされているROMは次の通りです。

・.md: メガドライブ
・.sfc: スーパーファミコン
・.nes: ファミコン
・.a26: Atari 2600
・.gb: ゲームボーイ
・.gba: ゲームボーイアドバンス
・.gbc: ゲームボーイカラー
・.gg: ゲームギア
・.pce: PCエンジン
・.sms: セガマスターシステム

これらのシステムのROMは異なる拡張子を使用する場合があります。その場合、前述の拡張子を使用するようにROMの名前を変更してください。

3. ゲームインテグレーションの例

以下は、ゲーム「Airstriker-Genesis」のゲームインテグレーションに利用する設定ファイルです。

◎Level1.state
「*.state」は、ゲームの「開始状態」を保存したセーブデータです。環境リセット時に、ゲームはこの状態に配置されます。ファイル形式はエミュレーター固有のセーブデータをgzipで圧縮したものになります。

◎data.json
「data.json」は、Pythonから「ゲーム変数」にアクセスできるように、「ゲーム変数」と「メモリアドレス」と「変数の型」を定義します。

{
 "info": {
   "gameover": {
     "address": 16712294,
     "type": ">u2"
   },
   "lives": {
     "address": 16712282,
     "type": ">u2"
   },
   "score": {
     "address": 16712270,
     "type": ">u4"
   }
 }
}

「info」セクション下の「変数」セクションには、メモリアドレス「address」と変数の型「type」のプロパティを指定します。
上記のJSONの「score」は、メモリアドレスは「16712270」、変数の型は「符号なしビッグエンディアン形式の4バイト幅」であることを示します。変数の型の種類については、「Appendix: Types」を参照してください。

◎scenario.json
「scenario.json」は、「data.json」で定義したゲーム変数を使用して、「報酬関数」と「完了条件」を定義します。
デフォルトでは、「scenario.json」から「報酬関数」と「完了条件」がロードされますが、retro.RetroEnvコンストラクターで手動で設定することもできます。

{
 "done": {
   "condition": "all",
   "variables": {
     "gameover": {
       "op": "equal",
       "reference": 1
     },
     "lives": {
       "op": "zero"
     }
   }
 },
 "reward": {
   "variables": {
     "score": {
       "reward": 1.0
     }
   }
 }
}

・reward
「reward」では、報酬の計算方法を定義します。
「reward」下には、「variables」を指定します。
「variables」下には報酬となる「ゲーム変数」を指定します。「ゲーム変数」の抽出方法は「op」「measurement」「reference」で指定します。「measurement」のデフォルトは「delta」、「op」のデフォルトはなしです。
「ゲーム変数」の報酬に乗算する係数は「reward」「penalty」で指定します。

・reward: 値が正の場合に値に乗算される係数。
・penalty: 値が負の場合に値に乗算される係数。

・done
「done」では、エピソード完了の条件を定義します。
「done」下には、「condition」「variables」を指定します。
「condition」ンは完了条件の結合方法を指定します。

・any: doneセクションの条件のいずれかが満たされる。(デフォルト)
・all: doneセクションのすべての条件が満たされる。

「variables」下には完了条件となる「ゲーム変数」を指定します。「ゲーム変数」の抽出方法は「op」「measurement」「reference」で指定します。「measurement」のデフォルトは「absolute」、「op」のデフォルトはなしです。

詳しくは「Appendix: Operations」を参照してください。

◎metadata.json
「metadata.json」は、ユーザーが状態を指定しない場合のデフォルトの「開始状態」と、その他の「デバッグ情報」を定義します。

{
 "default_state": "Level1",
 "whitelist": {
   "data.json": [
     "suspicious type >u2 for lives"
   ]
 }
}

◎rom.md
「rom.md」はインポートしたゲームのROMです。
ROMはGym Retroには含まれていないので、インポート後にGym Retroのローカルコピーされます。

◎rom.sha
「rom.sha」は、ROMのインポートに利用するrom.mdファイルのSHA1ハッシュです。

a8be7b0ca850119b167f9644e6a4a22e983d61a4

4. インテグレーションUI

インテグレーションUIを使用すると、ゲーム変数を簡単に見つけて、報酬関数で何が起こっているかを確認できます。以下からダウンロードできます。

Windows用のインテグレーションUI
Mac用のインテグレーションUI

画像1

「Scenario Infomation」には、以下の情報が表示されます。

・Reward: 報酬
・Done: 完了
・Frame: フレーム数
・Movie: 動画

・Cumulative: 累積報酬
・Did end: 完了 
・Timestep: タイムステップ

5. 新規ROMのインテグレーション

(1)「Gym Retro Integration UI」を開きます
(2)メニュー「Game→Integration」を選択し、インテグレーションするゲームのROM「rom.md」を選択。
(3)ゲーム名を指定。
(4)メニュー「Window→Controls」を選択し、ゲーム内のコントロールに対応するキーを確認。
(5)ゲームを操作して、「開始状態」とする瞬間になったら、「Command-P」で一時停止し、「Command-S」で状態保存。
(6)ファイル名を指定し、Saveボタンを押すことで「*.state」が出力。

アメリカ版のROMを優先しており、(USA)、(USA、ヨーロッパ)、(日本、アメリカ)などのいずれかで示されます。ROMの拡張子が.binの場合は、サポートされているROMタイプにリストされているシステムの正しい拡張子に変更してください。

6. 完了条件

最適な「完了条件」は、ゲームが終了した後の「ゲームオーバー画面」または「コンティニュー画面です。ゲームオーバー変数などの信頼性の低い終了条件を設定するよりも、シンプルで信頼できるがわずかに間違った終了条件
(ライフ0を検出するのが難しい場合はライフ1の時にゲームを終了)を設定することをお勧めします。

これは、多くの場合ゲームオーバー画面が存在することを検出しますが、レベルを切り替え時にも誤って起動します。ゲームオーバー変数を作成する場合は、複数のレベルを連続して再生するリプレイテストで、誤起動しないことを確認してください。

7. 報酬関数

強化学習エージェントは、報酬を最大化しようとします。理想的な報酬関数は、ゲームの攻略時に1ポイントを獲得することです。ゲームを攻略する以外にそれを最大化する方法はありません。ただし、既存の強化学習アルゴリズムでは、取得が非常に困難な報酬で進歩を遂げることができないため、その報酬は非現実的です。
代わりに、報酬をより簡単に獲得できるように指定することができます。これを最大化することで、ゲームを攻略できるようにします。

ゲームにスコアがある場合、これはしばしば良い選択です。ただし、一部のゲームでは、1か所に立って、同じ敵をリスポーンしながら何度も攻撃することで、必要なだけスコアを獲得できます。これはゲームを攻略することとは非常に異なるため、多くの場合非常にゲーム固有のものですが、代わりの報酬を持つことが最善です。

ただし、スコア以外の変数には注意してください。正しく取得するには注意が必要です。報酬を使用して複数のレベルをプレイし、意味があるかどうかを確認してください。

エージェントが受け取る報酬が画面に表示されるスコアと一致するように報酬を設定し、10または100倍になっていないことを確認してください。インテグレーションUIのシナリオ情報ペインに表示される累積報酬(Cumulative)で確認できます。

8. オペレーション

ゲーム変数は、未加工の値がメモリから抽出後、任意の操作を行い、有用な形式に変換できます。そのために、次の3つのプロパティが定義されています。

◎measurement
メモリからゲーム変数を抽出する方法を指定します。
デフォルトはコンテキストによって異なります。

・absolute: 現在の値
・delta: 現在の値と以前の値との差

◎op
値に適用する特定の操作を指定します。

・nonzero: 値が0の時は0、それ以外の時は1
・zero: 値が0の時は1、それ以外の時は0
・positive: 値が正の時は1、それ以外の時は0
・negative: 値が負の時は1、それ以外の時は0
・sign: 値が正の時は1、値が負の時は-1、それ以外の時は0
・equal: 値が参照値と同じ時は1、それ以外の時は0
・not-equal: 値が参照値と同じでない時は1、それ以外の時は0
・less-than: 値が参照値より小さい時は1、それ以外の時は0
・greater-than: 値が参照値より大きい時は1、それ以外の時は0
・less-or-equal: 値が参照値以下の時は1、それ以外の時は0
・greater-or-equal: 値が参照値以上の時は1、それ以外の時は0

◎reference
オペレーションの参照値です。

9. ソニック環境のscenario.jsonの例

以下は、ソニック環境の「scenario.json」の例です。

{
 "done": {
   "variables": {
     "lives": {
       "op": "equal",
       "reference": 2
     }
   }
 },
 "reward": {
   "variables": {
     "x": {
       "reward": 0.001
     },
     "score": {
       "reward": 1.0
     }
   }
 }
}

・done
「done」下の「condition」に「any」を指定し、完了条件のいずれかがTrueの時に完了と判定します。
「done」下の「variables」にゲーム変数「lives」「x」を指定します。「lives」は2になった時、Trueとします。「x」は9600以上になった時、Trueとします。

・ reward
「reward」下の「variables」にゲーム変数「x」「score」を指定します。
「x」はデフォルトでXの増加変化量で、その値に0.001を乗算した値を報酬とします。[score」はソニックのスコアの値を報酬とします。


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