PPO¶
PPO is the default synchronous on-policy training path. It uses
src/unilab/scripts/train_rsl_rl.py, composes from src/unilab/conf/ppo/config.yaml, and runs the
RSL-RL adapter code in uni_rl.algos.rsl_rl_ppo (unilab-rl repo) and
src/unilab/training/rsl_rl.py.
Quick Start¶
uv run train --algo ppo --task go2_joystick_flat --sim mujoco
uv run train --algo ppo --task go2_joystick_flat --sim motrix training.no_play=true
Common Overrides¶
uv run train --algo ppo --task go2_joystick_flat --sim mujoco \
algo.num_envs=2048 \
algo.max_iterations=300 \
training.no_play=true
Use uv run eval for checkpoint playback:
uv run eval --algo ppo --task go2_joystick_flat --sim mujoco --load-run -1
Logs are grouped by algo.algo_log_name; the default in src/unilab/conf/ppo/config.yaml
is rsl_rl_ppo.
Single-node multi-GPU training¶
training.devices enables RSL-RL’s synchronous data-parallel PPO path:
uv run train --algo ppo --task go2_joystick_flat --sim mujoco \
'training.devices=[0,1]' \
training.no_play=true
uv run train --algo ppo --task g1_motion_tracking --sim mujoco \
'training.devices=[0,1]' \
training.no_play=true
null or [] keeps automatic single-device selection, [d] selects one
CUDA device, and two or more entries launch one local process per listed
device. Do not set training.device and training.devices together. The
configured order is preserved, including when the parent already has
CUDA_VISIBLE_DEVICES set.
For the IsaacGym, IsaacSim, and Genesis owners, the same topology is also
applied to the simulator environment. Torchrun workers receive the local
index inside their remapped CUDA_VISIBLE_DEVICES list (for example, host
device 5 is sent as device_id=1 when the worker sees [4,5]); off-policy
workers keep the parent process’s visible index namespace. Genesis selects
its process-wide session before gs.init.
algo.num_envs is a per-rank count, not a global budget. For W ranks,
N configured envs, and rollout length T:
local samples / iteration = N * T
global samples / iteration = W * N * T
Each rank owns an independent env, policy copy, and rollout storage. Rollouts,
GAE, advantage normalization, and mini-batch shuffling stay rank-local.
RSL-RL broadcasts rank 0’s model state at startup and averages gradients after
every PPO mini-batch backward pass. Rank i uses algo.seed + i.
training.num_timesteps is interpreted as a global sample budget and therefore
uses W * N * T when deriving the iteration count.
Only rank 0 writes TensorBoard/W&B data, checkpoints, run_config.json, and
run_summary.json, then optionally enters playback after all ranks have closed
their process group. run_summary.json records world_size, per-rank/global
env counts, samples per iteration, and aggregate training throughput. RSL-RL’s
Perf/total_fps is also an aggregate global samples/s metric; reward and episode
statistics remain rank-0-local.
RSL-RL does not synchronize observation-normalizer buffers or environment curriculum state after startup. Consequently, tasks with empirical normalization (including the current Go2 flat owner) keep rank-local statistics, and the checkpoint contains rank 0’s copy. This is the upstream RSL-RL distributed semantic, not global-rollout PPO.
The integrated launcher is single-node only. The repository has two-GPU MuJoCo
smoke coverage for go2_joystick_flat and g1_motion_tracking; this does not
claim multi-node or Motrix multi-GPU support. On the currently validated RTX
6000D host, the launcher inherits the production NCCL compatibility defaults
NCCL_P2P_DISABLE=1 and NCCL_SHM_DISABLE=1; explicit environment values win.