上一節咱們講了如何配置ML-Agents環境,這一節咱們建立一個示例,主要利用Reinforcement Learning(強化學習)。git
如上圖,本示例將訓練一個球滾動找到隨機放置的立方體,並且要避免從平臺上掉下去。github
本示例是基於ML-Agents官方的示例,官方有中文版和英文版兩個文檔,英文版的是最新的,中文版中大部份內容和英文版的一致,但也有不一樣,本文是基於最新版所作(v0.15.0,master分支),須要參考官方文檔的也可參照以下地址食用。算法
英文:https://github.com/Unity-Technologies/ml-agents/tree/master/docsjson
在Unity項目中使用ML-Agents涉及如下基本步驟:數組
(PS.在官方中文文檔中,第2,3步須要實現Academy子類和Brain,但在新版中,這兩個東西已經不須要在場景裏定義了,因此比較重要的就是這個Agent子類,基本學習邏輯都在這裏)瀏覽器
第一步,咱們先新建一個Unity項目,而且將ML-Agents包導入到裏面:網絡
打開Unity,新建一個項目隨意叫個名字,例如「RollerBall」;dom
在Unity菜單「Edit」->「Project Settings」,在彈出的窗口中,找到「Player」,將「Api Compathbility Level」改成「.NET 4.x」,以下圖;ide
在上一節中,咱們已經將ml-agents代碼庫克隆到了本地,若是沒有克隆,請參考上一篇「Unity ML-Agents v0.15.0(一)環境部署與試運行」中的5、1,這裏咱們默認你們都是已經克隆了庫,則在Unity中須要將ML-Agents插件導入Unity中。我這裏的版本是Unity2019.2,方法以下:
文件夾中有一個「manifest.json」的文件,編輯它,這個就是工程中的Packages包集合,在最後加入"com.unity.ml-agents" : "file:D:/Unity Projects/ml-agents/com.unity.ml-agents",這裏file:後是你本身克隆的ml-agents源碼路徑,別照抄個人哦,除非你也是這個路徑- -,以下圖;
修改後保存,在切到Unity中,若是路徑正確,則會出現導入package包的畫面,在工程的Packages文件夾下也會成功出現「ML Agents」文件夾,以下圖:
建立環境
下面,咱們建立一個簡單的ML-Agent環境。該環境的「physical」組件包括一個Plane(充當agent移動的地板)、一個Cube(充當agent尋找的目標)和一個Sphere(表示agent自己)。
建立地板
在 Hierarchy 窗口中右鍵單擊,選擇 3D Object > Plane。
將遊戲對象命名爲「Floor」。
選擇 Plane 以便在 Inspector 窗口中查看其屬性。
將 Transform 設置爲 Position = (0,0,0)、Rotation = (0,0,0)、Scale = (1,1,1)。
修改Plane材質,變的好看點。
以上過程我都是複製的,其實就是建立一個Plane,而後換個好看的材質就行,隨意定義一個都OK。
建立目標立方體
在 Hierarchy 窗口中右鍵單擊,選擇 3D Object > Cube。
將遊戲對象命名爲「Target」
選擇 Target 以便在 Inspector 窗口中查看其屬性。
將 Transform 設置爲 Position = (3,0.5,3)、Rotation = (0,0,0)、Scale = (1,1,1)。
修改Cube材質。
添加Agent球體
OK,以上過程就將Unity中的三維環境建立好了,下面咱們來實現Agent。
在官方中文文檔中還有「實現Academy」及「添加Brain」,最新版裏已經不須要了!直接設置Agent就行。
要建立Agent:
而後,編輯新的RollerAgent
腳本:
RollerAgent
腳本;RollerAgent
繼承Agent
類,同時引用using MLAgents
和using MLAgents.Sensors
命名空間;Update()
方法,先保留Start()
方法以後要用。到目前爲止,以上的步驟都是爲了將ML-Agents添加到任何Unity項目中而須要的基本步驟。接下來,咱們將添加邏輯,使咱們的agent可以利用reinforcement learning(強化學習)技術學習找到立方體。
當agent(球體)到達目標位置(方塊)後,會將本身標記爲完成狀態,而agent的重置函數(Reset)會將方塊再從新移動到新的位置。另外,若是agent從平臺上掉落,也會觸發重置函數,使得agent初始化,目標位置也將隨機刷新。
爲了重置agent的速度(以及以後給它施加力移動),咱們須要引用到球體的Rigidbody
組件。這個組件的引用就能夠寫到Start()
方法中,以以上的邏輯,咱們的RollerAgent
腳本以下:
using MLAgents; using MLAgents.Sensors; using UnityEngine; public class RollerAgent : Agent { public Transform Target;//方塊 public float speed = 10;//小球移動速度 private Rigidbody rBody;//球剛體 private void Start() { rBody = GetComponent<Rigidbody>(); } /// <summary> /// Agent重置 /// </summary> public override void AgentReset() { if (this.transform.position.y < 0) {//若是小球掉落,小球初始化 rBody.velocity = Vector3.zero; rBody.angularVelocity = Vector3.zero; transform.position = new Vector3(0, 0.5f, 0); } //方塊位置隨機 Target.position = new Vector3(Random.value * 8 - 4, 0.5f, Random.value * 8 - 4); } }
接下來,咱們來實現Agent.CollectObservations(VectorSensor sensor)
方法。
注意,這裏和老版本方法不一樣,以前的函數中並無VectorSensor sensor
參數,不過用法差很少。
Agent將咱們收集的信息發送給Brain,由Brain使用這些信息來作決策。當你訓練Agent(或使用已經訓練好的模型)時,數據將做爲特徵向量輸入到神經網絡中。爲了讓Agent成功學習某個任務,咱們須要提供正確的信息。一個好的經驗法則則是考慮你在計算問題的分析解決方案時須要用到什麼。
這裏比較重要,就是說你在訓練的時候,須要考慮到的變量是哪些,咱們來看看這個例子中咱們須要agent收集的信息有哪些:
目標的位置
sensor.AddObservation(Target.position);
agent的位置
sensor.AddObservation(transform.position);
agent的速度,這有助於agent去學習控制本身的速度,而不會使其越過目標和從平臺上滾下來
sensor.AddObservation(rBody.velocity.x);
sensor.AddObservation(rBody.velocity.z);
這裏一共有8個觀測值(一個position算x,y,z三個值),以後須要在Behavior Parameters
組件的屬性裏進行設置,以下圖:
在中文文檔裏,對這些值進行了歸一化處理,最新英文文檔中並無進行歸一化處理,直接加上就行。而後這裏的重載函數以下:
/// <summary> /// Agent收集的觀察值 /// </summary> /// <param name="sensor"></param> public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(Target.position);//目標的位置 sensor.AddObservation(transform.position);//小球的位置 sensor.AddObservation(rBody.velocity.x);//小球x方向的速度 sensor.AddObservation(rBody.velocity.z);//小球z方向的速度 }
Agent的最後一部分是Aegnt.AgentAction()
函數,這個方法主要是用來接收Brain的決策命令以及根據不一樣狀況來進行Reward(獎勵)。
Brain的決策以動做數組的形式傳遞給AgentAction()函數。此數組中的元素主要由agent的Brain的Vector Action
、Space Type
和Space Size
來決定的。這裏分別表明 了向量運動空間、向量運動空間類型以及向量運動空間數,ML-Agents將動做分爲兩種:Continusous向量運動空間是一個能夠連續變化的數字向量,例如一個元素可能表示施加到agent某個Rigidbody
上的裏或扭矩;Discrete向量運動空間則將動做定義爲一個表,提供給agent的具體動做是這個表的索引。
咱們在這裏利用的是Continusous
向量運動空間,即將Space Type
設置爲Continuous,並將Space Size
設置爲2。這就表示了Brain生成的決策利用第一個元素action[0]
來肯定施加沿x軸的力,經過action[1]
來肯定施加沿z軸的力(若是agent是三維移動,則將Space Size
設置爲3)。注意,這個裏Brain並不知道action[]
數組中每一個值的具體含義,在訓練的過程當中只是根據觀測輸入來調整動做,而後看看會獲得什麼樣的獎勵。具體設置以下圖,一樣是在Behavior Parameters
組價中進行設置:
引伸一下,這裏也可使用Discrete類型來訓練,不過相應的Space Size
就要變成4了,由於有4個方向須要控制。
OK,上述的動做代碼以下:
//Space Type=Continuous Space Size=2 Vector3 controlSignal = Vector3.zero; controlSignal.x = vectorAction[0];//x軸方向力 controlSignal.z = vectorAction[1];//z軸方向力 //固然上面這兩句能夠互換,由於Brain並不知道action[]數組中數值具體含義 rBody.AddForce(controlSignal * speed);
Reinforcement Learning(強化學習)須要獎勵。一樣獎勵(懲罰)也在AgentAction()
函數中實現,與上面動做實現的重寫函數在一塊兒。學習算法使用在模擬和學習過程的每一個步驟中分配給agent的獎勵來肯定是否爲agent提供了最佳的動做。當agent完成任務時,對它進行獎勵。在這個示例中,若是Agent(小球)到達了目標位置(方塊),則給它獎勵1分。
RollerAgent會計算到達目標所需的距離,當到達目標時,咱們能夠經過Agent.SetReward()
方法來說agent標記爲完成,並給它獎勵1分,同時使用Done()
方法來重置環境。
//計算自身與目標的距離 float distanceToTarget = Vector3.Distance(transform.position,Target.position); //不一樣狀況進行獎勵 if (distanceToTarget < 1.42f) {//到達目標附近 SetReward(1); Done(); }
最後,若是小球掉落平臺,則讓agent重置。這裏沒有設置懲罰,有興趣的童靴能夠本身試試設置懲罰。
if (transform.position.y < 0) {//小球掉落 //SetReward(-1); 懲罰先不設置 Done(); }
OK,由以上的動做和獎勵構成了AgentAction()方法,主要理解裏面每一步的意義是爲什麼,最後AgentAction()
方法以下:
public override void AgentAction(float[] vectorAction) { //Space Type=Continuous Space Size=2 Vector3 controlSignal = Vector3.zero; controlSignal.x = vectorAction[0];//x軸方向力 controlSignal.z = vectorAction[1];//z軸方向力 //固然上面這兩句能夠互換,由於Brain並不知道action[]數組中數值具體含義 rBody.AddForce(controlSignal * speed); //計算自身與目標的距離 float distanceToTarget = Vector3.Distance(transform.position, Target.position); //不一樣狀況進行獎勵 if (distanceToTarget < 1.42f) {//到達目標附近 SetReward(1); Done(); } if (transform.position.y < 0) {//小球掉落 Done(); } }
到這一步,全部的遊戲對象和ML-Agent組件都已準備就緒,而後咱們須要在場景的小球上加一些腳本,修改一些屬性。
在場景中選擇RollerAgent小球,先添加Behavior Parameters
腳本,並設置其中的Space Size
爲8,Space Type
爲Continuous,Space Size
爲2。這步要是以前幾步裏已經搞定了,就不用管了。不過這裏面有個Behavior Name
,這個屬性應該就是區分Brain的名稱,新版中多個Agent擁有相同Brain的話,應該是在這裏進行區分,我我的是這麼以爲的,要是有錯的話,請指正;
這步必定要記得,老版裏沒有,須要加Decision Requester
組件,並將Decision Period
改成10!這裏英文文檔也寫得不起眼,要是不加這個腳本,你的小球是動不起來的。
在開始長時間訓練以前,手動測試你的測試環境是一個明智的作法。爲了手動測試,咱們須要在Roller Agent
腳本中添加Heuristic()
方法,以此來代替Brain決策,代碼以下:
/// <summary> /// 手動測試 /// </summary> /// <returns></returns> public override float[] Heuristic() { var action = new float[2]; action[0] = Input.GetAxis("Horizontal"); action[1] = Input.GetAxis("Vertical"); return action; }
其實這裏就是經過鍵盤來對動做空間action[]數組進行賦值來使得agent動做。
而後還須要在Behavior Parameters
組件中將Behavior Type
改成Heuristic Only
,以下:
這個時候咱們能夠運行一下,(忽然發現Roller
中的Targer忘記拖了,將方塊目標拖進來),而後就可使用WSAD或上下左右來控制小球了,到方塊附近,方塊會自動從新置位,若是小球掉落,也會從新置位。
OK,咱們Behavior Type
改回Default
,準備開始訓練了~
打開Anaconda3,找到咱們以前建好的訓練環境,啓動「Terminal」。
cd到ml-agent的根目錄,例如個人路徑:
cd /d D:\Unity Projects\ml-agents
這裏插一下,咱們修改一下ml-agents中的Config文件,找到ml-agents
中config
文件夾,並打開trainer_config.yaml
配置文件,在最後加一句
RollerBallBrain: batch_size: 10 buffer_size: 100
這裏能夠看到RollerBallBrain其實就是我剛纔在Behavior Parameters
組件中設置的Behavior Name
。這裏修改這兩個參數會覆蓋配置文件最前的默認項default
,這兩個超參數值修改小可使得訓練速度加快,若是用原來的參數(batch_size: 1024,buffer_size: 10240),則須要訓練大約300000步,可是修改後只須要低於20000步。這裏應該是根據具體項目具體設置的。
咱們配置完以後,回到命令行,輸入:
mlagents-learn config/trainer_config.yaml --run-id=RollerBall-1 --train
運行Unity中的程序。
若是Unity與Anaconda訓練環境成功通信,則會在命令行中發現你的訓練配置:
同時,能夠看到Unity中小球開始本身快速運動,方塊也會根據不一樣狀態來隨機生成。
過一段時間,命令行中會顯示相應的執行步數,通過的時間,平均獎勵等信息。
隨着訓練的進行,會發現小球很難掉下平臺,且一直跟隨方塊的位置:
最後訓練時間太長了,能夠經過配置文件中的max_steps
來修改最大訓練步驟,因此我這裏直接Ctrl+C了,這樣也會將訓練模型存下來。
找到這個RolerBallBrain.nn
文件,在ml-agent的models
文件夾下,將這個.nn文件考入Unity中,以下:
而後選中場景中的小球,將Behavior Parameters
組件中Model
屬性中,選擇剛纔訓練好的模型,並將Behavior Type
選爲Inference Only
,以下:
而後點擊運行,就能夠看到小球利用咱們訓練好的模型開始找方塊了。
咱們在命令行中,還能夠找到剛纔訓練的圖表信息,在命令行中輸入:
tensorboard --logdir=summaries
而後將地址在瀏覽器中打開,通常都是http://localhost:6006/
則能夠看到隨着訓練步數各個數值變化值。
這些值的含義,抄一些官方中文文檔:
Lesson - 只有在進行課程訓練]時纔有意義。
Cumulative Reward - 全部 agent 的平均累積場景獎勵。 在成功訓練期間應該增大。
Entropy - 模型決策的隨機程度。在成功訓練過程當中 應該緩慢減少。若是減少得太快,應增大 beta
超參數。
Episode Length - 全部 agent 在環境中每一個場景的 平均長度。
Learning Rate - 訓練算法搜索最優 policy 時須要多大的 步驟。隨着時間推移應該減少。
Policy Loss - policy 功能更新的平均損失。與 policy (決定動做的過程)的變化程度相關。此項的幅度 在成功訓練期間應該減少。
Value Estimate - agent 訪問的全部狀態的平均價值估算。 在成功訓練期間應該增大。
Value Loss - 價值功能更新的平均損失。與模型 對每一個狀態的價值進行預測的能力相關。此項 在成功訓練期間應該減少。
OK,以上就是官方訓練的一個小例子全過程了。
記錄這個還挺累,不過歡迎你們一塊兒留言討論,轉載麻煩請註明原地址哦,感謝你們~
引用:
https://github.com/Unity-Technologies/ml-agents/tree/master/docs