Skip to main content

Visualizing Training History

apps/rllib/visualize_training_history.py combines per-checkpoint rollout videos from one Ray Tune trial into a labeled montage that shows how the policy changed during training.

Prerequisites

Install the core and training dependencies with uv sync --extra core and the training-stack commands in Installation and Setup.

Checkpoint videos are off by default. Pass --video_on_checkpoint to train_samples.py to write video_000.mp4 and video_labels.json in each checkpoint_*/ directory. The renderer must also be available. For example:

cd superdex_lab/apps/rllib
uv run --no-project python train_samples.py \
--pattern "cart_pole" --checkpoint_freq 2 --video_on_checkpoint

If the selected checkpoints do not contain videos, the visualization command can generate them with --generate_missing.

See CheckpointVideoGeneratorCallback for the training callback details.

Inputs

Provide the Ray Tune trial directory as trial_dir, not an individual checkpoint. It contains the checkpoint_* directories and normally params.json. Each selected checkpoint must contain the file named by --video_name, which defaults to video_000.mp4, unless you use --generate_missing; generating videos also requires the trial's params.json.

Labels use video_labels.json when present. Otherwise, the tool matches the checkpoint write time against result.json, or against progress.csv when result.json is absent. One of those metadata files is required only when a selected checkpoint lacks a readable label sidecar.

Run the visualization

Use superdex_lab/apps/rllib as the working directory:

cd superdex_lab/apps/rllib
uv run python visualize_training_history.py \
~/ray_results/PPO/cart_pole_a1b2c3d4 --num_videos 8

The command samples up to eight checkpoints with the default linear schedule and always includes the final checkpoint.

Output

By default, the montage is written to <trial_dir>/training_history.mp4. Use --output to choose another path; the tool creates missing parent directories. Each clip is labeled iter=<training_iteration>, timestep=<num_env_steps>, for example iter=250, timestep=1.02e+06.

Four frames from a training-history montage, labeled iter=10, 250, 500 and 750, showing a robot hand&#39;s grasp on a cube improving as training progresses

Options

Input and selection

OptionDefaultDescription
trial_dirrequiredRay Tune trial directory containing checkpoint_<number> directories.
--num_videosrequiredNumber of checkpoints to sample. Clamped to the number available.
--schedulelinearlinear spaces checkpoints evenly; exponential concentrates samples on early training. Both include the final checkpoint.
--base2.0Curvature for exponential; must be greater than 1. Larger values put more samples early. Ignored for linear.
--video_namevideo_000.mp4Rollout video filename to read from each selected checkpoint.
--output<trial_dir>/training_history.mp4Output video path.
--fpssource frame rateOutput frame rate; each clip is resampled when set. Without it, all source videos must have the same frame rate.

Appearance

OptionDefaultDescription
--speed1.0Playback speed multiplier applied before other transforms.
--text_height_pct5.0Label font size as a percentage of frame height.
--margin_pct3.0Label inset from frame edges as a percentage of frame height.
--text_locationbottom-leftbottom-left, bottom-right, top-left, top-right, or center.
--font_colorwhiteAny color name or hex string accepted by PIL, such as '#ff0000'.
--font_pathPIL's built-in fontTrueType font file to use instead. The built-in scalable font requires Pillow 10.1 or newer.
--head_seconds1.0Seconds to hold each clip's first frame before playback.
--tail_seconds1.0Seconds to hold each clip's last frame after playback.
--transition_seconds0.5Crossfade duration between clips. It must not exceed --head_seconds or --tail_seconds.

For example, create a 10-clip montage weighted toward early training, at half speed, with a larger red label in the top-left:

uv run python visualize_training_history.py \
~/ray_results/PPO/cart_pole_a1b2c3d4 \
--num_videos 10 \
--schedule exponential --base 3.0 \
--speed 0.5 \
--text_height_pct 8 --text_location top-left --font_color '#ff0000' \
--output ./cart_pole_history.mp4

Missing Videos and Label Fallback

By default, a selected checkpoint without video_000.mp4, or the filename set by --video_name, stops with:

FileNotFoundError: Selected checkpoint is missing video_000.mp4: <checkpoint>

Use --generate_missing to run run_inference.py for each missing video. The inference subprocess writes inference_000.mp4, which the tool renames to the requested --video_name. This fallback requires the training dependencies and a working renderer.

OptionDefaultDescription
--generate_missingoffRun inference instead of failing when a selected checkpoint has no video.
--inference_episodes1Number of episodes to roll out; the first episode's clip is used. Only applies with --generate_missing.
--explore_during_inferenceoffUse the exploration policy while generating missing videos. Only applies with --generate_missing.

When video_labels.json is absent or unreadable, label resolution falls back to timestamp matching against the trial metadata. The maximum accepted difference is 300 seconds. If neither result.json nor progress.csv exists, or the closest result is more than 300 seconds away, the tool stops instead of assigning an unreliable label.

All selected videos must have the same frame dimensions. Use --fps to normalize different source frame rates before the clips are joined.