目次
初めに
前回の記事でUnitree Go2の学習環境を整えたので、どのようにコードを変更していけばいいかを説明していきたいと思います。
そもそも何を変更すればいいの?
基本的にIsaacLabでは、
python/scripts/skrl/train.py --task=$YOUR_TASK #訓練
python/scripts/skrl/play.py --task=$YOUR_TASK #プレイ
の二つのスクリプトを使用するのですが、この二つのコードを直接いじるわけではない点にまず注意が必要です。
train.pyの中身の詳細
@hydra_task_config(args_cli.task, agent_cfg_entry_point)
def main(env_cfg: ManagerBasedRLEnvCfg | DirectRLEnvCfg | DirectMARLEnvCfg, agent_cfg: dict):
"""Train with skrl agent."""
# override configurations with non-hydra CLI arguments
env_cfg.scene.num_envs = args_cli.num_envs if args_cli.num_envs is not None else env_cfg.scene.num_envs
env_cfg.sim.device = args_cli.device if args_cli.device is not None else env_cfg.sim.device
# check for invalid combination of CPU device with distributed training
if args_cli.distributed and args_cli.device is not None and "cpu" in args_cli.device:
raise ValueError(
"Distributed training is not supported when using CPU device. "
"Please use GPU device (e.g., --device cuda) for distributed training."
)
# multi-gpu training config
if args_cli.distributed:
env_cfg.sim.device = f"cuda:{app_launcher.local_rank}"
# max iterations for training
if args_cli.max_iterations:
agent_cfg["trainer"]["timesteps"] = args_cli.max_iterations * agent_cfg["agent"]["rollouts"]
agent_cfg["trainer"]["close_environment_at_exit"] = False
# configure the ML framework into the global skrl variable
if args_cli.ml_framework.startswith("jax"):
skrl.config.jax.backend = "jax" if args_cli.ml_framework == "jax" else "numpy"
# randomly sample a seed if seed = -1
if args_cli.seed == -1:
args_cli.seed = random.randint(0, 10000)
# set the agent and environment seed from command line
# note: certain randomization occur in the environment initialization so we set the seed here
agent_cfg["seed"] = args_cli.seed if args_cli.seed is not None else agent_cfg["seed"]
env_cfg.seed = agent_cfg["seed"]
# specify directory for logging experiments
log_root_path = os.path.join("logs", "skrl", agent_cfg["agent"]["experiment"]["directory"])
log_root_path = os.path.abspath(log_root_path)
print(f"[INFO] Logging experiment in directory: {log_root_path}")
# specify directory for logging runs: {time-stamp}_{run_name}
log_dir = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + f"_{algorithm}_{args_cli.ml_framework}"
# The Ray Tune workflow extracts experiment name using the logging line below, hence, do not change it (see PR #2346, comment-2819298849)
print(f"Exact experiment name requested from command line: {log_dir}")
if agent_cfg["agent"]["experiment"]["experiment_name"]:
log_dir += f'_{agent_cfg["agent"]["experiment"]["experiment_name"]}'
# set directory into agent config
agent_cfg["agent"]["experiment"]["directory"] = log_root_path
agent_cfg["agent"]["experiment"]["experiment_name"] = log_dir
# update log_dir
log_dir = os.path.join(log_root_path, log_dir)
# dump the configuration into log-directory
dump_yaml(os.path.join(log_dir, "params", "env.yaml"), env_cfg)
dump_yaml(os.path.join(log_dir, "params", "agent.yaml"), agent_cfg)
# get checkpoint path (to resume training)
resume_path = retrieve_file_path(args_cli.checkpoint) if args_cli.checkpoint else None
# set the IO descriptors export flag if requested
if isinstance(env_cfg, ManagerBasedRLEnvCfg):
env_cfg.export_io_descriptors = args_cli.export_io_descriptors
else:
omni.log.warn(
"IO descriptors are only supported for manager based RL environments. No IO descriptors will be exported."
)
# set the log directory for the environment (works for all environment types)
env_cfg.log_dir = log_dir
# create isaac environment
env = gym.make(args_cli.task, cfg=env_cfg, render_mode="rgb_array" if args_cli.video else None)
# convert to single-agent instance if required by the RL algorithm
if isinstance(env.unwrapped, DirectMARLEnv) and algorithm in ["ppo"]:
env = multi_agent_to_single_agent(env)
# wrap for video recording
if args_cli.video:
video_kwargs = {
"video_folder": os.path.join(log_dir, "videos", "train"),
"step_trigger": lambda step: step % args_cli.video_interval == 0,
"video_length": args_cli.video_length,
"disable_logger": True,
}
print("[INFO] Recording videos during training.")
print_dict(video_kwargs, nesting=4)
env = gym.wrappers.RecordVideo(env, **video_kwargs)
# wrap around environment for skrl
env = SkrlVecEnvWrapper(env, ml_framework=args_cli.ml_framework) # same as: `wrap_env(env, wrapper="auto")`
# configure and instantiate the skrl runner
# https://skrl.readthedocs.io/en/latest/api/utils/runner.html
runner = Runner(env, agent_cfg)
# load checkpoint (if specified)
if resume_path:
print(f"[INFO] Loading model checkpoint from: {resume_path}")
runner.agent.load(resume_path)
# run training
runner.run()
# close the simulator
env.close()
if __name__ == "__main__":
# run the main function
main()
# close sim app
simulation_app.close()
チュートリアルやウォークスルーで紹介されていたフルスクラッチな実装とは異なり、train.pyはDI的なことをしているだけです。具体的には、args_cli.task及びagent_cfg_entry_pointを注入しています。前者のargs_cli.taskは当然--taskオプションで指定したものですが、後者に関しては、そんなもの指定した覚えがありません。
# config shortcuts
if args_cli.agent is None:
algorithm = args_cli.algorithm.lower()
agent_cfg_entry_point = "skrl_cfg_entry_point" if algorithm in ["ppo"] else f"skrl_{algorithm}_cfg_entry_point"
上に行くとこんなことが書いてあります。hydraの説明を読んでいただくとわかりやすいですが、env_cfgのskrl_cfg_entry_pointを読みに行くということですね。
一旦、
train.pyの記述から、
#source/disr_inc_lab/disr_inc_lab/tasks/manager_based/disr_inc_lab/__init__.py
import gymnasium as gym
from . import agents
##
# Register Gym environments.
##
gym.register(
id="Template-Disr-Inc-Lab-v0",
entry_point="isaaclab.envs:ManagerBasedRLEnv",
disable_env_checker=True,
kwargs={
"env_cfg_entry_point": f"{__name__}.disr_inc_lab_env_cfg:DisrIncLabEnvCfg",
"skrl_cfg_entry_point": f"{agents.__name__}:skrl_cfg.yaml",
},
)
にある、disr_inc_lab_env_cfg:DisrIncLabEnvCfg及びskrl_cfg.yamlの二つの設定ファイルを変更すれば良いということがわかりました。
skrl_cfg.yamlの方はただのskrl向けのパラメタ群なのでまずは使い回しでいいとして、報酬関数などの設定を行うConfigについて解説していきます。
以降は、実際にどうやって設定をすればうまく動くかをここからは、Isaac-Velocity-Flat-Unitree-Go1-v0の設定に倣って見ていきます!
Configの設定のしかた
IsaacLabのConfigでは、強化学習のパラメタ以外の部分を主に設定します。
Isaac-Velocity-Flat-Unitree-Go1-v0の大元の継承元であるLocomotionVelocityRoughEnvCfgのコードを見てみましょう。実際に自分のロボットを学習させるときも、このクラスを継承させた上で微調整する形が基本になります。
強化学習フローのイメージ
Configの前に、IsaacLabの基本方針を説明しておきます。
基本的にニューラルネットワークの流れをイメージしていただければOKです。
ニューラルネットワークでは、基本的に以下のフローで学習を行います。

