Unity机器学习工具ML-Agents作为连结Unity和机器学习的桥梁,为无数开发者提供了各种可能性。4月,我们进行了第一期Unity ML-Agents 强化学习直播,向广大开发者介绍了如何使用ML-Agents创建一个强化学习项目,以及如何去训练它。今天将由Unity技术经理鲍健运带领大家重温本次直播的内容。
ML-Agents目前是v0.4版本,加入了好奇心驱动的探索(Curiosity-Driven Exploration)算法,还实现了编辑器内训练(In Editor Training)模式,丰富了机器学习的功能。在整理原有Platform2D-ML项目时,我将该项目迁移到ML-Agents v0.4版本,有意将v0.4一部分新功能加入其中。因此,本文中的项目设置与代码与4月25日直播的时候会稍有不同。

项目介绍
该机器学习示例项目基于Unity官方发布在Asset Store上的2D游戏开发套件 —2D Game Kit,展示的是通过机器学习的强化学习训练主角Ellen,进行简单的横版过关的游戏操作。

115939r5vzqqjuvccwyze6.jpg

机器学习展示用的关卡是Main场景,是基于2D Game Kit的example第一关修改而来的。大家可以发现后面延绵起伏的平台,这些正是用于验证我们机器学习训练结果的。

115940spmlixiwkso1dxmi.jpg

机器学习训练用的关卡是TrainingScene。它是一个比较封闭,限制比较多的场景。为什么需要做这样的设计呢?

因为现实中的游戏关卡有非常多的状态与参数,其中有一部分是机器学习需要参考和影响的,而另外有一些则是无关甚至是敢干扰的因素。所以需要设计个场景去除尽可能多的不必要因素,帮助机器学习训练的结果趋向于理想的表现。

在这个示例项目中,我们只希望角色Ellen只关注与不同层高平台间的跳跃,进而制作这样简单的场景。

115941s8ii2mc8u8puo9p2.jpg

原理分析

根据机器学习强化学习的方法,进行如下需求分析:
目标:让Ellen在平台上运动,到达终点。 观察值:角色脚下是否接触地面,角色前方是不是遇到台阶。 动作:默认角色横向向右移动,仅有操作是向上跳跃。 奖励:保持在地面奔跑(+0.001);如果前方有台阶而跳跃(+0.1);如果前方没有台阶但跳跃(-0.5)。


115941v44zi2a2beelgo22.jpg

理想训练结果:Ellen在Platform上奔跑,遇到Front进行跳跃,如此行进直到终点。

工程搭建
因为本项目需要使用2D Game Kit套件、ML-Agents工具和TensorFlowSharp插件,关联的资源都比较大。所以,我们只提供和示例项目相关的部分资源,其他的内容请各位移步下文所提及的相关链接进行下载。

1、Unity 版本选用
本项目所使用的ML-Agents版本为v0.4,所以需要安装Unity 2017.2及以上版本来进行开发。

2、搭建ML-Agents v0.4环境
在此前的微信技术文章中,我们发布过搭建ML-Agents的具体方法。现在版本升级到v0.4,大多数步骤还是与原来相近的,只不过TensorFlow的版本要求从原来的1.4.0改为1.7.1。

Windows 10 搭建:
从www.anaconda.com/download/#windows下载安装 Anaconda Python 3.6 version 管理员权限运行Anaconda Prompt 输入“conda create -n ml-agents python=3.6”创建ML-Agents机器学习环境 输入“activate ml-agents”激活环境 输入“pip install tensorflow==1.7.1”通过pip安装TensorFlow 1.7.1版本 从Github下载完ML-Agents之后,输入“cd /d *dir*”(*dir*代表ML-Agents下python目录) 输入“pip install .”通过requirement.txt安装ML-Agents相关机器学习工具库(记住install后面的是空格加英文句号) 等待环境安装完成


MacOS 搭建:
从www.python.org/downloads/mac-osx/下载安装Python 3 for Mac 输入“pip install tensorflow==1.7.1”通过pip安装TensorFlow 1.7.1版本 从Github下载完ML-Agents之后,输入“cd *dir*”(*dir*代表ML-Agents下python目录) 输入“pip install .”通过requirement.txt安装ML-Agents相关机器学习工具库(记住install后面的是空格加英文句号) 等待环境安装完成


3、Unity打开ML-Agents项目
使用Unity打开ML-Agents的unity-environment目录,打开项目工程。从https://s3.amazonaws.com/unity-m ... Plugin.unitypackage下载针对ML-Agents v0.4的TensorFlowSharp插件(python → C# API插件),将unitypackage导入工程。

