1. 程式人生 > >Unity機器學習 | 編寫代理及建立遊戲AI

Unity機器學習 | 編寫代理及建立遊戲AI

自2017年9月Unity推出了機器學習代理工具, 機器學習的開發者持續增長並在社群中獲得認可。Unity機器學習代理專案入選mybridge評選2017年最佳30個機器學習開源專案,並在Github中獲得1710星。Unity機器學習社群挑戰賽也在如火如荼的進行中。



今天的文章中,我們將會學習如何設定一個基本代理,它能利用強化機器學習達到隨機選擇的數字目標。我們將使用到最新的Unity機器學習代理工具建立並訓練代理,完成指定任務,並探討將這個簡單的代理優化為真正的遊戲AI。

設定Unity機器學習代理工具和TensorFlow

開始之前,我們需要設定好機器學習代理工具。設定請參考以下文章:

配置Unity機器學習代理工具和TensorFlow環境



Mac下配置Unity機器學習代理工具

說明:本文的程式碼和執行環境基於Windows 10環境。

機器學習代理(ML-Agents)場景設定

當我們完成設定後,開啟Unity專案,建立新場景。

首先新建一個遊戲物件,命名為“NumberAcademy“。新增“TemplateAcademy”元件到“NumberAcademy“遊戲物件中。

TemplateAcademy元件指令碼可從Github下載:

https://github.com/Unity-Technol ... /TemplateAcademy.cs

場景設定過程並不需要這個元件做太多事,所以我們只用模板中的基本內容即可。
 


NumberAcademy遊戲物件



在這個元件下,建立子游戲物件,命名為“NumberBrain“。

新增一個Brain元件。將狀態數量(State Size)和動作數量(Action Size)的值設為2。將動作空間型別(Action Space Type)設為離散(Discrete)。

在這專案中,我們將會用到兩個獨立的動作,也就是“上”和“下”。之所以使用離散型別,是因為這些動作會以整數值形式呈現。

將狀態空間型別(State Space Type)設為連續(Continuous)。我們將跟蹤兩個浮點數,所以使用連續型別。



NumberBrain遊戲物件



將大腦型別(Brain Type)設為玩家(Player),並加入兩個動作。選擇任意兩個鍵位,在此我們選擇的是A和B,並分別賦值為0和1。繫結0的鍵位將減小當前值,而繫結1的鍵位將增大它。


 


Brain指令碼元件



現在我們來建立新指令碼,命名為NumberDemoAgent.cs,將其基本類設定為Agent,替換原有的“: MonoBehaviour with : Agent”。程式碼如下:
 

