Zhao, Kumar, Levine, Finn — 2023

ACT: Action Chunking
with Transformers

Low-cost bimanual manipulation via ALOHA teleoperation and a CVAE-based imitation learning algorithm that predicts action chunks — achieving 80-90% success on tasks like battery insertion and cup opening from just 10 minutes of demonstrations.

Prerequisites: Behavior cloning + Transformers + VAEs
10
Chapters
14
Interactive + 3D sims

Chapter 0: The Problem

You are teleoperating a robot to open a tiny condiment cup. You tip it over with the right gripper, nudge it into the left gripper's grasp, close gently — too hard and the thin plastic buckles, too soft and it slips — lift a few centimeters, then pry the lid with a fingertip. Every one of those four motions has a millimeter-wide window for success. Miss it and the cup skitters off the table.

Now suppose you want a neural network to learn this from watching you do it a few dozen times. The standard recipe is behavioral cloning: at every timestep, feed the network the current camera image and joint positions, and train it to predict the single next action a human would have taken. It is beautifully simple. It is also, for tasks like this, close to hopeless.

Why one small mistake becomes a big one

Here is the failure mode. The policy is trained on states that come from a human's smooth, correct trajectory. At test time it drives itself — its own output becomes the input to the next step. Timestep 1: a tiny mispredicted gripper angle, off by a hair. Timestep 2: the robot is now in a state slightly outside anything the training data ever showed it, because a human never made that exact mistake. The policy, asked to act in unfamiliar territory, guesses — and guesses worse than before. Timestep 3 inherits that worse state. This is compounding error: each step's mistake feeds the next step's input, and the errors do not just add, they cascade, because every wrong state is itself further outside the training distribution than the last.

Why fine manipulation is the worst case for this: Compounding error is dangerous in proportion to how little slack the task gives you. A robot stacking large blocks can drift a centimeter and recover. A robot threading a cable tie through a loop, or seating a 288-pin RAM stick, has a tolerance measured in millimeters. The same rate of per-step drift that is invisible in coarse pick-and-place is fatal in fine manipulation — the failure isn't that the policy is worse at hard tasks, it's that hard tasks have no room left to absorb an error that any policy will eventually make.
Think of it this way: A tightrope walker who must react to a thousand tiny gusts, one correction per gust, has a thousand chances to overcorrect and fall. A tightrope walker who instead commits to a few long, deliberate strides — planned as a unit, each one already accounting for balance across its whole length — has far fewer chances to compound a wobble into a fall. Nothing about the rope changed. What changed is how many independent decisions get made along the way. That's the whole intuition behind everything from Chapter 1 onward.

You might reach for a classical fix: build a physics model of the gripper, the object, the friction between them, and plan contact-rich motions against it. For a rigid parallel-jaw grasp of a known box, this is tractable. For a floppy ziploc bag, a reflective foil wrapper, or a shoelace made of two different fabrics threading through an eyelet — contact-rich manipulation with deformable, transparent, or ambiguous-geometry objects — writing down an accurate physics model is itself a research problem, and a slow one to solve per-object, per-task. Meanwhile the raw camera image already contains everything a human operator needs to succeed: what the gripper sees is what the human's eyes saw when they demonstrated the task.

The bet this paper makes: Skip the physics model. Train an end-to-end visuomotor policy that maps pixels and joint state directly to actions, and make it closed-loop — replanning frequently against fresh camera images — so it can react to wherever it actually ends up, instead of needing to have predicted its own trajectory perfectly in advance. The hard problem shifts from "model contact physics exactly" to "make imitation learning robust enough that closed-loop pixel-to-action control doesn't fall apart." That second problem is what the rest of this lesson is about.

What "closed-loop" actually buys you

Two words are doing a lot of work above, so let's pin them down. An open-loop controller decides its whole action sequence in advance and executes it blind — like memorizing turn-by-turn directions before leaving and never looking at the road again. A closed-loop controller keeps observing and keeps correcting — like driving with your eyes open. ALOHA's teleoperation and data recording run at 50Hz: every 20 milliseconds, a fresh 480×640 image lands from each of four cameras (top, front, two wrists) alongside the current joint angles. A policy that is closed-loop at that rate can, in principle, correct a mistake within a fraction of a second of making it. The question this whole lesson answers is: closed-loop at what granularity? Correcting every single 20ms tick sounds maximally reactive — but Chapter 1 shows that's exactly the regime where compounding error is worst.

The stakes, concretely. This isn't an abstract precision argument — it's the actual difficulty of the eight tasks this system is evaluated on. Sliding open a ziploc bag. Slotting a battery into a compartment. Prying open a childproof cup. Threading a zip tie through a loop roughly 3mm×25mm — about the width of a few grains of rice stacked together. Cutting and applying tape. Putting a shoe on a stand. And as capability demonstrations beyond the benchmark tasks: threading a zip tie one-shot, inserting a 288-pin RAM stick into its slot, juggling a ping-pong ball between grippers, and manipulating the chains and belts on NIST Assembly Task Board #2. Every one of these fails not because the robot is weak or slow, but because being a few millimeters off at the wrong moment is unrecoverable.

Prior attempts to patch behavioral cloning's compounding-error problem have real costs. DAgger asks a human expert to label corrections live, mid-rollout — workable in simulation, painful when the "expert" is a person teleoperating a physical arm for every single rollout. Injecting noise into the demonstrations to teach the policy to recover makes the demonstrations themselves worse and harder to collect. Synthetic correction labels only work when the state is low-dimensional enough to interpolate — not true of raw RGB images. None of these are free lunches. The fix this lesson builds toward attacks the problem differently: instead of making the policy robust to errors, cut down how many chances it gets to make one.

Compounding-Error Playground

Each timestep, the rollout drifts from the ideal path by a random amount up to ε. Because the error is a random walk, the envelope of possible drift grows with the square root of the number of decisions made — not with time directly. Drag the sliders. Watch how quickly the drift envelope (orange) blows past the task's tolerance band (green) and the rollout traces (thin lines) wander outside it.

Error (ε) 5
Horizon T 400

That preview checkbox is not a throwaway toggle — it's the entire thesis of this paper in miniature. If the number of times the policy has to make an independent decision drops from T to T/k, the random-walk envelope shrinks from growing like √T to growing like √(T/k). At the real numbers ACT uses — episodes of 400–700 steps at 50Hz, chunk size k=100 — that is the difference between 400–700 independent "rolls of the dice" and roughly 4–7. Chapter 1 makes this precise.

