Hydra 配置系统#

通过 Hydra 覆盖参数,可在命令行修改任务和智能体设置,无需编辑 Python。

环境设置使用 env.<path>=<value>,例如 env.actions.joint_effort.scale=10.0;训练设置使用 agent 前缀,例如 agent.seed=2024。

路径遵循各强化学习库的配置结构。例如,RL-Games 使用 agent.params.seed,RSL-RL、skrl 和 SB3 使用 agent.seed。

例如:

uv run isaaclab train --rl_library rsl_rl --task=Isaac-Cartpole env.actions.joint_effort.scale=10.0 agent.seed=2024
uv run --extra rl-games isaaclab train --rl_library rl_games --task=Isaac-Cartpole env.actions.joint_effort.scale=10.0 agent.params.seed=2024
uv run --extra skrl isaaclab train --rl_library skrl --task=Isaac-Cartpole env.actions.joint_effort.scale=10.0 agent.seed=2024
uv run --extra sb3 isaaclab train --rl_library sb3 --task=Isaac-Cartpole env.actions.joint_effort.scale=10.0 agent.seed=2024

上述命令训练 Isaac-Cartpole 任务,不选择可视化器,并将 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):
            self.enable_corruption = False
            self.concatenate_terms = True

    # observation groups
    policy: PolicyCfg = PolicyCfg()

我们可以修改 joint_pos_rel 以计算绝对位置,而不是相对位置,使用 env.observations.policy.joint_pos_rel.func=isaaclab.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),
        },
    )

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

  • 该值包含空格,因此必须用引号括起,供 shell 正确解析。

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

修改高级参数#

覆盖参数不会重新计算此前已由其他设置推导出的值。除非环境会在运行时重新计算,否则也需更新这些依赖值。

例如,Cartpole 相机环境的配置:

class CartpoleCameraEnvCfg(PresetCfg):
    """Cartpole camera environment with a selectable camera data type.

    The selector also picks the matching tiled camera preset and its rendering backend through
    :attr:`CartpoleCameraSceneCfg.tiled_camera`.
    """

    @configclass
    class BaseCartpoleCameraEnvCfg(CartpoleEnvCfg):
        """Camera variant of :class:`CartpoleEnvCfg`; only the fields that differ are overridden."""

        write_image_to_file = False

        frame_stack: int = 2
        """Number of frames to stack along the channel dimension.

        Values less than two disable stacking.
        """

        # spaces: single-frame channels + default spatial size. At env init, height/width
        # are replaced with the tiled camera size and channels are expanded by frame_stack.
        # Only the channel count must stay in sync with the camera data type (presets set this).
        observation_space = [3, 96, 96]

配置声明单帧通道数和默认空间尺寸。环境初始化时, CartpoleCameraEnv 根据解析后的相机重新构建 observation_space :默认 frame_stack=2 会扩展通道数,高度和宽度来自 scene.tiled_camera 。因此,仅设置 env.scene.tiled_camera.width=128 env.scene.tiled_camera.height=128 ,就会得到有效的堆叠形状 [6,128,128] ,无需同时覆盖 env.observation_space 。 observation_space 中的通道数仍必须匹配相机数据类型(例如 presets=depth 对应 [1, ...] );预设已完成这一设置。

类体中的赋值在导入时只求值一次, 不会 随后续 Hydra 覆盖自动更新,除非运行时代码显式重新构建依赖值,正如这个相机环境所做的那样。

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

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

    # Simulation settings
    sim: SimulationCfg = SimulationCfg(physics=RoughPhysicsCfg())
    # 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: EventsCfg = EventsCfg()
    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.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

    def play_mode(self):
        """Play-mode overrides shared by the velocity-tracking environments."""
        super().play_mode()
        # spawn the robot randomly in the grid (instead of their terrain levels)
        self.scene.terrain.max_init_terrain_level = None
        # reduce the number of terrains to save memory
        if self.scene.terrain.terrain_generator is not None:
            self.scene.terrain.terrain_generator.num_rows = 5
            self.scene.terrain.terrain_generator.num_cols = 5
            self.scene.terrain.terrain_generator.curriculum = False
        # remove random pushing events
        self.events.base_external_force_torque = None
        self.events.push_robot = None

