Unity-ML-Agents-代码解读-RollerBall

使用版本:https://github.com/Unity-Technologies/ml-agents/releases/tag/release_19

文件路径:ml-agents-release_19/docs/Learning-Environment-Create-New.md

20和19的在rollerBall上一样:https://github.com/Unity-Technologies/ml-agents/blob/develop/docs/Learning-Environment-Create-New.md

本文只涉及代码解析,对于unity的对应操作请看相应文档

目录

1. Initialization and Resetting the Agent

1.1 代码总括

1.2 代码分解

1.2.1 导入包和命名空间

1.2.2 this.transform.localPosition.y < 0

1.2.3 this.transform.localPosition = new Vector3( 0, 0.5f, 0)

1.2.4 Target.localPosition = new Vector3(Random.value * 8 - 4, 0.5f, Random.value * 8 - 4); }

2. Observing the Environment

2.1 代码总括

2.2 代码分解

2.2.1 public override void CollectObservations(VectorSensor sensor)

2.2.2 sensor.AddObservation(Target.localPosition)

2.2.3 sensor.AddObservation(this.transform.localPosition)这一行代码将 

2.2.4 sensor.AddObservation(rBody.velocity.x)

2.2.5 sensor.AddObservation(rBody.velocity.z)

3. Taking Actions and Assigning Rewards

3.1 代码总括

3.2 代码分解

3.2.1 public float forceMultiplier = 10

3.2.2 public override void OnActionReceived(ActionBuffers actionBuffers)

3.2.3 controlSignal.x = actionBuffers.ContinuousActions[0]

3.2.4 float distanceToTarget = Vector3.Distance(this.transform.localPosition, Target.localPosition)

4.问题

4.1 报错

4.1.1 解决报错1

4.1.2 解决报错2


1. Initialization and Resetting the Agent

1.1 代码总括

using System.Collections.Generic; // 导入命名空间 System.Collections.Generic
using UnityEngine; // 导入 Unity 引擎的命名空间
using Unity.MLAgents; // 导入 Unity 引擎的 Machine Learning Agents(ML-Agents)的命名空间
using Unity.MLAgents.Sensors; // 导入 Unity 引擎的 ML-Agents 的 Sensors 的命名空间

public class RollerAgent : Agent // 声明一个 RollerAgent 类,继承自 Agent 类
{
    Rigidbody rBody; // 声明一个 Rigidbody 类型的变量 rBody

    void Start () { // 声明一个 Start 方法,当脚本启动时会执行该方法
        rBody = GetComponent<Rigidbody>(); // 获取当前 GameObject 的 Rigidbody 组件
    }

    public Transform Target; // 声明一个 Transform 类型的公共变量 Target,用于储存目标物体的位置信息

    public override void OnEpisodeBegin() // 重写 OnEpisodeBegin 方法
    {
       // 如果智能体掉落,则将其动量归零
        if (this.transform.localPosition.y < 0)
        {
            this.rBody.angularVelocity = Vector3.zero;
            this.rBody.velocity = Vector3.zero;
            this.transform.localPosition = new Vector3( 0, 0.5f, 0); // 将智能体放在起点
        }

        // 将目标物体移动到新的位置
        Target.localPosition = new Vector3(Random.value * 8 - 4, 0.5f, Random.value * 8 - 4);
    }
}

这段代码是一个简单的机器学习智能体(RollerAgent),用于学习如何控制一个球体移动到场景中随机位置的目标点。其中,using 语句用于导入所需的命名空间,public 关键字用于声明公共变量,Start 方法是 Unity 引擎中的一个特殊方法,当脚本启动时会自动执行,OnEpisodeBegin 方法则是重写了 Agent 类的该方法,用于在每个新的 episode(一次训练)开始时执行。

1.2 代码分解

1.2.1 导入包和命名空间

using System.Collections.Generic; // 导入命名空间 System.Collections.Generic
using UnityEngine; // 导入 Unity 引擎的命名空间
using Unity.MLAgents; // 导入 Unity 引擎的 Machine Learning Agents(ML-Agents)的命名空间
using Unity.MLAgents.Sensors // 导入 Unity 引擎的 ML-Agents 的 Sensors 的命名空间

