Morikatron Engineer Blog

モリカトロン開発者ブログ

Unity ML-Agents(Release 2)+baselinesを使って学習してみる

こんにちは、モリカトロンのAIエンジニアの本間です。

Unity ML-Agentsがついに1.0メジャーアップデートされましたね!(気付けばRelease-2がリリースされていました)
今回の記事ではgym_unityというシミュレーションパッケージとOpenAI Baselinesという強化学習の実装セットを使ってサンプルプロジェクトで学習します。以前投稿したMacでUnity ML-Agents(v1.0)の環境構築という記事ではmlagents-learnというコマンドを使うことでコードを書かずに学習しましたが、今回はUnity ML-Agents gym-unityドキュメントを参考に少しだけコードを書いてみます。


検証環境

  • 機種名 : iMac (21.5-inch, 2017)
    • CPU:2.3GHz デュアルコア Core i5
    • メモリ:16GB
    • グラフィックス:Intel Iris Plus Graphics 640 1536MB
  • OS : MacOS Catalina 10.15.2
  • Unity : 2019.3.12f1
  • Python : 3.6.5
  • Unity ML-Agents : release_2

この記事は、UnityとPythonの開発構築が有り、Unity ML-Agentsのセットアップが完了している事を前提とします。

また、以下のディレクトリ構成になっている事を前提とします。

mla_test
└── ml-agents
    ├ いろいろ
    ├ 色々


まだの方は前回の記事サンプルプロジェクトを動かすまでを参考にしていただければ。


(必要なら)Unity ML-AgentsのPythonパッケージをインストール

前回の記事でUnity ML-Agentsのセットアップを行った際は、pip install mlagentsを実行する事でmlagents-learnコマンドの実行に必要なPythonパッケージをインストールしました。

今回はPythonのコードを書いてUnityアプリケーションを学習するため、その他のパッケージもインストールします。

mlagents_envsをインストール

mlagents_envs Pythonパッケージ は Unity ML-AgentsのPython APIを提供するパッケージです。 このパッケージを使う事で、Python APIを通してUnityアプリケーションとやり取り出来ます。

# 作業ディレクトリへ移動
cd mla_test

pip install -e ml-agents/ml-agents-envs

gym_unityをインストール

gym_unity Pythonパッケージ は 強化学習用のシミュレーションパッケージです。 このパッケージは、OpenAI Gymという強化学習用シミュレーションプラットフォームの仕組みを踏襲して作られています。こうする事で、OpenAI Gymを使用する既存の強化学習プログラムをそのままUnityアプリケーションの学習に使うことが出来ます。

pip install -e ml-agents/gym-unity

注意点として、Unity ML-Agents release_1 / release_2 のgym_unityはマルチエージェント学習に対応していません、マルチエージェント学習がしたい場合はmlagents_envsパッケージを使って自前で実装する必要があります。
手っ取り早くマルチエージェント学習がしたい場合、Unity ML-Agents 0.15.1 にバージョンを戻すという方法 *1もあります。

今回の記事ではrelease_2ブランチのgym_unityを使うため、シングルエージェントで学習していきます。


Unityプロジェクト(PushBlock)をビルド

f:id:morika-homma:20200601105314g:plain

1.Unity Hubから【mla_test/ml-agents/Project】を開きます

2.Unityエディタのプロジェクトウィンドウにて、【Assets/ML-Agents/Examples/PushBlock/Scenes/PushBlock】をダブルクリックで開きます。

3.学習済みモデルの設定を外します

4.【Area以外の、全てのArea(n)オブジェクト】を削除します

f:id:morika-homma:20200410113137p:plain:h400

以下のような状態になっている事を確認して下さい。

f:id:morika-homma:20200410113944p:plain:w300

※ 補足
PushBlockは、以下のように複数の学習エリアを作る事で一度に複数のエージェントを並列学習する仕組みになっています。しかし今回はシングルエージェントで学習するため、1つのエリアを残して全て削除します。

f:id:morika-homma:20200507124634g:plain

5.【ファイル > ビルド設定】をクリックし、【シーンを追加】をクリックします。

6.【ビルド】をクリックし、【PushBlock】と名前を付け、【mla_test/ml-agents/Project/】ディレクトリに保存します。

mla_test/ml-agents/Project/PushBlock.appがあれば、ビルド成功です。

(補足)PushBlockについて:

前回の記事でPushBlockの学習環境情報を記載しましたので、気になる方はそちらをご参考下さい。


OpenAI Baselinesをインストール

