今回はおたまじゃくしのお友達向けです
こんにちわ、こんばんわ。かえるのクーの助手の弟子の「井戸中 瑠璃」(いとなか るり)です。かえる族の方はおたまじゃくしさん、人類の方でいえば、中学生、高校生向け、入門したての方向けの内容です。もちろん瑠璃も入門したて(4日め)です。
連休中はずっとUNITY & ML-Agentsで遊んでいます。
ボールを動かして箱に当てる学習のチュートリアルをやってみました。
驚くほど簡単です。が、UNITYで動作させるC#のデバッグの仕方がいまいちわかりません。学習途中に止めたいのですが、よくPython側がタイムアウト?になってしまいます。そのうちちゃんと検索してみます。
さて、そのまま「チュートリアルやってみた」記事を書くのもなんなので、よくあるチュートリアルを少し変更してやってみました。
内容
宇宙空間にある2つの球体が衝突するように学習します。
重力は存在しないものとし、球体は一方(Agent)のみ、力で方向を変更できるものとします。目標(Target)はエピソード毎に微妙に位置を変えます。
移動方向、力はともに3次元(x,y,z)とします。
UNITYでの準備
SpaceAgent:球体:直径1:青色
Target:球体:直径1:緑色
ML-Agentsでの情報
観察(CollectObservationsに指定する値 9つ)
・Targetの X, Y, Z 座標
・SpaceAgentの X, Y, Z 座標
・SpaceAgentの X, Y, Z の速度
以上9つの情報
行動(OnActionReceivedで受け取る値3つ)
・SpaceAgentの X, Y, Z へ加える力
終了条件(衝突判定→EndEpisode)
2つの球体が極めて接近したとき(中心距離が1.2)衝突とみなす。
衝突時に報酬を与えてその回のエピソードを終了します。
報酬(Reward)
3次元でとても衝突させにくいため、その前段階でも報酬を与えます。強化学習なので、最終結果だけに与えたいところですが、それでは学習にたいへん時間がかかりそうなので、補助的な報酬も微小に与えます。
・Targetまでの前回距離 - Targetまでの今回距離 を報酬とします(おおむね1よりかなり小さい値です。前回距離より遠くなればマイナス報酬となります。)この報酬は判定毎に与えます。
・衝突できた場合 報酬として 1 を与えます。
チュートリアル操作
(1)新規作成で、UNITYのプロジェクト名 SpaceBallを入力して起動します。
(2)BlueとGreenのマテリアルを作成します。(色指定に使うだけ)
- 1. 左下 ProjectのAssetsフォルダ選択 / 右ボタン/2. Create/3.Material で 4.名称をGreen/5.右側 Inspector Main Maps のAlbedo の色部分をクリック/6. Color R=32, G=255, B=64 とします。(色なのでてきとーでよい)
同様に Blueマテリアル Color R=32 G=64 B=255 をつくります。
(3)青色球体(SpaceAgent)と緑色球体(Target)を作成します。
- 1.左上 Hierachey の展開部分で右ボタン/2. 3D Object/3. Sphere/4.名称を SpaceAgentに変更
- 5. 右 Inspector のMeshRendererのMaterialsを展開/6. AssetsにあるBlueのマテリアルをElement0にドラッグ&ドロップ
- 7. Inspector のTransformのX=2 Y=1として移動
- 8. 同様に Targetを3DObject Sphereで GreenでX=0 Y=0 に作成
以上で球体の配置は完了です。次に青色SpaceAgentに物理演算と学習について定義していきます。
(4) ML-Agentsのパッケージを導入します。
- 1. メニューのWindow/2. Package Manager/3. PackageManager + 部分左クリック/4. Add Package from Disk.../5. ml-agens展開フォルダのcom.unity.ml-agents\6. package.json を選択/7.開く でML-Agentsが導入されます。Package Managerを閉じます。
※説明例ではSphere⇒Targetにするのを忘れてました。最終的には緑球をTagetという名称にしています。
(5)青色球体(SpaceAgent)に物理エンジンを紐づけます。
- 1. HierarchyのSpaceAgent選択/2.右 Add Componentボタン / 3. 検索欄に Rigi入力/4. Rigidbodyを選択 (5. Use Gravityはチェックしたまま)
※重力Gravityはoffにするといろいろ不都合なのでONにしておきます。無重力はプログラムで指定することにします。
(6)ML-Agentsのパラメータ定義を設定します。
- 1. HierarchyのSpaceAgent選択/2. 右 Add Componentボタン / 3. 検索欄に Beh入力/4. Behavior Parametersを選択
- 5. Behavior Name をSpaceBall /6. Vector ObservationのSpace Sizeを9 /7. Vector ActionのSpace Typeを Continuous , 8. Space Sizeを 3 に設定
(7)スクリプトの設定をします。
- 1. HierarchyのSpaceAgent選択/2. 右 Add Componentボタン /3. 検索欄に SpaceAgent入力/4. New Script/5. Create and add ボタンクリック(8)作成されたスクリプトファイル内をコーディングします。
動作構想とおりのコーディングをする。(表示が崩れているのは。ご容赦ください)
ソースの文字コードは UTF-8 とします (更新:2020/05/06再調整しました)
(9)スクリプトの動作を指定します。
- Space Agent Script部の Max Step を 500 にする(この値はいろいろかえる)
- Target に Hierarchyの Target をドラッグ & ドロップする
(10)行動決定のタイミング(単位)を指定します。
- HierarchyのSpaceAgent選択/右 Add Componentボタン / 検索欄に Deci入力/Decision Requester を選択
- Decision Period に 10を入力 (この値はいろいろかえる)
ここまででUNITYの準備は完了です。
(11)学習用のパラメータをyamlファイルで指定します。
ML-Agentsのインストールフォルダの confフォルダに SpaceBall.yamlファイルを作成します。(表示が崩れているのはご容赦ください)(更新:該当バージョンでのパラメータに誤りがあったので修正しました。学習が超絶遅かったのはそのためでした)
(12)Pythonの学習エージェントを起動します。
- コマンドプロンプトで、cd ML-Agentsの展開フォルダ とします。
> conda activate ml-agents-vp107
※もしもcondaの設定がまだの場合はここで設定します。
> conda create -n ml-agents-vp107 python=3.7
> conda activate ml-agents-vp107
> pip install -e ./ml-agents-envs
> pip install -e ./ml-agents
※ ここまで
学習プロセスを起動します。
> mlagents-learn ./config/SpaceBall.yaml --run-id=SpaceBall-ppo-1
数値部分は失敗したり、実験が進むごとにアップさせます。
初回は下記がでますが許可をします。
学習エージェントが起動します。Portは5004を使用するようです。Unity側の操作が遅いとタイムアウトすることがあるので、その場合は数字をアップしてもう一度実行します。
(13)UnityのPlayを実行します。
mlagents-learnの実行で以下の表示が出れば、Unityのplayボタン▶をクリックします。
学習が始まりますので、学習の経過が観察できます。
※学習と実行を交互に行う場合、必ず「BehaviorParameters」のModelの状態を確認してから実行してください。
学習の停止はUNITYで一時停止ボタンをクリックして、mlagentsのプロンプト画面でctrl+c します。
(14) 学習の継続をする場合
> mlagents-learn ./config/SpaceBall.yaml --run-id=SpaceBall-ppo-1 --resume
Start training by pressing the Play button in the Unity Editor.
の表示がでてからUnityのPlayボタン▶をクリックします。
データが壊れている場合はエラーが出て続行しません。その場合は数値をカウントアップさせてもう一度最初から学習します。
(15)学習結果の反映
- 再び学習を停止します。
- ML-Agents解凍フォルダ\models\SpaceBall-ppo-1にできるpaceBall.nn ファイルを Unityプロジェクトの Assetsフォルダに複写します。
- Assetsに表示されたSpaceBall.nnファイルを Behevior ParametersのModelにDrag&Dropします。
- メニューのFile/Save をします。モデル変更の内部状態が反映されきらない場合があるようなので、Unityを再起動します。
(16)実行してみます。
- UnityのPlayボタン▶をクリックします。
学習は早送りしているので、実際の球の動作は遅いです。
右側のInspectorのRigidbodyのMass(重さ)を1/10の0.1にすると早く動きます。
逆に10にするとかなり重いです。
それ以上の変化をさせるとこの学習結果ではあまりうまく動かない感じです。
※学習済データを実行する場合は、プログラム SpaceBall.csの
として実行ください。(学習の最初は簡単(中心近傍)に目標が出現するようにしているため)
学習のすこしばかりのコツ
最初は MaxStep=100, DecisionPeriod=10くらいで学習させます。
すこしばかり、緑の球のまわりをうろつきはじめたら(画面からはみでなくなるくらい)、MaxStep=500, DecisionPeriod=5くらいにします。
かなり学習できてきたら、MaxStep=2000m DecisionPeriod=3くらいにします。
なお、ずっと学習しているとどこかで学習が頭打ちになって停止します。
(追記)パラメータを調整したら上記の操作はしなくてもちゃんとはやく学習するようになりました。これはやらなくてもOKです。学習の終了は頭打ち判定ではなく、規定の回数(max_steps)によるものでした。
興味ある方は是非やってみてください。
報酬の与え方をかえるとアプローチの仕方がかわると思います。