本案例源自ML-Agents官方的示例,Github地址:https://github.com/Unity-Technologies/ml-agents,本文是详细的配套讲解。
本文基于我前面发的两篇文章,需要对ML-Agents有一定的了解,详情请见:Unity强化学习之ML-Agents的使用、ML-Agents命令及配置大全。
我前面的相关文章有:
ML-Agents案例之Crawler
ML-Agents案例之推箱子游戏
ML-Agents案例之跳墙游戏
ML-Agents案例之食物收集者
ML-Agents案例之双人足球
Unity人工智能之不断自我进化的五人足球赛
ML-Agents案例之地牢逃脱
ML-Agents案例之金字塔
ML-Agents案例之蠕虫
环境说明
在阅读本文之前,可以参考ML-Agents案例之Crawler、ML-Agents案例之蠕虫这两个案例。它们的目标都是一致的:吃掉绿色的方块,并且都是仿生机器人,区别是仿生的对象不一样,之前是仿爬虫和蠕虫,这一次是直接仿人。因此,本案例是之前两个案例的高配版,机器人的关节要比以往多得多,这将导致输入和输出维度上的急剧增加,这对训练来说是一项巨大的挑战,导致找到一个好的策略称为一项艰难的任务。
现在我们看看机器人的构造:
可以看到,相比于现实中的人,Unity中的机器人已经在关节上做到尽量简化了,例如:锁死了手腕的关节,没有手指脚趾,脊椎当成一个关节等。但是剩余的关节数目仍然是一个比爬虫大得多的数目。
我们查看其物体列表,发现整个人以臀部作为所有部位的父物体。然后臀部上挂的子物体有左腿、右腿、躯干,它们的关节链接的都是臀部。如下腰部连接臀部:
可以看到腰部的关节的x,y,z三个轴都是可以转动的,因为人的腰在生理构造上是既可以前后倾,也能左右倾,还能左右扭腰。我们可以通过Edit Angular Limits可视化修改其可以转动的幅度。
左右腿同理,连接臀部,但是自由度z轴旋转被锁定,这是因为人腿部并不能做到像腰一样左右扭动。
每一条腿除了和臀部连接的关节外,还有膝盖和脚踝两个关节。
膝盖只有一个x轴能够旋转,即一个自由度,连接的是大腿部。
同样的,脚踝三个轴都能旋转,连接的是小腿部。
现在我们再来看看躯干部分的各个关节,整个躯干的父物体是腹部。
首先是脊椎,也是胸部的关节,连接的是腹部,x,y,z轴皆可旋转。
然后链接胸部的有三个部位,分别是左手,右手,头部。
先看看头部,头部是两个轴的自由度。
然后是手部,左手右手一样,胳膊上有一个关节,两个轴的自由度(个人认为应该有三个轴的自由度),连接胸部。手肘上有一个关节,一个自由度,连接上臂。
到此为止,上面讲解的就是我们接下来要控制的关节了。同样,想要控制各个关节的运动,我们需要在智能体上挂载一个JointDriveController.cs的脚本,这个脚本不会自己运作,只有在别的脚本的调用下才会起作用。关于这个脚本的代码说明参考ML-Agents案例之Crawler。
我们在进行深度强化学习训练时,智能体接收的状态输入为:目标速度与身体平均速度的距离,一维。指向方块坐标下的身体速度和目标速度,六维。头部方向到目标方向的旋转,四维。整个身体面朝方向到目标方向的旋转,四维。目标方块相对于智能体的坐标,三维。每节躯体的移动速度、角速度、是否接触地面、相对于臀部的位置,16 * 10维。每个关节的力度、局部坐标的旋转,13 * 5维。一共是243维。
动作输出:我们一共有13个关节需要控制,加起来是26个轴的自由度,再加上控制13个轴的力度,所以一共是39维的连续输出。
代码讲解
参数设置:
private float m_TargetWalkingSpeed = 10;
public float MTargetWalkingSpeed
{
get {
return m_TargetWalkingSpeed; }
set {
m_TargetWalkingSpeed = Mathf.Clamp(value, .1f, m_maxWalkingSpeed); }
}
const float m_maxWalkingSpeed = 10;
public bool randomizeWalkSpeedEachEpisode;
private Vector3 m_WorldDirToWalk = Vector3.right;
// 目标方块
[Header("Target To Walk Towards")] public Transform target;
// 身体的各个部位
[Header("Body Parts")] public Transform hips;
public Transform chest;
public Transform spine;
public Transform head;
public Transform thighL;
public Transform shinL;
public Transform footL;
public Transform thighR;
public Transform shinR;
public Transform footR;
public Transform armL;
public Transform forearmL;
public Transform handL;
public Transform armR;
public Transform forearmR;
public Transform handR;
// 指向方块的设置为一个稳定的空间参考点,可以提高学习效果
OrientationCubeController m_OrientationCube;
// 脚下的箭头指示器的脚本
DirectionIndicator m_DirectionIndicator;
// 关节控制脚本
JointDriveController m_JdController;
// 环境参数,可从配置文件中获取
EnvironmentParameters m_ResetParams;
初始化方法Initialize():
public override void Initialize()
{
// 获取三个脚本
m_OrientationCube = GetComponentInChildren
m_DirectionIndicator = GetComponentInChildren
m_JdController = GetComponent
// 初始化16个身体部位
m_JdController.SetupBodyPart(hips);
m_JdController.SetupBodyPart(chest);
m_JdController.SetupBodyPart(spine);
m_JdController.SetupBodyPart(head);
m_JdController.SetupBodyPart(thighL);
m_JdController.SetupBodyPart(shinL);
m_JdController.SetupBodyPart(footL);
m_JdController.SetupBodyPart(thighR);
m_JdController.SetupBodyPart(shinR);
m_JdController.SetupBodyPart(footR);
m_JdController.SetupBodyPart(armL