
Octo is a 27M or 93M transformer policy trained on 800k Open X-Embodiment trajectories. Its diffusion action head, how it refits to new sensors and action spaces, and where it stands now.
Octo is a transformer policy trained on 800k robot trajectories from Open X-Embodiment and released whole: weights, pretraining code, finetuning scripts and data loaders, all MIT. It came out of UC Berkeley's RAIL lab with Stanford, CMU and Google DeepMind co-authors, and was presented at Robotics: Science and Systems 2024. Two sizes shipped, 27M and 93M parameters, which makes it a very small vision-language-action model. That smallness is the point: Octo is the cleanest worked example of a design the big VLAs inherited and then buried under scale, one shared transformer taking arbitrary tokens in and a tiny separate head turning one output embedding into a chunk of continuous actions. It is also not one of the five models AY-Robots trains, and the tabs below say what that means in practice.
Octo in eight lines
- •Two checkpoints: Octo-Small at 27M and Octo-Base at 93M, both 12-layer transformers, ViT-S and ViT-B shaped.
- •Pretrained on 800k trajectories from 25 curated Open X-Embodiment datasets, Fractal, Kuka and Bridge at 17 percent of each batch each.
- •Actions come from a diffusion head: a 3-layer MLP, hidden dim 256, 20 DDPM steps, emitting a chunk of 4 seven-dimensional actions.
- •WidowX ablation: diffusion head 83 percent, MSE head 35 percent, discretized head 18 percent, so the head mattered more than the backbone.
- •Refitting to a new observation and action space is config surgery plus a parameter merge: about 100 demos, under 5 hours on one 24 GB A5000.
- •Stated limit: only 27 percent of the pretraining data had a wrist camera, and finetuning was often stronger without one.
- •JAX and Flax, pinned to jax 0.4.20, no commits since 31 July 2024, no Octo policy in LeRobot.
What Octo actually is
A policy maps observations to actions. Most published robot policies fix the observation space at training time: one camera, this resolution, this action dimension. Change any of it and you retrain from scratch. Octo's contribution is that it does not. You can add or remove a camera, swap end-effector deltas for joint positions, or move from a single arm to a bimanual setup, and keep the pretrained transformer.
| Property | Octo-Small | Octo-Base |
|---|---|---|
| Layers | 12 | 12 |
| Hidden size / MLP size | 384 / 1536 | 768 / 3072 |
| Attention heads | 6 | 12 |
| Parameters | 27M | 93M |
| Shaped like | ViT-S | ViT-B |
| Inference on 1x NVIDIA 4090 | 17 it/sec | 13 it/sec |
| Pretraining wall clock | 8 h on a TPU v4-128 pod | 14 h on a TPU v4-128 pod |
| Hugging Face id | rail-berkeley/octo-small-1.5 | rail-berkeley/octo-base-1.5 |
The README prints those speeds as it/sec without defining the unit. Read them as model calls: Octo emits 4 actions per call, so 13 it/sec is about 77 ms per call, or about 19 ms per commanded action if you execute the whole chunk. That is the order of ACT and far quicker than any 3B VLA. Run receding horizon control instead, one action per call, and you throw that factor of four away. See action chunking for why that choice changes how a policy feels on hardware.
The org rail-berkeley carries both octo-base / octo-small (1.0) and the -1.5 ids. The README's checkpoint table still links the 1.0 repositories while every command in the same README uses 1.5. Version 1.5 repeats the language task tokens at every timestep, adds GPT-3.5 rephrasings of the instructions, and fixes three bugs: dropout in the diffusion head conflicting with layer norm, an off-by-one in the attention mask, and image augmentations that did not get fresh random seeds.
The architecture: everything becomes a token
No fusion module, no cross-attention adapter, no per-embodiment head registry. Every input becomes tokens, the tokens get learnable position embeddings, and one transformer attends over all of it.
Tokenizers
- Workspace camera at 256x256: shallow convolutional stack, 16x16 patches, 256 tokens per frame.
- Wrist camera at 128x128: same stack, same patch size, 64 tokens per frame.
- Language: T5 tokenizer plus a frozen t5-base (111M) encoder, 16 tokens. The pretraining config freezes it with
frozen_keys=("*hf_model*",), so those 111M parameters never see a gradient. - Goal image: an optional task token block, run through the same image tokenizer as an observation. It is what lets Octo be conditioned on a target state instead of a sentence.
- History: 2 frames. The paper reports significantly diminishing gains beyond the first extra frame.
Note what is missing. The released checkpoints carry no proprioception tokenizer, and that is a result rather than an oversight: the authors report that policies trained with proprioceptive observations were generally worse, which they attribute to causal confusion between the state and the actions it correlates with. If you want joint angles anyway, you add the tokenizer at finetuning time, which is what the repo's ALOHA example does.
Readout tokens and block-wise attention
Octo inserts learned readout tokens into the sequence. A readout token attends to the observation and task tokens before it and is not attended to by any of them, a passive probe; the paper's analogy is the BERT [CLS] token. The action head consumes that embedding, not the observation embeddings.
Because nothing attends to a readout token, adding an output head cannot disturb the pretrained representation. And because attention is masked block-wise per input group, deleting a token block (the wrist camera) or inserting one (proprioception) is a mask edit plus new position embeddings, not surgery on learned weights. The whole finetuning story follows from that one choice.
The diffusion action head
The head is small and separate: a 3-layer MLP with hidden dimension 256, residual connections and layer normalization, trained with the standard DDPM objective on a cosine noise schedule with 20 denoising steps. The transformer runs once per timestep for the readout embedding, then the denoising loop runs entirely inside that MLP, so denoising cost is small and roughly independent of backbone size.
# octo/model/components/action_heads.py, class DiffusionActionHead
readout_key: str
use_map: bool = False # False = mean-pool, True = attention pooling
action_horizon: int = 1 # the pretraining config sets this to 4
action_dim: int = 7 # 6-DoF end-effector delta + gripper
max_action: float = 5.0
loss_type: str = "mse"
# diffusion-specific config with sane defaults
time_dim: int = 32
num_blocks: int = 3 # the "3-layer MLP" from the paper
dropout_rate: float = 0.0 # turned off in 1.5, it fought layer norm
hidden_dim: int = 256
use_layer_norm: bool = True
diffusion_steps: int = 20 # cosine beta schedule
n_diffusion_samples: int = 1Both obvious alternatives were tried, and the failures are in the appendix. A simple L2 loss produced hedging policies that moved very slowly and failed to rotate the gripper in the WidowX evaluations. Discretizing each dimension into 256 bins with cross-entropy, the RT-1 recipe, gave more decisive policies that lacked precision and often missed the grasp.
| Ablation on the WidowX setup | Success rate |
|---|---|
| Octo-Small, full recipe | 83% |
| ResNet-50 + transformer backbone instead of ViT | 70% |
| Trained on the smaller RT-X mix (11 datasets) | 60% |
| Trained on Bridge only | 43% |
| Continuous action prediction, MSE loss | 35% |
| Discretized action prediction, cross-entropy | 18% |
Read it as a ranking: the discretized head cost 65 points, cutting the mix to one robot cost 40, the visual backbone cost 13. Rates are averaged over 40 trials across four tasks, so single-digit gaps are noise; the ordering is not.
What it was trained on
The mix is 25 datasets picked out of Open X-Embodiment, the 22-robot, 527-skill collection from 21 institutions. Curation was subtractive: drop everything with no image stream, everything not using delta end-effector control, then whatever is too repetitive, too low-resolution or too niche. In the repo the survivors are the constant oxe_magic_soup, where a 26th entry, uiuc_d3field, sits commented out because its raw data is broken. Preprocessed, the mix is about 1.2 TB.
| Dataset | Share of each training batch |
|---|---|
| Fractal (the RT-1 Google Robot data) | 17.0% |
| Kuka | 17.0% |
| Bridge | 17.0% |
| BC-Z | 9.1% |
| Stanford Hydra | 6.0% |
| Language Table | 5.9% |
| Taco Play | 3.6% |
| 18 further datasets | the remaining 24.4% |
Those shares are mostly relative dataset size, with two manual thumbs on the scale: datasets judged more diverse get double weight, a few very repetitive ones get down-weighted so they cannot dominate. Fractal and Kuka carry explicit sub-1.0 weights in the repo, 0.541 and 0.834, and still land at 17 percent of every batch because they are that much bigger. Two of the sources have their own write-ups: BridgeData V2 and BC-Z.
Gripper actions across all 25 sources were aligned to one absolute convention, plus one open, zero closed. A relative encoding was tried, plus one or zero only on the timestep the gripper changes and 0.5 otherwise. It raised grasp success slightly, most frames being do-not-change commands, but the policy then retried less after a failed grasp, which the authors judged worse overall.
Only 27 percent of the pretraining data contains wrist camera images, and only 56 percent contains language annotations. The authors report that the model struggles to process wrist camera information adequately, and that finetuning results were often stronger using only a third-person camera than third-person plus wrist. If your SO-100 relies on the wrist camera to tell the gripper when to close, that is the most important sentence here.
What the authors say actually moved the needle
Appendix E lists what worked and what did not, and it is more useful than the headline results. Findings that transfer to any imitation learning pipeline, not just this one:
- 16x16 image patches beat 32x32, particularly on grasping and other fine-grained tasks, at 4x the token count.
- Action chunking produced more coherent movement. Temporal ensembling on top of receding horizon control added nothing in their evaluations.
- Shuffling mattered. A 20k shuffle buffer with trajectory-level interleaving hurt zero-shot performance badly; they shuffle frames before decoding images to fit a 500k buffer, and subsample at most 100 steps per trajectory.
- The frozen t5-base gave the best language-conditioned policies. A t5-large (386M) encoder did not help, nor did finetuning its last two layers, which they blame on how little free-form language the datasets contain.
Adapting Octo to a new observation and action space
This is what the paper is about, and the repo ships a runnable example: examples/02_finetune_new_observation_action.py refits a checkpoint pretrained on single-arm 7-dimensional end-effector deltas to a simulated bimanual ALOHA cube-handover setup: 14-dimensional joint actions, one camera, proprioception. Nothing about that target matches the pretraining. Five moves:
- 1Install the pinned stack
Requirements pin
jax==0.4.20,flax==0.7.5,tensorflow==2.15.0,numpy==1.24.3and Python 3.10. Do not float these.bashconda create -n octo python=3.10 conda activate octo git clone https://github.com/octo-models/octo.git cd octo pip install -e . pip install -r requirements.txt pip install --upgrade "jax[cuda11_pip]==0.4.20" \ -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html - 2Prove the path on the debug dataset first
The repo ships a tiny dataset under
tests/debug_dataset, which is what--debugpoints at. Verify the install before converting anything of your own.bashpython scripts/finetune.py \ --config.pretrained_path=hf://rail-berkeley/octo-small-1.5 \ --debug - 3Load the checkpoint and read its spec
get_pretty_spec()prints the observation and task keys the checkpoint expects. Read it before writing a data transform, not after.pythonfrom octo.model.octo_model import OctoModel model = OctoModel.load_pretrained("hf://rail-berkeley/octo-base-1.5") print(model.get_pretty_spec()) - 4Delete a tokenizer, add a tokenizer, replace the head
The pretrained config is a plain dict. Here the 7-dim diffusion head becomes a 14-dim L1 head with a 50-step horizon, the ALOHA recipe.
pythonconfig = pretrained_model.config del config["model"]["observation_tokenizers"]["wrist"] config["model"]["observation_tokenizers"]["proprio"] = ModuleSpec.create( LowdimObsTokenizer, n_bins=256, bin_type="normal", low=-2.0, high=2.0, obs_keys=["proprio"], ) config["model"]["heads"]["action"] = ModuleSpec.create( L1ActionHead, action_horizon=50, action_dim=14, readout_key="readout_action", ) - 5Rebuild from the edited config, then merge the old weights in
from_configinitialises fresh parameters, thenmerge_paramscopies in every pretrained tensor whose name and shape still match. New position embeddings and the new head stay random. That is the whole mechanism.pythonmodel = OctoModel.from_config( config, example_batch, text_processor, dataset_statistics=dataset.dataset_statistics, ) merged_params = merge_params(model.params, pretrained_model.params) model = model.replace(params=merged_params)
The example runs 5000 steps at a constant 3e-5 after a 100-step warmup, which is a smoke test, not the recipe. The paper's is longer: about 100 in-domain trajectories, 50k steps, cosine decay with linear warmup, full model updated. The authors state that updating everything beat the recipes freezing subsets, worth knowing because the repo still offers head_only and head_mlp_only.
The finetuning defaults you will actually run
The advanced path is scripts/finetune.py driven by scripts/configs/finetune_config.py. Its config string is two comma-separated choices, freezing mode and conditioning mode, defaulting to full,multimodal. Values below come from the last commit, 31 July 2024.
| Setting | Default | Note |
|---|---|---|
| batch_size | 256 | Asserted divisible by device count |
| num_steps | 50000 | Matches the paper's recipe |
| window_size | 1 | Pretraining used 2 |
| action_horizon | 4 | Chunk length |
| learning rate | cosine, peak 3e-4, warmup 2000 | Same peak as pretraining, which used rsqrt decay |
| weight_decay | 0.01 | Pretraining used 0.1 |
| clip_gradient | 1.0 | Same as pretraining |
| seed | 42 | It has one, unlike some vendor trainers |
| resize_size | primary 256x256, wrist 128x128 | The encoders assume these |
| action_normalization_mask | [True] x 6 + [False] | Gripper deliberately unnormalized |
| finetuning modes | full, head_only, head_mlp_only | Paper recommends full |
| task modes | image_conditioned, language_conditioned, multimodal | multimodal keeps the goal image with p=0.5 |
# full transformer update, images only, no language
python scripts/finetune.py \
--config=scripts/configs/finetune_config.py:full,image_conditioned \
--config.pretrained_path=hf://rail-berkeley/octo-small-1.5 \
--config.save_dir=/path/to/checkpoints
# reproduce the pretraining instead (needs the ~1.2 TB OXE mix)
python scripts/train.py \
--config scripts/configs/octo_pretrain_config.py:vit_b \
--name=octo \
--config.dataset_kwargs.oxe_kwargs.data_mix=oxe_magic_soupThe install line is jax[cuda11_pip]==0.4.20. JAX 0.4.20 went to PyPI on 2 November 2023 and those are CUDA 11 wheels. On a machine whose driver stack has moved on, the install resolves fine and then fails at the first compile with an opaque XLA or ptxas error. Nobody upstream will bump it: no commits since 31 July 2024, 88 issues and 8 pull requests open. Budget a container, and run the --debug finetune before converting a single episode, the discipline that keeps pages like out of memory during training short.
Do it yourself, or use what is already wired up
Same goal in both columns: a policy running on your own arm, trained on your own demonstrations.
You clone the repo, build the pinned JAX environment, and then face the real work, which is not the training: getting your data into RLDS, the TensorFlow Datasets format Octo's loader expects. There is no LeRobot reader in the repo. You write a standardization transform from your episode fields onto the config keys, compute dataset statistics, and pick your action space before the first step runs.
# after your dataset is in RLDS and registered
python scripts/finetune.py \
--config=scripts/configs/finetune_config.py:full,language_conditioned \
--config.pretrained_path=hf://rail-berkeley/octo-small-1.5 \
--config.dataset_kwargs.name=my_arm_dataset \
--config.dataset_kwargs.data_dir=/data/rlds \
--config.save_dir=/data/ckpt- You build the RLDS conversion, the standardization transform and the normalization mask for your gripper dimension.
- You rent and babysit the GPU. The paper's setups finetuned in under 5 hours on one 24 GB A5000, so a consumer card is enough.
- You write the serving loop.
examples/03_eval_finetuned.pycovers a Gym environment,examples/04_eval_finetuned_on_robot.pya real WidowX. Neither is your arm.
A reasonable week if you want to study the architecture. Not if you just want a policy that picks something up.
Straight answer: AY-Robots does not train Octo. The five trainable policies are GR00T N1.7, GR00T N1.5, Pi0.5, SmolVLA and ACT. What the platform removes is everything around the model: recording, dataset format, GPU rental, serving.
| Policy | Params | GPU tier | Latency per action step | Min episodes |
|---|---|---|---|---|
| GR00T N1.7 | ~3B, ~40M trained during fine-tuning | A100 80 GB or H100 80 GB | 152 ms | 50 |
| GR00T N1.5 | ~3B | A100 80 GB or H100 80 GB | 165 ms | 50 |
| Pi0.5 | ~3B, PaliGemma backbone | A100 80 GB or H100 80 GB | 485 ms | 50 |
| SmolVLA | ~450M | RTX 4090 or any 24 GB card | 245 ms | 30 |
| ACT | ~80M | RTX 4090 or any 24 GB card | 20 ms | 50 |
The desktop client on the download page records LeRobot datasets straight from a teleop session. The training form picks model, dataset and hyperparameters, the backend rents a GPU on a spot market by required VRAM, and checkpoints go to object storage. Inference pods carry an idle watchdog and destroy themselves, so nothing bills silently. A 24 GB run is about 1 to 3 USD, the 80 GB tier about 4 to 12 USD. See pricing and the training docs.
If what drew you to Octo was the small, fast, chunked policy, the closest equivalent is ACT on an SO-100 at 20 ms per action step. If it was the pretrained cross-embodiment prior, it is SmolVLA, which needs only 30 episodes. Neither is Octo.

