ML-Agents 閱讀筆記
===
Github:https://github.com/Unity-Technologies/ml-agents
說明文件(Docs):[Unity ML-Agents Toolkit Documentation](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Readme.md)
(不建議讀翻譯版,版本太舊,自行用 Google 翻譯看效果不錯)
Unity Manual:https://docs.unity3d.com/Packages/com.unity.ml-agents@2.1/manual/index.html
Installation & Set-up
---
### [Installation](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Installation.md)
- 如果要修改或想用最新的 example,要用 git clone 的方式安裝
- 要裝的東西:
- Unity:com.unity.ml-agents
- Python:
- mlagents:內建訓練模型,基於 mlagents_envs
- 附帶 `mlagents-learn` command line 指令
- mlagents.trainers 裡面有
- demo_loader
- demo_to_buffer
- buffer
- AgentBuffer
- mlagents_envs:最基本的,較底層與 Unity 溝通
- gym_unity(optional):OpenAI Gym interface
#### [Using Virtual Environment](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Using-Virtual-Environment.md)
- Python venv 的教學,會的話不用看
- 我的想法:可以用 poetry 或是 conda 看看,不然也可用 Colab
Getting Started
---
### [Getting Started Guide](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Getting-Started.md)
- 使用 3D Balance Ball 作為範例講解
- Agent(智能代理 / 主體)
- 同一個環境(場景)可以放好幾個
- Behavior Parameters:決策依據
- 觀察結果的向量
- Actions(分為連續和離散)
- Max Step:最多幾次要歸零重來
- 在講解訓練的步驟、方式,以及如何載入訓練好的模型
- 要熟悉 ML-Agents 的操作流程可以由這個範例著手
### [ML-Agents Toolkit Overview](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/ML-Agents-Overview.md)
==寫程式破關的人必看!==
講 ML-Agents Toolkit 的概觀、細部架構,
就算不使用官方內建 Trainer 也是可以參考這些機器學習的模型
優點:訓練智能代理的平台,支持多種訓練模式和場景,並提供多種功能
#### [Background: Unity](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Background-Unity.md)
- Unity 的使用說明(一些常用到的概念、物理引擎、說明等等)
- 熟悉 Unity 的就不用看
#### [Background: Machine Learning](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Background-Machine-Learning.md)
- 無監督式 / 監督式 / 強化學習
- 強化學習:訓練出策略
- 
- 屬性的選擇與模型的選擇
- 深度學習可以擬合上述的這些無監督式 / 監督式 / 強化學習
- 熟悉 ML 的就不用看
#### [Background: PyTorch](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Background-PyTorch.md)
- 有用到 PyTorch(模型)、TensorBoard(可視化)
- PyTorch 是可以支援 TensorBoard 的(神奇吧!)
以上三篇的背景知識(Background)要先看再繼續下去:
- 文章中的「圖」都是重點,要理解
- 以下面「訓練 NPC 行為」的範例遊戲來貫穿整篇文章
- 範例遊戲是如何在戰爭中讓醫生救到最多士兵
- 重要元件
- 學習環境(Learning Environment)
- Agent(智能代理 / 主體)
- 負責觀察、執行 Action、給獎勵
- Behavior(行為 / 大腦)
- 負責和機器學習的模型溝通、接收 Agent 傳過來的觀察結果,判斷要做什麼 Action
- 判斷依據
- 訓練(Training):透過 Python 訓練的階段
- 啟發(Heuristic):人為操作、給定規則
- 推測(Inference):根據訓練好的模型推測
- Environment Parameters(環境信息)
- 可以透過 Side Channel 傳給 Python
- Python 底層 API
- Python 端的 mlagents_envs 套件
- 外部溝通管道(External Communicator)
- Unity 與 Python 的溝通管道
- Python Trainer:Python 端的 mlagents 套件
- 附帶一個 Command Line 程式:mlagents-learn
- Gym Wrapper
- 與 OpenAI 的 gym 的互動管道
- 架構圖:

- 訓練模式分成內建 / 自訂
- 內建的範例本身就有自帶內建好的訓練架構
- Python Trainer(不用自己寫,而是使用 `mlagents-learn` 執行)
- 用 yaml 格式的 config 來讓 `mlagents-learn` 訓練
- 推測的部分可在 Unity 有支援的平台跑(大部分都有)
- 參考後面 Unity Inference Engine 章節
- 自訂的模式在說明文件不會太多提到
- 可以參考下面 [How to use the Python API](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Python-API.md) 章節
- 甚至可以變成 gym 的環境
- 訓練的情境(Scenarios)
- Single-Agent
- 同時 Single-Agent:並行化(共用 Behavior),加速訓練
- 對抗式 Self-Play:金庸裡面周伯通的雙手互搏
- 合作的 Multi-Agent
- 競爭的 Multi-Agent
- Ecosystem:一個小世界,自駕模擬屬於這類
- 以下提到的訓練方式都是「內建訓練」,但如果要用自訂方法也可以參考
- 「普遍」環境訓練方法
- 獎勵分為外部(環境)與內部(與模型相關)
- 模型主要可以區分為兩大類:
- Deep Reinforcement Learning(深度強化學習)
- 用試誤(Trial and error)的方式學習
- Reinforcement Learning(強化學習)簡稱 RL
- 一般頻率的獎勵情形
- PPO(Proximal Policy Optimization,近端策略優化)
- 預設模型
- SAC(Soft Actor-Critic)
- 用最大熵來做強化學習
- 稀疏頻率的獎勵情形
- Curiosity for Sparse-reward Environments
- 使用正向跟反向模型
- RND for Sparse-reward Environments
- Random Network Distillation (RND,D 是激勵、蒸餾的意思,也就是選一些比較有代表性的來用)
- 使用隨機生成權重跟預測模型
- Imitation Learning(模仿學習)
- 用模仿有經驗的玩家(Demo)來學習
- 可以使用 Demonstration Recorder 進行錄製
- Observations、Actions、Rewards 的資訊
- 可以結合 RL 來輔助與加速 RL 的訓練
- GAIL(Generative Adversarial Imitation Learning,生成對抗模仿學習)
- 判別器會判斷動作是由 Agent 還是 Demo 產生
- 可以不需要獎勵
- BC(Behavioral Cloning,行為複製)
- 如果行為越接近 Demo 效果越好
- 可以作為預訓練的方法
- 實驗結果圖:

