Part 9 of How to Make Your Model Fast (Part 8: Transformers on Small Machines | Part 10: Profiling)
A robot is a control loop with a neural network inside it, which changes what latency means: it stops being a quality metric and becomes a stability constraint. This chapter budgets the whole sense-to-act chain, shows why the network is usually a minority of it, and works the phase margin arithmetic explaining why ten extra milliseconds can make a controller ring. It then separates the two honest deployment patterns for vision language models in robotics, and shows how to cost a VLM auto-labelling system so its payback period survives a review. You will finish able to allocate a 33 ms budget across a real perception stack and to compute the cost per labelled frame before and after automation.
Every chapter so far has treated latency as a quality of service number: the model should be faster because the user waits less. Robotics is where that framing breaks. When a model sits inside a feedback loop driving an object with mass, latency becomes a term in the stability analysis. Past a certain delay the controller does not degrade gracefully. It rings, then it oscillates, then somebody unplugs it.
I spent two years as a robotics software engineer at Dyson, shipping convolutional networks for segmentation, detection and classification onto robot hardware and shrinking them with quantisation, pruning and distillation. Most of my time went on the parts that were not the network. This chapter is about the whole loop, and about where vision language models actually earn their place, which is usually not where the demos suggest.
A benchmark asks how good the output is and how long it took; a control loop asks when the actuator responds and how stale the information behind it is. Optimising for the first can make the second worse.
Define the age of information as the time between the physical instant a measurement describes and the instant an actuator acts on it:
\[A = t_{\text{act}} - t_{\text{capture}}\]where \(t_{\text{capture}}\) is the midpoint of the sensor’s integration window, not the moment the frame lands in your process.
Throughput is a different quantity: a three stage pipeline with 30 ms per stage delivers 33 frames per second at an age of 90 ms. Report the 33 and not the 90 and you have reported the wrong number.
Worked example: a 30 Hz camera, 6 ms exposure, 27 ms from end of exposure to motor command, 33.3 ms hold.
\[A_{\text{issue}} = 3 + 27 = 30 \text{ ms}, \qquad A_{\text{worst}} = 30 + 33.3 = 63.3 \text{ ms}\]At 1.2 m/s the robot has travelled 76 mm since the photons that justified the command. Put the 76 mm on the slide, not the 63 ms: a distance is something a reviewer can argue with.
A pure transport delay leaves a loop’s magnitude response untouched. It only rotates the phase, by \(-\omega\tau\) radians, and at gain crossover that lag comes straight out of your phase margin. In degrees:
\[\Delta\phi \approx 0.36 \, f_c[\text{Hz}] \, \tau[\text{ms}]\]Phase lag contributed by pure delay, as a function of loop bandwidth. This is the whole argument in one table.
| Loop crossover | \(\omega_c\) (rad/s) | Lag from 10 ms | Lag from 33 ms | Lag from 100 ms |
|---|---|---|---|---|
| 1 Hz (slow mobile base) | 6.28 | 3.6 deg | 11.9 deg | 36.0 deg |
| 2 Hz (typical heading loop) | 12.57 | 7.2 deg | 23.8 deg | 72.0 deg |
| 5 Hz (agile base, gimbal) | 31.42 | 18.0 deg | 59.4 deg | 180.0 deg |
| 8 Hz (visual servoing, arm) | 50.27 | 28.8 deg | 95.0 deg | 288.0 deg |
Closed loop damping is roughly the phase margin in degrees over 100,
On an 8 Hz visual servoing loop with 45 degrees of margin, a change adding 10 ms leaves 16 degrees: not slightly worse tracking, but a joint that hunts audibly. On a 1 Hz floor robot the same change costs 3.6 degrees and nobody notices. Identical software, an incident on one platform and a non-event on the other, and the only difference is \(\omega_c\).
Hence the most useful degradation strategy in this chapter: if \(\tau\) grows and you cannot shrink it, shrink \(\omega_c\). Slow the robot down. Their product is what matters.
Takeaway: Delay is phase and phase is stability. Budget the age of information from exposure midpoint to actuator command, not inference time alone.
I start every perception system by writing down each stage between a photon and a torque with a number next to it. Most teams never do this, which is why most teams optimise the wrong stage.
An illustrative sense-to-act budget at two loop rates. These are allocations rather than measurements from any product, but they are the shape I have repeatedly seen once a stack is instrumented. Preprocessing covers debayer, undistort, resize and normalise; postprocessing covers decode, non maximum suppression and mask upsampling.
| Stage | 33 ms budget | Share | 100 ms budget | Share |
|---|---|---|---|---|
| Sensor exposure | 6.0 ms | 18% | 10 ms | 10% |
| Readout and MIPI transport | 4.0 ms | 12% | 6 ms | 6% |
| Driver, DMA, buffer handoff | 1.5 ms | 5% | 4 ms | 4% |
| Cross-sensor synchronisation wait | 2.0 ms | 6% | 8 ms | 8% |
| Preprocessing | 3.0 ms | 9% | 8 ms | 8% |
| Network inference | 9.0 ms | 27% | 40 ms | 40% |
| Postprocessing | 2.0 ms | 6% | 6 ms | 6% |
| Fusion and state estimation | 2.0 ms | 6% | 8 ms | 8% |
| Planning | 2.0 ms | 6% | 6 ms | 6% |
| Actuation command and motor loop | 1.5 ms | 5% | 4 ms | 4% |
| Total | 33.0 ms | 100% | 100 ms | 100% |
In the 33 ms column the network is 27 per cent of the loop. Halving inference time through heroic quantisation work buys 4.5 ms, a 14 per cent improvement in what matters. Noticing that you block on a depth frame you could have predicted forward, and that preprocessing runs a colour conversion the ISP would do for free, can buy the same 4.5 ms in an afternoon.
This is the most common mistake I have watched teams make, including teams I was on: the network is the part with a leaderboard attached. Exposure is the largest single line in the 33 ms column and almost nobody treats it as tunable, yet halving it from 6 ms to 3 ms costs a stop of light, paid for in gain, noise and accuracy. That trade belongs in the same conversation as pruning.
The network’s share grows as the loop slows: at 100 ms it is 40 per cent and model work is the right lever. Know which regime you are in first. Part 10 is about getting these numbers honestly rather than guessing them.
Takeaway: Write the whole chain down with a millisecond next to every stage before optimising anything. In a fast loop the network is often a quarter of the budget, and the cheapest milliseconds sit elsewhere.
A robot has several clocks and they disagree: a pixel clock in the sensor, a crystal in the motor MCU, a monotonic clock and an NTP-stepped wall clock in the application processor. Treat “now” as one global concept and you build a system whose errors scale with velocity and that nobody can debug.
Four rules, simple to state and tedious to enforce. Every measurement carries a timestamp for the physical event, not for when your code saw it. All timestamps refer to one monotonic reference, with offsets to the other domains estimated continuously, not assumed constant.
Getting this wrong has a signature: the system works on the bench and degrades in proportion to speed in the field, because a fixed timing error becomes a growing spatial error. If accuracy scales with velocity, suspect time before you suspect the model.
Here is the rule benchmark culture teaches you backwards: a predictable 40 ms beats an average of 25 ms with a 90 ms tail.
A constant delay is compensable: feed it forward, propagate the state estimate to the moment the command will land, retune around it. A delay that varies unpredictably can only be tolerated, and you must design for its worst case anyway. Jitter also injects noise into the effective phase of the feedback path, so a controller tuned at the mean is under-damped at the tail.
Design against a high percentile, and be honest about how high. At 30 Hz you process 108,000 frames per hour, so p99.9 means about 108 overruns per hour, close to two a minute. A dropped frame is fine. But if an overrun is a potential safety event and you want fewer than one per thousand operating hours, you need a miss rate below \(10^{-8}\), a percentile no realistic test campaign can establish. Safety comes not from a tight latency distribution but from a fallback that is correct when the distribution misbehaves.
Dynamic memory allocation. A malloc is usually a few hundred nanoseconds and occasionally a few hundred microseconds, when the arena is contended or first touch of a page faults. Occasionally is the problem. Allocate every buffer at startup, size for the worst case, reuse, and call mlockall so nothing is paged out. Most runtimes manage this given static shapes and almost none do given dynamic ones.
Garbage collection. A managed runtime in the control path introduces pauses you do not control, whose length depends on allocation history. Keep the loop in C++ or Rust, and Python for configuration, tooling and tests.
Opportunistic batching. Serving stacks batch because it raises arithmetic intensity and therefore throughput, as Part 1 describes. Inside a control loop the objective is inverted: filling a batch of four at 30 Hz adds up to 100 ms to the oldest frame’s age so a throughput number can improve by 50 per cent. A dynamic batch size is worse still, because latency then depends on what the other sensors were doing. Use a fixed batch equal to the number of synchronised sensors, even when it is not full.
Anything that adapts at runtime. Autotuned kernel selection, recompilation on a new shape, frequency governors, thermal throttling and NUMA page migration all give a fast steady state with an unpredictable transient. Warm every code path before leaving the workshop, pin threads with SCHED_FIFO on isolated cores, fix the frequency, and steer interrupts off the working cores.
You will miss the budget, so plan the miss: a deadline-aware wrapper with a tier ladder, plus a watchdog independent of what it watches.
// Preallocated tensors, fixed shapes, no allocation in this function.
Percept run_perception(const Frame& f, Clock::time_point deadline) {
wd_.kick(); // hardware watchdog, independent timer
if (Clock::now() + tiers_[0].wcet < deadline) {
return tiers_[0].run(f, buf_full_); // full model, int8, 640x384
}
if (Clock::now() + tiers_[1].wcet < deadline) {
degraded_frames_++;
return tiers_[1].run(f, buf_small_); // distilled model, 320x192
}
missed_deadlines_++; // no tier fits; do not start work
return Percept::extrapolated(last_good_, Clock::now() - last_good_.stamp);
}
Tiers are chosen on worst case execution time measured offline, so the decision happens before the work starts rather than being discovered halfway through. Nothing allocates, and the degraded path runs regularly rather than only in emergencies.
Above that sits the safety layer, whose important property is that it does not depend on perception at all. A learned model is not a safety function and cannot be argued to be one. What keeps the robot safe when perception fails is a certified proximity sensor, a bumper, a torque limit and a speed limit chosen so the machine stops within the distance the non-learned sensors can see. Perception makes the robot useful; the independent layer makes it safe, and separating those roles is what lets you ship a neural network at all.
The degradation ladder, in increasing severity: slow the robot, restoring phase margin through the \(\omega_c \tau\) product; hold the last good estimate with growing uncertainty and a hard timeout; execute a controlled stop. A hardware timer the application kicks decides the third, because a software watchdog shares the fate of what it watches.
Takeaway: Report p99.9 and the maximum, never the mean alone. Preallocate everything, refuse dynamic batching, pick tiers on worst case execution time before starting work, and keep a safety layer that does not depend on the model.
Vision language models are the most interesting thing to happen to robotics perception in years, and the subject of the largest gap between demonstration and deployment. Separating two deployment patterns, and being precise about which you are proposing, helps enormously.
The VLM runs on the robot and its output influences behaviour. This is rare, expensive, and almost always uses a small distilled model. The arithmetic shows why.
Take an illustrative edge part: 2 TFLOP/s of dense int8 peak at 40 per cent achieved utilisation, so 0.8 TFLOP/s effective, with 50 GB/s of bandwidth. Transformer compute is about \(2NP\) operations for \(N\) matmul parameters over \(P\) tokens, and decode is bound by reading the weights once per token, as Part 8 sets out.
On-device VLM latency on that illustrative hardware.
| Stage | Off-the-shelf 2B VLM | Distilled small VLM |
|---|---|---|
| Vision encoder | ViT-L/14 at 336 px, 577 tokens, 346 GFLOP | ViT-B/16 at 224 px, 197 tokens, 33.9 GFLOP |
| Encoder time | 433 ms | 42 ms |
| Image tokens into the LM | 576 | 64 (pooled) |
| LM prefill | 606 tokens, 2.42 TFLOP | 94 tokens, 94 GFLOP |
| Prefill time | 3030 ms | 118 ms |
| Decode, 20 output tokens | 2.0 GB per token at 50 GB/s | 0.5 GB per token at 50 GB/s |
| Decode time | 800 ms | 200 ms |
| Total | 4.26 s (0.23 Hz) | 0.36 s (2.8 Hz) |
Even the distilled model, at 2.8 Hz, is eleven control periods away from a 30 Hz loop. A VLM is not a perception front end for a fast loop. It works as a supervisory layer in a rate hierarchy: a VLM near 1 Hz emitting goals or a chosen behaviour, a policy at 30 Hz turning that into velocity commands, a motor loop at 1 kHz. Nobody needs the category of the object ahead re-evaluated 30 times a second; they need the distance to it, and those are different models.
Note which term dominates. For the 2B model, prefill over 576 image tokens is 71 per cent of the total, so the best optimisation is not quantising harder but cutting image tokens by pooling or a coarser patch grid. For the distilled model, decode is 56 per cent, so the lever is fewer output tokens: return a class index or a short tag, never a sentence.
Here the VLM never touches the control loop. It runs offline at whatever rate is convenient and automates work humans were doing by hand: auto labelling the images that feed the fast models; triaging fleet logs by clustering interventions and describing what each cluster shares; turning “confidence dropped on 400 frames” into “the robot keeps failing on dark, high pile rugs in low light”; asserting that a scripted test run behaved as intended.
I want to be direct, because the field’s incentives push the other way. The highest return use of a VLM in a robotics programme today is almost always pattern two. Pattern one is a research programme with an uncertain schedule; pattern two is an automation project with a computable payback period, and it usually removes a bottleneck throttling everything else, because what gates your fast models is labelled data and what gates your releases is failure triage.
That is exactly the shape of the VLM project I built at Dyson. It was not a model in the control loop. It took a workflow people were doing by hand, automated the bulk of it with a vision language model under human review, and made the remaining human work an order of magnitude cheaper. It saved over one hundred thousand pounds and improved the workflow by twenty times, and I presented it to the CEO and senior leadership. What made it approvable was not the model. It was that the economics were written down in a form a finance-literate person could check.
Takeaway: Be explicit about which pattern you are proposing. In the loop on device is rare, needs a distilled model and lives in a rate hierarchy above 1 Hz. Out of the loop is where the defensible return is, because it automates human work at a computable payback.
The system is a pipeline, not a model: a VLM or open-vocabulary detector proposes labels; a rule layer rejects proposals violating known constraints, such as impossible sizes or objects floating above the floor plane; a tracker propagates accepted labels across adjacent frames so one decision covers many; and a reviewer sees what remains in an interface where accepting is one keystroke.
The economics live in the difference between drawing and checking. Drawing a polygon mask is slow; checking one and nudging two vertices is fast. The quantity that governs everything is the acceptance rate \(p\), the fraction of proposals accepted without correction. With labour rate \(r\) per second, manual draw time \(t_m\), verify time \(t_v\), extra fix time \(t_f\) and model cost \(c_{\text{model}}\):
\[C_{\text{manual}} = r \, t_m, \qquad C_{\text{auto}} = c_{\text{model}} + r \left[ t_v + (1-p)\, t_f \right]\]Illustrative cost per labelled frame at £25 per hour (£0.00694 per second) and £0.002 of model compute per frame. These are worked assumptions showing the method, not figures from any employer.
| Regime | Verify (s) | Accept rate | Fix (s) | Effective human time | Labour £/frame | Total £/frame | Speedup |
|---|---|---|---|---|---|---|---|
| Manual, from scratch | - | - | 120 | 120.0 s | 0.833 | 0.833 | 1.0x |
| Auto label, weak model | 5 | 60% | 40 | 21.0 s | 0.146 | 0.148 | 5.6x |
| Auto label, good model | 4 | 80% | 30 | 10.0 s | 0.069 | 0.071 | 11.7x |
| Auto label, tuned pipeline | 3 | 90% | 20 | 5.0 s | 0.035 | 0.037 | 22.7x |
Moving from the weak regime to the tuned pipeline is a 4x change in cost, driven mostly by acceptance rate rather than raw model accuracy. Acceptance rate is a product property: it responds to the rule layer, the review interface, sensible class definitions, and a threshold set so the model offers fewer, better proposals. Precision matters more than recall, because a false positive costs a correction while a miss costs a draw.
Once labelling is cheap per frame, the constraint is choosing which frames deserve a human. Four signals, in rough order of usefulness:
The savings compound: if random sampling needs 50,000 frames to hit a target and disagreement-plus-diversity reaches it at 18,000, that 2.8x multiplies the 11.7x per-frame saving.
Answer this before you start, because it is what kills auto-labelling projects.
Measure the human ceiling first. Have two or three annotators independently label the same 500 frames and compute agreement with the downstream metric. If humans agree at 0.86 mIoU, a pipeline at 0.84 is at parity, and demanding 0.95 from the machine is demanding something humans never delivered. Hold out a gold set the pipeline never touches, stratified by lighting, surface and class, and report per stratum, because an aggregate hides the failures that hurt.
Measure downstream accuracy. Label quality is instrumental. Train identical models on \(n\) gold labels, \(n\) auto labels and \(4n\) auto labels and compare on the gold set; more noisy labels often beats fewer clean ones, up to a threshold you can only find by measuring.
Do not train on your own output, or you teach the student the teacher’s blind spots. The source should differ meaningfully: a larger model, another modality, temporal information the student lacks at inference, or a sensor the robot does not carry. Then audit forever, sampling 2 per cent of accepted labels for blind review, because acceptance rate drifts when the fleet meets new environments and that drift warns you the deployed model is about to degrade too.
A technically excellent automation project nobody funds has produced zero value. The bridge is a payback calculation. With build cost \(C_0\), monthly running cost \(C_{\text{run}}\), monthly volume \(V\) and per-frame saving \(\Delta = C_{\text{manual}} - C_{\text{auto}}\):
\[T_{\text{payback}} = \frac{C_0}{V \Delta - C_{\text{run}}}\]Worked example on the “good model” row, all figures illustrative: \(C_0 = £24{,}000\) for three engineer-months at £8,000 fully loaded, \(C_{\text{run}} = £1{,}500\), \(V = 20{,}000\) frames per month, and \(\Delta = 0.833 - 0.071 = £0.762\) per frame.
\[V\Delta = 20{,}000 \times 0.762 = £15{,}240, \qquad T_{\text{payback}} = \frac{24{,}000}{15{,}240 - 1{,}500} = 1.75 \text{ months}\]Sanity check the volume, because a reviewer will: 20,000 frames at 120 seconds each is 667 hours, about four full time people. If your programme has no such operation, scale down and expect a longer payback.
Three points of honesty do more for your credibility than any accuracy figure. Say whether the saving is cash or capacity: outsourced labelling produces cash finance can see in the ledger, while internal staff produce capacity, which is only real if those hours go somewhere valuable. Include the system you have not built: the model is a third of the work, and the review interface, queueing, auditing and pipeline integration are the rest. State the sensitivity: at 60 per cent acceptance, cost per frame rises to £0.113, monthly net falls to £12,904 and payback stretches to 1.9 months. A proposal that survives its own pessimistic case is far easier to approve.
Takeaway: Write the per-frame cost equation, measure the acceptance rate because it dominates everything, and compute the payback explicitly. Distinguish cash savings from freed capacity and show the pessimistic case; that is how the work gets approved.
Simulation is excellent for covering situations you cannot safely stage, and poor at being correct. Domain randomisation addresses the first by training over a distribution of worlds: textures, lighting, geometry, sensor noise, intrinsics and extrinsics. The item everyone forgets is to randomise the latency. Your simulator very likely delivers perception with zero delay and perfect timestamps, which makes it the least realistic thing in the setup with respect to everything else in this chapter, and a policy trained that way depends on information it will never have in time.
The calibration gap is quieter. In simulation the camera is exactly where the model says it is; on a real robot the extrinsics carry residual error and drift with temperature, vibration and the first knock to the mount. One degree of error at 3 metres is \(3000 \tan(1°) = 52\) mm of lateral displacement, enough to miss a grasp or put an obstacle on the wrong side of a boundary. Treat calibration as a monitored runtime quantity with an alarm, not a commissioning step, and report the sim-to-real gap as one number: the same metric on both domains, tracked over time.
When the robot does something wrong you must be able to see exactly what it saw. Logging the output is nearly useless, because the output is the part you already know was wrong. Use a ring buffer of the last few seconds of raw inputs, flushed on a trigger: an intervention, an emergency stop, a planner failure, a deadline miss. Size it with arithmetic. Three cameras at 1920x1080, 10-bit Bayer, 30 fps:
\[1920 \times 1080 \times \tfrac{10}{8} = 2.59 \text{ MB/frame}, \qquad \times 30 \times 3 = 233 \text{ MB/s}\]A 10 second buffer is 2.3 GB of RAM, which most robot compute does not have spare, so the realistic answers are a hardware-encoded stream for the long window with a second or two of raw frames around the trigger, or reduced resolution and harder debugging.
Replay harness. Feed a recorded clip through the exact production perception and planning code and get bit-identical outputs. That works only if you enforced the earlier rules: no wall-clock calls, timestamps from the data, fixed seeds, deterministic reductions. Non-determinism is not a philosophical inconvenience, it is what stops you ever proving you fixed something.
Promote failures to tests. Every clip gets assertions about behaviour, not tensors. Not “the logit for class 4 exceeds 0.8”, which breaks on every retrain, but “the obstacle is detected beyond 1.5 m” or “commanded speed reaches zero within 300 ms of the bumper event”. Behavioural assertions survive model changes, which is the entire point.
Gate releases on the suite. Pass rate over the accumulated corpus becomes the release criterion, with no fixed failure allowed to regress. That corpus grows monotonically and is the most valuable artefact the team owns, because it encodes every mistake the programme has already paid for. Track mean distance between interventions as the top-level metric; a programme that only tracks offline accuracy optimises a number uncorrelated with whether the robot is useful.
This is where pattern two pays off a second time: given thousands of failure clips, a VLM can cluster them and describe each cluster in a sentence, turning a week of scrubbing video into an afternoon of reading summaries. The output is not a better model. It is a faster loop, and in robotics the speed of the failure analysis loop sets the rate of progress.
Takeaway: Log the inputs, not the outputs; enforce enough determinism that clips replay bit-exactly; and turn every real failure into a behavioural assertion in a suite that gates releases. The corpus of past failures outlives every model you ship.
Problem 1. A heading controller has gain crossover at 6 Hz and 50 degrees of phase margin measured with no perception delay. Safety review requires at least 30 degrees in operation. (a) What total sense-to-act delay can you afford? (b) Your non-inference stages sum to 14 ms. What is the inference budget? (c) You must ship a model taking 9 ms. What crossover preserves 30 degrees?
(a) You can spend \(50 - 30 = 20\) degrees, which is \(0.349\) rad, and \(\omega_c = 2\pi \times 6 = 37.70\) rad/s.
\[\tau_{\max} = \frac{0.349}{37.70} = 9.26 \text{ ms}\](b) The non-inference stages alone are 14 ms, already past 9.26 ms, so the budget is \(9.26 - 14 = -4.7\) ms. There is none: you are 4.7 ms over before the model runs, and the loop cannot meet the requirement even with an infinitely fast network. No amount of model optimisation fixes this system.
(c) With \(\tau = 14 + 9 = 23\) ms and the same allowance,
\[\omega_c = \frac{0.349}{0.023} = 15.2 \text{ rad/s} = 2.42 \text{ Hz}\]Bandwidth drops from 6 Hz to 2.42 Hz, a factor of 2.5. Since bandwidth bounds how fast the platform can be driven while still tracking, that means slowing the robot by about 2.5x, or attacking the 14 ms of fixed overhead, which is where the real work is.
Problem 2. Manual labelling takes 150 s per frame at £22 per hour. A VLM pipeline verifies in 5 s with 85 per cent acceptance, rejected proposals take a further 25 s to fix, and model compute is £0.003 per frame. Build cost £30,000, running cost £1,200 per month, volume 25,000 frames per month. (a) Cost per frame before and after, and the speedup. (b) Net monthly saving. (c) Payback period. (d) What if acceptance falls to 70 per cent, and what if volume were only 2,000 frames per month?
Labour rate: \(£22/3600 = £0.006111\) per second.
(a) Manual: \(150 \times 0.006111 = £0.9167\). Auto effective human time is \(5 + 0.15 \times 25 = 8.75\) s, so
\[C_{\text{auto}} = 8.75 \times 0.006111 + 0.003 = £0.0565\]a speedup of \(0.9167 / 0.0565 = 16.2\text{x}\).
(b) \(\Delta = £0.8602\) per frame, so \(V\Delta = 25{,}000 \times 0.8602 = £21{,}505\), and net of running cost \(£20{,}305\) per month.
(c) \(T = 30{,}000 / 20{,}305 = 1.48\) months, about six and a half weeks.
(d) At 70 per cent acceptance, effective time is 12.5 s, so \(C_{\text{auto}} = £0.0794\), \(\Delta = £0.8373\), net \(£19{,}733\) and payback 1.52 months: barely worse, which is the robustness you want to show a reviewer. At 2,000 frames per month, however, \(V\Delta = £1{,}720\) against £1,200 of running cost, so the net is £520 and payback is 57.6 months, or 63.2 at 70 per cent acceptance. Volume, not model quality, decides whether this class of project is worth doing.
Problem 3. An edge device delivers 2 TFLOP/s int8 peak at 40 per cent achieved utilisation and 60 GB/s of bandwidth. You want a distilled VLM on the robot: a ViT-B/16 encoder at 224 px (197 tokens, 86M matmul parameters), image tokens pooled to 49, a 1.1B parameter int8 language model, a 20 token prompt and 24 output tokens. (a) Encoder time. (b) Prefill time. (c) Decode time. (d) Achievable rate, how many 30 Hz control periods that is, and which term to attack first.
Effective compute is \(2 \times 0.40 = 0.8\) TFLOP/s, i.e. 800 GFLOP/s.
(a) \(2 \times 86 \times 10^6 \times 197 = 33.9\) GFLOP, so \(t_{\text{enc}} = 33.9/800 = 42.4\) ms.
(b) Prefill covers \(49 + 20 = 69\) tokens: \(2 \times 1.1 \times 10^9 \times 69 = 151.8\) GFLOP, so \(t_{\text{prefill}} = 189.8\) ms.
(c) Decode is memory bound at 1.1 GB of weights per token:
\[t_{\text{tok}} = 1.1/60 = 18.3 \text{ ms}, \qquad t_{\text{decode}} = 24 \times 18.3 = 440 \text{ ms}\](d) Total \(42.4 + 189.8 + 440 = 672\) ms, a rate of 1.49 Hz, which is \(672/33.3 = 20.2\) control periods. The VLM cannot sit in the fast loop and must run as a supervisory layer above it.
Attack decode first: it is 65 per cent of the total and scales linearly with output length. Changing the output from a sentence to a 4 token structured tag gives \(4 \times 18.3 = 73\) ms of decode and a total of 305 ms, a rate of 3.3 Hz. That is 2.2x from changing the prompt contract, with no change to the model, the quantisation or the hardware. Prefill is the next target, reachable by pooling to fewer image tokens.
Almost everything here depends on trustworthy numbers: the per-stage budget, the p99.9 rather than the mean, the worst case execution time the tier ladder rests on, the real utilisation of the accelerator. I have written them down as illustrative allocations, but on your system they are measurements, and measuring them correctly on a device that is thermally throttling, sharing memory bandwidth and running a scheduler you do not fully control is its own discipline.