using System.Collections.Generic 是一个 C# 中的命名空间,用于提供实现各种通用集合数据结构的类型。在使用 C# 中的 List、Dictionary 等数据结构时需要使用该命名空间。例如,当需要使用 List<T> 类型时,需要在代码文件的头部使用 using System.Collections.Generic; 声明该命名空间。

using UnityEngine 是 C# 编程语言中的一个关键字,用于引入 Unity 引擎的命名空间,使得在代码中可以直接使用 Unity 引擎提供的类和方法。这些类和方法包括用于创建游戏对象、控制游戏对象的位置、旋转、缩放、碰撞检测等等,以及访问 Unity 引擎中的其他功能。

Unity.MLAgents 是 Unity 官方提供的一个工具包,用于支持在 Unity 中训练机器学习模型,尤其是用于支持强化学习算法的训练。其中包含了许多用于强化学习的组件和类。通过使用这个工具包,开发者可以快速地在 Unity 中构建强化学习场景,训练自己的智能体,以及评估和部署训练好的模型。

using Unity.MLAgents.Sensors 引入了用于创建智能体感知信息的 ML-Agents 的 Sensor 类和相关组件。感知信息由智能体的观测(observation)和其他一些信息(如reward等)组成,用于训练智能体进行决策。该命名空间包含了许多不同类型的Sensor,例如VisualSensor和RayPerceptionSensor等,这些Sensor可用于感知不同类型的环境。

1.2.2 this.transform.localPosition.y < 0

this.transform.localPosition.y < 0

这段代码用于检测智能体在环境中是否跌落。具体地,它检查智能体的本地坐标(local position)的y值是否小于0,如果是,说明智能体已经跌落到地面以下。

1.2.3 this.transform.localPosition = new Vector3( 0, 0.5f, 0)

this.transform.localPosition = new Vector3( 0, 0.5f, 0)

this.transform.localPosition = new Vector3( 0, 0.5f, 0) 是将当前游戏对象的本地坐标设置为 (0, 0.5, 0)。其中 localPosition 是相对于父物体坐标系的位置,因此将其设置为 (0, 0.5, 0) 会将游戏对象相对于其父物体向上移动 0.5 个单位。

1.2.4 Target.localPosition = new Vector3(Random.value * 8 - 4, 0.5f, Random.value * 8 - 4); }

Target.localPosition = new Vector3(Random.value * 8 - 4, 0.5f, Random.value * 8 - 4);
    }

这行代码的作用是在每个Episode(一次训练周期)开始时将Target的位置设置为一个新的随机位置。具体来说,它使用Random.value生成一个介于0和1之间的随机值,并将其乘以8。然后,从这个结果中减去4,以使得结果介于-4和4之间。这个结果被用作新位置的X和Z坐标,而Y坐标设置为0.5f。因此,这行代码将随机移动目标的位置,从而使智能体必须适应不同的目标位置来完成任务。

2. Observing the Environment

2.1 代码总括

public override void CollectObservations(VectorSensor sensor)
{
    // 目标点和智能体位置
    sensor.AddObservation(Target.localPosition);
    sensor.AddObservation(this.transform.localPosition);

    // 智能体速度
    sensor.AddObservation(rBody.velocity.x);
    sensor.AddObservation(rBody.velocity.z);
}
  • public override void CollectObservations(VectorSensor sensor): 重写了父类 Agent 中的 CollectObservations 方法,该方法用于收集智能体的观测数据VectorSensor 类型的参数 sensor 用于存储观测数据。

  • sensor.AddObservation(Target.localPosition): 将目标点的位置作为一个观测数据添加到 sensor 中。

  • sensor.AddObservation(this.transform.localPosition): 将智能体的位置作为一个观测数据添加到 sensor 中。

  • sensor.AddObservation(rBody.velocity.x): 将智能体在 x 轴方向的速度作为一个观测数据添加到 sensor 中。

  • sensor.AddObservation(rBody.velocity.z): 将智能体在 z 轴方向的速度作为一个观测数据添加到 sensor 中。

2.2 代码分解

2.2.1 public override void CollectObservations(VectorSensor sensor)

public override void CollectObservations(VectorSensor sensor)

