从零开始搭建Unity机器学习环境—Chapter2:建立行人基本行为模型

0 前言

ML-Agents官方文档中首先介绍了该项目Demo Project的上手方法,随后才涉及到如何建立全新的机器学习环境。本专栏则将先行介绍如何从零开始搭建机器学习环境。

1 Unity工程设置

1.1 新建Unity 3D工程,名称随意。

1.2 菜单栏 Edit>Project Settings>Package Manager选项,勾选“Enable Preview Packages”选项,这将允许我们忽略Unity Editor版本所造成的限制,能够将最新版本的ML-Agents资源包导入到项目中,以便与Github项目资源或其他开源工程保持一致。

1.3 举个反例,当Unity Editor版本为2020.3.30时,若使用系统适配的ML-Agents资源包版本,则会出现部分命名空间未被定义的情况,说白了就是更新不及时,外面Demo已经在使用的功能旧版的包里没有。

从零开始搭建Unity机器学习环境—Chapter2:建立行人基本行为模型_第1张图片

 1.4 菜单栏 Window>Package Manager,打开包管理器,搜索ML-Agents,在结果中选取最新版本的资源包并导入到本地工程中。

从零开始搭建Unity机器学习环境—Chapter2:建立行人基本行为模型_第2张图片

1.5 在Unity项目目录中新建文件夹,命名为“config”,用于存放训练配置文件。

1.6 在Unity项目中或硬盘其他位置新建文件夹,命名随意,用于安装虚拟环境所需包。需注意的是,各项配置完成后该文件夹将占用较大空间,若置于Unity工程中较方便,同时也将导致项目体积过大,可自行权衡。

2 建立虚拟环境

2.1 搭建机器学习需要几十种插件,为避免项目逻辑混乱或影响到本地其他项目,应新建与本地环境完全隔绝的专用学习环境;此外,在专属环境中可以对不同版本、不同插件的兼容性进行较为便捷的验证。网上其他教程往往推荐使用conda对虚拟环境进行管理,若是只拿来跑ML-Agents,考虑到虚拟环境的可操作性(比如更换python解释器脚本)及稳定性(包链接被ban),更推荐通过CMD来管理虚拟环境。

2.2 在本地环境中安装Python解释器(别忘了设置系统变量和环境变量),推荐3.6及3.7版本(亲测3.7.0版本没有问题,所有工具采用默认版本即可,流程能跑得通),Python版本过高(如3.8以上)可能会出现与虚拟环境中所使用的插件无法兼容的问题。

2.3 在本地环境中安装pip,具体方法可参考pypi官网或其他论坛。

2.4 若Python及pip都安装成功,可在CMD中输入下列命令进行校验,若出现下列结果则证明安装无误。

pip -V
Python

 2.5 跳转到1.6中新建的文件夹,在此目录中打开CMD。

 2.6 当然,也可以自行扩展一下鼠标右键菜单(Win11更新后更难用了),添加一个“CMD Here”选项。新建一个文本文件,复制以下代码进去,然后将文件后缀名改为(.reg),退出点运行一下即可。对于经常用Git或者CMD的朋友们来说还是蛮有用的。

Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\*\shell\cmdhere]
@="Cmd&Here"
[HKEY_CLASSES_ROOT\*\shell\cmdhere\command]
@="\"C:\\Windows\\System32\\cmd.exe\" "
[HKEY_CLASSES_ROOT\Folder\shell\cmdhere]
@="Cmd&Here"
[HKEY_CLASSES_ROOT\Folder\shell\cmdhere\command]
@="\"C:\\Windows\\System32\\cmd.exe\""



[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\cmd_here] 
@="在此处打开命令行"
"Icon"="cmd.exe"
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\cmd_here\command] 
@="\"C:\\Windows\\System32\\cmd.exe\"" 
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\cmdPrompt] 
@="在此处打开命令行" 
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\cmdPrompt\command] 
@="\"C:\\Windows\\System32\\cmd.exe\" \"cd %1\""
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\cmd_here]
@="在此处打开命令行"
"Icon"="cmd.exe"
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\cmd_here\command]
@="\"C:\\Windows\\System32\\cmd.exe\""

2.7 无论如何,在虚拟环境对应的目录中打开CMD,依次输入如下代码。

md python-envs %建立虚拟环境目录,名字可以自行决定
python -m venv python-envs\sample-env %建立虚拟环境,名字可以自行决定
pip install --upgrade pip %检查pip是否为最新版本

2.8 此时我们已经建立了虚拟环境,为将其激活,我们应运行虚拟环境目录/Scripts中的activate.bat文件,CMD命令如下所示(不嫌麻烦可以鼠标点)。后续每次运行ML-Agents,都需要事前激活虚拟环境。

cd /d J:\Virtual Environment\python-envs\sample-env\Scripts
%定位到虚拟环境所在文件夹,若有多个环境存在,不要搞错环境名及环境目录
activate.bat
%激活虚拟环境
cd /d J:\Unity Projects\Homemade-ML-Agent
%切换到Unity工程所在目录

