上一节咱们讲了如何配置ML-Agents环境,这一节咱们建立一个示例,主要利用Reinforcement Learning(强化学习)。git
如上图,本示例将训练一个球滚动找到随机放置的立方体,并且要避免从平台上掉下去。github
本示例是基于ML-Agents官方的示例,官方有中文版和英文版两个文档,英文版的是最新的,中文版中大部份内容和英文版的一致,但也有不一样,本文是基于最新版所作(v0.15.0,master分支),须要参考官方文档的也可参照以下地址食用。算法
英文:https://github.com/Unity-Technologies/ml-agents/tree/master/docsjson
在Unity项目中使用ML-Agents涉及如下基本步骤:数组
(PS.在官方中文文档中,第2,3步须要实现Academy子类和Brain,但在新版中,这两个东西已经不须要在场景里定义了,因此比较重要的就是这个Agent子类,基本学习逻辑都在这里)浏览器
第一步,咱们先新建一个Unity项目,而且将ML-Agents包导入到里面:网络
打开Unity,新建一个项目随意叫个名字,例如“RollerBall”;dom
在Unity菜单“Edit”->“Project Settings”,在弹出的窗口中,找到“Player”,将“Api Compathbility Level”改成“.NET 4.x”,以下图;ide
在上一节中,咱们已经将ml-agents代码库克隆到了本地,若是没有克隆,请参考上一篇“Unity ML-Agents v0.15.0(一)环境部署与试运行”中的5、1,这里咱们默认你们都是已经克隆了库,则在Unity中须要将ML-Agents插件导入Unity中。我这里的版本是Unity2019.2,方法以下:
文件夹中有一个“manifest.json”的文件,编辑它,这个就是工程中的Packages包集合,在最后加入"com.unity.ml-agents" : "file:D:/Unity Projects/ml-agents/com.unity.ml-agents",这里file:后是你本身克隆的ml-agents源码路径,别照抄个人哦,除非你也是这个路径- -,以下图;
修改后保存,在切到Unity中,若是路径正确,则会出现导入package包的画面,在工程的Packages文件夹下也会成功出现“ML Agents”文件夹,以下图:
建立环境
下面,咱们建立一个简单的ML-Agent环境。该环境的“physical”组件包括一个Plane(充当agent移动的地板)、一个Cube(充当agent寻找的目标)和一个Sphere(表示agent自己)。
建立地板
在 Hierarchy 窗口中右键单击,选择 3D Object > Plane。
将游戏对象命名为“Floor”。
选择 Plane 以便在 Inspector 窗口中查看其属性。
将 Transform 设置为 Position = (0,0,0)、Rotation = (0,0,0)、Scale = (1,1,1)。
修改Plane材质,变的好看点。
以上过程我都是复制的,其实就是建立一个Plane,而后换个好看的材质就行,随意定义一个都OK。
建立目标立方体
在 Hierarchy 窗口中右键单击,选择 3D Object > Cube。
将游戏对象命名为“Target”
选择 Target 以便在 Inspector 窗口中查看其属性。
将 Transform 设置为 Position = (3,0.5,3)、Rotation = (0,0,0)、Scale = (1,1,1)。
修改Cube材质。
添加Agent球体
OK,以上过程就将Unity中的三维环境建立好了,下面咱们来实现Agent。
在官方中文文档中还有“实现Academy”及“添加Brain”,最新版里已经不须要了!直接设置Agent就行。
要建立Agent:
而后,编辑新的RollerAgent
脚本:
RollerAgent
脚本;RollerAgent
继承Agent
类,同时引用using MLAgents
和using MLAgents.Sensors
命名空间;Update()
方法,先保留Start()
方法以后要用。到目前为止,以上的步骤都是为了将ML-Agents添加到任何Unity项目中而须要的基本步骤。接下来,咱们将添加逻辑,使咱们的agent可以利用reinforcement learning(强化学习)技术学习找到立方体。
当agent(球体)到达目标位置(方块)后,会将本身标记为完成状态,而agent的重置函数(Reset)会将方块再从新移动到新的位置。另外,若是agent从平台上掉落,也会触发重置函数,使得agent初始化,目标位置也将随机刷新。
为了重置agent的速度(以及以后给它施加力移动),咱们须要引用到球体的Rigidbody
组件。这个组件的引用就能够写到Start()
方法中,以以上的逻辑,咱们的RollerAgent
脚本以下:
using MLAgents; using MLAgents.Sensors; using UnityEngine; public class RollerAgent : Agent { public Transform Target;//方块 public float speed = 10;//小球移动速度 private Rigidbody rBody;//球刚体 private void Start() { rBody = GetComponent<Rigidbody>(); } /// <summary> /// Agent重置 /// </summary> public override void AgentReset() { if (this.transform.position.y < 0) {//若是小球掉落,小球初始化 rBody.velocity = Vector3.zero; rBody.angularVelocity = Vector3.zero; transform.position = new Vector3(0, 0.5f, 0); } //方块位置随机 Target.position = new Vector3(Random.value * 8 - 4, 0.5f, Random.value * 8 - 4); } }
接下来,咱们来实现Agent.CollectObservations(VectorSensor sensor)
方法。
注意,这里和老版本方法不一样,以前的函数中并无VectorSensor sensor
参数,不过用法差很少。
Agent将咱们收集的信息发送给Brain,由Brain使用这些信息来作决策。当你训练Agent(或使用已经训练好的模型)时,数据将做为特征向量输入到神经网络中。为了让Agent成功学习某个任务,咱们须要提供正确的信息。一个好的经验法则则是考虑你在计算问题的分析解决方案时须要用到什么。
这里比较重要,就是说你在训练的时候,须要考虑到的变量是哪些,咱们来看看这个例子中咱们须要agent收集的信息有哪些:
目标的位置
sensor.AddObservation(Target.position);
agent的位置
sensor.AddObservation(transform.position);
agent的速度,这有助于agent去学习控制本身的速度,而不会使其越过目标和从平台上滚下来
sensor.AddObservation(rBody.velocity.x);
sensor.AddObservation(rBody.velocity.z);
这里一共有8个观测值(一个position算x,y,z三个值),以后须要在Behavior Parameters
组件的属性里进行设置,以下图:
在中文文档里,对这些值进行了归一化处理,最新英文文档中并无进行归一化处理,直接加上就行。而后这里的重载函数以下:
/// <summary> /// Agent收集的观察值 /// </summary> /// <param name="sensor"></param> public override void CollectObservations(VectorSensor sensor) { sensor.AddObservation(Target.position);//目标的位置 sensor.AddObservation(transform.position);//小球的位置 sensor.AddObservation(rBody.velocity.x);//小球x方向的速度 sensor.AddObservation(rBody.velocity.z);//小球z方向的速度 }
Agent的最后一部分是Aegnt.AgentAction()
函数,这个方法主要是用来接收Brain的决策命令以及根据不一样状况来进行Reward(奖励)。
Brain的决策以动做数组的形式传递给AgentAction()函数。此数组中的元素主要由agent的Brain的Vector Action
、Space Type
和Space Size
来决定的。这里分别表明 了向量运动空间、向量运动空间类型以及向量运动空间数,ML-Agents将动做分为两种:Continusous向量运动空间是一个能够连续变化的数字向量,例如一个元素可能表示施加到agent某个Rigidbody
上的里或扭矩;Discrete向量运动空间则将动做定义为一个表,提供给agent的具体动做是这个表的索引。
咱们在这里利用的是Continusous
向量运动空间,即将Space Type
设置为Continuous,并将Space Size
设置为2。这就表示了Brain生成的决策利用第一个元素action[0]
来肯定施加沿x轴的力,经过action[1]
来肯定施加沿z轴的力(若是agent是三维移动,则将Space Size
设置为3)。注意,这个里Brain并不知道action[]
数组中每一个值的具体含义,在训练的过程当中只是根据观测输入来调整动做,而后看看会获得什么样的奖励。具体设置以下图,一样是在Behavior Parameters
组价中进行设置:
引伸一下,这里也可使用Discrete类型来训练,不过相应的Space Size
就要变成4了,由于有4个方向须要控制。
OK,上述的动做代码以下:
//Space Type=Continuous Space Size=2 Vector3 controlSignal = Vector3.zero; controlSignal.x = vectorAction[0];//x轴方向力 controlSignal.z = vectorAction[1];//z轴方向力 //固然上面这两句能够互换,由于Brain并不知道action[]数组中数值具体含义 rBody.AddForce(controlSignal * speed);
Reinforcement Learning(强化学习)须要奖励。一样奖励(惩罚)也在AgentAction()
函数中实现,与上面动做实现的重写函数在一块儿。学习算法使用在模拟和学习过程的每一个步骤中分配给agent的奖励来肯定是否为agent提供了最佳的动做。当agent完成任务时,对它进行奖励。在这个示例中,若是Agent(小球)到达了目标位置(方块),则给它奖励1分。
RollerAgent会计算到达目标所需的距离,当到达目标时,咱们能够经过Agent.SetReward()
方法来说agent标记为完成,并给它奖励1分,同时使用Done()
方法来重置环境。
//计算自身与目标的距离 float distanceToTarget = Vector3.Distance(transform.position,Target.position); //不一样状况进行奖励 if (distanceToTarget < 1.42f) {//到达目标附近 SetReward(1); Done(); }
最后,若是小球掉落平台,则让agent重置。这里没有设置惩罚,有兴趣的童靴能够本身试试设置惩罚。
if (transform.position.y < 0) {//小球掉落 //SetReward(-1); 惩罚先不设置 Done(); }
OK,由以上的动做和奖励构成了AgentAction()方法,主要理解里面每一步的意义是为什么,最后AgentAction()
方法以下:
public override void AgentAction(float[] vectorAction) { //Space Type=Continuous Space Size=2 Vector3 controlSignal = Vector3.zero; controlSignal.x = vectorAction[0];//x轴方向力 controlSignal.z = vectorAction[1];//z轴方向力 //固然上面这两句能够互换,由于Brain并不知道action[]数组中数值具体含义 rBody.AddForce(controlSignal * speed); //计算自身与目标的距离 float distanceToTarget = Vector3.Distance(transform.position, Target.position); //不一样状况进行奖励 if (distanceToTarget < 1.42f) {//到达目标附近 SetReward(1); Done(); } if (transform.position.y < 0) {//小球掉落 Done(); } }
到这一步,全部的游戏对象和ML-Agent组件都已准备就绪,而后咱们须要在场景的小球上加一些脚本,修改一些属性。
在场景中选择RollerAgent小球,先添加Behavior Parameters
脚本,并设置其中的Space Size
为8,Space Type
为Continuous,Space Size
为2。这步要是以前几步里已经搞定了,就不用管了。不过这里面有个Behavior Name
,这个属性应该就是区分Brain的名称,新版中多个Agent拥有相同Brain的话,应该是在这里进行区分,我我的是这么以为的,要是有错的话,请指正;
这步必定要记得,老版里没有,须要加Decision Requester
组件,并将Decision Period
改成10!这里英文文档也写得不起眼,要是不加这个脚本,你的小球是动不起来的。
在开始长时间训练以前,手动测试你的测试环境是一个明智的作法。为了手动测试,咱们须要在Roller Agent
脚本中添加Heuristic()
方法,以此来代替Brain决策,代码以下:
/// <summary> /// 手动测试 /// </summary> /// <returns></returns> public override float[] Heuristic() { var action = new float[2]; action[0] = Input.GetAxis("Horizontal"); action[1] = Input.GetAxis("Vertical"); return action; }
其实这里就是经过键盘来对动做空间action[]数组进行赋值来使得agent动做。
而后还须要在Behavior Parameters
组件中将Behavior Type
改成Heuristic Only
,以下:
这个时候咱们能够运行一下,(忽然发现Roller
中的Targer忘记拖了,将方块目标拖进来),而后就可使用WSAD或上下左右来控制小球了,到方块附近,方块会自动从新置位,若是小球掉落,也会从新置位。
OK,咱们Behavior Type
改回Default
,准备开始训练了~
打开Anaconda3,找到咱们以前建好的训练环境,启动“Terminal”。
cd到ml-agent的根目录,例如个人路径:
cd /d D:\Unity Projects\ml-agents
这里插一下,咱们修改一下ml-agents中的Config文件,找到ml-agents
中config
文件夹,并打开trainer_config.yaml
配置文件,在最后加一句
RollerBallBrain: batch_size: 10 buffer_size: 100
这里能够看到RollerBallBrain其实就是我刚才在Behavior Parameters
组件中设置的Behavior Name
。这里修改这两个参数会覆盖配置文件最前的默认项default
,这两个超参数值修改小可使得训练速度加快,若是用原来的参数(batch_size: 1024,buffer_size: 10240),则须要训练大约300000步,可是修改后只须要低于20000步。这里应该是根据具体项目具体设置的。
咱们配置完以后,回到命令行,输入:
mlagents-learn config/trainer_config.yaml --run-id=RollerBall-1 --train
运行Unity中的程序。
若是Unity与Anaconda训练环境成功通信,则会在命令行中发现你的训练配置:
同时,能够看到Unity中小球开始本身快速运动,方块也会根据不一样状态来随机生成。
过一段时间,命令行中会显示相应的执行步数,通过的时间,平均奖励等信息。
随着训练的进行,会发现小球很难掉下平台,且一直跟随方块的位置:
最后训练时间太长了,能够经过配置文件中的max_steps
来修改最大训练步骤,因此我这里直接Ctrl+C了,这样也会将训练模型存下来。
找到这个RolerBallBrain.nn
文件,在ml-agent的models
文件夹下,将这个.nn文件考入Unity中,以下:
而后选中场景中的小球,将Behavior Parameters
组件中Model
属性中,选择刚才训练好的模型,并将Behavior Type
选为Inference Only
,以下:
而后点击运行,就能够看到小球利用咱们训练好的模型开始找方块了。
咱们在命令行中,还能够找到刚才训练的图表信息,在命令行中输入:
tensorboard --logdir=summaries
而后将地址在浏览器中打开,通常都是http://localhost:6006/
则能够看到随着训练步数各个数值变化值。
这些值的含义,抄一些官方中文文档:
Lesson - 只有在进行课程训练]时才有意义。
Cumulative Reward - 全部 agent 的平均累积场景奖励。 在成功训练期间应该增大。
Entropy - 模型决策的随机程度。在成功训练过程当中 应该缓慢减少。若是减少得太快,应增大 beta
超参数。
Episode Length - 全部 agent 在环境中每一个场景的 平均长度。
Learning Rate - 训练算法搜索最优 policy 时须要多大的 步骤。随着时间推移应该减少。
Policy Loss - policy 功能更新的平均损失。与 policy (决定动做的过程)的变化程度相关。此项的幅度 在成功训练期间应该减少。
Value Estimate - agent 访问的全部状态的平均价值估算。 在成功训练期间应该增大。
Value Loss - 价值功能更新的平均损失。与模型 对每一个状态的价值进行预测的能力相关。此项 在成功训练期间应该减少。
OK,以上就是官方训练的一个小例子全过程了。
记录这个还挺累,不过欢迎你们一块儿留言讨论,转载麻烦请注明原地址哦,感谢你们~
引用:
https://github.com/Unity-Technologies/ml-agents/tree/master/docs