Unity-ML-Agents--Learning-Environment-Design-Agents.md-代码解读(2)

代码来源:https://github.com/Unity-Technologies/ml-agents/blob/release_19/docs/Learning-Environment-Design-Agents.md

目录

1. Normalization

1.1 代码解析

1.2 问题

1.2.1 Quaternion类型

1.2.2 normalizedValue 和 Vector3 normalized 的区别?

2.Continuous Actions

2.1 代码解析

2.2 代码分解

2.2.1 OnActionReceived()

2.2.2 var actionZ = 2f * Mathf.Clamp(actionBuffers.ContinuousActions[0], -1f, 1f)

2.2.3 gameObject.transform.Rotate(new Vector3(0, 0, 1), actionZ)

3.Discrete Actions

3.1 代码解析

3.2 代码分解

3.2.1 int movement = actionBuffers.DiscreteActions[0]

3.2.2 int jump = actionBuffers.DiscreteActions[1]

4.Masking Discrete Actions

4.1 代码解析

5.Rewards

5.1 GridWorld

5.1.1 Collider[] hitObjects = Physics.OverlapBox(trueAgent.transform.position,new Vector3(0.3f, 0.3f, 0.3f))

5.1.2 if (hitObjects.Where(col => col.gameObject.tag == "goal").ToArray().Length == 1)

5.1.3 AddReward(1.0f)

5.1.4 else if (hitObjects.Where(col => col.gameObject.tag == "pit").ToArray().Length == 1)

5.2 Push Block

5.3 3DBall: 3D Balance Ball

5.3.1 Mathf.Abs(ball.transform.position.x - gameObject.transform.position.x) > 3f

5.3.2 Rewards Summary

6.Agent Properties

6.1 Stacked Vectors

6.2 Behavior Type

6.3 Team ID

7.Defining Multi-agent Scenarios

7.1 Teams for Adversarial Scenarios

7.2 Groups for Cooperative Scenarios

7.2.1 m_AgentGroup = new SimpleMultiAgentGroup()

7.2.2 m_AgentGroup.RegisterAgent(agent)

7.2.3 m_AgentGroup.AddGroupReward(rewardForGoal)

7.2.4 m_AgentGroup.EndGroupEpisode()


1. Normalization

1.1 代码解析

normalizedValue = (currentValue - minValue)/(maxValue - minValue)

normalizedValue 表示经过归一化处理的值,其取值范围在 0 到 1 之间,表示原始值 currentValue 在最小值 minValue 和最大值 maxValue 之间所处的相对位置。具体计算公式为 (currentValue - minValue) / (maxValue - minValue)。这种处理常用于数据标准化或者让算法更易于处理的情况。

Quaternion rotation = transform.rotation;
Vector3 normalized = rotation.eulerAngles / 180.0f - Vector3.one;  // [-1,1]
Vector3 normalized = rotation.eulerAngles / 360.0f;  // [0,1]

这段代码是对物体的旋转角度进行归一化处理,使得其范围在[-1,1]或[0,1]之间,方便后续神经网络模型的训练。

首先获取物体的旋转角度,即Quaternion类型的rotation,然后将其转换为Vector3类型的欧拉角,即rotation.eulerAngles。在将欧拉角进行归一化处理前,根据具体需要选择对其范围进行缩放。第一种方式的缩放系数为180.0f,第二种方式的缩放系数为360.0f。最后通过减去Vector3.one或直接除以1.0f,使得范围在[-1,1]或[0,1]之间。

因为 rotation.eulerAngles 返回的是一个 Vector3,其每个分量代表对应轴的旋转角度,单位为度。当除以 180 时,结果范围是 0 到 2(因为 0 度和 360 度表示同一方向,因此要排除这种情况),减去 Vector3.one 后结果范围变成了 -1 到 1。而当除以 360 时,结果范围是 0 到 1。

1.2 问题

1.2.1 Quaternion类型

Quaternion 是 Unity 引擎中用来表示旋转的结构体类型,它包含四个浮点数 x、y、z 和 w,分别表示旋转轴和旋转角度。它可以被用于旋转游戏对象的变换组件中,也可以被用于描述物理系统中的角动量。在机器学习领域,Quaternion 常常用于在智能体的观察中编码游戏对象的旋转状态。