public override void CollectObservations(VectorSensor sensor) 是一个重写了父类 Agent 中的 CollectObservations 方法的公共方法。在这个方法中,我们可以定义 Agent 用于学习的所有观察。这些观察将成为 Agent 的状态信息,并用于在训练过程中决策其行动。

VectorSensor sensor 参数是一个用于添加观察的 VectorSensor 实例。

这个方法的主要目的是向传感器添加观察。这个方法的实现可以根据具体的场景和需求而有所不同。

2.2.2 sensor.AddObservation(Target.localPosition)

sensor.AddObservation(Target.localPosition)

这行代码的作用是将 RollerAgent 脚本中定义的 Target(Unity Transform 组件)的本地位置添加到传感器观察中。在使用机器学习代理训练时,传感器负责向代理提供状态信息,这些信息可以是代理需要了解的任何东西,例如环境中其他物体的位置、速度、颜色等等。通过将目标的位置添加到传感器观察中,代理就可以了解到目标的位置。 

2.2.3 sensor.AddObservation(this.transform.localPosition)这一行代码将 

sensor.AddObservation(this.transform.localPosition);

这一行代码将 RollerAgent 自身的位置信息添加到 Sensor 中,具体来说,会将该 Agent 在 x、y、z 轴上的本地坐标分别作为 3 个观测值加入 Sensor 中,以供智能体在后续的训练中学习和使用。 

2.2.4 sensor.AddObservation(rBody.velocity.x)

sensor.AddObservation(rBody.velocity.x)

这一行代码将 RollerAgent 的刚体在 x 轴上的速度信息添加到 Sensor 中,用于作为智能体的观测值。具体来说,它将 RollerAgent 的刚体在 x 轴上的速度值作为一个观测值加入到 Sensor 中,以供智能体在后续的训练中学习和使用。

2.2.5 sensor.AddObservation(rBody.velocity.z)

sensor.AddObservation(rBody.velocity.z)

 这一行代码将 RollerAgent 的刚体在 z 轴上的速度信息添加到 Sensor 中,用于作为智能体的观测值。具体来说,它将 RollerAgent 的刚体在 z 轴上的速度值作为一个观测值加入到 Sensor 中,以供智能体在后续的训练中学习和使用。

3. Taking Actions and Assigning Rewards

3.1 代码总括

public float forceMultiplier = 10; // 添加一个 public 变量 forceMultiplier,用于调节施加的力的倍数
public override void OnActionReceived(ActionBuffers actionBuffers) // Override 基类 Agent 的 OnActionReceived 方法
{
    // Actions, size = 2
    Vector3 controlSignal = Vector3.zero; // 创建一个大小为 0 的 Vector3 变量 controlSignal
    controlSignal.x = actionBuffers.ContinuousActions[0]; // 将连续控制输入的第一个元素赋值给 controlSignal 的 x 分量
    controlSignal.z = actionBuffers.ContinuousActions[1]; // 将连续控制输入的第二个元素赋值给 controlSignal 的 z 分量
    rBody.AddForce(controlSignal * forceMultiplier); // 施加力,乘以 forceMultiplier 调节施加力的大小

    // Rewards
    float distanceToTarget = Vector3.Distance(this.transform.localPosition, Target.localPosition); // 计算 Agent 与 Target 之间的距离

    // Reached target
    if (distanceToTarget < 1.42f) // 如果 Agent 到达了 Target 的范围内(1.42f 是指一个单位立方体的对角线长度)
    {
        SetReward(1.0f); // 奖励 Agent
        EndEpisode(); // 结束 episode
    }

    // Fell off platform
    else if (this.transform.localPosition.y < 0) // 如果 Agent 掉下了平台
    {
        EndEpisode(); // 结束 episode
    }
}

这段代码是 RollerAgent 类的 OnActionReceived 方法,主要是处理智能体的行动和奖励等逻辑。在该方法中,首先解析智能体的行动,将其转换成控制信号,然后通过给定的力量系数将其施加在 RollerAgent 的刚体上。然后,根据智能体距离目标的距离计算奖励。如果智能体到达目标位置,则奖励为 1,并结束该 episode;如果 RollerAgent 掉落出平台,则直接结束该 episode。

为了解决向目标移动的任务,Agent (Sphere)需要能够在x和z方向上移动。因此,代理需要两个动作:第一个决定沿x轴施加的力;第二个决定了作用在z轴上的力。(如果我们允许Agent在三维空间中移动,那么我们就需要第三个动作。)

3.2 代码分解

3.2.1 public float forceMultiplier = 10

public float forceMultiplier = 10

这段代码定义了一个名为forceMultiplier的公共变量,并将其初始化为10。该变量的作用是控制代理施加的力的强度。

3.2.2 public override void OnActionReceived(ActionBuffers actionBuffers)

public override void OnActionReceived(ActionBuffers actionBuffers)

OnActionReceived 是 Agent 类的方法,表示 Agent 接收到一个 action 后需要执行的操作。在这个 RollerAgent 脚本中,它用于接收动作向量,并对其进行处理。

参数 actionBuffers 是一个 ActionBuffers 对象,代表着一个动作向量。此处的动作向量是一个连续的向量,包含两个浮点数,分别表示在 x 轴和 z 轴上的控制力。

因此,该函数的主要功能是对 actionBuffers 进行解析,并将其转化为 controlSignal 控制力,再将该力传递给物理引擎,以使得 RollerAgent 在场景中移动。

3.2.3 controlSignal.x = actionBuffers.ContinuousActions[0]

    Vector3 controlSignal = Vector3.zero; // 创建一个大小为 0 的 Vector3 变量 controlSignal
    controlSignal.x = actionBuffers.ContinuousActions[0]; // 将连续控制输入的第一个元素赋值给 controlSignal 的 x 分量
    controlSignal.z = actionBuffers.ContinuousActions[1]; // 将连续控制输入的第二个元素赋值给 controlSignal 的 z 分量
    rBody.AddForce(controlSignal * forceMultiplier); // 施加力,乘以 forceMultiplier 调节施加力的大小

RollerAgent使用Rigidbody. addforce()将action[]数组中的值应用到它的Rigidbody组件rBody上:

这行代码定义了一个名为controlSignal的Vector3类型变量,初始值为(0,0,0),用于存储代理(Agent)的操作信号

这行代码将第一个连续动作的值设置为控制信号向量controlSignal的x分量。actionBuffers.ContinuousActions[0]获取代理的第一个连续动作的值。在这个RollerBall例子中,代理有两个连续动作,每个动作的值范围在-1到1之间,代表x和z轴上的力量。

这行代码设置了控制信号的z轴分量,它的值从ActionBuffers中获取,index为1,代表模型的前后运动方向。具体来说,模型根据这个分量来决定是向前还是向后运动。

这行代码是将计算出来的控制向量controlSignal乘上一个forceMultiplier系数,然后通过调用AddForce函数对物体施加一个力的作用,从而实现对RollerAgent物体的控制。在这个环境下,RollerAgent物体被控制的目标是移动到一个随机移动的目标位置。

注意,forcMultiplier 类变量是在方法定义之前定义的。因为 forcMultiplier 是公共的,所以您可以设置检查器窗口中的值。

3.2.4 float distanceToTarget = Vector3.Distance(this.transform.localPosition, Target.localPosition)

float distanceToTarget = Vector3.Distance(this.transform.localPosition, Target.localPosition)

这段代码计算当前Agent和目标物体之间的距离,使用的是Vector3.Distance()方法,它返回两个向量之间的欧几里得距离(也称为长度)

具体地说,它使用当前Agent位置this.transform.localPosition和目标物体位置Target.localPosition作为两个向量的参数,计算它们之间的距离,并将结果赋值给变量distanceToTarget

4.问题

4.1 报错

4.1.1 解决报错1

这是在 Testing the Environment 的时候出现的问题,并不是实质意义上的报错,通过方向键可以控制agent,可以实现测试。

Couldn't connect to trainer on port 5004 using API version 1.5.0. Will perform inference instead.
UnityEngine.Debug:Log (object)
Unity.MLAgents.Academy:InitializeEnvironment () (at E:/ml-agents-release_19/com.unity.ml-agents/Runtime/Academy.cs:467)
Unity.MLAgents.Academy:LazyInitialize () (at E:/ml-agents-release_19/com.unity.ml-agents/Runtime/Academy.cs:286)
Unity.MLAgents.Academy:.ctor () (at E:/ml-agents-release_19/com.unity.ml-agents/Runtime/Academy.cs:255)
Unity.MLAgents.Academy/<>c:<.cctor>b__86_0 () (at E:/ml-agents-release_19/com.unity.ml-agents/Runtime/Academy.cs:117)
System.Lazy`1<Unity.MLAgents.Academy>:get_Value ()
Unity.MLAgents.Academy:get_Instance () (at E:/ml-agents-release_19/com.unity.ml-agents/Runtime/Academy.cs:132)
Unity.MLAgents.DecisionRequester:Awake () (at E:/ml-agents-release_19/com.unity.ml-agents/Runtime/DecisionRequester.cs:57)

无法使用 API 版本 1.5.0 连接到端口 5004 上的训练器,将执行推断。在环境上执行 Academy 初始化,创建一个未初始化的单例实例。这是在 Unity.MLAgents.Academy.InitializeEnvironment() 和 Unity.MLAgents.Academy.LazyInitialize() 方法中完成的。在这段代码中,会通过访问 Unity.MLAgents.Academy.Instance 获取单例实例。当 DecisionRequester 对象被唤醒时,会触发 Unity.MLAgents.DecisionRequester.Awake() 方法。

这个错误提示说明 Unity ML-Agents 无法连接到本地端口 5004 的 Trainer,通常这是因为没有正确启动 Trainer。如果你没有启动 Trainer,可以忽略这个错误,Unity ML-Agents 将会自动切换到 Inference 模式,仍然可以在 Unity 中进行 Agent 行为的模拟和可视化。

如果你已经启动了 Trainer,那么请确保 Trainer 的端口号和 Unity 中 Academy 的端口号一致。你可以在 Unity 编辑器中的 ML-Agents 设置中查看 Academy 端口号,并在 Trainer 启动时指定相同的端口号。

4.1.2 解决报错2

[INFO] Listening on port 5004. Start training by pressing the Play button in the Unity Editor.
[INFO] Connected to Unity environment with package version 2.2.1-exp.1 and communication version 1.5.0
Traceback (most recent call last):
  File "D:\RuanJianAnZhunangWeiZhi\anaconda\anaconda3\envs\mlagents\Scripts\mlagents-learn-script.py", line 33, in <module>
    sys.exit(load_entry_point('mlagents', 'console_scripts', 'mlagents-learn')())
  File "e:\ml-agents-release_19\ml-agents\mlagents\trainers\learn.py", line 260, in main
    run_cli(parse_command_line())
  File "e:\ml-agents-release_19\ml-agents\mlagents\trainers\learn.py", line 256, in run_cli
    run_training(run_seed, options, num_areas)
  File "e:\ml-agents-release_19\ml-agents\mlagents\trainers\learn.py", line 132, in run_training
    tc.start_learning(env_manager)
  File "e:\ml-agents-release_19\ml-agents-envs\mlagents_envs\timers.py", line 305, in wrapped
    return func(*args, **kwargs)
  File "e:\ml-agents-release_19\ml-agents\mlagents\trainers\trainer_controller.py", line 173, in start_learning
    self._reset_env(env_manager)
  File "e:\ml-agents-release_19\ml-agents-envs\mlagents_envs\timers.py", line 305, in wrapped
    return func(*args, **kwargs)
  File "e:\ml-agents-release_19\ml-agents\mlagents\trainers\trainer_controller.py", line 105, in _reset_env
    env_manager.reset(config=new_config)
  File "e:\ml-agents-release_19\ml-agents\mlagents\trainers\env_manager.py", line 68, in reset
    self.first_step_infos = self._reset_env(config)
  File "e:\ml-agents-release_19\ml-agents\mlagents\trainers\subprocess_env_manager.py", line 446, in _reset_env
    ew.previous_step = EnvironmentStep(ew.recv().payload, ew.worker_id, {}, {})
  File "e:\ml-agents-release_19\ml-agents\mlagents\trainers\subprocess_env_manager.py", line 101, in recv
    raise env_exception
mlagents_envs.exception.UnityTimeOutException: The Unity environment took too long to respond. Make sure that :
         The environment does not need user interaction to launch
         The Agents' Behavior Parameters > Behavior Type is set to "Default"
         The environment and the Python interface have compatible versions.
         If you're running on a headless server without graphics support, turn off display by either passing --no-graphics option or build your Unity executable as server build.

这个错误信息表明 Unity 环境没有响应,可能是因为以下原因之一:

  • 确保环境不需要用户交互才能启动。
  • 确保代理的行为参数 > 行为类型设置为 "Default"。
  • 确保环境和 Python 接口版本兼容。
  • 如果您正在运行无图形支持的无头服务器,请通过传递 --no-graphics 选项或构建 Unity 可执行文件作为服务器构建来关闭显示。

 解决方式就是错误原因的第二点,确保代理的行为参数 > 行为类型设置为 "Default"。

是因为在测试的时候,将Behavior Type 设置成了Heuristic Only(仅启用启发式),训练时需要设置成default。


http://www.niftyadmin.cn/n/248368.html

相关文章

vuepress-yarn-nodes-静态网页_个人博客搭建

nodes官网&#xff1a;https://nodejs.org/en 先下载nodes进行安装&#xff0c;一般nodes会自带包管理器npm&#xff0c;注意npm与nodes的对应关系&#xff0c;除了npm之外还有yarn包管理器&#xff0c;一般会用npm安装这个包 npm install --global yarnnpm降低版本的方法 np…

NC65 集团业务参数 GLS01参数值的默认值作用是什么?

NC65 集团业务参数 GLS01参数值的默认值作用是什么&#xff1f; 用在总账系统的所有账簿。如果设置的期间个数大于12&#xff0c;还得要求所查询的账表支持跨年查询&#xff0c;比如科目余额表&#xff0c;不支持跨年&#xff08;注意&#xff1a;这里说的不支持跨年是指余额为…

成都建博会:家居行业数字营销金点子 句句戳心坎,先收藏

四月&#xff0c;不仅是人间最美天&#xff0c;也是第二季度的开始。随着气温上升&#xff0c;行业进入了活跃期。对于西南地区的家居行业从业者来说&#xff0c;来一趟一年一度的成都建博会&#xff0c;总能获得无尽的灵感&#xff0c;对后续更加充满期待。而与同行的交流&…

java-word模板转化为pdf

文章目录 一、引入包1.1在pom引入1.2 因为我们的项目是打包成jar,所以以上方法在本地idea运行没有问题&#xff0c;linux系统不行1.2.1解决方法11.2.2解决方法2 二、配置文件--License.xml--去除水印2.1 license.xml直接放到resources的根目录下即可2.2 工具类 三、调用效果 一…

NumberPicker分析(三)

NumberPicker分析(三) 这一节主要用来分析NumberPicker的事件处理及滚动 NumberPicker继承自LinearLayout&#xff0c;是一个ViewGroup&#xff0c;ViewGroup事件处理的顺序大致如下&#xff1a; dispatchTouchEventonInterceptTouchEventonTouchEvent 另外&#xff0c;源码中…

JSon使用

官方文档 JSon在线文档&#xff1a;https://www.w3school.com.cn/js/js_json_intro.asp Ajax在线文档&#xff1a;https://www.w3school.com.cn/js/js_ajax_intro.asp Json介绍 Json快速入门 <!DOCTYPE html> <html lang"en"> <head><meta c…

C#串口通信从入门到精通(2)——串口相关参数介绍

1、端口号&#xff08;Port&#xff09; 我们使用一个串口的时候&#xff0c;首先是要打开这个串口&#xff0c;那么我们怎么知道电脑上现在支持几个串口呢&#xff1f;对应的端口号又是什么呢&#xff1f; 由于我的电脑系统是window11&#xff0c;下面就以window11为例介绍如…

wagon-maven-plugin 实现远程部署知识回顾

背景 记录 maven 的 wagon-plugin 自动部署插件的两个问题点&#xff1a; 远程主机密码中有特殊字符 直接在 url 路径的 scp 命令中写帐号密码识别不了的问题。执行 Java 命令报 java: command not found 的问题。commands 命令集合中&#xff0c;多个 command 之间开启的是…