Gymnasium MuJoCo 连续控制环境完整实战指南:从 5 行代码到造出自己的机器人
2026/9/13 9:44:09 网站建设 项目流程

Gymnasium MuJoCo 连续控制环境完整实战指南:从 5 行代码到造出自己的机器人

【免费下载链接】GymnasiumA standard API for single-agent reinforcement learning environments, with popular reference environments and related utilities (formerly Gym)项目地址: https://gitcode.com/GitHub_Trending/gy/Gymnasium

如果你只训练过离散环境,Gymnasium 的 MuJoCo 环境就是连续控制的入口:几行 Python 就能让一只小猎豹跑起来,一套完整训练闭环能看着奖励曲线从零爬升。本文带你从能跑起来的代码,一路走到自定义环境。

五分钟跑通第一个 MuJoCo 环境:HalfCheetah 的最小循环 🐆

假设你刚装好依赖:

pip install "gymnasium[mujoco]"

现在打开 Python,把下面这段原样跑一遍:

import gymnasium as gym env = gym.make("HalfCheetah-v5") obs, info = env.reset(seed=42) print(obs.shape) # (17,) print(info) # {'x_position': -0.262...} action = env.action_space.sample() # 随机采样一个动作 obs, reward, terminated, truncated, info = env.step(action) print(reward) # 例如 0.42 print(info) # 含 x_position / x_velocity / reward_forward / reward_ctrl env.close()

逐行拆一下发生了什么:

  • gym.make("HalfCheetah-v5")从注册表实例化环境。它是一只二维的"半截猎豹":躯干和头固定,6 个关节(前后大腿、小腿、脚)能施加扭矩,目标就是往右跑得越快越好。
  • env.reset(seed=42)把机器人放回初始姿态并加一点随机噪声,返回(obs, info)。注意 0.26 之后reset()返回的是二元组而不是单个观测。
  • obs.shape(17,),一个 float64 向量。它其实就是"位置 + 速度"的拼接:7 个关节角度加躯干高度等 8 个 qpos(位置),9 个 qvel(速度)。
  • env.action_space.sample()Box(-1, 1, (6,))里随机抽一个 6 维向量——相当于给 6 个关节随机拧一下力矩。
  • step()返回五元组:新观测、标量奖励、terminated(任务是否"失败"结束)、truncated(是否到时间上限)、info(诊断信息)。

这就是全部循环:观测进、动作出、拿奖励。训练强化学习,就是让这个"随机拧一下"逐步变成"知道怎么拧"。

读懂环境信号:HalfCheetah 的 17 维观测里装了什么

刚拿到obs时最容易犯的错误,是把它当成"一团数字"。其实 Gymnasium 的 MuJoCo 环境里,观测和动作都有清晰的物理含义。

信号形状 / 范围含义
obs(17,), float64前 8 项是 qpos(各关节角度、躯干高度等位置),后 9 项是 qvel(对应速度)
actionBox(-1, 1, (6,)), float326 个关节的归一化扭矩,环境内部再映射成牛顿米
reward标量前进速度奖励 - 0.1 × ‖action‖²,往前跑加分、用力过猛扣分
terminated恒为FalseHalfCheetah 永远不会"摔倒",只有 1000 步后truncated=True

三个值得注意的设计细节:

位置被故意藏起来了。17 维里没有躯干的前后坐标rootx——因为奖励本身就算自前进速度,直接喂位置等于把答案抄给智能体。想拿位置,看info["x_position"]即可。这个取舍可以开关:gym.make("HalfCheetah-v5", exclude_current_positions_from_observation=False)会得到 18 维观测。

奖励是拆解过的。每步info里都有reward_forwardreward_ctrl两项。调试"为什么奖励上不去"时,先看这两项谁在拖后腿,比盯着总奖励猜要快得多。

v5 帮你标注了观测结构。env.observation_structure直接告诉你哪些维度是 qpos、哪些是 qvel,做自定义 wrapper 时非常省事。

