跳到內容

使用連續動作

讓我們從之前的教程專案開始,為其添加連續動作。您可以使用初始專案跟隨操作,或者如果您願意,可以查看完整專案

離散動作 vs. 連續動作

在之前的指南中,我們使用了離散動作 - 我們的智能體必須在有限選項集(0 或 1)之間選擇以匹配模式。在實際場景中,我們可能會接收大量感應器數據和視覺輸入來決定按下哪個按鈕。

然而,在許多現實應用中,這並不總是可能的。對於控制以下類型的事物:

  • 車輛的轉向角度
  • 機械臂的關節扭矩
  • 引擎的功率水平

我們的智能體需要輸出連續動作——精確的浮點值,而非分類選擇。

向環境添加連續動作

讓我們修改環境,同時包含離散和連續動作。我們將保留原始的模式匹配任務,但添加第二個模式,我們期望 AI 輸出這個新值的平方根。

注意我們只改變了期望值——智能體需要僅通過獎勵信號的引導,通過試錯來弄清楚我們想要什麼!

首先,在 PatternMatchingEnvironment.cs 中添加新欄位以追蹤第二個模式和連續動作:

PatternMatchingEnvironment.cs
private int pattern = 0;
private int pattern2 = 0;
private int aiChoice = 0;
private float aicontinuousChoice = 0f;
private bool roundFinished = false;

接下來,添加第二個觀察方法和我們的連續動作方法:

PatternMatchingEnvironment.cs
[RLMatrixObservation]
public float SeePattern() => pattern;
[RLMatrixObservation]
public float SeePattern2() => pattern2;
[RLMatrixActionContinuous]
public void MakeChoiceContinuous(float input)
{
aicontinuousChoice = input;
}

現在,讓我們創建獎勵函數:

PatternMatchingEnvironment.cs
[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 方法以生成兩種模式:

PatternMatchingEnvironment.cs
[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 中更新程式碼:

Program.cs - Environment Type
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[]>>'

這是因為我們試圖將離散智能體與連續環境一起使用。我們需要更改智能體類型:

Program.cs - Agent Type
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(近端策略優化),它可以處理離散和連續動作空間:

Program.cs - Algorithm Options
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
);

我們的首次訓練運行

現在讓我們運行訓練,看看會發生什麼:

Training Output
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 並再次運行訓練…

有幫助嗎?可能沒有。事實上,您可能會注意到,雖然智能體學習離散動作更快,但它幾乎不探索連續動作空間,隨著訓練的進行,準確率甚至變得更糟。

那麼,究竟發生了什麼?

添加指導信號

讓我們嘗試通過提供更有幫助的獎勵信號來解決這個問題。我們將添加一個隨著智能體接近正確平方根而增加的獎勵,而不是僅獎勵精確匹配:

PatternMatchingEnvironment.cs
[RLMatrixReward]
public float ExtraSupportingReward() => 0.5f / (1 + Math.Abs(aicontinuousChoice - (float)Math.Sqrt(pattern2)));
//別忘了將 lr 改回 1E-03f!

這個獎勵函數創建了一個梯度——隨著智能體接近正確值,信號會變得更強。即使它不完全正確,它也會得到關於是變”熱”還是變”冷”的反饋。

讓我們再次運行訓練,看看會發生什麼:

Training Output
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 步:

Program.cs
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 獎勵,同時完全無法充分探索連續空間。

關鍵要點

通過這個練習,我們學到了幾個重要的教訓:

  1. 連續動作本質上比離散動作更難學習,這是由於稀疏獎勵問題。如果可能的話,將您的動作空間離散化!

  2. 獎勵工程對連續控制問題至關重要。提供關於”變熱”的信號將一個不可能的學習任務轉變為可處理的任務。

  3. 複雜任務需要更多訓練時間。隨著我們向動作空間添加維度,我們需要相應地擴展訓練持續時間。

  4. 演算法選擇至關重要。DQN 根本無法處理連續動作,而 PPO 可以處理離散、連續或混合動作空間。

  5. 學習率調整是微妙的,特別是使用 PPO 時。更高並不總是更好,有時對探索甚至可能更糟。

這些原則在您應對更複雜的 RLMatrix 強化學習挑戰時將為您提供很好的幫助。

測試您的理解

理解連續動作

下一步

現在您已經了解了連續動作空間的挑戰以及如何應對這些挑戰,您已準備好嘗試一個具有更複雜觀察的經典強化學習問題。