4、导入2D Game Kit开发者套件
从Asset Store资源商店下载(https://assetstore.unity.com/pac ... /2d-game-kit-107098),导入2D Game Kit套件到现在的项目工程中。

5、导入 Platform2D-ML包到工程
除去ML-Agents与2D Game Kit使用到的部分,原有Platform2D-ML项目包体其实很小,大约超过2MB。大家可以到这个地址去下载:https://oc.unity3d.com/index.php/s/yEtIIKyT4ELfq7Y。将这个Unity包导入该项目

6、调整项目工程设置参数
因为默认Unity的脚本Runtime是基于.Net 3.x的,但是TensorFlowSharp是需要.Net 4.x,所以需要在Unity → Project Settings → Player Settings → Other Settings → Configuration中做些调整。

115941p6d2wvtuod1llaon.jpg

需要将Scripting Runtime Version设置为.Net 4.6(Unity 2017.x)或4.x(Unity 2018.x),API就会自动切换到4.6或4.x。并且在代码中能够让TensorFlow功能生效,需要打开宏定义,在Scripting Define Symbols添加ENABLE_TENSORFLOW。

现在基础搭建的部分就完成了。

训练解析
下图所展示的就是Platform2D-ML项目的结构。我们双击打开TrainingScene训练场景。

115941hcooco0drgtksohz.jpg

1、代码部分
脚本CheckpointChecker.cs
[C#] 纯文本查看 复制代码void OnTriggerEnter2D(Collider2D collider) { if (collider.gameObject.tag == Player) { enteredCheckpoint = true; } } void OnTriggerExit2D(Collider2D collider) { if (collider.gameObject.tag == Player) { enteredCheckpoint = false; } }

这个脚本的主要功能就是在于判定角色Ellen是否进入或离开了检测点,便于处理Agent重置。

脚本PlatformerAcademy.cs 与 PlatformerDecision.cs
ML-Agents v0.4与v0.3在代码撰写方面的比较大的区别是,将功能统一迁移到了MLAgents的命名空间下。PlatformerAcademy只是单纯继承自MLAgents的Academy基础类,override二个基本方法,PlatformerDecision情况相近,二个类的实现目的主要是为了留出可以进行扩展的空间。

脚本PlatformerAgent.cs
这个类是进行强化学习训练主要的功能区域。

开始部分创建了4个参数,分别是:
m_Agent:ML-Agents的训练代理对象,也是场景中的角色Ellen。 m_Goal:目标终点,其实就是场景的Checkpoint。 playerCharacter:角色Ellen,Gamekit2D的角色对象。 initalPosition:角色的其实位。


帮助判定的检测方法:
1、HasPlatformInFront:用于检测角色前面是否有台阶(Front)

[C#] 纯文本查看 复制代码public bool HasPlatformInFront(Vector2 position, int layer) { Vector2 positionCentered = new Vector2(position.x, position.y + .5f); Vector2 direction = Vector2.right; LayerMask layerMask = 1 << layer; RaycastHit2D hitFront = Physics2D.Raycast(positionCentered, direction, 1f, layerMask); if (hitFront playerCharacter.CheckForGrounded()) return true; return false; }


2、IsGrounded:用于检测角色是否踏在地面上
[C#] 纯文本查看 复制代码public bool IsGrounded(Vector2 position) { Vector2 adjustedPosition = new Vector2(position.x, position.y + .5f); Vector2 direction = -Vector2.up; LayerMask layerMask = 1 << 31; RaycastHit2D grounded = Physics2D.Raycast(adjustedPosition, direction, 1f, layerMask); return grounded; }

Override机器学习代理Agent的方法:
1、 InitializeAgent:初始化Agent的状态
[C#] 纯文本查看 复制代码public override void InitializeAgent() { // 获取角色Ellen上的Gamekit2D → PlayerCharacter对象 playerCharacter = m_Agent.GetComponent<PlayerCharacter>(); // 将原有角色的初始位置保存下来 initialPosition = m_Agent.transform.position; }


2、 CollectObservations:收集观察值
[C#] 纯文本查看 复制代码public override void CollectObservations() { // 收集角色是否接触地面 AddVectorObs(IsGrounded(m_Agent.transform.position) ? 1f : 0f); // 收集角色前面是否有台阶 AddVectorObs(HasPlatformInFront(m_Agent.transform.position, 31) ? 1f : 0f); }

3、AgentAction:代理操作功能相关处理
[C#] 纯文本查看 复制代码public override void AgentAction(float[] vectorAction, string textAction) { // 在地面即驱动角色向前移动 if (IsGrounded(m_Agent.transform.position)) { playerCharacter.SetHorizontalMovement(5f); } // 获取输入操作值 int action = Mathf.FloorToInt(vectorAction[0]); // 在不操作的情况下,判断是否在地面 if (action == 0f IsGrounded(m_Agent.transform.position)) { // 符合情况,添加0.001的奖励 AddReward(0.001f); } // 在按space跳跃的情况下,判断是否在地面 else if (action == 1f IsGrounded(m_Agent.transform.position)) { // 给予角色向前20f,向上15f的移动 → 斜前方跳跃 playerCharacter.SetMoveVector(new Vector2(20f, 15f)); // 如果前面有台阶 if (HasPlatformInFront(m_Agent.transform.position, 31)) { // 获得0.1的奖励 AddReward(0.1f); } // 如果前面没有台阶 else { // 扣除0.5的奖励 AddReward(-0.5f); } } // 是否碰到监测点 if (m_Goal.GetComponent<CheckpointChecker>().enteredCheckpoint) { // 碰到即完成一个强化学习周期 Done(); } }

4、 AgentReset:强化学习周期完成后的代理重设
[C#] 纯文本查看 复制代码public override void AgentReset() { // 将角色重置回初始位置 m_Agent.transform.position = initialPosition; }

2、训练部分
1、将TrainingScene场景中的PlatformerBrain的Brain Type修改为External模式:

115942b22vxa2zp2l2ootx.jpg

2、 打开相关命令行工具(Windows 10电脑启动Anaconda Prompt;macOS电脑 启动Terminal)

3、通过“cd”命令进入项目“python”目录

4、输入“python learn.py --train”,进行强化学习训练

115943z75isswh1wes1s59.jpg

(在Mac环境下,Unity的Logo+文字的显示很漂亮,但是由于编码显示的问题,Windows环境下显示效果就一言难尽了……)

ML-Agents v0.4版本开始支持编辑器内训练的方法,命令行末出现了“unityagents: Start training by pressing the Play button in the Unity Editor.”即点击Unity编辑器上的运行按钮就可以在直接进行强化学习训练,原有之前的版本在发布应用来训练方式其实也保留了下来,但是直接通过编辑器环境训练能获得更好的体验。

120117mkigfzxyr9f2i9jg.png

在Unity ML-Agents中需要使用的是生成的.bytes文件,这里是editor_PlatformerAcademy_ppo.bytes。

120117lwqwvwcxc7cbvbrx.png

5、将训练生成的.bytes文件放到Unity工程中

120117jgheu4rr449ad44g.png

6、修改PlatformerBrain的Brain Type为Internal模式,并制定Graph Model为editor_PlatformerAcademy_ppo.bytes

120118vf4yfgjk4ybhxbfg.png

点击运行按钮查看训练效果:

120125cdnhhv4jhljane6a.jpg

ML-Agents工程中也提供了相关的使用项目:金字塔探索者(Pyramids)

120125q2qxzp7idig7iyyf.jpg

在trainer_config.yaml中设置Curiosity相关的参数,可能会得到更好的效果。我们可以在该文件文末,仿照PyramidBrain添加如下参数表:

PlatformerBrain:
use_curiosity: true
curiosity_strength: 0.01
curiosity_enc_size: 256
batch_size: 128
buffer_size: 2048
hidden_units: 512
num_layers: 2
beta: 1.0e-2
max_steps: 1.0e5
num_epoch: 3

保存后,从1步开始重新训练。

120130t7yyzwzv2wu6q7vu.gif

在观察训练过程时,可以发现角色的操作似乎已经很理想了。当然,我们完全可以在命令行中直接按键Ctrl+C或者点击Unity的运行按钮中断训练,保存训练数据.bytes二进制文件。

将训练完的文件重新放回Unity中,并Internal模式下进行演示,观察训练结果。

120139n5u1hhvvhju02jhk.gif

现在Ellen可以在一遇到台阶就能完成跳跃,虽然还有些瑕疵,但是比原有的训练结果改善不少。

7、打开Main场景,找到Academy → Brain,设置Brain Type为Internal,指定Graph Model为新的.bytes文件,观察强化学习在实际游戏场景中的效果。

120147zg2dg5tqcgt8fc62.gif

这里我稍微调整了TimeScale,让播放稍快些。使用Unity ML-Agents进行强化学习示例解析暂告一段落。

小结
下次还会发布进行模仿学习示例解析,敬请广大开发者期待。更多Unity官方技术直播课程尽在Unity Connect平台,更多Unity技术内容尽在Unity官方技术论坛(Unitychina.cn) ! 机器学习锐亚教育

锐亚教育 锐亚科技 unity unity教程