OpenAI Baselinesは、OpenAIが提供する強化学習の実装セットです。 沢山ある強化学習アルゴリズムのうち代表的なアルゴリズムの実装コードがあり、論文のスコアとほぼ同じスコアが出るようです。 Pythonコードからライブラリとして使うことが出来る他、コマンドから直接アルゴリズムを指定して学習する事も出来ます。

  • masterブランチがサポートしているTensorflowのバージョンは1.14~1.4のようですが、今回は2.xで学習するためtf2ブランチを使用します。
  • git cloneでローカルディレクトリに置いて使うことも出来ますが、 (今回は簡略化して)以下のコマンドでpip installします。
# (必要なら)(執筆時点の最新)tensorflow 2.2.0をインストール
pip install tensorflow==2.2.0

# baselinesインストール時に「cloudpickleのバージョンが合ってないよ!」というエラーが出るので、先にバージョンに合わせておきます
pip install cloudpickle==1.2.0

# baselinesをインストール
pip install git+git://github.com/openai/baselines.git@tf2


DQNで学習する

Unity ML-Agentsのサンプルコードを少し変更してPushBlockに対応したコードが以下です。 今回使用したコードはGitHubで公開しています、手元で学習する場合はそちらをご参照下さい。

著者の環境では以下の場所にソースコードを保存して相対パスを合わせました。
mla_test/train.py

動かしてみたところ、tf2ブランチのDQN実装ではチェックポイント保存が未実装になっていたため学習中にベストモデルを保存してくれませんでした。 そのため、学習終了時のモデル保存コードをtf2用に書き換えて追加しておきました(この保存コードを忘れると、モデルがどこにも保存されずプログラムが終了します)。masterブランチのDQN実装と同じ引数が用意してあるのに、肝心の実装は無い…これは罠ですね。

def train():
    engine_configuration_channel = EngineConfigurationChannel()
    # 時間スケールを20倍に設定
    engine_configuration_channel.set_configuration_parameters(time_scale=20.0)
    unity_env = UnityEnvironment("./ml-agents/Project/PushBlock", side_channels=[engine_configuration_channel])
    env = UnityToGymWrapper(unity_env, 0, flatten_branched=True)
    logger.configure('./logs')
    # DQNで学習
    model = deepq.learn(
        env,
        "mlp",
        seed=0,
        lr=2.5e-4,
        total_timesteps=400000,
        buffer_size=50000,
        exploration_fraction=0.05,
        exploration_final_eps=0.1,
        print_freq=20,
        train_freq=5,
        learning_starts=20000,
        target_network_update_freq=50,
        gamma=0.99,
        prioritized_replay=False,
        checkpoint_freq=1000,
        dueling=True,
        checkpoint_path=None,
        load_path="./model"
    )

    # モデルを保存
    save_path = "./model"
    ckpt = tf.train.Checkpoint(model=model)
    manager = tf.train.CheckpointManager(ckpt, save_path, max_to_keep=1)
    manager.save()


python train.py

で学習プログラムを実行すると、40万ステップ分学習した後にモデルを保存して終了します。 終了まで筆者のiMacで約40分でした。


学習済みモデルを動かす

以下のコードで、学習したモデルの動作確認が出来ます。

著者の環境では以下の場所にソースコードを保存して相対パスを合わせました。
mla_test/play.py

def play():
    engine_configuration_channel = EngineConfigurationChannel()
    # 時間スケールを10倍に設定
    engine_configuration_channel.set_configuration_parameters(time_scale=10.0)
    unity_env = UnityEnvironment("./ml-agents/Project/PushBlock", side_channels=[engine_configuration_channel])
    env = UnityToGymWrapper(unity_env, 0, flatten_branched=True)
    # モデル読み込み
    model = deepq.learn(env, "mlp", total_timesteps=0, load_path="./model")

    obs = env.reset()
    obs = np.expand_dims(np.array(obs), axis=0)

    while True:
        action, _, _, _ = model.step(tf.constant(obs))
        action = action[0].numpy()
        obs, rew, done, _ = env.step(action)
        if done:
            obs = env.reset()
        obs = np.expand_dims(np.array(obs), axis=0)


python play.py

で動作確認プログラムを実行します。 そしてこちらがプログラムを実行した時の動作画面です。

f:id:morika-homma:20200603150220g:plain
PushBlock動作画面(時間スケール10倍)

動作画面を見ると、時々失敗しつつも効率よく左右上下の壁にブロックをぶつけ回してます。


最後に

今回はgym_unityというシミュレーションパッケージとOpenAI Baselinesという強化学習の実装セットを使って学習してみました。前回の記事で使用したmlagents-learnコマンドと違い、今回はpythonコードを書いて学習しているため、baselinesのコードを書き換える事で機能の変更追加する事も出来ます(コレがうれしい)。
次の記事ではGoogle Colaboratoryを使ってブラウザ上でUnity ML-Agentsのサンプルプロジェクトを学習してみたいと思います。

最後まで読んでいただきありがとうございました。

*1:0.15.1のgym_unityの場合、multiagent=trueにするだけでマルチエージェント学習出来る