ML-Agents新环境搭建实战:从空白场景到训练收敛全记录

ML-Agents 这个项目我前前后后折腾了不少时间,从最开始的 0.8 一直用到 1.9.1,中间踩过的坑能写满一整个记事本。这篇内容就围绕“创建一个新的训练环境”展开,以官方文档为主线,结合我自己做过的几个模拟项目,把从空白项目到跑通训练的全流程拆开讲清楚。主要面向两类人:一类是刚接触强化学习、想在 Unity 里快速验证想法的初学者;另一类是被版本兼容、观察设置、奖励设计折磨到头秃的实践者。版本锁定在 ML-Agents 1.9.1 和 Unity 2018-2020,这套配置是目前我试下来最稳的组合之一。

很多新手拿到官方文档第一反应是照着 Example 环境改,这路子没错,但如果你不知道每个组件为什么存在,改了也是白改。本文会从环境结构、代码实现、训练配置、调参排错四个方面逐步走一遍,最后附上我在实际项目中遇到的高频问题。我会尽量说人话,每个配置都会解释背后的原因,而不是单纯让你照着抄。

1. 新训练环境的核心结构拆解

1.1 一个训练环境到底由哪些部分组成

先说结论:一个完整的 ML-Agents 训练环境,本质上就是一场不断重播的“剧本杀”。场景里的所有物体是舞台,Agent 是演员,Academy(现在叫 Behavior,抱歉这里有点绕)是导演,Reward 是观众反馈,而训练配置则决定了演员的表演风格。

在 1.9.1 版本中,你需要的核心层级是这样:

  • Unity 场景:包含地面、光源、目标、障碍物等所有静态或动态物体。
  • Agent 对象:挂载 Agent 脚本的子物体,负责感知环境、做出决策、接收奖励。
  • Behavior Parameters 组件:替代了旧版的 Brain,定义了这个 Agent 如何决策——是外部隔一段时间给一次指令(决策频率),还是自己按照固定步数思考。
  • 决策脚本:继承自Agent类的 C# 代码,包含OnEpisodeBegin()、CollectObservations()、OnActionReceived()、Heuristic()四个关键方法。
  • Python 端:通过mlagents-learn命令加载训练配置和场景名称,启动与 Unity 的通信。
  • 训练配置文件(YAML):定义强化学习算法(PPO、SAC)的超参数、网络结构、奖励信号等。

对初学者来说,最容易混淆的是把“Agent 对象的脚本”和“训练配置”混为一谈。实际上,Agent 脚本只负责与环境交互的接口,真正的学习发生在 Python 端的神经网络里。Unity 这边只是不断产生数据流,通过 socket 发给 Python,Python 算完再把动作指令传回来。

1.2 为什么我推荐从官方环境改造而不是完全从零开始

官方文档反复强调要先跑通一个现成环境,不是没有道理的。从零开始建环境,你需要同时处理场景物理、相机设置、脚本逻辑、训练配置四件事,任何一个环节出错,训练都不收敛。而你根本分不清是代码 bug 还是超参问题。

我自己经历过最痛苦的一次:一个简单的“方块找目标”任务,Agent 怎么都学不会,后来发现是场景中阴影和光照影响了视觉观察,加上奖励给的太稀疏,双重原因叠加。这种问题如果你用官方示例先跑通基准,再逐步替换,就能很快定位。

所以我的建议是:先拷贝一个官方示例环境(比如 3DBall 或 PushBlock),把场景内容替换成你自己的玩法,保留原来的框架,然后一点一点把你不需要的部分删掉。等到项目成功跑通一次训练,再考虑完全从空白场景构建。这个顺序能少走 80% 的弯路。

2. 从空白场景创建新环境的完整实操流程

2.1 环境准备工作:Package 版本与 Python 版本匹配

这一步是地基,很多人卡在最开始就是这个原因。ML-Agents 1.9.1 对应的 Unity 包版本是 Release 9,Python 包版本是mlagents==0.28.0(我试过 0.30.0 也能跑,但 0.28 最稳)。Unity 2018 到 2020 版本都可以用,但需要留意:

  • Unity 2019.4 LTS 搭配 1.9.1 是我最推荐的组合,测试覆盖最多。
  • Unity 2020 以上需要把包从com.unity.ml-agents路径导入,同时确认scopedRegistries是否正确。