2.9 仅仅有虚拟环境还不行,我们还需要配置ML-Agents所需的各类工具,如机器学习常用到的Pytorch、Numpy等等。激活虚拟环境后,在CMD中输入如下代码进行安装。由于链接可能被ban,所以在下载时应开启全局加速保证稳定性,再或是使用国内既有的开源镜像网站,如清华镜像、阿里镜像、豆瓣镜像等。工具包较大,安装时需要耐心等待。

pip3 install torch~=1.7.1 -f https://download.pytorch.org/whl/torch_stable.html

2.10 Windows系统下(默认大家都是了)运行ML-Agents还需要安装Microsoft's Visual C++ Redistributable库(Latest supported Visual C++ Redistributable downloads | Microsoft Learn),对应自己系统的版本进行选择即可。

2.11 最后一步,我们需要在虚拟环境中安装ML-Agents工具包,在CMD中输入如下代码进行安装。另注:2.9、2.10、2.11这三步都需要启动pip工具,都走到这一步了默认已经顺利安装上了。

python -m pip install mlagents==0.28.0

最后如果所有工具都安装成功,可在虚拟环境中输入如下代码核验所安装的工具列表,如图所示。

pip list

3 训练场景设置

激活虚拟环境后,打开Unity工程,建立训练环境

3.1 场景中建立空物体,Transform(1,1,1),Position(0,0,0),重命名为“TrainingArea”。

3.2 场景中建立Plane,设为TrainingArea的子物体,Transform(1,1,1),Position(0,0,0),重命名为“Floor”。

3.3 新建Cube,设为TrainingArea的子物体,Transform(1,1,1),Position(-3,0.5,-3),重命名为“Target”。

3.4 新建Sphere,设为TrainingArea的子物体,,Transform(1,1,1),Position(3,0.5,3),重命名为“RollerAgent”。

3.5 既然都是研究行人了,往场景中放点火很合理吧,Unity Asset Store中搜索Procedural fire可以发现相关资源,导入到项目中;该资源效果还说得过去,兼容性较好,最重要的是不要钱。

从零开始搭建Unity机器学习环境—Chapter2:建立行人基本行为模型_第3张图片

3.6 将Procedural fire包导入到工程中,随便拖一个预制体放到场景中,设为TrainingArea的子物体,Transform(1,1,1),Position(0,0.5,0)。各类火焰效果预制体层级比较复杂(涉及到粒子系统、Shader等组件),如果要改大小或者位置需要调整的参数较多,所以不如直接指代一个同位置的透明物体(关闭Mesh Renderer组件)作为火焰目标,预制体仅作为呈现效果。下图中绿色线框所代表的Sphere才是训练环境中与智能体进行交互的“火焰”,需注意的是,严谨起见这个Sphere最好也设为TrainingArea的子物体。

从零开始搭建Unity机器学习环境—Chapter2:建立行人基本行为模型_第4张图片

4 引入智能体行为

4.1 之前已经提到过,场景中的智能体叫RollerAgent,选中3.4中已经建立的Sphere,为其挂上一个新脚本,也命名为“RollerAgent”。

4.2 引入需要用到的命名空间,声明Agent类,声明Rigidbody。

using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;
using System.Collections.Generic;
using UnityEngine;

public class RollerAgent : Agent
{
    Rigidbody rBody;
    void Start() //保留Start方法,弃用Update方法
    {
        rBody = GetComponent();//声明刚体,并将其指定为RollerAgent物体下的刚体
    }

    public Transform Target; //定义目标对象
    public Transform Fire; //定义火焰对象

}

4.3 定义训练场景开始时所需进行的初始化操作,将智能体位置归零并将目标点移动至新的随机位置。

public override void OnEpisodeBegin() //训练场景初始化,每次训练执行一次
    {
        // 如果智能体跌落,重置其位置
        if (this.transform.localPosition.y < 0)
        {
            this.rBody.angularVelocity = Vector3.zero;
            this.rBody.velocity = Vector3.zero;
            this.transform.localPosition = new Vector3(3.0f, 0.5f, 3.0f);
        }

        // 将目标放置到随机生成的新位置
        Target.localPosition = new Vector3(Random.value * 8 - 4,
                                           0.5f,
                                           Random.value * 8 - 4);
    }

4.4 调用Sensors,为智能体赋予观察周边环境的能力。

public override void CollectObservations(VectorSensor sensor)
    {
        // 观察目标和智能体位置
        sensor.AddObservation(Target.localPosition);
        sensor.AddObservation(this.transform.localPosition);

        // 观察智能体(其实就是刚体)的运动速度
        sensor.AddObservation(rBody.velocity.x);
        sensor.AddObservation(rBody.velocity.z);
    }