1.2.2 normalizedValue 和 Vector3 normalized 的区别?

normalizedValue 是指将某个变量的值进行归一化后的结果,通常将变量的值映射到某个指定的范围内,例如将一个数值型变量从最小值到最大值的范围映射到0到1的范围内。在这个过程中,最小值对应的值为0,最大值对应的值为1,其他值则通过线性插值得到。

归一化的目的通常是为了将不同尺度的变量放在同一个量级下进行比较或者处理。

Vector3 normalized 则是将欧拉角(三维旋转)转换为一个向量,这个向量中的每个分量都是将欧拉角中的对应分量除以360得到的。这样做的目的通常是将欧拉角表示的旋转转换为神经网络可以理解和处理的数值Vector3.normalized 是一个用于将向量归一化的方法,即将向量的模(magnitude)变为 1,方向不变。这个方法可以用于任意的向量,不仅仅是欧拉角,比如空间中的位置向量、速度向量、加速度向量等等。

2.Continuous Actions

2.1 代码解析

public override void OnActionReceived(ActionBuffers actionBuffers)
{
    // 将第一个动作维度值映射到 [-2, 2] 的范围内 从连续的动作缓冲区中获取动作 Z
    var actionZ = 2f * Mathf.Clamp(actionBuffers.ContinuousActions[0], -1f, 1f);
    // 将第二个动作维度值映射到 [-2, 2] 的范围内 从连续的动作缓冲区中获取动作 X
    var actionX = 2f * Mathf.Clamp(actionBuffers.ContinuousActions[1], -1f, 1f);

    // 绕 z 轴旋转(左右)
    gameObject.transform.Rotate(new Vector3(0, 0, 1), actionZ);
    // 绕 x 轴旋转(上下)
    gameObject.transform.Rotate(new Vector3(1, 0, 0), actionX);
}

在这段代码中,OnActionReceived() 函数接收两个 float 类型的连续动作值,并将其分别作为绕 z 轴和 x 轴旋转的角度应用到当前游戏对象的变换组件上。具体来说,将绕 z 轴旋转的角度值(actionZ)映射到区间 [-2,2] 上,并乘以旋转轴 (0,0,1),将绕 x 轴旋转的角度值(actionX)映射到区间 [-2,2] 上,并乘以旋转轴 (1,0,0)。然后使用 gameObject.transform.Rotate 方法将这两个角度值作为参数,以对应的旋转轴为轴心进行旋转。

2.2 代码分解

2.2.1 OnActionReceived()

OnActionReceived()Agent 类中的一个函数,用于接收来自于神经网络输出的操作指令,即将神经网络输出的动作应用到智能体的状态中。

Unity ML-Agents 中,智能体通过一组状态(状态向量)描述自身环境中的情况。通过执行动作(action),智能体能够更改自身的状态,从而实现与环境的交互。当神经网络计算出下一步的动作后,这个动作将会被传递到 OnActionReceived() 函数,函数内部会根据这个动作更新智能体的状态,然后将新的状态传递给神经网络作为下一个决策的输入。

在这段代码中,OnActionReceived() 函数接收两个 float 类型的连续动作值,并将其分别作为绕 z 轴和 x 轴旋转的角度应用到当前游戏对象的变换组件上。具体来说,将绕 z 轴旋转的角度值(actionZ)映射到区间 [-2,2] 上,并乘以旋转轴 (0,0,1),将绕 x 轴旋转的角度值(actionX)映射到区间 [-2,2] 上,并乘以旋转轴 (1,0,0)。然后使用 gameObject.transform.Rotate 方法将这两个角度值作为参数,以对应的旋转轴为轴心进行旋转。

2.2.2 var actionZ = 2f * Mathf.Clamp(actionBuffers.ContinuousActions[0], -1f, 1f)

var actionZ = 2f * Mathf.Clamp(actionBuffers.ContinuousActions[0], -1f, 1f);

这一行代码是从actionBuffers获取到当前Agent应该执行的action,并且进行一些处理。在这里,它通过访问actionBuffers中的第一个连续(Continuous)动作(action)并将其限制在-1到1之间。然后将这个值乘以2,从而将其映射到-2到2的范围内。这个值代表着绕z轴旋转的角度

