メインコンテンツへ移動
AIチュートリアル

Ultimate SFighterAIチュートリアル:PPOで『ストリートファイターII』をクリアできるエージェントを訓練

このチュートリアルでは、Ultimate SFighterAIの設定、事前学習済みNatureCNNモデルの実行、連続クリア能力の評価、PPOによる再訓練または継続訓練、TensorBoardを使用した訓練曲線の分析方法を紹介します。

Ultimate SFighterAIチュートリアル:PPOで『ストリートファイターII』をクリアできるエージェントを訓練

プロジェクト概要

Ultimate SFighterAI は、『ストリートファイターII ダッシュターボ』を対象とした深層強化学習プロジェクトです。プレイヤーキャラクターにリュウを使用し、PPO アルゴリズムで NatureCNN モデルを訓練します。訓練範囲は全 12 ステージに拡張されています。

モデルの意思決定入力はゲーム画面の RGB ピクセルのみで、キャラクターの位置、動作状態、体力を直接読み取ることはありません。訓練環境では、メモリ変数内の agent_hp と enemy_hp のみを使用して報酬を計算し、勝敗を判定します。

プロジェクトには訓練済みモデルの重みと訓練記録が含まれているため、AI 同士の対戦をそのまま観戦したり、実験を再現したり、並列数を調整したり、既存モデルを基に訓練を継続したりできます。

主な機能と実装上の特徴

  • 全 12 ステージに対応:各ステージを独立したエミュレーターで実行し、同じ NatureCNN モデルを共同で訓練します。
  • 純粋な視覚判断:処理済みのゲーム画面に基づき、移動、攻撃、必殺技を選択します。
  • 27 種類の離散アクション:ニュートラル、移動、通常攻撃、しゃがみ攻撃に加え、左右方向に対応した波動拳、竜巻旋風脚、昇龍拳などを含みます。
  • PPO 強化学習:Stable-Baselines3 の PPO アルゴリズムを基盤として訓練します。
  • 複数の評価モード:ステージごとのセーブデータ読み込みテスト、3 ラウンド中 2 ラウンド先取、単一 KO 評価、1 ステージ目からの連続クリアに対応します。
  • 事前訓練済みモデル:デフォルトの重みは logs/trained_models/ppo_ryu.zip にあります。
  • 訓練の可視化:TensorBoard で報酬の変化やモデル更新の記録を確認できます。
  • 複数デバイスに対応:訓練および推論のパラメーターは auto、cpu、cuda、mps に対応します。

画面の前処理

元のゲーム画面に中央クロップ、動きのある前景の抽出、リサイズを行い、最終的に 84×84×3 のモデル入力を生成します。動きのある前景の抽出には、t-16、t-8、t の 3 時点におけるグレースケール差分を使用し、背景の明るさに 0.35 を乗算したうえで、R、G、B の 3 チャンネルを組み合わせます。この処理により、モデルはキャラクターの移動や攻撃を認識しやすくなります。

報酬の仕組み

報酬は主に、双方の体力変化、ノックアウト結果、時間コストによって構成されます。ダメージ報酬は次のように計算します。

0.01 × (3 × 相手の減少体力 − 自分の減少体力)

相手をノックアウトした場合の報酬は次のとおりです。

0.01 × (176 + 自分の残り体力)

自分がノックアウトされた場合のペナルティは次のとおりです。

0.01 × (176 + 相手の残り体力)

また、実際にアクションを実行するたびに時間ペナルティが差し引かれます。デフォルト値は 0.0005 です。

プロジェクト構成

  • data/:12 ステージの開始時セーブデータ、ゲーム内メモリ変数の定義、シナリオ設定を保存します。
  • main/train.py:全ステージの並列訓練と訓練の再開を担当します。
  • main/test.py:ステージごとのテストと連続クリア評価を担当します。
  • main/env_utils.py:ROM の設定と環境の構築を処理します。
  • main/custom_wrappers.py:画面処理、アクションマッピング、報酬計算を実装します。
  • logs/trained_models/ppo_ryu.zip:プロジェクトで提供される訓練済みモデルです。
  • logs/:訓練過程の TensorBoard 記録を含みます。
  • requirements.txt:Python 依存関係の一覧です。

インストールと環境設定

ステップ 1:Python 環境を準備する

Python 3.10 の使用を推奨します。README に記載された検証環境は macOS、Apple Silicon、Python 3.10.20 で、CPU と Apple MPS の両方の経路を検証済みです。その他のプラットフォームでは、Stable-Retro と PyTorch の公式インストール手順を参照してください。

プロジェクトのルートディレクトリで仮想環境を作成して有効化し、依存関係をインストールします。

python3.10 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt

Windows ユーザーは、次のコマンドで仮想環境を有効化できます。

.venv\Scripts\activate

Anaconda で Python 3.10 環境を作成してから、requirements.txt の依存関係をインストールすることもできます。主な依存関係は Gymnasium、Stable-Retro、Stable-Baselines3 です。

ステップ 2:ゲーム ROM を準備する

Stable-Retro はゲーム ROM を提供しておらず、本プロジェクトにも ROM は含まれていません。合法的な方法で『ストリートファイターII ダッシュターボ』米国版の対応 ROM を入手してください。

ROM を入手したら、環境変数で絶対パスを指定できます。macOS または Linux では次を実行します。

export SF2_ROM_PATH="/absolute/path/to/your/rom.md"

Windows PowerShell では次を使用します。

$env:SF2_ROM_PATH = "C:\path\to\your\rom.md"

別の方法として、ROM をプロジェクト内のデフォルトの場所に配置できます。

data/street-fighter-ii-special-champion-edition-usa.md

訓練およびテストプログラムが ROM を自動的にインポートします。現在の Python 環境の Stable-Retro に ROM がすでにインポートされている場合は、そのまま実行できます。

ステップ 3:ステージデータを確認する

data/ ディレクトリ内の 12 個の .state ファイルには、それぞれ第 1 ステージから第 12 ステージまでの開始時状態が保存されています。data.json と scenario_full_frame.json は、ゲーム内メモリ変数とシナリオ設定を定義します。プログラムはこれらのファイルを直接読み込むため、Stable-Retro のインストールディレクトリにコピーする必要はありません。

訓練済みモデルを実行する

全 12 ステージをステージごとにテストする

環境設定が完了したら、プロジェクトのルートディレクトリで次を実行します。

python -m main.test --episodes 1

プログラムは第 1 ステージから第 12 ステージまでの開始時セーブデータを順番に読み込み、各ステージでデフォルトの 3 ラウンド中 2 ラウンド先取方式を使用します。--episodes 1 は評価を 1 周実行することを意味します。この引数を省略した場合、デフォルトで 10 周テストします。

いずれかのステージに失敗しても、プログラムは後続ステージのテストを続行します。ターミナルには各ステージの勝敗、報酬、ステージ勝率、および 1 回の評価で 12 ステージすべてに勝利した割合が出力されます。

画面を無効にして評価結果に集中する

対戦を表示する必要がない場合は、レンダリングを無効にし、CPU 推論を明示的に指定できます。

python -m main.test --episodes 1 --no-render --device cpu

レンダリングを無効にすると、画面表示による余分な負荷を減らせるため、大量の評価に適しています。

第 1 ステージから連続してクリアする

AI がゲーム本来の流れに従って次の対戦相手に挑戦する様子を確認するには、次を実行します。

python -m main.test --episodes 1 --no-load-level-saves

このモードでは開始時に第 1 ステージのセーブデータのみを読み込み、その後はゲームを通常どおり進行させます。途中で失敗すると、その試行は終了します。プログラムには、挑戦したステージの勝率と全ステージクリア率が出力されます。

ステージごとのテストにおける「全勝」は、12 個の独立したステージセーブデータすべてで評価に合格することを意味します。一方、「全ステージクリア率」は、1 回の連続したプレイで 12 ステージすべてをクリアすることを求めます。両者の意味は異なります。

よく使うテストパラメーター

  • --model-path PATH:PPO モデルを指定します。デフォルトは logs/trained_models/ppo_ryu.zip です。
  • --episodes N:ステージごとの評価回数または連続クリアの試行回数を設定します。デフォルト値は 10 です。
  • --no-render:ゲーム画面を無効にします。
  • --no-load-level-saves:ステージごとにセーブデータを読み込まず、第 1 ステージから連続して挑戦します。
  • --reset-round:ステージごとのテストで、デフォルトの 3 ラウンド中 2 ラウンド先取ではなく、1 回の KO を評価単位にします。
  • --device auto/cpu/cuda/mps:モデルの推論デバイスを選択します。デフォルト値は auto です。
  • --speed N:表示フレーム数を減らして可視化を高速化します。デフォルト値は 4 です。

独自モデルを訓練する

小規模な設定から始める

デフォルトの訓練設定は非常に高いリソースを必要とします。初回実行時は、各ステージでシミュレーターを 1 台だけ起動し、より小さいバッチを使用することを推奨します。

python -m main.train --envs-per-level 1 --batch-size 256 --log-dir runs/ryu

プロジェクトには 12 ステージが含まれているため、--envs-per-level 1 は合計 12 台の並列シミュレーターを実行することを意味します。まず ROM、環境構築、デバイス、ログ出力が正常に動作することを確認してから、並列数を段階的に増やしてください。