具体安装步骤不展开了,简单列一下:

  1. 创建一个 3D 项目(建议用内置渲染管线,不要用 URP,否则感知传感器会多一层色彩空间的坑)。
  2. 从官方 GitHub 下载 releases 对应的 unity package,或者通过 Package Manager 添加。
  3. 添加ml-agents、ml-agents-extensions(如果有需要)到项目。
  4. 在 Python 环境(建议用 conda 独立环境)安装全套依赖:pip install mlagents==0.28.0 torch==1.10.2 -f ...(具体 wheel 请根据你的 CUDA 版本选择)。

这里有一个官方文档里没细说但特别重要的点:Jupyter Notebook 里提示No module named 'mlagents_envs'时,往往是你pip install mlagents时把基础包装好了,但是导入了错误的环境。正确姿势是在项目的 Python 环境里运行python -m mlagents_envs,而不是直接import mlagents_envs。

2.2 场景搭建与 Agent 对象的设计

场景逻辑决定了任务的可学性。以最经典的“方块寻找目标”任务为例,你需要:

  • 地面:一个足够大的 Plane,否则 Agent 走走就掉出边界。
  • 目标:一个可被视觉识别的小方块,随机位置生成。
  • Agent 主体:一个 Capsule 或 Cube,挂上 Rigidbody(注意冻结旋转,只保留 xz 移动)。
  • 墙体或 Boundary:用一个 invisible wall 把有效区域圈起来,避免 Agent 逃逸。

在层级结构中,建议单独建一个空物体叫Environment,下面挂EnvController脚本,负责在每轮训练开始前随机摆放目标位置。这比让 Agent 自己控制目标要清晰,因为 Agent 脚本只关心自身的观测和行动,不关心全局布局。

Agent 对象上需要挂两个组件:Agent脚本(自己写)和Behavior Parameters。Behavior Parameters 里,Behavior Name决定了你在训练命令行中用的名称,比如MyAgentBehavior。Vector Observation的Space Size要与你CollectObservations()中添加的数值数量严格一致,这个绝对不要写错,错一位都不行。Actions部分选择Continuous Actions还是Discrete Actions,取决于你的动作空间,下面会详细说明。

2.3 编写第一个 Agent 脚本:核心方法逐个解析

这是我的练习环境脚本,先给你看整体:

