概要

Unity ML-Agents(以下 ML-Agents)をクラウド上で動作させるのに適切な環境を探しています。
そのなかで、Google Cloud Machine Learning Engine(以下 Cloud ML)上で動作するものなのか、検証してみました。

ML-AgentsはTensorflowを利用した強化学習ができるライブラリです。
なので、Tensorflowなどの機械学習実行エンジンであるCloud MLで動かないわけがない。(はず)

Google Cloud Machine Learning Engineとは

Google Cloud Machine Learning Engine は”エンジン”であって開発環境ではない ~制約に気を付けよう~
https://www.gixo.jp/blog/10960/

ML Engine を一言で説明するなら「機械学習を実行するためのクラウドサービス」です。そのため、DataRobotなどの他のクラウドサービスのようにサービス上で開発は行えません。

Unity ML-Agents

Unity Machine Learning Agentsベータ版
https://unity3d.com/jp/machine-learning

Unity ML-Agentsは、新世代のロボット、ゲームをはじめさまざまな分野において、迅速かつ効率的に新しいAIアルゴリズムの開発を行い、テストする柔軟な方法を提供します。

手順

前提条件

Cloud MLやUnity、ML-Agentsの環境構築が済んでいる前提です。
まだ環境がないという方は下記をご参考ください。

MacでCloud Machine Learning Engineを利用してみる
https://cloudpack.media/42306

Macでhomebrewを使ってUnityをインストールする(Unity Hub、日本語化対応)
https://cloudpack.media/42142

MacでUnity ML-Agentsの環境を構築する
https://cloudpack.media/42164

Unityでアプリをビルドする

ML-Agentsでは実際にUnityアプリを動作させつつ強化学習がすすみます。
MacであればMac用、WindowsであればWindows用にアプリをビルドするわけですが、今回はCloud ML上で動作させる必要があるので、Linux用のビルドとなります。

アプリはML-Agentsに含まれる[3DBall]アプリを利用します。
手順は下記記事のDockerに関する手順以外をすすめてビルドします。

MacでUnity ML-AgentsをDockerで動作させる
https://cloudpack.media/42285

unity-volume フォルダに以下ファイルとフォルダが用意できたと思います。

> ll ml-agents/unity-volume/
3DBall.x86_64
3DBall_Data

Cloud ML上で実行するための準備

Cloud MLで実行するための下準備です。

変数設定

Cloud Storageのバケット名やCloud MLを利用するリージョンなどを変数に設定します。
BUCKET_NAMEJOB_NAMEは任意で指定してください。

fish

> set -x BUCKET_NAME 任意のバケット名
> set -x REGION us-central1
> set -x JOB_NAME gcp_ml_cloud_run_01

bash

> export BUCKET_NAME=任意のバケット名
> export REGION=us-central1
> export JOB_NAME=gcp_ml_cloud_run_01

ハイパーパラメータの指定

今回は動作確認が目的となりますので、学習のステップを少なくします。
ML-Agentsライブラリにtrainer_config.yamlというハイパーパラメータを指定するYAMLがあるので、そちらでmax_stepsの指定をして5,000ステップ実行して終了するようにします。

> cd 任意のディレクトリ/ml-agents

> vi python/trainer_config.yaml

Ball3DBrain:
    normalize: true
    batch_size: 64
    buffer_size: 12000
    summary_freq: 1000
    time_horizon: 1000
    lambd: 0.99
    gamma: 0.995
    beta: 0.001
+   max_steps: 5000

アプリとハイパーパラメータファイルのアップロード

Cloud MLでは学習に利用するファイルなどをCloud Storageに置いて利用することになります。
今回はUnityアプリのファイル・フォルダとハイパーパラメータ設定ファイルをCloud Storageにコピーしておきます。
また、Linux用ビルドはDataフォルダがないとアプリが起動しません。
フォルダのままだと取り回しが面倒なので、ZIPファイルに圧縮しておきます。

> cd 任意のディレクトリ/ml-agents

# Dataフォルダの圧縮
> zip -r 3DBall_Data.zip unity-volume/3DBall_Data/

# Cloud Storageのバケットにコピー

# Unityアプリファイル
> gsutil cp unity-volume/3DBall.x86_64 gs://$BUCKET_NAME/data/3DBall.x86_64

> gsutil cp unity-volume/3DBall_Data.zip gs://$BUCKET_NAME/data/3DBall_Data.zip

# ハイパーパラメータ設定ファイル
> gsutil cp python/trainer_config.yaml gs://$BUCKET_NAME/data/trainer_config.yaml

学習実行ファイルの準備

ML-Agentsに含まれているpython/learn.pyが学習を開始するためのファイルになりますが、これをCloud MLで動作できるように以下の準備をします。

  • Pythonのパッケージ化
  • Cloud Storage連携実装追加
Pythonのパッケージ化

Cloud MLにPythonでパッケージ化されたファイルをアップして実行するので、その準備をします。

