Add a new algorithm¶
A new method is a class with four methods. It is registered from a configuration file, without an edit to the library, and runs through the same two commands as the built-in methods.
Summary¶
| Aspect | Custom algorithm |
|---|---|
| Interface | A subclass of Algo with train, predict, save and load |
| Registration | The class key of an algorithm config, written module.path:ClassName |
| Configuration | hparams of the algorithm config, passed to the constructor |
| Training | baselines/train.py -c <experiment.yaml>, through the generic trainer baselines/train_algo.py |
| Evaluation | baselines/evaluate.py --run <run directory>, on the experiment card's grid |
| Limits | The generic trainer calls train once with the whole budget |
The interface¶
Algo is defined in the module robustrllib.algos.base.
from robustrllib.algos import Algo
print(sorted(Algo.__abstractmethods__))
['load', 'predict', 'save', 'train']
| Member | Signature | Contract | Called by |
|---|---|---|---|
| Constructor | __init__(self, **hparams) |
Accepts the hparams of the card as keyword arguments |
build_algo |
train |
train(self, env, total_timesteps, seed=None) |
Fits the policy on env |
baselines/train_algo.py |
predict |
predict(self, obs, deterministic=True) |
Returns the action for one observation | baselines/evaluate.py |
save |
save(self, path) |
Writes what load needs to path |
baselines/train_algo.py, after training |
load |
load(cls, path, **kwargs), a class method |
Returns an instance ready for predict |
load_algo |
The evaluator calls load with env=, device= and config=, the resolved configuration of
the run, from which the template reads its hparams.
A subclass that leaves out one of the four methods cannot be instantiated: Python raises
TypeError: Can't instantiate abstract class.
Implement a method¶
The module robustrllib.algos.template_reinforce is a minimal REINFORCE written to be copied.
The command prints the location of the file.
python -c "import robustrllib.algos.template_reinforce as m; print(m.__file__)"
The constructor takes hyperparameters as keyword arguments. The trailing **_ swallows keys the
class does not know.
class Reinforce(Algo): # <-- your algorithm body
def __init__(self, lr=3e-4, gamma=0.99, hidden=(64, 64), device="cpu", **_):
super().__init__()
self.lr, self.gamma, self.hidden, self.device = lr, gamma, tuple(hidden), device
self.policy = None
train reads the dimensions from the spaces of the environment and owns the training loop.
def _build(self, env):
obs_dim = int(np.prod(env.observation_space.shape))
act_dim = int(np.prod(env.action_space.shape))
self.policy = _Policy(obs_dim, act_dim, self.hidden).to(self.device)
self.opt = torch.optim.Adam(self.policy.parameters(), lr=self.lr)
def train(self, env, total_timesteps, seed=None):
self._build(env)
env.action_space.seed(seed)
steps = 0
while steps < total_timesteps:
obs, _ = env.reset(seed=seed)
...
predict maps one observation to one action, as a NumPy array.
def predict(self, obs, deterministic=True):
t = torch.as_tensor(np.asarray(obs), dtype=torch.float32, device=self.device)
with torch.no_grad():
dist = self.policy.dist(t)
a = dist.mean if deterministic else dist.sample()
return a.cpu().numpy()
load rebuilds the network from the environment and the run's hyperparameters, and restores
the weights.
def save(self, path):
torch.save(self.policy.state_dict(), path)
@classmethod
def load(cls, path, env=None, device="cpu", config=None, **kwargs):
hparams = dict((config or {}).get("algorithm", {}).get("hparams") or {})
algo = cls(device=device, **hparams)
algo._build(env)
algo.policy.load_state_dict(torch.load(path, map_location=algo.device))
return algo
The training loop uses only reset and step, so it does not need to know which shifts are
stacked on the environment. save and load use the path as given; the trainer names the
file and the evaluator finds it.
Register a method¶
Registration is one line in an algorithm config.
# A custom algorithm plugged in by import path: the REINFORCE template of
# robustrllib.algos, trained by the generic Algo trainer. No edit to the library is needed.
name: reinforce
entry: baselines/train_algo.py
class: robustrllib.algos.template_reinforce:Reinforce
checkpoint: last
hparams:
lr: 0.0003
gamma: 0.99
hidden: [64, 64]
| Key | Meaning |
|---|---|
name |
A label |
entry |
The training script; baselines/train_algo.py trains any Algo class |
class |
module.path:ClassName, importable from the root of the checkout |
checkpoint |
Which checkpoint the evaluator loads: last |
hparams |
Keyword arguments of the constructor |
The contract can be checked before any training. A budget of zero timesteps builds the network without running an episode.
import os
import tempfile
import numpy as np
from robustrllib import make_robust
from robustrllib.algos import Algo, build_algo, load_algo
CLASS = "robustrllib.algos.template_reinforce:Reinforce"
env = make_robust("Hopper-v5", seed=0)
algo = build_algo("reinforce", cls=CLASS, lr=0.0003, gamma=0.99, hidden=[64, 64])
algo.train(env, total_timesteps=0, seed=0)
obs, _ = env.reset(seed=0)
action = algo.predict(obs, deterministic=True)
print(type(algo).__name__, isinstance(algo, Algo), action.shape)
with tempfile.TemporaryDirectory() as tmp:
path = os.path.join(tmp, "step_0.pt")
algo.save(path)
clone = load_algo("reinforce", path, cls=CLASS, env=env)
print(os.listdir(tmp), np.allclose(clone.predict(obs), action))
Reinforce True (3,)
['step_0.pt'] True
Run a method¶
An experiment card names the algorithm, the task, the grid and the budget. Every section is a path to a card or an inline mapping.
name: reinforce_hopper
algorithm: robustrllib/configs/algorithm/reinforce.yaml
task: robustrllib/configs/task/hopper.yaml
eval: robustrllib/configs/eval/part1_mujoco.yaml
train: {steps: 20000}
python baselines/train.py -c examples/reinforce_hopper.yaml --seed 0
python baselines/evaluate.py --run runs/reinforce_hopper/seed0
| Step | Call |
|---|---|
| Build | make_env(task, shifts=train.shifts, seed), the task card's environment |
| Train | algo.train(env, total_timesteps=train.steps, seed=seed) |
| Save | algo.save("<run>/ckpt/step_<steps>.pt") |
| Evaluate | Reinforce.load(...), then every condition of the grid, 20 episodes each |
Tip
--train-shift <arm> trains under a shift of robustrllib/configs/train_shifts.yaml, and an
experiment card may list its own under train.shifts, in the dictionary form of the grid.
The shifts and their mode names are listed under
Shift Sources and Modes.
Evaluation and metrics¶
The evaluator prints one row per condition and writes <run>/eval/<grid>.json.
| Metric | Scope | Meaning |
|---|---|---|
return_mean, return_std, return_min |
Condition | Episodic return over the episodes of the condition |
cvar |
Condition | Mean of the worst 10% of the episodes |
score |
Condition | 100 (R - R_min) / (R_max - R_min) with the task card's anchors |
success_rate |
Condition | Share of episodes that report success, where the task does |
returns |
Condition | The return of every episode |
The evaluator applies the Evaluation Protocol to any class that follows the contract.
| Assumption | Detail |
|---|---|
| Checkpoint location | The highest-numbered file in <run>/ckpt/ |
| Path used verbatim | save(path) writes exactly path, and load(path) reads exactly path |
load keywords |
load is called with env=, device= and config= |
| Card references | Paths relative to the root of the checkout |
Registration rules¶
- A method subclasses
Algoand implements all four methods. - The constructor accepts every key of
hparamsas a keyword argument. - The module named in
classis importable from the directory where the launcher runs. predictreturns one action for one observation and honoursdeterministic=True.saveandloadagree on the file name, and use the path verbatim for the shared evaluator.- The training loop uses only
resetandstep, so that it runs on any shifted environment. - An optional
reset()method is called by the evaluator before every episode, for policies with a recurrent state; an optionalactorattribute, a differentiable map from observation to action, lets the evaluator run the adversarial observation conditions.