目錄
- 一、利用GPU進行訓練
- 二、3DBall介紹
- 三、3DBall代碼分析
- 初始化
- 環境觀察值
- Agent動作反饋
- Agent復位
- Agent手動設定
# ML-Agents(三)3DBall例子
前一周忙著公司的考試,都沒有怎么學新的,今天補上~
之后的記錄,我準備先只研究官方的示例,主要是把研究程序中的疑惑和想法記下來,首先我先補充一下如何利用GPU進行訓練,結合(一)中的安裝方法,需要CUDA v10.0,cuDNN v7.6.5 for CUDA v10.0,對應Tensorflow的版本是2.0.1,
一、利用GPU進行訓練
前置作業在文章(一)中都有,原先的環境可以保留,現在可以拉一個新的ml-agents原始碼,然后修改ml-agents檔案下的setup.py中如下圖:

原來是"tensorflow>=1.7,<2.1",現在修改為"tensorflow-gpu>=1.7,<2.1",然后再在Anaconda中新建一個環境,如下:

建好后在命令列中重新安裝環境(別忘記cd到新的ml-agents原始碼),分別輸入:
pip install -e ml-agents-envs -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
pip install -e ml-agents -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
就是分別安裝兩個環境,可以發現他會自動下載tensorflow_gpu-2.0.1,如下圖:

配置好后,在Unity對應的Agent腳本上,也需要將Inference Device勾選為GPU,然后按以前的方法開始訓練,就可以了,

二、3DBall介紹
官方示例中,3Dball是一個比較簡單的例子,主要運用了reinforcement learning(強化學習),就是小球在平臺上,萌版平臺要控制自己繞x、z軸旋轉,從而保持小球在自己頭上不掉下來,

現根據官方檔案翻譯一下:
-
設定:一個平衡球任務,agent需要保持小球在其腦袋上的平衡
-
目標:Agent必須盡可能長時間地保持球在頭頂的平衡
-
Agent設定:環境中包含12個想同型別的agent,全部使用同樣的行為引數
-
Agent獎勵設定:
-
小球每一步保持在方塊頭頂上就獎勵+0.1
-
如果小球掉落,懲罰-0.1
-
-
行為引數
- 矢量觀察空間:8個變數,包括agent方塊的旋轉角度(兩個值,x、z軸方向),球和方塊之間的相對位置關系(Vector3),球上剛體的速度(Vector3)
- 矢量動作空間:型別為
Continuous,Size為2,分別控制繞x軸旋轉、繞z軸旋轉
-
Float屬性:三個
- scale(比例):小球的比例,默認為1,推薦最小值為0.2,最大值為5
- gravity(重力):重力加速度,默認為9.81,推薦最小值4,最大值為105
- mass(質量):小球的質量,默認為1,推薦最小值為0.1,最大值為20
-
基準平均獎勵:100
OK,上面是借鑒官方檔案,隨意翻譯了一下,大概可以了解3DBall主要用途和一些主要引數,里面的Float屬性我這里不是很明白,在代碼中是用在Agent.InitializeAgent()中的SetResetParameters(),這個方法顧名思義應該是對Agent進行初始化的操作,也許在這里,我們可以任意修改小球的比例、質量、重力加速度來改變小球在不同的情況下,訓練的效果如何吧,
三、3DBall代碼分析
看到目前為止,ml-agents其中的精華就在agent的腳本如何設定了,我們下面來分析一下Ball3DAgent代碼,
初始化
public class Ball3DAgent : Agent
{
[Header("Specific to Ball3D")]
public GameObject ball;
Rigidbody m_BallRb;
IFloatProperties m_ResetParams;
public override void InitializeAgent()
{
m_BallRb = ball.GetComponent<Rigidbody>();
m_ResetParams = Academy.Instance.FloatProperties;
SetResetParameters();
}
public void SetBall()
{
//從Academy中獲取小球的屬性(質量、比例)
m_BallRb.mass = m_ResetParams.GetPropertyWithDefault("mass", 1.0f);
var scale = m_ResetParams.GetPropertyWithDefault("scale", 1.0f);
ball.transform.localScale = new Vector3(scale, scale, scale);
}
public void SetResetParameters()
{
SetBall();
}
}
這里初始化應用了InitializeAgent()方法,這里獲取了小球的剛體,并且利用SetBall()來設定了小球的質量和比例,這里的的m_ResetParams變數是Academy的FloatProperties變數,這里的變數好像是會作為環境引數傳遞給Python,具體的用途我也還沒研究清楚,姑且先看做是初始化小球的屬性,
環境觀察值
直接上原始碼,
public override void CollectObservations(VectorSensor sensor)
{
//平臺繞Z軸旋轉值
sensor.AddObservation(gameObject.transform.rotation.z);
//平臺繞X軸旋轉值
sensor.AddObservation(gameObject.transform.rotation.x);
//小球與平臺的相對位置
sensor.AddObservation(ball.transform.position -gameObject.transform.position);
//小球剛體的速度
sensor.AddObservation(m_BallRb.velocity);
}
以上一共運用了8個觀察值,注意Vector3型別的變數算是3個觀察值(x,y,z),
在Ball3DHardAgent專案里,與Ball3DAgent的區別就在于這里少了小球剛體速度的收集,從而導致前者在其他設定都相同的情況下,訓練效果不佳,如下圖,