# Pythonフォルダのsetup.pyがCloud MLで動作するようにファイルを追加
> touch python/MANIFEST.in
> vi python/MANIFEST.in
+include requirements.txt

# learn.py実行用のパッケージ作成
> mkdir python/tasks
> touch python/tasks/__init__.py
> cp python/learn.py python/tasks/learn.py
learn.pyのカスタマイズ

learn.pyにCloud Storageからファイルを取得、学習結果をCloud Storageへ保存する実装を追加します。
今回、ファイル名を固定していますが、とりあえず動作検証のためなので、あしからず。
Cloud Storageからのファイル取得・アップにgsutilコマンドを利用していますが、ここはPythonで実装してもOKです。
手抜きできるところは徹底的に^^

> vi python/tasks/learn.py

python/tasks/learn.py

 # import追加
    import shlex
    import subprocess
    import zipfile    
    # import追加ここまで

    (略)

    # General parameters
    (略)
    fast_simulation = not bool(options['--slow'])
    no_graphics = options['--no-graphics']

    # ここから追加
    # Stackdriver Loggingでログ確認できるようにする
    logging.basicConfig(level=logging.INFO)

    # Cloud Storageのパス指定
    trainer_config_file = 'gs://任意のバケット名/data/trainer_config.yaml'
    app_file = 'gs://任意のバケット名/data/3DBall.x86_64'
    app_data_file = 'gs://任意のバケット名/data/3DBall_Data.zip'

    # 実行環境のに保存する際のパスを指定
    file_name = env_path.strip().replace('.x86_64', '')
    cwd = os.getcwd() + '/'
    app_data_local_dir = os.path.join(cwd, file_name + '_Data')
    app_local_file = os.path.join(cwd, file_name + '.x86_64')
    app_data_local_file = app_data_local_dir + '.zip'

    # Cloud Storageからコピー、Cloud ML環境だとgsutilが利用できて楽
    logger.info(subprocess.call(['gsutil', 'cp', trainer_config_file, cwd]))
    logger.info(subprocess.call(['gsutil', 'cp', app_file, cwd]))
    logger.info(subprocess.call(['gsutil', 'cp', app_data_file, cwd]))

    # Unityアプリ動作用にDataファイルを展開する
    with zipfile.ZipFile(app_data_local_file) as existing_zip:
        existing_zip.extractall(cwd)

    # Unityアプリが実行できるように権限を付与する
    logger.info(subprocess.call(shlex.split('chmod u+x ' + app_local_file)))
    # ここまで追加

    (略)

    tc.start_learning()

    # ここから追加
    # モデルファイルをCloud Storageへアップ
    # TODO: 圧縮する
    models_local_path = './models/{run_id}'.format(run_id=run_id)
    models_storage_path = 'gs://任意のバケット名/{run_id}/models'.format(run_id=run_id)
    logger.info(subprocess.call(['gsutil', 'cp', '-r', models_local_path, models_storage_path]))
    # ここまで追加

パッケージ作成
Cloud MLの操作に利用するgcloudコマンドにはパッケージを自動作成する機能もありますが、ここでは手動でパッケージングします。

> cd python
> python setup.py sdist
(略)
Writing unityagents-0.4.0/setup.cfg
Creating tar archive
removing 'unityagents-0.4.0' (and everything under it)

> ll dist
total 96
-rw-r--r--  1 user  users    45K  8  6 11:14 unityagents-0.4.0.tar.gz

Cloud MLで実行してみる

さて、下準備が完了しましたので、Cloud MLへジョブ登録して学習を実行してみましょう。

パラメータ指定に--がありますが、これ以降のパラメータが--module-nameで指定したlearn.pyにパラメータとして渡されるので、取ってはいけません。(1敗)

> cd 任意のディレクトリ/ml-agents
> gcloud ml-engine jobs submit training $JOB_NAME \
    --python-version=3.5 \
    --runtime-version 1.8 \
    --module-name tasks.learn \
    --packages python/dist/unityagents-0.4.0.tar.gz \
    --region $REGION \
    --staging-bucket gs://$BUCKET_NAME \
    -- \
    3DBall \
    --run-id $JOB_NAME \
    --train

Job [gcp_ml_cloud_run_01] submitted successfully.
Your job is still active. You may view the status of your job with the command

  $ gcloud ml-engine jobs describe gcp_ml_cloud_run_01

or continue streaming the logs with the command

  $ gcloud ml-engine jobs stream-logs gcp_ml_cloud_run_01
jobId: gcp_ml_cloud_run_01
state: QUEUED


Updates are available for some Cloud SDK components.  To install them,
please run:
  $ gcloud components update

はい。

ジョブが登録されたか確認しましょう。

> gcloud ml-engine jobs describe $JOB_NAME

