Skip to main content
A training client is a GPU with π0.5 loaded. Your Python program is the training loop: it decides the data, the schedule, the loss and when to evaluate, and each call runs one step of it on the GPU.

Sessions

create_lora_training_client and create_full_training_client start a session: a GPU that loads the model, which takes about a minute (longer the first time). They return once it’s ready.
targets says where training goes; by default the action expert for LoRA, the whole model in full. See Where training goes. action_horizon is the length of the action chunks you train on. A session holds its GPU until you call close() or leave a with block, or until 10 minutes pass without a connection. What you haven’t saved is lost.
training_client.info has the model’s sizes: {"model": "pi05", "action_horizon": 10, "action_dim": 32, "trainable_params": 16026656}.

Data

A batch is a list of types.Datum: an observation in OpenPI’s format, as relay.Policy takes, and the action chunk to learn for it.
  • State and actions are as the model sees them (normalized), and are padded with zeros to 32.
  • Within a batch, each camera’s frames are one size. A camera a datum leaves out is masked.
  • Frames are sent losslessly by default. Pass codec=relay.Codec.JPEG_Q95 to the create call to send less.

Steps run in order, without waiting

forward_backward, optim_step, sample, save_state and load_state send their work and return a Future at once. The GPU runs calls in the order you make them, so the next step is sent while the GPU runs this one. Call .result() to wait for a call and get its value.
An error in a step, such as a malformed datum, raises only from that step’s .result(). Check a future regularly, as the loop above does every 100 steps.

The steps

forward_backward computes the flow-matching loss (the weighted mean squared error of the predicted velocity) and adds its gradients to those accumulated so far. Call it several times before an optim_step to train on a batch too big for one call.
optim_step takes an AdamW step with the accumulated gradients, then clears them. You pass AdamParams every step, so any schedule is a line of Python: A step whose gradient isn’t finite is skipped ("skipped": True).

Custom losses

forward_backward_custom computes your loss on your machine, in PyTorch:
The GPU runs the forward pass and sends back velocity (which requires grad), target, x_t, noise and time. Your function returns the loss and any metrics; the gradient of the loss with respect to velocity goes back to the GPU, which backpropagates it through the model. It waits for the forward pass, so that calls stay in order, and needs pip install "relay-intelligence[train]". forward(batch) returns the same outputs without gradients.

Sampling

save_weights_and_get_sampling_client(name) saves the weights and returns a client that samples with them, however training goes on, for evaluating a checkpoint while you keep training:

Saving and resuming

States are kept under your account. A name can’t contain a slash or start with a dot.