可以看到平臺的抖動很大,就是因為沒有考慮到小球的速度影響而導致訓練結果天差地別,因此在用ML-Agents的時候,需要嚴謹的考慮環境的觀測項,可能由于一個觀測項的增加或洗掉,就導致最終學習結果的好壞,這里我也是慢慢才學習,這就是我為什么要先研究官方的示例,到時候最壞也可以照貓畫虎,
Agent動作反饋
這里是Agent的核心實作,觀測值通過Agent收集到Brain處,Brain再通過外部Python訓練環境反饋動作,再沿相同的路線回傳到Agent的AgentAction(float[] vectorAction)上(這里不知道我的想法對不對),具體的代碼如下,
public override void AgentAction(float[] vectorAction)
{
//控制平臺繞Z軸、X軸旋轉的值
//用Mathf.Clamp()將回應的動作值限制到-2到2
var actionZ = 2f * Mathf.Clamp(vectorAction[0], -1f, 1f);
var actionX = 2f * Mathf.Clamp(vectorAction[1], -1f, 1f);
//平臺繞Z軸旋轉回應
if ((gameObject.transform.rotation.z < 0.25f && actionZ > 0f) ||
(gameObject.transform.rotation.z > -0.25f && actionZ < 0f))
{
gameObject.transform.Rotate(new Vector3(0, 0, 1), actionZ);
}
//平臺繞X軸旋轉回應
if ((gameObject.transform.rotation.x < 0.25f && actionX > 0f) ||
(gameObject.transform.rotation.x > -0.25f && actionX < 0f))
{
gameObject.transform.Rotate(new Vector3(1, 0, 0), actionX);
}
//gameObject.transform.Rotate(new Vector3(0, 0, 1), actionZ);
//gameObject.transform.Rotate(new Vector3(1, 0, 0), actionX);
//當小球在平臺上,掉落或飛出平臺,分別進行獎勵或懲罰
if ((ball.transform.position.y - gameObject.transform.position.y) < -2f ||
Mathf.Abs(ball.transform.position.x - gameObject.transform.position.x) > 3f ||
Mathf.Abs(ball.transform.position.z - gameObject.transform.position.z) > 3f)
{
SetReward(-1f);//懲罰1
Done();//此次訓練結束并重新開始,會呼叫AgentReset()
}
else
{
SetReward(0.1f);//在平臺上的時候,每次動作都獎勵0.1
}
}
首先是平臺對于旋轉的回應,我又將兩個if的條件去掉訓練了一下,發現平臺訓練程序中比較不穩,抖動較大,因為只要一來值就讓平臺旋轉,可能這里會造成平臺一直在調整姿態的程序中,而源代碼中,以繞Z軸為例,只有在平臺Z軸旋轉值<0.25f且actionZ>0、或平臺Z軸旋轉值>0.25f且actionZ<0時才對平臺的姿態進行動作,這樣就相當于設定了一個緩沖區間,不會讓平臺不停調整姿態,而是根據小球情況來適當調整姿態,
這里附上兩次訓練的tensorboard,