The numbers, from three evaluations
The paper's own finetuning table
Six target domains, roughly 100 demonstrations each, identical hyperparameters, 20 trials per domain. Three of the six changed the observation or action space relative to pretraining, which is the claim under test. VC-1 is a pretrained visual representation.
| Domain | From scratch | VC-1 features | Octo |
|---|---|---|---|
| Berkeley Insertion (new input: force-torque) | 10% | 5% | 70% |
| Stanford Coffee | 45% | 0% | 75% |
| CMU Baking | 25% | 30% | 50% |
| Berkeley Pick-Up (new action space: joint position) | 0% | 0% | 60% |
| Berkeley Coke | 20% | 10% | 100% |
| Berkeley Bimanual (new action space: joint position) | 20% | 50% | 80% |
| Average | 20% | 15% | 72% |
Zero-shot, on setups drawn from the pretraining distribution, Octo averaged a 29 percent higher success rate than RT-1-X (35M) and performed similarly to RT-2-X (55B). On the WidowX tasks, goal-image conditioning beat language conditioning by 25 percent, the goal image simply carrying more information. Both baselines have arena entries: RT-1-X and RT-2-X, and the line is covered in the RT-2 write-up.
LIBERO, as reported by the OpenVLA authors
Independent numbers matter more than a paper's own table. Three seeds, 500 trials each. Octo is finetuned on the target suite and OpenVLA with LoRA; Diffusion Policy is trained from scratch, a strong baseline rather than a pretrained one.
| Method | Spatial | Object | Goal | Long | Average |
|---|---|---|---|---|---|
| Diffusion Policy from scratch | 78.3% | 92.5% | 68.3% | 50.5% | 72.4% |
| Octo (93M), finetuned | 78.9% | 85.7% | 84.6% | 51.1% | 75.1% |
| OpenVLA (7B), finetuned | 84.7% | 88.4% | 79.2% | 53.7% | 76.5% |
A 93M policy landing 1.4 points behind a 7B policy, and beating it on LIBERO-Goal, is the most quoted fact about Octo and it is fair. It is also narrow: LIBERO is simulation, both pretrained policies saw only real-world data, and the OpenVLA authors attribute the tight margins to exactly that domain gap.
SIMPLER, which is less flattering
SIMPLER evaluated policies in the real world and in a matched simulator, and its real-world tables are the least flattering thing published about Octo. Note what was not run: Octo-Small appears only on WidowX + Bridge and RT-2-X only on the Google Robot, so this is not a clean four-way comparison.
| Real-world setup | Task | Octo-Base | Octo-Small | RT-1-X | RT-2-X |
|---|---|---|---|---|---|
| Google Robot | Pick Coke Can (average) | 0.293 | not run | 0.760 | 0.907 |
| Google Robot | Move Near | 0.350 | not run | 0.450 | 0.733 |
| Google Robot | Open / Close Drawer (average) | 0.333 | not run | 0.630 | 0.481 |
| WidowX + Bridge | Put Spoon on Towel | 0.333 | 0.417 | 0.000 | not run |
| WidowX + Bridge | Put Carrot on Plate | 0.250 | 0.083 | 0.000 | not run |
| WidowX + Bridge | Stack Green Block on Yellow | 0.000 | 0.125 | 0.000 | not run |
| WidowX + Bridge | Put Eggplant in Yellow Basket | 0.233 | 0.433 | 0.000 | not run |
On the Google Robot, where Fractal is 17 percent of the mix, Octo-Base trails both RT models everywhere. On the WidowX, where Bridge is another 17 percent, RT-1-X scores 0.000 on all four tasks while both Octo sizes finish some, and Octo-Small beats Octo-Base on three of the four at less than a third of the size. Distance from the dominant training data predicts performance here better than parameter count.
Where Octo sits next to newer VLAs
Octo went to arXiv on 20 May 2024, last commit 31 July 2024. The field then moved in a direction Octo deliberately did not take: newer models start from a pretrained vision-language model and inherit web-scale semantics, where Octo started from scratch on robot data with only a frozen t5-base. That is why Octo will not follow an instruction about an object it never saw in 800k trajectories, and Pi0.5 or a GR00T checkpoint sometimes will.
| Model | Params | Language backbone | Action head | Framework |
|---|---|---|---|---|
| Octo-Small | 27M | frozen t5-base | diffusion, 20 DDPM steps | JAX / Flax |
| Octo-Base | 93M | frozen t5-base | diffusion, 20 DDPM steps | JAX / Flax |
| ACT | ~80M | none | chunked transformer decoder | PyTorch, in LeRobot |
| SmolVLA | ~450M | SmolVLM backbone | flow matching | PyTorch, in LeRobot |
| GR00T N1.7 | ~3B | VLM backbone | diffusion | PyTorch, Isaac-GR00T |
| Pi0.5 | ~3B | PaliGemma | flow matching | PyTorch, in LeRobot |
| OpenVLA | 7B | Prismatic VLM on Llama 2 7B | discretized action tokens | PyTorch |
The same lab shipped the successor. CrossFormer scaled the identical token-in, readout-out idea to 900K trajectories across 20 robot embodiments, including wheeled robots, quadcopters and quadrupeds, and drops even the manual alignment of observation and action spaces that Octo needed. Neither is a production choice today. For the wider map, the VLA overview covers the families and the arena has the numbers with a source link on every one.