Hand-worked: why √T and not T. Suppose each independent decision adds an error of typical size σ in a random direction (could cancel, could add — you don't know in advance). After n independent decisions, the spread of the accumulated error is σ·√n, not σ·n. Walk through it:
Decisions (n)√nSpread (multiples of σ)
11
42
1001010σ
4002020σ

Going from 100 decisions to 400 (4× more) only grows the spread from 10σ to 20σ (2× — because √4 = 2). Now run the same table backward: cut the decision count 100-fold — 400 single-step decisions collapsed into 4 chunked decisions (k=100) — and the spread shrinks from 20σ down to √4·σ = 2σ. A 10× tighter drift envelope, for the price of committing to longer, coherent chunks instead of independent single steps. That's exactly the gap between the orange envelope and the teal preview overlay above.

One more thing has to be true for this trick to actually work in practice, and it's easy to miss: a chunk has to be a correct multi-step motion, not just a longer guess. If a policy that's only ever seen single frames suddenly has to output 100 actions in one shot, from one observation, with no chance to look again until the chunk finishes, it needs to be confident enough about what happens next to commit to it — and human demonstrations are not perfectly consistent from one moment to the next. Chapter 5's Conditional VAE machinery exists specifically to handle that. For now, hold onto the shape of the idea: fewer decisions, each one longer and more deliberate, beats many decisions, each one myopic.

ACT drives the robot from raw camera pixels rather than from an explicit physics model of gripper–object contact. Why is this the better call for tasks like inserting a battery or threading a zip tie?

Chapter 1: The Key Insight

ACT's whole contribution can be said in one sentence: instead of predicting one action at a time, predict a chunk of the next k actions at once, and treat that chunk as the output of a generative model rather than a single best guess. Everything else in this lesson — the transformer, the CVAE, the temporal ensembling — exists to make that one sentence work in practice. This chapter is about the sentence itself.

Where "chunking" comes from

The word is borrowed directly from psychology and neuroscience, not invented for robotics. Action chunking is the well-documented phenomenon that biological motor systems don't plan and execute one muscle twitch at a time — they group sequences of primitive actions into a single unit and fire that unit as a whole. Tie your shoelaces and you are not consciously sequencing forty individual finger movements; you are executing a handful of learned chunks ("make a loop," "wrap around," "pull through") that were themselves built out of finer motions long ago and compiled into one habit. Chunking is efficient to store and efficient to execute, in a nervous system exactly as in a robot policy.

What a chunk looks like in this paper's tasks: A chunk of actions might correspond to grasping a corner of a candy wrapper, or the full motion of inserting a battery into its slot. It is not an arbitrary slice of k timesteps — it's closer to a sub-skill, long enough to carry real semantic content, short enough that the robot still gets to replan before the next sub-skill begins.

The formal version

Standard behavioral cloning learns a policy that maps the current observation to a single action:

πθ(at | st)

ACT instead learns a policy that maps the current observation to a whole sequence of future actions:

πθ(at:t+k | st)

Every symbol, defined:

The arithmetic that motivates all of this: An 8–14 second episode at 50Hz is 400–700 timesteps. A single-step policy (k=1) has to make that many independent decisions per episode — 400 to 700 "rolls of the dice," as Chapter 0's playground showed. A chunked policy with k=100 makes roughly T/k = 4–7 decisions for the same episode. That is the literal meaning of "reduces the effective horizon of the task k-fold" — not a metaphor, a division. Fewer decisions, and by Chapter 0's random-walk argument, a much tighter drift envelope on each one.
Single-step BC
π(at | st) — 400–700 sequential decisions per episode
ACT (chunked)
π(at:t+k | st), k=100 — only 4–7 decisions, each one 2 seconds of committed motion

The second thing chunking buys you — for free

Reducing the decision count also fixes a completely different failure mode: non-Markovian demonstrations. A Markovian policy assumes the right action depends only on the current state — not on how you got there, and not on how long you've been there. Human demonstrators violate this constantly. They pause mid-task to reposition a hand, they hesitate before a tricky grasp, they hold still for half a second and then continue.

Here's the problem that causes for a single-step policy. Suppose four different demonstrations all pass through roughly the same visual state — gripper hovering just above the object — but each one pauses there for a different amount of time before continuing. A single-step policy sees "this exact state" many times in the training set, labeled with many different next actions: sometimes "stay put" (early in someone's pause), sometimes "move forward" (someone who had already finished pausing). The state alone can't tell these apart — the correct action depends on the timestep, on elapsed time within the pause, which a Markovian state-only policy has no way to observe. Trained on this contradiction, the policy learns something close to the average of "stay" and "go" — which in practice often means it barely moves at all, gets stuck at that state, and — because it never leaves — keeps seeing the exact same state forever.

This is a self-reinforcing freeze, not a random stumble: An aliased state produces a near-zero action. A near-zero action keeps the robot in the same state. The same state produces the same near-zero action again. Nothing in a single-step Markovian policy breaks that loop — there's no mechanism for "I've already been here for a while, time to go."

A chunked policy sidesteps this differently. Because it predicts a whole committed trajectory segment from one observation, it doesn't have to re-decide "stay or go?" at every single tick inside the pause. If the training chunks that started near a pause were themselves generated by demonstrations that eventually resumed and finished the sub-skill, the policy can learn to produce chunks that carry the pause-then-resume pattern as a single coherent unit, rather than needing to resolve the ambiguity frame by frame. It still isn't magic — Chapter 5's CVAE is what lets the model represent "this demo's particular style of pausing" as a single latent choice instead of forcing one deterministic mean-of-everything trajectory — but chunking alone already removes most of the instant-by-instant aliasing that traps a single-step policy.

Single-Step Freeze vs. Chunked Sail-Through

Two policies race along the same demonstrated path, which has a "pause zone" (shaded) where training demos held still for varying amounts of time. The single-step dot (red) re-decides its velocity every tick from the current position alone — inside the pause zone, that decision is aliased, so it jitters near-zero instead of committing. The chunked dot (teal) commits to a full 2-second-equivalent motion at each replan flash (tick marks) and sails through. Press Play, then drag the confounder-strength slider to see what happens as the ambiguity gets worse.

Confounder 7

Watch what happens at confounder strength 0: there's no ambiguity, both dots glide through the "pause zone" at the same speed, because there was nothing to be confused about. Turn it up, and the single-step dot starts to visibly stall and jitter right where the training demonstrations disagreed with each other about what to do next — while the chunked dot, which never had to resolve that instant-by-instant disagreement, keeps moving at a steady pace toward the goal.

A single-step behavioral-cloning policy is trained on demonstrations that sometimes pause mid-task at the same visual state. What specifically breaks the policy at that state?

Chapter 2: ALOHA Hardware

Chapter 1 established what ACT needs from its training data: demonstrations whose chunks are genuinely coherent sub-skills, collected fast enough and cheaply enough that you can gather 50 of them per task without a research budget the size of a hospital's. Before any of the algorithm can run, somebody has to actually generate that data — and for fine bimanual manipulation, that means teleoperation, because scripting a robot to thread a zip tie by hand-coded motion primitives is not realistic. Existing bimanual research platforms — Shadow Robot hands, ABB YuMi, da Vinci surgical systems — solve this, but at a price point that puts them out of reach for most labs. ALOHA (A Low-cost Open-source Hardware system for bimanual teleoperation) is the answer this paper builds: the whole two-arm teleoperation rig, under $20k, comparable to the price of a single commercial research arm.

Five design principles

The paper is explicit that every hardware choice traces back to one of five stated goals:

PrincipleWhat it rules in / out
Low-costTotal system budget comparable to a single industrial arm — not a specialty lab purchase
VersatileMust handle a wide range of fine manipulation tasks with real, everyday objects
User-friendlyIntuitive, reliable, easy for a non-expert operator to actually use
RepairableWhen a motor inevitably fails, a researcher — not a vendor — can fix it
Easy-to-buildAssembled from off-the-shelf parts plus a handful of 3D-printed pieces, in under 2 hours

Principles 1, 4, and 5 point directly at one hardware decision: build the system around ViperX 6-DoF arms with parallel-jaw grippers, rather than a dexterous multi-fingered hand. Dexterous hands are more capable in principle, but their price and their maintenance burden work directly against "low-cost" and "repairable."

RobotRolePricePayloadSpanRepeatabilityAccuracy
ViperX 300, 6-DoFFollower ×2~$5,600 ea.750g1.5m1mm5–8mm
WidowX 250, 6-DoFLeader ×2~$3,300 ea.

Total system: under $20,000.

Joint-space mapping, not task-space

The operator doesn't wear a VR controller or move a 3D mouse whose pose maps through inverse kinematics (IK) to the follower's gripper pose — that's task-space mapping, and it has a specific, serious failure mode for this application. Instead, the operator physically backdrives a smaller WidowX arm — the leader — and its joint angles are copied directly onto the larger ViperX follower. This is joint-space mapping, and the paper gives two concrete reasons it wins here.

Reason 1 — IK fails near singularities, and fine manipulation lives there. A 6-DoF arm with no redundant joints has kinematic singularities: poses where a small change in end-effector position requires an unreasonably large, or outright undefined, change in joint angles. Off-the-shelf IK solvers fail frequently near these configurations — and fine manipulation, which often needs the gripper at awkward, close-in angles, spends a lot of its time exactly there. Joint-space mapping sidesteps the problem entirely: there is no IK to fail, because the mapping is direct, joint to joint, and it works everywhere within the arm's joint limits.
Reason 2 — the leader's own weight is a feature. Backdriving a real, weighted robot arm is physically harder than waving a lightweight VR controller in free space — and that's exactly why it produces better demonstrations. The arm's inertia prevents the operator from moving too fast, and its mass naturally damps small hand tremors before they ever reach the follower. A floating, weightless controller has no such filter.

Two more details make this system usable for tasks that take real concentration. The stock ViperX fingers aren't built for delicate work, so ALOHA replaces them with 3D-printed see-through fingers fitted with grip tape — the operator can watch exactly what's happening between the jaws while grasping, and thin plastic films still hold without slipping. And the leader arm is retrofitted with a 3D-printed "handle and scissor" mechanism plus a rubber-band gravity-balancing rig: together they let the operator control the gripper continuously (rather than as a binary open/closed switch) while cutting the physical effort of backdriving enough to make sessions longer than 30 minutes practical.

