查看原文
其他

Unity机器学习代理ML-Agents强化学习示例解析

Unity Unity官方平台 2018-11-15

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日直播的时候会稍有不同。


这是直播课程内容。


https://v.qq.com/txp/iframe/player.html?vid=e064454489j&width=500&height=375&auto=0

项目介绍

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


  

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



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


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


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

 

原理分析

根据机器学习强化学习的方法,进行如下需求分析:

  • 目标:让Ellen在平台上运动,到达终点。

  • 观察值:角色脚下是否接触地面,角色前方是不是遇到台阶。

  • 动作:默认角色横向向右移动,仅有操作是向上跳跃。

  • 奖励:保持在地面奔跑(+0.001);如果前方有台阶而跳跃(+0.1);如果前方没有台阶但跳跃(-0.5)。



理想训练结果: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-ml-agents/0.4/TFSharpPlugin.unitypackage 下载针对ML-Agents v0.4的TensorFlowSharp插件(python → C# API插件),将unitypackage导入工程。

 

4

导入2D Game Kit开发者套件

从Asset Store资源商店下载(https://assetstore.unity.com/packages/essentials/tutorial-projects/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中做些调整。

 

 

需要将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训练场景。



1

代码部分

脚本CheckpointChecker.cs

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)

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:用于检测角色是否踏在地面上

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的状态

public override void InitializeAgent()

{

       // 获取角色Ellen上的Gamekit2D → PlayerCharacter对象

       playerCharacter = m_Agent.GetComponent<PlayerCharacter>();

       // 将原有角色的初始位置保存下来

       initialPosition = m_Agent.transform.position;

}


 2、 CollectObservations:收集观察值

public override void CollectObservations() {

       // 收集角色是否接触地面

       AddVectorObs(IsGrounded(m_Agent.transform.position) ? 1f : 0f);

       // 收集角色前面是否有台阶

       AddVectorObs(HasPlatformInFront(m_Agent.transform.position, 31) ? 1f : 0f);

}



3、AgentAction:代理操作功能相关处理

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:强化学习周期完成后的代理重设

public override void AgentReset()

{

       // 将角色重置回初始位置

       m_Agent.transform.position = initialPosition;

}


2

训练部分

1、将TrainingScene场景中的PlatformerBrain的Brain Type修改为External模式:

 


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

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

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



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


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

 


完成50000次训练之后,在python/model/ppo目录下会生成机器学习相关的文件。

 


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



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

 


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



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



角色Ellen能够正常在平台上跑动,可以跳跃过台阶。大家如果仔细观察,会发现她在台阶前会有比较长的跑动等待。

 

在Python目录下有个Brain参数配置的文件,叫做trainer_config.yaml,其中有许多XXXBrain形式的参数表。这些XXXBrain其实是从Default扩展而来的。由于这个项目没有为PlatformerBrain进行过特定的设置,因此强化学习的训练是直接参照default的。原有单纯的PPO算法训练方式让Agent的探索可能比较保守,如果使用稍微积极一些的方式,可能效果会更好。

 

ML-Agents v0.4版本加入了一个新的算法:好奇心驱动的探索 (Curiosity-Driven Exploration)。



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

 


在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步开始重新训练。



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

 

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

 

 

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


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



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


小结

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


推荐阅读



官方活动


首期Unity官方在线培训课程

7月18日,Unity将正式举办首期Unity官方在线培训课程,打破地理位置的限制,通过在线一日系统化教学,帮助你掌握和使用Unity。参加完此次一天的在线课程后, 参会者将被授予Unity官方培训证明。[了解详情

报名地址:

https://connect.unity.com/events/UnityTrainingWorkshop


实时优化,智造收益 - Unity Monetization开发者生态沙龙

8月3日,Unity将于举办为期半天的Unity Monetization开发者生态沙龙!本次活动将与大家共同探讨移动游戏开发与变现相关难点与痛点。[了解详情]

报名地址:

https://connect.unity.com/events/unityads



7月Asset Store资源商店促销 

7月,只需在Asset Store资源商店消费满30-199美元,最高可获得价值235美元的5款免费资源,参与活动,获得夏日精选资源包。

活动地址:

https://assetstore.unity.com/g/july-promo-activation-cn



点击“阅读原文”访问Unity官方中文论坛

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存