VLA · Paper guide
SmolVLA: A vision-language-action model for affordable and efficient robotics
A 450-million-parameter robot policy built from community data, explained through the questions an engineer would ask.
This is a guide to the SmolVLA paper, not a sentence-by-sentence paraphrase. It shows how far a small vision-language-action model can go on low-cost robots, and it reuses ideas from the RT-2, π0 and Flow Matching guides: a pretrained vision-language model, a flow matching action expert and chunked actions. Part A is a 4-minute overview. Parts B to D explain the method, the data and the experiments one idea at a time. Equations and tables are folded away in Part E, and Part F is a critical review of the paper’s text, tables and claims.
How to use this page
- In a hurry: read Part A (about 4 minutes).
- To understand the method: add Parts B to D. Each idea follows the same pattern: intuition, the problem it solves, how it works, an example, then technical details and where to find them in the paper.
- To check or rebuild it: open the folded sections (equations, the control loop, the ablation tables, runnable examples) and read Part F.
Open the paper (arXiv:2506.01844) beside this page; section, table and figure references are to it. We paraphrase and never reproduce its text. Statements are labelled so you can tell them apart: Reported by the paper, Our calculation from the paper’s numbers, and Our interpretation. Runnable examples are marked Toy illustration when they are our own small model of an idea, and are never presented as results of the paper.
Part A · about 4 minutes
Start here: the paper at a glance
The problem
Vision-language-action (VLA) models, which read camera images and an instruction and output robot actions, are usually large: billions of parameters, expensive to train and hard to run on the hardware an ordinary lab or hobbyist owns. Much of the best work is also proprietary, or shares only weights. The authors, at Hugging Face, ask whether a small VLA, trained on data that the robotics community has collected on low-cost robots and runnable on a consumer graphics card, can still compete.[1]
The main contribution
- A compact architecture. A small pretrained vision-language model (VLM), the model that reads images and text, is cut to its first half of layers. It feeds an “action expert” of about 100 million parameters that is trained with flow matching to output a chunk of 50 actions at once; the main model has 450 million parameters in total.[2]
- Pretraining on community data. About 23 thousand episodes from 481 community datasets, with messy task descriptions regenerated by another VLM and camera views put in a standard order.[2]
- Asynchronous inference. A control loop that asks for the next chunk of actions while the robot is still executing the current one, so it does not stand still waiting for the model.[2]
How the model works, in one paragraph
Up to three camera images, the instruction (for example “put the red cube in the right box”) and the robot’s joint readings are turned into tokens. The vision-language model, with only the first 16 of its language-model layers kept and frozen, turns them into features. An action expert, a small transformer that alternates between looking at those features (cross-attention) and looking at its own action tokens (causal self-attention), starts from random noise and, in 10 steps of flow matching, produces 50 future actions. The robot executes them and the loop repeats. In the real-world tests the robot finishes a chunk before asking again; the paper’s asynchronous stack instead requests the next chunk early.
What it learns from, and what it is tested on
Learns from: the 481 community datasets (22.9 thousand episodes, 10.6 million frames, recorded mostly on low-cost SO100 arms), then fine-tuning on small task datasets of 50 demonstrations each in the real world, or 1,693 to 2,500 episodes in simulation. Tested on: two simulated benchmarks, LIBERO (40 tasks) and Meta-World (50 tasks), and four simple real-world tasks on two low-cost arms: pick and place, stacking, sorting and picking up a small lego brick. Baselines include the larger π0 model and a small policy called ACT (Action Chunking with Transformers).
What the paper reports
| Test | SmolVLA (0.45B) | Comparison |
|---|---|---|
| LIBERO average (%) | 87.3 | 86.0 (π0, 3.3B); 76.5 (OpenVLA, 7B) |
| Meta-World average (%) | 57.3 | 47.9 (π0, 3.5B) |
| Real-world average, three SO100 tasks (%) | 78.3 | 61.7 (π0); 48.3 (ACT) |
| Effect of community pretraining (%) | 51.7 without, 78.3 with | same model, multi-task |
| Time per pick-and-place | 9.70 s asynchronous | 13.75 s synchronous |
What to keep in mind
- The tasks are short and simple, the real-world fine-tuning sets have 50 demonstrations, and the success rates come from small numbers of trials without repeated runs; many gaps are within chance.
- The paper never tests whether the pretrained vision-language model helps, and no test asks for knowledge beyond the training tasks.
- The efficiency claims (training cost, memory, running on a CPU) are stated, with almost no measurements.
- A few statements in the text are contradicted by the paper’s own tables, and the flow matching target is printed with the opposite sign from its own path (Part F).
If you read nothing else: SmolVLA shows that a 450-million-parameter vision-language-action model, pretrained on about 23 thousand community episodes, can match or beat a model seven times larger on simple simulated and real tasks, and that requesting actions early makes a real robot about 30% faster; the evidence is thin on trial counts, on measured efficiency and on whether the language model matters.
Check your understanding: Why does the paper keep only the first half of the vision-language model’s layers?
It makes inference faster and the model smaller, and the authors argue that features from a middle layer are not worse for control than the last layer’s. Their ablation shows 16 of 32 layers scoring close to using all of them.
Part B
Understand the method
SmolVLA is built from three decisions: take a small vision-language model and use only part of it, add a small action expert that generates a chunk of actions with flow matching, and run the control loop so that the next chunk is requested early. Each idea below follows the same pattern, from intuition to where to find it in the paper.
1. A small vision-language model plus an action expert
- Intuition
- Use a ready-made, small model that understands pictures and words as the eyes and ears, and train a still smaller network to be the hands.
- The problem it solves
- Large VLAs cost a lot to train and to run, and they are hard to use on low-cost hardware.
- How it works
- SmolVLA has two parts that are connected by attention. The perception part is SmolVLM-2, a small vision-language model that pairs a vision encoder (SigLIP) with a language model (SmolLM2) and is made for several images and video. The action part is an action expert, trained from scratch with flow matching. The main model has 450 million parameters, about 100 million of them in the action expert, and the paper also reports a 0.24-billion and a 2.25-billion-parameter version. Only the action expert is trained; the vision-language model stays frozen.
- Example
- Illustration, not from the paper An image from above the table, an image from the wrist camera and the sentence “pick up the cube and put it in the box” go in; fifty small joint movements come out.
- Why the authors chose it
- A small backbone and a small expert keep training and inference cheap, and reusing a pretrained model avoids learning to see from scratch.
- Technical details
Our calculation By our arithmetic the vision-language part is about 350 million of the 450 million parameters and the expert about 22%. The paper’s statement that it keeps 16 layers as half of the total implies a language model of 32 layers. The comparison models are 7.3 times larger (π0 at 3.3 billion) to 15.6 times larger (OpenVLA at 7 billion). The example also lists what the paper says, and does not say, about cost.
Run the example: size and cost
Our calculationWhat each part does
- Split the 450 million parameters into the expert and the rest.
- Compare the size with the models the paper compares against.
- Work out what the stated 30,000 GPU hours mean, and list the cost figures the paper does not give.
# Size and cost figures, as stated in the paper (Sections 3.1, 4.3, 4.4 and 5.1). total, expert = 450e6, 100e6 print(f"action expert share of the main model: {expert / total:.0%}; the rest ({(total - expert) / 1e6:.0f} M) is the cut-down vision-language model") print(f"the paper keeps the first N = 16 layers, which it calls N = L/2, so the language model has L = {2 * 16} layers") print() print("how much larger are the comparison models?") for name, size in (("pi0 as stated in Section 4.4 and Table 2 (3.3B)", 3.3e9), ("pi0 as labelled in Tables 2 and 3 for Meta-World and real world (3.5B)", 3.5e9), ("OpenVLA (7B)", 7e9)): print(f" {name:72s} {size / total:5.1f} times") print('the abstract says "10x larger"; the text says about 7x for pi0') print() gpu_hours, gpus = 30_000, 4 print(f"project total of {gpu_hours} GPU hours; on {gpus} GPUs that would be {gpu_hours / gpus:.0f} hours = {gpu_hours / gpus / 24:.0f} days") print("the paper gives no GPU hours for the main pretraining run alone, and no inference latency, memory or CPU figures") print("it states 'about 40% faster to train and 6 times less memory' than pi0, without a table")Output:
action expert share of the main model: 22%; the rest (350 M) is the cut-down vision-language model the paper keeps the first N = 16 layers, which it calls N = L/2, so the language model has L = 32 layers how much larger are the comparison models? pi0 as stated in Section 4.4 and Table 2 (3.3B) 7.3 times pi0 as labelled in Tables 2 and 3 for Meta-World and real world (3.5B) 7.8 times OpenVLA (7B) 15.6 times the abstract says "10x larger"; the text says about 7x for pi0 project total of 30000 GPU hours; on 4 GPUs that would be 7500 hours = 312 days the paper gives no GPU hours for the main pretraining run alone, and no inference latency, memory or CPU figures it states 'about 40% faster to train and 6 times less memory' than pi0, without a table
Arithmetic on numbers stated in Sections 3.1, 4.3 and 4.4.
- Evidence in the paper
- Abstract · §3.1 · §4.3 · §4.4 · Figure 1
Check your understanding: Which part of SmolVLA is trained, and which is frozen?
The action expert (and the small linear projection layers) is trained; the vision-language model is frozen. The paper states this in the implementation details.
2. What goes in: images, an instruction and the robot’s state
- Intuition
- Three kinds of input are all turned into the same kind of object, a token, so one transformer can read them together.
- The problem it solves
- High-resolution images produce very many tokens, which makes inference slow and, on a robot, too slow to be useful.
- How it works
- Each camera image is resized to 512 by 512 and encoded. SmolVLM-2 normally also looks at several crops of the same image (tiling); SmolVLA uses only the whole image, and a pixel shuffle operation that limits the visual tokens to 64 per frame. The instruction is split into text tokens. The robot’s joint readings, its state, are turned into a single token by a linear layer. The three kinds of tokens are concatenated and passed to the language model.
- Example
- Illustration, not from the paper Two cameras and a 12-word instruction: 128 visual tokens, about a dozen text tokens and one state token, so the transformer reads roughly 140 tokens.
- Why the authors chose it
- Fewer visual tokens make every later step cheaper, and the paper treats the image-token count as one of its main efficiency choices.
- Technical details
- The paper does not give the patch size or the shuffle factor. A pixel shuffle moves each small block of neighbouring tokens into the feature dimension, giving fewer, wider tokens without discarding numbers. The example below assumes 16 by 16 patches and a factor of 4, which is one way to get 64 tokens.
Run the example: pixel shuffle
Toy illustrationWhat each part does
- Cut a 512 by 512 image into 16 by 16 patches and count the tokens.
- Apply a pixel shuffle with factor 4 and count again.
- Undo the shuffle to show that nothing was lost.
import numpy as np # Visual token reduction (Section 3.1): "pixel shuffle" limits the visual tokens to 64 per frame. # The paper does not give the patch size or the shuffle factor. We assume 16 x 16 patches and a factor of 4, # which is one way to get 64 tokens from a 512 x 512 image. image, patch, factor = 512, 16, 4 grid = image // patch # patches along each side tokens = grid * grid print(f"{image} x {image} image, {patch} x {patch} patches: {grid} x {grid} = {tokens} tokens") dim = 8 # a tiny feature size, to keep the example small x = np.random.default_rng(0).normal(size=(grid, grid, dim)) def pixel_shuffle(x, f): # move each f x f block of neighbouring tokens into the feature dimension: fewer tokens, wider features g, _, d = x.shape return x.reshape(g // f, f, g // f, f, d).transpose(0, 2, 1, 3, 4).reshape(g // f, g // f, f * f * d) y = pixel_shuffle(x, factor) print(f"after pixel shuffle with factor {factor}: {y.shape[0]} x {y.shape[1]} = {y.shape[0] * y.shape[1]} tokens, each with {y.shape[2]} features (was {dim})") print("numbers stored before and after:", x.size, y.size, "(nothing is thrown away)") # the shuffle can be undone exactly def unshuffle(y, f): g, _, d = y.shape return y.reshape(g, g, f, f, d // (f * f)).transpose(0, 2, 1, 3, 4).reshape(g * f, g * f, d // (f * f)) print("exactly reversible:", bool(np.array_equal(unshuffle(y, factor), x)))Output:
512 x 512 image, 16 x 16 patches: 32 x 32 = 1024 tokens after pixel shuffle with factor 4: 8 x 8 = 64 tokens, each with 128 features (was 8) numbers stored before and after: 8192 8192 (nothing is thrown away) exactly reversible: True
The patch size and factor are our assumptions, chosen to give 64 tokens.
- Evidence in the paper
- §3.1 “Vision-language model”, “Visual tokens reduction” · §4.3
Check your understanding: Why is a pixel shuffle different from simply shrinking the image?
The shuffle keeps all the numbers: it trades the number of tokens for wider tokens. Shrinking the image would discard detail.
3. Skipping layers: use the middle of the network, not the end
- Intuition
- The best summary of a scene for control may sit halfway through the language model, not at its last layer.
- The problem it solves
- Running all the layers of the vision-language model, and giving the expert features of the same width, costs time at every control step.
- How it works
- The action expert reads features from layer N of the language model, not from its last layer, and the layers above N are discarded before training starts. The authors set N to half of the total number of layers, 16 of 32, which they say halves the cost of the language model and of the action expert. They cite earlier work that found the best features for downstream tasks are not always in the last layer.
- Example
- Illustration, not from the paper Think of reading a book to the middle and writing a summary: you save half the reading time, and the summary can be nearly as good for the one purpose it is for.
- Why the authors chose it
- It is a cheap way to cut inference time and parameters without retraining a smaller model.
- Technical details
- The ablation (Table 8, in Part D) compares N = 8, 16, 24 and 32, a variant that keeps every second layer, and a smaller 256-million-parameter vision-language model. N = 16 scores 78.5, N = 32 scores 80.3 and the smaller model scores 75.8, on a benchmark where chance alone moves a score by about 2 points.
- Evidence in the paper
- §3.1 “Faster inference through layer skipping” · §4.7 · Table 8
Check your understanding: What trade does N = L/2 make?
A little accuracy (78.5 against 80.3 for all layers in the paper’s table) for about half the language-model compute.
4. The flow matching action expert
- Intuition
- Start from random actions and, in ten small steps, nudge them towards a sensible chunk of future movements.
- The problem it solves
- A policy must produce smooth, correct actions even when several different actions would be reasonable, such as going around an obstacle to the left or right.
- How it works
- During training, a chunk of real actions is blended with noise, with a random blending weight τ between 0 (pure noise) and 1 (the real actions), and the expert learns to predict the direction that leads back to the real chunk, given the vision-language features. The blending weights are drawn from a Beta distribution, as in π0. At run time the expert starts from noise and follows its predicted direction in 10 steps. The expert’s hidden size is 0.75 times the vision-language model’s, to save time, and it outputs n = 50 actions per chunk. The paper compares this training with a plain regression loss and finds flow matching better (Part D).
- Example
- Illustration, not from the paper A random 50-step trajectory, nudged ten times, turns into the smooth movement that the camera images and the instruction call for.
- Why the authors chose it
- Flow matching handles several valid actions better than a regression that predicts their average.
- Technical details
- The flow matching method itself is explained in the Flow Matching and Rectified Flow guides, and π0’s action expert in the π0 guide. As in the π0 and GR00T N1 papers, the printed target has the opposite sign from the printed path; Part F checks this numerically.
- Evidence in the paper
- §3.1 “Flow matching action expert” · §4.3 · Table 10
Check your understanding: Why does the expert predict a direction towards the actions rather than the actions themselves?
The direction is a simple regression target that can be trained for any blend of noise and data, and following it step by step lets the model represent several different valid action chunks.
5. Interleaved cross-attention and causal self-attention
- Intuition
- The action tokens alternately look at what the VLM saw and at the actions planned so far.
- The problem it solves
- The expert must use the vision-language features, and must make a chunk whose actions fit together.
- How it works
- Layers of the action expert alternate. In a cross-attention layer, the action tokens ask questions of the vision-language features, which supply the keys and values. In a self-attention layer, the action tokens look at each other, with a causal mask so that each action token sees only the earlier ones in the chunk. The authors say the interleaving gives higher success and faster inference than either kind alone, and that the self-attention layers make the chunk smoother on real robots.
- Example
- Illustration, not from the paper When planning the fifth action, a cross-attention layer reads the scene; a self-attention layer reads actions one to four.
- Why the authors chose it
- Cross-attention only touches the vision-language features once per layer, which is cheaper than concatenating everything into one long sequence.
- Technical details
- The example is a tiny version with random numbers: it checks that a causal mask stops information flowing from a later action to an earlier one, while a bidirectional layer does not. It illustrates the mask, not the trained model.
Run the example: the two kinds of attention
Toy illustrationWhat each part does
- Build a small cross-attention layer, a causal self-attention layer and a bidirectional one with random weights.
- Change only the last action token.
- See which outputs change in each kind.
import numpy as np # The action expert's two kinds of attention layer (Section 3.1), in a tiny version with random weights. rng = np.random.default_rng(0) d, n_actions, n_vlm = 4, 6, 8 Wq, Wk, Wv = (rng.normal(size=(d, d)) for _ in range(3)) vlm = rng.normal(size=(n_vlm, d)) # features from the vision-language model actions = rng.normal(size=(n_actions, d)) # noisy action tokens def attend(queries, keys_values, mask=None): q, k, v = queries @ Wq, keys_values @ Wk, keys_values @ Wv scores = q @ k.T / np.sqrt(d) if mask is not None: scores = np.where(mask, scores, -1e9) w = np.exp(scores - scores.max(axis=1, keepdims=True)) return (w / w.sum(axis=1, keepdims=True)) @ v causal = np.tril(np.ones((n_actions, n_actions), dtype=bool)) print("causal mask (row = action token, column = token it may look at):") for row in causal.astype(int): print(" ", " ".join(map(str, row))) # Change only the LAST action token and see which outputs move. changed = actions.copy() changed[-1] += 5.0 for name, mask in (("causal self-attention", causal), ("bidirectional self-attention", None)): before, after = attend(actions, actions, mask), attend(changed, changed, mask) moved = np.abs(after - before).max(axis=1) > 1e-9 print(f"{name:30s} outputs that change when the last token changes: {moved.astype(int).tolist()}") # Cross-attention: the keys and values come from the VLM, so action tokens do not exchange information with each other. before, after = attend(actions, vlm), attend(changed, vlm) moved = np.abs(after - before).max(axis=1) > 1e-9 print(f"{'cross-attention':30s} outputs that change when the last token changes: {moved.astype(int).tolist()}")Output:
causal mask (row = action token, column = token it may look at): 1 0 0 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 1 1 1 0 0 1 1 1 1 1 0 1 1 1 1 1 1 causal self-attention outputs that change when the last token changes: [0, 0, 0, 0, 0, 1] bidirectional self-attention outputs that change when the last token changes: [1, 1, 1, 1, 1, 1] cross-attention outputs that change when the last token changes: [0, 0, 0, 0, 0, 1]
Random weights and a tiny size; it shows what the mask does.
- Evidence in the paper
- §3.1 “Interleaved cross and causal self-attention layers” · §4.7 · Tables 6 and 7
Check your understanding: What does the causal mask prevent?
A later action in the chunk influencing the processing of an earlier one; each action token can use only the actions before it.
6. Asynchronous inference: act while thinking
- Intuition
- Order the next course while the current one is still being eaten, so the table never sits empty.
- The problem it solves
- If the robot executes a whole chunk and only then asks for the next one, it stands idle while the model computes, and it cannot react in between.
- How it works
- A robot client keeps a queue of actions. When the queue has fewer than a fraction g of a chunk left, the client captures a new observation and sends it to a policy server, which can be on another machine. The robot keeps consuming actions while the server works; when the new chunk arrives, its overlap with the old queue is merged. To avoid redundant calls, a new observation is skipped if the joint readings are almost the same as the last one processed, unless the queue is empty. The authors derive that the queue never empties when g is at least the number of steps the server takes divided by the chunk size.
- Example
- Illustration, not from the paper A chunk lasts 1.67 seconds at 30 frames per second. If the server needs 0.5 seconds, the client must ask when at least 30% of the chunk is left.
- Why the authors chose it
- It removes idle gaps, lets the policy run on a stronger remote machine and keeps the average computing load low compared with asking at every step.
- Technical details
Our calculation The example works the paper’s condition for the stated 30 frames per second and 50-action chunks. For a latency of 0.3 seconds the queue never empties with g of 0.18 or more, and a synchronous cycle idles for 15% of the time. The paper does not report the values of g or of the similarity threshold used in its real-world async experiments, nor how the old and new chunks are merged.
Run the example: how long can the queue run dry?
Our calculationWhat each part does
- Take a chunk of 50 actions at 30 frames per second.
- For several latencies, find the smallest g that avoids an empty queue and the idle share of a synchronous cycle.
- Count server calls per second for g of 0, 0.7 and 1.
import math # Section 3.3: an action queue of n actions, a control step of dt seconds, a policy latency l seconds. n = 50 # chunk size (Section 4.3) dt = 1 / 30 # 30 frames per second (Section 3.3) print(f"one chunk lasts n * dt = {n * dt:.2f} s") print() print("latency | smallest g that avoids an empty queue | idle share of a synchronous cycle") for latency in (0.1, 0.3, 0.5, 1.0, 1.5): g_min = (latency / dt) / n # the paper's condition: g >= (E[l] / dt) / n idle = latency / (n * dt + latency) # synchronous: run a chunk, then wait for the next print(f"{latency:5.1f} s | {g_min:37.2f} | {idle:5.0%}") g = 0.7 print() print(f"with g = {g}: the longest latency that can be hidden is g * n * dt = {g * n * dt:.2f} s") print(f"with g = {g}: a new observation is sent every (1 - g) * n * dt = {(1 - g) * n * dt:.2f} s") for name, gg in (("g = 0 (synchronous)", 0.0), ("g = 0.7", 0.7), ("g = 1", 1.0)): # observations sent per second when the latency is 0.3 s (no similarity filter) interval = n * dt + 0.3 if gg == 0 else max((1 - gg) * n * dt, dt) print(f"{name:20s} server calls per second: {1 / interval:5.2f}")Output:
one chunk lasts n * dt = 1.67 s latency | smallest g that avoids an empty queue | idle share of a synchronous cycle 0.1 s | 0.06 | 6% 0.3 s | 0.18 | 15% 0.5 s | 0.30 | 23% 1.0 s | 0.60 | 37% 1.5 s | 0.90 | 47% with g = 0.7: the longest latency that can be hidden is g * n * dt = 1.17 s with g = 0.7: a new observation is sent every (1 - g) * n * dt = 0.50 s g = 0 (synchronous) server calls per second: 0.51 g = 0.7 server calls per second: 2.00 g = 1 server calls per second: 30.00
Arithmetic on the paper’s formula; latencies are examples.
- Evidence in the paper
- §3.3 · Algorithm 1 · Figures 2 and 3 · §4.6
Check your understanding: What does g = 1 do, and why is it expensive?
The client sends a new observation at every control step, so the queue is always full, but the model runs once per step, which can be too much for low-cost hardware.
Part C
Understand the data and the training
The training story is about the data. The model is small and the vision-language part is frozen, so the question is what the action expert learns from, and how messy volunteer-recorded data was made usable.
Community datasets: plentiful, varied and noisy
- Intuition
- Instead of one lab’s carefully collected set, the model learns from hundreds of small sets that hobbyists and labs recorded on low-cost robots.
- The problem it solves
- Robot data is scarce, and large collections are separate “islands” with different robots, cameras, control rates and formats.
- How it works
- The authors select a subset of community datasets from Hugging Face, filtered by embodiment type, number of episodes, overall quality and frame coverage. The result is 481 datasets, 22.9 thousand episodes and 10.6 million frames. Unlike datasets that follow one protocol, these contain different robots, camera positions and tasks, and noisy demonstrations. The paper counts this as an advantage for pretraining.
- Example
- Illustration, not from the paper One dataset has a few dozen episodes of putting a lego brick in a box, another has someone sorting fruit, a third plays chess; all were recorded on similar arms with their own cameras.
- Why the authors chose it
- It uses data that already exists and is openly available, in an amount that one group can handle.
- Technical details
Table 1, as printed. Datasets Episodes Frames 481 22.9 thousand 10.6 million Our calculation That is 463 frames per episode, about 15 seconds at 30 frames per second, and about 98 hours in total if every dataset ran at 30 frames per second. It is a pretraining set with 44 times fewer episodes than OpenVLA’s roughly one million trajectories. The example also shows our count of the dataset names in Appendix A.1, which does not match 481.
Run the example: the pretraining data
Our calculationWhat each part does
- Divide frames by episodes and convert to time.
- Compare with the episode count the paper quotes for OpenVLA.
- Compare the number of datasets in Table 1 with the names printed in Appendix A.1.
# The pretraining data (Table 1 and Appendix A.1). The counts of dataset names are ours, from the printed list. episodes = 22_900 frames = 10_600_000 datasets_table = 481 datasets_listed = 532 # distinct names printed in Appendix A.1 fps = 30 # the real-world frame rate quoted in Section 3.3; community datasets may differ openvla_episodes = 1_000_000 # "around 1 million trajectories" (Section 5.1) print(f"frames per episode: {frames / episodes:.0f} ({frames / episodes / fps:.1f} s at {fps} frames per second)") print(f"total length: {frames / fps / 3600:.0f} hours at {fps} frames per second") print(f"OpenVLA episodes / SmolVLA episodes: {openvla_episodes / episodes:.0f}") print(f"Table 1 caption says about 10M episodes; the table says {episodes} episodes -> factor {10_000_000 / episodes:.0f}") print(f"datasets in Table 1: {datasets_table}; names printed in Appendix A.1: {datasets_listed}; difference {datasets_listed - datasets_table}") samples = 200_000 * 256 # steps x global batch size (Section 4.3) print(f"pretraining samples: {samples / 1e6:.1f} million = {samples / frames:.1f} passes over {frames / 1e6:.1f} million frames") print() print("dataset names in Appendix A.1 that contain a keyword (our count, names only):") for word, count in (("stack", 9), ("sort", 12), ("pick", 66), ("place", 50), ("lego", 20), ("so101", 0)): print(f" {word:6s} {count:3d}") print("the four real-world tasks are pick-place, stacking, sorting and pick-place with a lego brick on another arm")Output:
frames per episode: 463 (15.4 s at 30 frames per second) total length: 98 hours at 30 frames per second OpenVLA episodes / SmolVLA episodes: 44 Table 1 caption says about 10M episodes; the table says 22900 episodes -> factor 437 datasets in Table 1: 481; names printed in Appendix A.1: 532; difference 51 pretraining samples: 51.2 million = 4.8 passes over 10.6 million frames dataset names in Appendix A.1 that contain a keyword (our count, names only): stack 9 sort 12 pick 66 place 50 lego 20 so101 0 the four real-world tasks are pick-place, stacking, sorting and pick-place with a lego brick on another arm
Arithmetic on Table 1; the count of dataset names and keywords is ours, made from the printed list.
- Evidence in the paper
- §3.2 · Table 1 · Appendix A.1
Check your understanding: Why might heterogeneous community data be useful for pretraining despite being noisy?
It covers many scenes, cameras, objects and demonstrators, so the model is less tied to one setup; the paper reports a large gain from this pretraining on real-world tasks.
Cleaning the data: task descriptions and camera views
- Intuition
- Before the model can learn from volunteers’ data, the labels and camera names have to mean the same thing everywhere.
- The problem it solves
- Task descriptions in community datasets were often placeholders (such as “task desc”), too vague (“Hold”, “Up”) or missing, and cameras with the same name could show different views.
- How it works
- For each dataset the authors sampled representative frames and gave them, with the original instruction, to an off-the-shelf vision-language model, Qwen2.5-VL-3B-Instruct, which was asked for a short, action-oriented sentence of at most 30 characters. They also mapped each camera by hand to a standard view type: top, wrist and side became image 1, 2 and 3, extra views kept their order, and unused views were dropped during training.
- Example
- Illustration, not from the paper A dataset with the instruction “Hold” and a video of a cube going into a box becomes “Place the cube in the box”.
- Why the authors chose it
- The authors found the inconsistent camera naming harmful in pretraining, and consistent ordering helpful in this data regime.
- Technical details
- The paper says that future work could automate the camera mapping with vision-language models, and gives no measurement of how much the new descriptions or the camera ordering help; the effect of camera ordering is stated as an observation.
- Evidence in the paper
- §3.2 “Task annotation with VLM”, “Camera viewpoint normalization” · Appendix A.1
Check your understanding: What could go wrong with machine-written task descriptions?
The vision-language model might describe the wrong action, or give the same sentence to different tasks; the paper does not report an accuracy check of the descriptions.
Pretraining and fine-tuning recipe
- Intuition
- Learn general control from many small datasets first, then specialise to the task you want.
- The problem it solves
- Fifty demonstrations are too few to train a policy from a pretrained image model alone.
- How it works
- The model is pretrained on all the community data for 200,000 steps with a global batch size of 256, with a learning-rate schedule of a 100-step warm-up and a cosine decay from 1e-4 to 2.5e-6, using the AdamW optimiser, with images resized to 512 by 512. Only the action expert is trained. Training uses bfloat16 precision and torch.compile with a fixed sequence length and batch size. Pretraining used 4 GPUs, although the authors say a single GPU would do because of the model’s size, and the whole project used about 30,000 GPU hours. For simulation, the model is fine-tuned for 100,000 steps at batch size 64; for the real-world tasks, for 200,000 steps, though the authors note that far fewer steps work almost as well.
- Example
- Illustration, not from the paper Pretrain once on 22.9 thousand mixed episodes, then fine-tune a copy on the 50 demonstrations of the cube-stacking task.
- Why the authors chose it
- Pretraining on community data is the paper’s answer to having little task-specific data.
- Technical details
Sections 4.3 and 3.1, as printed. Setting Value Pretraining steps, batch size 200,000; 256 Learning rate 1e-4, cosine to 2.5e-6, 100 warm-up steps Optimiser AdamW (β1 = 0.9, β2 = 0.95) Image size 512 by 512 Action chunk, flow matching steps 50 actions; 10 steps Simulation fine-tuning 100,000 steps, batch size 64 Real-world fine-tuning 200,000 steps (batch size not stated) - Evidence in the paper
- §4.3
Check your understanding: Why can the model be trained on a single GPU if pretraining used four?
The authors say the small size allows it; the four GPUs were used to fit the large batch. The paper does not report the time or memory a single GPU would need.
Part D
Understand the experiments
The experiments have four parts: two simulated benchmarks, four small real-world tasks, a comparison of synchronous and asynchronous inference, and a set of ablations on the design choices. This part explains how each was set up, what the tables say and what they can and cannot show. Our re-calculations are in the folded examples.
The set-up: benchmarks, robots, baselines and scoring
- How it works
- In simulation, LIBERO has four groups (Spatial, Object, Goal, Long) of 10 tasks, with a training set of 1,693 episodes, and Meta-World has 50 tasks of four difficulty levels (easy, medium, hard, very hard), with 50 demonstrations per task collected by the authors. Both are scored with 10 trials per task, and a trial counts only if the task is completed. In the real world there are three tasks on the SO100 arm (pick and place a cube into a box, stack a red cube on a blue one, sort a red and a blue cube into two boxes) and a pick-and-place of a small lego brick into a transparent box on the SO101 arm. Each real-world dataset has 50 demonstrations, 10 for each of 5 starting positions. Real-world scores give partial credit: half for the grasp and half for the placement, or a quarter for each of four sub-steps when sorting. The SO100 and SO101 are low-cost, 3D-printable six-degree-of-freedom arms; simulation uses a Franka Panda (7 degrees of freedom) in LIBERO and a four-degree-of-freedom Sawyer arm in Meta-World. The baselines are π0 (3.3 billion parameters, pretrained on 10,000 hours of cross-embodiment data and fine-tuned on each target dataset), ACT (about 80 million parameters, trained from scratch on each dataset), and in simulation published numbers for Octo, OpenVLA, Diffusion Policy and TinyVLA.
- Technical details
Our calculation With 10 trials per task, a LIBERO suite has 100 trials and the four-suite average 400, so a success rate near 80% carries a standard error of about 2 points (a 95% interval of about ±3.9) if the trials were independent. The paper reports one run per entry. The number of real-world trials per task is not stated.
Run the example: how much a success rate can move by chance
Our calculationWhat each part does
- Work out the number of trials behind a suite and the four-suite average.
- Express the gaps behind the main statements in standard errors.
- List the numbers that look like the same configuration in different tables, and their spread.
import math # How much can a LIBERO success rate move by chance? 10 tasks per suite and 10 trials per task (Section 4.1). trials_suite, trials_average = 100, 400 def se(p, n): # standard error of a success rate p out of n independent trials, in percentage points return 100 * math.sqrt(p * (1 - p) / n) print(f"one suite (n = {trials_suite}) at 80%: standard error {se(0.8, trials_suite):.1f} points") print(f"four-suite average (n = {trials_average}) at 80%: standard error {se(0.8, trials_average):.1f} points; 95% interval about +-{1.96 * se(0.8, trials_average):.1f}") def gap(a, b, name): pa, pb = a / 100, b / 100 s = math.sqrt((se(pa, trials_average)) ** 2 + (se(pb, trials_average)) ** 2) print(f"{name:52s} {a:6.2f} vs {b:6.2f}: gap {a - b:+5.1f}, {abs(a - b) / s:3.1f} standard errors") print() print("gaps behind the paper's main statements (independent trials assumed)") gap(87.3, 86.0, "SmolVLA 0.45B against pi0 3.3B, LIBERO (Table 2)") gap(85.5, 79.0, "CA+SA against CA (Table 6)") gap(79.0, 74.5, "CA against SA (Table 6)") gap(74.5, 67.5, "causal against bidirectional (Table 7)") gap(80.25, 75.25, "flow matching against regression (Table 10)") gap(84.0, 80.3, "chunk size 10 against 50 (Table 12)") gap(80.3, 51.8, "update every step against every 50 steps (Table 13)") # The same-looking configuration, as it appears in different tables same = {"Table 6, CA": 79.0, "Table 8, N = 32": 80.3, "Table 9, x1.00": 82.3, "Table 10, flow matching": 80.25, "Table 11, prefix + CA": 80.3, "Table 12, chunk 50": 80.3, "Table 13, 1 step": 80.3} vals = sorted(set(same.values())) print() print("rows that look like the same configuration:", vals) print(f"spread between runs: {max(vals) - min(vals):.1f} points")Output:
one suite (n = 100) at 80%: standard error 4.0 points four-suite average (n = 400) at 80%: standard error 2.0 points; 95% interval about +-3.9 gaps behind the paper's main statements (independent trials assumed) SmolVLA 0.45B against pi0 3.3B, LIBERO (Table 2) 87.30 vs 86.00: gap +1.3, 0.5 standard errors CA+SA against CA (Table 6) 85.50 vs 79.00: gap +6.5, 2.4 standard errors CA against SA (Table 6) 79.00 vs 74.50: gap +4.5, 1.5 standard errors causal against bidirectional (Table 7) 74.50 vs 67.50: gap +7.0, 2.2 standard errors flow matching against regression (Table 10) 80.25 vs 75.25: gap +5.0, 1.7 standard errors chunk size 10 against 50 (Table 12) 84.00 vs 80.30: gap +3.7, 1.4 standard errors update every step against every 50 steps (Table 13) 80.30 vs 51.80: gap +28.5, 8.9 standard errors rows that look like the same configuration: [79.0, 80.25, 80.3, 82.3] spread between runs: 3.3 points
Our calculation; it assumes independent trials, which is not exactly true for repeated tasks.
- Evidence in the paper
- §4.1 · §4.2 · §4.3 · §4.4
Check your understanding: Why do real-world scores come in steps of 0.5 or 0.25?
The tasks are split into sub-steps (grasp, place, and so on) and each completed sub-step earns partial credit, so a failed placement after a good grasp still scores something.
Simulation: LIBERO and Meta-World (Table 2)
- How it works
- On LIBERO the 0.45-billion-parameter model averages 87.3%, against 86.0% for the robotics-pretrained π0 (3.3 billion), 71.8% for π0 initialised only from its vision-language model, 76.5% for OpenVLA (7 billion), 75.1% for Octo and 72.4% for Diffusion Policy. On Meta-World it averages 57.3%, against 47.9% for the pretrained π0 and 50.5% for the vision-language-initialised one. The paper’s two larger and smaller versions of SmolVLA score 82.75% and 88.75% on LIBERO and 56.95% and 68.24% on Meta-World. The authors also say that SmolVLA trains about 40% faster than π0 and uses 6 times less memory. In simulation, SmolVLA is not pretrained on robot data; it starts from the vision-language model only.
- Technical details
Table 2, LIBERO, success rate in percent, as printed. Policy Spatial Object Goal Long Average Diffusion Policy 78.3 92.5 68.3 50.5 72.4 Octo (0.09B) 78.9 85.7 84.6 51.1 75.1 OpenVLA (7B) 84.7 88.4 79.2 53.7 76.5 π0 (Paligemma-3B) 87 63 89 48 71.8 π0 (3.3B) 90 86 95 73 86.0 SmolVLA (0.24B) 87 93 88 63 82.75 SmolVLA (0.45B) 90 96 92 71 87.3 SmolVLA (2.25B) 93 94 91 77 88.75 Table 2, Meta-World, success rate in percent, as printed. Policy Easy Medium Hard Very hard Average Diffusion Policy 23.1 10.7 1.9 6.1 10.5 TinyVLA 77.6 21.5 11.4 15.8 31.6 π0 (3.5B-Paligemma) 80.4 40.9 36.7 44.0 50.5 π0 (3.5B) 71.8 48.2 41.7 30.0 47.9 SmolVLA (0.24B) 86.43 46.36 35 60 56.95 SmolVLA (0.45B) 82.5 41.8 45.0 60.0 57.3 SmolVLA (2.25B) 87.14 51.82 70 64 68.24 Our calculation The Meta-World average is the plain mean of the four difficulty groups, not of the 50 tasks. The printed decimals fit 28, 11, 6 and 5 tasks with 10 trials each, and weighting by tasks gives 66.80 for the 0.45-billion model and 58.82 for π0 (3.5B) (Part F).
Run the example: Meta-World averages and task counts
Our calculationWhat each part does
- Type in the Meta-World rows.
- Check that the printed average is the mean of the four groups.
- Check which rows fit whole numbers of successes for 28, 11, 6 and 5 tasks, then average over tasks instead.
# Meta-World (Table 2): success rates per difficulty group, as printed, and the printed average. rows = { "SmolVLA (0.24B)": ([86.43, 46.36, 35.0, 60.0], 56.95), "SmolVLA (0.45B)": ([82.5, 41.8, 45.0, 60.0], 57.3), "SmolVLA (2.25B)": ([87.14, 51.82, 70.0, 64.0], 68.24), "pi0 (3.5B-Paligemma)": ([80.4, 40.9, 36.7, 44.0], 50.5), "pi0 (3.5B)": ([71.8, 48.2, 41.7, 30.0], 47.9), "Diffusion Policy": ([23.1, 10.7, 1.9, 6.1], 10.5), "TinyVLA": ([77.6, 21.5, 11.4, 15.8], 31.6), } # 10 trials per task. If the groups had 28, 11, 6 and 5 tasks, their trial counts would be 280, 110, 60 and 50. tasks = [28, 11, 6, 5] trials = [10 * t for t in tasks] print("printed average is the plain mean of the four groups:") for name, (groups, printed) in rows.items(): print(f" {name:22s} mean {sum(groups) / 4:6.2f} printed {printed}") print() print("do the printed percentages equal whole numbers of successes out of 280, 110, 60 and 50?") for name, (groups, printed) in rows.items(): ok = [abs(round(g * n / 100) * 100 / n - g) < 0.06 for g, n in zip(groups, trials)] print(f" {name:22s} {ok}") print() print("average over the 50 tasks instead of over the four groups (weights 28, 11, 6, 5, as the first five rows imply):") for name, (groups, printed) in rows.items(): weighted = sum(g * t for g, t in zip(groups, tasks)) / sum(tasks) print(f" {name:22s} groups {printed:6.2f} tasks {weighted:6.2f}")Output:
printed average is the plain mean of the four groups: SmolVLA (0.24B) mean 56.95 printed 56.95 SmolVLA (0.45B) mean 57.33 printed 57.3 SmolVLA (2.25B) mean 68.24 printed 68.24 pi0 (3.5B-Paligemma) mean 50.50 printed 50.5 pi0 (3.5B) mean 47.92 printed 47.9 Diffusion Policy mean 10.45 printed 10.5 TinyVLA mean 31.57 printed 31.6 do the printed percentages equal whole numbers of successes out of 280, 110, 60 and 50? SmolVLA (0.24B) [True, True, True, True] SmolVLA (0.45B) [True, True, True, True] SmolVLA (2.25B) [True, True, True, True] pi0 (3.5B-Paligemma) [True, True, True, True] pi0 (3.5B) [True, True, True, True] Diffusion Policy [False, False, False, False] TinyVLA [False, False, False, False] average over the 50 tasks instead of over the four groups (weights 28, 11, 6, 5, as the first five rows imply): SmolVLA (0.24B) groups 56.95 tasks 68.80 SmolVLA (0.45B) groups 57.30 tasks 66.80 SmolVLA (2.25B) groups 68.24 tasks 75.00 pi0 (3.5B-Paligemma) groups 50.50 tasks 62.83 pi0 (3.5B) groups 47.90 tasks 58.82 Diffusion Policy groups 10.50 tasks 16.13 TinyVLA groups 31.60 tasks 51.13
Arithmetic on the printed table; the group sizes are inferred by us from the decimals.
- Evidence in the paper
- §4.5 “Simulation Evaluation” · Table 2
Check your understanding: What does the π0 pair of rows (Paligemma-initialised and robotics-pretrained) tell you?
On LIBERO, robotics pretraining helps π0 a lot (71.8 to 86.0); on Meta-World it does not (50.5 to 47.9). So the benefit of robot pretraining differs by benchmark, and SmolVLA, which has none in simulation, is compared with both.
Real-world tasks and the effect of pretraining (Tables 3 to 5)
- How it works
- On the three SO100 tasks, the pretrained multi-task SmolVLA averages 78.3%, against 61.7% for multi-task π0 and 48.3% for ACT trained on each task separately. π0 is best on pick-and-place (100%); SmolVLA is best on stacking (90% against 40% for π0) and sorting (70% against 45%). On the SO101 lego task, trained on that task only, SmolVLA scores 90% in distribution and 50% with the brick in new positions, against 70% and 40% for ACT. The authors credit pretraining on community data with the rise from 51.7% to 78.3% and multi-task fine-tuning with further gains.
- Technical details
Table 3, SO100, success rate in percent, as printed. Policy Pick-Place Stacking Sorting Average ACT (single-task) 70 50 25 48.3 π0 (3.5B, multi-task) 100 40 45 61.7 SmolVLA (0.45B, multi-task) 75 90 70 78.3 Table 5, as printed. SmolVLA training Pick-Place Stacking Sorting Average Single task, no pretraining 55 45 20 40 Multi-task, no pretraining 80 40 35 51.7 Multi-task, pretrained 75 90 70 78.3 Our calculation Per task, pretraining adds 50 points on stacking and 35 on sorting, and subtracts 5 on pick-and-place. The example recomputes the averages and the winners per task, and also the numbers of the speed experiment.
Run the example: the real-world tables and the speed experiments
Our calculationWhat each part does
- Type in Tables 3 and 5 and the numbers of Figure 5.
- Recompute the averages and find the best method per task.
- Compare synchronous and asynchronous inference with a t-test on the times and the counts.
import math # Real-world results as printed (success in percent). Tables 3 and 5 and Figure 5. t3 = {"ACT (single task)": (70, 50, 25), "pi0 (multi-task)": (100, 40, 45), "SmolVLA (pretrained, multi-task)": (75, 90, 70)} t5 = {"SmolVLA, single task, no pretraining": (55, 45, 20), "SmolVLA, multi-task, no pretraining": (80, 40, 35), "SmolVLA, multi-task, pretrained": (75, 90, 70)} tasks = ("Pick-Place", "Stacking", "Sorting") print("Table 3, averages recomputed, and the best method per task") for name, row in t3.items(): print(f" {name:34s} mean {sum(row) / 3:5.1f}") for i, task in enumerate(tasks): best = max(t3, key=lambda k: t3[k][i]) print(f" best on {task:10s}: {best} ({t3[best][i]})") print() print("effect of pretraining and multi-task training (Table 5), points per task") a, b, c = t5.values() for i, task in enumerate(tasks): print(f" {task:10s} multi-task over single-task {b[i] - a[i]:+4d} pretraining over none {c[i] - b[i]:+4d}") print() print("synchronous against asynchronous inference (Figure 5)") sync, asyn = (75, 90, 70), (80, 90, 50) print(f" success per task: sync {sync} async {asyn} differences {[x - y for x, y in zip(asyn, sync)]}; averages {sum(sync) / 3:.1f} and {sum(asyn) / 3:.1f}") def t_two_sided_p(t, df): # Student t two-sided p-value by numerical integration of the density pdf = lambda x: math.gamma((df + 1) / 2) / (math.sqrt(df * math.pi) * math.gamma(df / 2)) * (1 + x * x / df) ** (-(df + 1) / 2) steps, top = 20000, abs(t) h = top / steps area = sum((pdf(i * h) + pdf((i + 1) * h)) / 2 * h for i in range(steps)) return 1 - 2 * area def welch(m1, s1, n1, m2, s2, n2): se = math.sqrt(s1 ** 2 / n1 + s2 ** 2 / n2) t = (m1 - m2) / se df = se ** 4 / ((s1 ** 2 / n1) ** 2 / (n1 - 1) + (s2 ** 2 / n2) ** 2 / (n2 - 1)) return t, df, t_two_sided_p(t, df) t, df, p = welch(13.75, 2.42, 10, 9.70, 2.95, 10) print(f" time per task, sync 13.75 s against async 9.70 s (n = 10): t = {t:.2f}, df = {df:.1f}, p = {p:.3f}; {100 * (13.75 - 9.70) / 13.75:.0f}% faster") t, df, p = welch(3.8, 1.3, 5, 1.8, 0.45, 5) print(f" cubes in a fixed time, async 3.8 against sync 1.8 (n = 5): t = {t:.2f}, df = {df:.1f}, p = {p:.3f}") print() print("do the two speed experiments agree?") print(f" speed-up from the task times: {13.75 / 9.70:.2f}x") print(f" speed-up from the fixed-time counts: {3.8 / 1.8:.2f}x") print(f" a 60 s limit would allow {60 / 13.75:.1f} (sync) and {60 / 9.70:.1f} (async) tasks at those times; the paper reports {1.8} and {3.8} per run") print(" the time limit is given only as 'e.g., 60 seconds'")Output:
Table 3, averages recomputed, and the best method per task ACT (single task) mean 48.3 pi0 (multi-task) mean 61.7 SmolVLA (pretrained, multi-task) mean 78.3 best on Pick-Place: pi0 (multi-task) (100) best on Stacking : SmolVLA (pretrained, multi-task) (90) best on Sorting : SmolVLA (pretrained, multi-task) (70) effect of pretraining and multi-task training (Table 5), points per task Pick-Place multi-task over single-task +25 pretraining over none -5 Stacking multi-task over single-task -5 pretraining over none +50 Sorting multi-task over single-task +15 pretraining over none +35 synchronous against asynchronous inference (Figure 5) success per task: sync (75, 90, 70) async (80, 90, 50) differences [5, 0, -20]; averages 78.3 and 73.3 time per task, sync 13.75 s against async 9.70 s (n = 10): t = 3.36, df = 17.3, p = 0.004; 29% faster cubes in a fixed time, async 3.8 against sync 1.8 (n = 5): t = 3.25, df = 4.9, p = 0.023 do the two speed experiments agree? speed-up from the task times: 1.42x speed-up from the fixed-time counts: 2.11x a 60 s limit would allow 4.4 (sync) and 6.2 (async) tasks at those times; the paper reports 1.8 and 3.8 per run the time limit is given only as 'e.g., 60 seconds'
Arithmetic on the printed tables; the tests assume independent trials.
- Evidence in the paper
- §4.5 “Real-World Evaluation”, “Effect of pretraining and multitask learning” · Tables 3, 4 and 5
Check your understanding: What does the π0 pick-and-place score of 100% against SmolVLA’s 75% add to the headline average of 78.3% against 61.7%?
It shows that the average hides a task where the larger model clearly wins; SmolVLA’s lead comes from stacking and sorting.
Synchronous against asynchronous inference (Figure 5)
- How it works
- The authors run the pretrained SmolVLA in both modes on the three SO100 tasks. Success rates are similar (78.3% synchronous, 73.3% asynchronous on average), but the asynchronous mode finishes a pick-and-place in 9.7 seconds on average against 13.75 seconds, about 30% faster, over 10 trials from 5 cube positions. In a fixed time (the paper says, for example, 60 seconds) it completes 19 pick-and-place cycles over five positions against 9. The authors add that asynchronous inference gave faster reactions and more robustness to changes in object positions, which they observed but did not measure separately.
- Technical details
Our calculation Both speed results are statistically solid by a simple test (p of 0.004 and 0.023), but they imply different speed-ups: 1.42 times from the task times and 2.11 times from the fixed-time counts. The sorting task scores 20 points lower in the asynchronous mode (70 to 50), which the caption attributes to hyperparameters tuned for pick-and-place only. The numbers are in the example of the previous concept (open it).
- Evidence in the paper
- §4.6 · Figure 5
Check your understanding: What would you want to know before trusting that asynchronous inference “does not lose accuracy”?
The number of trials per task and several repeats: the sorting score fell by 20 points, which is large, and with so few trials the paper cannot tell whether that is chance or a real cost.
Ablations: which design choices matter (Tables 6 to 13)
- How it works
- All ablations use LIBERO, a frozen vision-language model and an expert trained from scratch. Cross-attention (79.0) beats self-attention (74.5), and interleaving both is best (85.5). Causal attention beats bidirectional (74.5 against 67.5). Keeping 16 layers is a good trade-off (78.5 against 80.3 for 32). An expert width of 0.75 times the vision-language model is chosen. Flow matching beats a regression loss (80.25 against 75.25). The robot state is better given to the vision-language model than to the expert for cross-attention. Chunk sizes of 10 to 50 work best and replanning every 1 or 10 steps is far better than every 50 (80.3 and 82.8 against 51.8).
- Technical details
Tables 6 to 13, as printed. Choice Values tried (LIBERO average, %) Attention type (Table 6) cross 79.0; self 74.5; interleaved 85.5 Attention mask (Table 7) bidirectional 67.5; causal 74.5 Layers kept N (Table 8) 8: 75.0; 16: 78.5; 24: 79.5; 32: 80.3; every second: 75.5; smaller VLM: 75.8 Expert width (Table 9) 1.00: 82.3; 0.75: 77.5; 0.50: 80.3; 0.25: 73.8 Objective (Table 10) flow matching 80.25; regression 75.25 State as prefix or suffix (Table 11) cross: 80.3 and 73.3; self: 53.3 and 74.8 Chunk size (Table 12) 1: 50.0; 10: 84.0; 30: 78.5; 50: 80.3; 100: 74.5 Steps executed before replanning (Table 13) 1: 80.3; 10: 82.8; 30: 70.8; 50: 51.8 Our calculation Three sentences in the text are not borne out by their own tables (Part F). The example checks them, and the first section of this part explains how large a chance difference can be.
Run the example: the ablation sentences against the tables
Our calculationWhat each part does
- Type in the relevant rows of Tables 8, 9 and 11.
- Quote the sentence each one is meant to support.
- Print the differences the tables actually show.
# Ablation tables, typed in as printed (LIBERO success rate, percent). Columns: Spatial, Object, Goal, Long, average. table11 = {("states to the VLM (prefix)", "cross-attention"): (89, 94, 85, 53, 80.3), ("states to the expert (suffix)", "cross-attention"): (86, 82, 78, 47, 73.3), ("states to the VLM (prefix)", "self-attention"): (62, 74, 57, 20, 53.3), ("states to the expert (suffix)", "self-attention"): (80, 92, 80, 47, 74.8)} table8 = {"first 16 layers (N = 16)": 78.5, "every second layer (Skip % 2)": 75.5, "smaller VLM (VLM-256M)": 75.8} table9 = {"x1.00": 82.3, "x0.75": 77.5, "x0.50": 80.3, "x0.25": 73.8} print("Text: 'including state information in the VLM leads to significantly better performance for both the CA and SA variants' (Table 11)") for attention in ("cross-attention", "self-attention"): prefix = table11[("states to the VLM (prefix)", attention)][4] suffix = table11[("states to the expert (suffix)", attention)][4] print(f" {attention:16s} prefix {prefix:5.1f} suffix {suffix:5.1f} prefix minus suffix {prefix - suffix:+5.1f}") print() print("Text: 'skipping every second layer performs better than training a smaller VLM' (Table 8)") print(f" every second layer {table8['every second layer (Skip % 2)']} against smaller VLM {table8['smaller VLM (VLM-256M)']} difference {table8['every second layer (Skip % 2)'] - table8['smaller VLM (VLM-256M)']:+.1f}") print(f" (first 16 layers {table8['first 16 layers (N = 16)']} against smaller VLM {table8['smaller VLM (VLM-256M)']}: {table8['first 16 layers (N = 16)'] - table8['smaller VLM (VLM-256M)']:+.1f})") print() print("Caption of Table 9: 'Larger capacities yield better success rates'") widths = list(table9) for a, b in zip(widths, widths[1:]): print(f" {a} -> {b}: {table9[b] - table9[a]:+.1f}") best = max(table9, key=table9.get) print(f" the chosen width x0.75 scores {table9['x0.75']}; x0.50 scores {table9['x0.50']}; the best is {best} at {table9[best]}")Output:
Text: 'including state information in the VLM leads to significantly better performance for both the CA and SA variants' (Table 11) cross-attention prefix 80.3 suffix 73.3 prefix minus suffix +7.0 self-attention prefix 53.3 suffix 74.8 prefix minus suffix -21.5 Text: 'skipping every second layer performs better than training a smaller VLM' (Table 8) every second layer 75.5 against smaller VLM 75.8 difference -0.3 (first 16 layers 78.5 against smaller VLM 75.8: +2.7) Caption of Table 9: 'Larger capacities yield better success rates' x1.00 -> x0.75: -4.8 x0.75 -> x0.50: +2.8 x0.50 -> x0.25: -6.5 the chosen width x0.75 scores 77.5; x0.50 scores 80.3; the best is x1.00 at 82.3
Arithmetic on the printed tables.
- Evidence in the paper
- §4.7 · Tables 6 to 13
Check your understanding: Why is the gap in Table 13 (80.3 against 51.8) more trustworthy than the gap in Table 6 (79.0 against 74.5)?
It is about nine standard errors of chance for 400 trials, while the Table 6 gap is about one and a half; large gaps survive noise that small ones do not.
What the results show
- A 0.45-billion-parameter model reaches LIBERO and Meta-World averages comparable to or above those of larger VLAs and a 3.3-billion-parameter π0 that the authors ran.
- On three simple real-world tasks, pretrained on community data and fine-tuned on 50 demonstrations, it has the highest average of the compared methods, driven by stacking and sorting.
- Asking for the next chunk early makes the pick-and-place task about 30% faster.
- Large effects in the ablations, such as replanning often and flow matching over plain regression, are consistent with earlier work.
What they do not show
- That the gaps in the small ablations and in LIBERO and Meta-World are more than chance: there are no repeats or intervals.
- That the pretrained vision-language model, or its language knowledge, matters: this is never tested.
- That the efficiency claims hold: no latency, memory or CPU measurements are reported.
- That the model handles new tasks, longer horizons or other robots: the pretraining data, tasks and robots are all of one kind.
Part E · optional
Engineering deep dive
The equations, the control-loop algorithm, the ablation tables as printed and the descriptions of the baselines and tasks, for readers who want to rebuild or audit the work. Everything is collapsed; Parts A to D do not depend on it.
The equations
Symbols: At a chunk of n actions, ε noise, τ the blend between noise (0) and actions (1), ot the vision-language features at layer N, vθ the action expert.
Reported by the paper The flow matching objective and the noisy chunk (Section 3.1):
Reported by the paper The paper prints the target as u = ε − At and samples τ from a Beta distribution as in π0.
Our calculation From the path as printed, the time derivative is At − ε, the opposite sign (see F1).
Reported by the paper The asynchronous queue (Section 3.3): with E[ℓS] the server’s inference time, Δt the control step and n the chunk size, the queue never empties when
and, without the similarity filter, a new observation is sent every (1 − g) n Δt seconds and a new chunk arrives every (1 − g) n Δt + E[ℓS] seconds on average.
The control loop (Algorithm 1), in words
- Capture the first observation, send it to the policy server and receive the first chunk A0.
- At every step, pop the next action from the queue and execute it.
- If the queue holds less than a fraction g of a chunk, capture a new observation. If it is not a near-duplicate of the last one processed (distance in joint space above a threshold), send it for processing without blocking.
- When a new chunk arrives, merge it with the remaining queue on the overlapping time steps (the paper does not say how), and continue. If the answer has not arrived, keep the old queue.
Ablation tables as printed (LIBERO)
| Variant | Spatial | Object | Goal | Long | Average |
|---|---|---|---|---|---|
| Table 6: cross-attention | 87 | 92 | 83 | 54 | 79.0 |
| Table 6: self-attention | 80 | 94 | 84 | 40 | 74.5 |
| Table 6: interleaved (ours) | 86 | 99 | 90 | 67 | 85.5 |
| Table 7: bidirectional | 79 | 86 | 82 | 23 | 67.5 |
| Table 7: causal | 80 | 94 | 84 | 40 | 74.5 |
| Table 8: N = 8 | 77 | 88 | 86 | 49 | 75.0 |
| Table 8: N = 16 | 88 | 91 | 91 | 44 | 78.5 |
| Table 8: N = 24 | 86 | 97 | 86 | 49 | 79.5 |
| Table 8: N = 32 | 89 | 94 | 85 | 53 | 80.3 |
| Table 8: every second layer | 84 | 90 | 83 | 45 | 75.5 |
| Table 8: VLM-256M | 86 | 83 | 75 | 59 | 75.8 |
| Table 9: width ×1.00 | 87 | 96 | 90 | 56 | 82.3 |
| Table 9: ×0.75 | 82 | 89 | 84 | 55 | 77.5 |
| Table 9: ×0.50 | 89 | 94 | 85 | 53 | 80.3 |
| Table 9: ×0.25 | 76 | 97 | 83 | 39 | 73.8 |
| Table 10: flow matching | 89 | 94 | 85 | 53 | 80.25 |
| Table 10: regression | 92 | 85 | 86 | 38 | 75.25 |
| Table 11: state to VLM, cross | 89 | 94 | 85 | 53 | 80.3 |
| Table 11: state to expert, cross | 86 | 82 | 78 | 47 | 73.3 |
| Table 11: state to VLM, self | 62 | 74 | 57 | 20 | 53.3 |
| Table 11: state to expert, self | 80 | 92 | 80 | 47 | 74.8 |
| Table 12: chunk 1 | 45 | 77 | 54 | 24 | 50.0 |
| Table 12: chunk 10 | 90 | 94 | 94 | 58 | 84.0 |
| Table 12: chunk 30 | 85 | 94 | 87 | 48 | 78.5 |
| Table 12: chunk 50 | 89 | 94 | 85 | 53 | 80.3 |
| Table 12: chunk 100 | 83 | 88 | 85 | 42 | 74.5 |
| Table 13: replan every 1 step | 89 | 94 | 85 | 53 | 80.3 |
| Table 13: every 10 | 89 | 94 | 91 | 57 | 82.8 |
| Table 13: every 30 | 76 | 91 | 74 | 42 | 70.8 |
| Table 13: every 50 | 54 | 70 | 58 | 25 | 51.8 |
The baselines and the robots
- Reported by the paper π0: 3.3 billion parameters, based on PaliGemma, three RGB images, joint readings and an instruction; pretrained on 10,000 hours of cross-embodiment robot data; fine-tuned on each target dataset.
- Reported by the paper ACT: a conditional variational autoencoder policy with an encoder-decoder transformer of about 80 million parameters and a ResNet vision encoder pretrained on ImageNet; it predicts action chunks by regression and is trained from scratch on each dataset.
- Reported by the paper SO100 and SO101: open-source, 3D-printable six-degree-of-freedom arms with low-cost servo motors controlled by position commands; cameras are top and wrist for the SO100 tasks and top and side for the SO101 task.
- Reported by the paper Pretraining data: the 481 datasets are listed in Appendix A.1. Our calculation Our count of the printed names is 532, and 229 contain “so100” in the name; none contain “so101”. See F10.
Limitations stated by the authors (Section 5.1)
- Pretraining uses a single robot type (SO100); multiple embodiments are expected to be important for generalisation.
- The dataset is small, about 23 thousand trajectories against about one million for OpenVLA.
- Scaling the model while keeping it fast on consumer hardware is an open direction.
- The off-the-shelf vision-language backbone is pretrained mainly on document reading and optical character recognition, and may not be best for robot interaction.
- Joint training on robotics and broader multimodal data, longer-horizon tasks and learning beyond imitation are listed as future work.
Part F
Critical paper review
Everything above reports what the paper says. This part is our independent reading: where its text and tables disagree, where its evidence is thinner than its wording, and what it does not test. SmolVLA is an open, reproducible and useful piece of work, and its architecture and data choices are clearly described; most findings concern the strength of the comparisons. Each one links back to the concept it affects, and the calculations are reproducible in the examples.
Numbers that do not agree
-
F1. The flow matching target has the opposite sign from the path Numerical inconsistency
What the paper says. The noisy chunk is Atτ = τ At + (1 − τ) ε, and the expert is trained to output u = ε − At.
What we found. At τ = 0 the point is noise and at τ = 1 it is the action chunk, so the point moves with velocity At − ε. The printed target is minus that. In our example, ten forward steps along the true slope land on the action chunk, while ten forward steps along the printed target end at twice the starting distance from it (5.04 against 2.52). This is the same convention as in the π0 and GR00T N1 papers, which the earlier guides also flagged; the Flow Matching and Rectified Flow papers use data minus noise.
Why it matters. Most likely a typo or a reversed time convention rather than a bug in the released code, but the printed equation cannot be implemented as written; check the code before reusing the formula. Concept: The flow matching action expert · π0 guide F1 · GR00T N1 guide F1 · Rectified Flow guide F6
Run the example: the sign of the target
Our calculationWhat each part does
- Build the path the paper defines from random vectors and measure its slope.
- Compare the slope with the printed target.
- Take ten forward steps with each and see which one reaches the action chunk.
import numpy as np # The paper's flow matching objective (Section 3.1): A_tau = tau * A + (1 - tau) * eps, with eps ~ N(0, I), # and the network is trained to output u = eps - A. At tau = 0 the point is noise; at tau = 1 it is the action chunk A. rng = np.random.default_rng(0) A = rng.normal(size=6) # stands in for a clean action chunk eps = rng.normal(size=6) # noise path = lambda tau: tau * A + (1 - tau) * eps h = 1e-6 slope = (path(0.5 + h) - path(0.5 - h)) / (2 * h) # how fast the point moves along the path print("slope of the path equals A - eps:", np.allclose(slope, A - eps)) print("printed target eps - A equals the slope:", np.allclose(eps - A, slope)) print("printed target equals minus the slope:", np.allclose(eps - A, -slope)) def integrate(target_sign, steps=10): # start at noise (tau = 0) and take Euler steps of size 1/steps along +target_sign * (A - eps) x = eps.copy() for _ in range(steps): x = x + (1 / steps) * target_sign * (A - eps) return x dist = lambda x: float(np.linalg.norm(x - A)) print(f"distance from A after 10 forward steps with the slope A - eps: {dist(integrate(+1)):.3f}") print(f"distance from A after 10 forward steps with the printed eps - A: {dist(integrate(-1)):.3f} (start: {dist(eps):.3f})")Output:
slope of the path equals A - eps: True printed target eps - A equals the slope: False printed target equals minus the slope: True distance from A after 10 forward steps with the slope A - eps: 0.000 distance from A after 10 forward steps with the printed eps - A: 5.039 (start: 2.519)
Random vectors stand in for an action chunk and noise; the point is only the sign.
-
F2. Three sentences about the ablations that the tables do not support Numerical inconsistency
What the paper says. Putting the robot state into the vision-language model “leads to significantly better performance for both” attention variants; skipping every second layer “performs better than training a smaller VLM”; and a larger expert capacity yields better success rates.
What we found. For cross-attention the state in the vision-language model is better (80.3 against 73.3), but for self-attention it is far worse (53.3 against 74.8). Skipping every second layer scores 75.5 and the smaller model 75.8. For the expert width, 0.50 scores 80.3 and the chosen 0.75 scores 77.5, and the best is the full width at 82.3, so the series is not monotonic.
Why it matters. The final design choices (state in the vision-language model, 16 layers, 0.75 width) are reasonable, but the stated reasons overstate what the tables show, and the tables themselves are within chance of each other. Concept: Ablations · example
-
F3. “About 10 million episodes”, 481 datasets and the printed list Numerical inconsistency
What the paper says. Table 1 lists 481 datasets, 22.9 thousand episodes and 10.6 million frames; its caption says the set has about 10M episodes and is at least one order of magnitude smaller than other state-of-the-art sets.
What we found. The caption confuses frames with episodes: 10 million episodes would be about 437 times more than the 22.9 thousand in the table. By our count the printed list in Appendix A.1 has 532 distinct dataset names, not 481, which may be the list before filtering, but the paper does not say. The conclusion about size holds either way: 22.9 thousand episodes is 44 times fewer than OpenVLA’s roughly one million.
Why it matters. A small slip, but it appears on the headline statistic of the data section. Concept: Community datasets · example
-
F4. Small labelling inconsistencies Numerical inconsistency
What the paper says. π0 has 3.3 billion parameters (Section 4.4 and the LIBERO rows) and is about 7 times larger than SmolVLA. For the real-world evaluation “the model is trained on a combination of three datasets” for the SO101 benchmark.
What we found. The Meta-World and real-world rows label the same π0 as 3.5 billion, which would make it 7.8 times larger. The three-dataset combination belongs to the SO100 tasks (Table 3); the SO101 task is a single-task evaluation (Table 4). The Table 2 caption credits baseline scores to two earlier papers, but the π0 decimals in Meta-World fit the authors’ own protocol of 10 trials per task (our check in Part D), so they were probably run by the authors, with the fine-tuning settings not reported.
Why it matters. None changes a conclusion, but the baseline comparisons depend on how the larger model was run, which is not described. Concept: The set-up · example
How far the claims go
-
F5. The ablation and benchmark gaps are mostly within chance Method caveat
What the paper says. The design choices are supported by “thorough ablations”; SmolVLA performs competitively with, or better than, much larger models.
What we found. Each LIBERO suite has 100 trials and the four-suite average 400, a standard error of about 2 points and a 95% interval of about ±3.9, with one run per entry. The 1.3-point lead over π0 is half a standard error. The gaps behind interleaved against cross-attention, causal against bidirectional, flow matching against regression and chunk 10 against 50 are 1.4 to 2.4 standard errors; only the replanning effect (80.3 against 51.8) is far beyond chance. The numbers that look like the same configuration appear as 79.0, 80.25, 80.3 and 82.3 in different tables, a spread of 3.3 points. The paper does not say which configuration the later tables start from; the row 89, 94, 85, 53 recurs in Tables 8, 10, 11, 12 and 13, and is not the final model (85.5).
Why it matters. The large effects are probably real; the small ones, which decide most design choices, cannot be distinguished from chance, and the table baselines are not the final model. Concept: The set-up · Ablations · example
-
F6. The Meta-World average counts a group of 5 tasks like a group of 28 Method caveat
What the paper says. The Meta-World averages are given for SmolVLA and the baselines, over four difficulty levels.
What we found. The printed average is the plain mean of the four groups. The printed decimals fit 28, 11, 6 and 5 tasks with 10 trials each (our inference; the paper does not state the group sizes). Weighting by tasks gives 66.80 for the 0.45-billion-parameter model against 58.82 for π0 (3.5B), a lead of 8.0 points instead of 9.4, and every number rises. The decimals of Diffusion Policy and TinyVLA do not fit the same protocol, so they come from other papers with other settings.
Why it matters. The ranking does not change, but the “average” gives the very hard group, with the fewest tasks, the same weight as the easy group, and the averages of other papers’ numbers are not directly comparable. Concept: Simulation · example
-
F7. “Outperforms π0” rests on the average and on very few trials Method caveat
What the paper says. SmolVLA outperforms ACT and π0, a model about seven times larger, on the real-world tasks.
What we found. On pick-and-place π0 scores 100% and SmolVLA 75%; SmolVLA wins stacking (90 against 40) and sorting (70 against 45), which gives the 78.3 against 61.7 average. The number of trials per task is not stated; the scores come in steps of 5, which fits 10 trials with half credit (our assumption), so 25 points is about two and a half trials. The fine-tuning settings of π0 and ACT are not reported. The pretraining list contains dataset names with “stack” (9), “sort” (12), “pick” (66), “place” (50) and “lego” (20), our count by name only, so the real-world tasks are in the same families as the pretraining data.
Why it matters. The real-world result shows that a small pretrained model can be competitive on simple tasks it was fine-tuned for; it is not evidence of a general advantage over π0 or of generalisation to new tasks. Concept: Real-world tasks · Community datasets · example
-
F8. Pretraining helps two of three tasks Ambiguity
What the paper says. Pretraining on community data leads to a substantial improvement, from 51.7 to 78.3 on average.
What we found. Per task, pretraining adds 50 points on stacking and 35 on sorting and subtracts 5 on pick-and-place. Multi-task training without pretraining lowers stacking by 5 points compared with single-task training. The comparison is one run per row, with an unstated number of trials.
Why it matters. The average is real, but it comes from two tasks; with a few trials per task, the effect on any single task is uncertain. Concept: Real-world tasks · example
-
F9. Asynchronous inference: solid speed-up, uncertain accuracy, unreported settings Method caveat
What the paper says. Asynchronous inference achieves similar success rates but is significantly faster, finishes a pick-and-place in 9.7 seconds against 13.75 seconds, and completes 19 cycles against 9 in a fixed time.
What we found. The speed results hold up in a simple test (p of 0.004 for the times, 0.023 for the counts). But the two experiments imply different speed-ups, 1.42 times from the times and 2.11 times from the counts: at the stated times, a 60-second limit (the paper says “e.g., 60 seconds”) would allow 4.4 and 6.2 cycles, against 1.8 and 3.8 reported. On accuracy, sorting falls from 70 to 50, an average of 78.3 to 73.3, which the paper calls similar. The queue threshold g, the similarity threshold, the server’s latency and hardware and the merging rule are not reported.
Why it matters. Asynchronous inference is clearly faster on pick-and-place, but its accuracy cost on longer tasks is not established, and the experiment cannot be repeated from the paper. Concept: Asynchronous inference · Sync against async · example
-
F10. The ablations and the real-world results use different execution modes Method caveat
What the paper says. In simulation, the model samples a new observation after each executed action; for real-world evaluation it executes the full chunk before sampling again.
What we found. Table 13 shows what this choice costs in LIBERO: executing all 50 actions scores 51.8, against 80.3 when replanning every step. The ablations (chunk size 50 and one step) therefore describe a different regime from the main real-world results (full 50-action chunks), and in the chunk-size table the chosen 50 is 3.7 points below chunk 10 (84.0), within chance.
Why it matters. The reported design choices may not transfer to the real-world mode, and the real-world results may be understated or overstated by it; the paper does not discuss this. Concept: Ablations · The recipe
What is not tested
-
F11. The efficiency claims have few measurements Limitation
What the paper says. SmolVLA is designed to be trained on a single GPU and deployed on consumer-grade GPUs or even CPUs; it is about 40% faster to train than π0 and uses 6 times less memory.
What we found. The paper gives no table, hardware or batch size behind the 40% and the 6 times, no inference latency, throughput or memory for any GPU or CPU, and no GPU hours for the main pretraining run; the 30,000 GPU hours are for the whole project and pretraining used four GPUs. The only timings are the task times of the asynchronous experiment.[2]
Why it matters. The model is small, so the claims are plausible, but cost and deployability are the paper’s headline contribution and they are asserted, not measured. Concept: A small model · example
-
F12. “Trained end-to-end” and a frozen vision-language model Ambiguity
What the paper says. The contributions list says SmolVLA is trained end-to-end on fewer than 30 thousand episodes.
What we found. The implementation details say that only the action expert is trained and the vision-language model is frozen. The 0.24-billion and 2.25-billion-parameter versions in Table 2 are not described: which backbone, how many layers are kept and how large the expert is are not given.
Why it matters. About a fifth of the model is trained, which matters for the cost and data claims, and the size comparison in Table 2 cannot be reproduced for two of the three rows. Concept: A small model · The recipe
-
F13. Whether the pretrained vision-language model helps is never tested Method caveat
What the paper says. Pretrained vision-language models encode rich visual and linguistic knowledge and are a strong foundation for robotics.
What we found. The backbone is frozen and, as the authors note, pretrained mainly on document reading and OCR. No experiment replaces it with random weights or with a different pretraining, and the only backbone comparison is a smaller model (Table 8). The instructions in all tasks are fixed sentences, and the only variation is the colour in the sorting task, so no test asks for language or world knowledge beyond the training tasks, as RT-2 did. The architecture’s gains could equally come from the vision features and the trained expert.
Why it matters. The paper shows a small, efficient policy, not that the language model’s knowledge makes it better; the framing borrows a justification that its experiments do not test. Concept: Skipping layers · Ablations
-
F14. What the paper says about its limits, and what it leaves out Limitation
What the paper says. The authors list a single pretraining robot type, a small dataset, the model-size trade-off, an off-the-shelf backbone, short-horizon tasks and imitation-only learning.[2]
What we found. These are accurate. The paper also does not discuss that every result is a single run, that the real-world tasks have fixed box positions, that there is no failure analysis, that community data of unknown quality and licence is the pretraining set, and that the descriptions generated by a language model were not checked for accuracy. The SO101 task, the only test on a different arm, has 10 or fewer trials per condition.
Why it matters. SmolVLA is a clear and open starting point for small VLAs on low-cost arms; the evidence supports “works on simple tasks on these arms” more than “rivals much larger VLAs”. Concept: Real-world tasks · Cleaning the data
Knowledge check
Try each question first, then reveal the explanation.
Question 1
In your own words: how does SmolVLA produce actions, and which parts are trained?
Explanation
A small vision-language model, cut to its first half of layers and frozen, turns images, the instruction and the robot state into features. A trained action expert, which alternates cross-attention to those features with causal self-attention over action tokens, uses flow matching in 10 steps to produce a chunk of 50 actions.
Question 2
What problem does asynchronous inference solve, and how?
Explanation
A robot that runs a whole chunk and then waits for the next one stands idle while the model computes. The asynchronous stack requests the next chunk when the queue is low, so the robot keeps moving, and merges the overlapping actions when the new chunk arrives.
Question 3
What do the real-world tables show, and what do they hide?
Explanation
They show a higher average for SmolVLA (78.3 against 61.7 for π0). They hide that π0 wins pick-and-place, that the number of trials is not stated, and that pretraining helped two of the three tasks.
Question 4
Name one place where the paper’s text and tables disagree.
Explanation
For example: the text says putting the robot state in the vision-language model is better for both attention variants, but for self-attention the table shows it is far worse (53.3 against 74.8); or the Table 1 caption says about 10 million episodes where the table says 22.9 thousand.
Glossary
- Vision-language-action model (VLA)
- A model that reads images and an instruction and outputs robot actions.
- Vision-language model (VLM)
- A model that reads images and text and writes text; here the frozen backbone.
- Action expert
- A smaller network, trained from scratch, that turns the backbone’s features into actions.
- Action chunk
- A short sequence of future actions predicted at once; here 50.
- Flow matching
- Training a network to predict the direction that turns noise into the target, then following it in a few steps.
- Cross-attention
- A layer in which one set of tokens reads from another set; here, action tokens read the VLM’s features.
- Causal self-attention
- A layer in which each token reads only the tokens before it.
- Pixel shuffle
- Moving neighbouring tokens into the feature dimension to reduce the number of tokens without discarding numbers.
- Layer skipping
- Using features from a middle layer and discarding the layers above it.
- Community dataset
- A robot dataset recorded and shared by individuals or labs on affordable robots.
- Embodiment
- The robot’s physical form: arms, joints, cameras.
- Action queue
- The list of upcoming actions the robot is about to execute.
- Synchronous / asynchronous inference
- Waiting for the next chunk after finishing the current one, or requesting it early while still executing.
- Imitation learning
- Learning from demonstrations by copying the demonstrator’s actions.
- Success rate
- The share of trials in which the task was completed, here sometimes with partial credit.
- LIBERO
- A simulated benchmark with four groups of 10 tasks: Spatial, Object, Goal and Long.
- Meta-World
- A simulated benchmark of 50 manipulation tasks in four difficulty levels.
- SO100 / SO101
- Open-source, low-cost six-degree-of-freedom robot arms.
- ACT
- Action Chunking with Transformers, a small policy that predicts chunks of actions by regression.
- Standard error
- How much a measured rate would typically move by chance if the trials were repeated.
References
Numbered notes in the text, like [1], point here. Each entry says what it is cited for and how that was checked. Papers and books can be revised or misread, so follow the links before relying on a detail. Code marked “Toy model” is our own illustration of an idea, not the code of the cited system.
(2023). RT-2: Vision-language-action models transfer web knowledge to robotic control. Conference on Robot Learning (CoRL) 2023. arXiv:2307.15818
Cited for:
- Introduces the name vision-language-action (VLA) models for vision-language models co-fine-tuned on robot trajectories and Internet-scale vision-language tasks. Checked against the paper’s abstract.
(2025). SmolVLA: A vision-language-action model for affordable and efficient robotics. arXiv. arXiv:2506.01844
Cited for:
- A pretrained SmolVLM-2 vision-language model, cut to its first half of language-model layers with 64 visual tokens per frame, feeds an action expert of about 100 million parameters (450 million in total for the main model) that is trained with flow matching and alternates cross-attention and causal self-attention layers to output chunks of 50 actions. Checked against the full text of the paper (arXiv v2 PDF), read sentence by sentence.
- Pretraining uses 481 community datasets from Hugging Face (22.9 thousand episodes, 10.6 million frames), with task descriptions regenerated by a vision-language model and camera views mapped to a standard order. Checked against the full text of the paper (arXiv v2 PDF), read sentence by sentence.
- Introduces an asynchronous inference stack that decouples perception and action prediction from action execution, allowing higher control rates with chunked action generation. Checked against the paper’s abstract.
- A small, efficient, community-driven VLA that reduces training and inference costs while retaining competitive performance, designed to be trained on a single GPU and deployed on consumer-grade GPUs or even CPUs. Checked against the paper’s abstract.
- The authors list a single pretraining robot type (SO100), a small dataset of about 23 thousand trajectories, an off-the-shelf backbone pretrained mainly on document reading and OCR, short-horizon tasks and imitation-only learning as limitations. Checked against the full text of the paper (arXiv v2 PDF), read sentence by sentence.
Go further
- Paper guide: Octo (a baseline in this paper)
- Paper guide: OpenVLA (a baseline in this paper; its LIBERO row is copied from the OpenVLA paper)
- Lesson 6.4: SmolVLA
- Paper guide: RT-2 (the VLA recipe SmolVLA builds on)
- Paper guide: π0 (the model SmolVLA compares with)
- Paper guide: AsyncVLA (another approach to asynchronous action generation)
- Foundations: Flow Matching paper guide
- Foundations: Rectified Flow paper guide