前言:上一篇博文已經介紹了Unity Ml-Agents的環境配置了。
個人建議先敲深度強化學習的Demo再摸清概念比較容易上手,因此本文先提供一個深度強化學習的Demo示例簡單闡述下。
更新於2020.3.6:由於現在Unity ml-agents項目比起2018年已經更新了許多,以前的Demo教程已經不適合了,因此決定翻新Unity ml-agents機器學習系列博客。
更新於2020.7.6:沒想到僅僅過了幾個月,ml-agents項目已經從最初的beta版到現在已經第3個正式發行版了。因此再次翻新博客。
本次示例:訓練一個追蹤紅球的白球AI
1. 新建Unity項目,導入package
進入Unity項目,在上方 Window => Package Manager,然后安裝 Barracuda 這個package(如果沒看見,一般就是沒有顯示All packages或沒顯示preview package):

注意:不要在Package Manager加載ml-agents package,因為后面我們要手動導入該包相關內容,不然會引發重復定義的錯誤。
並將之前下載的ml-agents項目com.unity.ml-agents目錄下Editor、Plugin、Runtime復制進新建Unity項目里(建議放在Assets文件夾內)。
2. 編寫Agent腳本
RollerAgent 是將用於智能體對象的組件腳本:
//RollerAgent.cs
//繼承Agent用於重寫智能體的CollectObservations等方法。
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
public class RollerAgent : Agent
{
public Transform Target;
public float speed = 10;
Rigidbody rBody;
void Start()
{
rBody = GetComponent<Rigidbody>();
}
//進入新一輪訓練時調用
public override void OnEpisodeBegin()
{
if (this.transform.position.y < 0)
{
//如果智能體掉下去,則重置位置+重置速度
this.rBody.angularVelocity = Vector3.zero;
this.rBody.velocity = Vector3.zero;
this.transform.position = new Vector3(0, 0.5f, 0);
}
//將目標球重生至一個新的隨機位置
Target.position = new Vector3(UnityEngine.Random.value * 8 - 4, 0.5f, UnityEngine.Random.value * 8 - 4);
}
//收集觀察結果
public override void CollectObservations(VectorSensor sensor)
{
//觀察目標球和智能體的位置
sensor.AddObservation(Target.position);
sensor.AddObservation(this.transform.position);
//觀察智能體的速度
sensor.AddObservation(rBody.velocity.x);
sensor.AddObservation(rBody.velocity.z);
//在這里因為目標球是不會動的,智能體也不會在y軸上又運動,所以沒有必要觀察這些值的變化。
//sensor.AddObservation(rBody.velocity.y);
}
//處理接受的動作,並根據當前動作評估獎勵信號值
public override void OnActionReceived(float[] vectorAction)
{
//------ 動作處理
// 接受兩個動作數值
Vector3 controlSignal = Vector3.zero;
controlSignal.x = vectorAction[0];
controlSignal.z = vectorAction[1];
rBody.AddForce(controlSignal * speed);
//------ 獎勵信號
float distanceToTarget = Vector3.Distance(this.transform.position, Target.position);
// 到達目標球
if (distanceToTarget < 1.42f)
{
//獎勵值+1.0f
SetReward(1.0f);
EndEpisode();
}
// 掉落場景外
if (this.transform.position.y < 0)
{
EndEpisode();
}
}
//手動操控智能體,用於手動調試智能體或啟發模仿學習。
public override void Heuristic(float[] action)
{
action[0] = -Input.GetAxis("Horizontal");
action[1] = Input.GetAxis("Vertical");
}
}
Agent,即智能體,含有感知和行為——它通過觀察環境然后做出相應的行為。在最常使用的強化學習里,智能體的訓練模型類似一個黑盒。
每一次模擬步長中,智能體的感知會作為黑盒的輸入,然后黑盒會輸出行為選擇,然后根據行為選擇來讓智能體做出行為。
當我們需要創建一個智能體類型時,讓其繼承Agent類,以用於重寫智能體CollectObservations,OnActionReceived等方法。
void OnEpisodeBegin()
- 每一輪訓練開始時調用,一般用於負責重新設置場景。
在示例里,為了讓訓練更加有效更加廣泛化,因此該函數內容是給目標球設置的是隨機位置(實際上智能體球也應該設置隨機位置)。
void CollectObservations(VectorSensor sensor)
- 每一個模擬步長都會被調用。
- 負責收集智能體的對環境的觀察信息。
這部分類似於黑箱子的輸入。值得注意的是,所需觀察的信息越少越好。因此,我們需要盡可能減少不必要的觀察信息,這會讓訓練變得更加快速、准確。
void OnActionReceived(float[] vectorAction)
- 每一個模擬步長都會被調用。
- 負責接受決策的行為選擇從而讓智能體做出行為。示例里,通過行為選擇的2個float輸入值來驅使球體移動,一旦掉出場景外,便調用Done()。
- 負責評估此步長的reward(獎勵值)。示例里,只要觸碰到目標球即可獲得一定的reward。
如何根據實際問題設計reward往往是一個難點,設計的不好(例如部分獎勵值過大)容易造成網絡不收斂。
void Heuristic(float[] action)
- 通過玩家親自操控智能體來輸出行為選擇。
親自操控智能體可用於模仿學習或調試智能體的行為。
3. 搭建好游戲場景
創建一個地板:
創建一個小球:
創建一個智能體(RollerAgent):
先創建一個帶剛體的球體對象,然后我們需要給它掛載RollerAgent腳本(掛載后自動額外掛載BehaviorParameters腳本用於配置)和DecisionRequester腳本。
4. 調整腳本參數
Behavior Parameters
每個Agent還必須得附帶一個行為參數腳本,行為參數腳本用於定義智能體如何做出決策。
Vector Observation Space Size:觀察信息的大小。在本示例中應調整為8,因為示例智能體腳本總共需要觀察的特征元素為2個3D位置+2個1D速度,因此總共需要空間為8個float大小。
Vector Action Space Size:動作矢量的大小。在本示例中應調整為2,因為智能體腳本里接受2個浮點型動作輸入。動作矢量的元素可以選擇兩種類型:一種是離散型的整型數值,適用於離散動作,例如下棋的位置選擇;另一種則是連續性的浮點數值,適用於連續動作,例如3個float值可以代表一個施加到智能體剛體的力或力矩。
Inference Device:調整為GPU,從而使用GPU來訓練。
Behavior Type:行為類型,主要有Default、Heuristic、Inference三種模式。
- Default:默認訓練模式,用於一般的強化學習。
- Heuristic Only:啟發模式,玩家親自操控智能體,可用於模仿學習或調試游戲場景。
- Inference Only:推理模式,運行訓練好的模型。
Roller Agent
Max Step:決定智能體最多可以有多少步決策,超過限制后則強制Done。特殊地,設置為0意思是不限制步數。在本示例中應調整為0。
Decision Requester
Decision Period:決策間隔。在本示例中應調整為10。
目前場景預覽:
在這里,最好先Behavior Type切換成Heuristic Only模式用於調試游戲場景,運行Unity場景后可嘗試自己用WASD鍵盤操控小球,測試游戲場景是否OK。然后確認無問題后再切換回Default。
5. 開始訓練
然后現在可以打開開始菜單,直接使用cmd命令窗口,
cd到之前下載ml-agents項目的目錄里
cd C:\Downloads\ml-agents
再輸入激活ml-agents環境:
activate ml-agents
開啟訓練:
mlagents-learn config/ppo/config.yaml
- config/ppo/config.yaml是訓練配置文件,RollerBall-1是你給訓練出來的模型取的名字
- 此外注意config/ppo/config.yaml是不存在的,需要自己仿照官方的示例yaml文件修改配置而新建的。
下面是config.yaml示例:
behaviors:
RollerBall:
trainer_type: ppo
hyperparameters:
batch_size: 64
buffer_size: 12000
learning_rate: 0.0003
beta: 0.001
epsilon: 0.2
lambd: 0.99
num_epoch: 3
learning_rate_schedule: linear
network_settings:
normalize: true
hidden_units: 128
num_layers: 2
vis_encode_type: simple
reward_signals:
extrinsic:
gamma: 0.99
strength: 1.0
keep_checkpoints: 5
max_steps: 300000
time_horizon: 1000
summary_freq: 1000
threaded: true
有關config參數具體配置將放在文末附錄。由於ml-agents項目一直在更新,配置的格式也可能會有改變。本文提供的配置文件示例是依據第三版正式發行版時配置文件格式編寫的。
當出現如下畫面:
返還到Unity,點下運行鍵,那么你就會看到Unity執行訓練。
你的命令窗口也會時刻告訴你訓練階段的信息:
- Step:模擬的步長次數
- Time Elapsed:所用時間
- Mean Reward:獎勵平均值
- Std of Reward:獎勵標准方差值
一般來說,隨着訓練的進行,獎勵平均值越來越高,獎勵標准方差值越來越低。這意味着智能體的行為越來越穩定趨向於獲獎收益最高的行為。
現在可以去掛機等待結果了,亦或者在某個時間停止Unity場景運行。那么ml-agents會將目前為止訓練出來的數據模型(.nn文件)保存到ml-agents\results目錄下。
6. 將訓練過的模型整合到Unity中
將訓練出來的nn文件導入到Unity項目文件夾中,並在智能體Behavior Parameters腳本上的Model選擇剛剛導入的nn文件;然后將Behavior Type調整為Inference Only。
運行Unity場景,看看你跑出來的模型的蠢樣了(笑)。
附錄
config文件配置
參數配置(翻修中,建議參考關於訓練配置文件的官方文檔)
參考
另外一提,最新的介紹文檔資料示例等都在Unity官方機器學習的github項目,感興趣可以持續保持關注它的更新:
[1] Unity官方機器學習的github項目 https://github.com/Unity-Technologies/ml-agents
[2] Unity官方博客機器學習概念詳解(1) https://blogs.unity3d.com/2017/12/11/using-machine-learning-agents-in-a-real-game-a-beginners-guide/
[3] Unity官方博客機器學習概念詳解(2) https://blogs.unity3d.com/2017/06/26/unity-ai-themed-blog-entries/
[4] Unity ml-agents概念詳解國內翻譯博客 https://blog.csdn.net/u010019717/article/details/80382933