createTime: '2018-08-06T02:20:53Z'
etag: sm-_r3BqJBo=
jobId: gcp_ml_cloud_run_01
startTime: '2018-08-06T02:21:24Z'
state: RUNNING
trainingInput:
  args:
  - 3DBall
  - --run-id
  - gcp_ml_cloud_run_01
  - --train
  packageUris:
  - gs://任意のバケット名/gcp_ml_cloud_run_01/xxxx/unityagents-0.4.0.tar.gz
  pythonModule: tasks.learn
  pythonVersion: '3.5'
  region: us-central1
  runtimeVersion: '1.8'
trainingOutput:
  consumedMLUnits: 0.01

ジョブ実行されたかログを見てみましょう。

> gcloud ml-engine jobs stream-logs $JOB_NAME

(略)
INFO    2018-08-06 11:22:50 +0900       master-replica-0                List of nodes to export :
INFO    2018-08-06 11:22:50 +0900       master-replica-0                        action
INFO    2018-08-06 11:22:50 +0900       master-replica-0                        value_estimate
INFO    2018-08-06 11:22:50 +0900       master-replica-0                        action_probs
INFO    2018-08-06 11:22:51 +0900       master-replica-0                Restoring parameters from ./models/gcp_ml_cloud_run_01/model-5001.cptk
INFO    2018-08-06 11:22:51 +0900       master-replica-0                Froze 16 variables.
(略)
INFO    2018-08-06 11:22:54 +0900       master-replica-0                Module completed; cleaning up.
INFO    2018-08-06 11:22:54 +0900       master-replica-0                Clean up finished.
INFO    2018-08-06 11:22:54 +0900       master-replica-0                Task completed successfully.
INFO    2018-08-06 11:27:32 +0900       service         Job completed successfully.

はい。

これで、ML-AgentsがCloud ML上で実行されて、modelsフォルダに結果ファイルが出力されているはずです。
learn.pymodelsフォルダをCloud Storageにコピーしてるので、フォルダをローカルにコピーして、Unityアプリにbytesファイルを組み込んで動作させることができます。

> gsutil ls gs://任意のバケット名/$JOB_NAME/models

gs://任意のバケット名/gcp_ml_cloud_run_01/models/3DBall_gcp_ml_cloud_run_01.bytes
gs://任意のバケット名/gcp_ml_cloud_run_01/models/checkpoint
gs://任意のバケット名/gcp_ml_cloud_run_01/models/model-5001.cptk.data-00000-of-00001
gs://任意のバケット名/gcp_ml_cloud_run_01/models/model-5001.cptk.index
gs://任意のバケット名/gcp_ml_cloud_run_01/models/model-5001.cptk.meta
gs://任意のバケット名/gcp_ml_cloud_run_01/models/raw_graph_def.pb

tensorboardでも結果が確認できます。

> gsutil cp -r gs://任意のバケット名/$JOB_NAME/models ローカルの任意のフォルダ/
> tensorboard --logdir=ローカルの任意のフォルダ/models

実行できることが確認できました。やったぜ^^

あとは、learn.pyをもう少し実用的に改修したり、Cloud Pub/Subや、Cloud Functionsなどを利用すれば、Cloud StorageにUnityアプリをアップすれば、自動的に強化学習が実行される素敵環境が構築できそうです^^

参考

Google Cloud Machine Learning Engine は”エンジン”であって開発環境ではない ~制約に気を付けよう~
https://www.gixo.jp/blog/10960/

Unity Machine Learning Agentsベータ版
https://unity3d.com/jp/machine-learning

MacでCloud Machine Learning Engineを利用してみる
https://cloudpack.media/42306

Macでhomebrewを使ってUnityをインストールする(Unity Hub、日本語化対応)
https://cloudpack.media/42142

MacでUnity ML-Agentsの環境を構築する
https://cloudpack.media/42164

MacでUnity ML-AgentsをDockerで動作させる
https://cloudpack.media/422854

トレーニング アプリケーションのパッケージング
https://cloud.google.com/ml-engine/docs/tensorflow/packaging-trainer?hl=ja

【mac】zipファイル操作コマンド
https://qiita.com/griffin3104/items/948e38aab62bbb0d0610

Linuxの権限確認と変更(超初心者向け)
https://qiita.com/shisama/items/5f4c4fa768642aad9e06

17.5.1. subprocess モジュールを使う
https://docs.python.jp/3/library/subprocess.html

CloudMLからgoogle cloud storageのファイルにアクセスする
https://qiita.com/mikebird28/items/543581ef04476a76d3e0

Google Cloud ML Engine 上でPythonを実行する時のコツ
https://rooter.jp/ml/google-cloud-ml-engine-python-tips/

Pythonでzipファイルを圧縮・解凍するzipfile
https://note.nkmk.me/python-zipfile/

gsutilコマンド全部試したので解説する(part1)
https://www.apps-gcp.com/gsutil-command-explanation-part1/

元記事はこちら

Google Cloud Machine Learning EngineでUnity ML-Agentsを動かす