行业资讯

Unity ML-Agents入门实战:从零搭建强化学习训练环境与AI智能体

发布时间:2026/7/30 14:51:28
Unity ML-Agents入门实战:从零搭建强化学习训练环境与AI智能体 1. 项目概述为什么选择Unity ML-Agents作为游戏AI的起点如果你是一个游戏开发者或者对AI如何“玩”游戏感兴趣那么Unity ML-Agents绝对是你绕不开的一个工具包。它不是一个简单的插件而是一个桥梁将Unity这个强大的实时3D内容创作平台与主流的机器学习框架如PyTorch连接起来。简单来说它让你能在自己熟悉的Unity编辑器里搭建一个虚拟的“训练场”然后看着AI智能体从零开始通过试错学会走路、跳跃、射击甚至制定复杂的策略。我最初接触ML-Agents是因为厌倦了为NPC编写繁琐的、基于规则的状态机。一个巡逻的敌人你需要写“如果看到玩家就追击如果距离小于5米就攻击如果血量低于20%就逃跑……”这样的代码不仅冗长而且行为僵硬玩家很容易找到规律。ML-Agents提供了一种可能性让AI自己去学习最优的行为策略。这听起来很酷但入门时官方文档和零散的教程往往让人望而却步特别是环境配置和训练流程每一步都可能藏着坑。所以这篇内容的目标非常明确我们不谈高深的理论就从零开始手把手带你搭建一个能跑起来的训练环境并完成一个最简单的AI训练案例。你会学到如何配置Python环境、安装ML-Agents包、在Unity中设置一个基础的训练场景以及如何启动训练并观察AI的进化过程。整个过程我会穿插我踩过的坑和总结的经验确保你能避开那些让我头疼了好几个小时的问题。无论你是想为游戏增加更智能的敌人还是单纯想探索强化学习在游戏中的应用这篇实战指南都能给你一个坚实的起点。2. 环境搭建避开版本地狱的精准配置万事开头难对于ML-Agents来说这个“难”几乎都集中在环境配置上。Unity版本、Python版本、PyTorch版本、ML-Agents包版本这四个家伙必须严丝合缝地对上否则你会遇到各种千奇百怪的报错。我建议你严格按照我下面的步骤来这是我经过多次“版本冲突”洗礼后总结出的最稳定组合。2.1 Unity项目与编辑器版本选择首先我们需要一个干净的Unity项目。我强烈建议你不要在你现有的复杂游戏项目里直接尝试ML-Agents新建一个空项目来学习是最稳妥的。Unity版本ML-Agents对Unity版本有一定要求。经过实测Unity 2022.3 LTS长期支持版是目前兼容性最好的选择之一。LTS版本稳定社区支持多能避免很多新版本才有的奇怪问题。你可以通过Unity Hub直接安装这个版本。创建项目打开Unity Hub点击“新建项目”。模板选择“核心Core”下的“3DURP”或“3D”即可。给项目起个名字比如“MLAgentsFirstDemo”。URP通用渲染管线是较新的渲染方案但对于我们做AI训练来说内置管线或URP区别不大选择你熟悉的即可。创建好项目后先别急着做别的。我们需要安装ML-Agents的Unity包。传统的方式是下载.unitypackage文件导入但现在更推荐使用Unity的Package Manager。在Unity编辑器中点击顶部菜单栏的Window-Package Manager。在Package Manager窗口左上角点击“”按钮选择“Add package from git URL...”。输入ML-Agents官方仓库的Git地址https://github.com/Unity-Technologies/ml-agents.git?pathcom.unity.ml-agents点击“Add”。Unity会开始从Git仓库下载并安装ML-Agents包。这个过程可能需要一点时间取决于你的网络。注意这里安装的是ML-Agents的核心运行时Runtime部分它负责在Unity中定义智能体、收集观测、执行动作。而训练大脑Brain的部分是由我们后面配置的Python环境来完成的。这种设计将游戏模拟Unity和模型训练Python解耦非常灵活。2.2 Python环境与关键库安装这是最容易出错的一步。请暂时忘掉你系统里可能已经安装的Python。Python版本必须使用Python 3.8.x 或 3.9.x。Python 3.10及以上版本在安装某些依赖时可能会遇到兼容性问题。我推荐使用Python 3.8.10这是经过大量项目验证的稳定版本。安装工具我强烈推荐使用Anaconda或Miniconda来管理Python环境。它可以为你创建独立的虚拟环境避免污染系统环境也方便你为不同项目切换不同的Python版本和库版本。去Anaconda官网下载安装即可。创建并激活虚拟环境# 打开命令行Windows用Anaconda PromptMac/Linux用终端 # 创建一个名为mlagents的新环境并指定Python版本为3.8 conda create -n mlagents python3.8 # 激活这个环境 conda activate mlagents激活后你的命令行提示符前面应该会显示(mlagents)表示你正在这个虚拟环境中操作。接下来安装核心的mlagents包。官方推荐使用pip安装。# 确保你在 (mlagents) 环境下 pip install mlagents这个命令会安装mlagents包及其核心依赖其中最重要的是PyTorch。mlagents包会自动安装一个与之兼容的PyTorch CPU版本。对于入门学习和大多数简单训练场景CPU版本完全足够。如果你想用GPU加速训练当你的环境非常复杂、智能体很多时你需要手动安装对应CUDA版本的PyTorch但这会引入额外的配置复杂度我们入门阶段先不涉及。实操心得安装mlagents时网络问题可能导致超时或失败。你可以尝试使用国内的镜像源来加速例如pip install mlagents -i https://pypi.tuna.tsinghua.edu.cn/simple如果安装后在后续步骤中遇到与PyTorch相关的错误可以尝试先卸载再直接用mlagents推荐的版本重装pip uninstall torch torchvision torchaudio pip install mlagents --force-reinstall安装完成后验证一下是否成功。在命令行输入mlagents-learn --help如果能看到一长串帮助信息而没有报“命令未找到”的错误那么恭喜你Python侧的ML-Agents训练工具就安装成功了。3. 第一个训练场景让小球滚向目标理论说再多不如动手做一遍。我们将创建一个经典到不能再经典的ML-Agents入门示例RollerBall滚球。在这个场景里一个球体智能体需要在一个平台上学习移动并触碰到随机生成的目标方块奖励物。我们将完整地走一遍流程创建环境、编写智能体脚本、配置训练参数、启动训练。3.1 构建Unity训练场景回到Unity编辑器。创建地面在Hierarchy窗口右键 - 3D Object - Plane重命名为Ground。可以稍微缩放一下比如Scale设置为 (3, 1, 3)让它大一点。创建智能体小球右键 - 3D Object - Sphere重命名为RollerAgent。将其位置Position的Y设为0.5这样它就会悬在地面之上。创建目标右键 - 3D Object - Cube重命名为Target。将其Scale缩放为 (0.5, 0.5, 0.5)让它小一点。给它换一个醒目的颜色比如红色。在Inspector窗口点击Add Component添加一个Rigidbody组件。勾选Is Kinematic这样它就不会受物理力影响而乱跑。创建空物体作为智能体父对象在Hierarchy中右键 - Create Empty重命名为TrainingArea。将Ground、RollerAgent和Target都拖拽成为TrainingArea的子物体。这样做的目的是当我们后续需要重置环境比如一局训练结束时可以方便地整体管理或重新生成这个区域。现在场景看起来应该是一个平台上有一个小球和一个红色小方块。3.2 编写智能体C#脚本这是核心的一步。我们需要创建一个脚本告诉Unity这个RollerAgent是谁它如何观察环境它能做什么动作以及它做对了或做错了会得到什么奖励。在Project窗口右键 - Create - C# Script命名为RollerAgent。双击用代码编辑器打开将内容完全替换为以下代码using UnityEngine; using Unity.MLAgents; // ML-Agents核心命名空间 using Unity.MLAgents.Sensors; // 用于观测 using Unity.MLAgents.Actuators; // 用于执行动作 using System; public class RollerAgent : Agent { public Transform target; // 目标物体的Transform将在Unity编辑器中赋值 Rigidbody rBody; // 小球自身的刚体组件 public override void Initialize() { // 初始化获取刚体组件 rBody GetComponentRigidbody(); } public override void OnEpisodeBegin() { // 每一局训练开始时调用用于重置环境 // 如果小球掉下去了把它拉回平台中央 if (this.transform.localPosition.y 0) { this.transform.localPosition new Vector3(0, 0.5f, 0); this.rBody.velocity Vector3.zero; this.rBody.angularVelocity Vector3.zero; } // 随机重置目标的位置 target.localPosition new Vector3( UnityEngine.Random.Range(-4f, 4f), // X轴随机位置 0.5f, // Y轴高度 UnityEngine.Random.Range(-4f, 4f) // Z轴随机位置 ); } public override void CollectObservations(VectorSensor sensor) { // 收集观测值即AI的“眼睛” // 观测1小球自身的位置 (3个浮点数x, y, z) sensor.AddObservation(this.transform.localPosition); // 观测2目标的位置 (3个浮点数) sensor.AddObservation(target.localPosition); // 观测3小球的速度 (3个浮点数) sensor.AddObservation(rBody.velocity); // 总观测值数量 3 3 3 9 } public override void OnActionReceived(ActionBuffers actions) { // 接收来自神经网络的动作决策并执行 // 假设动作是连续值控制X和Z方向的力 Vector3 controlSignal Vector3.zero; controlSignal.x actions.ContinuousActions[0]; // 第一个连续动作值 controlSignal.z actions.ContinuousActions[1]; // 第二个连续动作值 // 施加力 rBody.AddForce(controlSignal * 10); // 计算奖励 float distanceToTarget Vector3.Distance(this.transform.localPosition, target.localPosition); // 如果离目标很近给予大量正奖励并结束本局 if (distanceToTarget 1.42f) // 1.42是一个经验值大约是小球半径方块半对角线长 { SetReward(1.0f); EndEpisode(); // 结束本局触发OnEpisodeBegin开始新一局 } // 如果小球掉下平台给予负奖励并结束本局 else if (this.transform.localPosition.y 0) { SetReward(-1.0f); EndEpisode(); } // 否则给予一个小的负奖励鼓励它尽快找到目标可选 else { SetReward(-0.001f); } } // 这是一个可选方法用于在编辑器中手动测试时用键盘控制智能体 public override void Heuristic(in ActionBuffers actionsOut) { var continuousActionsOut actionsOut.ContinuousActions; continuousActionsOut[0] Input.GetAxis(Horizontal); continuousActionsOut[1] Input.GetAxis(Vertical); } }代码解析与关键点继承自Agent这是ML-Agents智能体的基类提供了训练的生命周期钩子。Initialize: 类似于Start用于初始化获取组件。OnEpisodeBegin:至关重要。一局训练一个Episode开始时的重置逻辑。在这里我们重置小球的位置和速度并随机放置目标。随机化是强化学习训练的关键它能防止AI记住固定的位置而是学会通用的“寻找”策略。CollectObservations: 定义AI能感知到什么。我们给了它9个浮点数自己的位置(3)、目标位置(3)、自己的速度(3)。这就是AI的“观察空间”。OnActionReceived: AI大脑决策后的执行入口。actions.ContinuousActions是一个数组我们定义了两个连续动作值分别对应X和Z方向的力。AddForce施加力后物理引擎会让小球运动。然后我们计算奖励碰到目标给1分掉下平台给-1分其他情况给一个微小的负奖励称为“时间惩罚”鼓励AI提高效率。Heuristic: 启发式函数允许我们用键盘方向键控制小球在训练前测试环境逻辑是否正确。保存脚本回到Unity。选中Hierarchy中的RollerAgent小球在Inspector中点击Add Component搜索并添加我们刚写的RollerAgent脚本。然后你会看到脚本有两个公开变量需要赋值Target。将Hierarchy中的Target立方体拖拽到脚本的Target插槽上。接着给RollerAgent小球也添加一个Rigidbody组件刚体这样它才能受物理力影响。保持默认设置即可。最后我们需要为这个场景添加ML-Agents的“大脑”——Behavior Parameters组件。选中RollerAgent点击Add Component搜索Behavior Parameters并添加。Behavior Name: 填写RollerBallBehavior。这是这个智能体行为的标识符后面训练配置文件会用到。Vector Observation-Space Size: 设置为9。这就是我们CollectObservations方法里添加的观测值总数。Actions-Continuous Actions: 设置为2。对应我们OnActionReceived中使用的两个连续动作。Actions-Discrete Actions: 保持为0因为我们这个例子没用离散动作如跳跃、开火等开关型动作。至此Unity侧的设置就全部完成了。你可以先点击运行然后用方向键控制小球因为Heuristic函数看看它是否能撞到红色方块以及掉下平台后是否会重置。这是一个重要的测试确保你的基础逻辑移动、碰撞检测、重置是正常的。4. 配置与启动训练见证AI的成长环境搭好了智能体脚本也写好了现在该让AI开始学习了。我们需要一个配置文件来指导训练过程。4.1 编写训练配置文件在Unity项目的根目录下与Assets文件夹同级创建一个新的文本文件命名为rollerball_config.yaml。用文本编辑器打开输入以下内容behaviors: RollerBallBehavior: # 必须与Unity中Behavior Parameters组件的Behavior Name完全一致 trainer_type: ppo # 使用PPO算法这是目前最稳定、最常用的强化学习算法之一 hyperparameters: batch_size: 128 # 每次参数更新时使用的经验数据量 buffer_size: 2048 # 经验回放缓冲区的大小 learning_rate: 3.0e-4 # 学习率决定参数更新步长的大小 beta: 5.0e-4 # 熵系数鼓励探索防止策略过早收敛到局部最优 epsilon: 0.2 # PPO算法的裁剪参数限制每次更新的幅度使训练更稳定 lambd: 0.95 # GAE广义优势估计的参数 num_epoch: 3 # 每次更新时对缓冲区数据重复利用的轮数 learning_rate_schedule: linear # 学习率调度方式这里使用线性衰减 network_settings: normalize: true # 归一化观测值有助于稳定训练 hidden_units: 128 # 神经网络隐藏层的神经元数量 num_layers: 2 # 神经网络的隐藏层层数 reward_signals: extrinsic: gamma: 0.99 # 折扣因子决定未来奖励的重要性。0.99意味着AI会考虑较长期的回报。 strength: 1.0 # 外部奖励的权重我们只有外部奖励碰到目标1掉下去-1 max_steps: 500000 # 最大训练步数达到后训练自动停止 time_horizon: 64 # 每个智能体在更新前收集多少步的经验 summary_freq: 10000 # 每多少步记录一次训练摘要用于TensorBoard可视化这个配置文件定义了训练的所有超参数。作为初学者你不需要完全理解每一个参数的含义可以先用这套经过调优的默认参数。最关键的是behaviors下的名字RollerBallBehavior必须和Unity中Behavior Parameters组件里的一模一样。4.2 启动训练过程并监控确保你的Unity项目处于运行状态点击Play按钮。然后打开之前配置好的Anaconda命令行并激活mlagents环境。使用cd命令导航到你的Unity项目根目录即包含rollerball_config.yaml文件和Assets文件夹的目录。输入以下命令启动训练mlagents-learn rollerball_config.yaml --run-idRollerBall_FirstTrainmlagents-learn: 训练命令。rollerball_config.yaml: 指定配置文件。--run-id: 为这次训练任务起一个名字用于区分不同的训练实验。所有日志和生成的模型都会保存在以这个ID命名的文件夹下。按下回车后命令行会输出一系列信息最后会停在这样一句话[INFO] Listening on port 5004. Start training by pressing the Play button in the Unity Editor.这意味着Python端的训练服务器已经启动正在等待Unity客户端你的游戏连接。现在回到Unity编辑器点击Play按钮。你会看到命令行窗口开始疯狂滚动日志显示它正在接收数据、更新模型。同时Unity的游戏窗口里小球开始自己动起来了最初它的动作完全是随机的到处乱滚经常掉下去。但随着时间的推移通常几分钟后你会发现它逐渐变得“聪明”能够有意识地向红色方块的方向移动并且成功触碰到目标的次数越来越多。这就是强化学习在起作用AI通过不断尝试根据得到的奖励正/负来调整自己的行为策略神经网络参数最终学会完成任务。4.3 使用TensorBoard可视化训练过程训练日志看起来很枯燥我们可以用TensorBoard来直观地查看训练曲线。在刚才的命令行窗口或者新开一个同样环境的命令行导航到项目根目录运行tensorboard --logdir resultsresults文件夹是mlagents-learn命令自动创建的里面保存了每次训练以--run-id命名的日志。命令执行后会输出一个本地网址通常是http://localhost:6006。在浏览器中打开这个网址。在TensorBoard中最重要的图表是Cumulative Reward累计奖励这是训练效果的核心指标。曲线整体呈上升趋势说明AI正在学习获得的奖励越来越多。最终会稳定在一个较高的值附近。Policy Loss策略损失和Value Loss价值损失反映了神经网络训练的稳定程度。理想情况下它们应该逐渐下降并趋于平稳。如果剧烈震荡或飙升可能意味着超参数如学习率设置不当。一边看着Unity里小球的笨拙表演一边看着TensorBoard里不断爬升的奖励曲线这种成就感是无可比拟的。你会真切地感受到一个智能体正在从零开始“学会”一件事。5. 模型导出与应用从训练场到游戏世界训练了足够多的步数比如累计奖励曲线已经稳定或者达到了max_steps后训练会自动停止。你也可以在命令行按CtrlC手动中断训练。5.1 定位与使用训练好的模型训练结束后在项目根目录下会生成一个以--run-id命名的文件夹例如results/RollerBall_FirstTrain。在这个文件夹里你可以找到最终生成的模型文件通常名为RollerBallBehavior.onnx或.nn格式取决于版本。这个.onnx文件就是训练好的“大脑”。现在我们要把它放回Unity让智能体脱离Python训练环境独立运行。在Unity编辑器中停止运行再次点击Play按钮。在Project窗口创建一个文件夹比如ML-Agents用来存放模型。将results/RollerBall_FirstTrain/RollerBallBehavior.onnx文件复制到Unity项目的Assets/ML-Agents文件夹下。在Unity中选中RollerAgent小球找到它的Behavior Parameters组件。将Behavior Type从Default改为Inference推理模式。将Model字段指向你刚刚导入的RollerBallBehavior.onnx文件。现在再次点击Unity的Play按钮。你会发现小球不再需要连接Python就能自主地、智能地寻找目标了它使用的就是刚才训练好的神经网络模型进行决策。5.2 训练过程中的常见问题与排查第一次训练很少有一帆风顺的。下面是我总结的一些常见问题及解决方法问题现象可能原因排查与解决命令行报错Connection failed...Unity编辑器未运行或运行后未点击Play。1. 确保Unity项目已打开。2. 先运行mlagents-learn命令。3. 看到监听提示后再在Unity中点击Play。小球在Unity中一动不动1.Behavior Parameters中的Behavior Name与配置文件中的名字不匹配。2. 观测值Space Size或动作数Continuous Actions设置错误。3. 脚本中的OnActionReceived方法没有正确施加力。1. 仔细检查Behavior Name大小写和空格都必须一致。2. 核对Space Size是否为9Continuous Actions是否为2。3. 在Heuristic模式下用键盘测试确保基础移动逻辑正常。训练开始后累计奖励Cumulative Reward不上升甚至下降1. 奖励函数设计不合理。2. 超参数如学习率设置不当。3. 任务本身太难探索空间太大。1. 检查奖励逻辑触碰目标是否给了正奖励掉下平台是否给了负奖励奖励的数值是否合理不宜过大或过小2. 尝试降低learning_rate例如从3e-4改为1e-4。3. 简化环境比如先让目标固定不动等AI学会移动后再加入随机。TensorBoard中Policy Loss值异常高或为NaN通常意味着训练不稳定梯度爆炸。1.首要检查在Behavior Parameters组件中勾选Vector Observation下的Normalize选项或在配置文件中设置normalize: true。观测值归一化对稳定训练至关重要。2. 大幅降低learning_rate。3. 增加batch_size或buffer_size。训练速度非常慢1. 场景过于复杂渲染开销大。2. 使用了GPU训练但驱动有问题。3. 智能体数量太多。1. 训练时可以关闭或简化不必要的图形效果如阴影、后处理。在Unity的Game窗口将显示比例调低。2. 入门阶段使用CPU训练即可确保稳定。3. 我们这个例子只有一个智能体没问题。如果是多智能体需要考虑性能。实操心得关于随机种子强化学习的训练结果具有一定随机性。同样的代码和配置两次训练的结果曲线可能不完全一样。这是正常的因为环境的初始状态目标随机位置、神经网络的初始权重、智能体的随机探索都存在随机性。为了进行公平的比较实验你可以在配置文件中加入seed: 12345来固定随机种子确保每次训练的环境随机序列是一致的。6. 下一步从入门到精通的路径成功运行第一个RollerBall示例只是迈出了第一步。ML-Agents的能力远不止于此。基于这个基础你可以从以下几个方向深入设计更复杂的观测除了位置和速度你还可以让AI“看到”更多。例如使用Ray Perception Sensor组件给智能体添加射线探测让它能感知前方是否有障碍物或目标。或者直接将相机渲染的图像作为视觉观测输入这属于更高阶的“视觉强化学习”。设计更复杂的动作我们的例子只有2个连续动作力。你可以定义离散动作比如“跳跃”、“攻击”、“切换武器”。在Behavior Parameters中设置Discrete Actions并在OnActionReceived中通过actions.DiscreteActions来读取。设计更精巧的奖励函数Reward Shaping奖励函数是强化学习的“指挥棒”。除了最终的成功/失败奖励你还可以设计中间奖励。例如给一个与目标距离成反比的持续小奖励引导AI向目标靠近。但要注意奖励设计是一门艺术设计不当会导致AI学会“刷分”而不是真正解决问题。尝试多智能体ML-Agents支持在同一个环境中训练多个智能体。你可以模拟足球、捉迷藏等对抗或合作游戏。关键是为每个智能体设置相同的Behavior Name它们就会共享同一个神经网络进行学习或者通过不同的组Team ID来区分策略。使用课程学习Curriculum Learning如果任务太难AI一开始可能完全学不会。课程学习允许你由易到难地训练。例如先让目标固定不动训练到一定成功率后再让目标在小范围内随机移动最后再放到全平台随机。这可以通过编写课程学习的JSON配置文件来实现。搭建第一个可训练的环境就像是拿到了打开游戏AI大门的钥匙。过程中遇到的每一个错误解决的每一个问题都会让你对智能体、环境、奖励这些核心概念有更深的理解。最重要的是动手去做去修改代码去调整参数去观察AI行为的变化。当你看到自己创造的虚拟角色从一片混沌中诞生出有目的的行为时那种感觉正是驱动我们不断探索的动力。