ManiSkill 通过统一的 API 支持各种强化学习方法,并提供多种现成的、经过测试的基线以供使用/比较。以下页面展示了如何设置强化学习环境以及如何使用 RL 基线。所有基线结果都发布到我们的公共 wandb 页面。在该页面上,可以按使用的算法、环境类型等进行过滤。我们仍在进行所有实验,因此并非所有结果都已上传。
本页记录了为强化学习设置 ManiSkill 环境时需要了解的关键事项,包括:
- 如何将 ManiSkill 环境转换为兼容 gymnasium API 的环境,包括单个和向量化 API。
- 如何正确地公平地评估 RL 策略
- 有用的包装器
ManiSkill 环境由 gymnasium 的 make 函数创建。默认情况下,结果是一个“批处理”环境,其中每个输入和输出都是批处理的。请注意,这不是标准的 gymnasium API。如果想要标准的 gymnasium 环境 / 向量化环境 API,请参阅下一节。
import mani_skill.envs
import gymnasium as gym
N = 4
env = gym.make("PickCube-v1", num_envs=N)
env.action_space # shape (N, D)
env.observation_space # shape (N, ...)
env.reset()
obs, rew, terminated, truncated, info = env.step(env.action_space.sample())
# obs (N, ...), rew (N, ), terminated (N, ), truncated (N, )如果想使用 CPU 模拟器 / 单个环境,可以应用 CPUGymWrapper,它本质上会取消所有批处理,并将所有内容转换为 numpy,因此环境的行为就像一个普通的 gym 环境一样。有关 gym 环境的 API 的详细信息,请参阅其文档。
import mani_skill.envs
import gymnasium as gym
from mani_skill.utils.wrappers.gymnasium import CPUGymWrapper
N = 1
env = gym.make("PickCube-v1", num_envs=N)
env = CPUGymWrapper(env)
env.action_space # shape (D, )
env.observation_space # shape (...)
env.reset()
obs, rew, terminated, truncated, info = env.step(env.action_space.sample())
# obs (...), rew (float), terminated (bool), truncated (bool)我们还采用了 gymnasium VectorEnv(也称为 AsyncVectorEnv)接口,可以通过单个包装器来实现这一点,以便假设 VectorEnv 接口的算法可以无缝工作。有关向量化 gym 环境的 API 的详细信息,请参阅其文档
import mani_skill.envs
import gymnasium as gym
from mani_skill.vector.wrappers.gymnasium import ManiSkillVectorEnv
N = 4
env = gym.make("PickCube-v1", num_envs=N)
env = ManiSkillVectorEnv(env, auto_reset=True, ignore_terminations=False)
env.action_space # shape (N, D)
env.single_action_space # shape (D, )
env.observation_space # shape (N, ...)
env.single_observation_space # shape (...)
env.reset()
obs, rew, terminated, truncated, info = env.step(env.action_space.sample())
# obs (N, ...), rew (N, ), terminated (N, ), truncated (N, )可能还会注意到,在创建向量环境时,还有两个额外的选项。auto_reset 参数控制当并行环境终止或截断时是否自动重置该环境。这取决于算法。ignore_terminations 参数控制环境是否在 terminated 为 True 时重置。与 gymnasium 向量环境一样,可能会发生部分重置,其中一些并行环境重置,而另一些则不重置。
请注意,为了提高效率,环境返回的所有内容都将是 GPU 上的批处理 torch 张量,而不是 CPU 上的批处理 numpy 数组。这可能是 ManiSkill 向量化环境和 gymnasium 向量化环境之间可能需要考虑的唯一区别。
考虑到不同类型的环境、算法和评估方法,我们在下面描述了一种一致且标准化的方法,以在 ManiSkill 中公平地评估所有类型的策略。总而言之,需要以下设置以确保公平评估:
- 关闭部分重置,并且环境在成功/失败/终止时不重置 (
ignore_terminations=True)。相反,我们记录多种类型的成功/失败指标。 - 所有并行环境在重置时重新配置 (
reconfiguration_freq=1),如果任务具有对象随机化,则会随机化对象几何体。
以下代码展示了如何在 ManiSkill 中公平地评估策略并记录标准指标。对于 GPU 向量化环境,建议按环境 ID 评估策略的代码如下:
import gymnasium as gym
from mani_skill.vector.wrappers.gymnasium import ManiSkillVectorEnv
env_id = "PushCube-v1"
num_eval_envs = 64
env_kwargs = dict(obs_mode="state") # modify your env_kwargs here
eval_envs = gym.make(env_id, num_envs=num_eval_envs, reconfiguration_freq=1, **env_kwargs)
# add any other wrappers here
eval_envs = ManiSkillVectorEnv(eval_envs, ignore_terminations=True, record_metrics=True)
# evaluation loop, which will record metrics for complete episodes only
obs, _ = eval_envs.reset(seed=0)
eval_metrics = defaultdict(list)
for _ in range(400):
action = eval_envs.action_space.sample() # replace with your policy action
obs, rew, terminated, truncated, info = eval_envs.step(action)
# note as there are no partial resets, truncated is True for all environments at the same time
if truncated.any():
for k, v in info["final_info"]["episode"].items():
eval_metrics[k].append(v.float())
for k in eval_metrics.keys():
print(f"{k}_mean: {torch.mean(torch.stack(eval_metrics[k])).item()}")对于 CPU 向量化环境,建议使用以下代码进行评估:
import gymnasium as gym
from mani_skill.utils.wrappers import CPUGymWrapper
env_id = "PickCube-v1"
num_eval_envs = 8
env_kwargs = dict(obs_mode="state") # modify your env_kwargs here
def cpu_make_env(env_id, env_kwargs = dict()):
def thunk():
env = gym.make(env_id, reconfiguration_freq=1, **env_kwargs)
env = CPUGymWrapper(env, ignore_terminations=True, record_metrics=True)
# add any other wrappers here
return env
return thunk
vector_cls = gym.vector.SyncVectorEnv if num_eval_envs == 1 else lambda x : gym.vector.AsyncVectorEnv(x, context="forkserver")
eval_envs = vector_cls([cpu_make_env(env_id, env_kwargs) for _ in range(num_eval_envs)])
# evaluation loop, which will record metrics for complete episodes only
obs, _ = eval_envs.reset(seed=0)
eval_metrics = defaultdict(list)
for _ in range(400):
action = eval_envs.action_space.sample() # replace with your policy action
obs, rew, terminated, truncated, info = eval_envs.step(action)
# note as there are no partial resets, truncated is True for all environments at the same time
if truncated.any():
for final_info in info["final_info"]:
for k, v in final_info["episode"].items():
eval_metrics[k].append(v)
for k in eval_metrics.keys():
print(f"{k}_mean: {np.mean(eval_metrics[k])}")以下指标被记录并在下面解释:
success_once:任务在 episode 中的任何时间点是否成功。success_at_end:任务在 episode 的最后一步是否成功。fail_once/fail_at_end:与上述两个指标相同,但用于失败。请注意,并非所有任务都具有成功/失败标准。return:episode 中累积的总奖励。
RL 从业者经常使用包装器来修改和增强环境。这些记录在 wrappers部分中。一些常用的包括:
- RecordEpisode 用于记录 rollouts 的视频/轨迹。
- FlattenRGBDObservations用于将
obs_mode="rgbd"或obs_mode="rgb+depth"观察结果展平为简单的字典,其中仅包含组合的rgbd张量和state张量。
在旧的环境/基准测试中,人们经常使用 env.render(mode="rgb_array") 或 env.render() 来获取 RL 代理的图像输入。这是不正确的,因为图像观察结果由 env.reset() 和 env.step() 直接返回,并且 env.render 仅用于 ManiSkill 中的可视化/视频录制。
对于机器人任务,观察结果通常由状态信息(如机器人关节角度)和图像观察结果(如相机图像)组成。当 obs_mode 不是 state 或 state_dict(如地面实况对象姿势)时,ManiSkill 中的所有任务都将专门从观察结果中删除某些特权状态信息。此外,env.reset() 和 env.step() 返回的图像观察结果通常来自位于特定位置的相机,以提供任务的良好视野,使其可解决。
我们提供了多种不同的基准线,通过在线强化学习从奖励中学习。
作为这些基准线的一部分,我们建立了标准化的强化学习基准,涵盖了广泛的难度(易于解决以进行验证,但未饱和)和机器人任务类型的多样性,包括但不限于经典控制、灵巧操作、桌面操作、移动操作等。
已实现并测试的在线强化学习基准线列表。结果链接会将带到相应的 wandb 页面以查看结果。可以在 wandb 工作区中更改过滤器/视图,以查看具有其他设置(例如基于状态或基于 RGB 的训练)的结果。请注意,还有利用演示的强化学习(离线 RL、在线模仿学习)基准线
| 基准线 | 代码 | 结果 | 论文 |
|---|---|---|---|
| 近端策略优化 (PPO) | 链接 | 链接 | 链接 |
| 软演员-评论家 (SAC) | 链接 | WIP | 链接 |
| 用于模型预测控制的时间差分学习 (TD-MPC2) | WIP | WIP | 链接 |
ManiSkill 中强化学习的标准基准由两组组成,一组包含 8 个任务的小集合,另一组包含 50 个任务的大集合,两者都具有基于状态和基于视觉的设置。所有标准基准任务都带有归一化的密集奖励函数。创建了一个推荐的小集合,以便没有大量计算资源的研人员仍然可以合理地对其工作进行基准测试/比较。大型集合仍在开发和测试中。
这些任务涵盖了机器人/强化学习中极其广泛的问题,即:高维观察/动作、大型初始状态分布、关节物体操作、可泛化操作、移动操作、运动等。
小集合环境 ID:
PushCube-v1, PickCube-v1, PegInsertionSide-v1, PushT-v1, HumanoidPlaceAppleInBowl-v1, AnymalC-Reach-v1, OpenCabinetDrawer-v1
要正确评估强化学习策略,请参阅强化学习设置页面中的评估部分,了解该代码的设置方式。上面链接的结果中报告的所有结果都遵循相同的评估设置。