
超详细的Unity小白的 ML-Agents(Release 22)学习记录3:以 RollerBall 为例建立并行运算(多重影分身)
以 RollerBall 为例建立并行运算(多重影分身)
0. 目的
① 看到官方的 3DBall 案例可同时进行12个 Agent 的训练,且经验共享,极大加速训练过程。
3DBall 官方教程:https://github.com/Unity-Technologies/ml-agents/blob/develop/docs/Getting-Started.md
② 因此,尝试进行对 RollerBall案例 进行并行训练设置。
RollerBall 官方教程:https://github.com/Unity-Technologies/ml-agents/blob/develop/docs/Learning-Environment-Create-New.md
详细的CSDN中文教程:https://blog.csdn.net/CDSN985144132/article/details/145779969
1. 创建 Scene 副本
① 打开 RollerBall 项目
② Project → Scenes → Crtl+C、Ctrl+V 复制黏贴 SampleScene → Rename “MultipleScene”
③ 双击 “MultipleScene” 进入
※ 不建议小白(比如我) Copy 整个 Project ,同名的 C# Script 会出现一堆报错,我没解决明白。
所以还不如在一个 Project 中创建多个 Scene 副本和 Script 副本 进行版本迭代比价方便。
2. 重新建立关联的 C# Script
① MultipleScene 关联的还是原来的 RollerAgent 的 Script,对我们修改代码很不方便,所以先进行断联,并重建新的 Script。
② 按如下顺序,点每个模块右上角的三点,Remove Component。因为有依赖关系,所以要按顺序删除。
③ 重命名 Hierarchy 中的元素,方便后面新建的 C# Script 的区分:
TrainingArea → MultiTrainingArea
Floor → MultiFloor
Target → MultiTarget
RollerBall → MultiRollerBall
※ 我第一次做的时候用了下划线,结果发现训练时的yaml文件中无法打出下划线,所以后面为了统一,全部改为了Multi前缀无下划线链接的形式,推荐大家在这里就改好。
代码中的变量已重新更改,图片就不再重新改动了, Hierarchy 的重命名设置可参考(步骤 8 及以后的图片) 才是完全正确的无下划线连接版本。
④ 在 Multi_RollerAgent 的 Inspector 中重新 Add Component → New Script → 重命名为 Multi_Roller Agent
3. 编辑 Multi_RollerAgent.cs 的思路与准备
① 在 VS code 中打开 Multi_RollerAgent.cs 、RollerAgents.cs 和 Ball3DAgents.cs 进行参考修改。
② 在并行运算中,最核心的是检查代码中:更改将 Agent坐标系,是否基于父类的 “TrainingArea的相对坐标”。
③ 因此,我们以 RollerAgent.cs 为基础,参考 Ball3DAgents.cs 中的相对坐标语句,来编写我们的 Multi_RollerAgent.cs。
4. Multi_RollerAgent.cs 的完整版
① 经检查发现:localPosition 就表示父类的相对坐标,因此不需要改动
② 因此仅做变量名的修改:如 RollerAgent 变为 MultiRollerAgent、Target 变为 MultiTarget、TrainingArea 变为 MultiTrainingArea 等。
③ 完整 Multi_RollerAgent.cs 代码如下:
// 引入必要的工具包(就像拼装模型需要的不同工具)
// 引入必要的工具包(就像拼装模型需要的不同工具)
using System.Collections; // 基础系统工具(虽然本例未直接使用,但保留无害)
using System.Collections.Generic; // 列表等数据结构工具(本例未直接使用)
using UnityEngine; // Unity引擎核心功能(控制游戏对象、物理等)
using Unity.MLAgents; // 机器学习基础功能(训练AI)
using Unity.MLAgents.Sensors; // 感知环境(类似AI的眼睛)
using Unity.MLAgents.Actuators; // 控制行为(类似AI的手脚)
// 【类名修改】将原来的RollerAgent改为MultiRollerAgent
// 这个类控制AI小球的全部行为
public class MultiRollerAgent : Agent // 类名必须和文件名一致
{
// 【变量声明区域】--------------------------------
// 小球的物理组件(就像给小球装上发动机)
private Rigidbody rBody;
// 【变量名修改】将Target改为MultiTarget
// 在Unity编辑器中将目标物体拖拽到这里(关联目标方块)
public Transform MultiTarget;
// 控制移动力度(数字越大,推得越猛)
public float forceMultiplier = 10;
// 【初始化】当小球被创建时自动执行(类似玩具装电池)
public override void Initialize()
{
// 获取小球的物理组件(找到自带的发动机)
rBody = GetComponent<Rigidbody>();
}
// 【回合开始】每次训练回合开始时执行(类似游戏重新开局)
public override void OnEpisodeBegin()
{
// 如果小球掉下平台(Y坐标小于0)
if (transform.localPosition.y < 0)
{
// 重置物理状态(停止旋转和移动)
rBody.angularVelocity = Vector3.zero; // 角速度归零
rBody.velocity = Vector3.zero; // 移动速度归零
// 将小球放回中心位置(X=0,Y=0.5,Z=0)
transform.localPosition = new Vector3(0, 0.5f, 0);
}
// 【重要修改】设置目标的新位置(使用MultiTarget变量)
// 随机生成目标位置(X和Z在-4到4之间,Y保持0.5)
MultiTarget.localPosition = new Vector3(
Random.value * 8 - 4, // X轴:-4到4
0.5f, // Y轴固定(避免悬空或下沉)
Random.value * 8 - 4 // Z轴:-4到4
);
}
// 【收集信息】告诉AI当前环境状态(类似给AI看仪表盘)
public override void CollectObservations(VectorSensor sensor)
{
// 观察目标位置(X,Y,Z坐标)——使用修改后的MultiTarget
sensor.AddObservation(MultiTarget.localPosition);
// 观察自身位置(X,Y,Z坐标)
sensor.AddObservation(transform.localPosition);
// 观察速度(只记录X和Z方向,因为Y轴掉落时已经结束回合)
sensor.AddObservation(rBody.velocity.x); // X轴速度
sensor.AddObservation(rBody.velocity.z); // Z轴速度
// 总共收集 3(目标) + 3(自身) + 2(速度) = 8个数据
}
// 【执行动作】根据AI的决策移动小球(类似操纵方向盘)
public override void OnActionReceived(ActionBuffers actionBuffers)
{
// 获取AI的输出(两个方向的控制信号)
Vector3 controlSignal = Vector3.zero; // 初始化控制信号
controlSignal.x = actionBuffers.ContinuousActions[0]; // 左右控制
controlSignal.z = actionBuffers.ContinuousActions[1]; // 前后控制
// 施加力到小球(forceMultiplier调节力度大小)
rBody.AddForce(controlSignal * forceMultiplier);
// 计算与目标的距离(使用修改后的MultiTarget)
float distanceToTarget = Vector3.Distance(
transform.localPosition, // 小球位置
MultiTarget.localPosition // 目标位置
);
// 如果碰到目标(距离小于1.42单位)
if (distanceToTarget < 1.42f)
{
SetReward(1.0f); // 奖励1分
EndEpisode(); // 结束当前回合
}
// 如果掉下平台(Y坐标小于0)
else if (transform.localPosition.y < 0)
{
EndEpisode(); // 结束回合(无奖励)
}
}
// 【手动控制】用键盘测试小球移动(训练时不会用到)
public override void Heuristic(in ActionBuffers actionsOut)
{
// 获取键盘输入(左右箭头控制X,上下箭头控制Z)
var continuousActionsOut = actionsOut.ContinuousActions;
continuousActionsOut[0] = Input.GetAxis("Horizontal"); // 左右方向
continuousActionsOut[1] = Input.GetAxis("Vertical"); // 前后方向
}
}
5. 完成 GameObject 复制前的设置
① ml-agents 的核心特点 (分析自 Deepseek,自行验证真伪):
所有Agent共享同一个神经网络模型
每个Agent的体验数据会汇总到中央学习系统
系统分析所有数据后更新同一个模型
② 重新设置好 Multi_TrainingArea, 再复制。
下图是我后补的截图,大家这个位置目前只有一个 Multi_TrainingArea 的。
③ 先放入 单个 GameObject 训练出来的模型进行推理,以验证 Multi_RollerAgent.cs 写得对不对。
※ 单个 GameObject 模型没训练出来的,参考我之前的博客:
https://blog.csdn.net/CDSN985144132/article/details/145779969
6. 复制多个 GameObject
① 调整每个 GameObject 的 Transform ,x ± 20,z ± 20。距离不能太窄,不然影响小球的掉落。
② 调整 Main Camera 的参数,进行俯拍,并包含 9 个 GameObject。
7. 使用单个 Agent 训练的 Model 进行推理测试
① 检测 Behavior Parameters 的设置。
② Model 来自 RollerAgent 教程中的训练结果。
※ 单个 GameObject 的 RollerAgent 模型没训练出来的,参考我之前的博客:
https://blog.csdn.net/CDSN985144132/article/details/145779969
③ 点击上方的 Play 符号,开始推理测试,观察 9 个 GameObject 是否运行正常。如运行正常,则可以开始进行并行训练。
8. 设置训练超参数
① 在 ml-agents 文件夹下找到 config 文件夹,用 windows 系统自带的 记事本 新建 multi_rollerball_config.yaml 文件,将 txt 扩展名改为 yaml 即可。
② 文件内容如下,可以先不改动完成教程,后续根据自己的需求改动:
behaviors:
MultiRollerBall:
trainer_type: ppo
hyperparameters:
batch_size: 10
buffer_size: 100
learning_rate: 3.0e-4
beta: 5.0e-4
epsilon: 0.2
lambd: 0.99
num_epoch: 3
learning_rate_schedule: linear
beta_schedule: constant
epsilon_schedule: linear
network_settings:
normalize: false
hidden_units: 128
num_layers: 2
reward_signals:
extrinsic:
gamma: 0.99
strength: 1.0
max_steps: 100000
time_horizon: 64
summary_freq: 10000
※ 与 RollerBall 的 config 相比,唯一的改动是将 max_steps 从 500000 改为100000,降低了5倍,因为分身了9个,所以按理说总轮数也能下降以达到相同效果。
③ 超参数设置来源于官网教程:
https://github.com/Unity-Technologies/ml-agents/blob/develop/docs/Learning-Environment-Create-New.md
④ 超参数详解文档官网链接:
https://github.com/Unity-Technologies/ml-agents/blob/develop/docs/Training-Configuration-File.md
9. 开始进行并行训练
① 对每个 GameObject 执行以下操作:
选中 Model,按 Delete 键。
将 Inference Device 改为 Compute Shader (有些版本显示 CPU)。
Behavior Type 是 Default。
② 在终端打开 mlagents 所在的环境,打开 ml-agents 的文件夹,运行以下训练代码:
mlagents-learn config/multi_rollerball_config.yaml --run-id=Multi_RollerBall
每次运行都会生成一个id,如果 id 占用可以在末尾加上 “ --force”,就会强制覆盖,如下图。
③ 正常情况会显示如下:
④ 按 Editor 中的 Play 键就会看到训练开始,9个小球愉快得跑起来了:
10. 打开 TensorBoard 实时查看训练数据:
TensorBoard 使用教程及参数讲解官方链接:
https://github.com/Unity-Technologies/ml-agents/blob/develop/docs/Using-Tensorboard.md
① 打开新的 cmd终端窗口,打开所在虚拟环境,打开到 ml-agents 的文件夹。
② 运行以下命令:
tensorboard --logdir results
③看到以下输出:
④ 打开浏览器,输入:localhost:6006,即可打开 TensorBoard 界面,点击上方蓝框中的 SCALARS 和 下方蓝框中的 Policy,即可动态监控训练过程的参数,右上角的刷新号即可刷新:
※ 这里我把 单个的 RollerBall 和 9重影分身的 MultiRollerBall 进行了对比。可以看到并行训练在更少的轮次下,总奖励更高,而且学习曲线更平滑,训练时间也大大缩减。
⑤训练完成后显示如下信息,说明了 ONNX 模型的存放位置:
11. 更换训练好的模型进行推理:
① 参考我的另一篇CSDN博客的步骤10,链接如下,在此不再赘述:
https://blog.csdn.net/CDSN985144132/article/details/145779969
② 更换模型后,发现MultiRollerBall的模型比RollerBall的模型更高效,减少了喝假酒转圈的情况,更趋向于两点之间直线最短,唯一的出现转圈的情况主要是需要接化发抵消惯性和Floor边缘的刹车,但抵消完惯性和刹车后很快就会直奔目标。
更多推荐
所有评论(0)