在这里,当修改 env.decimation 或 env.sim.dt 时,用户还需要输入更新后的 env.sim.render_interval 、 env.scene.height_scanner.update_period 和 env.scene.contact_forces.update_period 。

自定义配置验证#

Configclass 对象可以定义 validate_config() 方法,在所有字段解析后执行领域相关验证。预设解析和 MISSING 字段检查成功后会自动调用该钩子,使你能尽早发现无效参数组合,并提供明确的错误信息。

例如,Franka 到达任务配置会验证 Newton IK 动作预设是否与 Newton 物理配置配合使用:

    def validate_config(self) -> None:
        """Validate the selected controller and physics backend."""
        if self.observations.policy.ee_target_error is not None and not isinstance(
            self.actions.arm_action, mdp.JointPositionActionCfg
        ):
            raise ValueError("The 'hold' preset requires the Franka joint-position action.")
        if isinstance(self.actions.arm_action, NewtonInverseKinematicsActionCfg) and not isinstance(
            self.sim.physics, NewtonCfg
        ):
            raise ValueError("The 'newton_ik' action preset requires a Newton physics preset.")

执行时机:

  1. 先检查所有 MISSING 字段;仍有缺失时抛出 TypeError 。

  2. 只有此后,才在 顶层 配置对象上调用 validate_config() 。

  3. 该钩子应抛出 ValueError ,并给出明确说明和迁移建议。

常见验证内容:

  • 独立选择的控制器、物理配置和渲染器之间的兼容性

  • 渲染器、相机数据类型和特征提取器的兼容性

  • 仅靠字段类型无法表达的数值关系或限制

预设系统#

若想从使用者角度了解如何选择物理、渲染和任务变体,请先阅读 后端与预设 。本节介绍完整的预设定义和解析行为。

预设系统允许通过一个命令行参数替换整个配置部分,或单个标量值。无需逐字段覆盖,只需选择命名预设,即可 完全替换 对应配置部分(不合并字段)。

预设通过继承 PresetCfg ,或使用便捷工厂 preset() 声明。系统自动从嵌套配置中递归发现全部预设,包括字典字段内的预设(例如 actuators )。

覆盖顺序#

实际优先级从低到高为:

  1. 默认值 :未解析的 PresetCfg 回退到各自的 default 字段。

  2. 带类型和领域选择 : physics=newton_mjwarp 选择物理配置, presets=rgb 将任务特有名称广播到所有匹配配置。

  3. 路径选择 : env.sim.physics=newton_kamino 定位一个具体的 PresetCfg ,并在该路径上优先生效。

  4. 回放模式修改 :回放命令请求时,将环境的 play_mode() 修改应用到解析后的配置。

  5. 标量覆盖 : env.sim.dt=0.001 对单个字段具有最终决定权。

如果多个广播名称在同一有效路径上选择不同选项,解析会失败,而不是静默选择其中一个。

使用 PresetCfg 定义预设#

创建 PresetCfg 子类,将每个字段定义为一个命名选项。没有命令行覆盖时,使用 default 字段指定的配置:

from isaaclab.sim import SimulationCfg
from isaaclab.utils import configclass
from isaaclab_newton.physics import NewtonCfg
from isaaclab_physx.physics import PhysxCfg
from isaaclab_tasks.utils import PresetCfg

@configclass
class PhysicsPresetsCfg(PresetCfg):
    isaacsim_physx: PhysxCfg = PhysxCfg()
    default: PhysxCfg = isaacsim_physx
    newton_mjwarp: NewtonCfg = NewtonCfg()

@configclass
class MyEnvCfg:
    sim: SimulationCfg = SimulationCfg(physics=PhysicsPresetsCfg())

物理由 SimulationCfg 管理,因此预设配置路径是 env.sim.physics 。选择后端时优先使用带类型选择器:

