ML-Agentsの入力
入力にレイを用いることができますが、使い方が独特なので、そのためのメモ
1 2 3 4 | public override void CollectObservations() { //ここに入力関係を書く } |
使い方
1 2 3 4 5 6 7 8 | CollectObservations() { const float rayDistance = 40f; float[] rayAngles = {20f, 90f, 160f, 45f, 135f, 70f, 110f}; string[] detectableObjects = {"wall", "agent", "ground"}; AddVectorObs(rayPer.Perceive(rayDistance, rayAngles, detectableObjects, 1.6f, 0f)); } |
準備
3行目:レイの長さ
1 | const float rayDistance = 40f; |
4行目:レイを飛ばす方向
1 | float[] rayAngles = {20f, 90f, 160f, 45f, 135f, 70f, 110f}; |
角度を配列に入れていますが、これらの角度はどこからを基準にした角度かに注意する必要があります。
これは事前に決まっており、エージェントの右真横を0度として反時計回りに角度が増えていきます。
5行目:識別タグ
1 | string[] detectableObjects = {"wall", "agent", "ground"}; |
後述しますが、レイを飛ばした際、当たったオブジェクトのタグと識別タグが一致したら、タグに応じてフラグを返してきます。
ここで注意してもらいたいのは、定義した識別タグが見当たらない場合は強制的にレイのフラグが全て0になるので、ここで、レイが当たりうるオブジェクトのタグは全て定義しておきましょう。
7行目:レイ(Ray)発射
1 | rayPer.Perceive(rayDistance, rayAngles1, detectableObjects, 1.6f, 0f) |
rayPer.Perceive関数で レイを発射 & 戻り値でレイの情報を受け取ります。
引数
- レイが届く距離
- レイを飛ばす角度を収めた配列
- 識別タグを収めた配列
- 始点の高さ(y座標)
- 終点の高さ(y座標)
5の終点の高さとは、4で設定した始点の高さとの相対的な差で表します。
4と5に差を設けることで上下方向の角度を調整できます。
戻り値
設定したの識別タグの個数に応じて返ってくる配列の要素数が変わります。
よって、ここに応じてインスペクターからBrainオブジェクトの入力のサイズ(個数)も変えてあげる必要があります。
計算式
配列の要素数 = レイの方向数 ✖(識別タグ数+2)
ここでは、
レイの方向数(20度, 90度, 160度, 45度, 135度, 70度, 110度)=7
識別タグ数(”wall”, “agent”, “ground”)=3 より、
7 ×(3+2)=35
入力の個数は35個となります。
計算式の意味
レイ1本の時、以下のような戻り値が浮動小数点の配列で返ってきます。
(0, 0, 1, 0, 0.884703)
これは左から、
- “wall”タグがついたオブジェクトとの衝突フラグ
- “agent”タグがついたオブジェクトとの衝突フラグ
- “ground”タグがついたオブジェクトとの衝突フラグ
- 何も衝突していないフラグ
- 衝突した際の距離(レイの距離で0~1に正規化)
となっています。
先程の(識別タグ数+2)の(+2)は4番と5番が追加されていたためです。
衝突関係フラグは1が該当時、0が該当外のOne-hot表現になっています。
4番(何も衝突していない)が該当時は、5番(距離)は0となります。
(0, 0, 0, 1, 0)
レイが3本の時は
(0, 0, 0, 1, 0, 0, 0, 1, 0, 0.884703, 0, 1, 0, 0, 0.254203)
のような感じで、1~5を3回繰り返した配列が返ってきます。
注意
ここで注意すべきは、衝突したオブジェクトについているタグが識別タグに含まれていない場合です。
この場合、1番から5番までのすべてが0で返ってきます。距離も含めて0になってしまうので、状態の誤認につながる可能性があります。
よって、レイが当たりうるオブジェクトのタグは全て定義しましょう。
7行目:入力
1 | AddVectorObs(rayPer.Perceive(rayDistance, rayAngles, detectableObjects, 1.6f, 0f)); |
AddVectorObs関数でレイ戻り値を入力として与えています。
まとめ
ML-Agentのサンプルでレイを使ったものは、”PushBlock”、”BananaCollectors”、”Pyramids”などあるので1度スクリプトを確認してみるといいかもしれません。
URL:https://github.com/Unity-Technologies/ml-agents/tree/master/UnitySDK/Assets/ML-Agents/Examples
状態の入力の精度を上げたい場合は、レイの本数を増やしたり、角度を微妙にずらして発射するといいと思います。
1 2 3 4 5 6 7 8 9 | //本数を増やす float[] rayAngles0 = {20f, 90f, 160f, 45f, 135f, 70f, 110f}; float[] rayAngles1 = {25f, 95f, 165f, 50f, 140f, 75f, 115f}; //先程と5度角度を変える float[] rayAngles2 = {15f, 85f, 155f, 40f, 130f, 65f, 105f}; string[] detectableObjects = {"wall", "agent", "ground"}; AddVectorObs(rayPer.Perceive(rayDistance, rayAngles0, detectableObjects, 1.6f, 0f)); AddVectorObs(rayPer.Perceive(rayDistance, rayAngles1, detectableObjects, 1.6f, -2f)); //終点の高さを変える AddVectorObs(rayPer.Perceive(rayDistance, rayAngles2, detectableObjects, 1.6f, -5f)); |
参考
「Unityではじめる機械学習・強化学習 Unity ML-Agents実践ゲームプログラミング」