目錄
- ML-Agents(二)創建一個學習環境
- 一、前言
- 二、概述
- 三、設定Unity專案
- 四、實作Agent
- 初始化和重置Agent
- 觀測環境(Observing the Environment)
- 動作(Actions)
- 獎勵(Rewards)
- AgentAction()方法
- 最終Editor設定
- 手動測驗環境
- 五、進行訓練
- TensorBoard統計資訊
ML-Agents(二)創建一個學習環境
一、前言
上一節我們講了如何配置ML-Agents環境,這一節我們創建一個示例,主要利用Reinforcement Learning(強化學習),

如上圖,本示例將訓練一個球滾動找到隨機放置的立方體,而且要避免從平臺上掉下去,
本示例是基于ML-Agents官方的示例,官方有中文版和英文版兩個檔案,英文版的是最新的,中文版中大部分內容和英文版的一致,但也有不同,本文是基于最新版所做(v0.15.0,master分支),需要參考官方檔案的也可參照如下地址食用,
英文:https://github.com/Unity-Technologies/ml-agents/tree/master/docs
中文:https://github.com/Unity-Technologies/ml-agents/blob/master/docs/localized/zh-CN/docs/Learning-Environment-Create-New.md
二、概述
在Unity專案中使用ML-Agents涉及以下基本步驟:
- 創建一個容納agent的環境,該環境可以從包含少量物件的簡單物理模擬環境到整個游戲或生態系統,環境的樣式可以多種多樣;
- 實作Agent子類,Agent子類定義了必要的代碼以供agent用于觀測自身環境、執行指定動作以及計算用于強化訓練的獎勵,你同樣可以實作可選方法,從而在agent完成任務或任務失敗時重置agent;
- 將實作Agent子類的腳本加到適當的GameObject上,當該物件在場景中,即代表對應agent在模擬環境中了,
(PS.在官方中文檔案中,第2,3步需要實作Academy子類和Brain,但在新版中,這兩個東西已經不需要在場景里定義了,所以比較重要的就是這個Agent子類,基本學習邏輯都在這里)
三、設定Unity專案
第一步,我們先新建一個Unity專案,并且將ML-Agents包匯入到里面:
-
打開Unity,新建一個專案隨意叫個名字,例如“RollerBall”;

-
在Unity選單“Edit”->“Project Settings”,在彈出的視窗中,找到“Player”,將“Api Compathbility Level”改為“.NET 4.x”,如下圖;


-
在上一節中,我們已經將ml-agents代碼庫克隆到了本地,如果沒有克隆,請參考上一篇“Unity ML-Agents v0.15.0(一)環境部署與試運行”中的五、1,這里我們默認大家都是已經克隆了庫,則在Unity中需要將ML-Agents插件匯入Unity中,我這里的版本是Unity2019.2,方法如下:
- 在專案根目錄中找到Packages檔案夾;

-
檔案夾中有一個“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球體
- 在 Hierarchy 視窗中右鍵單擊,選擇 3D Object > Sphere,
- 將游戲物件命名為“RollerAgent”
- 選擇 Target 以便在 Inspector 視窗中查看其屬性,
- 將 Transform 設定為 Position = (0,0.5,0)、Rotation = (0,0,0)、Scale = (1,1,1),
- 在 Sphere 的 Mesh Renderer 上,展開 Materials 屬性并將默認材質更改為 checker 1,
- 單擊 Add Component,
- 向 Sphere 添加 Physics/Rigidbody 組件,(添加 Rigidbody)

-
OK,以上程序就將Unity中的三維環境創建好了,下面我們來實作Agent,
四、實作Agent
在官方中文檔案中還有“實作Academy”及“添加Brain”,最新版里已經不需要了!直接設定Agent就行,
要創建Agent:
- 選擇 RollerAgent 游戲物件以便在 Inspector 視窗中查看該物件,
- 單擊 Add Component,
- 在組件串列中單擊 New Script(位于底部),
- 將該腳本命名為“RollerAgent”,
- 單擊 Create and Add,
然后,編輯新的RollerAgent腳本:
- 打開
RollerAgent腳本; - 令
RollerAgent繼承Agent類,同時參考using MLAgents和using MLAgents.Sensors命名空間; - 洗掉
Update()方法,先保留Start()方法之后要用,
到目前為止,以上的步驟都是為了將ML-Agents添加到任何Unity專案中而需要的基本步驟,接下來,我們將添加邏輯,使我們的agent能夠利用reinforcement learning(強化學習)技術學習找到立方體,
初始化和重置Agent
當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引數,不過用法差不多,
觀測環境(Observing the Environment)
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(獎勵),
動作(Actions)
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);
獎勵(Rewards)
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();
}
AgentAction()方法
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();
}
}
最終Editor設定
到這一步,所有的游戲物件和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統計資訊
我們在命令列中,還可以找到剛才訓練的圖表資訊,在命令列中輸入:
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
https://github.com/Unity-Technologies/ml-agents/blob/master/docs/localized/zh-CN/docs/Learning-Environment-Create-New.md
寫文不易~因此做以下申明:
1.博客中標注原創的文章,著作權歸原作者 煦陽(本博博主) 所有;
2.未經原作者允許不得轉載本文內容,否則將視為侵權;
3.轉載或者參考本文內容請注明來源及原作者;
4.對于不遵守此宣告或者其他違法使用本文內容者,本人依法保留追究權等,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/3897.html
標籤:其他