Observation comes from four Logitech C922x webcams — top, front, and one on each follower's wrist — each streaming 480×640 RGB. Teleoperation and data recording both run at 50Hz. The wrist cameras matter more than they sound: the fixed top and front cameras simply cannot see what's happening between the gripper fingers during a delicate grasp, which is exactly the moment that needs to be visible.

ALOHA Teleop Rig

Drag the sliders (or play the canned reach-grasp-lift trajectory) to move the right leader arm (blue, front). The right follower (gray, back) tracks it with simulated PID lag. Toggle force view to see the leader–follower gap visualized as a halo at the gripper — the bigger the gap, the harder the follower's controller is working to catch up. Toggle 50Hz / 5Hz to feel the difference a slow control loop makes. Drag to orbit, pinch/scroll to zoom.

Yaw (base)
Shoulder 30°
Elbow -40°
Wrist
Gripper 60%
User study (n=6, none had used ALOHA before): thread zip tie 33s @5Hz → 20s @50Hz · unstack cups 16s → 10s · 5Hz ≈62% slower overall (p<0.001).
Look at the picture-in-picture panel. That's a stylized rendering of the front camera's feed — mounted rotated 90° from how you'd naively expect, so what reads as horizontal motion on the table shows up as vertical motion in that camera's frame, and vice versa. It's a small detail, but it's a reminder that the policy never sees the scene the way you're viewing this 3D rig — it only ever sees four fixed 480×640 crops, and whatever isn't visible in one of them doesn't exist as far as the network is concerned.

Now, the detail that matters most for everything from Chapter 3 onward: when ALOHA records a demonstration, it logs the leader's joint positions as the action — not the follower's. This looks backwards at first; the follower is the arm actually doing the work. But the leader-minus-follower gap is exactly what a Dynamixel PID controller uses to compute how much torque to apply, so that gap implicitly encodes contact force — how hard the gripper is pressing, how much resistance an object is offering — without any force sensor anywhere in the system. Record the follower's position instead, and you throw that signal away: a follower joint reads almost the same whether it's pressing hard against a stuck lid or gliding through empty air, because the follower is, definitionally, always close to wherever it managed to get to. The leader's target is the actual intention; the follower's actual position is a noisy, force-blind copy of it.

Why does ALOHA record the leader robot's target joint positions as the training action, rather than the follower's actual joint positions?

Chapter 3: Action Chunking

Chapter 1 argued, in the abstract, that fewer decisions means less compounding drift. This chapter puts a number on "fewer" and shows what actually happens as you sweep the chunk size k across the range the paper tests — including the part of the story that a purely "bigger is better" intuition gets wrong.

The naive chunking rule

Fix a chunk size k. Every k timesteps, the policy receives one observation st, generates the next k target-joint-position vectors in a single forward pass, and the robot executes all k of them in sequence before looking again. Formally, the policy models πθ(at:t+k | st) instead of πθ(at | st) — exactly the object Chapter 1 defined. This reduces the effective horizon — the number of independent decisions per episode — by a factor of k.

A useful anchor: at ALOHA's 50Hz control rate, k=100 is exactly 2 seconds of committed motion per decision. For a representative 500-step episode (well inside the paper's real 400–700 step range), that's the difference between 500 single-step decisions and 5 chunked ones.

This "naive" version — observe, commit to k actions, repeat — is fully open-loop for the duration of each chunk: nothing the robot sees during those k steps can change what it does during them, because it already committed. Chapter 4 fixes that specific weakness with temporal ensembling. This chapter is about a different question: independent of that fix, how does k itself trade off against performance?

Why bigger k helps — and then stops helping

Two effects pull in opposite directions as k grows, and neither one is optional to understand if you want to predict where the sweet spot lands.

Effect 1 — fewer decisions, less compounding (favors large k). Exactly Chapter 0's random-walk argument: every replan is a fresh opportunity for the policy to condition on a state that has drifted slightly off its training distribution and answer slightly wrong. Cut the number of replans and you cut the number of chances for that self-reinforcing drift to take hold.
Effect 2 — longer open-loop commitments, harder to get right (favors small k). A chunk that's already 8 seconds long (k=400) has to be correct as one single forward pass, with zero opportunity to react to anything unexpected for its entire duration. Longer output sequences are also simply harder for the model to predict accurately in one shot — more can go wrong inside a single commitment, and once committed, nothing corrects it until the whole chunk finishes.

Small k: too many replans, each one a chance to compound error. Very large k: too few replans, but each remaining one is a long, hard, uncorrectable bet. Somewhere in between is a sweet spot — and the paper finds it empirically by sweeping k with temporal ensembling turned off, isolating chunking's effect on its own.

Cube-Transfer Rollout at Chunk Size k

A stylized bimanual cube-transfer cell: the right arm picks up the cube, hands it off near the table's center, and the left arm carries it to the goal pad. Pick a chunk size k and press Run rollout. Each run samples one stochastic attempt at that k's real success rate; watch the replan flashes (pulses at the active gripper) get sparser as k grows, and watch how far the cube wanders off the ideal path between them.

Chunk k k=100
What the plot recreates: This is Fig. 8(a) from the paper: two baselines (BC-ConvMLP, VINN) grafted with action chunking, plus ACT itself, all improve as k grows from 1 — with temporal ensembling turned off, isolating chunking's own effect. The two hard numbers are 1% success at k=1 (essentially no chunking) and 44% at k=100 — a 44× improvement from one hyperparameter. Past that point, success tapers slightly at k=200 and k=400. The paper's own reading: the very long chunks are open-loop for too long to react to anything, and harder to model accurately as a single sequence in the first place.

Chunking isn't special to ACT's specific architecture, either. The same ablation grafts action chunking onto BC-ConvMLP (which starts predicting a k×action_dim block instead of one action) and onto VINN (which retrieves the next k actions from its nearest training match instead of just one) — and both baselines improve too. That's the paper's basis for calling chunking "generally useful" rather than an ACT-specific trick: it's a property of the decision-horizon math from Chapter 0, not of any one model family.

In the k-sweep ablation (temporal ensembling off), success rises sharply from k=1 to k=100 but tapers slightly at k=200 and k=400. Why does very large k hurt, given that Effect 1 says fewer decisions should mean less compounding error?

Chapter 4: Temporal Ensembling

Chunking (chapter 3) fixed the big problem: predicting k actions at once cuts the effective horizon k-fold, so errors have far less time to compound before the policy gets a fresh look at the world. But chunking on its own creates a smaller, uglier problem at the seams.

Picture the robot executing chunk after chunk, open-loop, k steps at a time. It finishes chunk #1, and now needs chunk #2. It queries the policy again — but the policy has no memory of exactly what chunk #1 was doing at its very last step. Chunk #2 starts from scratch, predicting its own k-step plan from the current observation. If that new plan disagrees even slightly with where chunk #1 left off, the follower arm's target jumps instantly at the boundary. The paper is blunt about this: “A naïve implementation of action chunking can be suboptimal: a new environment observation is incorporated abruptly every k steps and can result in jerky robot motion.”

The seam problem, concretely: at k=100 (2 seconds at 50Hz), the robot re-plans once every 2 seconds. Between re-plans it is committed, open-loop, to a single k-step guess made 2 seconds ago. When that guess ends and a new one begins, nothing constrains the new chunk's first predicted joint angle to match the old chunk's last one. Multiply that by two arms, 14 joints, dozens of chunk boundaries per episode — the robot visibly twitches every time it replans.

The fix: never stop asking

The paper's answer is almost too simple: instead of querying the policy once every k steps, query it at every single timestep. Every timestep t gets its own fresh k-step chunk prediction πθt:t+k | ot). This means chunks now overlap — heavily. For any given real timestep, there isn't one prediction of what to do — there are up to k of them, one contributed by each of the last k queries, each one guessing what should happen right now from a slightly different vantage point in time.

That overlap is exactly the raw material temporal ensembling needs. Instead of blindly trusting whichever chunk happens to be “active” this instant (the naive, jerky version), average all of the overlapping predictions for this timestep into one number.

at = Σi wi At[i]  /  Σi wi      where    wi = exp(−m · i)

Unpacking every symbol: At is the list of all predictions currently sitting in the buffer for timestep t — one entry from every one of the last (up to) k queries whose chunk still reaches this far. i indexes that list from 0 = the OLDEST active prediction (the query made furthest in the past that still covers t) up through the newest (the query made just now, at t itself). m is a single knob that controls how fast the weight falls off as predictions get newer. wi is that prediction's vote in the weighted average.

