
INT8 and FP8 next to the servos: what quantisation saves in memory, what it costs in success rate, which runtimes support it, and why 8-bit VLA inference is often slower than 16-bit.
Quantisation is the first thing people reach for when a vision-language-action model is too slow on the robot, and the thing most often misread. Cutting weights from 16 bits to 8 does halve the memory. It does not reliably halve the latency, and on the best-measured VLA in public it cost thirteen points of task success while the arithmetic stayed accurate. The failure was not numerical. The policy got slower and stopped matching the control rate it was trained at.
What follows is what INT8 and FP8 cost and save next to the servos: which formats need which silicon, which runtimes will build a quantised engine for a VLA today, and where quantisation is simply the wrong lever. Search note: the American spelling is quantization, and every flag name below uses it.
What you need to know
- •Quantisation buys memory first, throughput second. OpenVLA-7B measures 16.8 GB in bfloat16, 10.2 GB in int8, 7.0 GB in int4.
- •8-bit is the trap. In the OpenVLA paper the BridgeData V2 success rate fell from 71.3 to 58.1 percent at int8, while int4 held at 71.9 percent. The cause was speed, not rounding.
- •FP8 needs compute capability 8.9 or newer. Jetson Orin is Ampere: INT8 yes, FP8 no. Jetson Thor is Blackwell: FP8 and FP4.
- •NVIDIA's own TensorRT path for GR00T N1.7 is bf16 only. Its 2.35x speedup on Orin comes from graph compilation, not lower precision.
- •On AY-Robots the policy is served from a rented cloud GPU with headroom, so quantisation is not the lever that fixes control latency. Distance to the arm is.
The formats, and what silicon each one needs
A quantised tensor is a low-precision value plus a scale. TensorRT's scheme is symmetric: values are stored as signed INT8, FP8E4M3, signed INT4 or FP4E2M1, converting back is one multiply, and rounding is round-to-nearest ties-to-even with a clamp. The two FP8 encodings come from the FP8 Formats for Deep Learning paper: E4M3 spends four exponent bits and three mantissa bits, E5M2 the reverse. Inference uses E4M3; E5M2 is mainly for gradients.
| Format | Bits | Clamp range (TensorRT) | Hardware floor | Role in a VLA stack |
|---|---|---|---|---|
| FP32 | 32 | n/a | anything | statistics, action un-normalisation |
| BF16 / FP16 | 16 | n/a | Pascal and newer | what nearly every VLA checkpoint ships as |
| FP8 (E4M3) | 8 | -448 to 448 | compute capability 8.9+ | weights and activations via TensorRT |
| INT8 | 8 | -128 to 127 | Turing+ for LLM.int8() | classic PTQ with a calibration pass |
| INT4 | 4 | -8 to 7 | Ampere and newer | weight-only compression of the backbone |
| NF4 | 4 | codebook, not a clamp | Pascal and newer | QLoRA-style low-VRAM loading |
| FP4 (E2M1) | 4 | native on Blackwell | Blackwell, Jetson Thor | Transformer Engine switches FP4/FP8 |
Weight-only (NF4, int4 weight-only) shrinks the checkpoint, but the matmul still runs in bf16 after an on-the-fly dequantise, so it can be slower per step. Weight-plus-activation (INT8 PTQ, FP8 in TensorRT) issues real low-precision Tensor Core instructions, but needs calibration data and the right silicon. Confusing the two is the commonest reason a quantisation project produces no speedup.
The measurement that should change your plan
The cleanest published numbers on quantised VLAs are in the OpenVLA paper. OpenVLA is a 7B model on a Prismatic VLM with a Llama 2 backbone, evaluated on real-robot BridgeData V2 tasks at three precisions on the same hardware.
| Precision | GPU memory | Bridge success rate | Rate on their A5000 |
|---|---|---|---|
| bfloat16 | 16.8 GB | 71.3 +/- 4.8 % | reference |
| int8 | 10.2 GB | 58.1 +/- 5.1 % | 1.2 Hz |
| int4 | 7.0 GB | 71.9 +/- 4.7 % | 3 Hz |
Read the middle row twice. 8-bit cost 13.2 points of success rate; 4-bit cost nothing measurable, though it discards twice as much information. The paper is explicit: "8-bit quantization slows down inference across most GPUs, due to the overhead of the added quantization operations", and at 1.2 Hz against a controller recorded at 5 Hz this "significantly changes the system dynamics compared to the training dataset". The model was not wrong. It was late.
A policy trained at one control rate has that rate baked into its action distribution. Halve the step rate and every predicted action covers twice the distance it was trained for. The symptom is overshoot, hesitation, the arm stopping mid-reach. Before touching precision, read policy freezes mid-motion and policy only works in one setup.
Why 8-bit can be slower than 16-bit
- bitsandbytes LLM.int8() is not a plain INT8 matmul. Per the LLM.int8() paper it quantises vector-wise, then splits outlier feature dimensions into a separate 16-bit matmul. Over 99.9 percent of values go through INT8, but you run two matmuls plus a scatter instead of one.
- Weight-only 4-bit skips that: dequantise to bf16, one matmul, fewer kernels, less memory traffic.
- Quantise and dequantise nodes are not free. Unfused, each is an extra full pass over the tensor.
- Batch size 1 is the robot's only batch size, and a 7B model at batch 1 is memory-bandwidth bound. Halving arithmetic width buys far less than the FLOP count suggests.
- None of this shows up at batch 32, which is how most quantisation results are reported.