uv run isaaclab train --rl_library rsl_rl \
    --task Isaac-Cartpole physics=newton_mjwarp

只有明确希望替换这一个预设节点、而不选择其他匹配的任务预设时,才使用路径形式 env.sim.physics=newton_mjwarp 。

将 default 字段设为 None ,可定义默认关闭、只有显式选择才启用的可选功能:

@configclass
class CameraSettingsCfg:
    width: int = 64
    height: int = 64

@configclass
class CameraPresetCfg(PresetCfg):
    default = None
    small: CameraSettingsCfg = CameraSettingsCfg()
    large: CameraSettingsCfg = CameraSettingsCfg(width=256, height=256)

@configclass
class SceneCfg:
    camera: CameraPresetCfg = CameraPresetCfg()

此处 env.scene.camera 默认解析为 None 。使用该配置的已注册任务可以通过路径选择器 env.scene.camera=large 启用大相机。

后端与求解器预设#

物理后端选择使用同一预设系统。任务可以定义 PresetCfg ,各条目替换完整物理配置:

Cartpole 任务中的定义是一个持续维护的示例:

class CartpolePhysicsCfg(PresetCfg):
    """Physics backend presets for the cartpole environments."""

    isaacsim_physx: PhysxCfg = PhysxCfg()
    ovphysx: OvPhysxCfg = OvPhysxCfg()
    physx: PhysxAutoCfg = PhysxAutoCfg(isaacsim_physx=isaacsim_physx, ovphysx=ovphysx)
    newton_mjwarp: NewtonCfg = NewtonCfg(
        solver_cfg=MJWarpSolverCfg(
            njmax=5,
            nconmax=3,
            cone="pyramidal",
            impratio=1,
            integrator="implicitfast",
        ),
        num_substeps=1,
        debug_mode=False,
        use_cuda_graph=True,
    )
    newton_kamino: NewtonCfg = NewtonCfg(
        solver_cfg=KaminoPADMMSolverCfg(sparse_jacobian=True),
        debug_mode=False,
        use_cuda_graph=True,
    )
    default: NewtonCfg = newton_mjwarp


newton_mjwarp 和 newton_kamino 均选择 Newton 物理后端,因为两者都是 NewtonCfg 对象。区别在于求解器配置: newton_mjwarp 使用 MJWarpSolverCfg , newton_kamino 使用 KaminoPADMMSolverCfg 。

因此,Kamino 是求解器预设,不是独立的 Isaac Lab 后端。预设解析后,仍使用同一套 Newton 资产、传感器、渲染器和可视化器。它是基于近端交替方向乘子法(P-ADMM)的约束刚性多体动力学求解器。

备注

Kamino 要求资产具有兼容的模型结构。能够使用 MuJoCo-Warp 或 PhysX 预设的资产,可能仍需调整模型结构,才能使用 physics=newton_kamino。

# Preferred: select and validate a physics preset by type
uv run isaaclab train --rl_library rsl_rl \
    --task Isaac-Cartpole physics=newton_kamino

# Advanced: replace only the physics config at this path
uv run isaaclab train --rl_library rsl_rl \
    --task Isaac-Cartpole env.sim.physics=newton_kamino

后端支持范围取决于具体任务,并会随验证进展变化,以任务的 --help 输出为准。向未列出该预设的任务传入 physics=newton_kamino 会失败,不会自动为该任务添加 Kamino 配置。

通过 preset() 定义内联预设#

对于不值得单独定义完整子类的简单值(标量、列表),使用 preset() 工厂。它根据关键字参数动态创建 PresetCfg 实例:

from isaaclab_tasks.utils.hydra import preset

# Scalar preset -- no boilerplate subclass
self.scene.robot.actuators["legs"].armature = preset(
    default=0.0, isaacsim_physx=0.0, newton_mjwarp=0.01, physx=0.0
)

这会创建与 PresetCfg 子类相同的字段,default 参数必填。

preset() 适用于任意值类型,包括标量、列表,甚至配置实例:

# Resolution preset on a camera config field
width = preset(default=64, res128=128, res256=256)

