Unity 用ml

Wesley13
• 阅读 655

目录

  • 本次示例:训练一个追踪红球的白球AI
  • 1. 新建Unity项目,导入package
  • 2. 编写Agent脚本
    • void OnEpisodeBegin()
    • void CollectObservations(VectorSensor sensor)
    • void OnActionReceived(float[] vectorAction)
    • void Heuristic(float[] action)
  • 3. 搭建好游戏场景
  • 4. 调整脚本参数
    • Behavior Parameters
    • Roller Agent
    • Decision Requester
  • 5. 开始训练
  • 6. 将训练过的模型整合到Unity中
  • 附录
    • config文件配置
  • 参考

前言:上一篇博文已经介绍了Unity Ml-Agents的环境配置了。

个人建议先敲深度强化学习的Demo再摸清概念比较容易上手,因此本文先提供一个深度强化学习的Demo示例简单阐述下。

更新于2020.3.6:由于现在Unity ml-agents项目比起2018年已经更新了许多,以前的Demo教程已经不适合了,因此决定翻新Unity ml-agents机器学习系列博客。

更新于2020.7.6:没想到仅仅过了几个月,ml-agents项目已经从最初的beta版到现在已经第3个正式发行版了。因此再次翻新博客。

本次示例:训练一个追踪红球的白球AI


Unity 用ml

1. 新建Unity项目,导入package


进入Unity项目,在上方 Window => Package Manager,然后安装 Barracuda 这个package(如果没看见,一般就是没有显示All packages或没显示preview package):

Unity 用ml

注意:不要在Package Manager加载ml-agents package,因为后面我们要手动导入该包相关内容,不然会引发重复定义的错误。

并将之前下载的ml-agents项目com.unity.ml-agents目录下Editor、Plugin、Runtime复制进新建Unity项目里(建议放在Assets文件夹内)。

Unity 用ml

2. 编写Agent脚本


RollerAgent 是将用于智能体对象的组件脚本:

//RollerAgent.cs
//继承Agent用于重写智能体的CollectObservations等方法。
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
public class RollerAgent : Agent
{
    public Transform Target;
    public float speed = 10;
    Rigidbody rBody;

    void Start()
    {
        rBody = GetComponent<Rigidbody>();
    }    

    //进入新一轮训练时调用
    public override void OnEpisodeBegin()
    {
        if (this.transform.position.y < 0)
        {
            //如果智能体掉下去,则重置位置+重置速度
            this.rBody.angularVelocity = Vector3.zero;
            this.rBody.velocity = Vector3.zero;
            this.transform.position = new Vector3(0, 0.5f, 0);
        }
        //将目标球重生至一个新的随机位置
        Target.position = new Vector3(UnityEngine.Random.value * 8 - 4, 0.5f, UnityEngine.Random.value * 8 - 4);
    }

    //收集观察结果
    public override void CollectObservations(VectorSensor sensor)
    {
        //观察目标球和智能体的位置
        sensor.AddObservation(Target.position);
        sensor.AddObservation(this.transform.position);
        //观察智能体的速度
        sensor.AddObservation(rBody.velocity.x);
        sensor.AddObservation(rBody.velocity.z);
        //在这里因为目标球是不会动的,智能体也不会在y轴上又运动,所以没有必要观察这些值的变化。
        //sensor.AddObservation(rBody.velocity.y);
    }

    //处理接受的动作,并根据当前动作评估奖励信号值    
    public override void OnActionReceived(float[] vectorAction)
    {
        //------ 动作处理
        // 接受两个动作数值
        Vector3 controlSignal = Vector3.zero;
        controlSignal.x = vectorAction[0];
        controlSignal.z = vectorAction[1];
        rBody.AddForce(controlSignal * speed);

        //------ 奖励信号
        float distanceToTarget = Vector3.Distance(this.transform.position, Target.position);
        // 到达目标球
        if (distanceToTarget < 1.42f)
        {
            //奖励值+1.0f
            SetReward(1.0f);
            EndEpisode();
        }

        // 掉落场景外
        if (this.transform.position.y < 0)
        {
            EndEpisode();
        }
    }

    //手动操控智能体,用于手动调试智能体或启发模仿学习。
    public override void Heuristic(float[] action)
    {
        action[0] = -Input.GetAxis("Horizontal");
        action[1] = Input.GetAxis("Vertical");
    }
}

Agent,即智能体,含有感知和行为——它通过观察环境然后做出相应的行为。在最常使用的强化学习里,智能体的训练模型类似一个黑盒。
每一次模拟步长中,智能体的感知会作为黑盒的输入,然后黑盒会输出行为选择,然后根据行为选择来让智能体做出行为。

当我们需要创建一个智能体类型时,让其继承Agent类,以用于重写智能体CollectObservations,OnActionReceived等方法。

void OnEpisodeBegin()

  • 每一轮训练开始时调用,一般用于负责重新设置场景。

在示例里,为了让训练更加有效更加广泛化,因此该函数内容是给目标球设置的是随机位置(实际上智能体球也应该设置随机位置)。

void CollectObservations(VectorSensor sensor)

  • 每一个模拟步长都会被调用。
  • 负责收集智能体的对环境的观察信息。

这部分类似于黑箱子的输入。值得注意的是,所需观察的信息越少越好。因此,我们需要尽可能减少不必要的观察信息,这会让训练变得更加快速、准确。

void OnActionReceived(float[] vectorAction)

  • 每一个模拟步长都会被调用。
  • 负责接受决策的行为选择从而让智能体做出行为。示例里,通过行为选择的2个float输入值来驱使球体移动,一旦掉出场景外,便调用Done()。
  • 负责评估此步长的reward(奖励值)。示例里,只要触碰到目标球即可获得一定的reward。

