跳到內容

小車-桿平衡示例

準備好親眼見證強化學習的實際應用了嗎?在本教程中,我們將挑戰經典的平衡任務,你將觀察到AI如何學會在移動小車上保持一根桿子直立。

小車-桿平衡挑戰結合了簡單性和視覺反饋,使其成為強化學習的完美示例。你向左或向右推動小車,物理定律決定了附著的桿子是保持平衡還是倒下。每個時間步,你的智能體做出決策,而你可以滿意地觀察你的算法如何逐漸掌握這項任務。

項目設置

我們將使用SciSharp/Gym.NET提供模擬物理環境。

您可以跟隨教程操作,也可以下載完整項目

讓我們安裝必要的包:

安裝必要的包
dotnet add package RLMatrix
dotnet add package RLMatrix.Toolkit
dotnet add package Gym.NET
dotnet add package Gym.NET.Environments
dotnet add package Gym.NET.Rendering.WinForm

構建環境

以下是我們的小車-桿環境實現:

CartPoleEnvironment.cs
using System;
using System.Threading.Tasks;
using Gym.Environments.Envs.Classic;
using Gym.Rendering.WinForm;
using RLMatrix.Toolkit;
using NumSharp;
namespace MyEnv
{
[RLMatrixEnvironment]
public partial class CartPoleEnvironment
{
private CartPoleEnv myEnv;
private float[] myState;
private int stepCounter;
private const int MaxSteps = 100000;
private bool isDone;
public CartPoleEnvironment()
{
InitialiseAsync();
}
private void InitialiseAsync()
{
myEnv = new CartPoleEnv(WinFormEnvViewer.Factory);
ResetEnvironment();
}
[RLMatrixObservation]
public float GetCartPosition() => myState[0];
[RLMatrixObservation]
public float GetCartVelocity() => myState[1];
[RLMatrixObservation]
public float GetPoleAngle() => myState[2];
[RLMatrixObservation]
public float GetPoleAngularVelocity() => myState[3];
[RLMatrixActionDiscrete(2)]
public void ApplyForce(int action)
{
if (isDone)
ResetEnvironment();
var (observation, reward, done, _) = myEnv.Step(action);
myEnv.Render();
myState = ToFloatArray(observation);
isDone = done;
stepCounter++;
if (stepCounter > MaxSteps)
isDone = true;
}
private float[] ToFloatArray(NDArray npArray)
{
double[] doubleArray = npArray.ToArray<double>();
return Array.ConvertAll(doubleArray, item => (float)item);
}
[RLMatrixReward]
public float CalculateReward()
{
return isDone ? 0 : 1;
}
[RLMatrixDone]
public bool IsEpisodeFinished()
{
return isDone;
}
[RLMatrixReset]
public void ResetEnvironment()
{
myEnv.Reset();
myState = new float[4] { 0, 0, 0, 0 };
isDone = false;
stepCounter = 0;
}
}
}

設置訓練

現在是教導我們的智能體平衡的訓練代碼:

Program.cs
using RLMatrix.Agents.Common;
using RLMatrix;
using MyEnv;
Console.WriteLine("Starting cart-pole training...\n");
// 配置學習參數
var learningSetup = new PPOAgentOptions(
batchSize: 8,
ppoEpochs: 8,
memorySize: 1000,
gamma: 0.99f,
width: 128,
entropyCoefficient: 0.01f,
lr: 1E-02f
);
// 創建環境並連接到智能體
var environment = new CartPoleEnvironment().RLInit(maxStepsSoft: 1200, maxStepsHard: 1200);
var env = new List<IEnvironmentAsync<float[]>> {
environment,
//new CartPoleEnvironment().RLInit() //取消註釋可使用多環境訓練
};
// 初始化智能體
var agent = new LocalDiscreteRolloutAgent<float[]>(learningSetup, env);
// 訓練直至收斂
for (int i = 0; i < 100000; i++)
{
await agent.Step();
}
Console.WriteLine("\nTraining complete!");
Console.ReadLine();

每時間步+1的簡單獎勵出奇地有效。深度強化學習算法自然會優化長期目標,發現微妙、預防性的調整能導致更長的平衡時間和更高的累積獎勵。

RLMatrix中的PPO:有何不同

雖然DQN(我們早期教程中的算法)對簡單任務可能更具樣本效率,但PPO通常提供更穩定的訓練,無需大量超參數調整。這使其特別適合具有挑戰性的控制問題。

你需要知道的記憶體節省技巧

看看我們訓練代碼中的這一行:

var environment = new CartPoleEnvironment().RLInit(maxStepsSoft: 1200, maxStepsHard: 1200);

這個看似普通的參數配置包含了在不讓GPU記憶體不堪重負的情況下進行非常長回合訓練的關鍵。讓我解釋:

當我們修改這些值時會發生什麼?

var environment = new CartPoleEnvironment().RLInit(maxStepsSoft: 200, maxStepsHard: 1200);

現在神奇的事情發生了:

  1. 我們只對前200步累積獎勵並計算梯度
  2. 模擬繼續自然運行到1200步或直到失敗
  3. GPU記憶體使用大幅下降

當您運行此配置時,查看您的獎勵圖表 – 您會注意到沒有獎勵超過200(我們的軟限制),儘管小車-桿物理模擬在該點之後仍在繼續。打開任務管理器,實時觀察記憶體節省情況。

這種技術對於回合可能無限運行的複雜環境變得不可或缺。與其因記憶體不足錯誤而崩潰,您可以精確控制投入多少計算努力,同時保持自然的環境動態。

觀察學習過程

當您運行此訓練時,會彈出一個顯示小車-桿環境的窗口。一開始,桿子會迅速倒下 – 您的智能體完全不知道該怎麼做。但在幾分鐘內,您將見證一個非凡的轉變:

  1. 最初,智能體做出隨機移動,沒有策略
  2. 然後它開始在桿子已經倒下時反應(太晚了!)
  3. 它逐漸學會更早做出糾正動作
  4. 最終,它做出微妙的預防性調整,使桿子保持完美平衡

這種可見的進展是什麼使小車-桿作為學習示例如此令人滿意。您不僅僅是看到圖表上的數字改善 – 您正在親眼目睹您的AI發展技能。

測試您的理解

理解小車-桿強化學習

下一步

在本教程中,您已經:

  • 為強化學習設置了實時物理模擬
  • 實現了一個完整的智能體來掌握經典控制問題
  • 學習了如何使用軟/硬終止技巧高效管理記憶體
  • 了解了RLMatrix的PPO實現與標準實現的不同之處

接下來,我們將不使用工具包實現相同的環境,讓您深入了解那些整潔屬性背後發生的事情。