The counter-intuitive part: because wi = exp(−m·i) and i=0 is the oldest prediction, the oldest prediction always gets the largest possible weight — exp(0) = 1, the ceiling every other weight is measured against. Every newer prediction gets discounted below that ceiling. This feels backwards until you track what m actually does: with m close to 0, exp(−m·i) ≈ 1 for every i, so newer predictions are barely discounted at all — they carry almost as much weight as the ancient one, and fresh information about the world floods in fast. With m large, exp(−m·i) collapses toward 0 for any i>0, so only the oldest active prediction really counts — the ensemble is anchored to a query made possibly k−1 steps ago, and it takes that entire window for fresh information to finally win out (once the old query ages out of the buffer). That's precisely what the paper means by “a smaller m means faster incorporation of new observations.”

The Chunk-Overlap Lattice — recreating Fig. 5

Every row is one historical query's k-step chunk, drawn as a strip of dots starting where that query happened. The playhead (vertical line) is the current real timestep. The dots it crosses — one per still-active row — are the overlapping predictions for right now; their brightness shows their weight. Drag k and m and watch which predictions the ensemble leans on.

chunk size k12
m (decay)0.30
Hand-Compute: One Executed Action, Every Step Shown

Three overlapping queries all predict a value for the same upcoming timestep — the joint angle of one wrist, in degrees. Oldest query: 41.0°. Middle query: 44.0°. Newest query (just issued): 50.0°. Drag m and watch every arithmetic step update live.

m0.50
i (0=oldest)predictionwi = exp(−m·i)wi · prediction
i = 0 (oldest)41.0°1.000041.0000
i = 1 (middle)44.0°
i = 2 (newest)50.0°
Normalize and execute: Σwi = . Σ(wi·prediction) = °. Executed action at = ÷ = °.
Compare to a plain unweighted average of the three: (41.0 + 44.0 + 50.0) / 3 = 45.0°. The weighted result sits closer to the oldest prediction — that's w0's ceiling weight of 1.0000 pulling the answer toward it.
Not the same as smoothing: a moving-average filter blends a signal with its neighbors in time — the value at t=10 gets mixed with the values at t=9 and t=11. That introduces lag: the filtered signal always trails a step or two behind the true trajectory. Temporal ensembling never does this. Every prediction being averaged is a guess about the exact same timestep t, made from different vantage points. There's no lag being introduced, because nothing from a different point in time is being blended in — only different opinions about the same point in time.
Raw Chunking vs. Ensembled — the Joint Trace

Same underlying (noisy) per-query predictions, same k and m as the lattice above. Gray staircase: naive chunking — execute one query's whole chunk, then jump to the next query's chunk at the boundary. Teal: the same predictions run through temporal ensembling.

3D Playback — Jerky vs. Smooth

The same wrist-angle trace from the plot above, driving one joint of a follower arm. Toggle between the raw chunk-switching trace and the temporally-ensembled trace and watch the difference in the hardware.

What ensembling costs — and buys

Querying every timestep instead of every k steps means k× more forward passes through the network at test time. The paper is explicit that this is the only price: “This procedure also incurs no additional training cost, only extra inference-time computation.” At roughly 0.01 seconds per forward pass on a single 2080 Ti, that overhead is easily absorbed at 50Hz.

MethodΔ from temporal ensembling
ACT+3.3%
BC-ConvMLP (chunked)+4%
VINN (chunked)≈ −20%

ACT and BC-ConvMLP are parametric policies — neural networks that output a continuous prediction with real modeling error baked in. Averaging several independent guesses at the same target cancels out a chunk of that error, the same reason averaging several noisy sensor readings beats trusting just one.

VINN is different: it's non-parametric — it retrieves an actual recorded action straight out of the demonstration dataset via nearest-neighbor lookup. There's no modeling error to average away, because the retrieved action already is a real, correct demonstration. Averaging it in with older retrieved neighbors just blends in less-relevant, already-correct actions from a slightly different moment — there's nothing to gain and precision to lose.

In temporal ensembling, with wi = exp(−m·i) and m > 0, which prediction gets the LARGEST weight?

Chapter 5: The CVAE

Chunking and ensembling (chapters 3-4) both assume the policy has one right answer to give at each moment. That assumption breaks the moment demonstrations come from a human. Ask the same person to repeat the exact same handover a hundred times and you will get a hundred slightly different trajectories — not because they're being sloppy, but because when precision doesn't matter, humans don't hold themselves to a single millimeter-perfect path. The paper puts it plainly: “Given the same observation, a human can use different trajectories to solve the task.”

Why this actually breaks training: the training data now contains two (or more) valid, correct, but different actions recorded for what looks like the identical observation. A network trained to output one deterministic action per observation has no way to represent “it could go either way” — it has exactly one output slot, and the training loss is going to push that slot toward some compromise between the demonstrated options.

A hand-worked collision

Picture a handover task where the gripper must pass a small block sitting on a raised stand, leaving just enough gap underneath to slip through. Some demonstrations go over the block; others go under, through the gap. Both work. Neither one is “more correct” than the other — they're two equally valid solutions the human happened to alternate between.

Measure clearance as height relative to the block's vertical center (0 = dead center, where the block itself is). The over-demonstrations clear it by +4cm. The under-demonstrations clear it by −4cm, passing through the gap below. Both demonstrations get equal weight during training. A model that must commit to one deterministic number for this observation settles somewhere between the two targets it was shown — the simplest such compromise is the plain average:

clearance = (+4cm + (−4cm)) ÷ 2 = 0cm

Zero centimeters of clearance is exactly the block's own height — nowhere either demonstration actually went. The “averaged” policy doesn't cautiously split the difference into a safe path; it drives straight into the obstacle both real demonstrations were carefully avoiding.

3D: The Averaged Path Collides

Teal = the “over” demo. Blue = the “under” demo. Toggle to see the plain-average path (warm, collides) versus the CVAE fix (green, commits to one clean mode).

Why the fix works — the short version: during training, the CVAE encoder is also shown the actual recorded action sequence for that episode, so it knows which mode (over or under) this particular demonstration belongs to. It compresses that information into a small latent code z and hands it to the decoder alongside the observation. The decoder is now solving an easier problem: given the observation AND which mode this is, produce that mode's precise trajectory. It never has to learn to blend two contradictory targets for one input, because during training it was never asked to — z told it which one to produce. Chapter 6 traces exactly where z enters the network.

The machinery: how z gets learned

The encoder is a small, BERT-style transformer that only exists during training. Its job: look at a real demonstration (the joint observations and the k-step action chunk that followed) and compress “which behavior is this” into z. The input is built the same way BERT builds sentence-level representations — prepend a learned [CLS] token, then the embedded current joint positions, then the embedded k-step action sequence:

input length = 1 ([CLS]) + 1 (joints) + k (action sequence) = k + 2 tokens

After the transformer processes this sequence, the feature at the [CLS] position — the one token whose whole job is to summarize everything else — gets projected into two vectors: a mean μ and a variance σ2, defining a diagonal Gaussian distribution over z. Sampling z = μ + σ·ε (with ε drawn from a standard normal) lets gradients flow through the sampling step during training.

One deliberate shortcut: the encoder's input is joints and actions only — no camera images. The paper is direct about why: “For faster training in practice, we leave out the image observations and only condition on the proprioceptive observation and the action sequence.” The decoder (the actual policy, covered fully in chapter 6) still sees all four camera views — only the training-only encoder skips them, trading a small amount of encoder expressiveness for meaningfully faster training.

The full training loss balances two goals: reconstruct the demonstrated action chunk accurately, and keep the distribution of z close to a simple prior so it doesn't degenerate into memorizing training examples one-by-one:

L = L1(â, a) + β · DKL(qφ(z|a,ō) ‖ N(0, I))     β = 10

L1 reconstruction (not L2) — chapter 6 covers exactly why the paper prefers it for actions. The KL term is the standard VAE regularizer, weighted by β: push qφ(z|…) toward the simple prior N(0,I) so z stays well-behaved and doesn't become a lookup table for individual training examples. Higher β means less information can flow through z — squeeze the bottleneck hard enough and z stops carrying any real signal about which mode this demonstration was, which pushes the decoder right back toward the collapsed-average behavior this whole mechanism exists to avoid.

2D: Mode Explorer — Watch β Squeeze the Bottleneck

