我们提供了一个命令行工具来下载场景数据集(通常是从原始数据集改编而来)。
ManiSkill 可以构建任何场景,只要提供了相关的资源。ManiSkill 默认提供了代码和下载链接,以便使用 RoboCasa、ReplicaCAD 和 AI2THOR 等场景数据集(如下所示)。这些场景因其一般较高的建模质量和互动性而被选中。
ManiSkill 还支持异构 GPU 仿真,其中每个并行环境可以具有不同的物体和纹理。以下是由仿真器生成的鸟瞰图示例,展示了 RoboCasa 厨房场景
要开始使用这些场景,可以使用以下命令下载它们。请注意,如果在工作中使用这些场景,请同时引用 ManiSkill3 和场景数据集的作者。
# 列出所有可下载的场景数据集
python -m mani_skill.utils.download_asset --list "scene"
python -m mani_skill.utils.download_asset ReplicaCAD # 小场景,下载速度快
python -m mani_skill.utils.download_asset RoboCasa # 大量程序生成的场景,下载速度快
python -m mani_skill.utils.download_asset AI2THOR # 大量场景,下载速度慢要探索场景数据集,可以提供环境 ID 和种子(如果有多个可用场景,可更改采样的场景),并运行随机动作脚本。下面展示了已经配置好的各种环境,可以用来与 RoboCasa、ReplicaCAD 和 ArchitecTHOR(AI2THOR 的一个变体)进行交互。
python -m mani_skill.examples.demo_random_action \
-e "ReplicaCAD_SceneManipulation-v1" \
--render-mode="rgb_array" --record-dir="videos" # 无头模式运行并保存视频
python -m mani_skill.examples.demo_random_action \
-e "ArchitecTHOR_SceneManipulation-v1" --render-mode="human" \
-s 3 # 打开 GUI 并使用种子 3 采样一个场景
# 加载 4 个环境并使用种子 0, 1, 2, 3 采样场景
# 使用 fetch 机器人
python -m mani_skill.examples.demo_random_action \
-e "RoboCasaKitchen-v1" \
-n 4 -s 0 1 2 3 \
--render-mode="human" -r "fetch"还可以传递 -r "none" 来在没有任何智能体的情况下运行环境。
像 ReplicaCAD 和 AI2THOR 这样的大型场景数据集,包含数百个物体,可以用于训练更通用的机器人/智能体,并且还可以作为合成数据生成的来源。我们仍在提供更多示例代码和文档的过程中,以便更好地利用这些场景数据集,但目前我们提供了代码来探索和与这些场景数据集进行交互。
我们目前正在构建类似于 ReplicaCAD Rearrange 挑战的任务代码,并将在完成后开源。除此之外,目前没有任何训练任务具有定义的成功/失败条件和/或奖励,并且使用任何大型场景数据集。
我们提供了一个命令行工具,可以通过任务 ID 从我们的 Hugging Face 🤗 数据集直接下载演示。该工具将演示文件下载到一个文件夹,并且还会下载一些展示演示外观的视频。有关所有支持的任务及其演示的列表,请参见 任务。
# 下载特定任务的演示数据集
python -m mani_skill.utils.download_demo ${ENV_ID}
python -m mani_skill.utils.download_demo # 没有参数时,这会打印所有可用的数据集
# 下载完整的数据集(可能非常慢)
python -m mani_skill.utils.download_demo all演示数据集通常以简化格式存储(例如,不包含观察数据),而是存储环境状态以进行压缩。我们提供了一个灵活的工具,可以重播演示数据集并修改它们,例如添加视觉观察数据、录制视频等,详见 轨迹重播文档。如果希望在本地生成原始的压缩数据集,我们将用于数据集生成的所有脚本保存在 data_generation 文件夹中。对于希望基准化模仿学习的用户,我们强烈建议遵循 模仿学习设置页面 上的说明,了解如何重播压缩数据集以进行训练数据集的基准测试。
每个任务的所有演示都以 HDF5 格式保存,可以通过 h5py 打开。每个 HDF5 数据集命名为 trajectory.{obs_mode}.{control_mode}.{sim_backend}.h5,并且有一个与其同名的 JSON 元数据文件。除非另有说明,trajectory.h5 是 trajectory.none.pd_joint_pos.physx_cpu.h5 的简写,其中包含由 pd_joint_pos 控制器生成的原始演示,使用 none 观察模式(空观察数据)并在基于 CPU 的仿真中生成。然而,可能存在由其他控制器生成的演示。因此,请检查关联的 JSON 文件以确保使用了哪个控制器。
每个 JSON 文件包含:
env_info(字典):任务(也称为环境)信息,可用于初始化任务env_id(字符串):任务 IDmax_episode_steps(整数)env_kwargs(字典):初始化任务的关键字参数。这是重现环境所必需的。
episodes(列表[字典]):回合信息source_type(可选[字符串]):一个简单的分类字符串,描述生成轨迹数据的过程。source_desc(可选[字符串]):对数据生成过程的更长解释。
回合信息(episodes 的元素)包括:
episode_id(整数):回合的唯一 IDreset_kwargs(字典):重置任务的关键字参数。重现轨迹时必须使用这些参数。control_mode(字符串):用于该回合的控制模式。elapsed_steps(整数):轨迹长度info(字典):回合结束时的信息。
仅凭元数据,通常可以重现任务,就像它在收集轨迹时创建的方式一样:
env = gym.make(env_info["env_id"], **env_info["env_kwargs"])
episode = env_info["episodes"][0] # 选择第一个
env.reset(**episode["reset_kwargs"])有时轨迹数据是在 GPU 仿真中收集的,这意味着随机化不仅依赖于种子,还依赖于并行环境的数量。为了确保相同的起始状态,可以使用存储在轨迹中的第一个环境状态数据,并相应地设置环境状态。
每个 HDF5 演示数据集由多个轨迹组成。每个轨迹的键是 traj_{episode_id},例如,traj_0。
每个轨迹是一个 h5py.Group,其中包含:
- actions: [T, A],
np.float32。T是转移次数。 - terminated: [T],
np.bool_。表示任务是否在每个时间步结束。 - truncated: [T],
np.bool_。表示任务是否在每个时间步被截断。 - env_states: [T+1, D],
np.float32。环境状态。可以用来通过env.set_state_dict将环境设置为特定状态。然而,这可能不足以重现轨迹。 - success(可选):[T],
np.bool_。表示任务在每个时间步是否成功。如果任务定义了成功,则包括该字段。 - fail(可选):[T],
np.bool_。表示任务在每个时间步是否失败。如果任务定义了失败,则包括该字段。 - obs(可选):[T+1, D] 观察数据。
注意,env_states 是以字典形式存储的(观察数据也可能如此,具体取决于观察模式),它被格式化为一个列表字典。例如,典型的环境状态如下所示:
env_state = env.get_state_dict()
"""
env_state = {
"actors": {
"actor_id": [...numpy_actor_state...],
...
},
"articulations": {
"articulation_id": [...numpy_articulation_state...],
...
}
}
"""在轨迹文件中,env_states 将具有相同的结构,但字典中的每个值/叶子节点将是一个表示该实体在仿真中随时间变化的状态序列。
在实践中,使用 env_states 数据的切片(或观察数据)可能会更有用,可以通过以下方式完成:
import mani_skill.trajectory.utils as trajectory_utils
env_states = trajectory_utils.dict_to_list_of_dicts(env_states)
# 现在 env_states[i] 就是 env.get_state_dict() 在第 i 个时间步返回的数据
i = 10
env_state_i = trajectory_utils.index_dict(env_states, i)
# 现在 env_state_i 就是 env.get_state_dict() 在第 i 个时间步返回的数据这些工具也用于我们提供的 PyTorch 数据集实现,详细信息见下一部分。
我们提供了一个示例方式来构建 PyTorch 数据集,并轻松加载轨迹 .h5 数据,具体请见 https://github.com/haosulab/ManiSkill/tree/main/mani_skill/trajectory/datasets.py。虽然它不是超级优化的,但展示了如何灵活地处理我们的数据格式。代码副本已粘贴在下面的下拉框中。
:::{dropdown} dataset.py :color: primary :icon: code
from typing import Union
import h5py
import numpy as np
from torch.utils.data import Dataset
from tqdm import tqdm
from mani_skill.utils.io_utils import load_json
from mani_skill.utils import sapien_utils
from mani_skill.utils import common
# loads h5 data into memory for faster access
def load_h5_data(data):
out = dict()
for k in data.keys():
if isinstance(data[k], h5py.Dataset):
out[k] = data[k][:]
else:
out[k] = load_h5_data(data[k])
return out
class ManiSkillTrajectoryDataset(Dataset):
"""
一个通用的 PyTorch 数据集,可以立即使用它加载任何由 ManiSkill 生成的轨迹 .h5 数据。
这个类只是一个简单的起始代码,用于轻松加载轨迹数据,但不做任何数据转换或高级操作
我们建议直接复制此代码并根据更高级的用例进行修改
参数:
dataset_file (str): 要加载的数据 .h5 文件的路径
load_count (int): 要加载到内存中的轨迹数量。如果为 -1,将加载所有数据
success_only (bool): 是否跳过最终不成功的轨迹。默认为 False
device: 数据保存的位置。如果为 None,将以 numpy 格式存储(默认),否则会将数据移动到指定的设备上
"""
def __init__(self, dataset_file: str, load_count=-1, success_only: bool = False, device = None) -> None:
self.dataset_file = dataset_file
self.device = device
self.data = h5py.File(dataset_file, "r")
json_path = dataset_file.replace(".h5", ".json")
self.json_data = load_json(json_path)
self.episodes = self.json_data["episodes"]
self.env_info = self.json_data["env_info"]
self.env_id = self.env_info["env_id"]
self.env_kwargs = self.env_info["env_kwargs"]
self.obs = None
self.actions = []
self.terminated = []
self.truncated = []
self.success, self.fail, self.rewards = None, None, None
if load_count == -1:
load_count = len(self.episodes)
for eps_id in tqdm(range(load_count)):
eps = self.episodes[eps_id]
if success_only:
assert "success" in eps, "episodes in this dataset do not have the success attribute, cannot load dataset with success_only=True"
if not eps["success"]:
continue
trajectory = self.data[f"traj_{eps['episode_id']}"]
trajectory = load_h5_data(trajectory)
eps_len = len(trajectory["actions"])
# exclude the final observation as most learning workflows do not use it
obs = common.index_dict_array(trajectory["obs"], slice(eps_len))
if eps_id == 0:
self.obs = obs
else:
self.obs = common.append_dict_array(self.obs, obs)
self.actions.append(trajectory["actions"])
self.terminated.append(trajectory["terminated"])
self.truncated.append(trajectory["truncated"])
# handle data that might optionally be in the trajectory
if "rewards" in trajectory:
if self.rewards is None:
self.rewards = [trajectory["rewards"]]
else:
self.rewards.append(trajectory["rewards"])
if "success" in trajectory:
if self.success is None:
self.success = [trajectory["success"]]
else:
self.success.append(trajectory["success"])
if "fail" in trajectory:
if self.fail is None:
self.fail = [trajectory["fail"]]
else:
self.fail.append(trajectory["fail"])
self.actions = np.vstack(self.actions)
self.terminated = np.concatenate(self.terminated)
self.truncated = np.concatenate(self.truncated)
if self.rewards is not None:
self.rewards = np.concatenate(self.rewards)
if self.success is not None:
self.success = np.concatenate(self.success)
if self.fail is not None:
self.fail = np.concatenate(self.fail)
def remove_np_uint16(x: Union[np.ndarray, dict]):
if isinstance(x, dict):
for k in x.keys():
x[k] = remove_np_uint16(x[k])
return x
else:
if x.dtype == np.uint16:
return x.astype(np.int32)
return x
# uint16 dtype is used to conserve disk space and memory
# you can optimize this dataset code to keep it as uint16 and process that
# dtype of data yourself. for simplicity we simply cast to a int32 so
# it can automatically be converted to torch tensors without complaint
self.obs = remove_np_uint16(self.obs)
if device is not None:
self.actions = sapien_utils.to_tensor(self.actions, device=device)
self.obs = sapien_utils.to_tensor(self.obs, device=device)
self.terminated = sapien_utils.to_tensor(self.terminated, device=device)
self.truncated = sapien_utils.to_tensor(self.truncated, device=device)
if self.rewards is not None:
self.rewards = sapien_utils.to_tensor(self.rewards, device=device)
if self.success is not None:
self.success = sapien_utils.to_tensor(self.terminated, device=device)
if self.fail is not None:
self.fail = sapien_utils.to_tensor(self.truncated, device=device)
def __len__(self):
return len(self.actions)
def __getitem__(self, idx):
action = sapien_utils.to_tensor(self.actions[idx], device=self.device)
obs = common.index_dict_array(self.obs, idx, inplace=False)
res = dict(
obs=obs,
action=action,
terminated=self.terminated[idx],
truncated=self.truncated[idx],
)
if self.rewards is not None:
res.update(reward=self.rewards[idx])
if self.success is not None:
res.update(success=self.success[idx])
if self.fail is not None:
res.update(fail=self.fail[idx])
return res:::
ManiSkill 提供了工具,不仅可以收集/加载轨迹,还可以重播轨迹并转换观察/动作。
要重播演示(不改变观察模式和控制模式):
# 通过 sapien viewer 重播并查看轨迹
python -m mani_skill.trajectory.replay_trajectory \
--traj-path ~/.maniskill/demos/PushCube-v1/motionplanning/trajectory.h5 \
--vis
# 保存轨迹的视频(保存到与轨迹相同的目录)
python -m mani_skill.trajectory.replay_trajectory \
--traj-path ~/.maniskill/demos/PushCube-v1/motionplanning/trajectory.h5 \
--save-video
# 查看所有可用选项
python -m mani_skill.trajectory.replay_trajectory -h结果分别如下
:::{note}
该脚本要求 trajectory.h5 和 trajectory.json 文件都位于相同目录下。
:::
默认情况下,原始演示文件包含重现轨迹所需的所有必要信息(例如初始状态、动作、种子)。由于没有后处理,观察数据通常不包含在内,因为它们可能导致文件大小过大。此外,这些文件中的动作不涵盖所有控制模式。因此,需要将原始文件转换为所需的观察和控制模式。我们提供了一个实用脚本,使用方式如下:
# 重播演示,控制模式为 pd_joint_delta_pos
python -m mani_skill.trajectory.replay_trajectory \
--traj-path ~/.maniskill/demos/PickCube-v1/motionplanning/trajectory.h5 \
--save-traj --target-control-mode pd_joint_delta_pos \
--obs-mode none #--num-procs 10:::{dropdown} 点击查看轨迹重播工具选项
╭─ options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ -h, --help 显示此帮助信息并退出 │
│ --traj-path STR 要重播的轨迹 .h5 文件路径(必需) │
│ --sim-backend {None}|STR, -b {None}|STR │
│ 使用的仿真后端,可以是 'physx_cpu' 或 'physx_gpu'。如果未指定,默认使用收集轨迹数据时的后端。(默认:None) │
│ --obs-mode {None}|STR, -o {None}|STR │
│ 要记录到轨迹中的目标观察模式。请参见 │
│ https://maniskill.readthedocs.io/en/latest/user_guide/concepts/observation.html 获取完整的支持的观察模式列表。(默认:None) │
│ --target-control-mode {None}|STR, -c {None}|STR │
│ 要转换为的目标控制模式。 │
│ 注意,并非所有控制模式可以成功转换,且并非所有机器人都有容易转换的控制模式。 │
│ 目前 Panda 机器人在控制模式转换方面支持得最好。此外,在 GPU 并行化环境中不支持控制模式转换。(默认:None) │
│ --verbose, --no-verbose │
│ 是否在轨迹重播过程中打印详细信息(默认:False) │
│ --save-traj, --no-save-traj │
│ 是否保存轨迹到磁盘。这不会覆盖原始轨迹文件。(默认:False) │
│ --save-video, --no-save-video │
│ 是否保存视频(默认:False) │
│ --num-procs INT 用于并行化轨迹重播过程的进程数。对于 CPU 后端,通常通过 Python 多进程并行化。 │
│ 对于像 physx_gpu 这样的并行仿真后端,这将在单个 Python 进程内通过利用 GPU 来并行化。(默认:1) │
│ --max-retry INT 在任务成功结束前,重播轨迹的最大尝试次数。(默认:0) │
│ --discard-timeout, --no-discard-timeout │
│ 是否丢弃超时并被截断的回合(取决于任务的 max_episode_steps 参数) │
│ (默认:False) │
│ --allow-failure, --no-allow-failure │
│ 是否包含失败的回合,在保存的视频和轨迹数据中根据环境的评估返回的 "success" 标签决定 │
│ (默认:False) │
│ --vis, --no-vis 是否通过 GUI 可视化轨迹重播。(默认:False) │
│ --use-env-states, --no-use-env-states │
│ 是否通过环境状态重播,而不是通过动作。这可以保证环境在每个步骤看起来与原始轨迹完全相同。(默认:False) │
│ --use-first-env-state, --no-use-first-env-state │
│ 是否使用轨迹中的第一个环境状态来设置初始状态。这对于尝试将收集自 CPU 仿真中的演示重播到 GPU 仿真中非常有用,因为 GPU │
│ 仿真即使给定相同种子也会以不同的方式随机化初始状态。(默认:False) │
│ --count {None}|INT 要重播的演示数量,直到退出。默认情况下将重播所有演示(默认:None) │
│ --reward-mode {None}|STR │
│ 指定环境应使用的奖励类型。默认情况下将选择第一个支持的奖励模式。大多数环境支持 'sparse'、'none',有些还支持 'normalized_dense' │
│ 和 'dense' 奖励模式(默认:None) │
│ --record-rewards, --no-record-rewards │
│ 是否在重播的轨迹中包含奖励(默认:False) │
│ --shader {None}|STR 更改所有相机渲染使用的着色器。默认情况下使用原始数据收集时使用的着色器。可以选择 'rt' 进行光线追踪生成逼真的渲染, │
│ 也可以选择 'rt-fast' 进行更快但质量较低的光线追踪渲染。(默认:None) │
│ --video-fps {None}|INT 保存视频的 FPS。默认为控制频率(默认:None) │
│ --render-mode STR 用于保存视频的渲染模式。通常还包括 'sensors' 和 'all' 渲染模式,进一步渲染所有传感器输出,如相机。(默认:rgb_array) │
│ --num-envs INT, -n INT 要运行的环境数量以重播轨迹。对于 CPU 后端,通常通过 Python 多进程并行化。 │
│ 对于像 physx_gpu 这样的并行仿真后端,这将在单个 Python 进程内通过利用 GPU 来并行化。(默认:1) │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
但是最新的参数出现了变化
╭─ 选项 ──────────────────────────────────────────────────────────────────╮ │ -h, --help │ │ 显示帮助信息并退出 │ │ --traj-path STR │ │ 需要回放的轨迹 .h5 文件路径(必需) │ │ -b {None}|STR, --sim-backend {None}|STR │ │ 使用的仿真后端。可以是 'physx_cpu' 或 'physx_gpu'。如果未指定, │ │ 默认使用收集轨迹数据时使用的后端。(默认:None) │ │ -o {None}|STR, --obs-mode {None}|STR │ │ 目标观察模式,用于记录轨迹中的观察数据。查看 │ │ https://maniskill.readthedocs.io/en/latest/user_guide/concepts/observ… │ │ 获取支持的所有观察模式的完整列表。(默认:None) │ │ -c {None}|STR, --target-control-mode {None}|STR │ │ 目标控制模式,用于将示范动作转换为其他控制模式。注意,并非所有的控制 │ │ 模式都能成功转换,并且并非所有机器人都支持轻松转换控制模式。 │ │ 目前,Panda 机器人在控制模式转换方面支持最好。并且,在 GPU 并行化环境 │ │ 下不支持控制模式转换。(默认:None) │ │ --verbose, --no-verbose │ │ 是否在回放轨迹时打印详细信息。(默认:False) │ │ --save-traj, --no-save-traj │ │ 是否将轨迹保存到磁盘。此操作不会覆盖原始轨迹文件。(默认:False) │ │ --save-video, --no-save-video │ │ 是否保存视频。(默认:False) │ │ --max-retry INT │ │ 回放轨迹时最大重试次数,直到任务在结束时达到成功状态。(默认:0) │ │ --discard-timeout, --no-discard-timeout │ │ 是否丢弃超时并被截断的回合(取决于任务的 max_episode_steps 参数) │ │ (默认:False) │ │ --allow-failure, --no-allow-failure │ │ 是否在保存的视频和轨迹数据中包含失败的回合,基于环境的评估返回的“成功” │ │ 标签。(默认:False) │ │ --vis, --no-vis │ │ 是否通过 GUI 可视化回放轨迹。(默认:False) │ │ --use-env-states, --no-use-env-states │ │ 是否使用环境状态而不是动作进行回放。这样可以保证环境的每一步状态与 │ │ 原始轨迹完全相同。(默认:False) │ │ --use-first-env-state, --no-use-first-env-state │ │ 使用轨迹中的第一个环境状态来设置初始状态。对于尝试在 GPU 仿真中回放 │ │ 在 CPU 仿真中收集的示范,这非常有用,因为 GPU 仿真会与 CPU 仿真 │ │ 使用相同种子时随机化初始状态。(默认:False) │ │ --count {None}|INT │ │ 在退出之前回放的示范数量。默认情况下,将回放所有示范。(默认:None) │ │ --reward-mode {None}|STR │ │ 指定环境应使用的奖励类型。默认情况下将选择第一个支持的奖励模式。大多数 │ │ 环境支持 'sparse'、'none',有些环境还支持 'normalized_dense' 和 │ │ 'dense' 奖励模式。(默认:None) │ │ --record-rewards, --no-record-rewards │ │ 是否在回放的轨迹中包含奖励。(默认:False) │ │ --shader {None}|STR │ │ 更改所有摄像机渲染使用的着色器。默认值为 none,即使用原始数据收集时 │ │ 使用的着色器或环境默认着色器。也可以设置为 'rt' 来启用光线追踪,生成 │ │ 照片级逼真渲染。还可以设置为 'rt-fast' 来启用更快但质量较低的光线追踪 │ │ 渲染器。(默认:None) │ │ --video-fps {None}|INT │ │ 保存视频的帧率。默认为控制频率。(默认:None) │ │ --render-mode STR │ │ 保存视频时使用的渲染模式。通常还有 'sensors' 和 'all' 渲染模式, │ │ 可以渲染所有传感器输出,如摄像头。(默认:rgb_array) │ │ -n INT, --num-envs INT │ │ 用于回放轨迹的环境数量。对于 CPU 后端,通常通过 Python 多进程并行化。 │ │ 对于像 physx_gpu 这样的并行仿真后端,通常通过在单个 Python 进程中利用 │ │ GPU 并行化。(默认:1) │ ╰────────────────────────────────────────────────────────────────────────────╯
下面的表格列出了旧版本与新版本中各个参数的对比情况:
| 参数 | 旧版本描述 | 新版本描述 | 备注 |
|---|---|---|---|
| --traj-path STR | 需要回放的轨迹 .h5 文件路径(必需) | 需要回放的轨迹 .h5 文件路径(必需) | 无变化 |
| --sim-backend {None}|STR, -b {None}|STR | 使用的仿真后端,可选 'physx_cpu' 或 'physx_gpu'。未指定时默认使用收集轨迹时使用的后端。(默认:None) | 同旧版本描述 | 无变化 |
| --obs-mode {None}|STR, -o {None}|STR | 目标观察模式,用于记录轨迹中的观察数据。参见文档获取支持的观察模式列表。(默认:None) | 同旧版本描述 | 无变化 |
| --target-control-mode {None}|STR, -c {None}|STR | 目标控制模式,用于将示范动作转换为其他控制模式。注意不是所有控制模式都能成功转换,目前 Panda 机器人支持最佳;GPU 环境下不支持转换。(默认:None) | 同旧版本描述 | 无变化 |
| --verbose, --no-verbose | 是否在轨迹重播过程中打印详细信息。(默认:False) | 是否在回放轨迹时打印详细信息。(默认:False) | 描述略有不同,但功能相同 |
| --save-traj, --no-save-traj | 是否保存轨迹到磁盘,不会覆盖原始轨迹文件。(默认:False) | 是否将轨迹保存到磁盘,不会覆盖原始轨迹文件。(默认:False) | 无变化 |
| --save-video, --no-save-video | 是否保存视频。(默认:False) | 是否保存视频。(默认:False) | 无变化 |
| --num-procs INT | 用于并行化轨迹重播过程的进程数。CPU 后端通过 Python 多进程并行;physx_gpu 后端在单进程内利用 GPU 并行化。(默认:1) | 已删除 | 新版本中移除了该参数 |
| --max-retry INT | 回放轨迹时最大重试次数,直到任务在结束时达到成功状态。(默认:0) | 同旧版本描述 | 无变化 |
| --discard-timeout, --no-discard-timeout | 是否丢弃超时并被截断的回合(取决于任务的 max_episode_steps 参数)。(默认:False) | 同旧版本描述 | 无变化 |
| --allow-failure, --no-allow-failure | 是否在保存的视频和轨迹数据中包含失败的回合,依据环境评估返回的 "success" 标签决定。(默认:False) | 同旧版本描述 | 无变化 |
| --vis, --no-vis | 是否通过 GUI 可视化轨迹重播。(默认:False) | 同旧版本描述 | 无变化 |
| --use-env-states, --no-use-env-states | 是否使用环境状态而非动作进行回放,保证环境在每一步与原始轨迹一致。(默认:False) | 同旧版本描述 | 无变化 |
| --use-first-env-state, --no-use-first-env-state | 是否使用轨迹中的第一个环境状态作为初始状态,用于在 GPU 仿真中重播 CPU 收集的示范。(默认:False) | 同旧版本描述 | 无变化 |
| --count {None}|INT | 在退出前回放的示范数量,默认回放所有示范。(默认:None) | 同旧版本描述 | 无变化 |
| --reward-mode {None}|STR | 指定环境使用的奖励类型,大多数环境支持 'sparse'、'none',部分支持 'normalized_dense' 和 'dense'。(默认:None) | 同旧版本描述 | 无变化 |
| --record-rewards, --no-record-rewards | 是否在回放轨迹中包含奖励。(默认:False) | 同旧版本描述 | 无变化 |
| --shader {None}|STR | 更改所有摄像机渲染使用的着色器。默认使用原始数据收集时或环境默认的着色器;可选 'rt'(光线追踪)或 'rt-fast'(快速光线追踪)。(默认:None) | 同旧版本描述 | 无变化 |
| --video-fps {None}|INT | 保存视频的帧率,默认为控制频率。(默认:None) | 同旧版本描述 | 无变化 |
| --render-mode STR | 保存视频时使用的渲染模式,支持 'rgb_array'、'sensors'、'all' 等模式,后两者可渲染所有传感器数据。(默认:rgb_array) | 同旧版本描述 | 无变化 |
| --num-envs INT, -n INT | 用于回放轨迹的环境数量。CPU 后端通过 Python 多进程并行;physx_gpu 后端在单进程内利用 GPU 并行化。(默认:1) | 同旧版本描述 | 无变化 |
通过上表可以看出,最新版本主要移除了 --num-procs 参数,其余各参数及其功能基本保持一致。
:::
:::{caution}
由于某些演示是以非准静态方式收集的(在操作过程中物体没有固定在操纵器上)或某些具有挑战性的任务(例如 PushT-v1 或 PickSingleYCB-v1)需要高精度,因此,由于仿真中的非确定性,重播动作/转换动作可能会失败。因此,通过传递 --use-env-states 来重播轨迹并确保重播的状态/观察数据与原始轨迹相同是必需的。
:::
由于轨迹重播工具功能丰富且复杂,我们建议几个示例工作流程,适用于各种用例。
在机器学习工作流中,有时从一些控制模式(例如末端执行器控制模式)中学习会更容易。下面的示例正是这样做的:
python -m mani_skill.trajectory.replay_trajectory \
--traj-path path/to/trajectory.h5 \
-c pd_ee_delta_pose -o state \
--save-traj请注意,由于控制器和演示行为的固有差异,一些目标控制模式可能很难转换。
-
PickCube-v1任务:这是一个相对简单的任务,适合初步测试
~/.maniskill/demos/PickCube-v1/rl/trajectory.none.pd_joint_delta_pos.physx_cuda.h5(源控制模式:关节控制)- 转换目标:
pd_ee_delta_pose(末端执行器姿态控制)
-
PushCube-v1任务:这是一个推箱子的任务,动作相对简单
~/.maniskill/demos/PushCube-v1/rl/trajectory.none.pd_joint_delta_pos.physx_cuda.h5(源控制模式:关节控制)- 转换目标:
pd_ee_delta_pos(末端执行器位置控制)
-
StackCube-v1任务:这是一个更复杂的堆叠任务,需要更精确的控制
~/.maniskill/demos/StackCube-v1/rl/trajectory.none.pd_ee_delta_pos.physx_cuda.h5(源控制模式:末端执行器位置控制)- 转换目标:
pd_ee_delta_pose(末端执行器姿态控制)
要查看测试效果,你可以:
- 观察生成的轨迹文件:重播后会生成一个新的 h5 文件,文件名中包含目标控制模式
- 查看生成的视频:使用
--render-mode rgb_array --render-camera third_view --replay-render参数可以生成重播视频 - 比较前后的轨迹:可以比较原始轨迹和重播轨迹的 MP4 视频,看机器人的行为是否相似
我推荐从 PickCube-v1 任务开始测试,因为它是最基础的拾取任务,可以执行以下命令:
python -m mani_skill.trajectory.replay_trajectory \
--traj-path ~/.maniskill/demos/PickCube-v1/rl/trajectory.none.pd_joint_delta_pos.physx_cuda.h5 \
-c pd_ee_delta_pose -o state \
--render-mode rgb_array --render-camera third_view --replay-render \
--save-traj这个命令会:
- 读取源轨迹文件(关节控制模式)
- 重播到末端执行器姿态控制模式
- 保存新的轨迹文件
- 生成重播视频
执行后,你可以比较 sample_pd_joint_delta_pos.mp4 和新生成的视频文件,查看机器人在不同控制模式下的表现差异。
但是,如果遇到相关最大步数的报错,记得修改
ManiSkill 的控制模式转换有一些限制,特别是:
- 从
pd_joint_delta_pos只能转换为pd_joint_pos - 从
pd_joint_pos可以转换为末端执行器控制(pd_ee_delta_pose等)
为了解决这个问题,我们需要进行两步转换:
- 首先从
pd_joint_delta_pos转换为pd_joint_pos - 然后从
pd_joint_pos转换为pd_ee_delta_pose
以下是解决方案:
# 第一步:转换为 pd_joint_pos
python -m mani_skill.trajectory.replay_trajectory \
--traj-path ~/.maniskill/demos/PickCube-v1/rl/trajectory.none.pd_joint_delta_pos.physx_cuda.h5 \
--target-control-mode pd_joint_pos \
--obs-mode state \
--render-mode rgb_array \
--save-traj \
--sim-backend physx_cpu \
--num-envs 1
# 第二步:从 pd_joint_pos 转换为 pd_ee_delta_pose
python -m mani_skill.trajectory.replay_trajectory \
--traj-path ~/.maniskill/demos/PickCube-v1/rl/trajectory.state.pd_joint_pos.physx_cpu.h5 \
--target-control-mode pd_ee_delta_pose \
--obs-mode state \
--render-mode rgb_array \
--save-traj \
--save-video \
--video-fps 30 \
--sim-backend physx_cpu \
--num-envs 1另外,如果想查看代码中支持的转换路径,可以看一下 utils/actions/conversion.py 文件。根据我们的查看,ManiSkill 支持的转换路径主要有:
pd_joint_pos→pd_ee_delta_pose(通过from_pd_joint_pos_to_ee函数)pd_joint_delta_pos→pd_joint_pos(通过from_pd_joint_delta_pos函数)
为了节省内存,演示通常不包含观察数据和奖励。下面的示例展示了如何将奖励、RGB 观察数据和标准化的密集奖励(假设环境支持密集奖励)重新添加到轨迹中。--use-env-states 作为确保重播的状态/观察数据与原始轨迹完全相同的方式被添加。
python -m mani_skill.trajectory.replay_trajectory \
--traj-path path/to/trajectory.h5 \
--record-rewards --reward-mode="normalized_dense" -o rgb \
--use-env-states \
--save-traj
例如:
python -m mani_skill.trajectory.replay_trajectory \
--traj-path ~/.maniskill/demos/PickCube-v1/motionplanning/trajectory.h5 \
--record-rewards --reward-mode="normalized_dense" -o rgb \
--use-env-states \
--save-traj \
--sim-backend physx_cpu \
--num-envs 1这个就是刚刚生成的文件
然后是可视化环节
python -m mani_skill.trajectory.replay_trajectory \
--traj-path ~/.maniskill/demos/PickCube-v1/motionplanning/trajectory.rgb.none.physx_cpu.h5 \
--vis \
--sim-backend physx_cpu \
--num-envs 1
其实就是生成这个绿色的点
某些演示可能是在 CPU 仿真中收集的,但希望它们能够在 GPU 仿真中使用,反之亦然。由于 CPU 和 GPU 仿真在给定相同动作和初始状态时会有略微不同的行为,需要确保演示可以被学习。
例如,如果使用遥操作收集演示,这些演示通常会在 CPU 仿真中收集,以便提供更大的灵活性和更高的单线程速度。然而,模仿/强化学习工作流可能会在 GPU 仿真中进行训练。为了确保可以从演示中学习,我们可以将它们重播到 GPU 仿真中,并保存那些成功重播的演示。这是通过使用第一个环境状态、强制使用 GPU 仿真(-b "physx_cuda")并设置所需的控制和观察模式来实现的。
python -m mani_skill.trajectory.replay_trajectory \
--traj-path path/to/trajectory.h5 \
--use-first-env-state -b "physx_cuda" \
-c pd_joint_delta_pos -o state \
--save-traj
例如
python -m mani_skill.trajectory.replay_trajectory \
--traj-path ~/.maniskill/demos/PushCube-v1/motionplanning/trajectory.h5 \
--use-first-env-state -b "physx_cuda" \
-c pd_joint_delta_pos -o state \
--save-traj
生成
~/.maniskill/demos/PushCube-v1/motionplanning/trajectory.state.pd_joint_delta_pos.physx_cuda.h5
可视化
python -m mani_skill.trajectory.replay_trajectory \
--traj-path ~/.maniskill/demos/PushCube-v1/motionplanning/trajectory.state.pd_joint_delta_pos.physx_cuda.h5 \
--vis




