使用連續動作
讓我們從之前的教程專案開始,為其添加連續動作。您可以使用初始專案跟隨操作,或者如果您願意,可以查看完整專案。
離散動作 vs. 連續動作
在之前的指南中,我們使用了離散動作 - 我們的智能體必須在有限選項集(0 或 1)之間選擇以匹配模式。在實際場景中,我們可能會接收大量感應器數據和視覺輸入來決定按下哪個按鈕。
然而,在許多現實應用中,這並不總是可能的。對於控制以下類型的事物:
- 車輛的轉向角度
- 機械臂的關節扭矩
- 引擎的功率水平
我們的智能體需要輸出連續動作——精確的浮點值,而非分類選擇。
向環境添加連續動作
讓我們修改環境,同時包含離散和連續動作。我們將保留原始的模式匹配任務,但添加第二個模式,我們期望 AI 輸出這個新值的平方根。
注意我們只改變了期望值——智能體需要僅通過獎勵信號的引導,通過試錯來弄清楚我們想要什麼!
首先,在 PatternMatchingEnvironment.cs
中添加新欄位以追蹤第二個模式和連續動作:
private int pattern = 0;private int pattern2 = 0;private int aiChoice = 0;private float aicontinuousChoice = 0f;private bool roundFinished = false;
接下來,添加第二個觀察方法和我們的連續動作方法:
[RLMatrixObservation]public float SeePattern() => pattern;
[RLMatrixObservation]public float SeePattern2() => pattern2;
[RLMatrixActionContinuous]public void MakeChoiceContinuous(float input){ aicontinuousChoice = input;}
現在,讓我們創建獎勵函數:
[RLMatrixReward]public float GiveReward() => aiChoice == pattern ? 1.0f : -1.0f;
// 當 AI 的連續輸出接近第二個模式的平方根時,添加 +2 獎勵[RLMatrixReward]public float ExtraRewards() => Math.Abs(aicontinuousChoice - Math.Sqrt(pattern2)) < 0.1f ? 2f : 0.0f;
最後,我們需要更新 StartNewRound
方法以生成兩種模式:
[RLMatrixReset]public void StartNewRound(){ pattern = Random.Shared.Next(2); pattern2 = Random.Shared.Next(10); aiChoice = 0; roundFinished = false;}
注意我們為 pattern2 使用了 0-9 的範圍,這給智能體提供了一個更有趣的挑戰:預測不同的平方根值。
修復編譯錯誤
當您嘗試構建解決方案時,您會遇到一系列錯誤。這實際上很有幫助——RLMatrix 使用強類型來防止運行時錯誤,並引導您朝著連續動作的正確實現方向前進。
錯誤 1:環境類型不匹配
Argument 1: cannot convert from 'PatternMatchingExample.PatternMatchingEnvironment' to 'RLMatrix.IEnvironmentAsync<float[]>'
這是因為 RLMatrix 為連續和離散環境提供了不同的接口,以確保類型安全。讓我們在 Program.cs
中更新程式碼:
var env = new List<IEnvironmentAsync<float[]>> {var env = new List<IContinuousEnvironmentAsync<float[]>> { environment, //new PatternMatchingEnvironment().RLInit() //you can add more than one to train in parallel};
錯誤 2:智能體類型不匹配
進行此更改後,我們會遇到第二個錯誤:
Argument 2: cannot convert from 'System.Collections.Generic.List<RLMatrix.IContinuousEnvironmentAsync<float[]>>' to 'System.Collections.Generic.IEnumerable<RLMatrix.IEnvironmentAsync<float[]>>'
這是因為我們試圖將離散智能體與連續環境一起使用。我們需要更改智能體類型:
var agent = new LocalDiscreteRolloutAgent<float[]>(learningSetup, env);var agent = new LocalContinuousRolloutAgent<float[]>(learningSetup, env);
錯誤 3:演算法選項不匹配
這導致我們的第三個錯誤:
Argument 1: cannot convert from 'RLMatrix.DQNAgentOptions' to 'RLMatrix.PPOAgentOptions'
這個最終錯誤表明 DQN 與連續動作不兼容。我們需要切換到 PPO(近端策略優化),它可以處理離散和連續動作空間:
var learningSetup = new DQNAgentOptions( batchSize: 32, memorySize: 1000, gamma: 0.99f, epsStart: 1f, epsEnd: 0.05f, epsDecay: 150f);var learningSetup = new PPOAgentOptions( batchSize: 128, memorySize: 1000, gamma: 0.99f, width: 128, lr: 1E-03f);
我們的首次訓練運行
現在讓我們運行訓練,看看會發生什麼:
Step 800/1000 - Last 50 steps accuracy: 42.0%Press Enter to continue...
Step 850/1000 - Last 50 steps accuracy: 38.0%Press Enter to continue...
Step 900/1000 - Last 50 steps accuracy: 40.0%Press Enter to continue...
Step 950/1000 - Last 50 steps accuracy: 38.0%Press Enter to continue...
Step 1000/1000 - Last 50 steps accuracy: 37.0%Press Enter to continue...
驚訝吧!AI 幾乎沒有學到任何東西。準確率沒有超過 50%,如果查看儀表板,我們會發現它定期獲得離散動作(匹配模式)的 +1 獎勵,但很少獲得連續動作(預測 √pattern2)的 +2 獎勵。
為什麼會這樣?
問問自己:為什麼 AI 學習離散動作比連續動作容易得多?
您的第一直覺可能是學習率(lr
)——也許太低了?讓我們嘗試將其更改為 1E-02f
並再次運行訓練…
有幫助嗎?可能沒有。事實上,您可能會注意到,雖然智能體學習離散動作更快,但它幾乎不探索連續動作空間,隨著訓練的進行,準確率甚至變得更糟。
那麼,究竟發生了什麼?
添加指導信號
讓我們嘗試通過提供更有幫助的獎勵信號來解決這個問題。我們將添加一個隨著智能體接近正確平方根而增加的獎勵,而不是僅獎勵精確匹配:
[RLMatrixReward]public float ExtraSupportingReward() => 0.5f / (1 + Math.Abs(aicontinuousChoice - (float)Math.Sqrt(pattern2)));
//別忘了將 lr 改回 1E-03f!
這個獎勵函數創建了一個梯度——隨著智能體接近正確值,信號會變得更強。即使它不完全正確,它也會得到關於是變”熱”還是變”冷”的反饋。
讓我們再次運行訓練,看看會發生什麼:
Step 850/1000 - Last 50 steps accuracy: 35.0%Press Enter to continue...
Step 900/1000 - Last 50 steps accuracy: 40.0%Press Enter to continue...
Step 950/1000 - Last 50 steps accuracy: 47.0%Press Enter to continue...
Step 1000/1000 - Last 50 steps accuracy: 36.0%Press Enter to continue...
我們看到一些小的改進,但仍然不太理想。儀表板可能顯示學習正在進行的跡象,但顯然,對於這個更複雜的任務,我們需要更多的訓練時間。
延長訓練時間
對於連續動作預測等更複雜的挑戰,我們通常需要更多的訓練步驟。讓我們修改程序,訓練 10,000 步而不是 1,000 步:
for (int i = 0; i < 10000; i++){ await agent.Step();
if ((i + 1) % 500 == 0) { Console.WriteLine($"Step {i + 1}/10000 - Last 500 steps accuracy: {environment.RecentAccuracy:F1}%"); environment.ResetStats();
Console.WriteLine("\nPress Enter to continue..."); Console.ReadLine(); }}
實驗:學習率的影響
在觀察更長的訓練進度時,嘗試使用不同的學習率進行實驗。如果進一步降低會發生什麼?如果顯著提高呢?
在我的實驗中,設置非常高的學習率會導致模型陷入只收集離散動作的 +1 獎勵,同時完全無法充分探索連續空間。
關鍵要點
通過這個練習,我們學到了幾個重要的教訓:
-
連續動作本質上比離散動作更難學習,這是由於稀疏獎勵問題。如果可能的話,將您的動作空間離散化!
-
獎勵工程對連續控制問題至關重要。提供關於”變熱”的信號將一個不可能的學習任務轉變為可處理的任務。
-
複雜任務需要更多訓練時間。隨著我們向動作空間添加維度,我們需要相應地擴展訓練持續時間。
-
演算法選擇至關重要。DQN 根本無法處理連續動作,而 PPO 可以處理離散、連續或混合動作空間。
-
學習率調整是微妙的,特別是使用 PPO 時。更高並不總是更好,有時對探索甚至可能更糟。
這些原則在您應對更複雜的 RLMatrix 強化學習挑戰時將為您提供很好的幫助。
測試您的理解
理解連續動作
下一步
現在您已經了解了連續動作空間的挑戰以及如何應對這些挑戰,您已準備好嘗試一個具有更複雜觀察的經典強化學習問題。