go2Demo/scripts/rsl_rl/train_rsl_rl.py

184 lines
6.8 KiB
Python

# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
"""RSL-RL training logic for the unified reinforcement learning entrypoint."""
from __future__ import annotations
import argparse
import contextlib
import importlib.metadata as metadata
import logging
import os
import platform
import time
from datetime import datetime
from pathlib import Path
from common import (
add_common_train_args,
add_isaaclab_launcher_args,
apply_env_overrides,
configure_io_descriptors,
create_isaaclab_env,
dump_train_configs,
enable_cameras_for_video,
import_local_module,
set_hydra_args,
validate_distributed_device,
wrap_record_video,
)
from packaging import version
import isaaclab_tasks # noqa: F401
logger = logging.getLogger(__name__)
RSL_RL_VERSION = "5.0.1"
RL_ROOT = Path(__file__).resolve().parents[1]
CLI_ARGS = import_local_module("isaaclab_rsl_rl_cli_args", RL_ROOT / "rsl_rl" / "cli_args.py")
import go2Demo.tasks # noqa: F401
with contextlib.suppress(ImportError):
import isaaclab_tasks_experimental # noqa: F401
def _check_rsl_rl_version() -> str:
"""Check that the installed RSL-RL version is supported."""
installed_version = metadata.version("rsl-rl-lib")
if version.parse(installed_version) < version.parse(RSL_RL_VERSION):
if platform.system() == "Windows":
cmd = [r".\isaaclab.bat", "-p", "-m", "pip", "install", f"rsl-rl-lib=={RSL_RL_VERSION}"]
else:
cmd = ["./isaaclab.sh", "-p", "-m", "pip", "install", f"rsl-rl-lib=={RSL_RL_VERSION}"]
print(
f"Please install the correct version of RSL-RL.\nExisting version is: '{installed_version}'"
f" and required version is: '{RSL_RL_VERSION}'.\nTo install the correct version, run:"
f"\n\n\t{' '.join(cmd)}\n"
)
raise SystemExit(1)
return installed_version
def _parse_args(argv: list[str]) -> argparse.Namespace:
"""Parse RSL-RL training arguments."""
from isaaclab.utils.string import list_intersection, string_to_callable
from isaaclab_tasks.utils import setup_preset_cli
parser = argparse.ArgumentParser(description="Train an RL agent with RSL-RL.")
add_common_train_args(
parser,
agent_default="rsl_rl_cfg_entry_point",
agent_help="Name of the RL agent configuration entry point.",
)
parser.add_argument(
"--external_callback",
default=None,
help="Fully qualified path to an externally defined callback.",
)
CLI_ARGS.add_rsl_rl_args(parser)
add_isaaclab_launcher_args(parser)
# setup_preset_cli registers preset-selection help text + runs parse_known_args
args_cli, remaining_args = setup_preset_cli(parser, argv)
enable_cameras_for_video(args_cli)
remaining_args_env_registration = None
if args_cli.external_callback:
external_callback_function = string_to_callable(args_cli.external_callback, separator=".")
remaining_args_env_registration = external_callback_function()
# physics=/renderer=/presets= tokens pass through the remainder for hydra to parse later
set_hydra_args(list_intersection(remaining_args, remaining_args_env_registration))
return args_cli
def run(argv: list[str]) -> None:
"""Train an RSL-RL agent."""
import torch
from rsl_rl.runners import DistillationRunner, OnPolicyRunner
from isaaclab.envs import DirectMARLEnvCfg
from isaaclab_rl.rsl_rl import RslRlVecEnvWrapper, handle_deprecated_rsl_rl_cfg
from isaaclab_tasks.utils import get_checkpoint_path, launch_simulation, resolve_task_config
torch.backends.cuda.matmul.allow_tf32 = True
torch.backends.cudnn.allow_tf32 = True
torch.backends.cudnn.deterministic = False
torch.backends.cudnn.benchmark = False
args_cli = _parse_args(argv)
installed_version = _check_rsl_rl_version()
env_cfg, agent_cfg = resolve_task_config(args_cli.task, args_cli.agent)
with launch_simulation(env_cfg, args_cli):
agent_cfg = CLI_ARGS.update_rsl_rl_cfg(agent_cfg, args_cli)
apply_env_overrides(args_cli, env_cfg)
agent_cfg.max_iterations = (
args_cli.max_iterations if args_cli.max_iterations is not None else agent_cfg.max_iterations
)
agent_cfg = handle_deprecated_rsl_rl_cfg(agent_cfg, installed_version)
env_cfg.seed = agent_cfg.seed
validate_distributed_device(args_cli)
if args_cli.distributed:
global_rank = int(os.getenv("RANK", "0"))
agent_cfg.device = env_cfg.sim.device
seed = agent_cfg.seed + global_rank
env_cfg.seed = seed
agent_cfg.seed = seed
log_root_path = os.path.abspath(os.path.join("logs", "rsl_rl", agent_cfg.experiment_name))
print(f"[INFO] Logging experiment in directory: {log_root_path}")
log_dir = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
print(f"Exact experiment name requested from command line: {log_dir}")
if agent_cfg.run_name:
log_dir += f"_{agent_cfg.run_name}"
log_dir = os.path.join(log_root_path, log_dir)
configure_io_descriptors(env_cfg, args_cli, logger)
env_cfg.log_dir = log_dir
env = create_isaaclab_env(
args_cli.task,
env_cfg,
args_cli,
convert_marl_to_single_agent=isinstance(env_cfg, DirectMARLEnvCfg),
)
if agent_cfg.resume or agent_cfg.algorithm.class_name == "Distillation":
resume_path = get_checkpoint_path(log_root_path, agent_cfg.load_run, agent_cfg.load_checkpoint)
env = wrap_record_video(env, log_dir, args_cli)
start_time = time.time()
env = RslRlVecEnvWrapper(env, clip_actions=agent_cfg.clip_actions)
if agent_cfg.class_name == "OnPolicyRunner":
runner = OnPolicyRunner(env, agent_cfg.to_dict(), log_dir=log_dir, device=agent_cfg.device)
elif agent_cfg.class_name == "DistillationRunner":
runner = DistillationRunner(env, agent_cfg.to_dict(), log_dir=log_dir, device=agent_cfg.device)
else:
raise ValueError(f"Unsupported runner class: {agent_cfg.class_name}")
runner.add_git_repo_to_log(__file__)
if agent_cfg.resume or agent_cfg.algorithm.class_name == "Distillation":
print(f"[INFO]: Loading model checkpoint from: {resume_path}")
runner.load(resume_path)
dump_train_configs(log_dir, env_cfg, agent_cfg)
try:
runner.learn(num_learning_iterations=agent_cfg.max_iterations, init_at_random_ep_len=True)
print(f"Training time: {round(time.time() - start_time, 2)} seconds")
env.close()
except KeyboardInterrupt:
pass