ML-Agents Python Low Level API入門：Pythonによる環境操作その4

# はじめに
今回は、これまでの記事で解説してきAPIを実際の環境で使用して理解を深めていきます。したがって、この記事で出てくる用語でよく思い出せないものがあった場合、その2やその3へ戻るとよいでしょう。

# 環境との通信
まず、Pythonの仮想環境を起動して、環境との接続を開始します。以下、Pythonコマンドで対話環境を起動して入力します。なお、対象とするUnityのビルドは、ウィンドウ付きバージョンで行います。特に動作に違いがあるわけではないですが、Dedicated Server Buildに比べてウィンドウが表示される分環境の状態が分かりやすいからです。
```python
from mlagents_envs.environment import UnityEnvironment
env = UnityEnvironment(file_name="MLAgentsLowLevelAPI", seed=1, side_channels=[])
```
これで環境との通信を確立できました。成功した場合はウィンドウが表示されます。

```python
env.reset()
env.step()
env.step()
env.step()
```
これらのメソッドは環境操作の基本メソッドです。```env.step()```を呼び出すごとに環境が少しずつ進んでいくことが分かります。

```python
env.close()
```
これによりウィンドウが閉じたら成功です。ctrl+Zで対話環境から抜けましょう。

# 観測情報の取得
それではもう一度環境を作成し、今度はエージェントが収集してきた情報を取得してみましょう。
```python
# 接続処理は先ほどと同様に行う
env.reset()
env.step()
behavior_specs = env.behavior_specs
```
この```behavior_specs```プロパティは、そのステップにおける```BehaviorStep```をすべて含む辞書です。これらは同時に、その環境に存在するBehaviorを列挙するために使うこともできます。
```python
behavior_key_list = list(behavior_specs.keys())
print(behavior_key_list)  # ['Jump?team=0']を出力
```
behavior_specsのキーが1つということは、今回のステップにおいては環境内で動いているエージェントの種類は1種類ということになります。
この```Jump?team=0```という文字列は、```Behavior Parameters```コンポーネントに設定した```Behavior Name```と```Team Id```を組み合わせたもので、Behaviorを一意に識別するものになります。その書式は、"(Behavior Name)?(Team Id)"です。mlagents-envsでは、この書式のIDを使って環境中のBehaviorを区別しています。
それでは、このIDを使って観測情報を取得してみましょう。
```python
jumpID = behavior_key_list[0]
print(jumpID)  # "Jump?team=0"を出力
env.get_steps(jumpID)  # 2つのオブジェクトが入ったタプルを返す
```
env.get_steps関数は、IDを指定してそのIDのBehaviorを持つエージェントからの観測情報を得ることができます。その戻り値は```Decision Steps```と```Terminal Steps```です。変数で受け取ってから中身を確認してみます。
```python
decisions, terminals = env.get_steps(jumpID)

print(decisions.obs)
# 以下の値が出力される
[array([[-2.8212771, 0.5, -5.396847 , -1.76456, 0., -1.]], dtype=float32)]

print(decisions.reward)
# 以下の値が出力される
array([0.], dtype=float32)

print(decisions.agent_id)
# 以下の値が出力される
array([0])

print(decisions.action_mask)
# 以下の値が出力される
[array([[False,  False]]), array([[False, False, False]])]
```
復習ですが```obs```プロパティはそのステップまでに観測を終えて決定待ち状態になったエージェントの観測を示すNumPy配列です。```reward```などのプロパティも同様です。
```python
len(decisions)  # 決定待ちのエージェント数
len(terminals)  # 終了したエージェント数
```

# 決定を送信する
決定を行うにあたって、どのような情報が要求されているのかを知っておくのは重要です。```BehaviorSpec```を取得しましょう。
```python
actionSpec = env.behavior_specs[jumpID].action_spec
print(actionSpec)
# 以下が表示される
ActionSpec(continuous_size=0, discrete_branches=(2, 3))
```
この情報から、連続行動の個数が0、離散行動の個数が2で、1つ目が2通り、2つ目が3通りであることが分かります。

決定を行い、それを通知するには```env.set_actions```を使います。このメソッドは第一引数にはBehaviorのIDを指定して、第二引数に```ActionTuple```を指定します。```ActionTuple```クラスは、以下の2つのフィールドを持ち、それぞれ連続行動と離散行動を表します。

- discrete：NumPy二次元配列。最初の次元はエージェントの個数、2つ目の次元は離散行動の個数
- continuous：NumPy二次元配列。最初の次元はエージェントの個数、2つ目の次元は連続行動の個数

```python
# まずはActionTupleを使えるようにインポートする
from mlagents_envs.base_env import ActionTuple
decision = np.array([[0, 1]]) # 決定を求めているエージェントが1つだったので形状は(1, 2)
actionTuple = ActionTuple(continuous=None, discrete=decision)
env.set_actions(jumpID, actionTuple)
env.step() # 設定した決定を送信する
```
これによって環境からの情報を取得、決定を作成、情報を送信する流れを作成することができました。

# おわりに
基本的な環境の操作の流れをPythonで実装しました。[公式ドキュメント](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Python-API-Documentation.md)に含まれるたくさんのメソッド・プロパティも同じように対話環境で試すことができます。ぜひ、手を動かしてメソッドを体で覚えていきましょう。