小车-杆平衡示例
准备好亲眼见证强化学习的实际应用了吗?在本教程中,我们将挑战经典的平衡任务,你将观察到AI如何学会在移动小车上保持一根杆子直立。
小车-杆平衡挑战结合了简单性和视觉反馈,使其成为强化学习的完美示例。你向左或向右推动小车,物理定律决定了附着的杆子是保持平衡还是倒下。每个时间步,你的智能体做出决策,而你可以满意地观察你的算法如何逐渐掌握这项任务。
项目设置
我们将使用SciSharp/Gym.NET提供模拟物理环境。
您可以跟随教程操作,也可以下载完整项目。
让我们安装必要的包:
dotnet add package RLMatrixdotnet add package RLMatrix.Toolkitdotnet add package Gym.NETdotnet add package Gym.NET.Environmentsdotnet add package Gym.NET.Rendering.WinForm构建环境
以下是我们的小车-杆环境实现:
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; } }}设置训练
现在是教导我们的智能体平衡的训练代码:
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);现在神奇的事情发生了:
- 我们只对前200步累积奖励并计算梯度
- 模拟继续自然运行到1200步或直到失败
- GPU内存使用大幅下降
当您运行此配置时,查看您的奖励图表 – 您会注意到没有奖励超过200(我们的软限制),尽管小车-杆物理模拟在该点之后仍在继续。打开任务管理器,实时观察内存节省情况。
这种技术对于回合可能无限运行的复杂环境变得不可或缺。与其因内存不足错误而崩溃,您可以精确控制投入多少计算努力,同时保持自然的环境动态。
观察学习过程
当您运行此训练时,会弹出一个显示小车-杆环境的窗口。一开始,杆子会迅速倒下 – 您的智能体完全不知道该怎么做。但在几分钟内,您将见证一个非凡的转变:
- 最初,智能体做出随机移动,没有策略
- 然后它开始在杆子已经倒下时反应(太晚了!)
- 它逐渐学会更早做出纠正动作
- 最终,它做出微妙的预防性调整,使杆子保持完美平衡
这种可见的进展是什么使小车-杆作为学习示例如此令人满意。您不仅仅是看到图表上的数字改善 – 您正在亲眼目睹您的AI发展技能。
测试您的理解
理解小车-杆强化学习
下一步
在本教程中,您已经:
- 为强化学习设置了实时物理模拟
- 实现了一个完整的智能体来掌握经典控制问题
- 学习了如何使用软/硬终止技巧高效管理内存
- 了解了RLMatrix的PPO实现与标准实现的不同之处
接下来,我们将不使用工具包实现相同的环境,让您深入了解那些整洁属性背后发生的事情。