- The cleanest published demonstration that a pretrained robot transformer can be refitted to a new sensor set and action space without retraining it.
- Genuinely small: 27M and 93M parameters, 13 to 17 model calls per second on one 4090.
- Fully open under MIT: pretraining pipeline, data mix constant, exact hyperparameters.
- The ablation and appendix are honest: the action head and data mix dominate, the visual backbone does not, and the failures are written down.
- No commits since 31 July 2024, pinned to jax 0.4.20 and tensorflow 2.15.0, 88 issues and 8 pull requests open.
- JAX and Flax, in an ecosystem that consolidated on PyTorch. No Octo policy class in LeRobot.
- No pretrained vision-language model underneath, so semantic generalization is weak next to a 2025-era VLA.
- RLDS in, so a conversion step for anyone whose data is already in LeRobot format.
Can you run Octo on an SO-100?
Technically yes, and nobody has made it easy. The missing pieces are the ones the repo never had: an RLDS conversion, a standardization transform, an action space decision (the default action_dim is 7, a 6-DoF end-effector delta plus a gripper, so a joint-space head for an SO-100 means declaring the dimension you command and rebuilding the head for it), and a serving loop that talks to your arm at a fixed rate. None of it is research. All of it is a week.
SO-100 and SO-101 use Feetech STS3215 bus servos on a 7.4 V rail. Feeding them 12 V destroys them, quietly enough that you will blame your policy first. Koch v1.1 uses Dynamixel servos on 5 V and 12 V rails; LeKiwi runs a 7.4 V arm on a 12 V base. Check the supply against the arm before every first power-up. See the SO-100 page and the failure-mode index.
The parts of this workflow that transfer to any policy are worth investing in: clean, consistently framed episodes, a rig that does not move between recording and inference, enough episodes for the objective to fit. Recording your first dataset and training your first policy walk that path with trainers already wired up, and the dataset directory shows what other people's episodes look like. No arm yet? The live arm streams a physical SO-100 you can drive from the browser without signing up.
Octo-Base at 13 calls per second is fast enough that the network becomes the bottleneck long before the model does. Per action step the platform's policies span 20 ms (ACT) to 485 ms (Pi0.5), and public-internet round trips turn any of them into a hesitant policy. Remote inference is viable for slow pick-and-place, not for fast reactive motion; if you need reactive control, inference sits next to the servos, and that is decided before you pick a model. See inference latency and policy freezes mid-motion.

