Google Kubernetes EngineでUnity ML-Agentsを動かしてみる(V0.5.0対応)

## 概要

Unity ML-AgentsはDockerでも動作させることができるので、Google Kubernetes Engine(GKE)でも動作させることができるはず！と検証してみました。

Google Kubernetes Engineについては下記をご参考ください。

Google KUBERNETES ENGINE
https://cloud.google.com/kubernetes-engine/?hl=ja

Unity ML-Agentsについては下記をご参考ください。

MacでUnity ML-Agentsの環境を構築する(v0.5.0対応)
https://qiita.com/kai_kou/items/6478fa686ce1af5939d8

DockerでUnity ML-Agentsを動作させる(v0.5.0対応)
https://qiita.com/kai_kou/items/df3f3518a5a27b66f617


## 準備

下記記事を参考に進めました。

GKEを使ったバッチジョブ実行
http://otiai10.hatenablog.com/entry/2017/12/19/162430


Dockerのインストールは済んでいる前提です。

今回の手順で利用したのはMacでDockerバージョンは以下となります。

```sh
> docker --version
Docker version 18.06.1-ce, build e68fc7a
```


```gcloud``` (Cloud SDK)のインストールがまだの場合、下記をご参考ください。
https://cloud.google.com/sdk/downloads?hl=ja

```kubectl``` のインストールと初期化は下記をご参考ください。
https://cloud.google.com/kubernetes-engine/docs/quickstart

```kubectl``` コマンドはDockerアプリでKubernetesが有効化するとコマンドが有効化されるようです。


GCPの設定については、上記記事の[gcloud のデフォルト設定を構成する]まで進めている前提です。


## Unity ML-Agentsのダウンロード

Unity ML-Agentsのソースを取得します。

```sh
> mkdir 任意のディレクトリ
> cd 任意のディレクトリ
> git clone https://github.com/Unity-Technologies/ml-agents.git
```

## Dockerイメージの用意

Unity ML-Agentsに含まれているDockerfileを利用してDockerイメージを作成します。

今回は、強化学習させるUnityアプリをイメージに含めてしまいます。
本来であれば、Unityアプリやハイパーパラメータファイルはコンテナ作成時にCloud Storageなどから取ってくるべきですが、検証のため割愛します。

Unityアプリのビルドについては下記記事をご参考ください。

DockerでUnity ML-Agentsを動作させる(v0.5.0対応)
https://qiita.com/kai_kou/items/df3f3518a5a27b66f617

```sh
> cd ml-agents
> ls ml-agents/
3DBall.x86_64       README.md           requirements.txt    tests
3DBall_Data         mlagents            setup.py            trainer_config.yaml
```

```3DBall.x86_64``` と```3DBall_Data``` がLinuxビルドしたUnityアプリ、```trainer_config.yaml``` がハイパーパラメータファイルとなります。


Unityアプリとハイパーパラメータファイルが準備できたら、イメージを作成します。

```sh
> docker build -t unity_ml_agents_on_gke .
```

イメージは、GKEで利用できるように、Google Container RegistryにPUSHします。

プライベートDocker RegistryをGoogle Container Registry で構築
https://qiita.com/zum/items/1904ccd280879ca481c5

PUSHするために、タグを指定します。

```sh
> docker tag unity_ml_agents_on_gke:latest gcr.io/[GCPのプロジェクトID]/unity_ml_agents_on_gke
```

タグが指定できたか確認しておきます。

```sh
> docker images
REPOSITORY                                             TAG                 IMAGE ID            CREATEDSIZE
gcr.io/[GCPのプロジェクトID]/unity_ml_agents_on_gke       latest              fd69fd69de11        8 days ago904MB
```

Google Container RegistryにPUSHします。

```sh
> gcloud docker -- push gcr.io/[GCPのプロジェクトID]/unity_ml_agents_on_gke
(略)
latest: digest: sha256:xxxxxx size: 3044
```
はい。
これで、GKEから利用できるDockerイメージの準備ができました。


## コンテナクラスタを作成する

続いて、GKEでコンテナクラスタを作成します。

```sh
> gcloud container clusters create unity-ml-agents-on-gke
```

```unity-ml-agents-on-gke``` はクラスタ名となりますので、任意の名称でOKです。

クラスタが作成できたら、ローカル環境から利用できるように、credentialsをfetchします。

```sh
> gcloud container clusters list

NAME                        LOCATION           MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
unity-ml-agents-on-gke      asia-northeast1-a  1.9.7-gke.6     xxx.xxx.xxx.xxx   n1-standard-1  1.9.7-gke.6   3    RUNNING
```

