从跑通到调优:Gymnasium MuJoCo 连续控制环境上手指南
【免费下载链接】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 连续控制环境从哪下手?本文以 Hopper、Walker2d、Ant 为主线,带你从第一次跑通make/reset/step,走到读懂奖励构成、向量化加速和参数调优。全程只需要一个终端和几段最小代码。
为什么连续控制比 Atari 更难
这节帮你判断:为什么很多在 Atari 上有效的直觉,换到 MuJoCo 环境就会失效。
Atari 里你按下的是一个确定的按键——动作离散、有限、结果立等可见。MuJoCo 连续控制环境完全不同:你的输出是一个实数向量,每个分量直接变成机器人某个执行器(actuator——关节上那个"马达")的扭矩。0.30 和 0.31 是两个合法动作,效果却可能天差地别。这有点像开车:Atari 是换挡杆,咔哒一下换到位;连续控制是油门踏板,踩多深、松多快,车辆姿态就怎么变。
还有一个隐藏难点:奖励通常不是"拿到就加分",而是和前进速度、是否摔倒、动作大小都挂钩,你得自己读懂它由哪几项拼成。下面先跑通第一个环境,再回头拆这些细节。
5 分钟跑通第一个 MuJoCo 环境
这节解决"能不能跑起来"的问题:装依赖、建环境、循环采样、读结果。
先安装 MuJoCo 后端:
pip install "gymnasium[mujoco]"然后创建环境。以 Hopper-v5 为例——一条腿的弹跳机器人,动作维度只有 3,是入门的好选择:
import gymnasium as gym env = gym.make("Hopper-v5") # 不传 render_mode,纯跑数据 obs, info = env.reset(seed=7) # 固定种子,保证可复现 total = 0.0 done = False while not done: action = env.action_space.sample() # 随机动作占位 obs, reward, terminated, truncated, info = env.step(action) total += reward done = terminated or truncated print(f"本回合累计奖励: {total:.2f}") env.close()跑起来大概是这样:回合会在 1000 步内结束(机器人摔倒提前terminated,到点则truncated),随机策略的累计奖励通常只有几十量级——这就是你后面训练要超过的基线。
渲染有三种模式,各用一句话带过:
render_mode="human":弹出一个窗口实时播放,适合肉眼观察;render_mode="rgb_array":env.render()返回一张 NumPy 图像,适合录视频、贴博客;- 不传:无头模式,不产生任何画面,速度最快。
跑通了,接下来看每步返回的数据到底是什么。
读懂观测、动作和奖励:Hopper-v5 的三个空间
这节把step返回值逐个拆开,之后看任何 MuJoCo 环境的文档你都不会迷路。
观测(observation)是一个一维浮点向量,按"位置 + 速度"拼接。Hopper-v5 默认是 11 维(float64):
- 前 5 维是位置类:躯干离地高度、躯干倾角、髋/腿/脚三个关节角;
- 后 6 维是对应的速度类:躯干水平速度、垂直速度,以及各关节的角速度。
注意一个刻意设计:默认观测不含躯干的 x 坐标(横向走了多远)。官方用exclude_current_positions_from_observation=False可以把它加回来。这样做的意图是逼策略学会"不依赖绝对位置"也能往前走,属于一种归纳偏置。
动作(action)是 3 维Box(-1, 1, float32),每个分量是一个关节扭矩的归一化控制量,环境内部再换算成真实牛顿米。你可以理解为"油门开度",而不是"绝对角度"。
奖励(reward)由三股力量拼成,以 Hopper-v5 为例:
总奖励 = 存活奖励 + 前进奖励 − 控制代价
- 存活奖励:只要机器人还"健康"(没摔倒、躯干倾角没超限),每步 +1;
- 前进奖励:与 x 方向前进速度成正比,往前走得越快分越高;
- 控制代价:按动作平方和惩罚,防止你靠猛踩"油门"刷前进分。
好消息是 v5 把这三项拆开放进了info:info["reward_forward"]、info["reward_survive"]、info["reward_ctrl"]。训练时打印这三个键,比盯着总奖励猜"分是怎么丢的"高效得多。
下面这张来自官方教程的 REINFORCE 训练奖励曲线,就是连续控制环境"从乱跳到稳定拿分"的典型样子(横轴是回合数,纵轴是每回合总奖励):
看懂了单个环境的"输入—输出—打分"三件套,下一步就是挑一个适合你的环境。
连续控制环境速查表:从 InvertedPendulum 到 Humanoid 怎么选
这节给你一张选型地图:先练哪个、后练哪个、每个环境在练什么。
| 环境 | 动作维度 | 观测维度(默认) | 它在练什么 | 上手难度 |
|---|---|---|---|---|
| InvertedPendulum-v5 | 1 | 7 | 平衡入门,动作只有推小车一个力 | ★ |
| Hopper-v5 | 3 | 11 | 单腿弹跳,速度—平衡—代价三角 | ★★ |
| Swimmer-v5 | 5 | 15 | 二维游动,接触弱、数值友好 | ★★ |
| Walker2d-v5 | 6 | 17 | 双足步态,左右腿协调 | ★★★ |
| Ant-v5 | 8 | 105 | 四足协同;观测额外含接触力项,维度大 | ★★★★ |
| Humanoid-v5 | 21 | 34 | 全身控制,重计算、重耐心 | ★★★★★ |
两点建议:
- 热身从 InvertedPendulum 或 Hopper 开始,动作维数低,训练反馈快,适合先验证你的算法管线;Ant 的 105 维观测会显著拖慢小算力下的调试节奏。
- 版本上,新项目直接选
-v5系列(要求mujoco >= 2.3.3,reset()会返回非空info,奖励分项也齐全);复现旧文献时对照原文用的是-v4还是-v3——v3 及更早属于旧模拟器后端,现已迁出主仓库。
环境选好了,训练慢才是下一个真问题。下面三件事能立刻见效。
训练提速三板斧:向量化、归一化、渲染分离
这节把采样和训练流程提速,不碰算法本身。
第一板斧:向量化采样。强化学习最耗时的环节是环境交互,不是参数更新。用SyncVectorEnv把 N 个环境打包成"一个环境",step一次推进 N 步,吞吐随之上去:
from gymnasium.vector import SyncVectorEnv envs = SyncVectorEnv([lambda: gym.make("Hopper-v5") for _ in range(8)]) obs, infos = envs.reset(seed=7) actions = envs.action_space.sample() obs, rewards, terms, truns, infos = envs.step(actions)批量观测形状从(11,)变成(8, 11),奖励、终止标志同理都是 8 个。CPU 核数够用时还可以换成AsyncVectorEnv,交互更满。
第二板斧:观测归一化。连续控制的观测量纲混乱(高度是米、倾角是弧度、角速度是 rad/s),直接用会让网络输入忽大忽小。套一个 wrapper 即可:
from gymnasium.wrappers import NormalizeObservation env = NormalizeObservation(env) # 滚动统计均值方差,在线归一化动作侧如果要做缩放开环测试,RescaleAction也是同类工具。
第三板斧:训练与渲染分离。开着render_mode="human"训练,采样速度会被画面拖到明显变慢。正确姿势是训练时不开渲染;要留证据,用rgb_array+RecordVideowrapper 按需录几段,或者直接看info里的分项数字。
提速完成之后,剩下的麻烦多半是"结果对不上"和"训练炸掉"两类。
新手最容易踩的 3 个坑:慢、不可复现、数值不稳
这节按"症状 → 原因 → 一行解法"给你排障。
坑一:采样莫名其妙慢。原因几乎总是渲染开着,或frame_skip被调大了(它决定每次step内部模拟多少子步)。解法:训练环境不传render_mode,需要画面时另建一个评估环境。
坑二:结果不可复现。原因常见有三:只给环境设了种子、没给 NumPy/策略网络设种子、评估时还在采样随机动作。解法:
import numpy as np obs, info = env.reset(seed=2024) np.random.seed(2024) # 网络初始化、采样等同样要钉住再配合"评估时用确定性动作(取分布均值而非采样)+ 多跑几个回合取平均",波动就小多了。
坑三:数值不稳,奖励突然爆表或策略崩盘。原因是连续控制对奖励尺度和观测分布敏感,大动作一步就能把状态带飞。解法组合拳:上NormalizeObservation;训练循环里加梯度范数裁剪;学习率随训练线性衰减。这三招在仓库自带的教程(docs/tutorials/training_agents/mujoco_reinforce.py)里都有体现。
排完这三类坑,你的实验基本能"跑得动、跑得快、跑得稳"了。
下一步去哪:自定义模型、参数表和官方教程
这节给你三条现成的延伸路径,不用自己找方向。
- 改机器人本身:每个环境背后是一个 MuJoCo XML 模型(位置、质量、关节限位都写在那里),源码在 gymnasium/envs/mujoco/。v5 起你可以直接传
xml_file参数加载自己的模型,再配一个default_camera_config就能出图——这是做自定义连续控制任务的标准入口。 - 调任务难度:每个环境的 docstring 里都有一张参数表,
forward_reward_weight、ctrl_cost_weight、reset_noise_scale、健康判定的healthy_z_range都开放了。想加大难度,调大重置噪声;想让机器人"更怕摔",抬高存活奖励权重。 - 看官方完整示例:仓库
docs/tutorials/training_agents/下有一份从零实现 REINFORCE 的 MuJoCo 教程,策略网络结构如右图所示(共享层输出均值与标准差,从正态分布采样动作),适合你想不用现成算法库、自己写训练循环时参考:
- 逐环境查参数:Gymnasium 官方文档(https://gymnasium.farama.org/)为每个 MuJoCo 环境单独建了页,观测每一维叫什么、奖励怎么算、哪些参数可调,全都列得清清楚楚。
往上看有两个方向值得留意:一是把单机器人任务扩展成多智能体协同;二是把模拟器里的策略迁移到真实硬件(sim-to-real)。这两条路,都始于你现在就能跑通的这几行make和step。
【免费下载链接】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),仅供参考