Compare 85 VLA models with the sources attached
Octo-Base, Octo-Small, RT-1-X, RT-2-X, OpenVLA, CrossFormer and 79 more, with 332 benchmark results and a link from every number back to the paper or model card it came from.
Open the arenaFrequently asked questions
How many parameters does Octo have?▾
Octo-Small has 27M: 12 layers, hidden size 384, MLP size 1536, 6 heads, ViT-S shaped. Octo-Base has 93M: 12 layers, hidden size 768, MLP size 3072, 12 heads, ViT-B shaped. Those are the transformer figures from Table V; the frozen t5-base encoder is a further 111M parameters that never receive a gradient.
What is the difference between octo-base and octo-base-1.5?▾
Version 1.5 repeats the language task tokens at every timestep instead of only at the start, adds GPT-3.5 rephrasings of the training instructions, and fixes three bugs: dropout in the diffusion head conflicting with layer norm, an off-by-one in the attention mask, and image augmentations reusing random seeds. Every command in the README uses the 1.5 ids.
Can Octo be finetuned on a single consumer GPU?▾
Yes. The paper reports each finetuning setup running in under 5 hours on one NVIDIA A5000 with 24 GB of VRAM, on around 100 in-domain demonstrations and the same hyperparameters across all six domains. The obstacle is not VRAM, it is the pinned JAX 0.4.20 CUDA 11 environment and getting your data into RLDS.
Is Octo supported in LeRobot?▾
No. The LeRobot policy directory contains act, diffusion, groot, pi0, pi05, pi0_fast, smolvla, tdmpc, vqbet and newer entries, but no octo. Octo is JAX and Flax with its own RLDS pipeline, so there is no drop-in path from a LeRobot recording to an Octo finetune.
Should I use Octo for a new project?▾
As a production policy, probably not: no commits since 31 July 2024, a JAX build from November 2023, and no pretrained vision-language model underneath. As a thing to read and run once, it is still the clearest example of readout tokens, block-wise attention masking and a separate diffusion head. For a real arm, pick a policy that is maintained and has a serving path to your hardware.
Sources
- Octo: An Open-Source Generalist Robot Policy (arXiv 2405.12213)
- Octo, Robotics: Science and Systems 2024 proceedings, paper p090
- octo-models/octo reference implementation
- octo action_heads.py, the DiffusionActionHead defaults
- octo finetune_config.py, the real finetuning defaults
- octo oxe_dataset_mixes.py, the oxe_magic_soup constant
- octo example: finetuning to a new observation and action space
- rail-berkeley/octo-base-1.5 model card
- rail-berkeley/octo-small-1.5 model card
- Open X-Embodiment: Robotic Learning Datasets and RT-X Models
- Open X-Embodiment project page
- OpenVLA: An Open-Source Vision-Language-Action Model (source of the LIBERO table)
- Evaluating Real-World Robot Manipulation Policies in Simulation (SIMPLER)
- Scaling Cross-Embodied Learning (CrossFormer)
- huggingface/lerobot, the policy directory
Sources
- Octo: An Open-Source Generalist Robot Policy (arXiv 2405.12213)
- Octo, Robotics: Science and Systems 2024 proceedings, paper p090
- octo-models/octo reference implementation
- octo action_heads.py, the DiffusionActionHead defaults
- octo finetune_config.py, the real finetuning defaults
- octo oxe_dataset_mixes.py, the oxe_magic_soup constant
- octo example: finetuning to a new observation and action space
- rail-berkeley/octo-base-1.5 model card
- rail-berkeley/octo-small-1.5 model card
- Open X-Embodiment: Robotic Learning Datasets and RT-X Models
- Open X-Embodiment project page
- OpenVLA: An Open-Source Vision-Language-Action Model (source of the LIBERO table)
- Evaluating Real-World Robot Manipulation Policies in Simulation (SIMPLER)
- Scaling Cross-Embodied Learning (CrossFormer)
- huggingface/lerobot, the policy directory
Ready for high-quality robotics data?
AY-Robots connects your robots to skilled operators worldwide.
Get Started