问:Mathf.Clamp()函数

Mathf.Clamp() 是一个 Unity 引擎中的数学函数,用于将输入值限制在指定的范围内。它的声明如下:

public static float Clamp(float value, float min, float max);

其中,value 表示要被限制的值,min 表示最小值,max 表示最大值。函数的返回值为限制后的结果,即在 [min, max] 范围内的 value,如果 value 小于 min,返回 min;如果 value 大于 max,返回 max

问:actionBuffers.ContinuousActions

actionBuffers.ContinuousActions 是一个包含所有连续动作的数组该数组的长度等于动作空间中连续动作的数量。这些值是由智能体的决策策略输出的,它们表示智能体将执行的具体动作。在 OnActionReceived() 函数中,这些动作被提取并用于更新智能体的状态和环境。

2.2.3 gameObject.transform.Rotate(new Vector3(0, 0, 1), actionZ)

 gameObject.transform.Rotate(new Vector3(0, 0, 1), actionZ);

这行代码的作用是将游戏对象(game object)绕着 Z 轴旋转。参数中的 new Vector3(0, 0, 1) 表示沿着 Z 轴旋转,而 actionZ 表示旋转的角度。具体来说,actionZ 是从 agent 接收的动作,它是一个在 [-1, 1] 范围内的值,通过 2f * Mathf.Clamp(actionBuffers.ContinuousActions[0], -1f, 1f) 将其转换为 [-2, 2] 范围内的值,然后作为旋转的角度。因此,这行代码的作用是让游戏对象绕着 Z 轴旋转一个 [-2, 2] 范围内的角度。

问:new Vector3(0, 0, 1) ?

new Vector3(0, 0, 1) 表示一个三维向量,x轴和y轴的分量为0,z轴的分量为1,即表示沿着z轴的方向。在这里用它作为旋转的轴,表示以z轴为中心旋转。

3.Discrete Actions

3.1 代码解析

// 从ActionBuffers中获取移动和跳跃动作的索引
int movement = actionBuffers.DiscreteActions[0];
int jump = actionBuffers.DiscreteActions[1];

// 根据索引查找对应的动作
if (movement == 1) { directionX = -1; } // 向左移动
if (movement == 2) { directionX = 1; } // 向右移动
if (movement == 3) { directionZ = -1; } // 向下移动
if (movement == 4) { directionZ = 1; } // 向上移动
if (jump == 1 && IsGrounded()) { directionY = 1; } // 跳跃

// 根据动作的结果移动Agent
gameObject.GetComponent<Rigidbody>().AddForce(
new Vector3(
directionX * 40f, directionY * 300f, directionZ * 40f)); // 朝指定方向施加力

这段代码首先从 DiscreteActions 数组中获取了两个离散动作的索引movementjump。然后根据这两个动作索引的值来确定代理应该执行的动作。

具体地,

如果 movement 的值是 1,说明代理应该向左移动,设置 directionX = -1

如果 movement 的值是 2,说明代理应该向右移动,设置 directionX = 1

如果 movement 的值是 3,说明代理应该向下移动,设置 directionZ = -1

如果 movement 的值是 4,说明代理应该向上移动,设置 directionZ = 1

接下来,如果 jump 的值是 1 并且代理当前处于地面上,说明代理应该执行跳跃操作,设置 directionY = 1

最后,根据这些方向变量的值来更新代理的运动状态。在这段代码中,通过 AddForce() 方法来为代理应用作用力,具体来说,AddForce() 方法的参数是一个 Vector3 向量,分别代表 x、y 和 z 方向上的作用力。这个向量的值根据方向变量的值来确定,其中 directionXdirectionZ 分别对应向左/右和向下/上的移动,directionY 对应跳跃。

3.2 代码分解

3.2.1 int movement = actionBuffers.DiscreteActions[0]

int movement = actionBuffers.DiscreteActions[0]

这行代码从Agent传递的离散动作(Action)中获取一个代表移动方向的整数。这个整数用来索引在动作空间(Action Space)中定义的移动动作列表。动作列表中的每个动作都有一个唯一的整数索引,这个整数由Unity ML Agents框架分配并传递给Agent,以表示Agent在该步骤中执行哪个动作。通过获取整数索引,Agent可以映射到对应的移动动作,从而移动自己的位置。

3.2.2 int jump = actionBuffers.DiscreteActions[1]

int jump = actionBuffers.DiscreteActions[1]

这行代码的作用是从接收到的actionBuffers中获取跳跃行为的离散值。在Unity ML-Agent中,离散动作使用整数来表示不同的离散动作,代表每个可能的离散动作的整数都被分配一个索引。在这个例子中,jump变量存储的是离散动作索引的值,用来代表是否执行跳跃操作。

4.Masking Discrete Actions

4.1 代码解析

public override void WriteDiscreteActionMask(IDiscreteActionMask actionMask)
{
    actionMask.SetActionEnabled(branch, actionIndex, isEnabled);
}

这段代码是一个Unity ML-Agent的函数,用于设置决策阶段的动作掩码,其中:

  • branch:表示动作空间的分支索引,一般情况下只有一个分支,取值为0。
  • actionIndex:表示动作空间中一个动作的索引
  • isEnabled:表示动作是否启用,如果启用则为true,否则为false。

该函数的作用是设置某个动作是否可用。在训练模型时,可能需要限制动作的选择,例如在某个状态下只允许普通攻击,不允许使用技能。这时可以通过设置动作掩码来实现这个功能。如果某个动作不可用,智能体在做出决策时就不会选择这个动作。

示例:

actionMask.SetActionEnabled(0, 1, false);
actionMask.SetActionEnabled(0, 2, false);

actionMask.SetActionEnabled(branch, actionIndex, isEnabled);方法用于禁用或启用智能体的离散动作空间中的特定动作。其中,branch是动作空间中的分支索引,actionIndex是动作索引,isEnabled是布尔值,表示是否启用该动作。

在这个例子中,actionMask.SetActionEnabled(0, 1, false);禁用了动作空间中的第一个分支的第二个动作,actionMask.SetActionEnabled(0, 2, false);禁用了动作空间中的第一个分支的第三个动作。

5.Rewards

5.1 GridWorld

agent在达到目标时得到正奖励,在掉入坑时得到负奖励。否则,它将得不到任何奖励。这是一个稀疏奖励系统的例子。代理必须进行大量探索才能找到不常见的奖励。

Collider[] hitObjects = Physics.OverlapBox(trueAgent.transform.position,
                                           new Vector3(0.3f, 0.3f, 0.3f));
// 获取与真实 Agent 碰撞的物体
if (hitObjects.Where(col => col.gameObject.tag == "goal").ToArray().Length == 1)
{
    AddReward(1.0f);  // 如果碰到了目标,则奖励值为 1
    EndEpisode();  // 重置场景
}
else if (hitObjects.Where(col => col.gameObject.tag == "pit").ToArray().Length == 1)
{
    AddReward(-1f);  // 如果碰到了陷阱,则奖励值为 -1
    EndEpisode();  // 重置场景
}

这段代码检测了trueAgent周围是否有碰撞体,如果有,再通过标签判断是goal还是pit。如果碰到了goal,则给智能体一个正的奖励并结束episode;如果碰到了pit,则给智能体一个负的奖励并结束episode。

具体解释如下:

  • Collider[] hitObjects = Physics.OverlapBox(trueAgent.transform.position, new Vector3(0.3f, 0.3f, 0.3f)):检测trueAgent周围是否有碰撞体。OverlapBox是一个物理API,它可以检测一个指定区域内的碰撞体。这里使用trueAgent的位置作为检测区域的中心,大小为(0.3,0.3,0.3)
  • hitObjects.Where(col => col.gameObject.tag == "goal").ToArray().Length == 1:检测hitObjects数组中标签为“goal”的GameObject的数量是否为1。这里使用了Linq库中的Where函数来过滤hitObjects数组,只保留标签为“goal”的GameObject,然后使用ToArray()将其转换为数组,最后通过Length属性得到数组长度
  • AddReward(1.0f); EndEpisode():如果碰到了goal,则给智能体一个正的奖励并结束episode。AddReward是一个ML-Agents的API,可以给智能体添加奖励,这里给的是一个1.0f的正奖励;EndEpisode则是结束episode的函数。
  • hitObjects.Where(col => col.gameObject.tag == "pit").ToArray().Length == 1:检测hitObjects数组中标签为“pit”的GameObject的数量是否为1。
  • AddReward(-1f); EndEpisode():如果碰到了pit,则给智能体一个负的奖励并结束episode。这里给的是一个-1.0f的负奖励。

5.1.1 Collider[] hitObjects = Physics.OverlapBox(trueAgent.transform.position,new Vector3(0.3f, 0.3f, 0.3f))

Collider[] hitObjects = Physics.OverlapBox(trueAgent.transform.position,new Vector3(0.3f, 0.3f, 0.3f));

这行代码是在场景中以 trueAgent 的当前位置为中心创建了一个长、宽、高均为 0.3 的立方体盒子,然后使用 Physics.OverlapBox 方法检测这个盒子内是否有其他的碰撞体(Collider),将结果存储在 hitObjects 数组中。这个方法的返回值是所有与这个盒子相交的碰撞体的数组。

问:Physics.OverlapBox ?

Physics.OverlapBox 是一个用于在场景中检测碰撞的函数。它会返回一个数组,包含与指定的盒子形状相交的所有碰撞体。函数需要传递两个参数:盒子的中心点和半径。在这里,我们使用 trueAgent 的位置作为盒子的中心,盒子大小为 (0.3, 0.3, 0.3)。这将返回与真实智能体发生碰撞的所有碰撞体。

5.1.2 if (hitObjects.Where(col => col.gameObject.tag == "goal").ToArray().Length == 1)

if (hitObjects.Where(col => col.gameObject.tag == "goal").ToArray().Length == 1)

这段代码是在检测与AI代理发生碰撞的物体中是否有 tag 为 "goal" 的物体。具体来说,先使用 LINQ 中的 Where 方法筛选出所有 tag 为 "goal" 的物体,然后通过 ToArray 转换为数组,最后使用 Length 属性判断数组长度是否为 1,如果是,则说明只有一个 tag 为 "goal" 的物体与 AI 代理发生了碰撞。

5.1.3 AddReward(1.0f)

AddReward(1.0f);  // 如果碰到了目标,则奖励值为 1
EndEpisode();  // 重置场景

这行代码表示如果碰到了目标,则奖励值为1,然后结束 episode,也就是重置场景,开始下一轮训练。这是在 Unity ML-Agent 框架中用于 RL 的 API。AddReward 用于在每次 step 中向智能体添加奖励,EndEpisode 用于在智能体达到目标或失败时结束当前的 episode。

5.1.4 else if (hitObjects.Where(col => col.gameObject.tag == "pit").ToArray().Length == 1)

else if (hitObjects.Where(col => col.gameObject.tag == "pit").ToArray().Length == 1)

这段代码判断是否有物体碰撞到了名为 "pit" 的标签,并且如果有的话,则触发一系列操作,具体来说:

  • hitObjects.Where(col => col.gameObject.tag == "pit") 返回所有碰撞到的物体中,其标签为 "pit" 的部分。
  • ToArray() 将这个物体数组转换为 col[] 类型的数组
  • Length 计算这个数组的长度(即物体的数量)
  • 如果数组长度为 1,则说明真正的物体被碰到了,此时奖励值为 -1,并且场景被重置。

问:hitObjects.Where() ?

hitObjects.Where 是 Linq 库提供的函数之一,用于在集合中筛选出满足条件的元素并返回一个新的集合。这个函数需要传入一个 lambda 表达式作为参数,lambda 表达式的参数就是集合中的每一个元素,返回值是一个 bool 类型,表示该元素是否满足条件。

问:col => col.gameObject.tag == "pit" ?

这段代码使用了Lambda表达式,可以将其理解为一个匿名函数。在这里,col => col.gameObject.tag == "pit" 表示接收一个参数 col,并检查这个参数所对应的GameObject组件的tag是否为"pit"。其中 => 是Lambda表达式的语法结构,它可以读作“goes to”。Lambda表达式通常用于函数式编程的场景,可以方便地定义并传递函数。

5.2 Push Block

Agent每一步都得到一个小的负奖励。为了获得最大奖励,agent必须尽快完成到达目标方格任务:

// 在每一步结束时,惩罚智能体 -0.005f 的奖励值
AddReward(-0.005f);
// 使智能体按照给定的动作进行移动
MoveAgent(act);

// 如果智能体掉入了水中或者超出了区域范围,进行以下操作
if (gameObject.transform.position.y < 0.0f ||
Mathf.Abs(gameObject.transform.position.x - area.transform.position.x) > 8f ||
Mathf.Abs(gameObject.transform.position.z + 5 - area.transform.position.z) > 8)
{
// 对智能体进行 -1 的惩罚,并且重置场景
AddReward(-1f);
EndEpisode();
}

5.3 3DBall: 3D Balance Ball

// 奖励智能体
SetReward(0.1f);

// 如果球掉落,将智能体标记为结束状态,并给予负面惩罚
if ((ball.transform.position.y - gameObject.transform.position.y) < -2f ||
Mathf.Abs(ball.transform.position.x - gameObject.transform.position.x) > 3f ||
Mathf.Abs(ball.transform.position.z - gameObject.transform.position.z) > 3f)
{
SetReward(-1f);
EndEpisode();
}

5.3.1 Mathf.Abs(ball.transform.position.x - gameObject.transform.position.x) > 3f

Mathf.Abs(ball.transform.position.x - gameObject.transform.position.x) > 3f 

这行代码的作用是判断球和代理之间的水平距离是否超过了3个单位,如果超过了,就会执行一个负的奖励和结束该episode的操作。

具体地,Mathf.Abs(ball.transform.position.x - gameObject.transform.position.x) 计算了球和代理之间在x轴方向上的距离,并取它的绝对值。然后,这个距离与3进行比较,如果大于3,就说明球和代理之间的距离超过了允许的范围,就会执行负奖励和结束该episode的操作。

5.3.2 Rewards Summary

使用AddReward()在决策之间累积奖励。使用SetReward()覆盖在决策之间累积的任何先前奖励
为了确保更稳定的学习过程,任何给定奖励的大小通常都不应大于1.0
积极的奖励通常比消极的奖励更有助于塑造代理人的期望行为。过多的负面奖励会导致代理无法学习任何有意义的行为。
对于移动任务,通常会对前进速度给予一个小的正奖励(+0.1)。
如果您希望代理快速完成任务,那么在代理没有完成任务的每一步(-0.05)提供一个小的惩罚通常是有帮助的。在这种情况下,任务的完成也应该与情节的结束相一致,在代理完成其目标时调用EndEpisode()。

问:SetReward()覆盖在决策之间累积的任何先前奖励? 怎么理解?

在Unity ML-Agents中,智能体的决策过程是基于策略网络输出的行为概率,通过对行为概率的采样来选择实际执行的行为,然后计算这个行为带来的奖励,从而训练策略网络。在一个 episode 中,智能体会不断地进行上述决策和行为执行的过程每次执行行为并获得奖励后,都会在智能体的累积奖励值上加上这个奖励值

当调用SetReward()函数时,它会覆盖在累积奖励值中之前所计算的任何奖励值,以设置新的奖励值。这意味着如果在 episode 的某个时刻调用SetReward()函数,它将会覆盖之前所有行为所带来的奖励值,因此,累积奖励值将会变为设置的新奖励值。所以,在累积奖励值的计算中,SetReward()的调用时机是非常重要的,它会影响策略网络的训练和智能体的决策。

在使用强化学习算法时,通常会给一个智能体在执行某个动作后奖励一定的分数。这个分数可以理解为是在执行这个动作后智能体对环境的影响。如果智能体的行动有利于完成任务,那么就给予正的奖励;如果不利于任务的完成,就给予负的奖励。如果智能体不做任何事情,就没有任何奖励。

在Unity ML-Agents中,使用AddReward()函数来为智能体增加奖励。在这个函数被调用时,会把这个奖励值累加到先前的奖励值上。这样,每次执行一个动作后,智能体就能够在之前的动作基础上增加相应的奖励值。这个奖励值的积累可以影响智能体的训练过程和最终的决策。

SetReward()函数则会覆盖之前的奖励值,即把当前的奖励值设置为新的值,而不是在之前的基础上累加。因此,每次调用SetReward()函数后,之前累积的奖励值都会被覆盖。

6.Agent Properties

6.1 Stacked Vectors

Stacked Vectors - The number of previous vector observations that will be stacked and used collectively for decision making. This results in the effective size of the vector observation being passed to the Policy being: Space Size x Stacked Vectors.

Stacked Vectors是指在决策时,将前几个时间步的观测数据进行堆叠,形成一个更大的向量作为网络输入。该参数指定要堆叠的历史观测向量数。例如,如果Stacked Vectors为2,则在每个时间步中,当前观测向量和上一个时间步的观测向量将被堆叠在一起,形成一个长度为2的向量。这样可以使智能体在做出决策时同时考虑多个时间步的信息,更好地捕捉状态之间的动态变化和趋势,从而提高智能体的性能。Stacked Vectors的值越大,向量的长度就越大,模型也会变得更加复杂。决策网络的输入向量大小等于状态空间大小(即Vector Observation space中的变量数)乘以Stacked Vectors。

6.2 Behavior Type

  • Inference Only - the Agent will always perform inference.

Inference是机器学习中一种使用训练好的模型对新数据进行预测或分类的过程。在这个场景中,"perform inference"的意思是Agent只会使用已经训练好的模型,而不会进行任何的训练。也就是说,Agent只会进行推断,根据已有的知识来做出决策,而不会再进行学习。

  • Heuristic Only - the Agent will always use the Heuristic() method.

Heuristic() 方法是指在强化学习中,一种基于规则或经验的决策方法。当 Agent 被设置为“仅启发式方法”时,它将始终使用此方法作为其行为策略。在这种情况下,Agent 将不会接受任何来自外部环境的观察和奖励信息,而是将根据其启发式方法进行动作选择。一般而言,这种方法是一种简单的“手工设计”的策略,可能不具备在复杂环境中进行智能决策所需的复杂度和灵活性。

当使用 "Heuristic Only" 模式时,代理程序将忽略神经网络模型,而是直接使用 "Heuristic()" 方法来决定每一步的行动。这意味着您可以手动编写一个简单的算法来控制代理的行动,而不需要训练神经网络。这在调试和测试模型时非常有用,因为您可以随时查看代理程序的行为,而不必等待训练完成。但是,这种方法也存在一些限制,因为它可能无法探索所有可能的策略,并且通常比使用深度强化学习训练的代理程序的性能差。

  • Default - the Agent will train if they connect to a python trainer, otherwise they will perform inference.

在 Unity ML-Agents 中,Default 是默认的 Agent 行为模式,它根据 Agent 是否与 Python Trainer 相连来判断 Agent 的操作模式。如果 Agent 与 Python Trainer 相连,则会进行训练;否则,将执行推断(inference)操作。推断是指 Agent 将使用训练好的模型进行预测并采取行动,而不会在此过程中更新模型的权重。在 Default 模式下,如果 Agent 未与 Trainer 相连,那么它将仅仅使用模型进行推断操作。

6.3 Team ID

  • Team ID - Used to define the team for self-play

"Team ID"是一种用于为自我对战场景定义团队的属性。在某些自我对战场景中,Agent可能会同时扮演不同团队的角色,此时每个团队需要有自己独立的策略和行动。通过指定Team ID,可以使每个Agent只关注其所在的团队,并与同一团队中的其他Agent协同工作,以实现团队的最优化。同时,也可以确保不同团队之间的行动独立性,避免混淆不同团队的行为。

7.Defining Multi-agent Scenarios

7.1 Teams for Adversarial Scenarios

问:symmetric game 和 asymmetric games?

对称博弈是指参与博弈的每个玩家的可选行动集合完全相同,并且每个玩家的利益相同,例如象棋、翻硬币等。在这种情况下,每个玩家的策略可以相同,因为它们在游戏中的位置是对称的。

非对称博弈则是指参与博弈的每个玩家的可选行动集合不同,或者每个玩家的利益不同,例如囚徒困境、扑克牌等。在这种情况下,每个玩家的策略通常是不同的,因为它们的行动和利益不对称。

7.2 Groups for Cooperative Scenarios

// 在Start()或Initialize()中创建一个多智能体组
m_AgentGroup = new SimpleMultiAgentGroup();

// 在每个 episode 开始时注册代理到智能体组中
for (var agent in AgentList)
{
  m_AgentGroup.RegisterAgent(agent);
}

// 如果团队得分了,为整个团队添加奖励
m_AgentGroup.AddGroupReward(rewardForGoal);

// 如果达到目标并结束 episode
m_AgentGroup.EndGroupEpisode();
ResetScene();

// 如果时间耗尽,需要中断 episode
m_AgentGroup.GroupEpisodeInterrupted();
ResetScene();

在开始时,通过实例化SimpleMultiAgentGroup来创建智能体组,然后在每个episode开始时,将所有智能体注册到组中。在episode中,如果团队得分,可以通过调用AddGroupReward()函数来给整个团队奖励。当episode结束时,可以使用EndGroupEpisode()函数结束整个组的episode,并通过ResetScene()函数重置场景,以便下一个episode的开始。如果episode在预期时间内未能完成,可以通过调用GroupEpisodeInterrupted()函数中断episode,并通过ResetScene()函数重置场景以便重新开始。

7.2.1 m_AgentGroup = new SimpleMultiAgentGroup()

m_AgentGroup = new SimpleMultiAgentGroup();

这段代码创建了一个名为m_AgentGroupSimpleMultiAgentGroup对象,它是一个用于管理多个智能体的类。SimpleMultiAgentGroup类提供了许多有用的方法,以方便我们管理组中所有智能体的奖励和行为。

在这个例子中,我们创建了一个SimpleMultiAgentGroup对象,并在每个新的episode开始时将所有代理注册到该组中。这允许我们跟踪每个代理在团队中的表现,并在所有代理中共享奖励。

例如,如果团队达到了一个目标,我们可以使用m_AgentGroup.AddGroupReward()方法向所有代理分配奖励。同样,当所有代理完成一个episode时,我们可以使用m_AgentGroup.EndGroupEpisode()方法来结束该episode,并在重新设置场景之前对所有代理进行任何必要的清理操作。如果在episode执行期间发生意外中断,我们可以使用m_AgentGroup.GroupEpisodeInterrupted()方法来停止episode的执行并进行清理。

7.2.2 m_AgentGroup.RegisterAgent(agent)

m_AgentGroup.RegisterAgent(agent)

m_AgentGroup.RegisterAgent(agent)是将智能体(agent)注册到多智能体组(multi-agent group)中,以便组内的所有智能体可以共享信息,并且在组内协同工作。在这个例子中,智能体列表中的每个智能体都被注册到m_AgentGroup中。这样,这些智能体就可以共享一些状态和信息,并且可以通过m_AgentGroup实例来控制整个组的奖励和结束。

7.2.3 m_AgentGroup.AddGroupReward(rewardForGoal)

m_AgentGroup.AddGroupReward(rewardForGoal)

m_AgentGroup.AddGroupReward(rewardForGoal) 是在多智能体场景中给整个智能体组添加奖励的方法。在多智能体场景中,一个团队或组中的所有智能体共享相同的奖励,因此当团队或组达到某个目标时,需要给整个团队或组添加奖励。在这种情况下,可以使用 AddGroupReward() 方法将奖励添加到整个智能体组中。rewardForGoal 是获得目标的奖励值,可以根据具体场景进行调整。

7.2.4 m_AgentGroup.EndGroupEpisode()

m_AgentGroup.EndGroupEpisode()

m_AgentGroup.EndGroupEpisode()方法用于在组内的所有代理完成一次完整的回合(episode)后,结束当前组回合并进行重置操作。该方法应该在所有代理完成一个完整的回合后被调用,以通知组结束当前回合并准备下一个回合。

在调用该方法之后,通常需要调用ResetScene()方法来重置环境并准备下一个回合。如果在调用EndGroupEpisode()之前组内有任何代理已经调用了EndEpisode()方法,那么该组的回合会被中断,而不是正常结束,此时应该调用GroupEpisodeInterrupted()方法来通知组回合中断。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天寒心亦热

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值