Twenty synthetic demonstrations of the same task, alternating between two valid modes (teal cluster near +4, blue cluster near −4 — same units as the collision example above). The horizontal line is what the current model predicts for that identical observation. This is a simplified sketch of the paper's qualitative claim — not the literal ACT formula.

β10.0

At test time: z is set to zero

Here's the part that surprises people on first read: the encoder that made all of this possible is thrown away entirely at test time. There's no real future action sequence to encode when the robot is actually running — that's the whole thing being predicted. So the paper sets z = 0, the mean of the prior distribution, and decodes deterministically. Every rollout of the policy on a given observation produces the same output; there's no randomness injected at execution time.

Why this doesn't collapse back to averaging: the decoder was never trained to produce a blend of over-and-under for an unconditioned input — every training example paired a specific observation with a specific, mode-consistent z drawn from that same demonstration. z=0 is just one particular, fixed, reproducible point the decoder learned to associate with a coherent output during that training — not an unconditioned average over everything it ever saw.
Training dataWith CVAEWithout CVAEΔ
Scripted (deterministic policy)≈ no change
Human (stochastic, multi-modal)35.3%2%−33.3 points

Scripted demonstrations come from one deterministic policy — there's no second mode to resolve, so the CVAE objective has nothing to do and success rate barely moves. Human demonstrations are exactly the multi-modal case this chapter has been building toward, and removing the CVAE objective there is catastrophic: 35.3% down to 2%. This is the single clearest piece of evidence in the whole paper that modeling multimodality isn't a nice-to-have — for learning from real human data, it's load-bearing.

What specific problem does training ACT as a CVAE (rather than a plain deterministic regressor) solve?

Chapter 6: Architecture

Three ideas so far: chunk k actions at once (chapter 3), ensemble overlapping chunks for smoothness (chapter 4), and train as a CVAE so the policy can represent more than one valid behavior (chapter 5). Time to open the box and trace the actual network that runs all three — the exact tensor shapes, end to end, that turn four camera images and two arms' worth of joint angles into the next hundred target positions.

What you're about to see: only the decoder half of the CVAE runs at test time (the encoder from chapter 5 exists purely to train it, and is discarded afterward). Everything below is that decoder — the actual policy that ships onto the robot. By the end of this chapter you should be able to implement it from the lesson alone.
The Tensor Spine — Click Any Stage

Four camera streams (top row) merge into one long token sequence, pick up the current joint state and the style variable z, and flow through an encoder-decoder transformer to the final action chunk. Click a block for its exact shape and the engineering reason behind it.

Click a stage above
Start with the camera images at the top — each one of the ten stages below is clickable.

Reading the spine in words

Each of the 4 cameras (480×640×3, all four streaming at 50Hz per chapter 2) passes through a ResNet18 backbone, which turns the raw pixels into a 15×20×512 feature map — a coarse grid of 512-dimensional descriptors, one per spatial location. Flatten the 15×20 grid into a sequence and each camera contributes 300 tokens: 15 × 20 = 300.

Where does 15×20 actually come from? A standard ResNet backbone downsamples its input by a total stride of 32× by the time it reaches the final feature map (a stem that strides down 4× (conv + maxpool), then three more stride-2 stages). Divide the 480×640 input by 32 on each axis: 480 ÷ 32 = 15 and 640 ÷ 32 = 20, exactly the feature-map size the paper reports. This is the kind of number you should always be able to derive, not just memorize.

Flattening throws away WHERE in the image each token came from — row 3, column 8 and row 8, column 3 become indistinguishable once they're just “token #38” and “token #123” in a flat list. A fixed 2D sinusoidal position embedding gets added back in, the same trick DETR (Carion et al., 2020) uses for object detection transformers, so the network can still reason about spatial layout downstream.

Stack all four cameras' 300-token sequences together: 300 × 4 = 1200 visual tokens. Append one more token for the current joint positions (a 14-dimensional vector — 7 per arm — linearly projected up to 512 dims) and one more for the CVAE style variable z from chapter 5 (also linearly projected to 512):

1200 (visual) + 1 (joints) + 1 (z) = 1202 tokens, each 512-dimensional

That 1202×512 sequence feeds a 4-layer transformer encoder, which lets every token — every patch of every camera, the joint state, and z — attend to every other token before anything gets decided. The output is still 1202×512, just contextualized.

The 7-layer transformer decoder works differently from a typical autoregressive decoder. Its query sequence isn't generated one token at a time from previous outputs — it's a fixed, learned-once sinusoidal position embedding of shape k×512 (k=100, the chunk size from chapter 3). Those k queries cross-attend into the encoder's 1202×512 output to pull out whatever information they need, and self-attend among themselves. Output: k×512. A small MLP projects each of the k rows down from 512 to 14 dimensions — the predicted target joint positions for that one future timestep.

Why fixed queries, not autoregressive decoding: generating action #2 by feeding back action #1 (the way a language model generates the next word) would mean small early errors compound INSIDE a single chunk prediction, and it would reintroduce the causal-confusion risk chunking was built to avoid in chapter 3. Fixed queries let all k actions be predicted in one parallel pass, conditioned only on the encoder's summary — not on each other.

The four camera views aren't redundant copies of each other — they cover different failure modes. The top and front views (chapter 2) give the wide workspace context: where is the object, where is the other arm, is anything about to collide. The two wrist views ride along with the follower grippers and give the close, stable, hand-eye viewpoint that fine manipulation actually depends on — exactly the view a human uses when threading a needle by feel more than by watching from across the room. Because every one of the 1200 visual tokens attends freely to every other token in the encoder, the network is free to combine “wrist-cam says the gripper is 2mm from the lid” with “top-cam says the cup hasn't moved” in whatever way the task needs.

Which k is this? Every k in this chapter is the real chunk size the paper trains with: k=100, 2 seconds of actions at 50Hz (chapter 3). The interactive lattice in chapter 4 used a smaller, illustrative k=12 purely so the overlapping-chunk diagram would fit on screen and stay readable — the underlying math (the weighted-average formula, the FIFO buffer) is identical at k=100; there would just be up to 100 overlapping predictions competing for every timestep instead of up to 12.

Design-decision ledger

DecisionChoiceWhy
Reconstruction lossL1L2's squared-error penalty smooths out sharp corrections; L1 gives more precise, less-blurred action modeling — exactly what fine manipulation needs.
Action representationAbsolute target jointsDelta joint actions measurably degraded performance in the paper's own tests — small per-step representation errors compound less when every prediction restates the full target.
Whose joints are “the action”Leader robotForce is implicit in the leader–follower gap through the Dynamixel PID controller (chapter 2). Recording the follower's joints instead would throw that signal away.
z at test timez = 0 (prior mean)The encoder is discarded entirely at test time — there's no real action sequence left to encode. z=0 gives one reproducible answer instead of a fresh random draw every step.
Training regimeFrom scratch, per task≈80M parameters, no cross-task pretraining in this paper. ≈5 hours on one 11GB RTX 2080 Ti; ≈0.01s inference on the same machine — comfortably inside a 50Hz control loop.

Hyperparameters (Table III)

HyperparameterValue
Learning rate1e-5
Batch size8
Encoder layers4
Decoder layers7
Feedforward dim3200
Hidden dim512
Attention heads8
Chunk size k100
β (KL weight)10
Dropout0.1

The forward pass, in pseudocode

Mirroring Algorithm 1 (training) and Algorithm 2 (inference) from the paper:

# ACT training step — mirrors Algorithm 1
def train_step(o_t, a_chunk):              # a_chunk: (k, 14) target joints
    o_bar = o_t.joints                        # proprioception only, no images
    z_mu, z_logvar = encoder(cls_tok, o_bar, a_chunk)  # BERT-style, k+2 tokens
    z = z_mu + exp(0.5 * z_logvar) * randn_like(z_mu)  # reparam trick

    tokens = []
    for cam in o_t.images:                  # 4 cameras
        feat = resnet18(cam)                  # (15, 20, 512)
        feat = flatten(feat) + pos_embed_2d    # (300, 512)
        tokens.append(feat)
    visual = concat(tokens, dim=0)             # (1200, 512)
    joints_tok = linear_joints(o_t.joints)     # (1, 512)
    z_tok = linear_z(z)                        # (1, 512)
    enc_in = concat([visual, joints_tok, z_tok]) # (1202, 512)

    memory = transformer_encoder(enc_in)       # 4 layers -> (1202, 512)
    queries = fixed_sin_posemb(k)              # (k, 512), NOT learned from data
    dec_out = transformer_decoder(queries, memory) # 7 layers, cross-attn -> (k, 512)
    a_hat = mlp_head(dec_out)                  # (k, 14)

    loss = l1_loss(a_hat, a_chunk) + BETA * kl_divergence(z_mu, z_logvar)
    loss.backward(); optimizer.step()          # Adam, lr = 1e-5