对比另一个环境更能体会差异:InvertedPendulum-v5的奖励是"每保持直立 0.2 弧度以内一步 +1",且摔倒立刻terminated=True。同样是"位置+速度"的观测,任务性质从"耐力跑"变成了"走钢丝"。

环境选型指南:从哪个 MuJoCo 环境开始训练

第一次做连续控制,最忌讳一上来就冲 Humanoid——21 维动作、全身协调,奖励曲线能让你怀疑人生。选环境的依据其实就三条:动作维度、有没有摔倒终止、你想对标什么论文。

先定动作维度预算。维度直接决定训练难度:

  • 1~2 维:InvertedPendulum-v5(1 维)、InvertedDoublePendulum-v5(2 维)、Reacher-v5(2 维)
  • 3~6 维:Hopper-v5(3 维)、Pusher-v5(3 维)、Swimmer-v5(5 维)、HalfCheetah-v5(6 维)、Walker2d-v5(6 维)
  • 8 维及以上:Ant-v5(8 维)、Humanoid-v5/HumanoidStandup-v5(21 维)

再看有没有"摔倒"终止。HalfCheetah永不终止,奖励曲线平滑,最适合当第一个 locomotion 任务;HopperWalker2dHumanoid一旦摔倒就提前截断,回合长度忽长忽短,奖励曲线天然带噪声——这对调算法是好事,但对刚上手的人是干扰。

最后看你想要什么。验证代码管线、快速看到收敛:选InvertedPendulum-v5(4 维观测、1 维动作,仓库官方教程就用它做 REINFORCE 示例,见 docs/tutorials/training_agents/mujoco_reinforce.py)。想学奔跑控制:HalfCheetah-v5。想摸 3D 操作(manipulation):Reacher-v5入门、Pusher-v5进阶。要发论文做对比:Ant-v5Humanoid-v5是 PPO/SAC 论文的标配基准。

一句话决策链:调试期用 InvertedPendulum,正式开跑用 HalfCheetah,冲基准上 Ant/Humanoid。另外所有环境都有 v4/v5 两代,新研究直接用-v5(mujoco>=2.3.3,特性最全);要复现旧文献结果再考虑 v4。

采样提速三板斧:渲染模式、向量化与无头后端 ⚡

训练 MuJoCo 环境时,真正的瓶颈往往不是算法而是环境采样速度。三板斧按收益排序:

第一斧:训练时别开渲染。窗口渲染会实打实地拖慢每一步:

train_env = gym.make("HalfCheetah-v5") # 训练:不渲染,最快 eval_env = gym.make("HalfCheetah-v5", render_mode="human") # 评估:弹窗看效果

想留训练过程当证据,用视频录制代替实时窗口:

from gymnasium.wrappers import RecordVideo video_env = RecordVideo( gym.make("HalfCheetah-v5", render_mode="rgb_array"), video_folder="./videos", )

第二斧:向量化环境并行采样。PPO 这类算法一个 update 要吃上千步样本,8 个环境并行跑比单环境快得多:

from gymnasium.vector import SyncVectorEnv envs = SyncVectorEnv([lambda: gym.make("HalfCheetah-v5") for _ in range(8)]) obs, infos = envs.reset(seed=42) actions = envs.action_space.sample() # 一次给 8 个环境各抽一个动作 obs, rewards, terminateds, truncateds, infos = envs.step(actions) print(obs.shape) # (8, 17)

多核机器上可以再换成AsyncVectorEnv,用多进程进一步并行。

第三斧:无头图形后端。服务器上根本没有显示器,默认后端会报错或卡死。MuJoCo 用MUJOCO_GL环境变量切换后端:

后端设置方式适用场景
GLFWMUJOCO_GL=glfw(默认)本地开发,带窗口的 GPU 渲染
EGLMUJOCO_GL=egl服务器无头 + GPU,推荐
OSMesaMUJOCO_GL=osmesa无 GPU 的纯 CPU 渲染,兼容性最好
export MUJOCO_GL=egl python train.py