他のCfgはこれらを定義するための前準備です。ただ、特徴的な要素として終了条件(TerminationCfg)があります。
それぞれのCfgの説明
InteractiveSceneCfg
強化学習環境に配置する地形やロボットなどの情報を記述します。
LocomotionVelocityRoughEnvCfgでは、高低差のある地形やRayCaster(下方向への赤外線センサの装着による地面のセンシング)などを設定していますね。
Unityをやったことがある方であれば、Hierarchyのアイテム群+Inspectorの重力アタッチなどをここでやっていると思っていただければいいと思います。

(↑の部分をプログラムで追加してる感じです!)
後でこれらのデータをObservationsCfgに入れて使います。
ObservationsCfg
ニューラルネットでいうところの入力層に該当します。
LocomotionVelocityRoughEnvCfgでは、各ジョイントの座標や速度を入力していますね。非常に大事なこととして、ObservationsCfgを変化させると、ニューラルネットの形が変化する
ため、前の学習済みの重みをロードできなくなるという点が挙げられます。
RewardsCfg
ニューラルネットでいうところの損失関数計算の仕組みを定義しています。LocomotionVelocityRoughEnvCfgでは、方向の是非、転倒時のペナルティなどを入れていますね。こちらの方はいじったところで損失関数そのもののサイズが変化しないので前の学習済みの重みをロード可能です。
基本的にはこの二つが主役なのですが、他にも色々設定できる条件があります。
TerminationCfg
ロボットの学習状況によっては、ちょっとこれ以上動かしても意味ないなみたいな状況があります。

(↑のように転んでしまうともう立ち上がるのは厳しいです)

(↑のロボットはもう歩けそうにないですね...)
学習の邪魔になるこのようなロボットを消してしまうというのがこのTerminationCfgです。LocomotionVelocityRoughEnvCfgでは、ロボットが倒れてしまった場合などに設定されます。
CurriculumCfg
ロボットを段差のある場所で歩かせる場合などでは、まずロボットに平地での歩き方を教えた上で段階的にがたついた足場での学習に移行させるというようなことを行います。これをカリキュラム学習というのですが、設定を手動でいじって何度も学習させるのはめんどくさいので、学習途中で自動的に移行するような仕組みが用意されています。
後のCfgは運動やイベントの定義などなので、基本的にはこれらの設定をもとに理解を進めるのが良いと思います。
終わりに
ここまでで基本的な強化学習の設定手法が理解できてきたので、いよいよ実際にUnitree Go2を強化学習していきたいと思います!
前回の記事
この記事はIsaac Lab 2025】コードベースで読み解くUnitree Go2強化学習の実装と理解:準備編の続きです!よろしければこちらもご覧ください。