如何根据实际问题设计reward往往是一个难点,设计的不好(例如部分奖励值过大)容易造成网络不收敛。

void Heuristic(float[] action)

  • 通过玩家亲自操控智能体来输出行为选择。

亲自操控智能体可用于模仿学习或调试智能体的行为。

3. 搭建好游戏场景


创建一个地板:

Unity 用ml

创建一个小球:

Unity 用ml

创建一个智能体(RollerAgent):

先创建一个带刚体的球体对象,然后我们需要给它挂载RollerAgent脚本(挂载后自动额外挂载BehaviorParameters脚本用于配置)和DecisionRequester脚本。

Unity 用ml

4. 调整脚本参数


Behavior Parameters

每个Agent还必须得附带一个行为参数脚本,行为参数脚本用于定义智能体如何做出决策。

Vector Observation Space Size:观察信息的大小。在本示例中应调整为8,因为示例智能体脚本总共需要观察的特征元素为2个3D位置+2个1D速度,因此总共需要空间为8个float大小。

Vector Action Space Size:动作矢量的大小。在本示例中应调整为2,因为智能体脚本里接受2个浮点型动作输入。动作矢量的元素可以选择两种类型:一种是离散型的整型数值,适用于离散动作,例如下棋的位置选择;另一种则是连续性的浮点数值,适用于连续动作,例如3个float值可以代表一个施加到智能体刚体的力或力矩。

Inference Device:调整为GPU,从而使用GPU来训练。

Behavior Type:行为类型,主要有Default、Heuristic、Inference三种模式。

  1. Default:默认训练模式,用于一般的强化学习。
  2. Heuristic Only:启发模式,玩家亲自操控智能体,可用于模仿学习或调试游戏场景。
  3. Inference Only:推理模式,运行训练好的模型。

Roller Agent

Max Step:决定智能体最多可以有多少步决策,超过限制后则强制Done。特殊地,设置为0意思是不限制步数。在本示例中应调整为0。

Decision Requester

Decision Period:决策间隔。在本示例中应调整为10。


目前场景预览:

Unity 用ml

Unity 用ml

在这里,最好先Behavior Type切换成Heuristic Only模式用于调试游戏场景,运行Unity场景后可尝试自己用WASD键盘操控小球,测试游戏场景是否OK。然后确认无问题后再切换回Default

5. 开始训练


然后现在可以打开开始菜单,直接使用cmd命令窗口,
cd到之前下载ml-agents项目的目录里

cd C:\Downloads\ml-agents

再输入激活ml-agents环境:

activate ml-agents

开启训练:

mlagents-learn config/ppo/config.yaml

Unity 用ml

  • config/ppo/config.yaml是训练配置文件,RollerBall-1是你给训练出来的模型取的名字
  • 此外注意config/ppo/config.yaml是不存在的,需要自己仿照官方的示例yaml文件修改配置而新建的。

下面是config.yaml示例:

behaviors:
  RollerBall:
    trainer_type: ppo
    hyperparameters:
      batch_size: 64
      buffer_size: 12000
      learning_rate: 0.0003
      beta: 0.001
      epsilon: 0.2
      lambd: 0.99
      num_epoch: 3
      learning_rate_schedule: linear
    network_settings:
      normalize: true
      hidden_units: 128
      num_layers: 2
      vis_encode_type: simple
    reward_signals:
      extrinsic:
        gamma: 0.99
        strength: 1.0
    keep_checkpoints: 5
    max_steps: 300000
    time_horizon: 1000
    summary_freq: 1000
    threaded: true

有关config参数具体配置将放在文末附录。由于ml-agents项目一直在更新,配置的格式也可能会有改变。本文提供的配置文件示例是依据第三版正式发行版时配置文件格式编写的。

当出现如下画面:

Unity 用ml

返还到Unity,点下运行键,那么你就会看到Unity执行训练。

Unity 用ml

Unity 用ml

你的命令窗口也会时刻告诉你训练阶段的信息:

  • Step:模拟的步长次数
  • Time Elapsed:所用时间
  • Mean Reward:奖励平均值
  • Std of Reward:奖励标准方差值

一般来说,随着训练的进行,奖励平均值越来越高,奖励标准方差值越来越低。这意味着智能体的行为越来越稳定趋向于获奖收益最高的行为。

现在可以去挂机等待结果了,亦或者在某个时间停止Unity场景运行。那么ml-agents会将目前为止训练出来的数据模型(.nn文件)保存到ml-agents\results目录下。

6. 将训练过的模型整合到Unity中


Unity 用ml

将训练出来的nn文件导入到Unity项目文件夹中,并在智能体Behavior Parameters脚本上的Model选择刚刚导入的nn文件;然后将Behavior Type调整为Inference Only。

Unity 用ml

运行Unity场景,看看你跑出来的模型的蠢样了(笑)。

Unity 用ml

附录


config文件配置

参数配置(翻修中,建议参考关于训练配置文件的官方文档

参考


另外一提,最新的介绍文档资料示例等都在Unity官方机器学习的github项目,感兴趣可以持续保持关注它的更新:

[1] Unity官方机器学习的github项目 https://github.com/Unity-Technologies/ml-agents

[2] Unity官方博客机器学习概念详解(1) https://blogs.unity3d.com/2017/12/11/using-machine-learning-agents-in-a-real-game-a-beginners-guide/

[3] Unity官方博客机器学习概念详解(2) https://blogs.unity3d.com/2017/06/26/unity-ai-themed-blog-entries/

[4] Unity ml-agents概念详解国内翻译博客 https://blog.csdn.net/u010019717/article/details/80382933

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这