紅色的是不加if條件的,藍色的是官方加if的,其實從資料來看,大的趨勢都差不多,不過我從訓練現象來看,確實官方加if之后訓練程序比較穩定,
后面的獎勵代碼中,有三個條件判斷小球應該受到懲罰,
-
(ball.transform.position.y - gameObject.transform.position.y) < -2f
小球與平臺y方向上的差值小于2,如下圖:

這里可以看出是小球掉落到平臺下邊,其實大多數情況是其他兩種情況,
-
Mathf.Abs(ball.transform.position.x - gameObject.transform.position.x) > 3f
和Mathf.Abs(ball.transform.position.z - gameObject.transform.position.z) > 3f
這兩種放一起將,先來看看小球的位置:

此時小球的x,z值都是3,可以看出小球剛好在x軸方向或者z方向滾出了平臺邊緣,
所以,上面三種情況只要發生一種就對小球Agent做出-1懲罰,同時呼叫Done(),
Agent復位
復位就比較簡單了,來看代碼:
public override void AgentReset()
{
//復位平臺旋轉角度
gameObject.transform.rotation = new Quaternion(0f, 0f, 0f, 0f);
//令平臺隨機繞x軸旋轉-10~10度
gameObject.transform.Rotate(new Vector3(1, 0, 0), Random.Range(-10f, 10f));
//令平臺隨機繞z軸旋轉-10~10度
gameObject.transform.Rotate(new Vector3(0, 0, 1), Random.Range(-10f, 10f));
//小球剛體速度變為0
m_BallRb.velocity = new Vector3(0f, 0f, 0f);
//小球在y(相對平臺高度)為4的地方,同時隨機x、z值出現
ball.transform.position = new Vector3(Random.Range(-1.5f, 1.5f), 4f, Random.Range(-1.5f, 1.5f))
+ gameObject.transform.position;
//Agent重置時,同時重置引數,[Obsolete]這里是指小球的質量和比例,其實我覺得這里沒必要,估計之后別的專案有用
//[new]這里重新設定泛化引數,具體見本博“ML-Agents(四)3DBall補充の引入泛化”
SetResetParameters();
}
這里的代碼比較簡單,注釋能看明白即可,
Agent手動設定
這里主要是當訓練模式為Heuristic Only時呼叫,具體設定如下:

代碼如下:
public override float[] Heuristic()
{
var action = new float[2];
action[0] = -Input.GetAxis("Horizontal");
action[1] = Input.GetAxis("Vertical");
return action;
}
這里的代碼相當于我們輸入來控制動作向量空間的值,其實就是action[]陣列,我們令action[0]控制平臺繞x軸的旋轉,action[1]控制平臺繞z軸的旋轉,
可以試一下,其實要保持小球在平臺上還有點難度,
至此第一個例子就研究到這,有什么問題歡迎大家一起探討,
寫文不易~因此做以下申明:
1.博客中標注原創的文章,著作權歸原作者 煦陽(本博博主) 所有;
2.未經原作者允許不得轉載本文內容,否則將視為侵權;
3.轉載或者參考本文內容請注明來源及原作者;
4.對于不遵守此宣告或者其他違法使用本文內容者,本人依法保留追究權等,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/2207.html
標籤:其他
上一篇:An approach to implement basic calculator with RPN and stack