```xxx.xxx.xxx.xxx``` はIPアドレスになります。


## Unity ML-Agentsで強化学習を実行する

Unity ML-Agentsで強化学習を実行するために作成したクラスタコンテナでジョブ実行します。

```sh
> touch job.yaml
```


```yaml:job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: unity-ml-agents-on-gke-01
spec:
  template:
    spec:
      containers:
      - name: unity-ml-agents-on-gke
        image: gcr.io/[GCPのプロジェクトID]/unity_ml_agents_on_gke:latest
        command: ["mlagents-learn", "trainer_config.yaml", "--env", "3DBall", "--train"]
      restartPolicy: OnFailure
```

```metadata.name``` はジョブ名になります。重複しているとエラーになるので、複数回実行する場合には名前を変更します。
```containers.name``` にはクラスタ名を指定します。

ジョブ実行してみます。

```sh
> kubectl create -f job.yaml

job.batch "unity-ml-agents-on-gke-01" created
```

登録できたら、ジョブ情報を見てみます。

```sh
> kubectl describe jobs/unity-ml-agents-on-gke-01

Name:           unity-ml-agents-on-gke-01
Namespace:      default
Selector:       controller-uid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Labels:         controller-uid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
                job-name=unity-ml-agents-on-gke-01
Annotations:    <none>
Parallelism:    1
Completions:    1
Start Time:     Fri, 21 Sep 2018 14:57:02 +0900
Pods Statuses:  1 Running / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  controller-uid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
           job-name=unity-ml-agents-on-gke-01
  Containers:
   unity-ml-agents-on-gke:
    Image:      gcr.io/[GCPのプロジェクトID]/unity_ml_agents_on_gke:latest
    Port:       <none>
    Host Port:  <none>
    Command:
      mlagents-learn
      trainer_config.yaml
      --env
      3DBall
      --train
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age   From            Message
  ----    ------            ----  ----            -------
  Normal  SuccessfulCreate  6s    job-controller  Created pod: unity-ml-agents-on-gke-01-c9fvg
```

```sh
> kubectl logs jobs/unity-ml-agents-on-gke-04

INFO:mlagents.trainers:{'--curriculum': 'None',
 '--docker-target-name': 'None',
 '--env': '3DBall',
 '--help': False,
 '--keep-checkpoints': '5',
 '--lesson': '0',
 '--load': False,
 '--no-graphics': False,
 '--num-runs': '1',
 '--run-id': 'ppo',
 '--save-freq': '50000',
 '--seed': '-1',
 '--slow': False,
 '--train': True,
 '--worker-id': '0',
 '<trainer-config-path>': 'trainer_config.yaml'}


                        ▄▄▄▓▓▓▓
                   ╓▓▓▓▓▓▓█▓▓▓▓▓
              ,▄▄▄m▀▀▀'  ,▓▓▓▀▓▓▄                           ▓▓▓  ▓▓▌
            ▄▓▓▓▀'      ▄▓▓▀  ▓▓▓      ▄▄     ▄▄ ,▄▄ ▄▄▄▄   ,▄▄ ▄▓▓▌▄ ▄▄▄    ,▄▄
          ▄▓▓▓▀        ▄▓▓▀   ▐▓▓▌     ▓▓▌   ▐▓▓ ▐▓▓▓▀▀▀▓▓▌ ▓▓▓ ▀▓▓▌▀ ^▓▓▌  ╒▓▓▌
        ▄▓▓▓▓▓▄▄▄▄▄▄▄▄▓▓▓      ▓▀      ▓▓▌   ▐▓▓ ▐▓▓    ▓▓▓ ▓▓▓  ▓▓▌   ▐▓▓▄ ▓▓▌
        ▀▓▓▓▓▀▀▀▀▀▀▀▀▀▀▓▓▄     ▓▓      ▓▓▌   ▐▓▓ ▐▓▓    ▓▓▓ ▓▓▓  ▓▓▌    ▐▓▓▐▓▓
          ^█▓▓▓        ▀▓▓▄   ▐▓▓▌     ▓▓▓▓▄▓▓▓▓ ▐▓▓    ▓▓▓ ▓▓▓  ▓▓▓▄    ▓▓▓▓`
            '▀▓▓▓▄      ^▓▓▓  ▓▓▓       └▀▀▀▀ ▀▀ ^▀▀    `▀▀ `▀▀   '▀▀    ▐▓▓▌
               ▀▀▀▀▓▄▄▄   ▓▓▓▓▓▓,                                      ▓▓▓▓▀
                   `▀█▓▓▓▓▓▓▓▓▓▌
                        ¬`▀▀▀█▓


Found path: /ml-agents/3DBall.x86_64
Mono path[0] = '/ml-agents/3DBall_Data/Managed'
Mono config path = '/ml-agents/3DBall_Data/MonoBleedingEdge/etc'
Preloaded 'libgrpc_csharp_ext.x64.so'
Preloaded 'liblibtensorflow.so'
Preloaded 'libtensorflow_framework.so'
PlayerPrefs - Creating folder: /root/.config/unity3d/Unity Technologies
PlayerPrefs - Creating folder: /root/.config/unity3d/Unity Technologies/Unity Environment
Logging to /root/.config/unity3d/Unity Technologies/Unity Environment/Player.log
INFO:mlagents.envs:
'Ball3DAcademy' started successfully!
Unity Academy name: Ball3DAcademy
        Number of Brains: 1
        Number of External Brains : 1
        Reset Parameters :

Unity brain name: Ball3DBrain
        Number of Visual Observations (per agent): 0
        Vector Observation space size (per agent): 8
        Number of stacked Vector Observation: 1
        Vector Action space type: continuous
        Vector Action space size (per agent): [2]
        Vector Action descriptions: ,
2018-09-21 05:57:10.516154: I tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
INFO:mlagents.envs:Hyperparameters for the PPO Trainer of brain Ball3DBrain:
        batch_size:     64
        beta:   0.001
        buffer_size:    12000
        epsilon:        0.2
        gamma:  0.995
        hidden_units:   128
        lambd:  0.99
        learning_rate:  0.0003
        max_steps:      5.0e4
        normalize:      True
        num_epoch:      3
        num_layers:     2
        time_horizon:   1000
        sequence_length:        64
        summary_freq:   1000
        use_recurrent:  False
        graph_scope:
        summary_path:   ./summaries/ppo-0
        memory_size:    256
        use_curiosity:  False
        curiosity_strength:     0.01
        curiosity_enc_size:     128
INFO:mlagents.trainers: ppo-0: Ball3DBrain: Step: 1000. Mean Reward: 1.201. Std of Reward: 0.662. Training.
INFO:mlagents.trainers: ppo-0: Ball3DBrain: Step: 2000. Mean Reward: 1.406. Std of Reward: 0.790. Training.
INFO:mlagents.trainers: ppo-0: Ball3DBrain: Step: 3000. Mean Reward: 1.618. Std of Reward: 1.028. Training.
INFO:mlagents.trainers: ppo-0: Ball3DBrain: Step: 4000. Mean Reward: 2.217. Std of Reward: 1.516. Training.
INFO:mlagents.trainers: ppo-0: Ball3DBrain: Step: 5000. Mean Reward: 3.195. Std of Reward: 2.365. Training.
INFO:mlagents.trainers: ppo-0: Ball3DBrain: Step: 6000. Mean Reward: 4.861. Std of Reward: 3.957. Training.
INFO:mlagents.trainers: ppo-0: Ball3DBrain: Step: 7000. Mean Reward: 8.058. Std of Reward: 7.471. Training.
INFO:mlagents.trainers: ppo-0: Ball3DBrain: Step: 8000. Mean Reward: 12.446. Std of Reward: 11.199. Training.
INFO:mlagents.trainers: ppo-0: Ball3DBrain: Step: 9000. Mean Reward: 17.426. Std of Reward: 18.031. Training.
(略)
```

はい。無事にML-Agentsで強化学習がされました。

このままだと、UnityアプリやハイパーパラメータファイルをDockerイメージに含めてしまっているので、使い勝手が悪いため、ジョブ実行時にCloud Storageから取得したり、学習結果ファイルをCloud Storageなどへ対比させるスクリプトを書く必要がありますが、思っていたより簡単に実行することができました。


## 参考

Google KUBERNETES ENGINE
https://cloud.google.com/kubernetes-engine/?hl=ja

Unity ML-Agentsについては下記をご参考ください。

MacでUnity ML-Agentsの環境を構築する(v0.5.0対応)
https://qiita.com/kai_kou/items/6478fa686ce1af5939d8

DockerでUnity ML-Agentsを動作させる(v0.5.0対応)
https://qiita.com/kai_kou/items/df3f3518a5a27b66f617

GKEを使ったバッチジョブ実行
http://otiai10.hatenablog.com/entry/2017/12/19/162430

Kubernetes Engineのクイックスタート
https://cloud.google.com/kubernetes-engine/docs/quickstart

Unity ML-Agents関連の記事まとめ
https://qiita.com/kai_kou/items/bffe1837ae1caccee179