4.5 定义作用力的大小,在场景启动时,为Sphere智能体配置行为模式,设置惩罚及奖励机制。

    public float forceMultiplier = 10; //由于智能体有Rigidbody组件,因此力的大小直接决定运动参数
    public override void OnActionReceived(ActionBuffers actionBuffers)
    //调用该方法需要使用MLAgents.Actuators命名空间,官方教程里没有引用
    {
        // Actions, size = 2
        Vector3 controlSignal = Vector3.zero;
        controlSignal.x = actionBuffers.ContinuousActions[0];
        controlSignal.z = actionBuffers.ContinuousActions[1];
        rBody.AddForce(controlSignal * forceMultiplier);
        //向刚体施加f = 10

        // 观察到目标点的距离,观察到火焰的距离
        float distanceToTarget = Vector3.Distance(this.transform.localPosition, Target.localPosition);
        float distanceToFire = Vector3.Distance(this.transform.localPosition, Fire.localPosition);
        // 若到达目标点,则奖励并结束场景
        if (distanceToTarget < 1.42f)
        {
            SetReward(1.0f);
            EndEpisode();
        }

        // 若从TrainingArea中摔落,则结束场景
        else if (this.transform.localPosition.y < 0)
        {
            EndEpisode();
        }
        //若距离火焰太近,则惩罚并结束场景
        else if (distanceToFire < 1.0f) //退出事件,离火太近
        {
            //SetReward(-1.0f);
            //根据需要时启用,在当前情景设置下开不开差别不大
            EndEpisode();
        }
    }
}

4.6 扩展:为智能体class添加计算时间成本的方法

首先,在类脚本开头定义两个DateTime变量。

    DateTime startTime;
    DateTime CurrentTime;

在每次训练场景开始的时候为startTime赋值。

    public override void OnEpisodeBegin()
    {
        startTime = DateTime.Now;
    }

在训练场景的每一帧为CurrentTime赋值,同时计算其与startTime差值(格式为秒数,以方便计算惩罚的数值)。这里GetSubSecends方法我们单独抽出来写。

public override void OnActionReceived(ActionBuffers actionBuffers)
{
    CurrentTime = DateTime.Now;
    float TimeSpan = GetSubSeconds(startTime, CurrentTime);
}

定义GetSubSecends方法,定义CalculateTimeCost方法,在Agent类的最后添加如下代码。

    public void CalculateTimeCost(float CostedTime)
    {
        float TimeLength = CostedTime;
        float Punishment = -0.001f * TimeLength;
        SetReward(Punishment);
    }
    public int GetSubSeconds(DateTime startTimer, DateTime endTimer)
    {
        TimeSpan startSpan = new TimeSpan(startTimer.Ticks);

        TimeSpan nowSpan = new TimeSpan(endTimer.Ticks);

        TimeSpan subTimer = nowSpan.Subtract(startSpan).Duration();

        //返回间隔秒数(不算差的分钟和小时等,仅返回秒与秒之间的差)
        //我们的学习场景肯定是用不上了
        //return subTimer.Seconds;

        //返回相差时长(算上分、时的差值,返回相差的总秒数)
        return (int)subTimer.TotalSeconds;
    }

4.7 为场景中智能体配置目标对象及火焰对象,即将Target物体及FireTarget物体(用于代表火焰的圆球)拖拽至Inspector面板中的对应位置。

从零开始搭建Unity机器学习环境—Chapter2:建立行人基本行为模型_第5张图片

4.8 在为智能体添加各种组件及脚本,随后通过Inspector面板中配置智能体参数。新添加的脚本应包括Decision Requester以及Behavior Parameters,设置完成的Inspector界面应当如下图所示。

从零开始搭建Unity机器学习环境—Chapter2:建立行人基本行为模型_第6张图片 

4.9 通过yaml文件对学习训练过程进行配置。打开1.5中已经在工程目录下建立的config文件夹,在其中新建文本文件,添加以下内容后将文件后缀名改为.yaml。

behaviors:
  RollerBall:
    trainer_type: ppo
    hyperparameters:
      batch_size: 10
      buffer_size: 100
      learning_rate: 3.0e-4
      beta: 5.0e-4
      epsilon: 0.2
      lambd: 0.99
      num_epoch: 3
      learning_rate_schedule: linear
      beta_schedule: constant
      epsilon_schedule: linear
    network_settings:
      normalize: false
      hidden_units: 128
      num_layers: 2
    reward_signals:
      extrinsic:
        gamma: 0.99
        strength: 1.0
    max_steps: 500000
    time_horizon: 64
    summary_freq: 10000

5 开始训练

至此,我们已经完成了所有前期准备工作,打开Unity工程,激活虚拟环境,输入如下代码即可激活ML-Agents组件。在看到Unity标志后,在Editor中运行场景便可开始训练智能体。

mlagents-learn config/rollerball_config.yaml --run-id=RollerBall --force
%如果不是首次运行且需要覆盖之前运行结果,则应启用--force参数,反之则不需要
%yaml文件路径必须与与之前所配置的参数文件对应上

6 查看训练结果

在训练结束或中途推出后,可通过如下代码查看训练数据。

tensorboard --logdir results

一般来说,训练数据的本地端口不变,可在浏览器中打开如下链接查看训练数据。

http://localhost:6006/

需注意的是,训练会产生大量垃圾文件,何况每次训练并不能保证达到理想的效果,因此需要不定期清理ML-Agents工具产生的缓存,地址如下所示。

C:\Users\"用户名"\AppData\Local\pip

你可能感兴趣的:(人工智能)