デフォルトの訓練規模を理解する

python -m main.train を直接実行すると、各ステージでデフォルト 64 台、合計 768 個の並列環境が起動します。デフォルトの n-steps=128 と組み合わせると、1 回の PPO 更新で 98,304 サンプルを収集し、完全な訓練目標は 7 億ステップになります。

デフォルト設定には十分な CPU とメモリが必要で、一般的なコンピューターでの初回テストには適していません。実際のハードウェアに応じて、--envs-per-level、--batch-size、または総訓練ステップ数を減らしてください。

よく使う訓練パラメーター

  • --envs-per-level N:各レベルの並列環境数。指定しない場合は、各レベル64個です。
  • --total-timesteps N:今回のトレーニング総ステップ数。追加学習時は追加ステップ数を表し、デフォルト値は700000000です。
  • --n-steps N:各シミュレーターが1回の更新前に収集するステップ数。デフォルト値は128です。
  • --batch-size N:PPO更新のバッチサイズ。デフォルト値は8192です。
  • --n-epochs N:各バッチのサンプルデータに対する学習エポック数。デフォルト値は3です。
  • --learning-rate N:学習率。デフォルト値は0.0002です。
  • --device auto/cpu/cuda/mps:学習デバイスを選択します。デフォルト値はmpsです。
  • --log-dir PATH:モデルと学習曲線の出力先。デフォルトはlogs/ALL_MOTION_SIMULTANEOUSです。

事前学習済み重みからの追加学習

提供されているPPO重みから追加学習を開始できます。以下のコマンドは100万ステップ分の学習を追加し、結果を新しいディレクトリに書き込みます。

python -m main.train \
  --resume-model logs/trained_models/ppo_ryu.zip \
  --envs-per-level 1 --batch-size 256 \
  --total-timesteps 1000000 --log-dir runs/ryu-resume

追加学習時、--total-timestepsは今回追加で実行する学習ステップ数を表し、旧モデルの学習量を含む累計目標ではありません。

TensorBoardで学習曲線を確認する

プロジェクトには学習ログの記録機能が組み込まれています。TensorBoardを起動します。

tensorboard --logdir=logs

その後、ブラウザでhttp://localhost:6006/を開くと、報酬の変化やモデル更新に関する曲線を確認できます。

自分で実行した学習のログを確認する場合は、ディレクトリを置き換えるだけです。

tensorboard --logdir=runs/ryu

高度な使用方法に関する提案

  1. まず検証してから拡張する:最初は各レベル1環境で短時間の学習を行い、ROMの読み込み、セーブデータの読み込み、ログの書き込みに問題がないことを確認してから、並列シミュレーター数を増やします。
  2. プラットフォームに応じてデバイスを指定する:Apple Siliconではmps、NVIDIA GPUに対応した環境ではcudaを試せます。それ以外の場合はcpuまたはautoを使用します。READMEで検証しているのはmacOS Apple Silicon環境であり、その他のプラットフォームではPyTorchとStable-Retroの要件に応じて設定してください。
  3. 2種類の評価を区別する:レベルごとのセーブデータテストは各対戦相手のパフォーマンス分析に適しており、連続ステージ攻略はゲーム全体の流れに近い評価です。結果を報告する際は、使用したモードを明記してください。
  4. レンダリングなしで一括評価する:複数ラウンドの統計を取る場合は--no-renderを追加し、エージェントの動作を確認するときだけ画面表示を有効にします。
  5. 実験ごとに独立したディレクトリを使用する:--log-dirで異なるパラメータの組み合わせごとにディレクトリを作成し、学習記録の上書きを防ぎます。TensorBoardで比較する際にも便利です。
  6. 完全なコマンドオプションを確認する:学習スクリプトとテストスクリプトには、いずれもヘルプ情報が用意されています。
python -m main.train --help
python -m main.test --help

モジュール形式に加えて、プロジェクトではスクリプトを直接実行することもできます。

python main/train.py
python main/test.py

まとめ

Ultimate SFighterAIは、ピクセル入力、アクションマッピング、報酬設計、PPO、複数レベルの並列環境を組み合わせ、完全な格闘ゲームエージェントを構築する方法を示しています。最も確実な導入手順は、まずROMを設定して事前学習済みモデルを実行し、次に並列度を低くして学習を再現し、最後に追加学習、デバイス選択、TensorBoardによる分析を通じて実験規模を段階的に拡大することです。

このプロジェクトはApache License 2.0に基づいて公開されており、Gymnasium、Stable-Retro、Stable-Baselines3などのオープンソースコンポーネントを使用しています。