三者叠加之后,一个 4 环境并行的 PPO 训练,环境侧基本不再是短板。

完整训练闭环:用 PPO 训练 HalfCheetah 并读懂奖励曲线

采样提速之后,来看一个能落地的完整闭环:训练 → 监控 → 评估。算法选 PPO,工具选 Stable-Baselines3,它是 Gymnasium 生态里最顺手的连续控制搭档。

训练。核心就这几行:

import gymnasium as gym from stable_baselines3 import PPO from stable_baselines3.common.callbacks import EvalCallback env = gym.make("HalfCheetah-v5") model = PPO("MlpPolicy", env, n_steps=1024, batch_size=64) model.learn(total_timesteps=1_000_000)

监控。EvalCallback周期性在独立评估环境里打分并保存最优权重,比盯着训练奖励靠谱:

eval_env = gym.make("HalfCheetah-v5") cb = EvalCallback(eval_env, best_model_save_path="./best", eval_freq=10_000) model.learn(1_000_000, callback=cb)

评估。评估一定多跑几个回合取平均,单回合在 MuJoCo 环境里噪声很大:

rewards = [] for _ in range(10): obs, _ = env.reset() total, done = 0.0, False while not done: action, _ = model.predict(obs) obs, r, terminated, truncated, _ = env.step(action) total += r done = terminated or truncated rewards.append(total) print(f"10 回合平均奖励: {sum(rewards)/10:.1f}")

怎么读奖励曲线。下面这张是 Gymnasium 官方教程里 REINFORCE 训练InvertedPendulum的曲线(5 条运行叠加),形态对所有连续控制任务通用:

  • 前 1000 回合贴着 0:策略基本在瞎探索,别急着调参。
  • 中段陡升:学到了"基本姿势"。曲线陡峭程度取决于任务难度,InvertedPendulum 五千多回合就能摸到满分 1000 附近,HalfCheetah 则要在百万步级别才见平台期。
  • 多条曲线之间的散度是随机性,不是 bug——初始状态噪声 + 策略初始化噪声都会体现在这。
  • 后半段围绕一个平台震荡:那是策略上限了,继续加步数收益递减,该去看评估环境里的平均数而不是训练曲线本身。

踩坑排查手册:MuJoCo 环境的 5 个高频问题

Q1:种子都固定了,为什么两次跑出来还是不一样?env.reset(seed=42)只固定了初始状态噪声。策略网络的初始化是另一套随机源,还要torch.manual_seed(42)/np.random.seed(42)一起管。另外 MuJoCo 官方说明过:不同版本的mujoco包因浮点运算顺序,结果会有微小差异——严格复现要连mujoco的版本号一起锁死。

Q2:服务器上报错或渲染卡死怎么办?十有八九是后端问题。服务器没有窗口系统,默认的 GLFW 会出问题:export MUJOCO_GL=egl用 GPU 无头渲染,或MUJOCO_GL=osmesa走 CPU。再检查一点:训练脚本里是不是不小心写了render_mode="human",有窗口的渲染能把采样拖慢几倍。

Q3:奖励变 NaN、terminated全 True,机器人"炸了"?这是状态数值溢出(MuJoCo 环境对非有限状态直接判终止)。按顺序排查:网络输出没压缩到[-1, 1](用tanh或动作缩放 wrapper);观测没归一化(gymnasium.wrappers.NormalizeObservation);学习率过大。三者占齐前两个,大多数"爆炸"都能救回来。

Q4:随机策略的奖励为什么低得离谱?正常。随机动作下的 HalfCheetah 基本在原地扑腾,平均奖励接近 0 甚至为负。想快速 sanity check,直接看info["x_position"]是否随回合缓慢漂移,比看总奖励直观。