What the runtimes actually support, August 2026
Support is not the same as a working VLA path. A runtime can advertise FP8 and still offer no route from a diffusion-head robot policy to a quantised engine.
| Runtime | Formats | Calibration | Jetson | Realistic VLA status |
|---|---|---|---|---|
| TensorRT 11.2 | INT8, FP8, INT4, FP4 via Q/DQ | yes, for activations | yes | engines build; placing Q/DQ in a VLA graph is your job |
| TensorRT Model Optimizer | INT8, SmoothQuant, FP8, NVFP4 | 128 to 512 samples | aarch64 builds exist | the practical PTQ front end |
| TensorRT-LLM | FP8 weights, FP8 KV cache | 512 calib batches in the example | no | LLM-shaped models only, no diffusion head |
| bitsandbytes | LLM.int8(), NF4, FP4 | none, data-free | source build required | easiest to try, weakest speed guarantee |
| torchao | int8 dynamic, float8, int4 weight-only, QAT | config-dependent | yes, with a matching wheel | closest to a general PyTorch answer |
| Isaac-GR00T scripts | bf16 only | n/a | yes, Orin and Thor | no quantisation offered |
| LeRobot | none | n/a | n/a | no quantisation path for policies |
Two rows contradict the marketing. TensorRT-LLM's FP8 guide states FP8 is supported only above compute capability 8.9: Ada, Hopper, Blackwell and later. An AGX Orin 64GB is Ampere, quoted at 275 sparse INT8 TOPS, with no FP8 path. Jetson Thor (25 August 2025) is Blackwell: 2070 sparse FP4 TFLOPS, 517 dense FP8 TFLOPS, 128 GB LPDDR5X at 273 GB/s, 130 W. If your plan says FP8 and your board says Orin, the plan is wrong.
NVIDIA's own GR00T path is bf16, and still 2.35x faster
The Isaac-GR00T deployment guide documents a full TensorRT pipeline for GR00T N1.7: export to ONNX, build engines, verify against PyTorch, benchmark. The precision flag exists and accepts exactly one value.
# Isaac-GR00T, scripts/deployment/build_trt_pipeline.py
# --precision default: bf16 "Precision for ONNX export and TRT engine build (bf16 only)"
uv run python scripts/deployment/build_trt_pipeline.py \
--model-path checkpoints/GR00T-N1.7-LIBERO/libero_10 \
--dataset-path demo_data/libero_demo \
--embodiment-tag LIBERO_PANDA \
--export-mode full_pipeline \
--batch-size 1 \
--workspace 8192 \
--steps export,build,verify,benchmarkThe speedups are real anyway. NVIDIA's table, measured at 4 denoising steps with 1 camera, shows what compilation alone does.
| Device | PyTorch eager | TensorRT full pipeline | Speedup |
|---|---|---|---|
| H100 80GB HBM3 | 85.8 ms (11.7 Hz) | 27.9 ms (35.9 Hz) | 3.08x |
| RTX Pro 6000 Blackwell | 78.4 ms (12.8 Hz) | 27.9 ms (35.9 Hz) | 2.81x |
| L40 | 128.3 ms (7.8 Hz) | 38.4 ms (26.0 Hz) | 3.34x |
| DGX Spark | 126.4 ms (7.9 Hz) | 98.6 ms (10.1 Hz) | 1.28x |
| AGX Thor | 112.8 ms (8.9 Hz) | 80.4 ms (12.4 Hz) | 1.40x |
| Jetson Orin | 354.0 ms (2.8 Hz) | 150.9 ms (6.6 Hz) | 2.35x |
Note the ordering. Orin gains 2.35x with no precision reduction at all, beating the 1.49x that QVLA reports for mixed-precision quantisation of OpenVLA-OFT and the 1.52x in Mix-QVLA. Kernel fusion, static shapes and removing Python from the loop are cheaper than bit width and do not touch the weights. Do them first.
The GR00T pipeline has a verify step that compares TensorRT output against PyTorch and expects cosine similarity of 0.999 or better. In its LIBERO closed-loop check over 20 episodes, PyTorch scored 20/20 and TensorRT 19/20, inside simulation noise. That is what a safe optimisation looks like: a gate you can run. Hold your quantisation to the same standard.
Do it yourself: the two paths that work
bitsandbytes if you are VRAM-bound and want an answer in ten minutes. TensorRT Model Optimizer if you want throughput and will build a calibration loop.
Path A: bitsandbytes, data-free, memory-first
- 1Check compute capability first
LLM.int8() needs capability 7.5 or newer (Turing); NF4 and FP4 need 6.0 or newer (Pascal). The library itself needs Python 3.10+ and PyTorch 2.4+.
bashpython -c "import torch; print(torch.cuda.get_device_capability())" # (8, 9) = Ada, FP8-capable # (8, 7) = Jetson Orin, INT8 only # (7, 5) = Turing, the LLM.int8() floor pip install --upgrade transformers accelerate bitsandbytes - 2Load the backbone in 4-bit NF4
This is the config the OpenVLA repository uses for quantised LoRA fine-tuning in vla-scripts/finetune.py, gated behind --use_quantization, which asserts LoRA is also on.
pythonimport torch from transformers import AutoModelForVision2Seq, BitsAndBytesConfig quantization_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16, bnb_4bit_use_double_quant=True, # a further ~0.4 bits per parameter ) model = AutoModelForVision2Seq.from_pretrained( "openvla/openvla-7b", quantization_config=quantization_config, low_cpu_mem_usage=True, trust_remote_code=True, device_map="auto", ) print(model.get_memory_footprint()) - 3If you insist on 8-bit, learn the threshold knob
llm_int8_threshold decides which hidden-state values count as outliers and stay in fp16. The documented default is 6. Setting it to 0.0 speeds inference up at some accuracy cost, which is exactly the trade the OpenVLA numbers warn about.
pythonquantization_config = BitsAndBytesConfig( load_in_8bit=True, llm_int8_threshold=6.0, llm_int8_skip_modules=["lm_head"], ) - 4Measure at batch 1, on the board, with the cameras attached
Not throughput. Wall-clock milliseconds from observation to action at batch 1, including preprocessing, on the machine that holds the arm. Then compare against the rate your episodes were recorded at.
pythonimport time, torch for _ in range(5): # warmup: engines, caches, autotune _ = policy.select_action(obs) torch.cuda.synchronize() t0 = time.perf_counter() for _ in range(50): _ = policy.select_action(obs) torch.cuda.synchronize() print(f"{(time.perf_counter() - t0) / 50 * 1000:.1f} ms per action step")
The bitsandbytes aarch64 wheels on PyPI target aarch64-sbsa, server ARM with the standard CUDA Toolkit. The installation guide states they are not compatible with the L4T runtime on Jetson (Orin Nano / NX / AGX, Xavier, Thor on CUDA 12), even though both are aarch64. It installs cleanly, then fails on the first CUDA op with Error named symbol not found in /src/csrc/ops.cu. The documented fixes: an on-device source build with the capability passed explicitly, cmake -DCOMPUTE_BACKEND=cuda -DCOMPUTE_CAPABILITY=87 . && make -j4 && pip install . for Orin (72 for Xavier), or a prebuilt wheel from the Jetson AI Lab index.
Path B: TensorRT Model Optimizer, calibration-first
ModelOpt produces a quantised checkpoint TensorRT can compile, and simulates quantisation in PyTorch first, so you can measure the accuracy hit before committing to an engine build.
# pip install -U nvidia-modelopt[all]
import modelopt.torch.quantization as mtq
# Named configs shipped by the library:
# mtq.INT8_DEFAULT_CFG per-tensor activations, per-channel weights
# mtq.INT8_SMOOTHQUANT_CFG shifts activation outliers into the weights first
# mtq.FP8_DEFAULT_CFG compute capability 8.9 or newer
# mtq.NVFP4_DEFAULT_CFG Blackwell only
def forward_loop(model):
# 128 to 512 real observations is the documented range.
# Use frames from YOUR episodes, in the lighting you will deploy in.
for batch in calib_loader:
model(batch)
model = mtq.quantize(model, mtq.INT8_DEFAULT_CFG, forward_loop)The calibration set is what people get wrong. It sets the scale factors, and therefore the clamp points. Calibrate on bright tidy frames, deploy under a different lamp, and real activations clip. Draw calibration frames from your own LeRobot dataset: same scene, same cameras, same exposure. If the dataset is thin, fix that first; the guide on collecting high-quality VLA training data is the prerequisite.
If PTQ costs too much, quantisation-aware training is the escalation. torchao ships a QAT recipe (prepare, fine-tune, convert) and reports recovering 96 percent of the accuracy degradation on hellaswag and 68 percent of the perplexity degradation on wikitext for Llama 3 against plain PTQ. For a robot policy that means folding QAT into the fine-tuning run rather than bolting it on afterwards.
Two ways to get a fast policy onto an SO-100
- Record with LeRobot and convert to the format the policy needs. GR00T wants v2.0 or v2.1; a v3.0 dataset crashes its loader.
- Rent or buy a GPU and fine-tune. openpi documents more than 70 GB for a full Pi0.5 fine-tune, more than 22.5 GB for LoRA.
- Pick a board. Orin means INT8 is your ceiling; Thor adds FP8 and FP4.
- Export to ONNX, build a TensorRT engine per GPU architecture (they are not portable), verify cosine similarity against PyTorch.
- Build a calibration loader from 128 to 512 of your own frames, run PTQ, re-verify.
- Benchmark at batch 1 on the board, then run a closed-loop success-rate evaluation. Quantisation you have not evaluated on the robot is a guess.
- Rebuild when the GPU, batch size or camera count changes.
Steps 4 to 6. Engines are GPU-architecture-specific and batch size is baked in as a static dimension, so every hardware change means a rebuild and a re-verify.
- Record with the desktop client, which writes LeRobot-format episodes straight from a teleop session.
- Pick a model and an arm from the matrix on /train. The backend rents a GPU on a spot market sized by required VRAM and runs the trainer.
- Serving is automatic:
/api/inference/podprovisions a cloud GPU pod and the local robot client talks to that endpoint. Pods carry an idle watchdog and destroy themselves, so nothing bills silently. - Because the pod is sized to the model, not to a 25 W board, there is nothing to quantise. GR00T N1.7 runs at its stated 152 ms per action step, ACT at 20 ms.
- The same operations are on the CLI and the MCP server, so sweeps are scriptable.
Cloud serving removes the VRAM problem and replaces it with a distance problem. The control loop is 20 to 485 ms per action step, and internet round trips on top turn a working policy into a hesitant one. Remote inference is viable for slow pick-and-place, not fast reactive motion. If your task is reactive, the compute must sit next to the servos, and quantisation is back on your plate.