# List preset for camera data types
@configclass
class DataTypeCfg(PresetCfg):
    default: list = ["rgb"]
    depth: list = ["depth"]
    albedo: list = ["albedo"]

定义可以写在一行时,使用 preset() 。选项较复杂、需要类型注解和多行排版时,使用 PresetCfg 子类。

预设系统会发现配置树中任意位置的 preset() 值,包括 actuators 等字典字段内部:

# Select MJWarp physics and all matching dependent alternatives
uv run isaaclab train --rl_library rsl_rl \
    --task IsaacContrib-Velocity-Rough-AnymalC physics=newton_mjwarp

带类型的 physics= 选择器按所选名称进行广播解析,因此具有相同名称的任务选项(例如这里的电枢惯量值)也会更新。它还验证该名称确实解析出了物理配置;自由形式的 presets= 选择器不提供这一类型检查。

带类型的预设选择器#

预设命令行层识别三种 key=value 参数(不带前导短横线),可附加到任意训练或回放脚本命令后:

参数

作用

physics=NAME

用于选择 PhysicsCfg 变体的带类型选择器

renderer=NAME

用于选择 RendererCfg 变体的带类型选择器

presets=NAME[,NAME,...]

广播:应用到配置树中每个匹配的 PresetCfg

带类型选择器采用与 presets= 相同的广播解析。因此 physics=newton_mjwarp 也可以更新具有相同名称的依赖任务预设,例如执行器或事件设置。但它们并不等价:带类型选择器必须解析出至少一个声明类型的配置,否则报错。后端选择使用 physics= 和 renderer= ,任务特有模式使用 presets= 。

常见物理预设名称 (仅当任务列出时可用):

名称

后端

isaacsim_physx

明确的 Isaac Sim PhysX 配置

physx

在已配置的选项中自动选择 PhysX 系列后端

newton_mjwarp

使用 MuJoCo-Warp 求解器的 Newton 物理配置

newton_kamino

使用 Kamino 求解器的 Newton 物理后端(部分任务支持,见 后端与求解器预设)

ovphysx

受支持的不依赖 Kit 的任务所用的明确 OvPhysX 配置

常见渲染器预设名称 (由 MultiBackendRendererCfg 提供时):

名称

渲染器

isaacsim_rtx

明确的 Isaac Sim RTX 渲染器

rtx

在已配置的选项中自动选择 RTX 系列渲染器

newton_renderer

Newton Warp 渲染器

ovrtx

受支持的不依赖 Kit 的任务所用的明确 OVRTX 渲染器

隐含的 default 字段由任务决定,并有意不在 --help 中列出。不要根据这些惯用名称推断任务默认后端,应查看帮助输出或配置。 physics=physx 和 renderer=rtx 等自动选择需显式启用,并非通用默认值。

领域预设(观测模式、相机配置等)取决于任务。向训练命令传入 --task=<task-name> --help ,可查看按选择器类型分组的全部可用任务预设。

对于强化学习任务,预设解析将已注册的环境和智能体配置组合为同级根节点。因此,库的规范 <library>_cfg_entry_point 可以返回根级 PresetCfg ,包含与环境相同名称的选项。 presets=resnet18 这样的广播会在一次解析中,在两个根节点上都选择 resnet18 :

uv run isaaclab train --rl_library rsl_rl \
     --task Isaac-Cartpole-Camera presets=resnet18

这是使依赖环境的策略形状(例如特征提取器或动作空间输出头)与所选环境保持一致的推荐方式,无需预设专属的注册条目,也无需改写 --agent 。

独立的训练方案仍通过显式选择智能体来指定。任务可以为对称性、循环网络、蒸馏或其他算法选择不同智能体,而不改变环境预设。

该模型不使用预设专属的智能体入口,也不在注册表端维护预设到智能体的映射。应使用规范入口,并通过 presets= 选择变体。对于旧版 SKRL 运行,如果其清单或目录以配置键后缀而非 agent.class 表示算法,请显式传入检查点路径,不要使用自动 latest 或 best 发现。

