ml-agent是unity中用于将机器学习算法嵌入到gameobject的一个插件。在我的游戏项目中,我想尝试将机器学习和深度学习算法带入到游戏中,让游戏角色能够利用我们给出的数据自动通关,因此想到尝试使用这个插件。写下这个帖子供也用到mlagent的入门同学进行学习参考。ml-agent的详细内容可以参照官方文档,里面也有详细的英文介绍和入门教程(中文版的维护的并不太好,所以学习主要以英文为主)。
环境搭建
环境搭建主要是安装配置unity以及anaconda,这些教程网络很多,这里不赘述。
ml-agent包下载
下载ml-agents插件和安装所需要的包 可以通过git下载,也可以通过直接去ml-agents插件地址下载
git clone https://github.com/Unity-Technologies/ml-agents.git
下载完成后开始安装所需要的包。
pip install mlagents?
训练最简单的例子3DBall
打开uinty,插件的项目在Project里,在场景中找到3DBall就可以进入到该场景中。
之后在命令行把目录切换到根目录下,切记,否则可能出现找不到文件,因为他会去config下找trainer_config.yaml文件,如果在其他目录下会找不到。然后在命令行输入
mlagents-learn config/trainer_config.yaml --run-id=3dball --train??
如果没有报错,那么命令行会提醒你在unity中点击开始按钮就会开始训练了。
训练
这个是训练前的情况,可以看到小球很容易就掉到盒子下方了。(中间的卡顿是训练周期结束重置造成的)。
这个经历了20000次左右训练之后的,盒子基本可以控制住小球不掉落,越多的训练小球能够保持得更稳。
代码分析
游戏中的机器学习主要分为几个步骤:接口抽离、算法选取、设计环境、参数调整。环境已经又unity调整好了,所以这里不多说,参数调整也不是这里的重点,主要聊聊接口抽离和算法的选取。
接口抽离
- Initialize ()函数相当于 Start()函数,获取小球的刚体。
public override void Initialize()
{
m_BallRb = ball.GetComponent<Rigidbody>();
m_ResetParams = Academy.Instance.EnvironmentParameters;
SetResetParameters();
} - OnEpisodeBegin()新一段开始函数,可以重置小球坠落出界后的重新开始的位置,以及 Cube 重新开始的一定范围的随机旋转。
public override void OnEpisodeBegin()
{
gameObject.transform.rotation = new Quaternion(0f, 0f, 0f, 0f);
gameObject.transform.Rotate(new Vector3(1, 0, 0), Random.Range(-10f, 10f));
gameObject.transform.Rotate(new Vector3(0, 0, 1), Random.Range(-10f, 10f));
m_BallRb.velocity = new Vector3(0f, 0f, 0f);
ball.transform.position = new Vector3(Random.Range(-1.5f, 1.5f), 4f, Random.Range(-1.5f, 1.5f))
+ gameObject.transform.position;
//Reset the parameters when the Agent is reset.
SetResetParameters();
} - CollectObservations()观察变量,包括球相对于Cube 的相对位置、球的速度、Cube X Z 的旋转。
public override void CollectObservations(VectorSensor sensor)
{
if (useVecObs)
{
sensor.AddObservation(gameObject.transform.rotation.z);
sensor.AddObservation(gameObject.transform.rotation.x);
sensor.AddObservation(ball.transform.position - gameObject.transform.position);
sensor.AddObservation(m_BallRb.velocity);
}
} - OnActionReceived ()改变 Cube XZ的两个变量,球出界的判断,以及设置奖励。
public override void OnActionReceived(ActionBuffers actionBuffers)
{
var actionZ = 2f * Mathf.Clamp(actionBuffers.ContinuousActions[0], -1f, 1f);
var actionX = 2f * Mathf.Clamp(actionBuffers.ContinuousActions[1], -1f, 1f);
if ((gameObject.transform.rotation.z < 0.25f && actionZ > 0f) ||
(gameObject.transform.rotation.z > -0.25f && actionZ < 0f))
{
gameObject.transform.Rotate(new Vector3(0, 0, 1), actionZ);
}
if ((gameObject.transform.rotation.x < 0.25f && actionX > 0f) ||
(gameObject.transform.rotation.x > -0.25f && actionX < 0f))
{
gameObject.transform.Rotate(new Vector3(1, 0, 0), actionX);
}
if ((ball.transform.position.y - gameObject.transform.position.y) < -2f ||
Mathf.Abs(ball.transform.position.x - gameObject.transform.position.x) > 3f ||
Mathf.Abs(ball.transform.position.z - gameObject.transform.position.z) > 3f)
{
SetReward(-1f);
EndEpisode();
}
else
{
SetReward(0.1f);
}
} - Heuristic ()在 HeuristicOnly 模式操作小球的输入,这里是水平竖直Axis 操纵。
public override void Heuristic(in ActionBuffers actionsOut)
{
var continuousActionsOut = actionsOut.ContinuousActions;
continuousActionsOut[0] = -Input.GetAxis("Horizontal");
continuousActionsOut[1] = Input.GetAxis("Vertical");
}
算法选取
这里使用的是PPO(Proximal Policy Optimization)算法,是一种新型的Policy Gradient算法。Policy?Gradient不通过误差反向传播,它通过观测信息选出一个行为直接进行反向传播,当然出人意料的是他并没有误差,而是利用reward奖励直接对选择行为的可能性进行增强和减弱,好的行为会被增加下一次被选中的概率,不好的行为会被减弱下次被选中的概率。
Policy?Gradient算法对步长十分敏感,但是又难以选择合适的步长,在训练过程中新旧策略的的变化差异如果过大则不利于学习。PPO提出了新的目标函数可以再多个训练步骤实现小批量的更新,解决了Policy?Gradient算法中步长难以确定的问题。
拓展
通过这个入门案例可以将思路拓展到更多的游戏。这种强化学习的思想是让计算机在不断尝试中,以获得最优学习结果的前提下,找到每个状态下的最优行为,也称作马尔可夫学习过程。ml-agent官方也提供了很多应用场景,可以在包中自行尝试。
?
|