ML-Agents(三)3DBall


# 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中如下圖:

image-20200319233335183

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

image-20200319234037666

建好后在命令行中重新安裝環境(別忘記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,如下圖:

GPU

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

image-20200319233940196

二、3DBall介紹

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

3dBall

現根據官方文檔翻譯一下:

  • 設置:一個平衡球任務,agent需要保持小球在其腦袋上的平衡

  • 目標:Agent必須盡可能長時間地保持球在頭頂的平衡

  • Agent設置:環境中包含12個想同類型的agent,全部使用同樣的行為參數

  • Agent獎勵設置:

    • 小球每一步保持在方塊頭頂上就獎勵+0.1

    • 如果小球掉落,懲罰-0.1

  • 行為參數

    • 矢量觀察空間:8個變量,包括agent方塊的旋轉角度(兩個值,x、z軸方向),球和方塊之間的相對位置關系(Vector3),球上剛體的速度(Vector3)
    • 矢量動作空間:類型為ContinuousSize為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的區別就在於這里少了小球剛體速度的收集,從而導致前者在其他設置都相同的情況下,訓練效果不佳,如下圖。

3dHardBall

可以看到平台的抖動很大,就是因為沒有考慮到小球的速度影響而導致訓練結果天差地別,因此在用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。

image-20200329000940392

紅色的是不加if條件的,藍色的是官方加if的。其實從數據來看,大的趨勢都差不多,不過我從訓練現象來看,確實官方加if之后訓練過程比較穩定。

后面的獎勵代碼中,有三個條件判斷小球應該受到懲罰。

  • (ball.transform.position.y - gameObject.transform.position.y) < -2f

    小球與平台y方向上的差值小於2,如下圖:

    image-20200329001534471

    這里可以看出是小球掉落到平台下邊,其實大多數情況是其他兩種情況。

  • Mathf.Abs(ball.transform.position.x - gameObject.transform.position.x) > 3f

    和Mathf.Abs(ball.transform.position.z - gameObject.transform.position.z) > 3f

    這兩種放一起將,先來看看小球的位置:

    image-20200329001749169

    此時小球的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時調用,具體設置如下:

image-20200329002653210

代碼如下:

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.對於不遵守此聲明或者其他違法使用本文內容者,本人依法保留追究權等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM