Hydra 配置系统#

Isaac Lab 支持 Hydra 配置系统,以通过命令行参数修改任务的配置,这对于自动化实验和执行超参数调整非常有用。

环境的任何参数都可以通过在命令行输入中添加一个或多个形式为 env.a.b.param1=value 的元素来修改,其中 a.b.param1 反映了参数的层次结构,例如 env.actions.joint_effort.scale=10.0 。类似地,智能体的参数可以通过使用 agent 前缀来修改,例如 agent.seed=2024

这些命令行参数的设置方式遵循配置文件的精确结构。由于不同的 RL 框架使用不同的约定,因此参数设置方式可能会有所不同。例如,使用 rl_games 时,种子将通过 agent.params.seed 设置,而在 rsl_rlskrlsb3 中,则通过 agent.seed 设置。

因此,使用 hydra 参数进行训练可以使用以下语法运行:

python source/standalone/workflows/rsl_rl/train.py --task=Isaac-Cartpole-v0 --headless env.actions.joint_effort.scale=10.0 agent.seed=2024
python source/standalone/workflows/rl_games/train.py --task=Isaac-Cartpole-v0 --headless env.actions.joint_effort.scale=10.0 agent.params.seed=2024
python source/standalone/workflows/skrl/train.py --task=Isaac-Cartpole-v0 --headless env.actions.joint_effort.scale=10.0 agent.seed=2024
python source/standalone/workflows/sb3/train.py --task=Isaac-Cartpole-v0 --headless env.actions.joint_effort.scale=10.0 agent.seed=2024

上述命令将以无头模式运行任务 Isaac-Cartpole-v0 的训练脚本,并将 env.actions.joint_effort.scale 参数设置为 10.0,以及将 agent.seed 参数设置为 2024。

备注

为了保持向后兼容性,并提供更友好的用户体验,我们保留了旧的 cli 参数形式 --param,例如 --num_envs--seed--max_iterations。这些参数优先于 hydra 参数,并将覆盖由 hydra 参数设置的值。

修改高级参数#

可调用对象#

可以通过使用语法 module:attribute_name 修改配置文件中的函数和类。例如,在 Cartpole 环境中:

class ObservationsCfg:
    """Observation specifications for the MDP."""

    @configclass
    class PolicyCfg(ObsGroup):
        """Observations for policy group."""

        # observation terms (order preserved)
        joint_pos_rel = ObsTerm(func=mdp.joint_pos_rel)
        joint_vel_rel = ObsTerm(func=mdp.joint_vel_rel)

        def __post_init__(self) -> None:
            self.enable_corruption = False
            self.concatenate_terms = True

    # observation groups
    policy: PolicyCfg = PolicyCfg()

我们可以修改 joint_pos_rel 以计算绝对位置,而不是相对位置,使用 env.observations.policy.joint_pos_rel.func=omni.isaac.lab.envs.mdp:joint_pos

将参数设置为 None#

要将参数设置为 None,请使用 null 关键字,这是 Hydra 中的一个特殊关键字,会自动转换为 None。在上面的示例中,我们还可以通过将 env.observations.policy.joint_pos_rel=null 设置为 None 来禁用 joint_pos_rel 观察。

字典#

字典中的元素被作为参数处理在层级结构中。例如,在 Cartpole 环境中:

    reset_cart_position = EventTerm(
        func=mdp.reset_joints_by_offset,
        mode="reset",
        params={
            "asset_cfg": SceneEntityCfg("robot", joint_names=["slider_to_cart"]),
            "position_range": (-1.0, 1.0),
            "velocity_range": (-0.5, 0.5),
        },
    )

    reset_pole_position = EventTerm(
        func=mdp.reset_joints_by_offset,
        mode="reset",
        params={
            "asset_cfg": SceneEntityCfg("robot", joint_names=["cart_to_pole"]),
            "position_range": (-0.25 * math.pi, 0.25 * math.pi),
            "velocity_range": (-0.25 * math.pi, 0.25 * math.pi),
        },
    )


@configclass
class RewardsCfg:
    """Reward terms for the MDP."""

position_range 参数可以通过 env.events.reset_cart_position.params.position_range="[-2.0, 2.0]" 进行修改。这个例子展示了两个值得注意的点:

  • 我们设置的参数包含空格,因此必须用引号括起来。

  • 参数是一个列表,而在 config 中它是一个元组。这是因为 Hydra 不支持元组。

修改高级参数#

在使用命令行参数修改参数时应特别小心。一些配置会根据其他参数执行中间计算。这些计算在参数被修改时不会更新。

例如,对于 Cartpole 相机深度环境的配置:

class CartpoleDepthCameraEnvCfg(CartpoleRGBCameraEnvCfg):
    # camera
    tiled_camera: TiledCameraCfg = TiledCameraCfg(
        prim_path="/World/envs/env_.*/Camera",
        offset=TiledCameraCfg.OffsetCfg(pos=(-5.0, 0.0, 2.0), rot=(1.0, 0.0, 0.0, 0.0), convention="world"),
        data_types=["depth"],
        spawn=sim_utils.PinholeCameraCfg(
            focal_length=24.0, focus_distance=400.0, horizontal_aperture=20.955, clipping_range=(0.1, 20.0)
        ),
        width=80,
        height=80,
    )

    # spaces
    observation_space = [tiled_camera.height, tiled_camera.width, 1]

如果用户修改了相机的宽度,即 env.tiled_camera.width=128 ,那么参数 env.observation_space=[80,128,1] 也必须更新并作为输入提供。

类似地,__post_init__ 方法不会随着命令行输入而更新。在 LocomotionVelocityRoughEnvCfg 中,例如,post init 更新如下:

class LocomotionVelocityRoughEnvCfg(ManagerBasedRLEnvCfg):
    """Configuration for the locomotion velocity-tracking environment."""

    # Scene settings
    scene: MySceneCfg = MySceneCfg(num_envs=4096, env_spacing=2.5)
    # Basic settings
    observations: ObservationsCfg = ObservationsCfg()
    actions: ActionsCfg = ActionsCfg()
    commands: CommandsCfg = CommandsCfg()
    # MDP settings
    rewards: RewardsCfg = RewardsCfg()
    terminations: TerminationsCfg = TerminationsCfg()
    events: EventCfg = EventCfg()
    curriculum: CurriculumCfg = CurriculumCfg()

    def __post_init__(self):
        """Post initialization."""
        # general settings
        self.decimation = 4
        self.episode_length_s = 20.0
        # simulation settings
        self.sim.dt = 0.005
        self.sim.render_interval = self.decimation
        self.sim.disable_contact_processing = True
        self.sim.physics_material = self.scene.terrain.physics_material
        # update sensor update periods
        # we tick all the sensors based on the smallest update period (physics update period)
        if self.scene.height_scanner is not None:
            self.scene.height_scanner.update_period = self.decimation * self.sim.dt
        if self.scene.contact_forces is not None:
            self.scene.contact_forces.update_period = self.sim.dt

        # check if terrain levels curriculum is enabled - if so, enable curriculum for terrain generator
        # this generates terrains with increasing difficulty and is useful for training
        if getattr(self.curriculum, "terrain_levels", None) is not None:
            if self.scene.terrain.terrain_generator is not None:
                self.scene.terrain.terrain_generator.curriculum = True
        else:
            if self.scene.terrain.terrain_generator is not None:
                self.scene.terrain.terrain_generator.curriculum = False

在这里,当修改 env.decimationenv.sim.dt 时,用户还需要输入更新后的 env.sim.render_intervalenv.scene.height_scanner.update_periodenv.scene.contact_forces.update_period