using UnityEngine; using Unity.MLAgents; using Unity.MLAgents.Sensors; using Unity.MLAgents.Actuators; public class SeekTargetAgent : Agent { public Transform target; public float moveSpeed = 2f; private Rigidbody rBody; public override void Initialize() { rBody = GetComponent<Rigidbody>(); } public override void OnEpisodeBegin() { // 重置 Agent 自己的位置和速度 rBody.angularVelocity = Vector3.zero; rBody.velocity = Vector3.zero; transform.localPosition = new Vector3(0f, 0.5f, 0f); transform.localRotation = Quaternion.identity; // 重置目标的位置到一个随机坐标 if (target != null) { target.localPosition = new Vector3(Random.Range(-8f, 8f), 0.5f, Random.Range(-8f, 8f)); } } public override void CollectObservations(VectorSensor sensor) { // 位置和方向:6 个 float sensor.AddObservation(transform.localPosition); sensor.AddObservation(transform.localRotation); // 目标相对位置:3 个 float sensor.AddObservation(target.localPosition - transform.localPosition); // Agent 自身速度:3 个 float(从 Rigidbody 获取) sensor.AddObservation(rBody.velocity); // 距离:1 个 float sensor.AddObservation(Vector3.Distance(target.localPosition, transform.localPosition)); // 总计 13 个观测变量 } public override void OnActionReceived(ActionBuffers actions) { // 连续动作:第一个控制 x 方向速度,第二个控制 z 方向速度 float moveX = actions.ContinuousActions[0]; float moveZ = actions.ContinuousActions[1]; Vector3 velocity = new Vector3(moveX, 0f, moveZ) * moveSpeed; rBody.velocity = velocity + new Vector3(0f, rBody.velocity.y, 0f); // 奖励逻辑:碰触目标给 +1 并结束回合 // 每步给一个小惩罚,迫使 Agent 尽快到达 AddReward(-0.01f); } public override void Heuristic(in ActionBuffers actionsOut) { // 手动控制测试用 var continuousActions = actionsOut.ContinuousActions; continuousActions[0] = Input.GetAxis("Horizontal"); continuousActions[1] = Input.GetAxis("Vertical"); } private void OnTriggerEnter(Collider other) { if (other.CompareTag("Target")) { AddReward(1.0f); EndEpisode(); } } }

然后讲每个方法的设计思路。

OnEpisodeBegin:每一轮训练(episode)开始时调用。它做两件事:一是重置 Agent 状态,二是重置目标任务状态。如果你希望目标位置是随机但又不是每次都换,可以加一个episodeCount字段控制每隔 N 回合换一次目标,这样可以观察 Agent 对固定目标的记忆能力。

CollectObservations:这是让环境能被学习的关键。你的观测空间就是“给神经网络的输入特征”。设计观测空间时,要遵循“相对而非绝对”的直觉:绝对坐标对 Agent 没有意义,因为它不知道世界原点是哪里;相对位置才是决策依据。所以我在上面把目标相对位置单独放进去。注意,位置 + 速度 + 相对位置一共 9 个维度,再加上一个距离,神经网络的学习压力已经比较大了。实际项目中,我一般会先用一两个维度验证训练能收敛,再逐步增加特征,而不是一开始就堆几十个变量。

OnActionReceived:动作空间设计。连续动作直接使用ContinuousActions数组。如果动作是离散的,比如上下左右四个方向,就需要用DiscreteActions。但我要提醒你:对于移动类任务,连续动作通常比离散动作学到更流畅的策略,因为离散动作在转向时会形成突变,不利于平滑控制。

Heuristic:这是调参神器。训练前先用键盘手动控制 Agent,观察传感器数据是否合理、碰撞检测是否正常、环境是否太简单或太难。如果手动控制都拿不到正奖励,那你不能指望强化学习能凭空学会。官方文档也建议在实际训练前启用 Heuristic 测试。

2.4 Behavior Parameters 与决策频率设置

Behavior Parameters 组件上有几个关键参数容易忽视:

  • Behavior Name:必须是一个合法的 Python 标识符,训练命令行中要完全一致。比如SeekTargetBehavior。
  • Vector Observation > Space Size:和CollectObservations中添加的总数一致。我在上面是 13,如果你想加入射线感知,Space Size 会变成numRays * (1 + detectionLevels),这个公式很多人记错,后面我会在常见问题里讲。
  • Vector Observation > Stacked Vectors:控制历史观测堆叠数量。通常设为 1,如果你希望 Agent 感知到速度或方向的变化,可以设为 3-5,但堆叠会显著增加输入维度,导致训练更慢。
  • Actions > Continuous Actions / Discrete Actions:这里选择的模式必须和OnActionReceived中读取的 action 类型匹配。你选了 Continuous,代码里用DiscreteActions读取就会报错。
  • Behavior Type:默认为 Default(训练时由 Python 决定)。如果你暂时不想训练,只想在编辑器里用 Heuristic 模式测试,可以临时切换为Heuristic Only。但务必记得训练前改回来,否则 Python 端会一直看待超时。

决策频率(Decision Frequency)在 1.9.1 版本中已经放到了 Behavior Parameters 里,不再需要单独的DecisionRequester脚本。默认值 5 意味着每隔 5 个 FixedUpdate 会请求一次决策。对于简单的控制任务,5 够用;对于需要快速反应的任务,可以设为 1,但会成倍增加训练时间。我个人经验是:除非任务对实时性非常敏感,否则尽量保持默认或稍微调高到 5-10,反而更容易学到一个稳定的策略。

3. 核心实现细节:观察、动作、奖励与代码实战

3.1 向量观察与视觉观察怎么选

ML-Agents 提供了三种感知方式:向量观察(Vector Observation)、视觉观察(Camera Sensor)、射线感知(RayPerception)。

public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(...); // 向量 }

如果你的 Agent 状态是可以直接量化的(位置、速度、角度),这是最方便、训练效率也最高的方式。因为它直接将原始数值作为神经网络输入,不需要做图像卷积。很多同学认为视觉观察看起来“更像 AI”,但实际效果往往不如精心设计的向量观察,因为相机传感器要求场景光照稳定、物体颜色对比度足够高,而且训练数据量需求大得多。

视觉观察适合那些“无法用简单数字描述”的任务,比如识别物体形状、判断方向、理解地图。一个典型的配置是在 Agent 上添加Camera Sensor组件,指定分辨率和灰度/彩色模式。我建议分辨率从 64x64 开始,不要一上来就用 128x128,参数量差距是平方级的。

射线感知是介于两者之间的方案,通过向多个方向发射射线探测物体距离,各个方向的探测结果拼接成一个向量。它比相机传感器计算开销小,也比纯手动设计特征更智能。常用的RayPerceptionSensor组件需要设置射线数量、角度范围和检测层。这里有个容易搞混的点:每条射线会对每个检测层返回一个 0-1 的距离值,外加一个是否命中的标记。所以空间大小的计算公式是:射线数 * (检测层数 + 1)。如果你设了 5 条射线、2 个检测层,那么空间大小应该是5 * (2+1) = 15。我在第一次配置时就没算这个,导致空间大小不匹配,报错排查了很久。

3.2 动作空间设计:连续、离散还是混合

ML-Agents 1.9.1 支持连续动作和离散动作,且可以同时存在。

连续动作空间,每个维度在 [-1, 1] 之间。为了让 Agent 更平滑地移动,我通常会把实际速度映射到动作值,比如动作值乘以最大速度。要注意的是,不要让输出直接作为速度,尤其是 Rigidbody 的速度,那样容易产生抖动,推荐在动作到实际物理操作之间加一个平滑层或限幅。

离散动作空间,比如Branch Size分别设定每个分支的离散选项数。一个典型例子:Discrete Branches = [2, 2, 2, 2]表示有四个分支,每个分支两个选项,可以编码“前进/后退”“左转/右转”“抓取/松开”“跳跃/静止”这四个独立能力。这个结构和 MultiDiscrete 空间是完全对应的,非常实用。

混合动作的常见场景是:一个分支控制方向(连续两个维度),另一个分支控制一个开关(离散两个选项)。在代码里,连续动作和离散动作分别通过ContinuousActions和DiscreteActions读取。

3.3 奖励设计的几条铁律

奖励设计是整个强化学习里最玄学的部分。我自己总结了几条经验:

规则一:先用稀疏大奖励,再用密集小奖励。如果 Agent 能通过一次碰撞直接获得 +1 奖励并结束回合,它会更快地学会“接近目标”这个行为。如果你一开始就给每一步的接近量进行微小奖励,Agent 很可能会学到原地抖动的作弊策略来骗奖励。我前几次试过用“距离减小一点给 +0.01”,结果 Agent 学会了曲线移动——因为它发现这样可以让距离反复变化,反复拿奖励。

规则二:惩罚不要太过,否则 Agent 选择提前结束。一个常见的错误是给每一步 -0.1 的惩罚,频繁碰撞再罚 -1。这样 Agent 会学到“站着不动”是最安全的。适当的做法是:步数惩罚设为 -0.01,让 Agent 在“快速完成”和“缓慢安全”之间找到平衡。

规则三:至少给一个终止条件和正奖励。如果整个训练过程中没有一个方法触发EndEpisode()并给正奖励,学习算法就会进入死循环,永远无法确认某个行为是好是坏。你的场景一定要确保存在“成功状态”,哪怕概率很低。

规则四:使用Reward Signals设置 External 和 Curiosity(可选)。如果你发现 Agent 在前几百 episodes 里毫无进展,可以尝试加入curiosity奖励信号,它会基于预测误差给出探索奖励,帮助 Agent 在早期找到稀疏奖励。但要注意,curiosity 过强会让 Agent 变成“乱跑狂魔”。YAML 里可以这样配:

reward_signals: extrinsic: strength: 1.0 gamma: 0.99 curiosity: strength: 0.01 gamma: 0.99 encoding_size: 128 learning_rate: 0.0003

gamma决定了 Agent 对未来奖励的重视程度。0.99 左右是默认,如果任务步数很多,可以适当降到 0.95,减小未来奖励的累积误差。

3.4 训练配置文件 YAML 关键参数实战

ML-Agents 1.9.1 支持 PPO 和 SAC。我的推荐是:默认用 PPO,连续动作空间可以用 SAC,但 SAC 对超参敏感,新手慎用。

一个基础 PPO 配置长这样(假设行为名是SeekTargetBehavior):

behaviors: SeekTargetBehavior: trainer_type: ppo hyperparameters: batch_size: 1024 buffer_size: 10240 learning_rate: 0.0003 beta: 0.005 epsilon: 0.2 lambd: 0.95 num_epoch: 3 learning_rate_schedule: linear network_settings: normalize: false hidden_units: 128 num_layers: 2 reward_signals: extrinsic: strength: 1.0 gamma: 0.99 max_steps: 500000 time_horizon: 64 summary_freq: 10000 keep_checkpoints: 5 checkpoint_interval: 50000 threaded: true

我解释几个容易踩坑的参数:

  • buffer_size要远大于batch_size,且能整除batch_size,否则训练时采样会报错或效率低下。
  • time_horizon是收集多少步经验后进行 GAE 计算。对于步数较多的任务,可适当调大到 128-256,太短会导致价值估计不够稳定。
  • normalize: false是对输入观测做归一化。如果观测值量纲差别很大(比如位置是 10,速度是 0.1),建议设为true。但要注意,设置normalize会增加一定训练开销。
  • max_steps表示总训练步数。500000 是最低量级,推荐至少 2000000 才可能收敛。如果想快速验证,可以先用 50000 看趋势。

启动训练的命令行我一直记着一句口诀:“配置文件、场景、run-id 三位一体”。

mlagents-learn config/ppo_SeekTarget.yaml --run-id=seek_target_1 --port=5005

训练开始前,会让你按 Play 键启动 Unity 场景。按下 Play,等到控制台出现 “Start training” 的字样,就开始正常跑了。如果卡在 “Waiting for trainer” 或半天不响应,多半是 Python 版本不匹配或端口被占用。

3.5 一次完整训练运行的观察记录

我以实际跑过一次的任务为例,展示你该关注哪些输出:

  • 前 20 万步:Cumulative Reward 一直徘徊在 -100 左右,Agent 基本在乱动。
  • 20-40 万步:偶尔出现几次正奖励,但方差很大,TensorBoard 上的奖励曲线开始有上升势头。
  • 40 万步之后:策略逐渐稳定,Agent 开始直线走向目标,碰撞后获得正奖励的频次增加。

在这个阶段,你可以在 Unity 编辑器里看到 Agent 的移动逐渐从抽搐变为平滑,这是胜利前的信号。但不要急着庆祝,去 TensorBoard 看Entropy值:如果熵早早降到 0.01 以下,而奖励还没起来,说明策略过早收敛到局部最优,需要降低beta或增大初始化噪声。我踩过这个坑,最后把beta从 0.005 调到 0.02,释放了更多探索行为,才最终学到正确策略。

4. 新环境训练中的高频问题与排查技巧

4.1 训练不收敛、奖励曲线毫无起色时怎么查

遇到这种问题先别怀疑算法,99% 是这四类原因:

  1. 奖励设计落地有问题:你写的AddReward真的执行到了吗?我没少犯这种低级错误,比如OnTriggerEnter里没有CompareTag匹配成功,导致奖励永远加不上。建议在代码里临时写一个Debug.Log("Reward +1")看看是否触发。

  2. 观测数据没有区分度:如果不同状态下观测值几乎一样,神经网络学不出决策。你可以打印观测看看,例如用VectorSensor的原始值,在Heuristic模式下人为制造两种状态差异,对比观测数值是否明显。

  3. 动作空间与物理响应不匹配:比如你让动作直接控制速度,但物理引擎阻尼过大,实际运动幅度很小。可以用Debug.Log(rBody.velocity)看速度变化。

  4. 训练配置里max_steps太小:我试过以为 200000 步足够了,结果 Agent 还在探索期。判断的标准是:TensorBoard 里的Cumulative Reward曲线是否在稳定步入上升通道。如果是乱撞,考虑加步数。

4.2 与 Unity 版本兼容的经典坑

ML-Agents 1.9.1 官方文档特别指明支持 Unity 2018-2020,但我实测发现 2020 版本中需要额外注意插件包中的Burst和Mathematics版本,如果不一致,会出现“socket exception”或TLS Allocator报错。解决办法是在 Package Manager 中把com.unity.burst降级到 1.4.0 左右。

另一个坑是:如果用MLAgents1.9.1,但 Python 端安装了 0.30.0 或更新版本,在启动训练时会出现Unable to connect to Unity或No brain in environment。这不是玄学,是因为 1.9.1 的通信协议版本与新版 Python 包不兼容。我的建议是严格锁定 Python 包版本为 0.28.0,并创建单独的虚拟环境,避免和别的项目混用依赖。

4.3 视觉观察全黑或轮廓不对

如果你用Camera Sensor或RayPerception,最典型的故障是视觉输入全黑。原因通常是相机Target Texture没有正确设置,或在训练模式下摄像机被 UI Canvas 遮挡。检查方法:在编辑器里调成一个空场景,把相机对准目标,查看相机预览是否正常。

关于射线感知,检查Detectable Tags列表是否设置正确。默认射线会检测所有标签,但如果你使用了自定义标签,一定要在Ray Perception Sensor 3D组件的参数里添加这些标签。官方文档里提到过,但很多人会翻来覆去找不到问题在哪。

4.4 利用 Heuristic 模式快速验证环境逻辑

这是我最推荐的基本功测试法。将 Behavior Type 切换为Heuristic Only,然后在OnActionReceived中通过Input.GetAxis控制动作。以我的经验,这个模式能帮你发现:

  • Agent 的物理感受器是否正常,比如碰撞、摩擦、重力。
  • 目标的产生和重置是否可靠。
  • 奖励是否正确累加并触发回合结束。

如果你手动控制可以轻松完成目标,但切换回训练模式学时非常慢,那说明奖励信号或观测结构还有待改进。反之,如果手动都完不成,说明任务设计有硬伤,比如目标永远生成在 Agent 无法到达的地方。

4.5 一个替代思路:从简单环境递增难度

最后分享一个我自己常用的策略:新建环境时,先造一个简化版,只保留一个目标点、没有障碍物、没有随机干扰,训练到稳定收敛,然后再逐步加入障碍物、移动目标、风力等干扰。这比直接上一个复杂任务要省心得多。因为每次只改一个变量,出了问题你能立刻知道是哪个改动引起的。

官方文档里虽然没有详细写这种工作流,但我认为它本质上符合强化学习的“课程学习”(Curriculum Learning)思想。在 ML-Agents 中可以设置lesson和Curriculum文件来动态改变难度参数,但对新手来说,手动简化环境就已经能解决 90% 的学习问题。

5. 训练启动后的实战观察与优化策略

5.1 以 TensorBoard 为核心的第一轮分析

训练开始后,不要干等着。

正确流程是立刻打开 TensorBoard:

tensorboard --logdir results/seek_target_1

重点关注这几个指标:

  • Cumulative Reward:回合总奖励的均值。如果持续上升,说明策略在改善;如果横盘甚至下降,优先查奖励函数。
  • Value Loss / Policy Loss:两者都应在一定范围内起伏。若 Value Loss 爆炸到 1e6 级别,可能是奖励数值范围太大,需要做尺度缩放,比如所有奖励乘以 0.1。
  • Entropy:代表动作分布的随机程度。初始约 1.0,逐步下降是正常的,但如果过早降到 0.01,就要怀疑探索不足。
  • Policy Gradient:看到它稳定为负且绝对值减小,说明策略在优化。

我第一次跑某个任务时,只看 Cumulative Reward 一直没涨,就想改网络结构。后来看了一眼 Entropy,才发现已经归零,其实是beta太小导致探索耗尽。这类案例说明指标之间要交叉验证,不能只看一个。

5.2 环境难度调节与课程表策略

官方文档提供了一个Curriculum文件的功能,可以按阶段改变环境参数,比如目标的运动速度、障碍物数量。我个人觉得 1.9.1 的 curriculum 配置稍显笨重,但确实有效。

它的核心思想是:从最简单的配置开始训练,当 Cumulated Reward 达到一个阈值后,通过lesson自动提高环境复杂度,让 Agent 渐进式学习。配置示例:

behaviors: SeekTargetBehavior: trainer_type: ppo curriculum: measure: reward threshold: 0.8 min_lesson_length: 100 signal_smoothing: true parameters: target_move_speed: - 0.0 - 1.0 - 2.0 - 3.0

在代码里,通过Academy.Instance.EnvironmentParameters读取参数并根据 lesson 改变目标移动速度。我在某个项目中靠着这个方法把一个原先学不会的“追移动目标”任务变成了稳定收敛。

但注意:curriculum 只适合奖励信号明确的场景,如果你在早期阶段连简单版都无法稳定拿正奖励,加课程表只会让训练雪上加霜。

5.3 多环境加速与训练稳定性

ML-Agents 支持在 Unity 中同时运行多个环境副本(即多个独立场景实例),可以显著加速数据采集。在 1.9.1 中,你可以通过将场景中的 Environment 做成 Prefab,然后在训练时用代码创建多个实例。但这里有个关键细节:每个实例的 Agent 都必须有不同的Behavior Parameters或独立 arena,否则数据会混在一起。

我常用的做法是,在场景中放置一个Dummy空物体,上面挂一个 Manager 脚本,在 Awake 中复制 N 个环境 Prefab。这个脚本不参与训练,只负责初始化。

5.4 训练合约之外的后处理技巧

训练完成后,模型会保存为.onnx文件。拿到模型后不要直接扔到项目中,先在Agent代码里通过Model Override加载模型,并把 Behavior Type 切换为Inference Only,在手动控制环境下观察它的表现。这里常遇到的问题是:

  • 模型推理速度正常但行为不符合预期,通常是训练时观测和推理时观测不一致,比如一个用了Random乱数,一个用了固定值。
  • 模型在编辑器里跑但发布到移动端后卡顿,可以考虑把Model Override中的Deterministic Inference选项打开,降低随机性。

最后一点切身感受:训练环境并不是建完就能一劳永逸的。你每修改一次场景物理、Agent 步长或奖励值,意味着之前训练出的模型很可能不再适用。建议把每个跑过的配置都记录下来,包括 Unity 场景版本、YAML 参数、Python 版本、训练步数,方便复现。

我自己习惯在项目目录下放一个train_log.md,每次实验记录一句话结论。时间久了你会感激这个习惯的。ML-Agents 的坑永远是那种“看似小但特别磨人”的类型,比如全黑画面、奖励不触发、版本冲突,但只要你肯花时间把每一步拆开验证,这些都能很快绕过去。如果你在创建一个新环境时卡住了,不妨回到基础:用 Heuristic 模式手动操作,确认环境反馈合理,再做智能训练。磨刀不误砍柴工。

相关新闻

SQL布尔盲注实战:从sqli-labs第十五、十六关拆解无回显渗透

SQL布尔盲注实战:从sqli-labs第十五、十六关拆解无回显渗透

1. 项目概述&#xff1a;从“看不见的输入框”开始理解布尔盲注的真实战场你有没有遇到过这样的页面&#xff1a;一个登录框&#xff0c;输入错误的账号密码&#xff0c;它不告诉你“用户名不存在”或“密码错误”&#xff0c;只冷冷地回一句“登录失败”&#xff1b;再试一次&…

2026/10/20 3:28:05 阅读更多 →
免费高精度IP定位查询入口:数据源拆解、实测对比与评估指南

免费高精度IP定位查询入口:数据源拆解、实测对比与评估指南

这些年我见过太多人带着“免费高精度IP地址定位查询入口”这个想法找上门&#xff0c;搜了一圈之后拿回来的要么是某个商业平台体验版&#xff0c;要么是挂着“全球精准定位”横幅、实际只能定位到城市甚至省份的普通接口。今天不绕弯子&#xff0c;直接把这几个问题拆开聊&…

2026/10/20 3:28:05 阅读更多 →
推理引擎原理与优化:从计算图到性能调优的完整指南

推理引擎原理与优化:从计算图到性能调优的完整指南

做推理引擎这几年&#xff0c;我最大的感受是&#xff1a;很多人手上的模型跑得起来&#xff0c;但跑不快、跑不稳&#xff0c;出了问题也不知道该从哪一层开始查。根本原因是把“AI 模型”和“推理引擎”当成两个隔离的黑盒——模型文件一丢&#xff0c;引擎一跑&#xff0c;结…

2026/10/20 3:28:05 阅读更多 →

最新新闻

Qt新建工程全攻略:从环境配置到构建调试一步到位

Qt新建工程全攻略:从环境配置到构建调试一步到位

最近有朋友问我&#xff1a;Qt 到底怎么新建工程&#xff1f;他说自己把 Qt Creator 装好了&#xff0c;结果打开软件&#xff0c;面对一堆模板和选项完全不知道该点哪里。这个问题看起来基础&#xff0c;但我在带新人时发现&#xff0c;能在这一步顺畅走完、并且真正理解每个选…

2026/10/20 4:26:40 阅读更多 →
Flutter集成HarmonyOS实战:从跨平台架构到鸿蒙适配全记录

Flutter集成HarmonyOS实战:从跨平台架构到鸿蒙适配全记录

开篇先说明一个事&#xff1a;这个项目不是我接的“外包订单”&#xff0c;也不是教学 Demo&#xff0c;而是我作为主要开发者&#xff0c;从 0 到 1 做的一个自研社区共享类 App。整个过程涉及三块硬骨头&#xff1a;第一&#xff0c;把“共享社区”这种偏软性的业务逻辑落到产…

2026/10/20 4:26:40 阅读更多 →
PyTorch从零手写Transformer:位置编码、多头注意力与mask详解

PyTorch从零手写Transformer:位置编码、多头注意力与mask详解

先说个个人感受&#xff1a;Transformer 这种架构&#xff0c;看论文、看别人写的博客总觉得挺简单&#xff0c;真正自己用 PyTorch 一行行从零实现一遍&#xff0c;才意识到里面有大量容易出问题的细节。维度、mask、残差和归一化的顺序&#xff0c;任何一个地方没想明白&…

2026/10/20 4:26:40 阅读更多 →
AI检测一片飘红?从降AI率底层逻辑到作业实战全流程

AI检测一片飘红?从降AI率底层逻辑到作业实战全流程

又到了交作业的季节&#xff0c;后台和私信里最密集的问题永远是同一个&#xff1a;老师发的AI检测报告一片飘红&#xff0c;初稿直接被标“疑似AI生成”&#xff0c;怎么办&#xff1f;这几年我陆陆续续试过市面上能见到的各种降AI率工具&#xff0c;说实话&#xff0c;真正能…

2026/10/20 4:26:40 阅读更多 →
Fort Firewall 防火墙配置教程:5分钟配出第一条拦截规则,附排错清单

Fort Firewall 防火墙配置教程:5分钟配出第一条拦截规则,附排错清单

Fort Firewall 防火墙配置教程&#xff1a;5分钟配出第一条拦截规则&#xff0c;附排错清单 【免费下载链接】fort Fort Firewall for Windows 项目地址: https://gitcode.com/GitHub_Trending/fo/fort 一次凌晨的境外异常外联&#xff0c;在 Windows 防火墙日志里几乎没…

2026/10/20 4:26:40 阅读更多 →
技术人技能管理指南:从技能盘点、刻意练习到作品集构建

技术人技能管理指南:从技能盘点、刻意练习到作品集构建

1. 从“skills”这个词说起&#xff1a;为什么它突然成了硬通货“skills”这个词&#xff0c;放在五年前&#xff0c;可能只是简历底部一个不起眼的栏目。但现在你打开任何一个技术社区、招聘页面或者同行群聊&#xff0c;它出现的频率高得离谱。我自己的感受是&#xff0c;过去…

2026/10/20 4:25:39 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →