[Project Bonsai] Bonsaiを触ってみる

# はじめに
Project Bonsaiについて調べてみました。

>「Project Bonsaiを使えば、AIの専門知識を持たない特定分野の専門家が、最先端の知識を機械システムに追加できる」
参照）[Techcrunch](https://jp.techcrunch.com/2020/05/20/2020-05-19-microsoft-launches-project-bonsai-its-new-machine-teaching-service-for-building-autonomous-systems/)

って事らしいので、AIの知識はほぼない私にでもできるかもしれません。

動かす中で、理解したことはできるだけ記載します。
細かな部分に関しては、[ドキュメント](https://docs.microsoft.com/en-us/bonsai/)も合わせてご確認ください。

# [Bonsai](https://azure.microsoft.com/ja-jp/services/project-bonsai/)って何？
Microsoftが提供している自律システム向け機械教示サービスです。（現在はPublic Preview）
産業制御システムに焦点を当てた汎用ディープ強化学習プラットフォームのようです。

#  とりあえず動かす
## 事前準備
Bonsaiを利用するには、Microsoftのアカウントや、Azureのサブスクリプション、Bonsaiのワークスペースが必要になります。
すごく丁寧に説明してくださってるページありますので、こちらをご参考にしてください

[[Project Bonsai/Moab]Bonsai育成記 (1)Moabバランス](https://qiita.com/Meeracker/items/8d39dc7907bef2650f98)

## [Cartpoleのチュートリアル](https://docs.microsoft.com/ja-jp/bonsai/quickstart/cartpole/)を実行する
現在、Bonsaiには、チュートリアルとして、Cartpoleと、Moabの2つのアセットが存在します。
Cartpoleのほうがシンプルであるため、ここではCartpoleを見ていきます。

### はじめる
Bonsaiのワークスペースを起動するか、「+Create brain」をクリックし、表示されるウィザードから、「Carpole」を選択します。
![ウィザード画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/918fe6e3-8dc9-c0ef-05e7-37b6d241b65d.png)

選択したら、表示名を入力します。
ここでは「Cartpole trial」と入力し、「Create brain」をクリックして作成します。
![名前の登録](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/6779fc32-7e9e-082f-fc1b-9afee3befb84.png)

作成すると、サンプルコードとCartpoleのシミュレータが追加されます。

### BonsaiのUI
Bonsaiのメイン画面です。
主に学習で使うことになるのは、この2つの画面

* Coding Panel<br>
 教育カリキュラムを記載する独自言語である[Inkling](https://docs.microsoft.com/ja-jp/bonsai/inkling/basics)のコードエディタです。<br>
タブの切り替えでトレーニング中の情報が表示されます。
* Graphing Panel<br>
 Inklingで記載された内容がグラフィカルに表示されます。
![UI画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/b09f5d41-f860-b8f3-8279-a781b67fa365.png)

#### 学習内容の確認

実際に学習に入る前に、何を学習の目標にしているか少し確認します。
教育カリキュラムは、Inklingに記載されいます。

#### Bonsaiの動きについて
Bonsaiは、シミュレータが必須の仕組みになっています。
シミュレータに指定された入力値を渡し、返ってきた結果を目標に合うかチェック、目標に近づけるように入力値を変化させて、再びシミュレータに入力値を渡します。
これを指定された反復回数を１サイクルとして実行します。

そのため、シミュレータの入出力が重要となります。

シミュレータの入出力は、　SimulatorsのCartPoleを選択することで確認です。
ここには、シミュレータで入出力される値や、環境設定の情報が記載されています。
例えば、`pole_angle`を指定すると、poleが傾いた状態を初期状態にすることが可能になります。
![シミュレータ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/3f05f51b-987c-f304-6e0b-d96f8e624cad.png)


#### シミュレータで使用する項目の設定
`SimAction`にはシミュレータへの入力値が記載されています。
`command`を使用するとCartの移動量(右や、左にどのくらい移動させるか)を指定することができます。

```shell:Inkling
type SimAction {
    # カートに適用するX方向の力の量
    command: number<-1 .. 1>
}
```

`SimState`にはシミュレータからの出力値の中で使用する項目が記載されています。
`SimAction`の入力（Cartの移動量）の入力の結果として、
Cartの位置や、速度、Poleの角度などの状態を受け取ることができます。

```shell:Inkling
type SimState {
    # Cartの位置(m)
    cart_position: number,

    # Cartの速度(m/s)
    cart_velocity: number,

    # 現在のPoleの角度(radians)
    pole_angle: number,

    # Poleの角速度(radians/s)
    pole_angular_velocity: number,
}
```
#### 学習の目標
学習の目標は、`goal`で記載されています。
`SimState`の出力情報をもとに`Fall Over`と`Out Of Range`の2つのGoalとして設定されています。
目標に優先度はなく、どちらの目標も満たすように学習が実行されます。

* Fall Over<br>
  Poleの角度を、12度以上傾けないようにする
* Out Of Range<br>
  Cartの位置を、0.25m以上動かないようする

```shell:Inkling
goal (State: SimState) {
    avoid `Fall Over`:
        Math.Abs(State.pole_angle)
        in Goal.RangeAbove(MaxPoleAngle)
     avoid `Out Of Range`:
        Math.Abs(State.cart_position)
        in Goal.RangeAbove(TrackLength / 2)
}
```

#### 一サイクルの反復回数
`training`の`EpisodeIterationLimit`に一回の学習サイクルの回数が記載されています。
シミュレータ対して、入力値を発行し、出力値を元に次の入力値の発行・・が反復実行されます。

```shell:Inkling
training {
  # 反復回数を120に制限します（デフォルトは1000回）
  EpisodeIterationLimit: 120
}
```

## 学習させてみる

学習の目標もわかったので学習させてみます。
チュートリアルは、学習カリキュラム(Inklingコード）、シミュレータともに準備されていますのでGraphing Panelにある「Train」ボタンを押すと学習が開始します。
![開始ボタン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/fa1183ac-8749-7fe5-92f3-8c4cecffc01a.png)

シミュレータの起動後、学習が始まるトレーニング画面が表示されます。
![学習中](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/dd4cb40f-71d4-d0ba-eef7-fd8bb09b5230.png)

### トレーニング画面について
学習中に表示される画面を説明します。

#### データグラフ
Inklingコードで記載されている、シミュレータからの入力、出力をグラフで表示することができます。
下記の画像は、シミュレータから出力されるCartの位置と、Poleの角度の表示しています。
グラフより、Cartが動くと、Poleの角度が大きく変わる、、（たぶん）Poleが倒れている状態になっていることがわかります。
![グラフ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/da38a139-f895-42f7-c946-9b571eb3409e.png)

#### 3Dシミュレータ
シミュレータからの出力結果に応じて、3Dモデルが表示されるので、動きをイメージしやすくなります。
※グラフ上でマウスカーソルを移動させることで、その時点での表示を確認することができます。
![3Dシミュレータ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/26a196bd-bf45-ce6b-a023-2de195dc8a8c.png)

#### 学習状況
現在の学習状況をグラフで確認することができます。
学習目標の到達状況や、経過時間や、学習速度、シミュレータのインスタンス数なども表示されます。
グラフは、目的ごとの達成率です。今回目標が2つあるので、それぞれの達成状況が表示されています。
グラフを見ると、`Out Of Range`のCartを動かさないようにキープする目的の達成率は高いですが、`Fall Over`のPoleを倒さないように維持することには苦戦していることがわかります。
![学習状況](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/80523b47-128d-1885-c64c-597c22f7679d.png)

## 学習終了
全体的な目標の達成度が100%になるか、これ以上学習に効果がなくなった場合に終了します。
今回は、28分で終了。公式ページでは、75万回の反復で終了とありましたが、今回は35万回で終了しています。
公式ページの記載では、 約1米ドル（110円くらい）のコストがかかると記載されていますが、反復回数も少ない影響は、その半分くらい感じでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/ae7d5456-5abb-fb57-5ccc-0465b5325286.png)

### 学習結果を見る
#### データグラフ
右が学習中(開始3分時点)、左が学習後の画像です。
学習中は、`pole_angle`が大きく動き、Porlが倒れています。
また、`pole_angle`が、目標の状態から外れることで、反復がやり直しになっています。
そのため、指定された反復回数分(120回)実行ができていないため、1回ごとの実行がまちまちな状態です。

学習後は、`pole_angle`が安定し、ほぼ動きがなく、`cart_position`も目標の範囲内です。（なぜか右に移動してバランスとってますね）
反復回数がしっかり実行されているので、1回ごとの実行期間も同じになっていています。
![シミシミュレータ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/c0b61f36-707d-1071-329c-65de2851998c.png)

#### 学習状況
`pole_angle`をキープするのが難しいのか、`Fall Over`は学習直後の目標達成率は50%ですが、
徐々に成果がでており、10万回の反復実施の時点ではほぼ100%になっています。
![学習状況結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189829/b3296c33-f9b5-8aa4-c5d5-8d3cc2bb3879.png)

# まとめ
シミュレータから、学習カリキュラム（Inklingコード）まで、準備されているので動かすのは何も問題ないでしょう。
操作方法は、チュートリアルから学べると思いますが、これだけでは中々利用方法をイメージしにくいので、
次は、学習カリキュラム（Inklingコード）を変更して、自分が思った結果が得られるか試してみたいと思います。