# ACT inference — mirrors Algorithm 2
buffer = [[] for _ in range(episode_len)]      # FIFO: buffer[t] = predictions for t
for t in range(episode_len):
    z = zeros(z_dim)                            # z = 0, deterministic decode
    a_hat_chunk = policy(o_t, z)                # (k, 14), same forward pass as above
    for i in range(k):
        buffer[t + i].append(a_hat_chunk[i])   # scatter into the FIFO
    preds = buffer[t]                          # every prediction covering NOW
    w = [exp(-M * i) for i in range(len(preds))] # i=0 -> oldest active prediction
    a_t = sum(w[i]*preds[i] for i in range(len(preds))) / sum(w)
    robot.execute(a_t)                          # sent to the Dynamixel PID (chapter 2)
Concept + Realization: nothing above is hand-wavy — every shape traces back to a concrete number. 480×640×3 is the raw webcam frame. 15×20×512 is ResNet18's stride-32 output on that resolution. 300 = 15×20. 1200 = 300×4 cameras. 1202 = 1200 + 1 joints token + 1 z token. k×14 is k timesteps of 14 joint values (7 per arm). Every one of these numbers is something you could print out of a real PyTorch .shape call — if a shape in your own implementation doesn't match one of these, that's exactly where the bug is.

With the network fully traced, the next two chapters put it to work: chapter 7 walks through all 8 tasks this exact architecture was trained on and how it stacked up against four prior imitation-learning baselines, and chapter 8 pulls apart every ablation — chunking, ensembling, and the CVAE — to show, numerically, how much each piece of this spine is actually pulling its weight.

The transformer encoder's input sequence has length 1202. What are the two non-visual tokens that get appended to the 1200 image tokens?

Chapter 7: Experiments

Chapters 1 through 6 built the machine. This chapter is where it gets tested. A results table by itself proves very little — anyone can report one favorable number. What makes ACT's evaluation convincing is what happens right after the headline number: every task is broken into subtasks, and every method's success rate is reported at each stage. When a policy fails, you can see exactly where the wheels came off, not just that they did.

Eight tasks. Six run on the real ALOHA hardware; two run in MuJoCo simulation. Four prior imitation-learning baselines. One question: does predicting chunks as a generative model actually buy you fine manipulation, or is it just a fancier way to fail?

What "success" means here: every task has 3–4 subtasks, and success is scored stage by stage — you only "pass" a later stage if you already passed the one before it. A policy that opens a cup's lid but never lifted the cup off the table first doesn't get credit for opening. This is why the cascades below only ever go down, never up.

Eight tasks, one randomization rule

Every task starts with the target object placed randomly — on the real robot, along a 15cm white reference line taped to the table; in simulation, uniformly inside a 2D region. Same idea, two implementations: the policy can never memorize a fixed pixel location for the object, it has to actually look.

TaskSettingWhat has to happen
Slide ZiplocRealLeft arm grasps the bag body; right arm pinches the slider; right arm slides it open. The bag is dropped from ~5cm above the table before each trial to randomize its deformation.
Slot BatteryRealRight arm grasps a battery and places it in the remote's slot; left arm presses the remote to counter the slot's internal spring while the right arm pushes the battery fully home.
Open CupRealRight fingers tip a small translucent condiment cup over into the open left gripper; left gripper closes gently and lifts the cup off the table; right fingers pry the lid open.
Thread VelcroRealLeft arm lifts a velcro cable tie by its plastic loop; right arm grasps the tail of the tie mid-air; both arms coordinate to insert one end of the tie into the loop on the other end.
Prep TapeRealRight gripper grasps a strip of tape and cuts it with the dispenser's blade; hands the cut segment to the left gripper mid-air; both arms lay it flat on a cardboard box edge and press it down.
Put On ShoeRealBoth arms lift a velcro-strap shoe and fit it onto a fixed mannequin foot; left arm supports the shoe from underneath so it doesn't slip off; right arm secures the velcro strap.
Cube TransferSimRight arm touches, then grasps, a red cube and hands it to the left arm — through a clearance of roughly 1cm between the cube and the receiving gripper.
Bimanual InsertionSimLeft and right arms grasp a socket and a peg respectively, then insert them mid-air so the peg's pins make contact inside the socket — a clearance of roughly 5mm.

Two of these objects deserve a special mention because they're adversarial to vision, not just control: the ziploc bag is largely transparent with a thin blue sealing line, the tape and the cup's body/lid are translucent (which makes depth cameras nearly useless), and the velcro tie and the table are both black — a low-contrast pairing that will come back to bite ACT in chapter 8's failure analysis.

Task Explorer: pick a task, watch where it falls apart

Every number below is the exact subtask cascade reported in the paper. Pick a task and watch ACT's success rate step down stage by stage, against the best comparable baseline — usually BeT, the strongest of the four on real hardware. For the two simulated tasks, ACT is trained twice: once on scripted (deterministic) demonstrations, once on human (stochastic) ones — toggle between them.

Subtask Cascade by Task

Click a task. Bars show success rate at each subtask, in order — teal for ACT, a muted red for the best baseline. A subtask can never score higher than the one before it.

The human-data drop (a preview of chapter 5)

Notice something if you flipped the sim toggle above: every method does worse when trained on human demonstrations than on scripted ones, even though it's the exact same task, the exact same policy architecture, and the exact same number of demos (50).

Cube Transfer, ACT
86% 50%
scripted → human · −36 points
Bimanual Insertion, ACT
32% 20%
scripted → human · −12 points
Why scripted ≠ human data: a scripted policy performs the exact same motion, in the exact same way, every single time — it's deterministic. A human demonstrating "hand the cube to the other arm" does it a little differently every episode: slightly different grasp point, slightly different timing, slightly different path. That variation is real signal a policy has to absorb, not noise to average away. This is exactly the multi-modality problem chapter 5's CVAE objective exists to solve — and exactly why the ablation in chapter 8 shows the CVAE mattering enormously on human data and barely at all on scripted data.

Baseline autopsy: four ways to fail at fine manipulation

ACT is compared against four established imitation-learning methods, each carefully tuned on the cube-transfer task before being run on everything else. Each one embodies a different, reasonable-sounding design choice for behavior cloning — and each one has exactly one weak point that fine manipulation exposes.

Aggregated across the two simulated tasks (scripted and human data each), ACT beats whichever baseline does best by 59, 49, 29, and 20 points — Cube Transfer scripted, Cube Transfer human, Bimanual Insertion scripted, Bimanual Insertion human, respectively. Every card below contributes to that gap.

BC-ConvMLP

A CNN reads the current images, concatenates the features with joint positions, and an MLP predicts one action. The simplest, most widely used baseline.

Kills it: single-step prediction

No notion of a chunk or a sequence — every timestep is an independent roll of the dice. Small per-step noise compounds relentlessly across an 8–14s, 400–700-step episode.

BeT

A transformer over a 100-step observation history, but the visual encoder is trained separately and frozen before the policy trains. Actions are discretized into bins plus a continuous offset from the bin center.

Kills it: frozen perception + discretization

The visual encoder never gets gradient signal from the control task, so it isn't tuned to notice millimeter-scale cues — like a gripper 2mm from a cable-tie loop. And binning the action space throws away exactly the sub-millimeter precision the subtask cascades demand.

RT-1

Another transformer predicting one action from a fixed-length history of past observations, with the action space fully discretized into categorical bins.

Kills it: discretization + fixed history

Still one prediction per step — still hundreds of independent decisions per episode — and the bins are coarser than BeT's (no continuous offset refinement at all).

VINN

Non-parametric: retrieves the k most visually similar past observations (via a pretrained ResNet finetuned with unsupervised learning on the demos) and returns a weighted k-nearest-neighbor average of their recorded actions.

Kills it: retrieval without modeling

There's no learned mapping from observation to action, just similarity search. Under 15cm-line randomization, the current view constantly fails to closely resemble any demonstrated one — so the "nearest" action is often borrowed from the wrong context entirely.

What it took to collect this data

QuantityValue
Demonstrations per task50 (100 for Thread Velcro)
Episode length8–14 seconds
Steps per episode400–700, at 50Hz control
Data volume per task~10–20 minutes of recorded demonstration
Wall-clock time per task30–60 minutes (resets + teleoperator mistakes)

