02. 双框架环境搭建与第一次运行
前置自测
📋 答不出 \(\ge\) 2 题 → 建议先阅读 Ch01(GPU 仿真生态全景)
- mjlab 和 Isaac Lab 各自使用什么物理引擎?两者在安装复杂度上的差异是什么?
sim.step()和env.step()的区别是什么?(回顾 Ch01:仿真三角色)- 为什么环境安装验证应该分层进行,而不是直接跑一个大训练?
- GPU 并行仿真的核心优势是什么?(回顾 Ch01:数据零搬运)
uv run和裸python运行脚本的区别是什么?从环境隔离的角度思考。
本章目标
学完本章后,你应该能够:
- 独立完成 mjlab 和 Isaac Lab 的安装,包括 GPU 环境验证
- 使用 两个框架的 CLI 分别完成训练、评估和可视化
- 执行 分层验证流程(smoke test → zero agent → random agent → 最小训练)
- 定位 常见安装错误属于哪一层,避免在错误方向上浪费时间
前置知识桥接
回顾 Ch01:我们建立了"仿真是训练基础设施"的认知,对比了 mjlab(轻量/MuJoCo Warp/pip install)和 Isaac Lab(功能丰富/PhysX/conda+Isaac Sim)的定位差异。本章把这些认知落地为可执行的命令——从 pip install 到第一个训练 reward 曲线上涨,你将亲手验证 Ch01 讨论的所有差异。
本质洞察:环境安装的目标不是"没有报错",而是证明从 CLI 入口到物理仿真到训练循环的每一层都能被独立触达。只有逐层证明可用性,出错时才能快速定位问题在哪一层。
2.1 安装不是杂务,而是实验的第一步 ⭐
这一节解决什么问题:建立"安装验证是工程方法论而不是一次性命令"的认知。
动机:机器人 RL 的安装为什么特别脆弱
机器人 RL 项目的安装问题不是一次性事件,而是贯穿整个项目周期的持续挑战。你换 GPU 会遇到 CUDA driver 问题,换机器会遇到依赖解析问题,换任务会遇到 asset 或 registry 问题,开 viewer 会遇到 DISPLAY 或 EGL 问题,开训练会遇到 WandB、RSL-RL、torch、MuJoCo Warp 的组合问题。
一个跨领域类比:安装验证之于机器人 RL,就像 CI/CD 之于软件工程。你不会只检查编译器是否存在就宣布"开发环境就绪"——你还会跑单元测试确认链接正确、运行示例程序确认动态库加载。同样,pip install mjlab 成功不代表你能训练——你还需要验证 GPU 可用、task 能注册、仿真能推进、训练循环能启动。
这个类比的边界:CI/CD 通常给出确定性的 pass/fail,而机器人 RL 的安装问题经常表现为运行时异常、模糊的 CUDA 报错或沉默的行为差异——所以分层验证比标准软件更加重要。
如果不分层验证会怎样
反面案例:想象你拿到一台新服务器,第一条命令就是 uv run train Mjlab-Velocity-Flat-Unitree-G1 --env.scene.num-envs 4096。报错了。日志很长,你不知道错误来自 CUDA 不可用、MuJoCo Warp 与 driver 不兼容、任务名拼错、WandB 没登录、viewer 在无显示服务器上卡住,还是 scene asset 路径错误。多个问题可能同时存在,修了一个又冒出另一个。
本章的分层流程就是为了避免这种局面:先用小命令逐层检查,每一层通过后再进入下一层。
分层验证流程总览
无论是 mjlab 还是 Isaac Lab,安装验证都遵循同一套分层逻辑:
| 层级 | 验证内容 | mjlab 命令 | Isaac Lab 命令 | 通过标准 |
|---|---|---|---|---|
| L0 | Python + GPU 环境 | python -c "import torch; print(torch.cuda.is_available())" |
同左 | 输出 True |
| L1 | 框架导入 | python -c "import mjlab; print(mjlab.__version__)" |
python -c "import isaaclab; print(isaaclab.__version__)" |
无 ImportError |
| L2 | 任务注册 | uv run list-envs |
python scripts/environments/list_envs.py |
列出可用任务 |
| L3 | 场景构建 | uv run export-scene <TASK> |
— | 导出 MJCF/USD 无错 |
| L4 | Zero agent 可视化 | uv run play <TASK> --agent zero |
python scripts/environments/zero_agent.py --task <TASK> |
机器人站在场景中不动 |
| L5 | Random agent | uv run play <TASK> --agent random |
python scripts/environments/random_agent.py --task <TASK> |
机器人有动作但不爆飞 |
| L6 | 最小训练 | uv run train <TASK> --env.scene.num-envs 16 |
python scripts/reinforcement_learning/rsl_rl/train.py --task <TASK> --num_envs 16 |
reward 曲线有变化 |
如果不按层级来会怎样:你在 L6(训练)报错后花两小时 debug,最后发现问题在 L0(CUDA 版本不对)。分层验证可以在 10 秒内定位到 L0。
⚠️ 常见陷阱
- 直接跑大训练跳过验证。 4096 环境的训练报错时,日志极长且多个问题叠加。先用 16 环境确认训练循环正确,再放大到 4096。
- 在无显示的服务器上开 viewer。 mjlab 的 Viser 是 web-based 的,不需要 X11/显示器(通过浏览器访问);Isaac Lab 的 Isaac Sim Viewer 需要显示服务器或
--headless模式。忘记--headless会导致卡死。 pip install成功 \(\ne\) 可以训练。pip install mjlab只安装了 Python 包,但 MuJoCo Warp 的 GPU kernel 编译发生在首次运行时——如果 CUDA 版本不匹配,安装不会报错但运行会失败。
练习
- 在你的机器上运行
python -c "import torch; print(torch.version.cuda, torch.cuda.get_device_name(0))"并记录输出。这个信息在后续 debug 中会反复用到。 - 解释为什么"L4 zero agent"比"L6 训练"更适合作为安装验证的第一步。
- 如果你在 L2(任务列表)阶段就失败了,这意味着什么?它排除了哪些可能的错误来源?(提示:L0 和 L1 已经通过,说明 GPU 和框架本身是正常的。)
真实安装失败案例集
以下案例来自社区论坛和 GitHub Issues(匿名化处理),每个案例都是真实发生过的:
案例 A:CUDA driver 和 PyTorch CUDA 版本看似匹配但不兼容
某同学的 nvidia-smi 显示 CUDA 12.4,于是安装了 PyTorch cu124。pip install 成功,import torch 成功,torch.cuda.is_available() 返回 True。但运行 uv run train 时报错:RuntimeError: CUDA error: no kernel image is available for execution on the device。
根因:他的 GPU 是 RTX 3060(Ampere 架构,sm_86),但 PyTorch cu124 的预编译 kernel 不包含 sm_86。解决方案:使用 pip install torch --index-url https://download.pytorch.org/whl/cu121(cu121 包含 sm_86 kernel)。
教训:torch.cuda.is_available() == True 不代表 kernel 兼容。L0 应该额外测试 torch.randn(10).cuda() 是否成功。
案例 B:conda install pytorch 安装了 CPU 版本
某同学用 conda install pytorch 安装 PyTorch(没有指定 CUDA 版本),conda 默认解析到 CPU 版本。import torch 成功,但 torch.cuda.is_available() 返回 False。他以为是 GPU driver 问题,花了一天重装 driver——结果问题在 PyTorch 层。
根因:conda install pytorch 的默认行为取决于 conda channel 的优先级,可能安装 CPU 版本。解决方案:永远不要 conda install pytorch——用 pip install torch --index-url https://download.pytorch.org/whl/cu121。
教训:这就是为什么 Isaac Lab 安装指南明确说"用 pip 安装 PyTorch,不要用 conda"。
案例 C:Isaac Lab 版本和 Isaac Sim 版本不对应
某同学安装了 Isaac Lab 3.0 Beta(develop branch),但 Isaac Sim 还是 5.1 版本。import isaaclab 成功,但创建环境时报 AttributeError: module 'isaacsim' has no attribute 'XXX'。
根因:Isaac Lab 3.0 需要 Isaac Sim 6.0 的新 API,旧版 Isaac Sim 没有这些接口。解决方案:要么升级 Isaac Sim 到 6.0,要么切到 Isaac Lab 2.3.0(main branch)。
教训:Isaac Lab 的版本号和 Isaac Sim 的版本号不是同一套系统。安装前必须查阅 README 的版本对照表。
案例 D:WandB 网络超时导致训练卡死
某同学在内网服务器上运行训练,WandB 初始化时尝试连接 wandb.ai——但服务器没有外网访问权限。训练进程卡在 WandB 初始化步骤 60 秒后超时失败。
根因:WandB 默认在线模式需要网络连接。解决方案:export WANDB_MODE=offline,训练完成后用 wandb sync 上传。
教训:在任何新环境上首次训练前,先确认网络连通性。如果不确定,直接设 WANDB_MODE=offline。
安装验证的工程哲学
上述分层验证流程不是本教材独创的——它来自一个通用的工程原则:故障隔离(fault isolation)。在复杂系统中,当最终结果不对时,你需要一种方法来确定"问题出在哪一层"。分层验证就是预先建立这些断点——每一层通过后,你可以确信该层及以下层是正常的,问题一定在更上层。
这个原则在后续章节中会反复出现:
| 章节 | 分层验证的应用 |
|---|---|
| Ch04 | Manager-Based 架构精读:逐个 Manager 验证(obs → action → reward → termination) |
| Ch06 | Reward 调试:逐项打印 reward 分项,确定哪一项有 bug |
| Ch08 | DR 调试:逐步添加 DR(先 mass → 再 friction → 再 push),确定哪一步导致崩溃 |
| Ch23 | Sim2Real 调试:sim2sim → ONNX 推理一致性 → 真机通信 → 完整部署 |
反事实推理:如果机器人 RL 的系统只有两层(install → train),那分层验证就没什么价值。但实际系统有 7+ 层(GPU → 框架 → registry → scene → physics → obs/reward → training),每一层都可能独立出错且互相遮掩——分层验证的价值与系统复杂度成正比。
上一节建立了分层验证的方法论,接下来我们具体执行——先从更简单的 mjlab 开始。
2.2 mjlab 安装与验证 ⭐⭐
这一节解决什么问题:从零完成 mjlab 的安装,并逐层验证到最小训练。
动机
mjlab 的安装哲学是"一条命令搞定"——这是它相比 Isaac Lab 的核心优势之一。但"简单"不意味着"不会出错"。MuJoCo Warp 的 GPU kernel 编译、PyTorch 与 CUDA 的版本匹配、WandB 的登录配置——这些都可能在看似成功的 pip install 之后制造麻烦。
如果不了解依赖关系会怎样
你可能在 pip install mjlab 之后立刻开始训练,然后遇到 RuntimeError: CUDA error: no kernel image is available for execution on the device。这个错误的意思是 PyTorch 的 CUDA 版本和你的 GPU driver 不兼容——但错误信息完全没提到这一点。如果你不了解 mjlab 的依赖链,你可能花两小时在 mjlab 的代码里找 bug,而实际问题在 PyTorch 层。
安装方式一:uv(推荐)
mjlab 推荐使用 uv(一个 Rust 编写的快速 Python 包管理器)来管理环境。如果你还不了解 uv,这里是你需要知道的核心概念:
uv 是什么? uv 是 Astral 公司开发的 Python 包管理器,用 Rust 编写,比 pip 快 10-100 倍。它同时替代了 pip(包安装)、virtualenv(环境管理)和 pip-tools(依赖锁定)。mjlab 选择 uv 而非 pip/conda 是因为:
- 可复现性:uv.lock 文件精确锁定每个依赖的版本和哈希,确保你和论文作者使用完全相同的依赖
- 速度:uv sync 安装所有依赖通常在 30 秒内完成(pip 可能需要数分钟)
- 项目脚本:uv run train 自动在正确的虚拟环境中运行,不需要手动 source activate
# 1. 安装 uv(如果还没有)
curl -LsSf https://astral.sh/uv/install.sh | sh
# 或者用 pip:pip install uv
# 2. 克隆 mjlab 仓库
git clone https://github.com/mujocolab/mjlab.git
cd mjlab
# 3. 创建虚拟环境并安装依赖(uv 自动处理)
uv sync
# 这一步做了什么:
# - 读取 pyproject.toml 中的依赖声明
# - 创建 .venv 虚拟环境(如果不存在)
# - 安装所有依赖,版本锁定到 uv.lock
# - 安装 mjlab 本身(editable mode)
# 4. 验证安装
uv run python -c "import mjlab; print(mjlab.__version__)"
uv run vs python:为什么本教材所有命令都用 uv run 而不是裸 python?
| 命令 | 行为 | 风险 |
|---|---|---|
python train.py |
使用系统 Python 或当前激活的环境 | 可能 import 到旧版本 mjlab,或找不到依赖 |
source .venv/bin/activate && python train.py |
先激活环境再运行 | 忘记激活 → 用错环境;切换项目时忘记 deactivate |
uv run train |
自动使用项目的 .venv,无需激活 | 无风险——uv 保证使用正确的环境 |
如果不用
uv run会怎样:你在 mjlab 目录中运行python scripts/train.py,但系统 PATH 中的python指向的是 conda base 环境——里面安装了旧版 mjlab 0.1。你花了一小时 debug 一个"奇怪的 API 变更",最后发现只是 import 了错误的版本。uv run消除了这类问题。
uvx 的边界:mjlab 的 README 中提到了 uvx——它是 uv 生态中用于"一次性运行已发布包"的工具,类似于 npx 之于 npm。但本教材的所有实验都不使用 uvx,原因有三:
| 工具 | 语义 | 本教材是否使用 |
|---|---|---|
uv run train |
在当前项目的 .venv 中运行 train 入口 |
✅ 始终使用 |
uvx mjlab train |
从 PyPI 拉取已发布版本并临时运行 | ❌ 不使用 |
不用 uvx 的核心原因是:本教材要求你在源码仓库中工作——你会修改 config、添加自定义 term、调试 reward 函数。uvx 运行的是 PyPI 上的已发布版本,不会反映你对本地源码的任何修改。如果你用 uvx 跑了一个实验,发现行为和预期不同,你无法确定是你的修改有问题还是 uvx 根本没用到你的修改——这会浪费大量调试时间。
简单记忆:做实验用
uv run,看文档用uvx。如果你只想快速体验 mjlab 而不打算修改任何代码(如在 Colab 中试玩),uvx是可以的。但一旦你进入本教材的动手实验,所有命令都通过uv run执行。
安装方式二:pip
如果你不想使用 uv,也可以用标准 pip:
# 1. 创建虚拟环境
python -m venv .venv
source .venv/bin/activate
# 2. 安装 mjlab
pip install mjlab
# 3. 验证
python -c "import mjlab; print(mjlab.__version__)"
| 安装方式 | 优势 | 劣势 |
|---|---|---|
| uv(推荐) | 版本锁定、可复现、速度快 | 需要额外安装 uv |
| pip | 无需额外工具 | 依赖版本可能和作者不一致 |
| Docker | 完全隔离 | 需要 nvidia-docker、文件交换不便 |
| Google Colab | 零配置 | GPU 受限、不适合大规模训练 |
安装方式三:Docker
Docker 是最"干净"的安装方式——所有依赖都在容器内,不会污染宿主机环境。适合在共享服务器上使用。
# 拉取官方镜像(GitHub Container Registry)
docker pull ghcr.io/mujocolab/mjlab:latest
# 运行(挂载 GPU + 端口映射用于 Viser + 挂载工作目录)
docker run --gpus all \
-p 7860:7860 \
-v $(pwd)/logs:/workspace/logs \
-it ghcr.io/mujocolab/mjlab:latest
# 在容器内验证
python -c "import mjlab; print(mjlab.__version__)"
uv run list-envs
Docker 的主要缺点是文件交换不便——你在容器内生成的 checkpoint 需要通过挂载卷(-v)才能被宿主机访问。建议把 logs/ 目录挂载出来。
安装方式四:Google Colab
mjlab 提供了官方 Colab 模板,适合三种场景:(1) 快速试用,(2) 给审稿人做可复现 demo,(3) 没有 GPU 的学生学习。
# Colab 第一个 cell
!pip install mjlab
import mjlab
print(mjlab.__version__)
# 第二个 cell:验证 GPU
import torch
print(f"GPU: {torch.cuda.get_device_name(0)}")
print(f"VRAM: {torch.cuda.get_device_properties(0).total_mem / 1e9:.1f} GB")
Colab 的 T4 GPU(16 GB VRAM)可以运行 256 环境的训练,但 4096 环境需要更大显存。正式实验应在本地或云端 A100/H100 上进行。
| 安装方式 | 安装时间 | 适合场景 | 限制 |
|---|---|---|---|
| uv(推荐) | ~2 分钟 | 日常开发、正式实验 | 需安装 uv |
| pip | ~3 分钟 | 不想装 uv 的用户 | 版本不锁定 |
| Docker | ~5 分钟(首次拉取镜像更久) | 共享服务器、CI/CD | 文件交换不便 |
| Google Colab | ~1 分钟 | 试用、demo、教学 | GPU 受限 |
MuJoCo Warp 的 GPU Kernel 编译
mjlab 依赖 MuJoCo Warp(NVIDIA 的 MuJoCo GPU 加速版)。MuJoCo Warp 使用 NVIDIA Warp 框架来编写 GPU kernel——这些 kernel 在首次运行时即时编译(JIT compilation),而不是在安装时编译。
这意味着:
- pip install mjlab 不会触发 GPU kernel 编译——即使 CUDA 版本不对,安装也不会报错
- 首次 uv run play <TASK> 会触发编译,耗时 10-30 秒(后续运行使用缓存,无需重新编译)
- 如果 CUDA toolkit 版本不匹配,编译时才会报错(而非安装时)
这是 mjlab 安装中最容易踩的坑——pip install 成功给你虚假的安全感。所以 L0-L1 的验证步骤不只是"能 import",还要实际运行一次来触发 kernel 编译。
WandB 配置(详细版)
WandB 是 mjlab 的默认实验管理工具。首次使用需要:
# 1. 注册 WandB 账号(免费): https://wandb.ai
# 2. 登录
wandb login
# 粘贴 API key(从 https://wandb.ai/authorize 获取)
# 3. 创建项目
# 在 WandB 网页上创建一个 project(如 "mjlab-experiments")
# 4. 训练时指定 entity 和 project
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--logger.wandb.entity your-username \
--logger.wandb.project mjlab-experiments
如果你在离线环境中(如内网服务器无法访问 wandb.ai),可以设置离线模式:
export WANDB_MODE=offline
# 训练照常运行,日志保存在本地
# 后续连接网络时用 wandb sync 上传
wandb sync logs/wandb/offline-run-*
回顾 Ch01 §1.5:我们提到 WandB 是"零成本高回报"的好习惯。一个研究生在三年博士期间可能跑 1000+ 个实验——没有实验管理工具,这些实验的参数和结果会变成一堆无法检索的文件夹。从第一天就用 WandB,三年后你会感谢自己。
GPU 显存估算与环境数选择
在开始训练前,你需要回答一个实际问题:我的 GPU 能跑多少个并行环境? 环境数太少(<256)数据不够、学习慢;环境数太大则 OOM(out of memory)。
Ch01 §1.2 给出了粗略的估算公式:max_envs ≈ (VRAM - 2GB) × 1000 / per_env_MB。这里给出更实用的实测参考:
mjlab 实测数据(Go2 velocity flat,无相机):
| GPU | 显存 | 推荐 num_envs | 实测 steps/s | 显存占用 |
|---|---|---|---|---|
| RTX 3090 | 24 GB | 4096 | ~45,000 | ~12 GB |
| RTX 4090 | 24 GB | 4096 | ~60,000 | ~11 GB |
| A100 | 80 GB | 8192 | ~80,000 | ~25 GB |
| H100 | 80 GB | 8192 | ~100,000 | ~22 GB |
以上数据为参考值,实际取决于任务复杂度(传感器数、接触点数等)。视觉任务(含 RGB 相机)的显存占用会增加 10-50 倍,需大幅降低 num_envs。
如何实测你的配置:
# 方法 1:从小到大尝试
uv run train Mjlab-Velocity-Flat-Unitree-Go2 --env.scene.num-envs 256 # 先小
uv run train Mjlab-Velocity-Flat-Unitree-Go2 --env.scene.num-envs 1024 # 加大
uv run train Mjlab-Velocity-Flat-Unitree-Go2 --env.scene.num-envs 4096 # 目标
# 方法 2:训练时监控显存
watch -n 1 nvidia-smi # 在另一个终端实时监控
# 方法 3:用 PyTorch API 精确查询
python -c "import torch; torch.cuda.empty_cache(); print(torch.cuda.memory_summary())"
经验法则:从 4096 开始尝试。如果 OOM,减半到 2048;如果 2048 也 OOM,减到 1024。如果 4096 正常且 GPU 利用率 < 80%,可以尝试增加到 8192。
mjlab 的依赖链是:
mjlab
├── mujoco-warp (MuJoCo 的 GPU 加速版,依赖 NVIDIA Warp)
│ └── warp-lang (NVIDIA Warp,需要 CUDA toolkit)
├── torch (PyTorch,需要与 CUDA driver 版本匹配)
├── rsl_rl (RL 算法库,本章只用 PPO;另含 Distillation)
└── wandb (实验管理,可选但强烈推荐)
最常见的安装问题出在 torch 与 CUDA driver 的版本匹配上。验证方法:
# 检查 CUDA driver 版本
nvidia-smi # 看右上角的 CUDA Version
# 检查 PyTorch 的 CUDA 版本
python -c "import torch; print(torch.version.cuda)"
# 两者必须兼容:PyTorch CUDA ≤ nvidia-smi CUDA
| nvidia-smi CUDA | 兼容的 PyTorch CUDA | 说明 |
|---|---|---|
| 12.4 | 12.1, 12.4 | driver 向后兼容 |
| 12.1 | 12.1, 11.8 | 不能用 12.4 的 PyTorch |
| 11.8 | 11.8 | 必须精确匹配 |
L0-L6 逐层验证
按 2.1 节的分层流程,依次执行:
L0:GPU 环境
python -c "import torch; print('CUDA:', torch.cuda.is_available(), '|', torch.cuda.get_device_name(0))"
# 期望输出:CUDA: True | NVIDIA A100-SXM4-80GB(或你的 GPU 型号)
L1:框架导入
uv run python -c "import mjlab; print('mjlab:', mjlab.__version__)"
uv run python -c "import mujoco; print('mujoco:', mujoco.__version__)"
# 期望:无 ImportError,打印版本号
L2:任务列表
uv run list-envs
# 期望输出:列出所有可用任务
# Mjlab-Velocity-Flat-Unitree-Go1
# Mjlab-Velocity-Flat-Unitree-Go2
# Mjlab-Velocity-Flat-Unitree-G1
# Mjlab-Tracking-Flat-Unitree-G1
# ...
如果这一步报错,问题通常在 task registry——可能是某个 task 的依赖(如特定的 MJCF 模型文件)缺失。
L3:场景导出
uv run export-scene Mjlab-Velocity-Flat-Unitree-Go2
# 期望:导出 MJCF 场景文件,可以用 MuJoCo 自带 viewer 打开检查
L4:Zero Agent
uv run play Mjlab-Velocity-Flat-Unitree-Go2 --agent zero
# 期望:打开 Viser 可视化,Go2 站在平地上一动不动
# Viser 默认在 http://localhost:7860 打开
这一步验证了三件事:
- 物理引擎正常:sim.step() 能推进而不崩溃
- 机器人模型正确:关节角在默认位置,碰撞体没有穿透
- 可视化工具正常:Viser 能渲染并通过浏览器访问
Zero agent 时你应该看到的具体画面:
| 检查项 | 正常 | 异常(及可能原因) |
|---|---|---|
| 机器人位置 | 站在地面上 | 悬浮在空中(初始高度设置错误) |
| 关节角 | 自然站立姿态 | 关节扭曲(默认关节角 default_joint_pos 配置错误) |
| 碰撞体 | 无穿透 | 足端穿透地面(collision mesh 问题或地面高度错误) |
| 物理行为 | 在重力下缓慢下沉到稳态 | 弹跳或振荡(接触参数 solref/solimp 不合理) |
反事实推理:如果跳过 L4 直接跑 L6 训练,而碰巧默认关节角配错了(比如所有腿完全伸直),训练可能"成功"但学到的是一个从错误初始姿态恢复的策略——不是你想要的。L4 的 30 秒投入可以避免数小时的无效训练。
L5:Random Agent
uv run play Mjlab-Velocity-Flat-Unitree-Go2 --agent random
# 期望:Go2 动作随机但不爆飞(如果爆飞说明 action scale 太大)
Random agent 测试的是 action 管线的合理性。你应该观察:
| 检查项 | 正常 | 异常(及可能原因) |
|---|---|---|
| 动作幅度 | 关节在合理范围内运动 | 关节打到限位甚至穿透(action scale 太大) |
| 机器人稳定性 | 随机动但不立即爆飞 | 第一个 step 就飞出屏幕(action scale >> 1.0) |
| 力矩大小 | 动作柔和 | 剧烈抖动(力矩限制缺失或太大) |
如果 random agent 导致机器人"爆飞"(第一个 step 就飞出画面),不要直接开始训练。先检查 action scaling:
# 典型的 action scale 配置(以 Go2 为例)
action_cfg = JointPositionActionCfg(
asset_name="robot",
joint_names=[".*"],
scale=0.25, # ← 这个值通常在 0.1-0.5 之间
offset=0.0, # ← offset 是默认关节角
)
如果 scale=1.0 或更大,random action(范围 [-1, 1])会让关节角变化 1 弧度——对于四足机器人来说这是剧烈的动作,很可能导致穿透或弹飞。
L6:最小训练
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--env.scene.num-envs 16 \
--num-iterations 50
# 期望:reward 曲线有上升趋势(不一定收敛,只要不是平的)
如果 L0-L5 都通过但 L6 失败,问题通常在 RL 训练配置——学习率、obs normalization 或 reward 定义。
WandB 配置
强烈建议从第一次训练开始就配置 WandB:
# 登录(一次性)
wandb login
# 训练时自动上传
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--logger.wandb.entity your-org \
--logger.wandb.project mjlab-ch02
⚠️ 常见陷阱
- 忘记用
uv run。 直接运行python或train可能使用系统 Python 而非项目虚拟环境,导致 import 版本不一致。所有命令都通过uv run执行。 - CUDA 版本不匹配但安装不报错。
pip install mjlab成功并不代表 GPU 可用。MuJoCo Warp 的 GPU kernel 在首次运行时才编译——如果 CUDA toolkit 版本不对,运行时才会报错。 - 在远程服务器上忘记端口转发。 Viser 默认监听
localhost:7860。如果你在远程服务器上运行,需要 SSH 端口转发:ssh -L 7860:localhost:7860 user@server。 - WandB 没登录就开训练。 训练会卡在 WandB 初始化步骤。先
wandb login或设置WANDB_MODE=offline。
练习
- 完成 L0-L6 的全部验证步骤,记录每一步的输出。如果某一步失败,用故障排查手册定位问题。
- 尝试用
--agent zero和--agent random分别可视化 Go2 和 G1 两个机器人。比较它们的默认姿态和自由度数量(Go2 有 12 个关节,G1 有 29 个——你能在可视化中看出这个差异吗?)。 - 运行一个 50 iteration 的最小训练,在 WandB 上查看 reward 曲线。reward 是否在上升?如果不是,可能的原因是什么?(提示:50 iteration 对大多数任务来说不够收敛,但应该能看到上升趋势。)
- 用
watch -n 1 nvidia-smi监控训练过程中的 GPU 显存使用。在 num_envs=256 和 num_envs=4096 下,显存使用差多少? - 尝试在不安装 WandB 的情况下训练(
export WANDB_MODE=disabled),然后在有 WandB 的情况下训练。对比两者的 steps/s——WandB 的日志上传是否影响了训练速度?
mjlab 的安装和验证完成了——从 pip install 到 reward 曲线上涨,整个过程不超过 10 分钟。接下来我们做 Isaac Lab,你会发现安装复杂度显著增加,但可用的功能也更丰富。
2.3 Isaac Lab 安装与验证 ⭐⭐
这一节解决什么问题:完成 Isaac Lab 的安装,理解其与 mjlab 在安装复杂度上的差异来源。
动机
Isaac Lab 的安装比 mjlab 复杂得多——这不是因为开发者"没做好",而是因为 Isaac Lab 承载了更多功能(RTX 渲染、多物理后端、Omniverse 生态集成)。理解这些复杂性的来源,可以帮你在出问题时更快定位。
如果不了解安装架构会怎样
Isaac Lab 的依赖链比 mjlab 长得多。如果你不理解 Isaac Sim → Isaac Lab → RL 算法库这条链,你可能在 Isaac Sim 版本不匹配时修改 Isaac Lab 的代码——南辕北辙。
两种安装模式
Isaac Lab 有两种安装模式,选择取决于你是否需要 GUI 可视化:
| 模式 | 说明 | 适合场景 |
|---|---|---|
| Isaac Sim 完整安装 | 包含 Omniverse 渲染器和 GUI | 需要 RTX 可视化、视觉策略训练 |
| kit-less 模式 | 仅安装物理引擎和核心库,无 GUI | 纯 locomotion 训练、远程服务器 |
对于本教材的大部分内容(locomotion、操作、motion imitation),kit-less 模式已经足够。只有 Ch18(视觉感知运动控制)需要完整安装。
安装步骤(conda + pip)
# 1. 创建 conda 环境
conda create -n isaaclab python=3.10 -y
conda activate isaaclab
# 2. 安装 PyTorch(确保 CUDA 版本匹配)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
# 3. 安装 Isaac Lab(kit-less 模式)
pip install isaacsim-rl isaacsim-replicator isaacsim-extscache-physics
# 4. 克隆 Isaac Lab 仓库
git clone https://github.com/isaac-sim/IsaacLab.git
cd IsaacLab
# 5. 安装 Isaac Lab 本身
./isaaclab.sh --install
# 6. 验证
python -c "import isaaclab; print(isaaclab.__version__)"
Docker 安装
Isaac Lab 也提供了 Docker 镜像,这是避免版本冲突的最可靠方式:
# 拉取官方镜像(注意选择与你的 CUDA driver 兼容的版本)
docker pull nvcr.io/nvidia/isaac-lab:latest
# 运行
docker run --gpus all --network=host \
-v $(pwd)/logs:/workspace/logs \
-it nvcr.io/nvidia/isaac-lab:latest bash
# 在容器内验证
python -c "import isaaclab; print(isaaclab.__version__)"
python scripts/environments/list_envs.py
kit-less vs 完整安装的选择
这是 Isaac Lab 安装的第一个决策点:
| 模式 | 安装内容 | 安装时间 | 磁盘占用 | 适合场景 |
|---|---|---|---|---|
| kit-less | 物理引擎 + 核心框架 | ~15 分钟 | ~5 GB | locomotion/操作训练(无视觉) |
| 完整安装 | Isaac Sim + Omniverse + 核心框架 | ~30-60 分钟 | ~20 GB | 视觉策略训练、RTX 渲染 |
如果不确定选哪个:先装 kit-less。本教材的 Ch01-17 都可以用 kit-less 完成。只有 Ch18(视觉感知运动控制)需要完整安装。kit-less 后续可以升级为完整安装而无需重新配置环境。
版本依赖关系
Isaac Lab 的依赖链比 mjlab 复杂一个层次:
CUDA Driver (nvidia-smi)
└── CUDA Toolkit (nvcc)
└── PyTorch
└── Isaac Sim (NVIDIA Omniverse 应用)
└── Isaac Lab (RL 框架)
├── rsl_rl (默认 RL 后端)
├── rl_games (可选)
├── skrl (可选)
└── stable_baselines3 (可选)
| 版本约束 | 说明 | 如何检查 |
|---|---|---|
| CUDA Driver → CUDA Toolkit | Driver 版本 \(\ge\) Toolkit 版本 | nvidia-smi vs nvcc --version |
| CUDA Toolkit → PyTorch | PyTorch 编译时的 CUDA 版本 \(\le\) Toolkit | python -c "import torch; print(torch.version.cuda)" |
| Isaac Sim 版本 → Isaac Lab 版本 | Isaac Lab 2.x 需 Isaac Sim 2023.x;3.x 需 2024.x | Isaac Lab README 的版本对照表 |
| Isaac Lab 版本 → rsl_rl 版本 | 不同 Isaac Lab 版本捆绑不同 rsl_rl | 查看 setup.py 或 pyproject.toml |
如果不注意版本匹配会怎样:你可能安装了 Isaac Lab 3.0 但 Isaac Sim 还是 2023 版本——结果是 import 时报一堆莫名其妙的
AttributeError。更隐蔽的情况是:版本号看起来对,但 pip 缓存了旧版本的编译产物——pip install --no-cache-dir --force-reinstall可以解决这类问题。
Isaac Lab 安装的常见失败模式
根据社区论坛和我们的教学经验,Isaac Lab 安装最常失败在以下三个环节:
| 失败环节 | 症状 | 根因 | 解决方案 |
|---|---|---|---|
| PyTorch CUDA 不匹配 | torch.cuda.is_available() 返回 False |
pip 安装了 CPU 版 PyTorch | 用 --index-url https://download.pytorch.org/whl/cu121 指定 CUDA 版本 |
| Isaac Sim 版本冲突 | ImportError: cannot import name 'XXX' from 'isaacsim' |
Isaac Sim 和 Isaac Lab 版本不对应 | 查阅 README 版本对照表,重新安装匹配版本 |
| conda 和 pip 混用 | 各种依赖冲突 | conda 安装了 CPU 版 PyTorch 覆盖了 pip 版本 | 不要 conda install pytorch,只用 pip |
反事实推理:如果 Isaac Lab 也像 mjlab 一样只需要
pip install,上面这些问题就不会存在。但 Isaac Lab 选择了更复杂的依赖链,因为它提供了更多功能(RTX 渲染需要 Isaac Sim/Omniverse,多 RL 后端需要可选依赖管理)。这是"功能丰富"和"安装简单"之间的工程权衡——没有免费的午餐。
Isaac Lab 3.0 Beta 注意事项
本教材以 Isaac Lab 2.3.0 为主线。以下信息帮助你了解 3.0 Beta 的变化,但不建议在 3.0 final GA 之前用于正式研究。
如果你想尝试 Isaac Lab 3.0 Beta(develop branch),需要注意以下破坏性变更:
kit-less 安装模式(最大的改进):
# Isaac Lab 3.0 kit-less 安装(不需要 Isaac Sim!)
uv venv --python 3.12
uv pip install -U torch==2.10.0 torchvision==0.25.0 \
--index-url https://download.pytorch.org/whl/cu128
uv pip install isaaclab
# 训练(使用 Newton 物理后端)
./isaaclab.sh -p scripts/reinforcement_learning/rsl_rl/train.py \
--task Isaac-Cartpole-Direct-v0 --num_envs 4096 \
presets=newton --visualizer viser
kit-less 模式的优势是安装时间从 30-60 分钟缩短到约 5 分钟,且不需要 Isaac Sim/Omniverse 的 GUI 依赖。但它有限制:不支持 PhysX-only 的功能(deformable objects、surface grippers、material randomization),且 Newton 后端尚在开发中。
其他破坏性变更速查:
| 变更 | 2.3.0 | 3.0 Beta | 你需要做什么 |
|---|---|---|---|
| Quaternion | wxyz | xyzw | 所有硬编码的四元数需更新 |
| 数据管线 | .data.* → torch |
.data.* → wp.array |
加 wp.to_torch() 包装 |
| 模块前缀 | omni.isaac.lab.* |
isaaclab.* |
import 路径全变 |
| Python | \(\ge\) 3.10 | 3.12 | 升级 Python |
| PyTorch | \(\ge\) 2.0 | 2.10.0+cu128 | 升级 PyTorch |
Isaac Lab 3.0 提供了自动化迁移工具:scripts/tools/wrap_warp_to_torch.py(处理 warp-native 数据管线)和 quaternion finder tool(定位需要更新的四元数)。
工程建议:如果你已经在 2.3.0 上有可工作的代码,不要急于迁移到 3.0 Beta。等 3.0 final GA(预计 2026 Q3)后再迁移。如果你是全新开始且不需要 PhysX-only 特性,可以尝试 3.0 kit-less——安装体验接近 mjlab。
L0-L6 逐层验证
L0:GPU 环境(同 mjlab)
python -c "import torch; print('CUDA:', torch.cuda.is_available())"
L1:框架导入
python -c "import isaaclab; print(isaaclab.__version__)"
python -c "from isaaclab.envs import ManagerBasedRLEnv; print('OK')"
L2:任务列表
python scripts/environments/list_envs.py
# 期望:列出 30+ 内置任务
# Isaac-Velocity-Flat-Anymal-C-v0
# Isaac-Velocity-Rough-Anymal-C-v0
# Isaac-Velocity-Flat-H1-v0
# Isaac-Lift-Cube-Franka-v0
# ...
L4:Zero Agent 测试
# headless 模式(远程服务器);Isaac Lab 官方零动作 agent 脚本
python scripts/environments/zero_agent.py \
--task Isaac-Velocity-Flat-Anymal-C-v0 \
--headless --num_envs 4
L6:最小训练
python scripts/reinforcement_learning/rsl_rl/train.py \
--task Isaac-Velocity-Flat-Anymal-C-v0 \
--num_envs 16 --max_iterations 50 --headless
# 期望:reward 曲线有变化
Isaac Lab 特有的启动延迟
Isaac Lab 的第一次启动通常需要 15-30 秒(Isaac Sim 初始化、USD 资源加载)。这是正常行为,不是卡死。后续启动会快一些(缓存生效)。相比之下,mjlab 的启动延迟约 2 秒。
| 框架 | 首次启动 | 后续启动 | 原因 |
|---|---|---|---|
| mjlab | ~2 秒 | ~2 秒 | MuJoCo Warp kernel 编译(首次稍慢,后续缓存) |
| Isaac Lab | 15-30 秒 | 5-15 秒 | Isaac Sim 初始化 + USD 资源加载 |
⚠️ 常见陷阱
- conda 和 pip 混用导致依赖冲突。 Isaac Lab 推荐用 conda 创建环境 + pip 安装包。不要用
conda install pytorch——它可能安装 CPU 版本。 - 忘记
--headless在远程服务器上。 Isaac Lab 默认尝试打开 GUI,在无显示服务器上会卡死。始终加--headless。 - CUDA 版本三重匹配。 Isaac Lab 需要 CUDA driver、PyTorch CUDA、Isaac Sim CUDA 三者兼容。任何一个不匹配都会导致运行时错误。
- Isaac Lab 版本和 Isaac Sim 版本不对应。 这是最常见的新手错误。查阅 Isaac Lab 的 README 确认版本对应关系。
练习
- 完成 Isaac Lab 的 L0-L6 验证。如果安装过程中遇到错误,记录错误信息和你的解决方法——这本身就是宝贵的工程经验。
- 比较 mjlab 和 Isaac Lab 从
git clone到 L6 通过所需的总时间。你的实测结果与 Ch01 中"mjlab 10 分钟 vs Isaac Lab 30-60 分钟"的说法是否一致? - 尝试在 Isaac Lab 中不加
--headless运行(如果你在远程服务器上)。观察错误信息——它是否足够清晰地告诉你问题在哪? - 用
python scripts/environments/list_envs.py列出 Isaac Lab 的所有内置任务。数一数每个类别(locomotion/manipulation/dexterous/classic)各有多少个任务。与 §2.3 的任务速览表对照。 - 如果你有兴趣尝试 Isaac Lab 3.0 Beta:切换到 develop branch,按 §2.3 的 kit-less 安装命令安装,用
--visualizer viser运行 CartPole 任务。对比安装时间和启动速度与 2.3.0 的差异。 - (思考题)Isaac Lab 2.3 的安装需要 30-60 分钟,而 mjlab 只需要 2 分钟。从软件工程角度分析:这种差异是否可以避免?Isaac Lab 为了什么功能付出了安装复杂度的代价?kit-less 模式是否解决了这个问题?
两个框架都安装完成后,有一个共同的调试工具值得提前了解——NaN Guard。物理仿真中的 NaN(Not a Number)是最棘手的运行时错误之一,因为它会沉默传播:一个关节速度变成 NaN → 所有 obs 变成 NaN → reward 变成 NaN → 整个训练崩溃,而你在日志中看到的只是最终的 NaN 错误,不知道 NaN 是从哪里开始的。
NaN Guard 初步
mjlab 的 NaN Guard:
mjlab 的 TerminationManager 内置了 NaN/Inf 检测——这是 mjlab 独有的功能(Isaac Lab 没有对应物)。当检测到 NaN 时,mjlab 会保留一段循环 buffer 记录 NaN 发生前的完整物理状态,可以通过 Viser 回放分析 NaN 的来源。
# 开启 NaN 检测
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--enable-nan-guard True \
--env.scene.num-envs 256
# NaN 发生时会:
# 1. 暂停训练
# 2. 打印 NaN 首次出现的位置(哪个环境、哪个变量)
# 3. 导出该环境的完整物理状态供分析
# 4. 可通过 Viser 回放 NaN 前的最后几帧
NaN 的常见来源:
| 来源 | 触发条件 | 症状 |
|---|---|---|
| 接触力过大 | 两个 body 高速碰撞 | 速度突然变成 inf → NaN |
| 关节速度过大 | action scale 太大 | 关节角/速度越界 → 仿真器数值不稳定 |
| reward 计算除零 | 分母为零(如 1/distance 在 distance=0 时) |
reward NaN → value loss NaN |
| obs normalization | running mean 初始化不当 | 归一化后的 obs 出现 NaN |
NaN 调试将在 Ch24(大规模训练与 NaN 排查)中详细讲解。本章只需要知道 --enable-nan-guard True 这个工具的存在——当你在后续训练中遇到 NaN 崩溃时,第一反应就是开启它。
回顾 Ch01 §1.1:仿真的三个角色中,"调试仪器"角色在这里体现——你可以用 NaN Guard 精确定位问题发生的时刻和变量,这在真机上完全不可能。
Isaac Lab 内置任务速览
安装完成后,你可以用 python scripts/environments/list_envs.py 查看所有可用任务。以下是按类别整理的内置任务概览——后续章节会逐一深入:
| 类别 | 代表任务 | DOF | 对应教材章节 | 说明 |
|---|---|---|---|---|
| Classic Control | Isaac-Cartpole-Direct-v0 |
1 | Ch04(教学用) | 最简单的验证任务 |
| Classic Locomotion | Isaac-Ant-Direct-v0 |
8 | Ch04 | OpenAI Gym 经典任务 |
| 四足 Locomotion | Isaac-Velocity-Flat-Anymal-C-v0 |
12 | Ch13 | ANYmal C/D flat/rough |
Isaac-Velocity-Rough-Anymal-D-v0 |
12 | Ch13 | 粗糙地形 + curriculum | |
Isaac-Velocity-Flat-Unitree-Go2-v0 |
12 | Ch13 | Unitree Go1/Go2 | |
| 人形 Locomotion | Isaac-Velocity-Flat-H1-v0 |
19 | Ch14 | Unitree H1 |
Isaac-Velocity-Flat-G1-v0 |
29 | Ch14 | Unitree G1(教材核心机器人) | |
| 机械臂操作 | Isaac-Lift-Cube-Franka-v0 |
7+2 | Ch17 | joint pos / IK-abs / IK-rel 三种 action |
Isaac-Reach-Franka-v0 |
7 | Ch17 | 最简操作任务 | |
| 灵巧手 | Isaac-Repose-Cube-Allegro-v0 |
16 | Ch17 | DexSuite(含 ADR) |
注意 Isaac Lab 的任务名末尾都有版本号(如
-v0),而 mjlab 没有。初次使用时最常见的错误就是忘记加-v0。回顾 Ch01 §1.4:mjlab 的内置任务更精简(velocity/tracking/lift_cube/tennis),但每个都经过框架开发者深度打磨。根据你的研究方向,在后续章节中选择合适的起点任务。
两个框架都安装完成了。接下来对比它们的日常操作界面——CLI 命令和可视化工具。
2.4 CLI 操作对比 ⭐⭐
这一节解决什么问题:建立两个框架日常操作的肌肉记忆,理解 CLI 设计差异背后的工程原因。
动机
安装验证只做一次,但 CLI 操作会贯穿你的整个研究周期——每天执行数十次。理解两个框架的 CLI 差异和设计理念,可以让你的日常工作流更高效。
如果不理解 CLI 设计会怎样
你可能在 mjlab 中习惯了 uv run train <TASK>,然后在 Isaac Lab 中也尝试相同的命令——结果发现不存在。或者你在 Isaac Lab 中用 --task 指定任务名,在 mjlab 中也加 --task——结果发现 mjlab 用位置参数而非命名参数。这些细微差异在频繁操作中会造成反复的低级错误。
核心命令对比
| 操作 | mjlab | Isaac Lab |
|---|---|---|
| 训练 | uv run train <TASK> --env.scene.num-envs 4096 |
python scripts/reinforcement_learning/rsl_rl/train.py --task <TASK> --num_envs 4096 --headless |
| 评估 | uv run play <TASK> --wandb-run-path org/proj/run |
python scripts/reinforcement_learning/rsl_rl/play.py --task <TASK> --checkpoint /path/model.pt |
| Zero Agent | uv run play <TASK> --agent zero |
需自行传入零权重或空 checkpoint |
| Random Agent | uv run play <TASK> --agent random |
需自行编写 random action wrapper |
| 任务列表 | uv run list-envs |
python scripts/environments/list_envs.py |
| 场景导出 | uv run export-scene <TASK> |
内置于 Isaac Sim GUI |
| WandB 集成 | --logger.wandb.entity/project 命令行参数 |
需要在 config 或环境变量中配置 |
| Headless 模式 | 默认 headless,--viewer 开启 |
默认有 GUI,--headless 关闭 |
CLI 设计差异的工程原因
| 差异 | mjlab 设计 | Isaac Lab 设计 | 原因 |
|---|---|---|---|
| 入口方式 | uv run(项目工具) |
python scripts/(脚本直接执行) |
mjlab 使用 uv 的 project script 功能;Isaac Lab 更传统 |
| 任务指定 | 位置参数(第一个参数) | --task 命名参数 |
mjlab 认为任务是最常指定的参数,应该最简洁 |
| 默认模式 | Headless(适合远程服务器) | GUI(适合本地工作站) | mjlab 的用户多在远程训练;Isaac Lab 的用户可能有本地 GPU |
| Checkpoint 管理 | WandB 原生(--wandb-run-path) |
本地路径 | mjlab 默认所有实验上 WandB;Isaac Lab 更灵活但需手动管理 |
双重解读:CLI 差异可以从两个角度理解:
角度 1(用户体验):mjlab 优化了"远程服务器上快速迭代"的场景——headless 默认、WandB 原生、
uv run不需要激活环境。Isaac Lab 优化了"本地工作站上交互调试"的场景——GUI 默认、丰富的可视化。角度 2(工程哲学):mjlab 追求"约定优于配置"(convention over configuration)——尽量减少需要指定的参数。Isaac Lab 追求"显式优于隐式"(explicit is better than implicit)——所有选项都通过参数明确指定。
一个完整的训练+评估工作流对比
mjlab 工作流:
# 训练(自动上传 WandB)
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--env.scene.num-envs 4096 \
--logger.wandb.entity my-lab \
--logger.wandb.project locomotion
# 评估(从 WandB 拉取 checkpoint)
uv run play Mjlab-Velocity-Flat-Unitree-Go2 \
--wandb-run-path my-lab/locomotion/abc123 \
--viewer
# 录制视频
uv run play Mjlab-Velocity-Flat-Unitree-Go2 \
--wandb-run-path my-lab/locomotion/abc123 \
--record-video --num-episodes 5
Isaac Lab 工作流:
# 训练
python scripts/reinforcement_learning/rsl_rl/train.py \
--task Isaac-Velocity-Flat-Unitree-Go2-v0 \
--num_envs 4096 --headless \
--run_name go2_flat_v1
# 评估
python scripts/reinforcement_learning/rsl_rl/play.py \
--task Isaac-Velocity-Flat-Unitree-Go2-v0 \
--checkpoint logs/rsl_rl/go2_flat_v1/model_5000.pt \
--num_envs 16
# TensorBoard 查看训练曲线
tensorboard --logdir logs/rsl_rl/ --port 6006
CLI 配置覆盖:如何在命令行修改任意参数
两个框架都支持在命令行覆盖 config 中的任意参数——这是日常实验中最常用的功能。但语法略有不同:
mjlab 的 tyro 风格覆盖:
# 修改环境数
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--env.scene.num-envs 2048
# 修改 reward 权重
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--env.rewards.track-lin-vel-xy-exp.weight 2.0
# 修改 action scale
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--env.actions.joint-pos.scale 0.25
# 多个参数同时覆盖
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--env.scene.num-envs 4096 \
--env.rewards.track-lin-vel-xy-exp.weight 2.0 \
--num-iterations 3000
Isaac Lab 的 argparse 覆盖:
# Isaac Lab 的命令行参数更传统
python scripts/reinforcement_learning/rsl_rl/train.py \
--task Isaac-Velocity-Flat-Anymal-C-v0 \
--num_envs 4096 \
--max_iterations 3000 \
--headless
# 修改 config 中的深层参数需要在 Python 代码中做
# 不支持 mjlab 那样的 --env.rewards.xxx.weight 命令行覆盖
| 特性 | mjlab | Isaac Lab |
|---|---|---|
| 命令行覆盖深层参数 | ✅(tyro 风格,任意深度) | ❌(仅支持预定义的命令行参数) |
| 修改 reward 权重 | 命令行 --env.rewards.xxx.weight |
修改 Python config 文件 |
| 修改 obs 项 | 命令行(复杂场景需改 config) | 修改 Python config 文件 |
| 实验管理 | WandB group/tags 命令行指定 | 需在代码中配置 |
这个差异对日常实验效率的影响很大:在 mjlab 中你可以在命令行快速做消融实验(改一个 reward 权重只需要加一个参数),而在 Isaac Lab 中你需要修改 Python config 文件然后重新运行脚本。
本质洞察:CLI 覆盖能力决定了你的实验迭代速度。如果每次修改一个参数都需要编辑文件 → 保存 → 运行,你的迭代效率会比命令行覆盖低 3-5 倍。这就是为什么 mjlab 的 tyro 风格覆盖对研究者如此有吸引力——它把"试一个新 reward 权重"从"修改文件 + 运行脚本"简化为"在命令末尾加一个参数"。
本质洞察:CLI 的默认设置反映了框架设计者对"典型用户场景"的假设。mjlab 默认 headless 是因为它假设用户在远程 GPU 服务器上训练;Isaac Lab 默认 GUI 是因为它假设用户有本地 Omniverse 工作站。理解这些假设可以帮你在第一次使用时就避免最常见的错误(远程不加 headless、本地不开 viewer)。
常用命令速查卡
以下是你在后续章节中最常用的命令,建议打印或保存:
mjlab 速查:
uv run list-envs # 列出所有任务
uv run train <TASK> [OPTIONS] # 训练
uv run play <TASK> --agent zero # 零动作测试
uv run play <TASK> --agent random # 随机动作测试
uv run play <TASK> --wandb-run-path <PATH> # 评估 checkpoint
uv run play <TASK> --viewer # 打开可视化
uv run export-scene <TASK> # 导出场景
Isaac Lab 速查:
python scripts/environments/list_envs.py # 列出所有任务
python scripts/reinforcement_learning/rsl_rl/train.py --task <TASK> --headless # 训练
python scripts/reinforcement_learning/rsl_rl/play.py --task <TASK> --checkpoint <PATH> # 评估
tensorboard --logdir logs/ --port 6006 # 查看曲线
⚠️ 常见陷阱
- 在 mjlab 中忘记加
--viewer。 mjlab 默认 headless,如果你想看可视化必须显式加--viewer。 - 在 Isaac Lab 中忘记加
--headless。 Isaac Lab 默认打开 GUI,在远程服务器上会卡死。 - 混淆两个框架的任务名格式。 mjlab 用
Mjlab-Velocity-Flat-Unitree-Go2,Isaac Lab 用Isaac-Velocity-Flat-Unitree-Go2-v0。注意 Isaac Lab 任务名末尾有版本号-v0。
练习
- 分别用 mjlab 和 Isaac Lab 训练 50 iteration 的 Go2/ANYmal 速度跟踪。对比训练启动时间和 steps/s 吞吐量。记录在 WandB 或笔记中。
- 在两个框架中分别用 zero agent 可视化 Go2/ANYmal。比较 Viser 和 Isaac Sim Viewer 的操作体验——哪个启动更快?哪个在远程使用时更方便?
- 尝试在 mjlab 中使用 tyro 命令行覆盖修改环境数:
uv run train Mjlab-Velocity-Flat-Unitree-Go2 --env.scene.num-envs 256。然后尝试覆盖一个 reward 权重:--env.rewards.track-lin-vel-xy-exp.weight 3.0。观察训练行为的变化。 - 在 Isaac Lab 中,尝试不加
--headless直接在远程服务器上运行训练。记录你看到的错误信息——它是否清楚地告诉了你问题在哪?然后加上--headless重试。
CLI 命令建立了操作的基础,但真正让你"看到"训练效果的是可视化工具。两个框架的可视化方案差异很大——理解它们的优劣可以让你选择更高效的调试方式。
2.5 可视化工具对比 ⭐⭐
这一节解决什么问题:理解两个框架的可视化方案差异,掌握用可视化调试策略行为的基本方法。
动机
可视化是机器人 RL 调试中最重要的工具——没有之一。reward 曲线告诉你"策略在数值上是否改善",但只有可视化才能告诉你"机器人实际在做什么"。一个经典的例子:reward 持续上涨,但可视化后发现机器人靠"卡在地面裂缝中不动"来获取 survival reward——这就是 reward hacking,只有可视化才能发现。
如果不做可视化会怎样
反面案例:某同学训练了一个人形 locomotion 策略,reward 曲线看起来很好——从 0 上升到 15 并稳定。他把这个结果写进了论文初稿。导师让他可视化 checkpoint 看看——结果发现机器人是靠"膝盖着地滑行"来获取前进速度 reward 的,完全不是正常的双足行走。如果他在训练中途(每 200 iter 检查一次)做过可视化,这个问题在 iter 400 就能发现。
三种可视化方案详解
方案一:Viser(mjlab 默认)
Viser 是一个基于 web 的 3D 可视化工具,由 Berkeley 开发。它的核心优势是远程友好——所有渲染在服务器端完成,用户通过浏览器访问。
# 启动带可视化的评估
uv run play Mjlab-Velocity-Flat-Unitree-Go2 --agent zero --viewer
# 输出:
# Viser server running at http://localhost:7860
# 在浏览器中打开此 URL
Viser 界面操作:
| 操作 | 方法 |
|---|---|
| 旋转视角 | 左键拖拽 |
| 缩放 | 滚轮 |
| 平移 | 右键拖拽 |
| 选择机器人 | 点击机器人 body |
| 查看关节角 | 侧边栏显示实时 joint state |
远程服务器使用 Viser:
# 在服务器上启动
uv run play Mjlab-Velocity-Flat-Unitree-Go2 --agent zero --viewer
# 在本地设置 SSH 端口转发
ssh -L 7860:localhost:7860 user@server
# 在本地浏览器访问
# http://localhost:7860
方案二:Isaac Sim Viewer(Isaac Lab 默认)
Isaac Sim Viewer 基于 NVIDIA Omniverse 平台,提供工业级的 RTX 实时光追渲染。它的渲染质量远超 Viser,但需要本地显示器或 VNC 连接。
# 在有显示器的工作站上(不加 --headless)
python scripts/reinforcement_learning/rsl_rl/play.py \
--task Isaac-Velocity-Flat-Anymal-C-v0 \
--checkpoint /path/model.pt
# Isaac Sim GUI 自动打开,包含:
# - 3D 视口(可旋转/缩放/平移)
# - 属性面板(查看物体参数)
# - 时间轴(控制仿真速度)
# - RTX 渲染模式切换
在远程服务器上使用 Isaac Sim Viewer:
# 方案 A:headless + 录制视频
python scripts/reinforcement_learning/rsl_rl/play.py --task <TASK> --checkpoint <PATH> \
--headless --enable_cameras --video --video_length 300
# 方案 B:VNC 远程桌面(需要配置 VNC 服务器)
# 性能受网络带宽限制,不推荐用于高帧率调试
# 方案 C:X11 转发(延迟高,不推荐)
ssh -X user@server
方案三:Rerun(跨框架兼容)
Rerun 是一个新兴的数据流可视化工具,可以记录并回放任意数据(3D 点云、图像、时间序列、标量)。它的核心优势是可以录制整个训练过程的数据,然后离线回放和分析。
| 方案 | 渲染质量 | 远程友好度 | 数据回放 | 适合场景 |
|---|---|---|---|---|
| Viser | 中 | ⭐⭐⭐(web-based) | ❌ 实时只 | 日常调试、远程服务器 |
| Isaac Sim | 高(RTX) | ⭐(需显示器) | 部分 | 视觉策略、论文截图 |
| Rerun | 中 | ⭐⭐ | ✅ 全量录制+回放 | 详细行为分析、长时间训练 |
方案三:Rerun(跨框架数据流可视化)
Rerun(rerun.io)与 Viser 和 Isaac Sim Viewer 互补。它的核心能力不是实时 3D 渲染,而是录制并回放任意数据流——你可以在一个时间轴上同时查看 3D 姿态、关节角轨迹、接触力时间序列、reward 分项曲线。
# 安装 Rerun
pip install rerun-sdk
# 在 mjlab 中使用(需要在代码中添加 logging)
# 具体集成方法见 Rerun 官方文档的 MuJoCo 教程
Rerun 的典型用途:当你发现某个 episode 的 reward 异常(突然下降或触发 termination),你需要回答"在第 137 步到底发生了什么"。Rerun 可以让你回放这个 episode 的完整数据,慢放到第 137 步附近,同时查看关节角、接触力和 reward 分项——这种时间序列级的调试在 Viser 和 Isaac Sim Viewer 中都做不到。
远程服务器可视化方案对比
大多数研究者的 GPU 在远程服务器上。以下是四种远程可视化方案的详细对比:
| 方案 | 配置复杂度 | 延迟 | 渲染质量 | 适合场景 |
|---|---|---|---|---|
| SSH + Viser | ⭐ 低(一行 SSH 命令) | 低 | 中 | 日常调试、远程训练(推荐) |
| headless + 录视频 | ⭐ 低(加 --record-video) |
无(离线) | 高 | 论文截图、批量评估 |
| VNC 远程桌面 | ⭐⭐⭐ 高(需配 VNC 服务器) | 中-高 | 高 | 需要 GUI 交互的调试 |
| X11 转发 | ⭐⭐ 中 | 高(不可用) | — | 不推荐(太慢) |
对于 99% 的日常使用场景,SSH + Viser 是最佳方案——配置简单(ssh -L 7860:localhost:7860),延迟低,不需要在服务器上安装任何 GUI 软件。只有在需要 RTX 级别渲染质量(论文 figure、视频 demo)时才需要考虑其他方案。
Isaac Lab 3.0 kit-less 模式的新可视化选项
Isaac Lab 3.0 的 kit-less 安装模式支持三种 visualizer,不再依赖 Isaac Sim GUI:
| Visualizer | 命令参数 | 说明 |
|---|---|---|
| Newton Warp | --visualizer newton |
Newton 内置渲染器,快但无 RTX |
| Rerun | --visualizer rerun |
时间序列可视化,适合调试 |
| Viser | --visualizer viser |
与 mjlab 相同的 web-based 体验 |
这意味着在 kit-less 模式下,Isaac Lab 的可视化体验和 mjlab 几乎一样——都是 web-based、远程友好的。这进一步降低了双框架切换的成本。
| 方案 | 渲染质量 | 远程友好度 | 数据回放 | 适合场景 |
|---|---|---|---|---|
| Viser | 中 | ⭐⭐⭐(web-based) | ❌ 实时只 | 日常调试、远程服务器 |
| Isaac Sim | 高(RTX) | ⭐(需显示器) | 部分 | 视觉策略、论文截图 |
| Rerun | 中 | ⭐⭐ | ✅ 全量录制+回放 | 详细行为分析、长时间训练 |
| Newton Warp | 中 | ⭐⭐ | ❌ | kit-less 快速预览 |
可视化调试的工作流
不论使用哪个工具,可视化调试都应遵循以下工作流:
| 步骤 | 做什么 | 目的 |
|---|---|---|
| 1. Zero agent 可视化 | 查看机器人默认姿态 | 验证模型加载正确(关节角、碰撞体、地面高度) |
| 2. Random agent 可视化 | 查看随机动作效果 | 验证 action scale 合理(不爆飞、不卡死) |
| 3. 训练中定期可视化 | 每 200-500 iter 检查一次 | 及早发现 reward hacking 或行为异常 |
| 4. 最终 checkpoint 可视化 | 多角度、多场景检查 | 确认策略质量达标 |
| 5. 失败案例可视化 | 查看 termination 前的行为 | 理解策略在什么情况下失败 |
本质洞察:可视化不只是"看看效果",而是一种系统性的调试方法。就像软件工程中的 print debugging 和 breakpoint debugging——reward 曲线是 print(告诉你数值),可视化是 breakpoint(让你看到完整状态)。
可视化时具体关注什么
新手最常犯的错误是"打开了可视化但不知道看什么"——看了 10 秒就关掉。以下是每个阶段应该关注的具体细节:
Zero agent 阶段: - 机器人的初始站姿是否自然?关节角度是否对称? - 脚底是否接触地面(而非悬浮或穿透)? - 碰撞体(collision geometry)是否和视觉模型对齐? - 如果有多个机器人(多环境可视化),它们的初始位置和方向是否正确分布?
Random agent 阶段: - 动作幅度是否合理?(机器人应该有明显的运动但不应该"爆炸"——四肢不应该穿过身体) - action scale 是否太大或太小?太大→机器人动作剧烈甚至飞出去;太小→几乎看不到运动 - 关节是否碰到了限位?(通常表现为某些关节卡在极端位置不动)
训练中期: - 步态是否对称?(四足应该是交替步态,不应该一直用同一侧的腿) - 基座是否稳定?(不应该有明显的上下颠簸或左右摇摆) - 转向时是否平滑?(不应该急停急转) - 有没有"exploit"行为?(如卡在地面缝隙中不动来获取 alive reward)
失败案例: - 摔倒前最后 0.5 秒发生了什么?(是某条腿滑了?是转向太急?是遇到了地形变化?) - termination 的原因是什么?(超时?身体接触地面?关节超限?) - 失败是否有模式?(总在相同的地形位置失败→地形参数可能需要调整)
训练中途可视化的实践
mjlab 支持在训练进行时同时可视化(训练和可视化在同一进程中,通过 --viewer 参数开启)。Isaac Lab 通常需要先暂停训练、保存 checkpoint、再单独可视化。
# mjlab:训练时同时可视化(仅用于短时间调试,会降低训练速度)
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--env.scene.num-envs 256 \
--viewer
# Isaac Lab:从训练目录中加载最新 checkpoint 可视化
python scripts/reinforcement_learning/rsl_rl/play.py \
--task Isaac-Velocity-Flat-Anymal-C-v0 \
--checkpoint logs/rsl_rl/<run>/model_latest.pt \
--num_envs 4
⚠️ 常见陷阱
- 在无显示服务器上使用 Isaac Sim Viewer。 会卡死。始终加
--headless。 - 忘记 SSH 端口转发就访问 Viser。 浏览器无法直接访问远程服务器的 7860 端口。需要
ssh -L 7860:localhost:7860。 - 只看 reward 曲线不看可视化。 reward 曲线能告诉你"是否在改善",但不能告诉你"改善是否合理"。务必定期可视化 checkpoint。
- 可视化时环境数太多。 可视化 4096 个机器人会让渲染变得很慢。评估时用 4-16 个环境足够。
- 忽视失败案例。 策略的失败行为(如摔倒前的姿态、碰撞时的接触力)包含了大量调试信息。专门可视化 termination 前 0.5 秒的行为。
练习
- 在 mjlab 中用 Viser 可视化一个 zero agent 的 Go2。尝试在 Viser 界面中旋转/缩放视角,观察机器人的默认关节角度。截图记录。
- 如果你有本地 GPU 工作站,尝试在 Isaac Lab 中打开 Isaac Sim Viewer 并可视化 ANYmal。比较与 Viser 的渲染质量和操作便利性。
- 在 mjlab 中训练 200 iteration 后用
--viewer可视化。描述你看到的机器人行为——它在尝试什么?成功了吗? - 尝试用 SSH 端口转发在远程服务器上访问 Viser:
ssh -L 7860:localhost:7860 user@server。然后在本地浏览器打开http://localhost:7860。记录你遇到的任何问题。 - (思考题)在可视化调试工作流中,为什么"zero agent 可视化"排在"random agent 可视化"之前?如果反过来(先 random 再 zero),你可能会错过什么信息?
所有安装和工具都就绪了。最后一步:跑通你的第一次完整训练,确认整个管线端到端正常工作。
2.6 第一次完整训练 ⭐⭐
这一节解决什么问题:在两个框架中各完成一次完整训练(非最小验证,而是 4096 环境的正式训练),建立对训练过程的直觉。
动机
L6 的 16 环境最小训练只验证了"管线能跑",但 16 个环境的数据量远远不够让策略学到有意义的行为。本节用 4096 环境做一次正式训练,让你看到完整的训练过程:reward 从零开始上升,机器人从摔倒到站立到行走。
如果不做完整训练就进入下一章
Ch03 开始讨论物理引擎的参数调优,Ch04 开始精读 Manager-Based 架构——这些内容都建立在"你已经亲眼看过一次完整训练"的基础上。如果你跳过这一步,后续的讨论都是纸上谈兵。
mjlab 完整训练
# 训练 Go2 速度跟踪(flat terrain,~20 分钟在 A100 上收敛)
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--env.scene.num-envs 4096 \
--num-iterations 1500 \
--logger.wandb.entity your-org \
--logger.wandb.project ch02-first-train
训练过程中你应该观察到以下四个阶段——这不只是"知道就好"的背景知识,而是你后续调试 reward 和 DR 时的基准参照:
| 阶段 | 迭代范围 | reward 表现 | 机器人行为 | 你应该关注什么 |
|---|---|---|---|---|
| 初始 | 0-100 | 接近零或负值 | 原地摔倒、抽搐 | 如果 reward 是 NaN 或极端值 → 配置有 bug |
| 探索 | 100-500 | 缓慢上升 | 尝试站立、偶尔迈步 | 如果 500 iter 后仍然趴着 → obs 或 action 可能有问题 |
| 学习 | 500-1000 | 快速上升 | 开始稳定行走、跟踪速度指令 | 正常阶段,reward 应该有明显的上升斜率 |
| 收敛 | 1000-1500 | 趋于平台 | 行走流畅、能跟踪不同速度和转向 | reward 波动变小,episode length 趋于稳定 |
如果你的训练不符合上述模式怎么办?
| 异常现象 | 可能原因 | 快速排查 |
|---|---|---|
| reward 始终为 0 | obs 全是零/reward 函数返回常数 | 打印 obs 和 reward 分项 |
| reward 为 NaN | 物理仿真不稳定(穿透、速度爆炸) | 用 --enable-nan-guard True 定位 NaN 源头 |
| reward 上升但很慢 | learning rate 太低 / num_envs 太少 | 增加环境数到 4096,检查 lr |
| reward 快速上升但行为丑 | reward hacking | 可视化 checkpoint,检查 reward 分项权重 |
| episode length 不增长 | termination 条件太严格 | 放宽 termination 条件或降低初始难度 |
Isaac Lab 完整训练
python scripts/reinforcement_learning/rsl_rl/train.py \
--task Isaac-Velocity-Flat-Anymal-C-v0 \
--num_envs 4096 --max_iterations 1500 --headless
Isaac Lab 的训练日志默认保存在 logs/rsl_rl/<task_name>/<run_name>/ 目录下。你可以用 TensorBoard 查看:
tensorboard --logdir logs/rsl_rl/ --port 6006
# 然后浏览器访问 http://localhost:6006
训练指标详解
训练过程中,WandB/TensorBoard 会记录多个指标。本章需要你理解以下核心指标(Ch07 会讲完整的指标集):
| 指标 | 含义 | 健康范围 | 异常时怎么想 |
|---|---|---|---|
reward/total |
每个 step 的平均总 reward | 持续上升,最终趋于稳定 | 不涨→检查 obs/reward;下降→策略崩溃 |
episode_length |
每个 episode 的平均长度 | 持续增加 | 不增→termination 太严或任务太难 |
policy/kl_divergence |
策略更新的 KL 散度 | 0.005-0.02 | >0.05→lr 太大;<0.001→lr 太小或已收敛 |
policy/entropy |
策略的动作熵 | 缓慢下降 | 骤降→策略过早坍缩;不降→探索不够 |
loss/value |
Value 网络的预测误差 | 应该逐渐下降 | 不降→critic 没学到有用信息 |
如果不理解这些指标会怎样:你看到 reward 在 500 iteration 后停止上升,但 KL 已经很小了——你不知道这意味着"策略已经收敛到当前 reward 能到达的最优"还是"学习率太低导致更新量不够"。Ch07 会系统性地讲解这些指标的联合解读方法。
WandB 训练面板实操指南
如果你正确配置了 WandB,训练过程中你的 WandB 项目页面应该显示以下面板:
核心图表(每次训练都要看的):
| 面板名称 | X 轴 | Y 轴 | 正常形状 | 异常信号 |
|---|---|---|---|---|
Train/mean_reward |
iteration | 平均 total reward | 上升后趋稳 | 平的/下降/NaN |
Train/mean_episode_length |
iteration | 平均 episode 长度 | 上升后趋稳 | 不增/振荡 |
Loss/policy_loss (surrogate) |
iteration | PPO 的 surrogate loss | 接近 0 | 正值增大→策略崩溃 |
Loss/value_loss |
iteration | critic 的 value 预测误差 | 逐渐下降 | 不降→critic 没学到东西 |
诊断图表(出问题时再看的):
| 面板名称 | 正常范围 | 异常及含义 |
|---|---|---|
Policy/kl |
0.005-0.02 | >0.05→更新太激进→降 lr |
Policy/entropy |
缓慢下降 | 骤降→策略过早坍缩→增 entropy_coef |
Policy/mean_noise_std |
缓慢下降 | 不降→策略没信心→检查 obs |
Train/fps |
接近 GPU 理论峰值 | 远低于预期→检查 viewer/video/sensor |
WandB 的几个实用功能:
| 功能 | 操作 | 典型用途 |
|---|---|---|
| Run Compare | 勾选多个 run → 点 "Compare" | 对比不同 reward 权重的训练曲线 |
| Group by | 右上角 Group → 选择参数 | 按 terrain_type 或 num_envs 分组 |
| Smooth | 曲线右上角拖拽 smoothing 滑块 | 去除高频噪声看趋势 |
| Step axis | X 轴切换 → Wall Time | 对比不同 GPU 的实际训练时间 |
这些功能在 Ch06(reward 消融)和 Ch07(超参调优)中会密集使用。本章只需要知道它们的存在——在训练完成后花 5 分钟探索 WandB 界面即可。
双框架训练对比
在两个框架中训练同一个机器人的同一个任务是理解框架差异的最佳方式。以下是一组参考数据(实际数值取决于 GPU 型号和具体配置):
| 维度 | mjlab (Go2 flat) | Isaac Lab (ANYmal flat) |
|---|---|---|
| 启动时间 | ~2 秒 | ~20 秒 |
| 4096 envs 吞吐量 | ~50,000 steps/s | ~40,000 steps/s |
| 1500 iter 训练时间 | ~15 分钟 | ~20 分钟 |
| 最终 reward | ~15-20 | ~12-18(任务不同,不可直接比较) |
| 默认 obs 维度 | ~48 | ~48(配置不同可能有差异) |
注意 reward 数值不能跨框架直接比较——因为两个框架的 reward 函数配置不同(权重、sigma、项数都可能不同)。有意义的比较是行为质量(通过可视化判断)和训练效率(steps/s)。
训练过程中的 5 个关键可视化时刻
不要等训练完成才可视化——在训练过程中的以下 5 个时刻各做一次可视化检查:
| 时刻 | 迭代 | 检查什么 | 正常表现 | 异常信号 |
|---|---|---|---|---|
| 启动后立刻 | 0-10 | 初始姿态是否正确 | 机器人站在地面上 | 穿透地面/悬浮/关节扭曲 |
| 探索初期 | ~100 | 是否有站立的趋势 | 开始尝试平衡 | 完全躺着不动→obs 可能全零 |
| 学习加速期 | ~500 | 步态雏形 | 迈出不稳的步伐 | 只靠一条腿蹦→reward hacking |
| 接近收敛 | ~1000 | 步态质量 | 四腿交替、节奏稳定 | 步态不对称→需 symmetry reward |
| 训练结束 | ~1500 | 多指令响应 | 能跟踪不同速度/转向 | 只会直走不会转→command 范围太窄 |
每次可视化只需要 30 秒——暂停当前训练的 iteration 计数器,加载最新 checkpoint,观察几个 episode 的行为。如果发现问题,在训练中途修正比训练完再重跑节省大量时间。
Isaac Lab 的 TensorBoard 训练监控
如果你选择 Isaac Lab(默认使用 TensorBoard 而非 WandB),训练曲线的查看方式略有不同:
# 启动 TensorBoard
tensorboard --logdir logs/rsl_rl/ --port 6006
# SSH 端口转发(远程服务器)
ssh -L 6006:localhost:6006 user@server
# 浏览器访问
# http://localhost:6006
TensorBoard 和 WandB 的核心指标名称略有不同:
| 指标 | WandB (mjlab) | TensorBoard (Isaac Lab) | 含义相同 |
|---|---|---|---|
| 总 reward | Train/mean_reward |
Train/mean_reward |
✅ |
| Episode 长度 | Train/mean_episode_length |
Train/mean_episode_length |
✅ |
| KL 散度 | Policy/kl |
Loss/policy_kl |
✅ |
| Value loss | Loss/value_loss |
Loss/value_function |
✅ |
| Entropy | Policy/entropy |
Loss/entropy |
✅ |
| 学习率 | Policy/learning_rate |
Loss/learning_rate |
✅ |
WandB 的优势在于:(1) 多实验曲线叠加对比,(2) 云端存储不怕丢失,(3) sweep 自动化。TensorBoard 的优势在于:(1) 无需注册账号,(2) 本地运行更快,(3) 不依赖网络。对于 Ch02 的第一次训练,两者都够用。Ch07 会详细讨论实验管理的最佳实践。
训练完成后的验证
训练完成后,必须用可视化验证行为质量——reward 数值高不代表行为好:
# mjlab:用 WandB 拉取最新 checkpoint 评估
uv run play Mjlab-Velocity-Flat-Unitree-Go2 \
--wandb-run-path your-org/ch02-first-train/<run-id> \
--viewer --num-episodes 10
# Isaac Lab:指定本地 checkpoint 评估
python scripts/reinforcement_learning/rsl_rl/play.py \
--task Isaac-Velocity-Flat-Anymal-C-v0 \
--checkpoint logs/rsl_rl/<run_name>/model_1500.pt \
--num_envs 16
可视化时重点检查以下行为:
| 检查项 | 好的策略 | 差的策略(可能是 reward hacking) |
|---|---|---|
| 步态 | 对称、节奏稳定 | 拖脚、抽搐、不对称 |
| 速度跟踪 | 指令变化时平滑过渡 | 急停急转、剧烈摇摆 |
| 身体姿态 | 躯干平稳、轻微晃动 | 躯干大幅倾斜、摆动 |
| 足端接触 | 清晰的抬腿-落地 | 拖地滑行、足端打滑 |
| 转向 | 弧线转向,速度降低 | 原地旋转或急转 |
本质洞察:第一次完整训练的目的不是调出最优策略,而是建立对训练过程的体感——reward 曲线的形状、收敛的时间量级、机器人行为随训练进展的变化。这个体感是后续所有章节讨论 reward 设计(Ch06)、DR(Ch08)、超参调优(Ch07)时的直觉基础。没有这个体感,那些讨论就是纸上谈兵。
你的第一个实验日志
建议你在第一次训练后写一份简短的实验日志(可以用 WandB 的 notes 功能):
实验:Ch02 第一次完整训练
框架:mjlab
任务:Mjlab-Velocity-Flat-Unitree-Go2
GPU:NVIDIA A100-80GB
环境数:4096
迭代数:1500
训练时间:XX 分钟
最终 reward:XX
观察:
- 约 iter 200 开始站立
- 约 iter 600 开始稳定行走
- 转向动作在 iter 1000 后变得平滑
- 足端有轻微滑移(Ch06 会讨论 foot slip penalty)
这个习惯看起来微小,但对于建立你的"训练直觉数据库"非常有价值。半年后你回看这些笔记,会发现它们帮你快速定位新任务训练中的异常——"这个 reward 曲线和我第一次训练 Go2 flat 时不一样,当时 500 iter 就开始上升了,现在 1000 iter 还没动静,一定是哪里配置错了"。
不同 GPU 的预期训练时间
以下是 Go2 flat terrain 任务(4096 envs \(\times\) 1500 iter)在不同 GPU 上的预期训练时间:
| GPU | 显存 | FPS (steps/s) | 训练时间 | 说明 |
|---|---|---|---|---|
| RTX 3090 | 24 GB | ~45,000 | ~40 min | 入门级研究 GPU |
| RTX 4090 | 24 GB | ~60,000 | ~25 min | 性价比最高 |
| A100 80GB | 80 GB | ~80,000 | ~18 min | 标准研究 GPU |
| H100 80GB | 80 GB | ~100,000 | ~15 min | 高端研究 GPU |
| T4 (Colab) | 16 GB | ~15,000 | ~90 min | 适合 demo,不适合正式实验 |
数据来源:NVIDIA Technical Blog "Closing the Sim-to-Real Gap"(RTX 4090 上 85-95k FPS 对 Spot 任务)+ 社区 benchmark。Go2 任务比 Spot 简单,FPS 略低但在同一量级。
如果你的训练时间明显超过上表(如在 4090 上需要 2 小时),很可能不是 GPU 太慢,而是配置有问题——检查是否意外开启了 viewer(--viewer 会严重拖慢训练)、是否开启了视频录制、或者 WandB 上传是否阻塞了训练循环。
训练后应该问自己的 10 个问题
完成第一次训练后,用以下 checklist 验证你的结果是否合理:
| # | 问题 | 健康标准 | 如果不满足 |
|---|---|---|---|
| 1 | reward 在 500 iter 后有上升趋势吗? | 是 | 检查 obs/reward 配置 |
| 2 | episode length 在增加吗? | 是 | 检查 termination 是否太严 |
| 3 | KL divergence 保持在 0.005-0.02? | 是 | 过大→降 lr;过小→已收敛或 lr 太低 |
| 4 | entropy 在缓慢下降吗? | 是 | 骤降→策略过早坍缩 |
| 5 | 可视化后行为合理吗? | 是 | reward hacking 或 obs 问题 |
| 6 | 步态对称吗? | 大致对称 | 可能需要 symmetry reward |
| 7 | 足端有严重滑移吗? | 轻微滑移正常 | 添加 foot slip penalty |
| 8 | 转向时速度下降吗? | 轻微下降正常 | 急停急转需要检查 command 范围 |
| 9 | 训练时间和预期相符吗? | 参考上表 | 检查 viewer/video/WandB 配置 |
| 10 | WandB 上能看到完整的训练曲线吗? | 是 | 检查 WandB 登录和项目配置 |
前 4 个问题可以从 WandB 曲线回答,第 5-8 个需要可视化 checkpoint,最后 2 个是工程检查。养成"训练完先过一遍这个 checklist"的习惯。
⚠️ 常见陷阱
- 训练时间预期不合理。 4096 环境 \(\times\) 1500 iteration 在 A100 上约 20 分钟,在 RTX 3090 上约 40 分钟。如果训练超过 2 小时还没收敛,很可能是配置问题(而非需要更多迭代)。
- reward 不涨就加 iteration。 如果 500 iteration 后 reward 完全没有上升趋势(不是上升慢,是完全平的),问题不在 iteration 数量,而在环境配置。检查 obs 是否正确、reward 权重是否合理、action scale 是否过大。
- 只看最终 reward 不看中间过程。 最终 reward 相同的两个策略可能行为完全不同(一个优雅行走,一个靠 reward hacking 得分)。务必用可视化检查。
练习
- 在 mjlab 中完成 Go2 flat terrain 的完整训练(1500 iteration),记录总训练时间和最终 reward 值。在 WandB 上截图你的训练曲线。
- 在训练过程中,在 iteration 100/500/1000/1500 各可视化一次。描述你观察到的行为变化——从"倒地不动"到"迈出第一步"到"稳定行走",每个阶段的转变发生在什么时候?
- 使用训练后 10 问 checklist 评估你的训练结果。哪些问题你能从 WandB 回答?哪些需要可视化?
- 用两个不同的 random seed(如 42 和 43)训练同一任务,在 WandB 中使用 Run Compare 比较两条曲线。最终 reward 差多少?这说明了单次训练结果的可靠程度。
- (跨章综合题)回顾 Ch01 的 env.step() 7 步时序和训练数据量参考表。将你的实测 FPS 与 Ch01 和本章的 GPU 时间对照表对比。差异可能来自什么因素?(提示:GPU 型号、环境数量、任务复杂度、sensor 配置。)
如何读懂训练终端日志
训练过程中,终端会打印每个 iteration 的摘要信息。以 mjlab 为例:
[2026-05-20 14:32:15] iter: 100/1500 | mean_reward: 3.42 | mean_ep_len: 45.2
policy_loss: -0.0123 | value_loss: 12.34 | kl: 0.0089 | entropy: 2.31
fps: 58234 | collection_time: 0.42s | learning_time: 0.18s
每个字段的含义和健康范围:
| 字段 | 含义 | 健康范围 | 异常处理 |
|---|---|---|---|
mean_reward |
所有环境的平均 episode 总 reward | 逐步增加 | 不涨→检查 reward 配置 |
mean_ep_len |
平均 episode 步数 | 逐步增加至最大值 | 不增→termination 太严 |
policy_loss |
PPO surrogate loss | 接近 0(可正可负) | 持续正值增大→策略崩溃 |
value_loss |
Critic 的 MSE loss | 逐步下降 | 不降→critic 网络太小或 obs 不足 |
kl |
策略更新前后的 KL 散度 | 0.005-0.02 | >0.05→lr 太大 |
entropy |
策略的熵(探索度) | 缓慢下降 | 骤降→过早坍缩 |
fps |
每秒环境步数 | 参考 GPU 时间表 | 远低于预期→检查 viewer/sensor |
collection_time |
rollout 数据收集时间 | < 1s | >>1s→env.step() 太慢 |
learning_time |
PPO 梯度更新时间 | < 0.5s | >>0.5s→网络太大或 mini_batch 太多 |
反事实推理:如果你不看终端日志,只看 WandB 图表,你会错过
fps和collection_time——这两个指标对于判断"训练慢是因为物理仿真慢还是因为 PPO 更新慢"至关重要。
sim2sim 预验证(30 秒 smoke test)
完整训练后,有一个额外的验证步骤值得在 Ch02 就建立习惯:sim2sim 验证——把在 GPU 仿真器中训练的策略导出为 ONNX,然后在 CPU MuJoCo 中运行,检查行为是否一致。
为什么要做这一步?因为 GPU 仿真器(MuJoCo Warp / PhysX)和 CPU MuJoCo 的数值行为不完全相同——浮点运算顺序不同、并行归约的舍入方式不同。如果你的策略严重依赖仿真器的特定数值行为(reward hacking 的一种形式),它在 CPU MuJoCo 或真机上的表现会大幅下降。
# mjlab:导出 ONNX(Ch07 详解,这里只做 smoke test)
uv run play Mjlab-Velocity-Flat-Unitree-Go2 \
--wandb-run-path your-org/ch02-first-train/<run-id> \
--export-onnx
# 如果导出成功,你会在 logs/ 目录看到 policy.onnx 文件
# Ch23 将教你如何在 CPU MuJoCo 中加载并运行这个 ONNX 模型
在 Ch02 阶段,你只需要确认 ONNX 导出不报错。完整的 sim2sim 验证流程(加载 ONNX → CPU MuJoCo 运行 → 行为对比)将在 Ch23(Sim2Real 部署)中详细讲解。
ONNX 导出的一个已知坑:如果你使用 RNN(LSTM/GRU)模型,Isaac Lab 的 ONNX exporter 硬编码了 LSTM——使用 GRU 会报错(Isaac Lab issue #3008)。Ch07 会提供 workaround。对于 Ch02 的默认 MLP 模型,ONNX 导出不会有问题。
完整训练跑通了,你现在有了一个可工作的双框架环境。最后一步是回顾整个安装过程,总结两个框架的工程差异——这些差异将在后续 26 个章节中反复出现。
2.7 双框架安装与使用的工程对比总结 ⭐⭐
这一节解决什么问题:系统性总结本章的双框架对比经验,建立可查阅的对照表。
动机
经过 2.2-2.6 的实操,你已经亲身体验了 mjlab 和 Isaac Lab 的差异。但这些差异散落在各个步骤中。本节把它们汇总为一张完整的对照表,供后续章节随时查阅。
全流程对比
| 环节 | mjlab | Isaac Lab | 差异来源 |
|---|---|---|---|
| 环境创建 | uv sync(自动创建 .venv) |
conda create + pip install |
uv vs conda 的包管理哲学 |
| 安装时间 | ~2 分钟 | ~15-60 分钟 | Isaac Lab 依赖链更长 |
| GPU 验证 | 首次运行时(MuJoCo Warp JIT 编译) | 安装时(Isaac Sim 检查 CUDA) | JIT vs AOT 编译策略 |
| 任务列表 | uv run list-envs |
python scripts/environments/list_envs.py |
入口方式不同 |
| 训练命令 | uv run train <TASK> |
python scripts/reinforcement_learning/rsl_rl/train.py --task <TASK> |
项目脚本 vs 直接执行 |
| 默认模式 | Headless | GUI | 目标用户场景不同 |
| 可视化 | Viser(浏览器,远程友好) | Isaac Sim Viewer(本地 GUI) | 轻量 vs 功能丰富 |
| 实验管理 | WandB 原生集成 | 需额外配置 WandB/TensorBoard | 框架默认设定不同 |
| Checkpoint 管理 | WandB run path | 本地文件路径 | 云端 vs 本地 |
| 启动延迟 | ~2 秒 | ~15-30 秒 | MuJoCo Warp 轻量 vs Isaac Sim 初始化 |
| RL 后端 | RSL-RL(PPO,另含 Distillation) | RSL-RL / RL Games / SKRL / SB3 | 单一 vs 多选 |
从安装差异看框架设计哲学
双重解读:安装过程的差异反映了两个框架的核心设计选择——
角度 1(最小依赖 vs 完整生态):mjlab 选择最小化依赖链(MuJoCo Warp + RSL-RL + WandB),以"10 分钟从零到训练"为设计目标。Isaac Lab 选择完整生态集成(Isaac Sim/Omniverse + 多 RL 后端 + RTX 渲染),以"一个平台覆盖所有需求"为设计目标。
角度 2(约定 vs 配置):mjlab 用更多的"约定"来减少配置量——默认 headless、默认 WandB、默认 RSL-RL。Isaac Lab 用更多的"配置"来提供灵活性——可选 headless/GUI、可选 WandB/TB、可选 RL 后端。
本质洞察:两个框架的安装复杂度差异不是"技术水平"差异,而是设计目标差异。mjlab 为"快速验证一个想法"优化——安装快、启动快、默认值合理。Isaac Lab 为"构建一个完整的研究平台"优化——功能多、可定制、社区大。理解这个差异可以帮你在正确的场景选择正确的工具,而不是在"哪个更好"上浪费时间。
什么时候需要同时使用两个框架?
在后续章节中,有几种场景需要你在两个框架之间切换:
| 场景 | 用 mjlab 做什么 | 用 Isaac Lab 做什么 |
|---|---|---|
| 快速验证 reward 设计 | 在 mjlab 中快速迭代(2 秒启动) | — |
| 视觉策略训练 | — | 用 Isaac Lab 的 RTX 渲染 |
| sim2sim 验证 | 在 MuJoCo 中验证 | 在 PhysX 中验证 |
| 多算法对比 | — | 用 Isaac Lab 切换 RL 后端 |
| 论文复现 | 复现基于 mjlab 的论文 | 复现基于 Isaac Lab 的论文 |
| Colab demo | 用 mjlab(一条命令安装) | — |
环境隔离最佳实践
同时使用两个框架时,环境隔离是关键:
# 推荐的目录结构
~/research/
├── mjlab/ # mjlab 项目(uv 管理的 .venv)
│ ├── .venv/
│ ├── pyproject.toml
│ └── logs/
├── IsaacLab/ # Isaac Lab 项目(conda 环境 isaaclab)
│ ├── scripts/
│ └── logs/
└── shared/ # 共享资源
├── urdfs/ # 机器人 URDF 文件
├── motions/ # 动作数据(AMASS 等)
└── checkpoints/ # 跨框架共享的 checkpoint
# 切换框架时的操作
cd ~/research/mjlab && uv run train ... # mjlab
cd ~/research/IsaacLab && conda activate isaaclab && python scripts/... # Isaac Lab
环境健康快速检查脚本
以下是一个一键检查双框架环境是否健康的脚本模板,建议保存为 check_env.sh:
#!/bin/bash
echo "====== 环境健康检查 ======"
echo ""
echo "--- GPU ---"
nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader
echo ""
echo "--- Python ---"
python --version
echo ""
echo "--- PyTorch ---"
python -c "import torch; print(f'PyTorch {torch.__version__}, CUDA {torch.version.cuda}, GPU available: {torch.cuda.is_available()}')"
echo ""
echo "--- mjlab ---"
cd ~/research/mjlab 2>/dev/null && uv run python -c "import mjlab; print(f'mjlab {mjlab.__version__}')" 2>/dev/null || echo "mjlab: 未安装或路径不对"
echo ""
echo "--- Isaac Lab ---"
conda run -n isaaclab python -c "import isaaclab; print(f'Isaac Lab {isaaclab.__version__}')" 2>/dev/null || echo "Isaac Lab: 未安装或环境名不对"
echo ""
echo "====== 检查完成 ======"
每次换机器、更新 driver 或升级框架后运行一次,30 秒内确认所有组件状态。
环境复现:从"我的电脑上能跑"到"任何电脑上都能跑"
一个常被忽视的最佳实践是环境可复现性。当你在 3 个月后换了一台新机器,或者实验室新来的同学需要复现你的结果,你需要精确地重建当前的软件环境。
mjlab 的环境复现(uv 原生支持):
# uv.lock 文件精确记录了所有依赖的版本
# 只需要 clone 仓库 + uv sync,环境完全一致
git clone <your-repo>
cd <your-repo>
uv sync # 根据 uv.lock 精确安装相同版本
# 验证版本一致性
uv run python -c "import mjlab; print(mjlab.__version__)"
Isaac Lab 的环境复现(需要更多手动工作):
# 保存当前环境
pip freeze > requirements_isaaclab.txt
conda list --export > conda_env.txt
# 在新机器上重建
conda create -n isaaclab python=3.10
conda activate isaaclab
pip install -r requirements_isaaclab.txt
Docker 方案(最可靠但学习曲线最陡):
# mjlab 和 Isaac Lab 都提供了官方 Docker 镜像
# 这是发论文时保证可复现性的最佳方案
docker pull ghcr.io/mujocolab/mjlab:latest
docker run --gpus all -it ghcr.io/mujocolab/mjlab:latest
如果不做环境复现会怎样:论文审稿人要求复现你的结果。你把代码发给他,他装了一个不同版本的 PyTorch,训练出来的结果和你的差 15%。你们为此来回邮件两周——最后发现是 PyTorch 版本差异导致 CUDA kernel 的数值行为不同。一个
uv.lock文件本可以在 10 秒内解决这个问题。如果不做环境隔离会怎样:两个框架的 PyTorch 版本要求可能不同、rsl_rl 版本可能冲突。在同一个 Python 环境中安装两者几乎一定会导致依赖冲突。务必使用独立的虚拟环境。
安装成功的检查清单
在进入 Ch03 之前,确认以下检查项全部通过:
| # | 检查项 | mjlab | Isaac Lab |
|---|---|---|---|
| 1 | GPU 可用 | torch.cuda.is_available() == True |
同左 |
| 2 | 框架可导入 | import mjlab 无错 |
import isaaclab 无错 |
| 3 | 任务列表 | list-envs 输出 \(\ge\)5 个任务 |
list_envs.py 输出 \(\ge\)10 个任务 |
| 4 | Zero agent | Go2 站在地上不动 | ANYmal 站在地上不动 |
| 5 | Random agent | Go2 有动作但不爆飞 | ANYmal 有动作但不爆飞 |
| 6 | 最小训练 | 16 envs \(\times\) 50 iter 完成 | 同左 |
| 7 | 完整训练 | 4096 envs \(\times\) 1500 iter 收敛 | 同左 |
| 8 | 可视化 | Viser 可访问 | headless + TensorBoard 可访问 |
| 9 | WandB | reward 曲线在 WandB 上可见 | — |
如果有任何一项未通过,用本章的故障排查手册定位并解决,不要带着问题进入下一章。
Day-1 完整工作流
把以上所有步骤串起来,你在拿到一台新机器时的完整操作流程(预计总耗时 30-60 分钟):
上午:mjlab 环境(~10 分钟)
# 1. 安装 uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# 2. 克隆并安装
git clone https://github.com/mujocolab/mjlab.git
cd mjlab && uv sync
# 3. 验证 L0-L4
uv run python -c "import torch; print(torch.cuda.is_available())"
uv run python -c "import mjlab; print(mjlab.__version__)"
uv run list-envs
uv run play Mjlab-Velocity-Flat-Unitree-Go2 --agent zero
# 4. 配置 WandB
wandb login
# 5. 最小训练
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--env.scene.num-envs 16 --num-iterations 50
下午:Isaac Lab 环境(~30 分钟)
# 1. 创建独立 conda 环境
conda create -n isaaclab python=3.10 -y
conda activate isaaclab
# 2. 安装 PyTorch(CUDA 版本匹配)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
# 3. 安装 Isaac Lab
pip install isaacsim-rl isaacsim-replicator isaacsim-extscache-physics
git clone https://github.com/isaac-sim/IsaacLab.git
cd IsaacLab && ./isaaclab.sh --install
# 4. 验证 L0-L4
python -c "import torch; print(torch.cuda.is_available())"
python -c "import isaaclab; print(isaaclab.__version__)"
python scripts/environments/list_envs.py
python scripts/reinforcement_learning/rsl_rl/train.py --task Isaac-Velocity-Flat-Anymal-C-v0 \
--num_envs 16 --max_iterations 50 --headless
傍晚:第一次完整训练(~30 分钟)
# mjlab 完整训练
cd ~/research/mjlab
uv run train Mjlab-Velocity-Flat-Unitree-Go2 \
--env.scene.num-envs 4096 --num-iterations 1500 \
--logger.wandb.entity your-org --logger.wandb.project day1
# 训练完成后可视化
uv run play Mjlab-Velocity-Flat-Unitree-Go2 \
--wandb-run-path your-org/day1/<run-id> --viewer
本质洞察:Day-1 的目标不是"深入理解框架",而是"证明管线端到端可用"。像软件工程中的 smoke test——只要能跑通一次,就证明基础设施是对的,后续的深入学习(Ch03-28)都建立在这个可用的环境之上。
版本记录的重要性
Day-1 完成后,记录你的完整环境版本信息——半年后在另一台机器上复现时会用到:
# 生成版本报告
echo "=== GPU ===" && nvidia-smi | head -5
echo "=== Python ===" && python --version
echo "=== PyTorch ===" && python -c "import torch; print(torch.__version__, torch.version.cuda)"
echo "=== mjlab ===" && uv run python -c "import mjlab; print(mjlab.__version__)"
echo "=== MuJoCo ===" && uv run python -c "import mujoco; print(mujoco.__version__)"
echo "=== uv.lock hash ===" && md5sum uv.lock
把这个输出保存在你的 WandB notes 或实验日志中。当你在新机器上遇到"同样的代码不同的结果"时,第一步就是对比版本信息。
第一周学习路线图
Day-1 的安装和训练只是起点。以下是从 Ch02 衔接到后续章节的推荐路线图(总耗时约一周):
| 天 | 目标 | 具体操作 | 产出 |
|---|---|---|---|
| Day 1 | 安装 + 第一次训练 | Ch02 全部内容 | 两个框架的 L0-L6 通过 + WandB 上的第一条曲线 |
| Day 2 | 理解默认配置 | 阅读 velocity_env_cfg.py(mjlab)的源码,标注每个 ObsTerm/RewTerm |
一份配置文件的注释版本 |
| Day 3 | 修改 reward | 将 track_lin_vel_xy_exp 的 weight 从 1.5 改为 3.0,重新训练 |
WandB 上两条曲线的对比截图 |
| Day 4 | 修改 obs | 移除 base_ang_vel(角速度观测),观察策略如何退化 |
理解 obs 对策略行为的影响 |
| Day 5 | 可视化对比 | 对比 Day 1(默认)、Day 3(高 tracking 权重)、Day 4(缺少角速度)的行为 | 3 个 checkpoint 的可视化视频 |
| Day 6 | 阅读一个顶会项目 | 选择 Ch01 §1.6 中一个与你研究相关的项目,clone 并阅读 README + config | 一份项目笔记(obs/reward/DR 设计总结) |
| Day 7 | 规划你的第一个实验 | 结合 Day 2-6 的经验,确定你的研究任务的 baseline 配置 | 一份实验计划(任务/框架/baseline/修改方向) |
这个路线图的核心理念是"先做再学"——Day 2-4 的操作实际上是在预览 Ch04-06 的内容。当你正式读到这些章节时,你已经有了动手经验,理解速度会快得多。
如果时间只有 3 天:压缩为 Day 1 + Day 3 + Day 5——安装、修改 reward、可视化对比。这是建立"训练直觉"的最小操作集。
⚠️ 常见陷阱
- 在同一个 Python 环境中安装两个框架。 依赖冲突几乎不可避免。使用独立虚拟环境。
- 不记录安装过程。 半年后换了机器,你会忘记当时的安装步骤。把安装命令和遇到的问题记录在 README 或 WandB notes 中。
- 跳过 zero/random agent 验证。 直接跑训练出错时,你不知道是环境问题还是训练配置问题。zero/random agent 验证可以在 30 秒内排除环境问题。
练习
- 制作你自己的安装脚本(
setup_mjlab.sh和setup_isaaclab.sh),包含从创建环境到完成 L6 验证的所有命令。这个脚本在你换机器时会非常有用。 - 记录你在安装过程中遇到的所有错误和解决方案。把这些记录发布到你的 lab wiki 或个人博客——帮助后来的同学避免相同的坑。
- (跨章综合题)回顾 Ch01 的 sim-to-real pipeline(Sim 训练 → DR → Teacher-Student → Sim2Sim → ONNX → 真机),在你当前安装的双框架环境中,每个步骤使用哪个框架最合适?画出你的 pipeline 框架选择图。
本章小结
知识点总表
| 编号 | 知识点 | 核心要点 | 对应节 | 难度 |
|---|---|---|---|---|
| 1 | 分层验证方法论 | L0-L6 逐层检查,故障隔离 | 2.1 | ⭐ |
| 2 | 分层验证是工程哲学 | 系统越复杂,分层验证越有价值 | 2.1 | ⭐ |
| 3 | 真实失败案例 | CUDA 版本匹配/conda 陷阱/版本链不对应/WandB 超时 | 2.1 | ⭐⭐ |
| 4 | mjlab 安装(uv) | uv sync,JIT kernel 编译,<2 分钟 |
2.2 | ⭐⭐ |
| 5 | uv run 的价值 | 环境隔离、版本锁定、不需要 activate | 2.2 | ⭐⭐ |
| 6 | MuJoCo Warp JIT | 首次运行编译 GPU kernel,安装时不报错 | 2.2 | ⭐⭐ |
| 7 | GPU 显存估算 | max_envs \(\approx\) (VRAM - 2GB) \(\times\) 1000 / per_env_MB | 2.2 | ⭐⭐ |
| 8 | WandB 配置 | 从第一次训练就用,离线模式可选 | 2.2 | ⭐ |
| 9 | Isaac Lab 安装 | conda + pip,kit-less vs 完整,版本三重匹配 | 2.3 | ⭐⭐ |
| 10 | Isaac Lab 版本链 | CUDA Driver → Toolkit → PyTorch → Isaac Sim → Isaac Lab | 2.3 | ⭐⭐ |
| 11 | Isaac Lab 3.0 注意事项 | kit-less/quaternion xyzw/warp-native/模块重命名 | 2.3 | ⭐⭐ |
| 12 | Isaac Lab 内置任务 | Classic/Locomotion/Manipulation/Dexterous 四大类 | 2.3 | ⭐ |
| 13 | NaN Guard | --enable-nan-guard True 定位 NaN 源头 |
2.3 | ⭐⭐ |
| 14 | CLI 差异 | mjlab: uv run + tyro 覆盖;Isaac Lab: python scripts/ + argparse |
2.4 | ⭐⭐ |
| 15 | 默认模式差异 | mjlab 默认 headless;Isaac Lab 默认 GUI | 2.4 | ⭐ |
| 16 | tyro 配置覆盖 | mjlab 命令行可覆盖任意深度参数 | 2.4 | ⭐⭐ |
| 17 | Viser vs Isaac Sim Viewer vs Rerun | Web-based / Omniverse GUI / 数据流回放 | 2.5 | ⭐⭐ |
| 18 | 远程可视化方案 | SSH+Viser(推荐)/ headless+video / VNC / X11(不推荐) | 2.5 | ⭐⭐ |
| 19 | 可视化调试工作流 | zero → random → 定期检查 → 最终验证 → 失败案例分析 | 2.5 | ⭐⭐ |
| 20 | 训练四阶段 | 初始→探索→学习→收敛,每阶段的 reward 和行为特征 | 2.6 | ⭐⭐ |
| 21 | 训练指标解读 | reward/KL/entropy/value_loss 联合解读 | 2.6 | ⭐⭐ |
| 22 | WandB 面板操作 | Run Compare/Group by/Smooth/Step axis | 2.6 | ⭐⭐ |
| 23 | 训练后 10 问 | 系统性验证训练结果是否合理 | 2.6 | ⭐⭐ |
| 24 | GPU 训练时间对照 | RTX 3090/4090/A100/H100 的预期 FPS 和训练时间 | 2.6 | ⭐ |
| 25 | sim2sim 预验证 | ONNX 导出 smoke test,Ch23 完整流程的预告 | 2.6 | ⭐⭐ |
| 26 | 行为可视化检查 | reward 高不代表行为好,必须可视化验证 | 2.6 | ⭐⭐ |
| 27 | 双框架环境隔离 | 独立虚拟环境,不在同一 Python 环境中安装两者 | 2.7 | ⭐ |
| 28 | 设计哲学差异 | 最小依赖 vs 完整生态;约定 vs 配置 | 2.7 | ⭐⭐ |
| 29 | Day-1 工作流 | 30-60 分钟完成双框架安装+验证+第一次训练 | 2.7 | ⭐ |
| 30 | 第一周路线图 | 从安装到修改 reward 到阅读项目到规划实验 | 2.7 | ⭐ |
概念关系图
安装验证(L0-L6)
└── L0 GPU 可用
└── L1 框架导入
└── L2 任务注册
└── L3 场景构建
└── L4 Zero Agent(物理 + 可视化)
└── L5 Random Agent(action 管线)
└── L6 最小训练(RL 循环)
└── 完整训练(4096 envs)
└── 可视化验证行为质量
每一层依赖上一层——如果 L2 失败,不要去排查 L6 的日志。
累积项目:本章新增模块
| 项目 | 本章贡献 | 验证标准 |
|---|---|---|
| A 四足速度跟踪 | ✅ 在 mjlab 中完成 Go2 的第一次完整训练 | WandB 上可见收敛的 reward 曲线 |
| B 人形 locomotion | 准备就绪(Isaac Lab 安装完成,Ch14 开始使用) | Isaac Lab L0-L6 全部通过 |
本章为后续所有累积项目建立了基础设施——可工作的双框架环境和 WandB 实验管理。后续章节的每个项目模块都依赖这个基础设施正常工作。
项目 A 的下一步(Ch04):精读 Mjlab-Velocity-Flat-Unitree-Go2 的 velocity_env_cfg.py,理解每个 ObsTerm、RewTerm 和 EventTerm 的含义。
项目 B 的下一步(Ch14):在 Isaac Lab 中训练 Isaac-Velocity-Flat-G1-v0,并与 mjlab 的 G1 训练结果做 sim2sim 对比。
延伸阅读
安装与工具
| 资源 | 难度 | 说明 |
|---|---|---|
| mjlab 官方文档:Installation | ⭐ | 最权威的安装参考,包含所有安装方式的详细步骤 |
| Isaac Lab 官方文档:Installation Guide | ⭐ | 安装步骤、版本对应表、kit-less vs 完整安装的详细说明 |
| Isaac Lab 3.0 Migration Guide | ⭐⭐ | 从 2.x 到 3.0 的迁移指南,含 API 重命名表和自动化工具 |
uv 官方文档:docs.astral.sh/uv |
⭐ | 理解 uv sync / uv run / uv.lock 的工作机制 |
Viser 文档:viser.studio |
⭐ | Viser 高级功能——自定义 GUI 面板、数据回放、远程协作 |
Rerun 文档:rerun.io/docs |
⭐ | 时间序列数据流可视化,MuJoCo 集成教程 |
| WandB 文档:Quickstart | ⭐ | WandB 登录、项目创建、sweep 配置 |
物理仿真基础(为 Ch03 做准备)
| 资源 | 难度 | 说明 |
|---|---|---|
| MuJoCo 官方文档:Overview | ⭐⭐ | MuJoCo 的物理模型和 MJCF 格式概述 |
| ROBOLAWEB:solref/solimp Cheat Sheet | ⭐ | MuJoCo 接触参数的实用推荐值(Ch01 已预览) |
| PhysX 官方文档 | ⭐⭐ | PhysX 的 TGS 求解器和接触参数含义 |
| NVIDIA Warp 文档 | ⭐⭐⭐ | MuJoCo Warp 的 GPU kernel 实现细节 |
相关论文
| 资源 | 难度 | 说明 |
|---|---|---|
| Rudin et al., Learning to Walk in Minutes, CoRL 2021 | ⭐⭐ | legged_gym,理解"第一次训练"的标准流程 |
| Zakka et al., mjlab: A Lightweight Framework, arXiv 2601.22074 | ⭐⭐ | mjlab 的 benchmark 数据——安装时间、吞吐量 |
| Mittal et al., Isaac Lab: A GPU-Accelerated Framework, arXiv 2511.04831 | ⭐⭐ | Isaac Lab 的安装架构和多后端设计 |
| Schwarke et al., RSL-RL: A Learning Library, arXiv 2509.10771 | ⭐⭐ | rsl_rl 4.0 的设计和 ONNX 导出 |
| He et al., ASAP: Aligning Simulation and Real-World Physics, RSS 2025, arXiv 2502.01143 | ⭐⭐⭐ | 跨仿真器 delta action model,Ch23 的核心参考 |
| NVIDIA, Closing the Sim-to-Real Gap: Training Spot, Technical Blog 2025 | ⭐⭐ | RTX 4090 上 85-95k FPS 训练 Spot,含 ONNX 部署到 Jetson |
社区资源
| 资源 | 说明 |
|---|---|
| Isaac Lab Discord | 官方社区,安装问题可以在这里提问 |
| Isaac Lab GitHub Discussions | 技术问题和 feature request |
| mjlab Show and Tell | mjlab 仓库的社区展示区 |
本章与后续章节的关系
本章完成了"从零到可运行"的全流程。后续章节在本章基础上逐层深入:
| 后续章节 | 与本章的关系 | 前提条件 |
|---|---|---|
| Ch03 物理引擎 | 本章你跑通了仿真但不知道引擎内部如何工作 → Ch03 深入引擎选型和调参 | 本章 L4(zero agent 可运行) |
| Ch04 Manager 架构 | 本章你看到了 config 文件但不理解其设计 → Ch04 精读架构 | 本章 L6(训练可跑通) |
| Ch05 Obs/Action 设计 | 本章你用了默认 obs → Ch05 讲如何设计和修改 obs | 本章 L5(random agent 验证了 action) |
| Ch06 Reward 设计 | 本章你观察了 reward 曲线 → Ch06 讲如何设计和调试 reward | 本章 §2.6(完整训练,观察了 reward 曲线) |
| Ch07 训练管线 | 本章你用了默认超参 → Ch07 讲每个参数的意义和调优 | 本章 §2.6(完整训练,观察了 KL/entropy 指标) |
| Ch08 DR | 本章你用了默认 DR → Ch08 讲 EventManager 的工程实现 | 本章 §2.6(完成至少一次训练) |
| Ch23 Sim2Real | 本章的 sim2sim 预验证是 Ch23 完整部署管线的第一步 | 本章 §2.6(ONNX 导出成功) |
关键过渡:本章和 Ch03 之间有一个天然的断点——Ch02 关注"跑通",Ch03 关注"跑好"。如果你只需要快速开始训练实验,可以从 Ch02 直接跳到 Ch04(Manager 架构),Ch03 的物理引擎调参可以在遇到接触问题时再回来读。
🔧 故障排查手册
本手册按出现阶段组织——你遇到问题时,先确认问题属于哪个阶段,然后在对应表中查找。
阶段一:安装问题
| 故障 | 症状 | 原因 | 排查步骤 |
|---|---|---|---|
| CUDA 不可用 | torch.cuda.is_available() 返回 False |
PyTorch CUDA 版本与 driver 不匹配 | 1. nvidia-smi 查 driver CUDA → 2. python -c "import torch; print(torch.version.cuda)" → 3. 安装匹配版本 |
| MuJoCo Warp 编译失败 | 首次运行报 warp 错误 |
CUDA toolkit 缺失或版本不对 | 1. nvcc --version → 2. 安装 CUDA toolkit → 3. 确保 PATH 包含 nvcc |
| Isaac Lab import 失败 | ImportError: No module named 'isaacsim' |
Isaac Sim 未安装或版本不匹配 | 1. 确认 conda 环境激活 → 2. pip list | grep isaacsim → 3. 对照 README 版本表 |
| WandB 卡住 | 训练启动停在 WandB | 未登录或网络不通 | wandb login 或 WANDB_MODE=offline |
| uv sync 失败 | 依赖解析冲突 | pyproject.toml 约束过严或网络问题 | 1. 检查 Python 版本 \(\ge\) 3.10 → 2. uv sync --no-cache |
| conda + pip 冲突 | 各种 ImportError | conda 安装了 CPU 版包覆盖 pip 版 | 不要 conda install pytorch/numpy,只用 pip |
阶段二:运行问题
| 故障 | 症状 | 原因 | 排查步骤 |
|---|---|---|---|
| Viser 无法访问 | 浏览器连不上 7860 | 端口未转发 | 1. 确认 ssh -L 7860:localhost:7860 → 2. 检查防火墙 |
| Isaac Sim 卡死 | GUI 窗口无响应 | 无显示服务器未加 headless | 加 --headless |
| 任务名找不到 | KeyError 或 ValueError |
名称拼写错误或 registry 未加载 | uv run list-envs 或 python scripts/environments/list_envs.py 查看正确名称 |
| OOM | CUDA out of memory |
环境数太多或 GPU 显存不足 | 减少 num-envs(4096→1024→256) |
| 模型穿透地面 | zero agent 时足端在地面以下 | 初始高度或 collision mesh 配置错误 | 1. 检查 default_init_state.pos 的 z 值 → 2. 检查 collision mesh |
| 机器人悬浮 | zero agent 时机器人不落地 | 重力未启用或 z 坐标太高 | 检查 sim config 的 gravity 设置 |
阶段三:训练问题
| 故障 | 症状 | 原因 | 排查步骤 |
|---|---|---|---|
| Reward 为零 | 1000 iter 后 reward 仍为 0 | obs/reward 配置错误 | 1. 打印 obs 张量检查是否全零 → 2. 打印 reward 各分项 → 3. 检查 command 采样范围 |
| Reward 为 NaN | 训练几十 iter 后 NaN | 物理不稳定 | 1. --enable-nan-guard True → 2. 减少 action scale → 3. 减少 env 数看是否可复现 |
| Reward 快速下降 | reward 先升后降 | KL 过大导致策略崩溃 | 降低 learning rate 或增加 mini_batch 数 |
| Episode length 不增 | 机器人总是很快 terminate | termination 条件太严 | 1. 检查 termination 配置 → 2. 临时放宽条件测试 |
| 训练极慢 | steps/s 远低于预期 | 传感器开销或渲染干扰 | 1. 确认 --headless → 2. 关闭视频录制 → 3. 减少传感器 → 4. 检查 WandB 是否阻塞 |
| Entropy 骤降 | entropy 在前 100 iter 就降到接近零 | 初始 noise std 太小或 obs scale 异常 | 检查 init_noise_std(应为 1.0)和 obs 的数值范围 |
| Value loss 不降 | value_loss 始终在高位振荡 | critic 网络太小或 obs 信息不足 | 1. 增大 critic hidden_dims → 2. 检查 critic obs 是否包含必要信息 |
| 策略抖动 | 可视化发现关节高频振荡 | action rate penalty 不够或 action scale 太大 | 1. 增加 action_rate penalty 权重 → 2. 降低 action scale → 3. 检查 actuator kd |
阶段四:跨框架问题
| 故障 | 症状 | 原因 | 排查步骤 |
|---|---|---|---|
| 同一机器人两框架行为不同 | 默认姿态差异 | MJCF vs USD 的默认关节角不同 | 对比两个模型文件的 default_joint_pos |
| 迁移 config 报错 | AttributeError | API 命名不同 | 查阅 writing_guide.md §5.3 的 API 对应表 |
| 同一任务 reward 数值差异大 | 数值不可比 | reward 权重/函数配置不同 | reward 数值不跨框架比较,比较行为质量 |
| mjlab 训练好的策略在 CPU MuJoCo 中行为不同 | sim2sim 差异 | GPU/CPU 数值精度差异 | 这是正常现象(MuJoCo Warp 与 CPU MuJoCo 有微小数值差异)。如果差异很大→策略可能 overfit 了仿真器特定行为 |
| Isaac Lab 3.0 代码在 2.3 环境中报错 | import / attribute error | 3.0 的破坏性变更 | 确认你在正确的 branch 上:3.0 用 develop,2.3 用 main |
| rsl_rl 4.0 config 和旧版不兼容 | actor_critic 属性找不到 |
rsl_rl 4.0 拆分 config | 使用新格式:actor = RslRlMLPModelCfg(...) + critic = RslRlMLPModelCfg(...) |
紧急修复速查
当你遇到紧急问题(如论文 deadline 前训练崩了),按以下优先级排查:
1. 是不是 CUDA OOM? → 减少 num_envs(4096→1024→256)
2. 是不是 NaN? → --enable-nan-guard True 定位首次 NaN 的位置
3. 是不是版本变了? → git log 查最近的代码变更;pip list 对比包版本
4. 是不是硬件问题? → nvidia-smi 查 GPU 状态、温度和利用率
5. 以上都不是? → 用已知能跑的 config 做最小复现,逐步增加修改
一个真实的紧急修复故事:某同学在 deadline 前一天发现训练 NaN。他先用 --enable-nan-guard True 定位到 NaN 首次出现在 obs 的 base_ang_vel 项。原因是某个环境的角速度在碰撞后变成 inf,然后传播到所有 obs。解决方案:在 obs 中加 clip(clip=(-100, 100))。从发现到修复总共 20 分钟——如果没有 NaN guard,他可能需要花一整天盲目排查。
最后的建议:现在就把你的两个框架环境做一个备份快照(
pip freeze/uv.lock复制到你的项目仓库中)。这 10 秒钟的投入,会在你未来某一天换机器或重装系统时节省数小时的安装调试时间。Ch02 完结。 本章从安装验证的方法论出发,分别在 mjlab 和 Isaac Lab 中完成了从零安装到完整训练的全流程。你现在有了一个可工作的双框架环境,以及对训练过程的初步体感。
你的收获: - 一个可工作的 mjlab 环境 + 一个可工作的 Isaac Lab 环境 - 在 WandB 上的第一条训练曲线 - 对训练四阶段(初始→探索→学习→收敛)的直觉 - 对两个框架 CLI/可视化/安装复杂度差异的亲身体验
下一步行动: 1. 如果你还没完成检查清单 → 回到 §2.7 逐项确认 2. 如果检查清单全部通过 → 按"第一周学习路线图"继续:修改一个 reward 权重、观察行为变化 3. 如果你急于进入理论 → 直接进入 Ch03(物理引擎)或 Ch04(Manager-Based 架构)
下一章将深入物理引擎层——你已经知道 mjlab 用 MuJoCo Warp、Isaac Lab 用 PhysX,但它们在接触行为上到底有什么不同?什么时候该选哪个?出了问题怎么排查?这些是 Ch03 要回答的工程问题。
视频教程
| 资源 | 说明 |
|---|---|
| NVIDIA Isaac Lab 官方 YouTube 教程 | 从安装到训练的完整视频演示 |
| mjlab 官方 Colab Notebooks | 零配置浏览器内运行,适合快速体验 |
| ETH RSL 的 legged_gym 教程视频 | 虽然基于旧框架,但 reward/obs 设计思想通用 |
视频教程适合"看一遍操作过程建立直觉",但不替代本教材的深度讲解。建议先跟着 Ch02 动手操作,遇到不理解的步骤再看对应的视频。
阅读建议:本章和 Ch03 之间有一个天然的断点——Ch02 关注"跑通",Ch03 关注"跑好"。如果你只需要快速开始训练实验,可以从 Ch02 直接跳到 Ch04(Manager 架构精读),Ch03 的物理引擎调参可以在遇到接触问题时再回来读。
Ch02 环境状态检查:如果你完成了本章的所有步骤,你现在应该有:(1) 一个可工作的 mjlab 环境 + Go2 的训练 checkpoint,(2) 一个可工作的 Isaac Lab 环境 + ANYmal 的训练 checkpoint,(3) WandB 上至少两条训练曲线,(4) 对双框架 CLI/可视化/安装复杂度差异的亲身体验。如果缺少任何一项,回到对应小节补完。
向 Ch03 的过渡:你现在能跑通训练了,但还不知道物理引擎内部在做什么。当你遇到"机器人穿透地面"、"接触行为不符合预期"、"同一机器人在两个框架中行为不同"这些问题时——Ch03 会给你答案。
向 Ch04 的过渡:你看到了 config 文件中的 ObsTerm、RewTerm、EventTerm,但不理解它们的设计原理——Ch04 会带你做源码级精读,理解 Manager-Based 架构的每一个组件。
记住:机器人 RL 是一个"做中学"的领域。本章建立的动手经验——从安装报错到训练曲线上涨——是后续所有章节的认知基础。没有这个基础,Ch03 的物理引擎讨论和 Ch04 的架构精读都只是纸上谈兵。
致谢:本章的安装流程经过多轮真实用户测试,感谢 mjlab 和 Isaac Lab 社区在 GitHub Issues 和 Discord 中提供的宝贵反馈。如果你在安装过程中发现了本章未覆盖的问题,欢迎反馈以帮助后续读者。
本教材版本锚定:本章所有安装命令和验证步骤以 mjlab 1.2.0 + Isaac Lab 2.3.0 + rsl_rl \(\ge\) 4.0.0 为准。Isaac Lab 3.0 Beta 的安装命令以注释框标注。版本更新后如有 API 变化,请查阅各框架的 CHANGELOG。
如果你在安装过程中遇到了本章未覆盖的问题并找到了解决方案,请考虑在对应框架的 GitHub Issues 中分享——这是开源社区进步的基础。