Evaluating a New Policy
June 1, 2026 · View on GitHub
This guide walks through how to evaluate your own policy against the RoboLab benchmark. You do not need to fork or modify RoboLab — everything can live in your own separate repository that imports robolab as a dependency.
RoboLab uses a server-client architecture: your model runs as a standalone server (any framework, any GPU), and a lightweight inference client inside the simulator sends observations and receives actions.
Prerequisites: You need registered environments before running evaluation. For DROID with joint-position actions, RoboLab ships a built-in registration you can use directly. If you need custom observations, a different robot, or different simulation parameters, first follow the Environment Registration guide.
Your Repository Structure
my_policy_eval/
my_policy/
__init__.py
inference_client.py # Your inference client (Step 1)
run_eval.py # Your evaluation script (Step 2)
requirements.txt # includes robolab as a dependency
Step 1: Implement an Inference Client
Subclass robolab.eval.InferenceClient. The base provides the control loop
(infer, reset, chunking, multi-env bookkeeping); subclasses implement
four narrow hooks:
# my_policy/inference_client.py
import numpy as np
from robolab.eval import InferenceClient
class MyPolicyClient(InferenceClient):
open_loop_horizon = 8 # how many actions to consume per server query
def __init__(self, remote_host: str = "localhost", remote_port: int = 8000) -> None:
super().__init__()
# Connect to your model server
...
# --- required hooks ---------------------------------------------------
def _extract_observation(self, raw_obs, *, env_id=0) -> dict:
# For the default DROID registration, raw_obs contains:
# raw_obs["image_obs"]["over_shoulder_left_camera"] - (N, H, W, 3) torch tensor, uint8
# raw_obs["image_obs"]["wrist_cam"] - (N, H, W, 3) torch tensor, uint8
# raw_obs["proprio_obs"]["arm_joint_pos"] - (N, 7) torch tensor, float32
# raw_obs["proprio_obs"]["gripper_pos"] - (N, 1) torch tensor, float32
return {
"image": raw_obs["image_obs"]["over_shoulder_left_camera"][env_id].cpu().numpy(),
"joint_pos": raw_obs["proprio_obs"]["arm_joint_pos"][env_id].cpu().numpy(),
}
def _pack_request(self, extracted_obs, instruction):
# Whatever wire format your server expects
return {"image": extracted_obs["image"], "prompt": instruction}
def _query_server(self, request):
return self.client.infer(request)
def _unpack_response(self, response) -> np.ndarray:
# Must return a (horizon, action_dim) array; base handles the rest.
return np.asarray(response["actions"])
# --- optional hooks (defaults are identity / None) -------------------
def _postprocess_chunk(self, chunk):
# Binarize gripper, pad 7->8, flip sign, etc.
return chunk
def _build_visualization(self, extracted_obs):
return extracted_obs["image"]
Key contract:
_extract_observation+_pack_requestsplit repo-specific obs munging from backend-specific wire format. The ABC's defaultinfer()wires them together: extract → pack → query → unpack → postprocess → cache chunk → step one action.- Action dict returned by
infer()has"action"(numpy array, typically 8-dim: 7 joints + 1 gripper) and"viz"(image for the live display window, orNone). reset(env_id=...)clears per-episode state. Override only if your server needs session notification; otherwise the base's default is enough.
See the existing clients for complete working examples.
Step 2: Write Your Evaluation Script and Run It
For the full evaluation script template, CLI reference, and run instructions, see Running Environments.
In short:
-
Install robolab as a dependency:
cd /path/to/robolab && uv pip install -e . -
Install your package so its modules are importable:
cd /path/to/my_policy_eval && uv pip install -e . -
Start your model server (in a separate terminal):
python -m my_model.serve --checkpoint /path/to/model --port 8000 -
Run evaluation:
# Run on all benchmark tasks python run_eval.py --headless # Run on a specific task python run_eval.py --task BananaInBowlTask # Run on a tag of tasks python run_eval.py --tag pick_place # Run multiple runs with parallel envs (total episodes = num_runs * num_envs) python run_eval.py --headless --num-runs 5 --num_envs 2 # Custom server address python run_eval.py --remote-host 10.0.0.1 --remote-port 5555 -
View results: Results are saved to
output/<timestamp>_my_policy/. See Analysis and Results Parsing for summarization tools.
Existing Clients as Reference
See Inference Clients for server setup instructions.