Is it worth it
- Memory is the hard constraint on an embedded board, and quantisation attacks it directly: 16.8 GB down to 7.0 GB at int4.
- It turns an impossible deployment into a possible one. A model that does not fit has a success rate of zero.
- Weight-only 4-bit is data-free: no calibration set, no extra training run.
- Mix-QVLA reports 15.4 GB down to 4.1 GB with 96.3 percent average LIBERO success against a 97.1 percent BF16 baseline.
- Native low precision is where the silicon is going: Thor quotes 517 dense FP8 TFLOPS in 130 W.
- 8-bit frequently costs latency instead of saving it, and on OpenVLA that meant 13.2 points of success rate.
- Every gain is hardware-conditional, and TensorRT engines do not move across architectures.
- Calibration is a data problem in engineering clothes. A mismatched set silently clips activations.
- The tooling does not meet VLAs halfway: Isaac-GR00T is bf16 only, LeRobot has no quantisation path, TensorRT-LLM ignores diffusion action heads.
- Knowing whether it worked needs a closed-loop success-rate evaluation, which costs robot hours most projects have not budgeted.
Where quantisation is the wrong lever
| Symptom | What people try | What is usually true |
|---|---|---|
| Policy is jerky or overshoots | quantise to go faster | the loop rate no longer matches the recording rate |
| Out of memory during training | quantise the model | training memory is optimiser state and batch size, not inference precision |
| Remote inference feels laggy | quantise the served model | the GPU is not the bottleneck, the network round trip is |
| ACT is too slow | quantise ACT | ACT is ~80 M parameters at 20 ms per step; nothing to reclaim |
| Model will not fit on the board | compile harder | the genuine case: weight-only 4-bit first, then PTQ |
That last row deserves a positive statement. When the model genuinely does not fit, quantisation is the enabling step. BitVLA trains a VLA natively in 1-bit, every parameter ternary, on top of BitNet b1.58 2B4T, and reports 11.0x lower memory and 4.4x lower end-to-end latency than OpenVLA-OFT at comparable performance. That is co-designing the policy for the precision rather than squeezing a bf16 checkpoint afterwards. The overview of VLA models and the Pi0 flow-matching write-up sit one layer below this page.
The smaller policies here make the same point without exotic arithmetic. SmolVLA is around 450 M parameters at 245 ms per step, ACT around 80 M at 20 ms, and both run locally on a 24 GB card. Choosing a smaller architecture is a cleaner route to a latency target than quantising a 3 B model into a shape its authors never validated. See ACT against SmolVLA, or the arena with 85 VLA models and 332 benchmark results.