Q5:不同环境的奖励数值不能直接比?对。InvertedPendulum一步最多 +1,满回合 1000 分;HalfCheetah满回合几百;Humanoid是几百上千的量级。跨环境谈"我的算法更强"之前,先统一到各自的评估协议(多回合平均、固定种子),否则比的是奖励标度。

造一个自己的 MuJoCo 环境:XML 模型 + 继承 MujocoEnv

当你想换一个机器人、改一个任务规则,就有两条路,难度差一个数量级。

轻量路线:只换模型。v5 的环境类全部支持xml_file参数,直接把自己的 XML 塞给现成环境:

env = gym.make("HalfCheetah-v5", xml_file="my_cheetah.xml")

观测空间会按新模型的 qpos/qvel 维度自动重建,不用改 Python 代码。参考模型都在 gymnasium/envs/mujoco/assets/ 下,XML 骨架长这样:

<mujoco> <option timestep="0.01" gravity="0 0 -9.81"/> <worldbody> <light pos="0 0 3" dir="0 0 -1"/> <geom name="floor" type="plane" size="5 5 0.1"/> <body name="cart"> <joint name="slide" type="slide" axis="1 0 0"/> <geom type="capsule" size="0.1 0.2" mass="1"/> </body> </worldbody> <actuator><motor joint="slide" gear="3"/></actuator> </mujoco>

三个关键标签:<joint>给自由度(每对 qpos/qvel),<geom>定义碰撞与外观,<actuator>决定动作维度和控制强度。

重量路线:自定义环境类。换任务规则(比如"推到指定位置给奖励")时,继承MujocoEnv并实现观测、奖励、终止、重置几个钩子,物理推进直接复用基类的do_simulation

import numpy as np from gymnasium.envs.mujoco import MujocoEnv class MyCartEnv(MujocoEnv): def __init__(self): super().__init__(xml_file="my_cart.xml", frame_skip=5) def _get_obs(self): return np.concatenate([self.data.qpos, self.data.qvel]) def _get_rew(self, x_velocity, action): return x_velocity - 0.1 * np.sum(np.square(action)), {} def _get_terminated(self): return bool(np.any(~np.isfinite(self.data.qpos))) def step(self, action): before = self.data.qpos[0] self.do_simulation(action, self.frame_skip) x_vel = (self.data.qpos[0] - before) / self.dt reward, info = self._get_rew(x_vel, action) return (self._get_obs(), reward, self._get_terminated(), False, info)

完整实现对照 gymnasium/envs/mujoco/mujoco_env.py 和 gymnasium/envs/mujoco/half_cheetah_v5.py 即可上手,钩子命名与官方环境完全一致。

一张表收尾:Gymnasium MuJoCo 环境要点速查

事项写法
安装依赖pip install "gymnasium[mujoco]"
创建环境 / 传参gym.make("Ant-v5", render_mode="rgb_array")
查空间env.observation_space/env.action_space
固定初始状态env.reset(seed=42)
并行采样gymnasium.vector.SyncVectorEnv/AsyncVectorEnv
录制训练视频gymnasium.wrappers.RecordVideo
观测归一化 / 动作缩放NormalizeObservation/RescaleAction
无头 GPU 渲染export MUJOCO_GL=egl

继续深入可以翻这几处(仓库内相对路径):

  • MuJoCo 环境总览与渲染参数:docs/environments/mujoco.md
  • 环境类与基类源码:gymnasium/envs/mujoco/
  • 环境注册表(所有可用 id):gymnasium/envs/init.py
  • 官方 REINFORCE 训练教程:docs/tutorials/training_agents/mujoco_reinforce.py
  • 向量化环境实现:gymnasium/vector/

InvertedPendulum的第一条曲线,到Humanoid的全身协调,路径都在这几节里了。现在去把MUJOCO_GL=egl设上,让猎豹先跑起来。

【免费下载链接】GymnasiumA standard API for single-agent reinforcement learning environments, with popular reference environments and related utilities (formerly Gym)项目地址: https://gitcode.com/GitHub_Trending/gy/Gymnasium

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询