Every one of the tasks above — the ones ACT solves at 80–90% success — was learned from that little data. That's the whole point of the low-cost hardware in chapter 2: cheap enough that collecting a few dozen demonstrations per skill is a lunch break, not a research program.

Every baseline the paper tested on a real task scores exactly 0% on that task's FINAL subtask — all four on Slide Ziploc and Slot Battery, and BeT (the strongest, the only one carried to the remaining four tasks) everywhere — even though they sometimes clear the very first subtask. What does the paper attribute this total collapse to?

Chapter 8: Ablations

Chapter 7 showed ACT winning. That's not the same as showing why it wins. ACT bundles three ideas together — chunking, temporal ensembling, and the CVAE objective — and it's fair to ask whether all three are pulling their weight, or whether one of them is doing all the work while the others are along for the ride.

This chapter turns each one off, one at a time, and measures what breaks. The paper presents this as four panels of one figure; the dashboard below rebuilds all four with the exact numbers reported.

Ablation Dashboard

(a) Chunk size k: how far ahead should one prediction commit?

With temporal ensembling switched off (isolating chunking's effect alone), ACT's success rate — averaged across all four settings from chapter 7 (2 simulated tasks × scripted/human) — climbs from 1% at k=1 (no chunking, i.e. plain single-step behavior cloning) to 44% at k=100, then tapers slightly at k=200 and k=400 as chunks approach the full episode length (fully open-loop control). The paper doesn't report exact numbers at k=200/400 — only that performance dips slightly, which the dashboard renders as a soft downward trend rather than a labeled value.

Chunking isn't ACT-specific. The paper grafts chunking onto two of the baselines to check whether the idea generalizes: BC-ConvMLP is changed to output k×action_dim in one forward pass, and VINN is changed to retrieve the next k actions instead of one. Both show the same rising-then-plateauing trend as k grows — still well below ACT, but clearly benefiting. Chunking is a generally useful technique, not a trick that only works inside ACT's specific architecture.

(b) Temporal ensembling: who benefits from smoothing?

With k fixed at each method's best setting, adding temporal ensembling on top changes success rate by:

MethodΔ from TEWhy
BC-ConvMLP+4%Parametric predictions have modeling noise; averaging overlapping chunks smooths it out.
ACT+3.3%Same mechanism — smaller gain because chunking already reduced the noise a lot.
VINN≈ −20%VINN retrieves ground-truth actions from the dataset — there's no modeling error to smooth. Averaging in a stale, older retrieved action just makes the current one worse.
The parametric-vs-retrieval line: temporal ensembling helps exactly the methods that learn a mapping from observation to action (ACT, BC-ConvMLP) — it smooths out their approximation error. It hurts the one method that doesn't learn a mapping at all (VINN), because there's no approximation error to smooth, only correct-for-a-different-moment answers getting blended in.

(c) The CVAE objective: does it matter?

Removing the CVAE objective means ACT just predicts one action chunk directly from the current observation, trained with plain L1 regression — no encoder, no latent z, no KL term. Averaged across the two simulated tasks:

Demo sourceWith CVAEWithout CVAE
ScriptedAlmost no difference — the data is fully deterministic, so there's no multi-modality to model.
Human35.3%2%

On human data, removing the CVAE isn't a modest regression — it's a collapse from 35.3% to 2%. This is the ablation that most directly explains chapter 5's design choice: the CVAE isn't decoration, it's the specific component that lets ACT learn from noisy, multi-modal human demonstrations at all.

(d) Is 50Hz actually necessary?

A separate user study, decoupled from ACT itself, tests whether high-frequency teleoperation is what makes fine manipulation possible in the first place — or whether a slower, more common control rate would do just as well. 6 participants (none had used ALOHA before) each performed two tasks at both 50Hz and 5Hz, order randomized:

Task50Hz5Hz
Thread zip tie20s33s
Unstack cups10s16s

Overall, dropping to 5Hz slowed task completion by 62%, confirmed with a repeated-measures statistical test at p < 0.001. This is a study about the human operator, not the learned policy — but it justifies the entire premise of chapter 2: if a human needs 50Hz feedback to thread a zip tie quickly, a policy trained on 5Hz demonstrations was never going to have the resolution to learn it either.

Thread Velcro failure forensics

Chapter 7's cascade for Thread Velcro was the ugliest of the six real tasks: success roughly halves at every stage, from 92% at Lift down to 20% by Insert. Two concrete failure modes explain it:

Failure mode 1 — grasp: at the second stage, the right arm's gripper closes too early and misses the tail of the cable tie while it's still in mid-air.
Failure mode 2 — insert: at the third stage, the final insertion isn't precise enough and misses the loop.

Both trace back to the same root cause: the plastic loop measures roughly 3mm × 25mm, while the tie itself measures roughly 2mm × 10–25mm depending on where you grip it. A few millimeters of error on the first grasp compounds through the mid-air handoff into more than a 10mm deviation by the insertion phase — on a target that's only 3mm wide. On top of that, the black cable tie sits against a black table (low visual contrast) and only occupies a small fraction of the frame from the top-down camera, so even localizing it precisely is hard before you get to threading it.

Which one of ACT's three components matters ONLY when the training data comes from HUMAN demonstrations, and barely matters at all on scripted data?

Chapter 9: Connections + Cheat Sheet

You've now built ACT chunk by chunk: the problem it solves, the math behind chunking, temporal ensembling, the CVAE, the full tensor spine, and the numbers that back it up. Knowing one algorithm's math cold isn't the same as knowing when to reach for it. This chapter places ACT on the map next to its neighbors, then compresses the whole lesson into one page you can return to.

Where ACT sits in the family tree

Every method in this lineage is answering the same question — what should a policy output, and how do you handle the fact that human demonstrations aren't unique? — with a different architectural bet. Plain behavior cloning ducks the question entirely: it regresses to a single action and hopes the training data doesn't disagree with itself too often. The moment you start collecting real human demonstrations — and chapter 7's numbers showed how much worse every method gets on human data versus scripted data — that hope stops holding, and the field splits into two answers.

Behavior Cloning (BC-ConvMLP)
One action per step, deterministic regression. Multi-modal demonstrations get averaged into a blurry, often physically invalid, mean action.
Discretize (BeT, RT-1)
Turn the action space into bins. A categorical distribution over bins can represent "several valid actions" naturally — but coarse bins can't express the sub-millimeter precision fine manipulation needs, and BeT additionally freezes its visual encoder.
Continuous chunks + CVAE (ACT)
Predict a whole chunk of continuous actions at once; a latent z (learned via a CVAE) picks which "style" of demonstration to decode — one shot, no denoising loop, z=0 at test time.
Diffusion over action sequences (Diffusion Policy)
Same multi-modality problem as ACT's CVAE — a different generative model. Instead of a single-shot latent decode, it runs iterative denoising over the action chunk, trading extra inference-time compute for a different (often smoother) way to represent multiple valid trajectories.

Click a branch for the longer version.

The one-sentence version: ACT and Diffusion Policy are solving the exact same problem — human demonstrations are multi-modal, and averaging over modes produces an invalid action — with two different generative models. ACT's CVAE decodes a chunk in a single forward pass; Diffusion Policy iteratively denoises one. BeT and RT-1 sidestep the generative-modeling question by discretizing instead, which buys simplicity at the cost of the precision fine manipulation needs.

ACT vs. Diffusion Policy, one level deeper

Both are "generative models over an action chunk," which makes them easy to conflate. The difference that matters in practice is how many forward passes it takes to turn one observation into one executable chunk:

ACTDiffusion Policy
Generative mechanismCVAE — encode/decode is one forward pass through the transformerDenoising diffusion — iteratively refine the chunk over multiple steps
What varies across "modes"The latent z, sampled once (or fixed to the prior mean, z=0, at test time)The noise trajectory the denoiser resolves
Test-time cost per chunkOne pass — this is why ACT's measured inference time is ~0.01sSeveral denoising passes — more compute per chunk, in exchange for a generative process that's been extensively studied for image synthesis and adapts well to it

Neither is strictly "better" — ACT's single-shot decode is what makes its ~0.01s inference time possible on an 11GB 2080 Ti, which matters when you're closing a 50Hz control loop. A denoising-based policy trades some of that speed margin for a generative process with a different, often smoother, inductive bias. Which one wins depends on how tight your real-time budget actually is.

It's worth being precise about what "same problem, different generative model" actually buys you as a practitioner, because it's easy to read that sentence and conclude the two are interchangeable. They're not: swapping ACT's CVAE for a diffusion head changes the training loss, the sampling procedure at test time, and the number of times you have to run the transformer per control cycle. What stays constant across both is the higher-level framing this whole lesson has built — predict a chunk of actions, not one action; model the distribution over valid chunks, don't regress to their mean; execute with some form of smoothing across overlapping predictions. That framing, not any one equation, is the actual transferable idea.

What came after ALOHA

ACT's own paper is the origin of the "action chunking" idea, but the ALOHA hardware platform kept evolving after this paper shipped, and both follow-ons kept the chunked imitation-learning recipe rather than replacing it.

Mobile ALOHA puts the bimanual arms on a mobile base, so the same chunked-action policy has to solve whole-body navigation-plus-manipulation tasks — walking up to a sink, opening a cabinet, reaching in — instead of working inside a fixed tabletop cell. The control problem gets harder (more degrees of freedom, a moving base to coordinate), but the underlying "predict a chunk, execute open-loop, temporally ensemble" recipe from this lesson carries over largely unchanged.

ALOHA 2 is a hardware revision of the same low-cost philosophy — refining the gripper mechanism and overall durability for more robust, longer data-collection sessions — while keeping the core idea intact: cheap, off-the-shelf hardware, joint-space teleoperation, and a policy trained on a small stack of human demonstrations. The lesson here is less about any specific successor and more about how durable the ALOHA + ACT recipe turned out to be: low-cost teleoperation hardware, paired with a chunked generative policy, has become a template the field keeps building on rather than discarding.

When to reach for which

ApproachAction representationHandles multi-modality viaGood fit when
ACTContinuous chunk (k=100)CVAE latent z, single-shot decodeLow-cost hardware, real-time control budget, fine bimanual manipulation, a modest number of demos per task
Diffusion PolicyContinuous chunkIterative denoising over the chunkMore inference-time compute is available; a well-studied, general-purpose generative backbone is preferred
BeT / RT-1Discretized bins (+ offset for BeT)Categorical distribution over binsLarge-scale, multi-task generalist policies where some precision loss is acceptable

Cheat sheet: the equations

EquationWhat it says
πθ(at:t+k | st)The chunk policy: from the state at time t, predict target joint positions for the next k timesteps in one forward pass.
qφ(z | ōt, at:t+k)The CVAE encoder (training only): maps the proprioceptive-only observation and the ground-truth action chunk to a diagonal-Gaussian distribution over the style latent z.
L = L1(â, a) + β·KL(qφ(z|·) ‖ N(0,I)), β=10The training loss: L1 reconstruction of the predicted chunk against the demonstrated one, plus a KL penalty pulling the encoder's posterior toward a standard normal prior.
wi = exp(−m·i), w0 = oldestTemporal-ensemble weight for the i-th oldest overlapping chunk's prediction of the SAME timestep. Smaller m weighs new information more heavily.
at = (∑ wi·At[i]) / (∑ wi)The action actually executed at time t: a weighted average across every overlapping chunk's prediction for that exact timestep.

How chapter 8's ablations pay for these equations

Every term in the equations above earned its place in the loss because removing it measurably hurt something in chapter 8. Reading the cheat sheet next to the ablation numbers makes the connection concrete:

Equation / componentChapter 8 resultWhat it proves
πθ(at:t+k|st) — chunking1% (k=1) → 44% (k=100)Chunking alone accounts for nearly the entire jump from "unusable single-step BC" to "a policy worth deploying"
wi = exp(−m·i) — temporal ensemble+3.3% ACT, +4% BC-ConvMLP, ≈−20% VINNSmoothing only helps methods with a learned mapping to smooth — it actively hurts pure retrieval
L = L1 + β·KL — CVAE35.3% → 2% on human data; ~no change on scriptedThe CVAE is a multi-modality fix, and it earns its entire keep specifically on the noisy, human-collected data it was designed for

Where to find this in the paper

For readers who want to go straight to the primary source instead of this lesson's retelling, here's the section map (arXiv 2304.13705):

ConceptPaper section
ALOHA hardware design§III
Chunking, temporal ensembling, CVAE machinery§IV
Task definitions§V-A, Fig. 6 (real tasks), Fig. 7 (sim tasks)
Data collection protocol§V-B
Headline results (Table I, Table II)§V-C
Ablations (chunk-size sweep, TE, CVAE)§VI-A, §VI-B, Fig. 8
User study (50Hz vs. 5Hz)§VI-C, Appendix E
Limitations§VII, Appendix F
HyperparametersAppendix D

Cheat sheet: symbol glossary

SymbolMeaning
kChunk size — 100 (2 seconds of control at 50Hz)
stFull observation at time t: 4 camera images plus 14 joint positions
at:t+kA chunk of k future target joint positions, one 14-dim vector per timestep
zThe CVAE's latent style variable — which valid way of performing the demonstrated motion to decode. Fixed at z=0 (the prior mean) at test time, for a deterministic decode.
ōtThe encoder's input observation — joint positions only, no images (kept small for training speed)
βKL weight in the training loss — 10
wi, mTemporal-ensemble weight and its decay rate; w0 is always the OLDEST prediction for that timestep

Cheat sheet: the numbers

QuantityValue
Chunk size k100 (2s at 50Hz)
Control / recording frequency50Hz
Cameras4, at 480×640
Action dimension14 (7 leader joints × 2 arms)
Model size~80M parameters
Training time~5 hours on one 11GB RTX 2080 Ti
Inference time~0.01 seconds
Total hardware cost< $20,000
Demos per task50 (100 for Thread Velcro)
Headline success rate80–90% (condiment cup opening, battery slotting)

Honest limitations

ACT is not magic, and the paper is upfront about where it stops working:

LimitationDetail
Thread Velcro tops out at 20%The lowest final success rate of all six real tasks — chapter 8's forensic breakdown pins this on millimeter-scale tolerances (a 3mm×25mm loop, a 2mm-wide tie) plus a low-contrast black-on-black object that's hard to even localize from the top camera.
Buttoning a dress shirt is explicitly beyond the systemCalled out directly by the authors — not a matter of collecting more demonstrations, but a task the hardware-and-algorithm combination doesn't yet reach.
Every task trains its own policy from scratchThere's no single generalist ACT model that does all eight tasks — each is a separate ~80M-parameter model, separately trained, on its own set of demonstrations.
Real-world results are single-seedThe two simulated tasks are evaluated across 3 random seeds × 50 trials each — a fairly rigorous protocol. The six real-world tasks are evaluated with one trained policy × 25 trials, because retraining and re-evaluating on physical hardware multiple times is far more expensive than in simulation. The real-world numbers in chapter 7 are strong, but they carry less statistical redundancy than the simulated ones.
Related lessons — where to go next depending on what you want to dig into:
  • Veanors: Diffusion Policy — the other answer to multi-modal action prediction, worked through with the same depth as this lesson.
  • Veanors: UMI — a different low-cost data-collection philosophy for manipulation, handheld instead of teleoperated.
  • Veanors: pi-0 — scales the "predict a chunk" idea up to a full vision-language-action foundation model.
  • Gleams: Imitation Learning — the general theory of behavior cloning and compounding error that motivates this entire lesson's chapter 0–1.
  • Gleams: Robot Learning — the wider field ACT sits inside, for readers who want the map before the territory.
If you only remember three things: (1) chunking predicts k actions at once so a single decision point doesn't compound into episode-long drift; (2) temporal ensembling smooths those chunk-boundary transitions by averaging every overlapping prediction of the same timestep, weighted toward the newest; (3) the CVAE is a completely separate fix for a completely separate problem — human demonstrations are multi-modal, and modeling that with a latent variable beats averaging it away. Three components, three distinct jobs. Get those three roles straight and the rest of the architecture — ResNet backbones, the 1202×512 encoder, the sinusoidal position embeddings — is just the plumbing that makes them trainable end-to-end on 50 demonstrations and an 11GB GPU.

Rapid-fire recap

Nine chapters, a lot of claims. Click each card below — some are true, several are common misreadings of the paper worth catching before you close this lesson.

Multi-select: which of the following correctly describe how ACT combats compounding error / distribution shift from naive single-step behavior cloning specifically (as opposed to the separate multi-modality problem)?
"What I cannot create, I do not understand."
— Richard Feynman, the standard this lesson tries to meet