备注

旧别名 newton → newton_mjwarp 和 kamino → newton_kamino 仍可使用,但会发出 FutureWarning 。渲染器别名 isaacsim_rtx_renderer → isaacsim_rtx 和 ovrtx_renderer → ovrtx 也如此。请优先使用规范名称。

使用预设#

带类型选择器 — 选择物理和渲染器后端的推荐形式:

# Switch to Newton MuJoCo-Warp physics
uv run isaaclab train --rl_library rsl_rl \
    --task IsaacContrib-Velocity-Rough-AnymalC physics=newton_mjwarp

# Switch to Newton renderer for camera environments
uv run isaaclab train --rl_library rsl_rl \
    --task Isaac-Cartpole-Camera-Direct renderer=newton_renderer

# Combine typed selectors with a task-specific observation preset
uv run isaaclab train --rl_library rsl_rl \
    --task Isaac-Cartpole-Camera-Direct \
    physics=newton_mjwarp renderer=newton_renderer presets=rgb

路径预设 — 为一个配置路径选择具体预设:

# Replace only this task's physics preset node
uv run isaaclab train --rl_library rsl_rl \
    --task Isaac-Cartpole env.sim.physics=newton_kamino

领域预设 — 在所有存在该名称的位置广播任务特有选项:

# Keep the observation pipeline and camera data type in sync
uv run isaaclab train --rl_library rsl_rl \
    --task Isaac-Cartpole-Camera presets=depth

多个领域预设 — 应用多个互不冲突的任务选项:

uv run isaaclab train --rl_library rsl_rl \
    --task Isaac-Lift-KukaAllegro-Camera presets=duo_camera,rgb128

KukaAllegro 的 -Camera 任务默认使用单相机,以及与之匹配的 RSL-RL CNN actor。 presets=duo_camera 同时切换相机组合和 actor 输入;critic 继续使用状态观测。

组合使用 — 带类型选择器、领域预设和标量覆盖:

uv run isaaclab train --rl_library rsl_rl \
    --task Isaac-Cartpole-Camera \
    physics=newton_mjwarp renderer=newton_renderer presets=rgb \
    env.sim.dt=0.002

全局预设冲突检测#

如果两个全局预设都匹配同一配置路径,会抛出错误,尽早暴露歧义:

ValueError: Conflicting global presets: 'foo' and 'bar'
            both define preset for 'env.events'

实际示例#

ANYmal-C 运动环境展示了 PresetCfg 与 preset() 的配合使用:

class AnymalCRoughEnvCfg(LocomotionVelocityRoughEnvCfg):
    def __post_init__(self):
        super().__post_init__()

        # scene
        self.scene.robot = replace(ANYMAL_C_CFG, prim_path="{ENV_REGEX_NS}/Robot")

基础速度配置还为物理和质心随机化事件定义了 newton_mjwarp 选项,MJWarp 会禁用该事件。显式设置 physics=newton_mjwarp ,会解析物理配置及具有同名的所有有效依赖选项:禁用该事件,并将 ANYmal-C 执行器电枢惯量设为 0.01 。带类型选择器还会验证确实选中了物理预设。

uv run isaaclab train --rl_library rsl_rl \
    --task IsaacContrib-Velocity-Rough-AnymalC physics=newton_mjwarp

不提供选择器时,各 PresetCfg 独立使用自己的 default ;默认选项的名称不会广播到其他预设节点。

总结#

覆盖类型

语法

作用

标量

env.sim.dt=0.001

修改单个字段

路径预设

env.sim.physics=newton_kamino

替换整个配置部分

领域预设

presets=rgb

在所有匹配位置应用任务特有名称

带类型的物理选择器

physics=newton_mjwarp

选择物理变体,更新匹配的依赖预设,并要求类型匹配

带类型的渲染器选择器

renderer=newton_renderer

选择渲染器变体,并要求类型匹配

组合使用

physics=newton_mjwarp renderer=newton_renderer presets=rgb env.sim.dt=0.001

带类型选择器 + 领域预设 + 标量覆盖