はじめに
今回は、これまでの記事で解説してきAPIを実際の環境で使用して理解を深めていきます。したがって、この記事で出てくる用語でよく思い出せないものがあった場合、その2やその3へ戻るとよいでしょう。
環境との通信
まず、Pythonの仮想環境を起動して、環境との接続を開始します。以下、Pythonコマンドで対話環境を起動して入力します。なお、対象とするUnityのビルドは、ウィンドウ付きバージョンで行います。特に動作に違いがあるわけではないですが、Dedicated Server Buildに比べてウィンドウが表示される分環境の状態が分かりやすいからです。
from mlagents_envs.environment import UnityEnvironment
env = UnityEnvironment(file_name="MLAgentsLowLevelAPI", seed=1, side_channels=[])
これで環境との通信を確立できました。成功した場合はウィンドウが表示されます。
env.reset()
env.step()
env.step()
env.step()
これらのメソッドは環境操作の基本メソッドです。env.step()
を呼び出すごとに環境が少しずつ進んでいくことが分かります。
env.close()
これによりウィンドウが閉じたら成功です。ctrl+Zで対話環境から抜けましょう。
観測情報の取得
それではもう一度環境を作成し、今度はエージェントが収集してきた情報を取得してみましょう。
# 接続処理は先ほどと同様に行う
env.reset()
env.step()
behavior_specs = env.behavior_specs
このbehavior_specs
プロパティは、そのステップにおけるBehaviorStep
をすべて含む辞書です。これらは同時に、その環境に存在するBehaviorを列挙するために使うこともできます。
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を使って観測情報を取得してみましょう。
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
です。変数で受け取ってから中身を確認してみます。
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
などのプロパティも同様です。
len(decisions) # 決定待ちのエージェント数
len(terminals) # 終了したエージェント数
決定を送信する
決定を行うにあたって、どのような情報が要求されているのかを知っておくのは重要です。BehaviorSpec
を取得しましょう。
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つ目の次元は連続行動の個数
# まずは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で実装しました。公式ドキュメントに含まれるたくさんのメソッド・プロパティも同じように対話環境で試すことができます。ぜひ、手を動かしてメソッドを体で覚えていきましょう。