An order of operations that does not waste a week
- Measure per-step latency at batch 1 on the target board with the cameras attached.
- Write down the control rate your episodes were recorded at. If the two disagree, that is the bug, and precision will not fix it.
- Remove Python from the hot loop. On Orin, NVIDIA measured 1.56x from torch.compile alone before any TensorRT work.
- Compile to TensorRT at bf16 and verify cosine similarity against PyTorch: 2.35x on Orin with zero precision loss.
- Only now consider precision: weight-only 4-bit if VRAM-bound, INT8 PTQ with real calibration data if compute-bound.
- Re-run the closed-loop success rate. A throughput number without a success rate is not evidence.
- If PTQ costs too much, move to QAT inside the fine-tuning run rather than accepting the loss.
The five trainable policies here span a 24x range in per-step latency: ACT 20 ms, GR00T N1.7 152 ms, GR00T N1.5 165 ms, SmolVLA 245 ms, Pi0.5 485 ms. Before spending a week on quantisation, spend an hour on the model comparison and the GR00T N1.7 against Pi0.5 head-to-head. Swapping architecture is usually the bigger and safer lever.

Frequently asked questions
Does INT8 always make a VLA faster?▾
No. In the OpenVLA paper 8-bit ran at 1.2 Hz on the authors' A5000, against a 5 Hz recorded controller, and the Bridge success rate fell from 71.3 to 58.1 percent. At batch size 1, the only batch size a robot uses, a 7B model is bandwidth-bound, so halving arithmetic width buys little.
Can I use FP8 on a Jetson Orin?▾
No. TensorRT-LLM documents FP8 as requiring compute capability above 8.9: Ada, Hopper, Blackwell. Orin is Ampere; the AGX Orin 64GB is quoted at 275 sparse INT8 TOPS with no FP8 path. Jetson Thor is Blackwell and quotes 517 dense FP8 TFLOPS plus native FP4.
Why does the Isaac-GR00T TensorRT pipeline not offer INT8?▾
Its build_trt_pipeline.py exposes --precision with bf16 as the only legal value. The speedups come from compiling every component to TensorRT engines and removing Python overhead: 3.08x on H100, 2.35x on Orin, 1.40x on AGX Thor. If NVIDIA has not validated an INT8 GR00T engine, treat a homemade one as an experiment needing its own closed-loop evaluation.
How much calibration data does PTQ need?▾
TensorRT Model Optimizer documents 128 to 512 samples as typical, and the TensorRT-LLM FP8 example uses 512 calibration batches. The count matters less than the match: frames must come from the same scene, cameras and lighting you will deploy in, because they set the clamp points.
Does quantisation help on AY-Robots?▾
Not directly. Training runs on rented A100/H100 or RTX 4090 class GPUs and inference is served from an auto-provisioned pod sized for the model, so VRAM is not the binding constraint. Distance is: the control loop is 20 to 485 ms per step, and internet round trips on top make fast reactive tasks unreliable. Quantisation matters once you move the compute onto the robot.
Is 4-bit really safe when 8-bit was not?▾
It was in that one measurement, and because of speed rather than numerical robustness, so do not generalise. QVLA reports 98.9 percent of original performance at 29.2 percent of the VRAM with a 1.49x speedup, and Mix-QVLA 96.3 percent average LIBERO success against 97.1 percent for BF16. All were measured on OpenVLA-OFT, not on GR00T or Pi0.5.
The short version
Quantisation is a memory tool that sometimes pays out as a speed tool. Treated as the default answer to "the policy is too slow", it costs a week and produces a model that is smaller, no faster and worse at the task. The order that works: measure at batch 1, match the control rate, compile, verify, then reach for bit width. To test the latency question before buying a board, drive a real SO-100 over the internet. The SO-100 setup guide covers the hardware, the training docs cover what the platform sends to the trainer, and pricing covers what a run costs.
Test the latency question before you buy a Jetson
Drive a real SO-100 from your browser with no signup, compare five policies on measured per-step latency, and rent a GPU for a training run from about 1 USD.
Try it without a robotSources
- OpenVLA: An Open-Source Vision-Language-Action Model
- Isaac-GR00T deployment and inference guide
- TensorRT 11.2.1 developer guide: Explicit Quantization
- TensorRT developer guide: Working with Quantized Types
- TensorRT-LLM performance tuning guide: FP8 Quantization
- NVIDIA TensorRT Model Optimizer: PyTorch quantization guide
- bitsandbytes installation guide
- Transformers: bitsandbytes quantization
- LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale
- FP8 Formats for Deep Learning
- BitVLA: 1-bit Vision-Language-Action Models for Robotics Manipulation
- QVLA: Not All Channels Are Equal in Vision-Language-Action Model's Quantization
- Mix-QVLA: Task-Evidence-Aware Mixed-Precision Quantization of VLA Models
- torchao: PyTorch native quantization and QAT
- Introducing NVIDIA Jetson Thor
Sources
- OpenVLA: An Open-Source Vision-Language-Action Model
- Isaac-GR00T deployment and inference guide
- TensorRT 11.2.1 developer guide: Explicit Quantization
- TensorRT developer guide: Working with Quantized Types
- TensorRT-LLM performance tuning guide: FP8 Quantization
- NVIDIA TensorRT Model Optimizer: PyTorch quantization guide
- bitsandbytes installation guide
- Transformers: bitsandbytes quantization
- LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale
- FP8 Formats for Deep Learning
- BitVLA: 1-bit Vision-Language-Action Models for Robotics Manipulation
- QVLA: Not All Channels Are Equal in Vision-Language-Action Model's Quantization
- Mix-QVLA: Task-Evidence-Aware Mixed-Precision Quantization of VLA Models
- torchao: PyTorch native quantization and QAT
- Introducing NVIDIA Jetson Thor
Ready for high-quality robotics data?
AY-Robots connects your robots to skilled operators worldwide.
Get Started