Training Runs¶
This page covers training a task with eden train, replaying a checkpoint with eden inference, and what a run
leaves on disk: the run directory, checkpoints, the progress file, seeding and logging. It ends with how to plug in an
RL algorithm or runner of your own. Read it when you train a task for the first time, when you resume or replay a
run, or when a run behaves in a way you did not expect.
eden train drives two RL libraries: rsl_rl (rsl-rl-lib, the default)
and rl_games. To train with another library (stable-baselines3, skrl, CleanRL) see
Using Eden with Another RL Library; to train on several GPUs see
Multi-GPU Training.

Train a task¶
Every registered task with runner_options trains from the command line:
eden list # the registered tasks
eden train --task reacher # train with the task's defaults
eden train --task reacher --num_envs 1024 # fewer parallel envs
eden train --task velocity_tracking_flat --run_name lower_lr \
--override "runner_options: {algorithm: {learning_rate: 3.0e-4}}"
A task may add flags of its own (its TaskMods); eden train --task <name> --help lists them. For
example, move_forward exposes --runner rl_games to train with rl_games instead of rsl_rl.
| Flag | What it does |
|---|---|
--task TASK |
The registered task to train. Required. |
--num_envs N |
Replace the task's env_options.num_envs. Under DDP this is the count per GPU. |
--config PATH |
A .json / .yaml config file. A config Eden saved (one that carries its class) replaces the task's config; any other file is a partial override layered on it. |
--override YAML |
An inline YAML mapping merged into the config, for example 'env_options: {num_envs: 64}'. Repeatable; later ones win; applied after --config. |
--checkpoint PATH |
Load these weights before training. |
--resume REF |
Continue from an earlier run of this task (see Resume a run). Mutually exclusive with --checkpoint. |
--run_name NAME |
Folded into the run directory name and used as the wandb run name. |
--logger {tensorboard,neptune,wandb} |
The rsl_rl logger. Default tensorboard. Ignored for rl_games. |
--wandb_group GROUP |
The wandb group for this run (default: the task name). Ignored unless --logger wandb. |
--cpu |
Run on the CPU backend. |
eden train picks the library from the type of the task's runner_options: an
RlGamesPpoRunnerOptions trains with rl_games, anything else with rsl_rl. A task whose runner_options is None
has its learner outside Eden, and eden train exits with a message that points at the task's standalone example.
Check a task before a long run
eden smoke --task <name> builds the task with two envs and steps it twice. It catches a broken config in
seconds, before a training run spends minutes building thousands of envs. eden smoke --task <name> --profile
measures what each term costs per step and writes term_cost.json.
What is checked before the build¶
A scene with thousands of envs can take minutes to build, so eden train checks the learner first and exits before
anything is built or written when:
runner_options.class_namenames a runner that cannot be imported, lacks the runner interface, or cannot train under the current distributed launch;- a model or algorithm
class_namegiven as an import path does not resolve; - the algorithm class does not accept the fields its options carry (see Custom algorithms);
- the runner needs a checkpoint to start (a distillation needs its teacher) and you passed neither
--checkpointnor--resume; - the algorithm options define a
preflight()and it fails (AMP-PPO loads its expert clips there).
The run directory¶
Each run writes into its own directory:
logs/<task>/<timestamp>[-<run_name>]-<run id>/
├── config.json # the full config the run trained with
├── run.json # provenance: versions, seed, world size, argv, parent run
├── progress.json # a small status snapshot, refreshed every iteration
├── model_<iteration>.pt
└── events.out.tfevents.* # TensorBoard (with --logger tensorboard)
The timestamp sorts chronologically (for example 26Nov10T141532), and the run id is a random 8-character string
that keeps two runs started in the same second apart. --run_name is sanitized and placed between them.
config.json is the source of truth for the run: eden inference, eden export and eden deploy rebuild the env
from the config.json next to a checkpoint, not from the task's current defaults. Keep it, and run.json, next to
the .pt when you copy a checkpoint elsewhere.
The directory is created on first use
en.init() only resolves the run directory; the first read of en.log_dir (or en.get_log_dir()) creates
it. A script that never logs anything leaves no empty directory behind. If you look up "my newest run" with
something like max(glob.glob("logs/<task>/*"), key=os.path.getmtime), do that glob before your script
reads en.log_dir, or the glob finds the empty directory of the run you just started.
run.json¶
run.json records what you need to reproduce or audit the run: run_id, run_name, timestamp, log_dir, task,
the base seed, world_size, the command line (argv), resumed_from (the parent run of a --resume), the Eden and
Genesis versions and commits (eden, genesis), and the RL library that wrote the checkpoints (rl_library:
{backend, distribution, version}). It is written by the main process only, and a failure to write it warns instead
of stopping the run.
progress.json¶
Every rsl_rl run also writes progress.json, an atomically updated snapshot that a script or a coding agent can
poll far more cheaply than it can tail the training log:
{"status": "running", "iteration": 42, "total_iterations": 1500,
"total_timesteps": 4128768, "mean_reward": 12.7, "mean_episode_length": 480.2,
"best_mean_reward": 12.9, "elapsed_s": 613.4, "updated_at": 1786781380.82}
status is "running" while training and "completed" once learn() returns normally. updated_at is wall-clock
epoch seconds, so a poller can tell a finished run ("completed") from a stalled or killed one (still "running"
with a stale updated_at: a hard stop never reaches the final write), and compute progress from iteration /
total_iterations. The file is written only by rank 0 and never by an evaluation runner.
A FlashSAC run (RslRlFlashSacRunnerOptions) refreshes the file once per log line, every log_interval iterations,
and its "running" snapshots trail slightly: total_timesteps and elapsed_s leave out the latest window's
iterations but one. The "completed" snapshot is exact.
Keeping only the newest checkpoints¶
rsl_rl saves model_<iteration>.pt every save_interval iterations and once more at the end. A long run at a short
interval would hold hundreds of them, so Eden deletes the older ones after each save and keeps the newest
runner_options.keep_last_checkpoints (default 1, which is all --resume needs). To keep every checkpoint, for a
learning-curve sweep say, pass None:
Details that matter when you rely on it:
- Only checkpoints of an earlier iteration than the one just saved are deleted. A later one, left in a reused
directory or from before a rollback, is kept and reported once, because
--resumewould pick it. - A save to any other file name (an export, say) prunes nothing. Checkpoints already uploaded to wandb stay there.
- While wandb or neptune uploads a checkpoint in the background, one extra checkpoint is kept. With wandb it goes when
learn()returns and the wandb run has finished; with neptune, or under rsl-rl-lib 3, nothing signals the end of the upload and the extra checkpoint stays. - rl_games (
RlGamesPpoRunnerOptions) takes the same option. rl_games writesnn/last_<name>_ep_<epoch>_rew_<reward>.ptheverysave_frequencyepochs and never deletes one, so Eden prunes those the same way. Its best-reward checkpointnn/<name>.pthis never deleted.
Loggers¶
eden train logs to TensorBoard unless you pass --logger wandb or --logger neptune. The runner options default
to logger="wandb", so a training script that builds the runner itself logs to wandb unless it sets the field;
eden inference and eden export always force TensorBoard so a replay never creates a wandb run.
With wandb, runs go to the project runner_options.wandb_project (default "eden") and are grouped by task, or by
--wandb_group to compare the arms of an ablation across tasks. The group is passed through the WANDB_RUN_GROUP
environment variable, and a value you exported yourself wins.
Resume a run¶
--resume REF continues a run of the same task. REF is resolved under logs/<task>/:
latest: the most recently modified run directory;- a run id: the trailing 8-character segment of a run directory's name;
- any other string: a substring of the directory name, such as part of a
--run_name.
A typo or an ambiguous substring fails before anything is built, and the error lists the runs it found. The resumed
run loads the newest model_<iteration>.pt of that directory and writes into a new run directory, whose run.json
names the parent in resumed_from. The old run's directory, TensorBoard events and wandb run are left alone.
eden train --task velocity_tracking_flat --resume latest
eden train --task velocity_tracking_flat --resume lower_lr # by run_name
--checkpoint PATH also loads weights before training, from any file, without the run lookup.
Replay a checkpoint¶
eden inference --task reacher --checkpoint logs/reacher/<run>/model_1500.pt --vis
eden inference --task reacher --checkpoint <ckpt> --num_envs 64 --episodes 200 # evaluate metrics
eden inference --task reacher --checkpoint <ckpt> --rec # record an mp4
eden inference --task reacher --checkpoint <ckpt> --async # deployment-style timing
eden inference rebuilds the env from the config.json next to the checkpoint, so the replay runs the exact config
the checkpoint trained with. --config (a partial one) and --override still apply on top. Three consequences:
- Task-mod flags are refused when a sibling
config.jsonexists: the saved config is authoritative and the flags would be silently ignored. Drop them, or pass a saved config to--configto use your own. --taskis only a label for a replay. If the saved config belongs to another task, the run is logged under that task'slogs/<task>/and Eden warns; re-run with the right--taskto silence it.- Fields that only speed up or instrument training (
EnvOptions.training_only_fields, such ascuda_graph_options) are reset to their defaults first, so a checkpoint trained on a GPU host replays on a host that cannot use them.
A checkpoint with no config.json beside it is replayed on the task's current config, rebuilt from --task and any
task-mod flags.
| Flag | What it does |
|---|---|
--checkpoint PATH |
The checkpoint to replay. Required unless you pass --policy. |
--num_envs N |
Parallel evaluation envs (default 1). |
--steps N |
Stop after N env steps (default: one episode, max_episode_length). |
--episodes N |
Run until each env has finished its first ceil(N / num_envs) episodes, then print the mean of every metric over them. |
--vis |
Open the Genesis viewer. |
--rec |
Add a rec camera and save an mp4 under the replay's own run directory. |
--async (--sim2sim) |
Run inference on a background thread with the sim paced to wall-clock dt, repeating the last action when inference lags, as eden deploy does. Reports stale steps, overruns and the real-time factor. |
--policy NAME |
Roll out a frozen policy from the policy zoo instead of a checkpoint. |
The checkpoint's library is detected from its keys: an rl_games checkpoint for a task configured for rsl_rl (or the
reverse) exits with a message naming the task-mod flag that selects the other library, rather than failing inside
load.
--episodes counts each env's first episodes rather than stopping at the N-th reset overall, because stopping early
would leave out the longest episodes still running and bias a metric such as success rate. Episodes in which Genesis
flagged the state as corrupt count toward the cap but not toward the means.
Train from a script¶
eden train is a thin layer over three calls you can make yourself:
import eden as en # import eden before genesis and torch (see Multi-GPU Training)
import genesis as gs
from eden.envs.wrappers.rsl_rl_env import RslRlVecEnvWrapper, make_rsl_rl_runner
from eden.tasks import TASK_REGISTRY
en.init(backend=gs.gpu, log_root_path="logs/reacher", performance_mode=True)
config = TASK_REGISTRY.build("reacher")
config.env_options.num_envs = 4096
config.runner_options.logger = "tensorboard" # the options default to wandb
config.save_as_json() # writes config.json into en.log_dir
env = RslRlVecEnvWrapper.from_config(config) # seeds, builds and resets the env
runner = make_rsl_rl_runner(env) # Eden's runner: retention, progress.json, DDP
runner.learn(num_learning_iterations=config.runner_options.max_iterations, init_at_random_ep_len=True)
RslRlVecEnvWrapper.from_config builds and resets the env, unlike RLEnvBase.from_config, which only constructs it.
Prefer make_rsl_rl_runner(env, checkpoint=...) to constructing rsl_rl's OnPolicyRunner directly: it builds the
runner runner_options.class_name names (the DDP variant under torchrun), adds checkpoint retention, the progress
file and the agent log theme, and loads a checkpoint across rsl-rl-lib versions. For a replay, pass
for_inference=True, build the env with eval_mode=True, and call runner.get_inference_policy(device=env.device).
examples/projects/reaching/reacher.py is a complete train-and-replay script.
Seeding¶
RslRlVecEnvWrapper.from_config and RlGamesVecEnvWrapper.from_config apply runner_options.seed (default 7100)
before constructing the env, so the scene build, the first reset and every domain-randomization draw come from
the seeded RNGs. rsl-rl-lib never applies the field itself.
- Under DDP, rank
rusesseed + r, so ranks sample different randomization instead of replaying rank 0.seedstays the base: the applied value is logged and returned, never written back.config.jsonandrun.jsonrecord the base, andrun.json'sworld_sizepins the rest. - Do not call
set_random_seed()around a wrapper'sfrom_config(): the wrapper overwrites it with the configured seed. Setconfig.runner_options.seedinstead. - Seeding is process-global. Building a second env mid-run restarts the RNG stream the first one draws from. Pass
apply_seed=Falsetofrom_configfor a caller that must not disturb it (hardware deployment does). - If you build the raw env yourself (
RLEnvBase.from_config(cfg)andbuild()) and wrap it by hand, calleden.utils.random.apply_run_seed(cfg.runner_options.seed)first; nothing else on that path will. - Seeds are non-negative. A negative seed is rejected when the config loads.
Checkpoints need a matching rsl-rl-lib¶
The layout of a .pt file belongs to rsl-rl-lib, not to Eden: rsl-rl-lib 3.x saves one model_state_dict, while
4.x and 5.x split it into actor_state_dict and critic_state_dict. Eden's dependency (rsl-rl-lib>=3.0) admits both,
so a checkpoint may not replay under the rsl-rl-lib you have installed.
Eden handles the two directions differently:
- A 3.x checkpoint under 4.x/5.x is converted: the file is rewritten into a
<name>.<std_type>.converted.ptsibling and loaded from there (your file is never modified). This also covers aDistillationRunner. The conversion needs the destination'sstd_type, read from the runner'sactor(elseteacher, elsestudent) options; a runner config that states none raises instead of guessing. - A 4.x/5.x checkpoint under 3.x cannot load. The error names both versions and the keys the file holds, instead
of rsl_rl's bare
KeyError: 'model_state_dict'.
Before loading, Eden reads the checkpoint's sibling run.json (rl_library) and warns when the version that trained
it differs from the installed one. A checkpoint copied out of its run directory loses that record, so move run.json
along with the .pt.
Console output: the human and agent log themes¶
Eden renders its own output, and Genesis', in one of two themes. agent is the default, on a terminal too,
because Eden's console output is read out of files, CI logs and a model's context window more often than watched:
human |
agent |
|
|---|---|---|
| ANSI color | yes | none |
| Greeting box | yes | skipped |
| Line prefix | [Eden 🍏] [12:17:11] [INFO] |
[Eden 12:17:11]; the level is named only when it is not INFO |
| Emoji in messages | yes | stripped (status marks such as ✓ / ✕ are kept) |
Tables (manager summaries, eden list) |
boxed | a Title: col \| col header and one line per row |
| rsl_rl per-iteration block | rsl_rl's own layout | [it 12/3000] total_steps=... reward=..., then one line per Episode_Reward / Episode_Termination / ... group, every number kept |
--help and CLI color |
yes | none |
agent removes layout, never content. A third setting, auto, picks human on a terminal and agent through a
pipe, honoring NO_COLOR and FORCE_COLOR.
EDEN_LOG_THEME=human python train.py # color for the whole process tree
eden --log-theme human train --task reacher # one command; the flag goes before the subcommand
en.init(logger_theme=...) also exports EDEN_LOG_THEME, so the help formatters and every subprocess (a DDP worker,
a spawned viewer) follow it. It sets Genesis' theme too; to choose a different Genesis theme, assign
genesis.styles.style.theme after en.init().
Runner options¶
The task config's runner_options describes the learner. For rsl_rl the usual class is RslRlOnPolicyRunnerOptions
(from eden.options.learning.rsl_rl import ...), with actor / critic model options and an algorithm
(RslRlPpoAlgorithmOptions). The fields you most often touch, all on RslRlBaseRunnerOptions:
| Field | Default | Meaning |
|---|---|---|
seed |
7100 |
Base seed (see Seeding). |
device |
"auto" |
The learner's device; "auto" follows the Genesis backend. |
num_steps_per_env |
24 |
Rollout length per env per iteration. |
max_iterations |
30000 |
Iterations eden train runs. |
obs_groups |
{} |
Which observation groups feed "actor" and "critic" (and optionally "rnd_state"). |
clip_actions |
None |
Clamp actions to [-clip_actions, clip_actions]; must be finite and positive, or None. |
save_interval |
500 |
Iterations between checkpoints. |
keep_last_checkpoints |
1 |
Newest checkpoints kept on disk; None keeps all. |
logger |
"wandb" |
"tensorboard", "neptune" or "wandb"; eden train --logger overrides it. |
wandb_project / neptune_project |
"eden" |
Project names for the two hosted loggers. |
rl_games uses RlGamesPpoRunnerOptions (eden.options.learning.rl_games), with its own names (max_epochs,
save_frequency, horizon_length, network, …) and the same seed, clip_actions and keep_last_checkpoints.
Install it with pip install 'eden-world[rl-games]' (or uv sync --inexact --extra rl-games in a checkout).
How these options fit into a task config is covered in Task Configuration.
Custom algorithms: algorithm.class_name¶
rsl_rl 5.x resolves the algorithm class from a string, so a task can train with its own PPO variant without forking rsl_rl or touching Eden's runner code:
algorithm=RslRlPpoAlgorithmOptions(
class_name="my_package.trainers:MyPPO", # "module.path:ClassName"; default "PPO"
..., # the usual PPO fields still apply
)
The string is resolved when the runner is built, so the module must be importable in every process that builds
the runner: the saved config.json names it the same way, so eden train --resume, eden inference and --config
must import it too.
Where an algorithm lives¶
An algorithm is not part of a task: a task defines the problem, and the algorithm its paper used is one way to solve
it. An algorithm therefore lives in eden/learning/wrappers/<library>/<algorithm>/, written against no particular
task, and a task selects it from its config:
- The algorithm takes the task's pieces as options. Whatever ties it to one observation layout (a mirror function, which group carries a privileged target) is a field of its options class, not a constant in its code.
- The task owns those pieces, next to its config (
eden/tasks/homie/symmetry.pyholds HOMIE's mirror). - The task's config names the algorithm its reference used, so dropping it is a visible config change.
examples/holds scripts only, never code a saved config imports: a path intoexamples/resolves only when that directory is onsys.path, soeden train --resumeandeden inferencecould not load the config.
Each algorithm package ships an options class whose class_name defaults to its implementation, so a task selects it
by using that class:
from eden.learning.wrappers.rsl_rl.him import HIMPPOAlgorithmOptions
algorithm=HIMPPOAlgorithmOptions(
data_augmentation_func="eden.tasks.homie.symmetry:mirror_observations_and_actions",
...,
)
The algorithms that ship with Eden (API reference: eden.learning):
| Options class | Package | Replaces | Used by |
|---|---|---|---|
HIMPPOAlgorithmOptions |
eden.learning.wrappers.rsl_rl.him |
algorithm (HIMLoco: history estimator, symmetry losses) |
homie |
RslRlAmpPpoAlgorithmOptions |
eden.learning.wrappers.rsl_rl.amp_ppo |
algorithm (PPO plus an adversarial motion prior reward) |
husky |
RslRlRmaActorOptions, RslRlRmaPpoAlgorithmOptions |
eden.learning.wrappers.rsl_rl.rma |
actor, algorithm (RMA teacher) |
extreme_parkour_teacher |
RslRlRmaDepthDistillationRunnerOptions |
eden.learning.wrappers.rsl_rl.rma |
runner_options (depth-student distillation) |
extreme_parkour_student |
RslRlSimBaActorOptions, RslRlSimBaCriticOptions |
eden.learning.wrappers.rsl_rl.simba |
actor, critic (SimBaV2) |
weave_hoi |
RslRlMuonPpoAlgorithmOptions |
eden.learning.wrappers.rsl_rl.muon_ppo |
algorithm (Muon + AdamW optimizers) |
weave_hoi |
RslRlFlashSacRunnerOptions |
eden.learning.wrappers.rsl_rl.flashsac |
runner_options (off-policy FlashSAC) |
flashdexretarget |
RslRlContrackRunnerOptions |
eden.learning.wrappers.rsl_rl_contrack |
runner_options (constrained-MDP PPO, external fork) |
contrack |
FlashSAC's backend is not on PyPI; in a checkout install it with
uv sync --inexact --extra flashsac --group flashsac-git. The ConTrack runner needs its rsl_rl fork, which the
eden.learning.wrappers.rsl_rl_contrack module docstring names.
What the runner checks and calls¶
The class need not subclass rsl_rl's PPO: the runner calls only its construct_algorithm(obs, env, cfg, device) and
the rollout, update, save and load methods. HIMPPO brings its own actor-critic and rollout storage that way.
Before it builds the env, eden train imports every class_name given as an import path and checks that the
algorithm class accepts the fields its options carry. Changing class_name alone (say, to "PPO" on
RslRlAmpPpoAlgorithmOptions) is refused, because the options' extra fields would reach a class that does not take
them: give the runner the options class made for the algorithm. The check covers subclasses of rsl_rl's PPO and
Distillation; a class with its own construct_algorithm (HIMPPO) reads and checks its fields there.
Optional hooks Eden reads off these classes:
preflight()on the algorithm options runs at that same pre-build check.for_inference()on the algorithm options returns the options to replay a checkpoint with:eden inference,eden deployandmake_rsl_rl_runner(..., for_inference=True)use it. AMP-PPO returns stock PPO, so its discriminator, clips and replay buffer are never built for a replay.distributed_unsupportedon the algorithm class, a message: undertorchrun,eden trainexits with it before the build (RmaPPO). An algorithm that does train under DDP extends rsl_rl's parameter broadcast and gradient reduction to its own modules (AmpPPOsyncs its discriminator).adapt_runner_dict(runner_dict, major)on the algorithm options runs on the runner dict after Eden translates it for the installed rsl-rl-lib major version. Eden's translation knows only rsl_rl's own models, so an algorithm whose construction differs adapts its own entries here.
Across rsl-rl-lib versions
rsl-rl-lib 4 and 5 build every algorithm through construct_algorithm; 3 builds the model from
policy.class_name and calls AlgClass(model, storage, device=..., **alg_cfg). HIM covers 3 with two factories
its adapt_runner_dict routes to (HIMActorCritic.from_rsl_rl_v3, HIMPPO.from_rsl_rl_v3). AMP-PPO and RMA need
rsl-rl-lib 5.5.1 or newer. To check another major version without changing your environment:
uv run --with rsl-rl-lib==3.3.0 pytest tests/learning/wrappers/rsl_rl/him/test_ppo.py.
Custom runners: runner_options.class_name¶
When the training loop itself differs (a distillation that backpropagates through the rollout, a fork of rsl_rl
with its own runner), set the runner options' class_name to an import path. eden train and eden inference then
build that class instead of Eden's OnPolicyRunner / DistillationRunner:
- It is called as
cls(env, runner_dict, log_dir=..., device=...)and must providelearn,loadandget_inference_policy. It composes Eden's runner mixins (checkpoint retention, progress file) itself; they are listed ineden.envs.wrappers.rsl_rl_env.EDEN_RUNNER_MIXINS. - A
checkpoint_requiredmessage on the class makeseden trainexit before anything is written when neither--checkpointnor--resumeis given. - Under a distributed launch it must compose
DDPRunnerMixin, or it is refused. - A bare
class_nameother than"OnPolicyRunner"/"DistillationRunner"is an error, never a fallback to the stock runner. Write an import path with a colon:"module.path:ClassName". eden deployloads checkpoints into rsl_rl's stockOnPolicyRunner, so it refuses a task whose runner is named by import path; replay those checkpoints witheden inference.
Examples: RslRlRmaDepthDistillationRunnerOptions (extreme_parkour_student) and RslRlContrackRunnerOptions
(contrack).
Data only the algorithm sees¶
If the algorithm needs data the actor and critic must not see, publish it as an extra observation group and leave
that group out of obs_groups:
runner_options = RslRlOnPolicyRunnerOptions(
obs_groups={"actor": ["policy"], "critic": ["critic"]}, # the extra group is routed to neither model
...
)
The full observation TensorDict, extra groups included, reaches the algorithm's process_env_step; rsl_rl's own RND
extension reads its rnd_state group the same way. Worked example: the husky task publishes an amp group (a joint
position history window plus a phase flag) that only the AMP discriminator reads (eden/tasks/husky/config.py and
eden/learning/wrappers/rsl_rl/amp_ppo/).
Training dynamics that look like bugs¶
Two behaviors have cost real debugging time in ports because they look like bugs and are not:
- Early collapse to one-step episodes. On tasks with per-step action penalties and cheap terminations, PPO can briefly learn to terminate immediately, because ending the episode beats paying the penalties while flailing at the initial action noise. It recovers on its own as the policy improves. Give a fresh run a few hundred iterations before you debug the MDP.
- Contact-rich rollouts can differ between runs at a fixed seed. GPU contact-solver atomics can reorder floating-point sums between runs, and chaotic contacts (rough terrain especially) amplify the difference. Judge a terrain policy on statistics over many episodes and seeds, not on one rollout that differs from the last.
See also¶
- Task Configuration: where
runner_optionssits in a task config - Using Eden with Another RL Library: gymnasium, stable-baselines3, skrl, CleanRL
- Multi-GPU Training:
torchrunand SLURM - Exporting a Policy: ONNX / TorchScript for your own runtime
- Deployment: running a checkpoint on a robot, and MuJoCo sim-to-sim