Progress Bar
RL Engine's sparse progress bar lives in src/rle/reusable/progress_bar and is
exported from rle.reusable. It wraps tqdm.auto.tqdm, but only renders at sparse
milestones so notebook cells and cluster logs do not fill with repeated progress
updates.
As a reusable component, the progress bar is for training loops, evaluation
passes, sweeps, and data preparation jobs in new project repos. It keeps the
familiar tqdm feel while avoiding noisy append-only logs.
Quick Start
from rle.reusable import ProgressBar
with ProgressBar(200_000, desc="IQL training", unit="env-step") as progress:
for batch in batches:
metrics = train_batch(batch)
progress.update(
len(batch),
postfix={"return_mean": f"{metrics['return_mean']:.3f}"},
)
The default cadence is every 5% plus final completion. This works well for
Marimo/Jupyter notebooks and for scheduler logs inspected through viewlog.
Iterable Helper
from rle.reusable import progress_bar
for episode in progress_bar(episodes, desc="Evaluation", unit="episode"):
evaluate(episode)
If the iterable has a length, the helper uses it as the progress total. For
generators, pass total= or refresh_units= when you want sparse rendering.
Public API
| helper | purpose |
|---|---|
ProgressBar(total, ...) |
manual progress bar for callback-based loops |
progress_bar(iterable, ...) |
iterable wrapper |
update(amount=1, postfix=None) |
track progress and render only at milestones |
set_postfix(**kwargs) |
store postfix values for the next rendered milestone |
Use refresh_percent= for percentage milestones, or refresh_units= when a
fixed number of units is clearer.
Copying To Another Project
Copy src/rle/reusable/progress_bar and add tqdm to the new project's
dependencies. The component is independent of RL Engine and can be renamed by
changing only the import path used by callers.
The defaults are tuned for notebooks and scheduler output: sparse updates,
dynamic columns, and a long maxinterval so the monitor thread does not redraw
unchanged progress into log files.
Adapting To Your Project
Copy src/rle/reusable/progress_bar and add tqdm to the project
dependencies. Then re-export ProgressBar and progress_bar from the project
package root so trainers and notebooks do not need to know where the helper
lives.
The progress bar is intentionally not tied to RL concepts. In a new project, the main thing to decide is the unit of progress for each long-running block:
- environment steps for step-based trainers;
- episodes for episodic evaluation;
- batches for supervised pretraining or model fitting;
- candidates or profiles for synthesis/certification work;
- runs for coarse outer-loop scripts.
When using the reusable experiment runner, the progress total normally comes
from AlgorithmSpec.config or ExperimentSuiteConfig.common_config:
from rle.reusable.experiments.models import AlgorithmSpec
AlgorithmSpec(
name="IPPO",
enabled_flag="run_ippo",
config={"progress_total": 1_000_000, "progress_unit": "env-step"},
run=run_ippo,
)
Inside the algorithm hook, call context.progress.update(...) from the loop
that best represents real progress. Do not rely on the reusable runner to infer
trainer internals:
for batch in trainer.iter_batches():
metrics = trainer.update(batch)
context.progress.update(
batch.num_env_steps,
postfix={"reward": f"{metrics['reward_mean']:.2f}"},
)
The blocks most often tuned are refresh_percent, refresh_units, unit, and
postfix formatting. For notebook demos, a percentage cadence is usually enough.
For large scheduler jobs, refresh_units can be clearer because it aligns
updates with meaningful training milestones.
If a project already has a trainer-level progress system, keep using it and
adapt only the outer loops to this helper. The reusable experiment runner only
expects a ProgressBar-like object with update(...); it does not need to own
every inner progress display.