Export a policy to ONNX
An export turns one policy checkpoint into an ONNX bundle: a folder with the model, its input and output contract, and a script that proves the model works on your machine. The bundle needs no Simulo account, no Simulo client, no PyTorch and no GPU.
1. Export a checkpoint
Section titled “1. Export a checkpoint”Name the policy and the checkpoint kind:
simulo export policy_brisk-heron-4f8k2m:bestEXPORT job_quiet-cedar-7k3m4qCheckpoint: policy_brisk-heron-4f8k2m:bestONNX bundle downloaded: ./train-policy-best/Verify it on this machine: cd train-policy-best python -m pip install -r requirements.txt python verify.pySimulo runs the export as a job of type export, which you can see in
simulo jobs. The job converts the checkpoint to ONNX, then runs 100 test
observations through both the original policy and the ONNX model. If any
action differs by more than 1e-4, the export fails and no bundle is
published. When the check passes, the CLI downloads the bundle, checks its
digest, and unpacks it.
The policy must be sealed, which means its training job has ended. The kind
is required, and a job ID gets the same hint as simulo policy get.
Where the bundle goes
Section titled “Where the bundle goes”The folder is named {job name}-policy-{kind}. The job name is the name of
the training job’s function, so the starter’s train job exports
train-policy-best or train-policy-latest. Use the path the CLI prints.
Useful options:
-o DIRunpacks the bundle intoDIRinstead of the current folder.--no-downloadwaits for the export to pass and leaves the bundle on the platform.--jsonprints the export record and the bundle path as JSON.
Exporting again replaces an earlier bundle folder with the same name. Two
policies trained by jobs with the same function name share a folder name, so
pass -o DIR to keep both.
If you press Ctrl-C while the export runs, it keeps running on Simulo. Run
the same simulo export command to pick it up again.
In Simulo Console, open Jobs, select the training job, and use its Export panel to create and download an ONNX bundle.
2. Verify the bundle on your machine
Section titled “2. Verify the bundle on your machine”Use a clean virtual environment, so nothing else on your machine helps the model run:
cd train-policy-bestpython3 -m venv .venvsource .venv/bin/activatepython -m pip install -r requirements.txtpython verify.pyrequirements.txt lists only ONNX Runtime and NumPy. verify.py loads
model.onnx, runs the bundle’s 100 test observations, and compares each
action with the one Simulo computed during the export, using the same
tolerance. It also reports the average time per action and the control
period. A passing run ends with:
LOCAL VALIDATION: PASSEDThis ONNX bundle runs independently of Simulo on this machine.Passing means the ONNX model reproduces Simulo’s own results on this machine. It does not show that the policy is safe or effective on a physical robot.
What’s in the bundle
Section titled “What’s in the bundle”| File | What it holds |
|---|---|
model.onnx |
The policy as an ONNX model. |
model.pt |
The source checkpoint, when the export includes it. |
manifest.json |
Identity, provenance, control period and versions. |
observation_schema.json |
The ordered inputs: names, shapes, types and units. |
action_schema.json |
The ordered outputs, with units and bounds. |
normalization.json |
Input scaling parameters, or an explicit none. |
test_vectors.npz |
The test observations and the actions Simulo computed for them. |
verify.py |
The standalone check you just ran. |
requirements.txt |
The check’s two dependencies. |
README.md |
These instructions, inside the bundle. |
Use the model in your code
Section titled “Use the model in your code”The model takes one input named observations and returns one output named
actions. For cartpole, an observation is 4 numbers:
import json
import numpy as npimport onnxruntime as ort
manifest = json.load(open("manifest.json"))session = ort.InferenceSession("model.onnx", providers=["CPUExecutionProvider"])
obs = np.zeros((1, 4), dtype=np.float32) # your robot's real observationaction = session.run(["actions"], {"observations": obs})[0]print(action)observation_schema.json says what goes in each slot of the observation and
in what order. action_schema.json says what each output value means and
its bounds. manifest.json records control_period_s in seconds, or the
string "unknown" when training didn’t record it, so check for that before
you use it as a number.