- 「特定」環境訓練方法
- 自我對戰(Self-Play)
- 對稱:像是足球
- 可以共用策略,戰勝過去的自己
- 非對稱:像是捉迷藏
- 建議使用 PPO
- 多人對戰(Multi-Agent)
- 合作完成目標
- 可以使用 MA-POCA(MultiAgent POsthumous Credit Assignment)
- 像是足球隊教練指揮足球隊員,也可以替換成員
- 課程學習(Curriculum Learning)
- 循序漸進,由簡單到複雜
- 人也是這樣學習的
- 在內建的 yaml config 可以定義不同的課程學習環境
- 藉著環境參數隨機化來訓練
- 可以增加適應性,適應不同環境變化
- 在內建的 yaml config 可以設定環境參數如何隨機
- 模型的類型
- 輸入為向量(像是位置、速度、射線等等)
- 使用一般的 NN
- 輸入為影像(支援多視角,多相機)
- 使用 CNN
- 輸入為可變長度向量(像是多個子彈)
- 使用 Attension Models(學長有講過)
- 需要有記憶性的特質(RNN)
- 使用 LSTM
- 其他 ML-Agents Toolkit 提供的功能
- 並行多個編譯好的執行檔,加速運算(加入 `--num-envs=<n>`)
- port 的部分從 `--base-port` 開始算起
- 記錄 Unity 執行時的統計數據
- 自定義 Side Channels
- Unity 與 Python 進行額外的溝通
- 自定義環境參數隨機化的 Sampler(取樣方式)
### [Example Environments(可參考)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Examples.md)
- 提供範例訓練場景的各種細節
Creating Learning Environments
---
==Unity 端的人必看!(尤其是前三篇)==
### [Making a New Learning Environment](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Create-New.md)
如何建造一個學習環境與 Agent
- 安裝 ML-Agents 套件
- com.unity.ml-agents
- 建立場景,包含 Agent Object
- 實作 Agent
- 要加入 Library,繼承自 Agent 而非 MonoBehaviour
- 幾個重要的 method(需要被覆寫)
- 初始化:`OnEpisodeBegin()`
- 觀察環境:`CollectObservations(VectorSensor sensor)`
- 回應:`OnActionReceived(ActionBuffers actionBuffers)`
- Episode 表示一個回合,結束的原因有成功、失敗、超時
- 初始化(開始一個新的回合)
- 寫在 `OnEpisodeBegin()` 裡面
- 觀察環境
- 寫在 `CollectObservations(VectorSensor sensor)` 裡面
- `sensor.AddObservation(資訊來源)`
- 可以放不同類型的資料
- 形式待研究
- 回應(處理 Action、獎勵與結束)
- 寫在 `OnActionReceived(ActionBuffers actionBuffers)` 裡面
- `actionBuffers` 裡面有 `ContinuousActions` 和 `DiscreteActions` 兩個陣列
- 收到資訊之後要決定 Action 對應的動作
- 獎勵
- 在適當位置使用 `SetReward(分數)` 給出獎勵
- 結束
- 在適當位置使用 `EndEpisode()` 結束該回合
- 最終的 Unity 編輯器設定
- 
- 在 Agent Object 底下加入兩個 Script 元件:
- `Decision Requester` 元件
- `Agent.RequestDecision()` 被呼叫的週期
- 需要做決定時要呼叫 `Agent.RequestDecision()`
- 一個 step 為一個單位
- DecisionFrequency 是決定訓練速度、成功率的關鍵
- 越少做出決定訓練越快,成功率越高(在簡易場景)
- 也可以選擇手動呼叫,就不需要 Decision Requester 元件了
- `Behavior Parameters` 元件
- `Behavior Name`:設定名字
- `Vector Observation`:向量性質觀察的參數設定
- `Space Size`:參數的量
- `Stacked Vectors`:目前先設 1
- `Actions`:Action 的參數設定
- `Continuous Actions`:連續 Action 的量
- `Discrete Branches`:離散 Action 的量
- 測試場景
- 可以實作 `Heuristic(in ActionBuffers actionsOut)` 來手動控制
- `actionsOut`對應 `OnActionReceived()` 的 `actionBuffers`
- 把上下左右(`Input.GetAxis("Horizontal|Vertical")`,-1 到 1 的值)、其他鍵盤滑鼠等控制訊號對應到 actionsOut 連續 / 離散的 Action
- `Behavior Parameters` 元件中的 `Behavior Type` 要改成 `Heuristic Only`
- 點擊 Play 鍵就能玩了,看看 Agent 設定有沒有問題
- 訓練
- 可以用官房提供的 `mlagents-learn` 搭配 yaml 設定檔訓練
- 語法:`mlagents-learn yaml位置 --run-id=取一個名字`
- 經驗建議(別的場景不一定)
- 對於小型的資料,batch size 和 buffer size 可以設小一點
- DecisionFrequency 是決定訓練速度、成功率的關鍵
- 在簡易場景,做決定的頻率越小,訓練越快,成功率越高
- 可用 TensorBoard 觀察訓練過程
- cumulative_reward 和 value_estimate 顯示學得多好
- 加速訓練(平行化)
- 同一個 Scene 放好幾份訓練區域
- 先把要訓練的區域做成 Prefab,就可以拖拉好幾份
- Behavior Name 取一樣的名字
- 開多個 Unity instance
- 在 `mlagents-learn` 指令最後加上 `--num-envs=數量`
### [Designing a Learning Environment](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Design.md)
如何設計一個學習環境,還有一些如何設計場景、模擬、簡單設計 Agent(Designing Agents 會提更多)的概覽。
如果要完全了解 ML-Agents Toolkit,可以直接去讀 API(在下面我有做一些 Source Code 的閱讀筆記),也可以透過範例來了解。
- 訓練、模擬的過程
- Academy 會驅動這些步驟
- 生命週期
1. 執行 Academy 的 `OnEnvironmentReset` hook
2. 執行每個 Agent 的 `OnEpisodeBegin()`
3. 收集觀察資訊,藉由 Agent 的 `CollectObservations(VectorSensor sensor)`
4. 用每個 Agent 對應到的 Policy(外部、啟發式、訓練結果) 決定下一步 Action
5. 執行 `OnActionReceived()`,傳入上面的 Action
6. `OnEpisodeBegin()` 會再次被執行,進入新回合,如果到達 `Max Step` 或者 `EndEpisode()` 被呼叫
- 以上的一些 method 要自己覆寫
- 安排 Unity 場景
- Academy(學院)
- Academy 會安排 Agent 們的運作,是一個 singleton(單獨個體),一次只會有一個(`Academy.Instance`)
- Academy 的 Reset
- 請在任意的 Script 中的函式掛到 `Academy.Instance.OnEnvironmentReset` 這個 hook 上面
- `Academy.Instance.OnEnvironmentReset += 函式名稱;
- 時機:在 Python `UnityEnvironment.reset()` 時會執行
- 例如:在新回合時把 Agent 移到新位置、目標物擺到隨機位置
- 如果想讓訓練結果適應更普遍的環境,可以在這時候改變一些環境的因子(像是迷宮的路線)
- 多個區域
- 可以同時擺好幾個區域用平行化加速訓練,只要把 Agent 的 `Behavior Name` 設成一樣的就好
- 在設計場景的時候,也可以設計成方便這種多個區域的形式
- 可以參考範例,或上一篇(講到用 Prefab 快速建立區域)
- 環境
- 製作訓練環境時要注意
- 訓練場景要在 Unity 程式開啟的時候自動打開
- 在每一回合結束後,Academy 要重設場景(可用 `OnEnvironmentReset` hook)
- 每一回合一定要可以結束,不論透過到達 `Max Step` 或是呼叫 `EndEpisode()`
- 環境參數
- 使用時機:Curriculum learning(課程學習)和 environment parameter randomization(環境參數隨機調整)
- Python 端 API 和內建訓練設定的 yaml 檔都可以透過 EnvironmentParameters 專屬的 Side Channel 來與之互動(提供了常數或是幾種亂數生成的功能),使用方法自行查詢文件
- 建議在 `OnEpisodeBegin()`(不一定,適當位置)透過 `Academy.Instance.EnvironmentParameters.GetWithDefault(key, float的預設值)` 來取用
- Agent
- Agent 要附在 GameObject 上面
- Behavior Parameters 要設定好
- 要覆寫的 methods:
- `OnEpisodeBegin()`
- 初始化或重設的時候會呼叫
- `CollectObservations(VectorSensor sensor)`
- 收集環境資訊
- `OnActionReceived(ActionBuffers actionBuffers)`
- 執行 Policy 決定好的 Action 並設定獎勵
- Behavior Parameters 與後兩個 methods 有關
- 必須要決定如何結束回合
- 在 `OnActionReceived()` 中呼叫 `EndEpisode()`
- 或設定最大步數 `Max Steps`
- 參考下一篇 Designing Agents 有更多資訊
- 錄製統計資訊
- `StatsRecorder.Add(key, value [, 性質])`
- 可以呈現在 TensorBoard 或透過 Side Channel 傳送到 Python 端
#### [Designing Agents(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Design-Agents.md)
Agent 相關的運作、觀察資料的種類、Action 的種類、如何給獎勵、多個 Agent 的狀況(Teams)、**錄製 Demonstrations**
裡面都有該如何設定的建議(Best Practices),對學機器學習很有幫助
如果要更知道更詳細運作原理請看下方的 Source Code 閱讀筆記
- Agent
-
### [Using an Executable Environment](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Executable.md)
- 可以先 Build 執行檔來進行訓練(當然,在 Unity Editor 也可以)
- 可以搭配 Unity Environment Registry(下面有解釋)使用
- 可以用 Server Mode(前提是不需要渲染畫面)
- 這篇文章有教如何 Build 一個執行檔
- 不過 Run in background 我覺得不需要
- 使用 Python API 時在 UnityEnvironment 的 file_name 傳入執行檔路徑即可
```=Python
from mlagents_envs.environment import UnityEnvironment
env = UnityEnvironment(file_name=<env_name>)
```
- 如果用內建的 `mlagents-learn` 要這樣執行
`mlagents-learn <trainer-config-file> --env=<env_name> --run-id=<run-identifier>`
- `<trainer-config-file>`:yaml 的 config 檔
- `<env_name>`:執行檔路徑(不用副檔名)
- `<run-identifier>`:區分不同次訓練用的
- 訓練完的模型會放在 `results/<run-identifier>/<behavior_name>.onnx`
- 可以移到適合位置(建議:專案下的 TFModels 資料夾)
- 在 Inspector 視窗把模型拉到 Agent 的 Model
### [ML-Agents Package Settings](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Package-Settings.md)
- 設定位於 Edit > Project Settings... > ML-Agents
- 可以針對整體做設定,也可以針對不同情境做設定
- 像是給訓練使用的設定、給推測使用的設定
Training & Inference
---
這部分 PAIA 框架不太需要,但可以試試自行轉換的 ONNX 能否使用?
### [Training ML-Agents(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Training-ML-Agents.md)
#### [Training Configuration File(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Training-Configuration-File.md)
#### [Using TensorBoard to Observe Training(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Using-Tensorboard.md)
#### [Profiling Trainers(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Profiling-Python.md)
### [Unity Inference Engine](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Unity-Inference-Engine.md)
- 用 Barracuda 使 Unity 可以用來做機器學習的 prediction
- [Unity Barracuda Github](https://github.com/Unity-Technologies/barracuda-release)
- [Unity Barracuda Mannual](https://docs.unity3d.com/Packages/com.unity.barracuda@2.1/manual/index.html)
- ML-Agents 只有對使用內建的訓練結果來 Inference 做說明
- 使用 ONNX(Open Neural Network Exchange)開放神經網路交換格式
- 訓練好的策略模型(Policy)是 `.onnx` 格式
- 如果要使用自己提供訓練好的模型
- 要轉成 ONNX 格式
- 要遵從一些慣例,參考:
- [TensorNames.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Inference/TensorNames.cs)
- [BarracudaModelParamLoader.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs)
- 如果不想管這些慣例,建議自行用 Barracuda 來跑
- 如果要把內建的訓練結果給外部使用
- 自行參考 ONNX 格式、ML-Agents 的慣例
Extending ML-Agents
---
### [Creating Custom Side Channels(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Custom-SideChannels.md)
### [Creating Custom Samplers for Environment Parameter Randomization(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Training-ML-Agents.md#defining-a-new-sampler-type)
Python Tutorial with Google Colab
---
使用 Python API 可以參考這些使用方法
### [Using a UnityEnvironment(未讀完)](https://colab.research.google.com/github/Unity-Technologies/ml-agents/blob/release_18_docs/colab/Colab_UnityEnvironment_1_Run.ipynb)
訓練時期如何使用 API,很多基本的操作都有示範了!
- Get the Behavior Specs from the Environment
```=Python
# We will only consider the first Behavior
behavior_name = list(env.behavior_specs)[0]
print(f"Name of the behavior : {behavior_name}")
spec = env.behavior_specs[behavior_name]
```
### [Q-Learning with a UnityEnvironment(未讀完)](https://colab.research.google.com/github/Unity-Technologies/ml-agents/blob/release_18_docs/colab/Colab_UnityEnvironment_2_Train.ipynb)
訓練時期如何使用 API(以 Q-Learning 為範例)
- 有儲存過去的觀察資料,這部分是要自己實作的
- Q-Learning 好像需要一個 memory 儲存過去的東西
### [Using Side Channels on a UnityEnvironment(未讀完)](https://colab.research.google.com/github/Unity-Technologies/ml-agents/blob/release_18_docs/colab/Colab_UnityEnvironment_3_SideChannel.ipynb)
Help
---
### [Migrating from earlier versions of ML-Agents(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Migrating.md)
- 以前的 Brain 現在變成 Behavior
### [Frequently Asked Questions](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/FAQ.md)
- 主要是環境設定的常見問題
- 要注意執行檔的權限
- 如果連線超時要怎麼解決?
- port 被佔用要修改
### [ML-Agents Glossary](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Glossary.md)
- 各種名詞解釋:Academy、Action、Agent、Decision、Editor、Environment、Experience、External Coordinator、FixedUpdate、Frame、Observation、Policy、Reward、State、Step、Trainer、Update
### [Limitations](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Limitations.md)
- 每個 package 都有一些使用限制要注意:
- com.unity.mlagents
- 訓練只支援三大作業系統:Windows、Mac、Linux
- 推測的話 CPU 都可以用,GPU 在行動裝置要看情況
- Headless Mode(Server Mode)無法支援「visual observations」
- 這樣就沒有圖形類的訓練資料
- 目前 Unity Inference Engine 只支援用官方 trainers 訓練出的模型
- 如果嫌照官方慣例太麻煩,可以自己用 Barracuda 跑
- mlagents
- 如果有使用到 Multi-Agent 或是 Self-Play 再注意一下
- mlagents_envs
- 用 Socket 來溝通,要注意防火牆設定,確保安全
- 如果要執行「多個」 UnityEnvironment 要指定不同 port
- 這個通道是不加密的,要注意不要外露
- Linux 如果剛關閉程式,port 是不會立即釋放的
- gym_unity
- 只適用在 Single Agent
- 其他限制自行去看
API Docs
---
### [API Reference](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/API-Reference.md)
- 請參考 [Scripting API](https://docs.unity3d.com/Packages/com.unity.ml-agents@2.1/api/index.html),Reference 都在裡面
### [Python API Documentation(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Python-API-Documentation.md)
- UnityEnvironment
- 用 Socket 來溝通(可不指定 port),要注意防火牆設定,確保安全
- 如果要執行多個 UnityEnvironment 要指定不同 port
- 這個通道是不加密的,要注意不要外露
- Linux 如果剛關閉程式,port 是不會立即釋放的
- 繼承自 `BaseEnv`(可參考底下 Source Code 閱讀筆記)
- UnityEnvRegistry
- SideChannel
### [How to use the Python API(未讀完、待思考)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Python-API.md)
- ==Python 端的人必看!==
- 可以不用下內建的 `mlagents-learn` 的 command 指令
- 學弟的直升機就是用這種方式
- ==待思考:這樣使用 ML-Agents 的優勢在哪裡?相比自己寫 Socket?==
- 我們善用 Agent 和 Recording 的部分,不用 Trainer 的部分
- 自訂模式要先開 Python 才能夠進行推測
- ML-Agents 是用 gRPC 來溝通的,資料結構定義完善
- 每一個 step 要怎麼做、資料傳送的格式、生命週期
### [How to use the Unity Environment Registry](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Unity-Environment-Registry.md)
- 不用安裝龐大的 Unity Editor 就可以執行 ML-Agents 相關訓練操作的方法
- 等於是把程式打包成不同的平台這樣
- 用 yaml 來定義不同學習環境
### [Wrapping Learning Environment as a Gym (+Baselines/Dopamine Integration)(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/gym-unity/README.md)
Deprecated Docs
---
因為已經不被使用,可能就不會再更新了,保留的原因是或許對你有幫助。
### [Windows Anaconda Installation(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Installation-Anaconda-Windows.md)
### [Using Docker(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Using-Docker.md)
### [Training on the Cloud with Amazon Web Services(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Training-on-Amazon-Web-Service.md)
### [Training on the Cloud with Microsoft Azure(未讀完)](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Training-on-Microsoft-Azure.md)
### [Using the Video Recorder(未讀完)](https://github.com/Unity-Technologies/video-recorder)
其他
---
官方文件沒有,是我自己整理的
==Python、Unity 端的人都要看!==
### Demonstration Recorder / Loader
錄製 demo 以及讀取 demo(一個 demo 對應一個 Agent,應該吧)
- Demonstration Recorder(Unity 端)
- [Imitation Learning](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/ML-Agents-Overview.md#imitation-learning)
- [Designing Agents - Recording Demonstrations](https://github.com/Unity-Technologies/ml-agents/blob/main/docs/Learning-Environment-Design-Agents.md#recording-demonstrations)
- [Imitation Learning and demo - old version](https://github.com/gzrjzcx/ML-agents/blob/master/docs/Training-Imitation-Learning.md)
- [Unity ML-Agents - Demonstration Recorder for Imitation Learning](https://www.youtube.com/watch?v=Dhr4tHY3joE)
- [How to Train a Machine Learning Agent via Demonstration](https://gamedevacademy.org/unity-machine-learning-training-tutorial/)
- Demonstration Loader(Python 端),官方文件沒寫
- mlagents.trainers.demo_loader
- Reference:[mlagents/trainers/demo_loader.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents/mlagents/trainers/demo_loader.py)
- 函式 demo_to_buffer(file_path, sequence_length)
- 說明:讀出 demo 檔然後存到訓練 buffer
- 參數 `file_path`:`.demo` 檔路徑
- 參數 `sequence_length`:填充 buffer 的 trajectories 長度
- 建議設為 `None` 或是 1
- [What is a "trajectory" in reinforcement learning?](https://ai.stackexchange.com/questions/7359/what-is-a-trajectory-in-reinforcement-learning/8955)
- 參考 [`resequence_and_append()`](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents/mlagents/trainers/demo_loader.py#L94)
- `batch_size=None`
- `training_length=sequence_length`
- 參考 [`get_batch()`](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents/mlagents/trainers/buffer.py#L143)
- `batch_size=batch_size=None`
- `training_length` 預設值為 1
- `training_length=None` 會自動變 1
- `sequential`:`If true and training_length is not None: the elements will not repeat in the sequence. [a,b,c,d,e] with training_length = 2 and sequential=True gives [[0,a],[b,c],[d,e]]. If sequential=False gives [[a,b],[b,c],[c,d],[d,e]]`
- 我們的狀況是預設值為 True 的
- 可省參數 expected_behavior_spec:預期 Behavior 的架構
- 回傳 Tuple[BehaviorSpec, AgentBuffer]
- BehaviorSpec:Behavior 的架構
- AgentBuffer:讀出來的資料
- 錄製的資料是以 Protocol Buffers 的文字形式儲存的
- `ParseFromString(data[pos : pos + next_pos])`
- [Interpreting .demo files. #2440](https://github.com/Unity-Technologies/ml-agents/issues/2440)
- [Faster loading of visual demonstrations? #2979](https://github.com/Unity-Technologies/ml-agents/issues/2979)
### Python 運作
#### Buffer 相關
Reference:[mlagents/trainers/buffer.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents/mlagents/trainers/buffer.py)
把 demo 的資料讀出來後會存到 AgentBuffer
- mlagents.trainers.AgentBuffer
- AgentBufferKey 說明(剩下直接參考 Source Code)
- `BufferKey`:取用 meta 資訊
- 常用 BufferKey:
- ACTION_MASK = "action_mask"
- ==CONTINUOUS_ACTION = "continuous_action"==
- ==DISCRETE_ACTION = "discrete_action"==
- ==DONE = "done"==
- ==ENVIRONMENT_REWARDS = "environment_rewards"==
- 這是取得 Reward 的部分!
- MASKS = "masks"
- MEMORY = "memory"
- GROUP_DONES = "group_dones"
- GROUPMATE_REWARDS = "groupmate_reward"
- GROUP_REWARD = "group_reward"
- GROUP_CONTINUOUS_ACTION = "group_continuous_action"
- GROUP_DISCRETE_ACTION = "group_discrete_aaction"
- `(ObservationKeyPrefix, int)`:取用觀察數據
- 常用 ObservationKeyPrefix:
- ==OBSERVATION = "obs"==
- GROUP_OBSERVATION = "group_obs"
- `(RewardSignalKeyPrefix, name)`:取用獎勵種類
- 常用 RewardSignalKeyPrefix:
- REWARDS = "rewards"
- VALUE_ESTIMATES = "value_estimates"
- name:`extrinsic`、`gail`、`curiosity`、`rnd`
- AgentBufferField(繼承自 list)
- 針對每個 Field 所儲存的錄製資料
- `[index]`:取用數據(一般是 np.ndarray,如果是群組、Actions、獎勵等才是 np.ndarray 的 List)
- index 第幾筆錄製資料
- AgentBuffer
- demo_to_buffer 產生的 buffer 屬於 AgentBuffer
- `[AgentBufferKey]`:取用 AgentBufferField
- 先類別再索引的概念
- ==batch、shuffle 之後再研究==
#### Env 相關
先參考上面 How to use the Python API、Python API Documentation,其餘的看 Source Code
Reference:[ml-agents-envs/mlagents_envs/base_env.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents-envs/mlagents_envs/base_env.py)
- Behavior 的資料之數值和 meta 資訊是分開的
- 數值放在 `DecisionStep`、`TerminalStep` 中
- 觀察類的數值用 `List[np.ndarray]` 型態存在 `.obs` 裡面
- 對應到的是 `BehaviorSpec.observation_specs`,也是 List 類型
- 獎勵存在 `.reward`
- 還有一些其他資訊(Agent ID、群組等等)
- 給出的 Action 要照著 `ActionSpec` 放在 `ActionTuple` 中
- meta 資訊用 `BehaviorSpec`、`ActionSpec` 表示
- DecisionStep
- ==待補充==
- DecisionSteps
- ==待補充==
- TerminalStep
- ==待補充==
- TerminalSteps
- ==待補充==
- ==BehaviorSpec:這是 Behavior meta 資訊的部分==
- `.observation_specs`:`List[ObservationSpec]`
- 我「猜」會依照 Vector、Camera、Raycast、可變長度區分
- `.action_spec`:`ActionSpec`
- ObservationSpec:觀察資訊的部分
- `.shape`:`Tuple[int, ...]`
- 每一個維度資料多長
- `.dimension_property`:`Tuple[DimensionProperty, ...]`
- 每一個維度資料的類型
- `.observation_type`:`ObservationType`
- 對達成目標有無重要影響
- `(.name)`:`str`
- 可選欄位,為 ISensor 的名字(`ISensor.GetName()`)
- ==DimensionProperty:維度的資料類型==
- UNSPECIFIED = 0
- 未知
- NONE = 1
- 一般的有序資料,可以直接丟到全連接層處理
- TRANSLATIONAL_EQUIVARIANCE = 2
- 平移(區域)不變性,適合用卷積神經網路 CNN 處理
- VARIABLE_SIZE = 4
- 資料長度可變,並且沒有排序,應該適合用 Attension 處理
- ObservationType:觀察資訊的類型(對達成目標有無重要影響)
- DEFAULT = 0
- 一般
- GOAL_SIGNAL = 1
- 這是對達成目標有重要影響的資訊
- ==ActionTuple:存放 Action 數值的 Object==
- 需照著 ActionSpec 來存放
- 維度分別是 (n_agents, continuous_size) 和 (n_agents, discrete_size)
- 均為二維陣列!
- branch 的意思不是多加一個維度,而是用來設定「每一組」離散 Action 的可能數目
- 可以給 Behavior 的所有 Agents 用,也可以給指定 Agent(n_agents = 1)
- 型態部分:連續是 np.float32,離散是 np.int32
- `.add_continuous(self, continuous: np.ndarray)`
- `.add_discrete(self, discrete: np.ndarray)`
- `.continuous(self) -> np.ndarray`
- `.discrete(self) -> np.ndarray`
- ActionSpec:Action meta 資訊的部分
- `.continuous_size`:`int`
- 連續 Action 的數量(沒有分組)
- `.discrete_branches`:`Tuple[int, ...]`
- 離散 Action 的上限(每組有幾個可能值)
- `.empty_action(self, n_agents: int) -> ActionTuple`
- 照著 ActionSpec 產生一個空的 ActionTuple
- `.random_action(self, n_agents: int) -> ActionTuple`
- 照著 ActionSpec 產生一個隨機的 ActionTuple
- 連續的部分是從 -1.0 到 1.0 取亂數
- 離散的部分是從 0 到該組的個數取亂數
- BaseEnv
- ==待補充==
Reference:[ml-agents-envs/mlagents_envs/environment.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents-envs/mlagents_envs/environment.py)
- UnityEnvironment
- ==待補充==
### 底層溝通管道
Python 與 Unity 之間的溝通管道是用 [gRPC](https://grpc.io/)
Reference:[rpc_communicator.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents-envs/mlagents_envs/rpc_communicator.py)
- 預設的 port 是從 5005 往上加
- gRPC 預設就是用 Protocol buffers 當資料結構了
Python 與 Unity 之間的溝通的資料結構是用 Protocol buffers 來實作的
Reference:[Unity ML-Agents Protobuf Definitions](https://github.com/Unity-Technologies/ml-agents/tree/main/protobuf-definitions)
可以參考:
- [Protocol Buffers 官網](https://developers.google.com/protocol-buffers)
- [比起 JSON 更方便、更快速、更簡短的 Protobuf 格式](https://yami.io/protobuf/)
其中 observation.proto 裡面有一些觀察資料的傳輸過程:
- [observation.proto](https://github.com/Unity-Technologies/ml-agents/blob/main/protobuf-definitions/proto/mlagents_envs/communicator_objects/observation.proto)
- 例如可以看到 PNG 圖檔如何被傳輸等等
- [observation_pb2.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents-envs/mlagents_envs/communicator_objects/observation_pb2.py)
- 這是 Protocol Buffers 自動生成的 Python 檔案
==從 Protocol Buffers 轉換到 Python 端的資料型態的工具==
Reference:[rpc_utils.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents-envs/mlagents_envs/rpc_utils.py)
- 裡面有實作如何把收到的資料轉換成 Python Low Level API 可用的資料
- 例如圖片如何被轉換、Spec 如何被轉換等等
- Low Level API、Demo Loader 都有用到 `steps_from_proto`、`behavior_spec_from_proto` 來轉換
- Steps、BehaviorSpec 兩大重點
- Low Level API:[environment.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents-envs/mlagents_envs/environment.py)
- Demo Loader:[demo_loader.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents/mlagents/trainers/demo_loader.py)
### Unity 運作
在 Source Code 當中可以看到大量的 `event Action` 配合 `Invoke()` 來執行,可以參考 [[C#]使用委派(Delegate)與事件(Event)](https://hackmd.io/@BKLiang/csharp_delegate_event) 這篇文章,要注意的是 `Invoke()` 本身是同步而不是非同步執行的,也就是會等待,執行完一個才會再執行下一個的意思。
註:Source Code 中如果出現
```=C#
using (TimerStack.Instance.Scoped("..."))
{
// 程式
}
```
是用來計算運行這段程式所需的時間(參考[【C#】小知識 #5 : 為什麼要使用using](https://ithelp.ithome.com.tw/articles/10199186))
應該是給統計數據用的
#### Agent
參考:[Class Agent](https://docs.unity3d.com/Packages/com.unity.ml-agents@2.1/api/Unity.MLAgents.Agent.html)
參考:[Agent.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Agent.cs)
執行 `RequestAction()` 表示想要做一個動作(但不收集新數據),這會設置 `m_RequestAction = true`,跟 `AgentStep()` 有關
想單獨觸發決策建議用 `RequestDecision()`,跟 `SendInfo()` 有關,會處理新收集到的資訊,這會設置 `m_RequestDecision = true`,也會執行 `RequestAction()`,所以 `RequestAction()` 就不用再執行一次了(因為沒差)
想要重設 Agent 可以執行 `EndEpisode()`,這是除了到達 MaxStep 之外的另外一個重新開始的方式,`EndEpisode()` 中會執行到 `_AgentReset()`,並且也會通知說該回合結束了
`SendInfo()` 會執行 `SendInfoToBrain()` 收集新資料、更新舊資訊,會跟 Policy 溝通,取得 `IPolicy.RequestDecision(m_Info, sensors)` 後的結果,也會把資訊錄製到 Demo Recorder,處理完之後 `m_RequestDecision` 會設回 `false`
`DecideAction()` 會跟 Policy 溝通,取得 `IPolicy.DecideAction()` 後的結果並用 `m_ActuatorManager.UpdateActions(actions)` 更新 `m_ActuatorManager` 裡面 Actuator 們的 Action
`AgentStep()` 會執行 m_ActuatorManager 中的所有 Action,或是終止動作,處理完之後 `m_RequestAction` 會設回 `false`
`_AgentReset()` 會清空先前資料,Step 設回 0,並執行 `OnEpisodeBegin()`,開始新回合
上面的東西外加一些其他的會對到這些 hooks:
```
Academy.Instance.AgentIncrementStep += AgentIncrementStep
Academy.Instance.AgentSendState += SendInfo
Academy.Instance.DecideAction += DecideAction
Academy.Instance.AgentAct += AgentStep
Academy.Instance.AgentForceReset += _AgentReset
```
都是放在 `LazyInitialize()`,在 Academy 中被 Invoke 的時候就會被執行到
註:`OnEnable()` 會執行 `LazyInitialize()`,`LazyInitialize()` 會執行 `Initialize()`(如果有的話)
`m_Info` 屬於 `struct AgentInfo`,儲存跟 Agent 有關的資料,包含 observations, actions 還有目前狀態
`m_PolicyFactory` 屬於 BehaviorParameters,會抓取 Agent GameObject 中的 BehaviorParameters
`m_Brain` 屬於 IPolicy,就是決策提供者,根據 `m_PolicyFactory` 的資訊選擇決策方式(Barracuda、Heuristic、Remote)
`SetModel(behaviorName, NNModel, InferenceDevice)` 可以變更 Behavior Name、替換 NN 的 Model
單純要改 Behavior Name(不要從 BehaviorParameters 改!):
`SetModel(behaviorName, null)`
會需要 Override 的幾個 methods 的執行時間點:
`OnEpisodeBegin()` 會在 `LazyInitialize()` 的時候被執行
`CollectObservations(VectorSensor sensor)` 會在 `SendInfoToBrain()` 中跟 Policy 溝通之前或 `AgentStep()` 遇到終止狀況的時候被執行(這算是比較舊的方法了,現在建議用 `ObservableAttribute`)
`OnActionReceived(ActionBuffers actionBuffers)` 會在 `AgentStep()` 裡面的 `m_ActuatorManager.ExecuteActions()` 被執行
#### Sensor
負責收集資訊
參考:[ISensor.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/ISensor.cs)
`GetName()` 可以取得名字,ML Agents 提供的 Sensor 都會自己取看得懂的名字(如果沒有提供)
在 Agent.cs 中,`InitializeSensors()` 時會執行到 `SensorUtils.SortSensors(sensors)`,所以我們拿到資訊的時候是照這些 Sensor 的名字去排序
參考:[ObservableAttribute.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/Reflection/ObservableAttribute.cs)
這是加入 Vector 數值的建議方法(取代 `CollectObservations(sensor)`)
用法:
`[Observable(name: null, numStackedObservations: 1)]`
如果沒有提供 name,命名的慣例是(Line 197):
`ObservableAttribute:型態名稱.成員名稱`
參考:[VectorSensor.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/VectorSensor.cs)
如果沒有提供 name,命名的慣例是(Line 28~31):
`VectorSensor_size + 參數數量 + _GOAL_SIGNAL(如果是的話)`
VectorSensorComponent 可以設定 ObservationType 屬性
參考:[StackingSensor.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/StackingSensor.cs)
如果沒有提供 name,命名的慣例是(Line 58):
`StackingSensor_size + Stack數量 + Sensor原本名字`
參考:[SensorComponent.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/SensorComponent.cs)
這是 Component 形式的 Sensor 集合,裡面可以塞很多個 Sensor
要實作 `ISensor[] CreateSensors()`
參考:[CameraSensorComponent.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/CameraSensorComponent.cs)
裡面對應到一個 CameraSensor
如果沒有提供 SensorName,命名的慣例是(Line 27~38):
`CameraSensor`
注意:如果執行後來再去改名,並不會影響原本排序
可以設定 ObservationType 屬性
參考:[RenderTextureSensorComponent.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/RenderTextureSensorComponent.cs)
裡面對應到一個 RenderTextureSensor
如果沒有提供 SensorName,命名的慣例是(Line 27~38):
`RenderTextureSensor`
注意:如果執行後來再去改名,並不會影響原本排序
參考:[RayPerceptionSensor.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/RayPerceptionSensor.cs)
RayPerceptionSensorComponent2D、RayPerceptionSensorComponent3D 裡面對應到一個 RayPerceptionSensor
如果 Component 沒有提供 SensorName,命名的慣例是([RayPerceptionSensorComponentBase.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/RayPerceptionSensorComponentBase.cs#L14)):
`RayPerceptionSensor`
注意:如果執行後來再去改名,並不會影響原本排序
資料的型態是 Vector,長度為:
`(Observation Stacks) * (1 + 2 * Rays Per Direction) * (Num Detectable Tags + 2)`
關於資料擺放方式可以參考 `ToFloatArray()`(Line 218、322)
一個 Ray 所存放的資訊(`ToFloatArray()` 上面的註解要看!):
先是 One-hot 的 HitTag,再來是 HasHit,再來是 HitFraction
所以才要 `Num Detectable Tags + 2`
`HitFraction` 是把觀察到的長度除以最大可觀察長度的結果
關於各個角度的擺放順序可以參考 [RayPerceptionSensorComponentBase.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/RayPerceptionSensorComponentBase.cs#L209) 的 `GetRayAngles()`:
從中間(90 度)開始,右左右左越來越大來擺放,例如:
`{ 90, 90 - delta, 90 + delta, 90 - 2*delta, 90 + 2*delta }`
回到 RayPerceptionSensor,
從 `RayExtents()`、`PolarToCartesian3D()` 可知,
經查證極坐標平面是 xz 平面,右方是 x,前方是 z,
所以才要 `1 + 2 * Rays Per Direction`
參考:[GridSensorComponent.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/GridSensorComponent.cs)
GridSensorComponent 裡面對應到一個 GridSensor
如果沒有提供 SensorName,命名的慣例是(Line 19~28):
`GridSensor`
注意:如果執行後來再去改名,並不會影響原本排序
資料的型態是 Vector,長度為:
`GridSize.x * GridSize.z * Num Detectable Tags`
關於資料擺放方式可以參考 [GridSensorBase.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/GridSensorBase.cs#L316)(`Write()`)
參考:[BufferSensorComponent.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Sensors/BufferSensorComponent.cs)
裡面對應到一個 BufferSensor
如果沒有提供 SensorName,命名的慣例是(Line 27~38):
`BufferSensor`
注意:如果執行後來再去改名,並不會影響原本排序
用 `AppendObservation(float[] obs)` 加入觀察數值陣列
(長度需要與給定的一樣)
#### Actuator
這是負責執行動作的角色
參考:[IActionReceiver.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Actuators/IActionReceiver.cs)
`struct ActionBuffers` 是定義在這個檔案裡面
`IActionReceiver` 中有 `OnActionReceived(ActionBuffers actionBuffers)`、`WriteDiscreteActionMask(IDiscreteActionMask actionMask)`,是要被覆寫的 method
參考:[IActuator.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Actuators/IActuator.cs)
`IActuator` 有繼承 `IActionReceiver` 等,再加上一些 `ActionSpec`、`Name` 之類的東西
參考:[ActuatorManager.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Actuators/ActuatorManager.cs)
`ActuatorManager` 其實就是 `IActuator` 的 List,提供一些像是 `UpdateActions(ActionBuffers actions)`、`ExecuteActions()` 等等的操作
#### DecisionRequester
參考:[DecisionRequester.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/DecisionRequester.cs)
參考:[Class DecisionRequester](https://docs.unity3d.com/Packages/com.unity.ml-agents@2.1/api/Unity.MLAgents.DecisionRequester.html)
如果是固定頻率要執行,可以掛上 DecisionRequester,`MakeRequests(int academyStepCount)` 會定期執行 `Agent.RequestDecision()` 或是可以設定 `TakeActionsBetweenDecisions`(預設為 `true`)在一般的時候要不要執行 `Agent.RequestAction()`
MakeRequests 會對到這個 hook:
```
Academy.Instance.AgentPreStep += MakeRequests
```
在 Academy 中被 Invoke 的時候就會被執行到
#### BehaviorParameters
參考:[BehaviorParameters.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Policies/BehaviorParameters.cs)
`GeneratePolicy()` 有寫到決策方式的選擇順序為何
#### Academy
參考:[Academy.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Academy.cs)
以下列出的 Hooks:
`AgentPreStep`(DecisionRequester 的 MakeRequests)、
`AgentIncrementStep`(計算次數)、
`AgentSendState`(SendInfo)、
`DecideAction`(DecideAction)、
`AgentAct`(AgentStep)
在 `EnvironmentStep()` 會依序被 Invoke(執行)到
`EnvironmentStep()` 在 `AcademyFixedUpdateStepper.FixedUpdate()` 被呼叫
所以可以知道==如果有掛 DecisionRequester,一個 step 單位為一個 FixedUpdate 的週期==,然而如果在決策時或其他地方有拖到時間,Frame 的週期會變長,一步的時間也會變長。
再來解釋如何 Reset:
`EnvironmentReset()` 是進到一個新環境,Agent 本身並不會 Reset,並且 `OnEnvironmentReset` 裡面的 hook 會被 Invoke(可以在 Unity 隨便一個 Script 把 function 加到 `Academy.Instance.OnEnvironmentReset` 這個 hook)
另外 `ForcedFullReset()` 被執行時會執行 `EnvironmentReset()`,也會 Invoke `AgentForceReset`,所以 Agent 們也會 Reset
在一開始的時候、`OnResetCommand()` 的時候會執行到 `ForcedFullReset()`,而 `OnResetCommand()` 又是由外部(Python 的溝通)來控制的
Academy 會在 Agent 被生成(`Agent.LazyInitialize()`)的時候自動生成(因為有用到 `Academy.Instance`)
`EnvironmentParameters` 可以獲得有關環境參數的資訊,透過 `Academy.Instance.EnvironmentParameters.GetWithDefault(key, float預設值)` 來取用
#### EnvironmentParameters
參考:[EnvironmentParameters.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/EnvironmentParameters.cs)
基本預設:每個參數都是 float 型態
Python 端 API 和內建訓練設定的 yaml 檔都可以透過 EnvironmentParameters 專屬的 Side Channel 來與之互動(提供了常數或是幾種亂數生成的功能),使用方法自行查詢文件
`float GetWithDefault(string key, float defaultValue)` 取得某個 key 的值(須提供預設值,萬一這個參數沒有被設定)
#### StatsRecorder
參考:[StatsRecorder.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/StatsRecorder.cs)
會建立 Side Channel,並且可以透過 TensorBoard 呈現
用 `/` 分隔可以建立巢狀的數據名稱
`Add(string key, float value, StatAggregationMethod aggregationMethod = StatAggregationMethod.Average)`
可以加入一個要觀察的值
### ONNX 格式(Open Neural Network Exchange)
官網:https://onnx.ai/
GitHub:https://github.com/onnx
ONNX Runtime:https://onnxruntime.ai/
ONNX 教學:https://github.com/onnx/tutorials
#### 教學文
- [Three Levels of ML Software](https://ml-ops.org/content/three-levels-of-ml-software)
- 跟 ONNX 類似的資料交換格式有哪些
- [Overview of ONNX and operators](https://medium.com/axinc-ai/overview-of-onnx-and-operators-9913540468ae)
- [Creating ONNX from scratch](https://towardsdatascience.com/creating-onnx-from-scratch-4063eab80fcd)
- 蠻詳細的
- [Python Bindings for ONNX Runtime](https://onnxruntime.ai/python/)
- [Tutorials: ORT Inferencing](https://onnxruntime.ai/docs/tutorials/inferencing/)
- 如何在 Python 上用已經訓練好的 ONNX 模型做 Inference
- `import onnxruntime as ort`
- `sess = ort.InferenceSession(path_or_bytes)`
- `sess.run([output_name], {input_name: x})`
- input 是 Numpy arrays(tensors)、dictionaries(maps)、Numpy arrays 的 List(sequences)
- [ONNX - Python API Overview](https://github.com/onnx/onnx/blob/master/docs/PythonAPIOverview.md)
- 如何在 Python 把模型轉成 ONNX
- [將您的 PyTorch 模型轉換成 ONNX](https://docs.microsoft.com/zh-tw/windows/ai/windows-ml/tutorials/pytorch-convert-model)
- [TORCH.ONNX](https://pytorch.org/docs/stable/onnx.html)
- 有些限制要注意一下
- 有分 trace-based 和 script-based
- script-based 會在 method 前加上 `@torch.jit.script` decorator
- 不支持 numpy
- 支持 index(Getter、Setter)
- Opset version 要新一點
- [tf2onnx - Convert TensorFlow, Keras, Tensorflow.js and Tflite models to ONNX](https://github.com/onnx/tensorflow-onnx)
- 有一些注意事項(How tf2onnx works)
- [tf2onnx Support Status](https://github.com/onnx/tensorflow-onnx/blob/master/support_status.md)
- 現在有支援哪些 Opset
- 分為 `tf2onnx.convert.from_keras()`、`tf2onnx.convert.from_function()` 和 `tf2onnx.convert.from_graph_def()`
- [sklearn-onnx: Convert your scikit-learn model into ONNX](http://onnx.ai/sklearn-onnx/)
- `skl2onnx.convert_sklearn(model, initial_types)`
- 或是 `skl2onnx.to_onnx(model, training_dataset)`
- [ONNXMLTools](https://github.com/onnx/onnxmltools)
- 有支援 Apple Core ML、Spark ML、LightGBM、libsvm、XGBoost、H2O、CatBoost 等等
- `convert_coreml(model, ...)`
- `convert_libsvm(model, ...)`
- `convert_catboost(model, ...)`
- `convert_lightgbm(model, ...)`
- `convert_sparkml(model, ...)`
- `convert_xgboost(model, ...)`
- `convert_h2o(model, ...)`
- 也有 Keras、TensorFlow、scikit-learn 支援,是 tf2onnx、skl2onnx 的包裝,但還是建議直接使用原本的
- `convert_keras(model, ...)`
- `from_keras()`
- `convert_sklearn(model, ...)`
- `convert_sklearn()`
- `convert_tensorflow(model, ...)`
- `from_graph_def()`
- [Apache MXNet contrib.onnx](https://mxnet.incubator.apache.org/api/python/docs/api/contrib/onnx/index.html)
- [Operator support and coverage](https://github.com/apache/incubator-mxnet/tree/v1.x/python/mxnet/onnx#operator-support-matrix)
#### 討論區
- [Can't load external model to agent (from .pth convert to .onnx and then to .nn) #3398](https://github.com/Unity-Technologies/ml-agents/issues/3398)
- [Running a PyTorch (or even a TensorFlow) Model on Unity MLAgent](https://forum.unity.com/threads/running-a-pytorch-or-even-a-tensorflow-model-on-unity-mlagent.895631/)
- 官方表示不會針對這部份(使用自己的模型)多做說明,但是是有可能是成功,只要遵照他們的規則(TensorNames.cs 的命名規定)
- [Using ONNX Runtime inside Unity worked flawlessly however, and I am now using that instead of Barracuda.](https://github.com/Unity-Technologies/barracuda-release/issues/190)
- Barracuda(Unity 用來跑 ONNX 的)有蠻多 Operator 不支援(例如 If)
- 可以試試用 ONNX Runtime 代替
- [Microsoft.ML.OnnxRuntime](https://www.nuget.org/packages/Microsoft.ML.OnnxRuntime/)
- [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity)
- 因為 ML Agents 沒有辦法改,所以還是串接到 Python 用 ONNX Runtime 跑最理想
#### Unity 端
參考:[TensorNames.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Inference/TensorNames.cs)
參數要對應到這些名稱才有「機會」運作成功
參考:[BarracudaModelParamLoader.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs)
這是在載入模型的時候會做的檢查(版本、存不存在、shape 等),可以去了解這些限制代表什麼意思
參數的擺放參考 model_serialization.py
規定參數的型態應該是 Tensor([ModelLoader.cs](https://github.com/Unity-Technologies/barracuda-release/blob/release/2.1.0/Barracuda/Runtime/Core/ModelLoader.cs#L153)),設計 Network 時加上這些參數
在 ML Agents 2.0,會有一個給類 RNN 模型用的 memory,大小存在 `TensorNames.MemorySize`,如果是 0 代表不用類 RNN 模型
Legacy 的部分是給 ML Agents 1.0 的,不用看
`CheckPreviousActionShape()` 在 ML Agents 2.0 不使用
參考:[Model.cs](https://github.com/Unity-Technologies/barracuda-release/blob/release/2.1.0/Barracuda/Runtime/Core/Model.cs)
這是 Barracuda 中的 Model Class,ML Agents 中會用到,可參考
參考:[ModelLoader.cs](https://github.com/Unity-Technologies/barracuda-release/blob/release/2.1.0/Barracuda/Runtime/Core/ModelLoader.cs)
Barracuda 最多只支援到 8 維 Tensor
參考:[BarracudaModelExtensions.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Inference/BarracudaModelExtensions.cs)
在 C# 當中有 Extension(擴充方法),在 static method 第一個 argument 放上
`this 要擴充的類別 變數` 就可以用了
BarracudaModelExtensions 是 ML Agent 對 Barracuda.Model 的擴充
`GetVersion()`、`CheckExpectedTensors()` 等等都有被 BarracudaModelParamLoader 用到
參考:[ModelRunner.cs](https://github.com/Unity-Technologies/ml-agents/blob/main/com.unity.ml-agents/Runtime/Inference/ModelRunner.cs)
這裡面有 Model 如何執行的細節,Input 跟 Output 傳遞的重要細節都在這
#### Python 端
參考:[model_serialization.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents/mlagents/trainers/torch/model_serialization.py#L149)
很完整的呈現 ONNX 檔是如何被生出來的
因為是 Inference,所以 batch 的維度是 1
參考:[NCHW和NHWC](https://www.itread01.com/content/1545104706.html)
ML Agent 和 Barracuda 是使用 NCHW 慣例
參考:[torch_policy.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents/mlagents/trainers/policy/torch_policy.py#L57)
self.actor(Line 57、70)是 Network 轉換的本體
參考:[torch_policy.py](https://github.com/Unity-Technologies/ml-agents/blob/main/ml-agents/mlagents/trainers/torch/networks.py)
SimpleActor(Line 572)、SharedActorCritic(Line 689)會用來生成 actor
NetworkBody(Line 174)底下的 `memory_size(self) -> int` 是用來看有沒有使用類 RNN 模型,有的話是需要傳回去的大小,如果是 0 代表不用類 RNN 模型