[C#] 純文字檢視 複製程式碼

?

public class NumberDemoAgent : Agent

{

[SerializeField]

private float currentNumber;

[SerializeField]

private float targetNumber;

[SerializeField]

private Text text;

[SerializeField]

private Transform cube;

[SerializeField]

private Transform sphere;

int solved;



currentNumber和targetNumber欄位在這段程式碼裡最重要。其它的程式碼都是用作除錯和視覺化。我們的代理將挑選一個隨機的targetNumber,試著通過使用增長和減小指令,將currentNumber的值調整到目標值。

下面將重寫CollectState方法。程式碼如下:
 

[C#] 純文字檢視 複製程式碼

?

public override List<float> CollectState()

{

List<float> state = new List<float>();

state.Add(currentNumber);

state.Add(targetNumber);

return state;

}



在上面這段段程式碼裡,我們會返回兩個浮點數給currentNumber和targetNumber,作為代理的狀態。

注意:這裡是如何匹配二個狀態變數的,而且它們都是浮點數,這就是為什麼我們要將狀態空間型別設為連續而不是分離。

為了訓練我們的代理,需要選取隨機目標數,所以要重寫AgentReset()方法。程式碼如下:
 

[C#] 純文字檢視 複製程式碼

?

public override void AgentReset()

{

targetNumber = UnityEngine.Random.RandomRange(-1f, 1f);

sphere.position = new Vector3(targetNumber * 5, 0, 0);

currentNumber = 0f;

}



最後也是最重要的一部分是AgentReset()方法。這是我們的輸入動作,處理任務,也就是迴應動作,如果代理回報(reward)結果則為成功。

程式碼如下:
 

[C#] 純文字檢視 複製程式碼

?

public override void AgentStep(float[] action)

{

if (text != null)

text.text = string.Format("C:{0} / T:{1} [{2}]", currentNumber, targetNumber, solved);

switch ((int)action[0])

{

case 0:

currentNumber -= 0.01f;

break;

case 1:

currentNumber += 0.01f;

break;

default:

return;

}

cube.position = new Vector3(currentNumber * 5f, 0f, 0f);

if (currentNumber < -1.2f || currentNumber > 1.2f)

{

reward = -1f;

done = true;

return;

}

float difference = Mathf.Abs(targetNumber - currentNumber);

if (difference <= 0.01f)

{

solved++;

reward = 1;

done = true;

return;

}

}



首先我們會看到文字的變化。這只是用於除錯或視覺化,它讓我們能看到當前值,還有目標值,以及我們所需要解決問題(即達到目標值)所測試的數值次數。

下一步是切換檢視動作和完成任務的地方。在示例中,指令碼要麼通過減小當前值迴應動作0,要麼增大當前值迴應動作1。除此之外,輸入的其它值都無效,但若是指令碼得到了其它值,指令碼會忽略這個值並返回。

現在我們基於currentNumber移動立方體,這個值會用作x軸偏移值。該立方體在此用於視覺化,對實際的邏輯或訓練過程沒有任何影響。

然後檢查currentNumber對大小限制的反應。因為我們選取的隨機數是在-1和1之間的,如果隨機數為-1.2或是1.2,將視作失敗,因為數值超過了極限。本示例中,我們給代理回報-1,表示失敗,然後給done變數賦值為true,以讓代理能重置並再次嘗試。

最後,我們會檢查currentNumber和目標值的差值是否小於0.01。若小於,則認為是匹配值,將回報(reward)值設為1.0,表示成功,給done賦值為true表示完成。我們還會再次期間使用solved變數作為計數器,用於除錯,這樣我們就能知道成功的次數了。

下面是完整的指令碼程式碼:
 

[C#] 純文字檢視 複製程式碼

?

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

public class NumberDemoAgent : Agent

{

[SerializeField]

private float currentNumber;

[SerializeField]

private float targetNumber;

[SerializeField]

private Text text;

[SerializeField]

private Transform cube;

[SerializeField]

private Transform sphere;

int solved;

public override List<float> CollectState()

{

List<float> state = new List<float>();

state.Add(currentNumber);

state.Add(targetNumber);

return state;

}

public override void AgentStep(float[] action)

{

if (text != null)

text.text = string.Format("C:{0} / T:{1} [{2}]", currentNumber, targetNumber, solved);

switch ((int)action[0])

{

case 0:

currentNumber -= 0.01f;

break;

case 1:

currentNumber += 0.01f;

break;

default:

return;

}

cube.position = new Vector3(currentNumber * 5f, 0f, 0f);

if (currentNumber < -1.2f || currentNumber > 1.2f)

{

reward = -1f;

done = true;

return;

}

float difference = Mathf.Abs(targetNumber - currentNumber);

if (difference <= 0.01f)

{

solved++;

reward = 1;

done = true;

return;

}

}

public override void AgentReset()

{

targetNumber = UnityEngine.Random.RandomRange(-1f, 1f);

sphere.position = new Vector3(targetNumber * 5, 0, 0);

currentNumber = 0f;

}

}



設定代理

現在指令碼完成了,我們需要新建遊戲物件,命名為“NumberDemoAgent”。

將剛剛寫好的NumberDemoAgent.cs指令碼附加到該遊戲物件上,並將NumberBrain新增到該元件的Brain部分。
 


NumberDemoAgent遊戲物件



下一步新建文字(Text)物件,將其放到明顯的位置,理想位置是在螢幕的中央,字號要大。將該文字物件附加到NumberDemoAgent上。

新建立方體(Cube)物件,將它們也新增到NumberDemoAgent上,這樣我們可以看到過程的變化,比閱讀一個個數值更輕鬆。

在執行模式下測試

點選play,就能用設定好的鍵位A和B,左右移動立方體。當我們將方塊向球體移動時,它將增大solved計數器,並重置。如果朝錯誤的方向移動的太遠,它也會重置(請記住1.2的範圍值限制)。

訓練

當它在執行模式下成功執行後,選擇brain並把Brain Type設為外部(External)。儲存場景,並構建一個可執行檔案,檔案中只包含了一個啟用除錯模式的場景。



關於輸出資料夾,選擇python資料夾作為存放這個機器學習代理專案的資料夾。例如,我的資料夾的地址是這個:C:\ml-agents\python。別忘了該可執行檔案的名字,因為後續我們就需要它了。

Anaconda / Jupyter

啟動Anaconda命令指示符。將目錄定位到剛剛的構建目錄,也就是那個python資料夾下,命令示例:cd c:\ml-agents\python

輸入命令“jupyter notebook”(提示:這裡可能要打兩次回車),自動開啟瀏覽器介面。會得到這樣一個網頁介面:



提示:這裡要修改高亮部分。對於env_name變數,要輸入可執行檔案的名字。對於buffer_size和batch_size,你可以使用截圖裡的值。要注意,這裡面的當前值部分只在測試的時候會看到。

當編輯好Hyperparameters部分後,按照步驟執行。從第一步和第二步開始。在第三步時,你會看到一個開啟的遊戲視窗。第一次開啟時,你也許會得到視窗許可對話方塊,記得要選擇允許。

在進行到第四步時,先注意得到的結果,第一次執行時也許會需要幾分鐘。



當它儲存多次後,點選stop按鈕。然後繼續第五步,並執行。這將匯出你的訓練資料到一個與可執行檔案同名的.bytes檔案中,匯出位置在上述python目錄的子目錄下。示例:python/models/ppo。



複製.bytes檔案,(再次提醒,它的名字會和你的可執行檔名字一樣)將這個貼上到Unity專案裡的某個位置。

選擇Brain指令碼元件,將Brain Type設為Internal。把.byetes檔案新增到Graph Model欄位上。



儲存並點選執行,就這樣我們就完成建立自定義代理。

結語

這個示例相當簡單,只是用來讓你理解這個系統的運作方式。我們很期待能看到這個專案你能夠繼續開發,並構建成更大更有趣的專案,用來控制遊戲AI,從而製作出有意思的遊戲機制和AI。更多精彩的機器學習文章歡迎訪問 Unity官方社群(Unitychina.cn)! 更多Unity機器學習社群挑戰賽的資訊請訪問Unity Connect!

參考資訊

Unity ML Agents GitHub
https://github.com/Unity-Technologies/ml-agents

HyperParameters Doc
https://github.com/Unity-Technol ... st-practices-ppo.md

2017年最佳30個機器學習開源專案
https://medium.mybridge.co/30-am ... v-2018-b853b8621ac7