Repository navigation
Description
This issue tracks LeRobot policies exported to ExecuTorch with Torch-TensorRT: which ones run on which GPU, how fast, and what each project still needs to look at. Other backends have their own issues: OpenVINO in #24325, XNNPACK in #24667, Qualcomm in #24668, Core ML and MLX in #24669, the CUDA backend alone in #24684, Vulkan in #24688, and Arm in #24697.
Coverage
| Policy | H100 | A100 | DGX Spark | Thor | Orin Nano | Programs |
|---|---|---|---|---|---|---|
| act | ✅ 2.94 (2.7x) | ✅ 4.24 (3.2x) | ✅ 4.07 (3.2x) | ✅ 8.26 (4.2x) | ✅ 26.0 (1.6x) | TRT 1 |
| cosmos3 | ✅ 282 (4.1x) | ✅ 498 (4.8x) | ✅ 1106 (1.3x) | ✅ 1051 (1.4x) | ➖ | TRT 8 + CUDA 5 |
| diffusion | ✅ 534 (1.6x) | ✅ 737 (3.2x) | ✅ 939 (7.8x) | ✅ 1233 (3.6x) | ✅ 3108 (1.7x) | TRT 3 + CUDA 1 |
| dm05 | 🟡 74.1 (6.6x) | 🟡 111 (9.1x) | 🟡 216 (1.6x) | 🟡 171 (2.8x) | ➖ | TRT 2 + CUDA 1 |
| eo1 | ✅ 57.3 (5.2x) | ✅ 83.1 (6.9x) | ✅ 305 (1.2x) | ✅ 295 (1.3x) | ➖ | TRT 2 + CUDA 1 |
| evo1 | ✅ 28.7 (6.8x) | ✅ 56.5 (6.8x) | ✅ 100 (4.0x) | ❌ | ✅ 1489 (1.0x) | TRT 4 + CUDA 3 |
| fastwam | ✅ 54.2 (8.6x) | ✅ 83.1 (10.5x) | ✅ 191 (1.9x) | ✅ 191 (2.1x) | ➖ | TRT 2 + CUDA 1 |
| fineart_vla | ✅ 105 (2.4x) | ✅ 242 (2.4x) | ✅ 293 (1.6x) | ✅ 693 (1.4x) | ➖ | TRT 1 |
| flux3 | ❌ | 🟡 1370 (1.2x) | ❌ | ❌ | ➖ | TRT 1 + CUDA 1 |
| g05 | ✅ 43.8 (8.9x) | ✅ 62.0 (12.2x) | ✅ 103 (1.8x) | ✅ 96.2 (3.2x) | ➖ | TRT 4 + CUDA 1 |
| gaussian_actor | ✅ 0.58 (3.7x) | ✅ 0.91 (4.0x) | ✅ 0.45 (2.7x) | ✅ 0.42 (3.4x) | ✅ 1.38 (4.0x) | TRT 1 |
| groot | ✅ 18.9 (7.1x) | ✅ 27.7 (8.6x) | ✅ 64.3 (3.4x) | ✅ 57.4 (3.6x) | ✅ 195 | TRT 10 |
| lawam | 🟡 35.1 (5.3x) | 🟡 60.6 (5.9x) | 🟡 73.4 (2.6x) | 🟡 90.3 (2.8x) | ➖ | TRT 2 + CUDA 1 |
| lingbot_va | ✅ 1826 (1.6x) | ✅ 2636 (2.1x) | ✅ 10757 (0.7x) | ✅ 10051 (0.8x) | ➖ | TRT 49 + CUDA 37 |
| lingbot_vla_v2 | ✅ 75.7 (7.8x) | ✅ 99.5 (11.3x) | ✅ 261 (1.4x) | ✅ 848 (0.6x) | ➖ | TRT 3 + CUDA 2 |
| longwam | ✅ 158 (3.2x) | ✅ 330 (3.0x) | ✅ 761 (2.1x) | ✅ 675 (1.7x) | ➖ | TRT 3 + CUDA 3 |
| molmoact2 | 🟡 48.8 (4.4x) | 🟡 84.2 (4.1x) | 🟡 161 (2.5x) | 🟡 152 (2.3x) | ➖ | TRT 1 |
| multi_task_dit | ✅ 80.7 (3.8x) | ✅ 96.9 (5.7x) | ✅ 168 (1.4x) | ✅ 192 (1.4x) | ✅ 486 (2.5x) | TRT 3 + CUDA 1 |
| pi0 | ✅ 36.8 (4.9x) | ✅ 69.5 (4.8x) | ✅ 114 (1.5x) | ✅ 101 (2.0x) | ✅ 543 | TRT 9 |
| pi05 | ✅ 31.5 (6.8x) | ✅ 55.8 (7.2x) | ✅ 92.2 (2.3x) | ✅ 85.7 (2.7x) | ✅ 444 | TRT 9 |
| pi0_fast | ✅ 1576 (1.8x) | ✅ 2329 (2.4x) | ✅ 11661 (1.1x) | ✅ 11667 (1.1x) | ➖ | TRT 3 |
| praxis | 🟡 434 (2.1x) | 🟡 1041 (1.9x) | 🟡 3044 (1.8x) | 🟡 3179 (1.8x) | ➖ | TRT 7 |
| smolvla | ✅ 17.4 (11.6x) | ✅ 28.0 (13.7x) | ✅ 35.9 (2.5x) | ✅ 37.7 (4.5x) | ✅ 176 (4.4x) | TRT 4 |
| tdmpc | ✅ 7.87 (4.7x) | ✅ 13.2 (5.3x) | ✅ 11.1 (1.8x) | ✅ 23.2 (1.8x) | ✅ 82.9 (1.8x) | TRT 1 |
| vla_jepa | ✅ 16.6 (4.9x) | ✅ 27.9 (5.5x) | ✅ 38.7 (1.8x) | ✅ 39.4 (2.4x) | ➖ | TRT 3 + CUDA 2 |
| vqbet | ✅ 2.37 (3.6x) | ✅ 3.20 (3.6x) | ✅ 2.55 (4.2x) | ✅ 3.31 (2.0x) | ✅ 7.80 (2.8x) | TRT 1 + CUDA 1 |
| wall_oss_05 | ✅ 61.9 (5.4x) | ✅ 94.4 (7.2x) | ✅ 187 (1.7x) | ✅ 150 (2.7x) | ➖ | TRT 4 + CUDA 3 |
| wall_x | 🟡 93.6 (4.9x) | 🟡 161 (5.5x) | ❌ | 🟡 457 (1.4x) | ➖ | TRT 41 + CUDA 40 |
| xvla | ✅ 16.5 (4.9x) | ✅ 32.4 (4.2x) | ✅ 49.4 (1.5x) | ✅ 45.8 (1.4x) | ✅ 243 (1.3x) | TRT 1 |
Legend:
- The number: milliseconds to produce one action chunk (batch size 1, median) in
lerobot-rollout --bundle.path, with PyTorch never loaded, inputs and outputs on the GPU, and no operator on the CPU. - In brackets: how many times faster than eager PyTorch (
lerobot-rollout --policy.path) on the same device, checkpoint and dtype, with--tf32=false. No brackets: eager does not fit the device. - ✅ and a number: works with torch 2.15 and the ExecuTorch 1.6 and Torch-TensorRT 2.15 fixes listed under "Built on" (some are still in review).
- 🟡 and a number: works only with PyTorch fixes that are not in torch 2.15 (see "PyTorch" below), so it needs the next torch release. Measured with a torch 2.15.0 build that adds them. For praxis: works only with the Torch-TensorRT fixes named in the notes. For flux3: works only with the flux3 fixes in fix(flux3): pass F3_NATTEN_BACKEND, run the VAE without NATTEN, serve frame checkpoints, and skip repeated work huggingface/lerobot#5213.
- ➖: the model is too big for this device's memory.
- ❌: measured, and it fails; the cause is in the tables below.
- ⏳: this cell is being measured (running or queued).
- Empty: not measured, and no fix in progress.
"Programs": how many TensorRT engines (TRT) and CUDA backend programs (CUDA) the model is split into, not counting the noise draw. On the current build, vqbet, diffusion and multi_task_dit have 1 more CUDA program than before: one of their encoder programs now has a small part on the CUDA backend. wall_oss_05 is split into 4 engines and 3 CUDA programs with the current LeRobot branch (2 and 1 before). pytorch/TensorRT#5022 (uint8 casts) brings it back to 2 and 1.
Notes:
- Every row is on the new build under "Built on" in every column, except lingbot_vla_v2: it uses the Nov 3 LeRobot branch and transformers 5.5.4 in every column, because the new build's branch cannot export it yet (on the DGX Spark with the new ExecuTorch and Torch-TensorRT). Every bundle first passed the export's accuracy check against eager PyTorch.
- DGX Spark is a GB10 (aarch64).
- On the Thor, lingbot_va is slower than eager PyTorch: 10051 ms against 8470 ms per chunk. The cause is not known yet.
- On the Thor, lingbot_vla_v2 splits into TRT 387 + CUDA 386, because LeRobot keeps attention out of TensorRT on this GPU (see the Thor fused attention row under NVIDIA TensorRT). That is why it is slower than eager there.
- praxis (Runway's Praxis-1: bf16, 27B parameters, a mixture of experts with 128 experts and 8 active per token) and longwam are new in LeRobot
main. Praxis-1 has 54 GB of weights and longwam 23 GB, so neither fits the Orin Nano. Its yellow cells need fixes in review on top of Torch-TensorRT 2.15.0: the Torch-TensorRT pull requests listed under "Torch-TensorRT" below. It uses the official ExecuTorch 1.6.0. CUDA backend: share GPU-resident weights in preprocess instead of deep-copying them #24937 (shares weights during preprocessing) lowers export memory when a large part runs on the CUDA backend; this row puts every large part in TensorRT, so it does not need it. The bundle and eager both ran withOMP_NUM_THREADS=8. The speedup is against eager that also decodes the video of the last step, which LeRobot cannot turn off; the bundle does not. To reproduce the praxis row from source, see Praxis-1 (27B) export to ExecuTorch with TensorRT: how to reproduce from source #25019. - flux3 (black-forest-labs/flux-3-action-droid, bf16) needs the flux3 fixes in fix(flux3): pass F3_NATTEN_BACKEND, run the VAE without NATTEN, serve frame checkpoints, and skip repeated work huggingface/lerobot#5213. The flux3 row is built with
--backend.deduplicate_weights=false, because weight sharing makes the TensorRT builder crash on it. - cosmos3 (lerobot/Cosmos3-Edge-Policy-LIBERO, bf16) takes the robot state as a CPU input; its images stay on the GPU.
- pi0 and xvla run in bf16 in every column, because their float32 exports do not fit the Orin Nano.
- On the Orin Nano, evo1 is built at TensorRT optimization level 0 so it fits in 8 GB.
- On the Orin Nano, lawam and vla_jepa are each a single program of about 5 GiB of weights, which needs about 13.5 GiB to compile, more than this 8 GB board has.
- On the Orin Nano, pi05 takes about 425 to 447 ms per chunk depending on the build (TensorRT picks kernels by timing at export, so exports can differ by about 5%; see Builder picks a slower bf16 GEMM kernel on Orin (sm_87): the 160x128x32 tiles run about 24% slower than the builder measured NVIDIA/TensorRT#4937).
- On the Thor, eager with TF32 on is faster than the strict float32 bundles (fineart_vla: 254 against 693 ms).
- diffusion, dm05, eo1, fineart_vla, gaussian_actor, lingbot_vla_v2, molmoact2, multi_task_dit, tdmpc, vla_jepa, vqbet and wall_x use random weights in every column, made by the same script and seed on each device. fastwam uses its real weights in every column.
Built on
One build, made from the same sources for every architecture. Only the lingbot_vla_v2 row still uses the older Nov 3 build, which differs where noted below (see the notes under the table).
Every cell is measured on the 2.15 packages, except molmoact2 on the Thor (still from the earlier build with release candidates of ExecuTorch 1.6 and Torch-TensorRT 2.15): torch 2.15.0, ExecuTorch 1.6.0 from PyPI, Torch-TensorRT 2.15.0 and torch-tensorrt-executorch-runtime 0.2.1 from the 2.15 test index (PyPI now has the same compiled files: pip install "torch_tensorrt[executorch]"), TensorRT 11.4, and the lerobot-export-stack-nov5 branch (see LeRobot below).
- ExecuTorch: 1.6 (now on PyPI). The Nov 3 build was ExecuTorch 1.6 with the same pull requests applied at the heads we measured.
- Merged into ExecuTorch 1.6 (directly or as a pick):
- Fix crashes, wrong outputs and lowering failures in several backends and in exir #24298: crashes, wrong outputs and lowering failures in several backends
- Python runtime: enforce CUDA stream selection rules on the stream itself #24346: CUDA stream rules in the Python runtime
- Keep ops above 6 dims out of XNNPACK and fix quantized ops it leaves out #24380: XNNPACK, ops above 6 dimensions (pick: Keep ops above 6 dims out of XNNPACK and fix quantized ops it leaves out #24445)
- Fix mixed-dtype cat and stack in to_edge and the edge check #24381: mixed-dtype
catandstack(pick: Fix mixed-dtype cat and stack in to_edge and the edge check #24450) - Support 3-D convolution in the portable convolution kernel #24385: 3-D convolution in the portable kernels (pick: Support 3-D convolution in the portable convolution kernel #24460)
- Limit the default thread pool to the allowed CPUs on Linux (not Android) #24395: default thread pool size (pick: Limit the default thread pool to the allowed CPUs on Linux (not Android) #24449)
- Keep Half and BFloat16 sums in float in portable matmul, var, cumsum and pooling kernels, and fix portable cat #24401: Half and BFloat16 sums in portable kernels (pick: Keep Half and BFloat16 sums in float in portable matmul, var, cumsum and pooling kernels, and fix portable cat #24443)
- Fix CUDA mask indexing, CUDA graph outputs and the runtime output-buffer check #24320: CUDA mask indexing, CUDA graph outputs, output buffer check (pick: [release/1.6] Fix CUDA indexing, graph execution and output buffers #24488)
- CUDA backend: per-program weights file names and antialiased resize #24324: CUDA weights file names, antialiased resize (pick: [release/1.6] Fix CUDA weights filenames and antialiased resize #24489)
- CUDA backend: delete each output handle once when a program returns one tensor twice #24420: CUDA output handles deleted once (pick: [release/1.6] Delete duplicate CUDA output handles once #24490)
- CUDA backend: lower fused attention variants #24426: CUDA fused attention variants (pick: [release/1.6] Lower fused CUDA attention variants #24491)
- Fix 0-d tensors, dynamic output sizes and integer reductions, and default to float32 on CPU, in the OpenVINO backend #24377 and OpenVINO: fix bool min/max and masked read lowering, and follow-ups to #24294 #24446: OpenVINO fixes (picks: [release/1.6] Fix OpenVINO scalars, precision, dynamic outputs and reductions #24492, [release/1.6] Fix OpenVINO bool operations and masked reads #24493)
- Add a portable kernel for antialiased bicubic resize #24400: portable antialiased bicubic resize (pick: [release/1.6] Add portable antialiased bicubic resize #24494)
- XNNPACK: fix enable_bf16 load failures and BatchNorm folding into a 3-D linear output #24477: XNNPACK bf16 loading and BatchNorm folding
- CUDA backend: keep wide attention heads that are not a power of 2 off the Triton SDPA kernel #24468: CUDA wide attention heads that are not a power of 2
- CUDA backend: CUDA graph fixes for mask indexing, .item() and changed input shapes, masked copies as where, tensor checks dropped before compiling, float64, _reshape_copy, scatter_reduce and varlen_attn, follow-ups #24326: CUDA graph and lowering fixes,
varlen_attn(pick: CUDA backend: CUDA graph fixes for mask indexing, .item() and changed input shapes, masked copies as where, tensor checks dropped before compiling, float64, _reshape_copy, scatter_reduce and varlen_attn, follow-ups #24512) - OpenVINO: fix wrong outputs when a partition returns a copy of its input #24466: OpenVINO, partitions that return a copy of an input (pick: OpenVINO: fix wrong outputs when a partition returns a copy of its input #24478)
- Python runtime: stop a backend's log from deadlocking 2 threads #24393: log deadlock between 2 threads (pick: Python runtime: stop a backend's log from deadlocking 2 threads #24529)
- Fix export of zero-stride constants and inputs, and of constants that delegates share #24404: zero-stride constants and shared constants (pick: Fix export of zero-stride constants and inputs, and of constants that delegates share #24526)
- CUDA backend: lower rotary embeddings written with complex numbers #24403: CUDA complex rotary embeddings (pick: CUDA backend: lower rotary embeddings written with complex numbers #24550)
- exir and MLX: fix folded-output clones, shared constants, boolean masks, int64 scatter_add, lowering time and memory, and #24404 follow-ups #24481: exir and MLX, folded-output clones and shared constants (pick: exir and MLX: fix folded-output clones, shared constants, boolean masks, int64 scatter_add, lowering time and memory, and #24404 follow-ups #24588)
- Only in the Nov 3 build (none of them touches the GPU backends):
- Merged into main, not picked for 1.6:
- Qualcomm AI Engine Direct - Keep node names unique across the QNN and Samsung passes #24316: Qualcomm, unique node names
- Core ML: run ops on the CPU when Core ML cannot take or return their values #24317: Core ML, uint8 and int8 inputs
- Qualcomm AI Engine Direct - Decompose kept-whole ops that HTP leaves on CPU #24429: Qualcomm, decompose kept-whole ops
- Merged into main, not picked for 1.6:
- Merged into ExecuTorch 1.6 (directly or as a pick):
- Torch-TensorRT: 2.15, plus these pull requests, at the heads we measured (newer heads in the new build).
- Merged into Torch-TensorRT 2.15:
- [2.15] Cherry-pick #4966, #4964, #4963 and #4965 TensorRT#4969: picks of fix(conversion): wrong attention, softmax and integer division results, and attention that fails to build TensorRT#4964 (attention, softmax and integer division fixes), fix(partitioning): resource partitioning RecursionError, tuple outputs and budget TensorRT#4963 (resource partitioning), fix(dynamo): keep, move and refit the tensors that PyTorch nodes read after global partitioning TensorRT#4966 (frozen constants after global partitioning) and feat(conversion): optionally add each shared weight to the network once TensorRT#4965 (add each shared weight once, opt-in)
- [2.15] Pin ExecuTorch 1.6.0 TensorRT#4950: pin ExecuTorch 1.6.0
- fix(dynamo): save programs with no inputs, keep attention masks that are not plain causal, fix uint8 shape ops and views left to PyTorch, show the runtime TensorRT build number, keep plugins that run PyTorch out of ExecuTorch programs TensorRT#4953: programs with no inputs, attention masks, uint8 shape ops, plugins
- Merged into Torch-TensorRT 2.15:
- LeRobot:
mainplus thelerobot-exportand torch-freelerobot-rollout --bundle.pathwork, on thelerobot-export-stackbranch of shoumikhin/lerobot. The policy fixes in it are also open as LeRobot pull requests. The table's rows were measured on the branch as it was on Nov 5, kept aslerobot-export-stack-nov5. The exceptions are praxis, measured on a newer tree whose Praxis recipe matches the current branch within 1% on the H100, flux3, measured on a newer tree with the flux3 fixes, and lingbot_vla_v2, measured on the Nov 3 branch. In the new build, pi0 and pi05 also map transformers 5.22's SigLIP weight names, as feat(policies): load pi0, pi0.5 and pi0-FAST checkpoints without first building random weights huggingface/lerobot#4775 does. - torch 2.15.0, TensorRT 11.4, transformers 5.22.1 (5.5.4 in the Nov 3 build). The yellow cells use torch 2.15.0 with the export fixes from [export] Save and load flat_apply calls, such as indexing inside vmap pytorch#202785 applied, as it was on Oct 31. That pull request has since been split into [export] Save and load flat_apply calls, such as indexing inside vmap pytorch#202785 and [export] Load higher order op regions that return nothing, such as autocast, no_grad and cond pytorch#202925 (both open), and [export] Record fake values for vmap and jvp calls, and keep those calls through dead code elimination pytorch#202929 and [export] Keep no_grad and autocast regions that read a cond's branches or a pytree spec pytorch#202991 (both merged into main, after 2.15).
- GPUs: H100, A100, Jetson AGX Thor, Jetson Orin Nano 8 GB. The Jetson builds are for aarch64 and CUDA 13.2.
How to reproduce a row
This shows xvla on one NVIDIA GPU. The full guide is the export docs on the lerobot-export-stack branch. The install line below takes the newest code on that branch; the table's rows were measured on lerobot-export-stack-nov5.
-
Install, in a new virtual environment. The export compiles CUDA code, so it also needs the CUDA compiler:
pip install "torch_tensorrt[executorch]" pip install "lerobot[export] @ git+https://github.com/shoumikhin/lerobot.git@lerobot-export-stack" pip install "cuda-toolkit[nvcc]==13.2.*" export CUDA_HOME=$(python -c "import os, nvidia; print(os.path.join(list(nvidia.__path__)[0], 'cu13'))") export PATH=$CUDA_HOME/bin:$PATH
-
Export. The export checks itself: it runs one test frame through the bundle and through PyTorch, and prints
Bundle test case: largest difference ... (tolerance ...). It stops if the difference is too large.--tolerancechanges the limit.lerobot-export --policy.path=lerobot/xvla-widowx --policy.dtype=bfloat16 --task="pick up the cube" \ --backend.type=executorch_tensorrt --output_dir=bundles/xvla_trt -
Time the bundle, then eager PyTorch on the same GPU, robot and checkpoint. The bundle run never imports PyTorch.
lerobot-rolloutlogs how long the programs took every 5 seconds. The table's number is the median time per action chunk over 30 chunks, after 3 warm-up chunks.lerobot-rollout --bundle.path=bundles/xvla_trt --robot.type=<your robot> ... --duration=60 lerobot-rollout --policy.path=lerobot/xvla-widowx --policy.dtype=bfloat16 --device=cuda --tf32=false \ --robot.type=<your robot> ... --duration=60
CUDA backend only: use --backend.type=executorch_cuda in step 2. The rest is the same, and the Torch-TensorRT line in step 1 is not needed (pip install 'lerobot[export]' already brings ExecuTorch's CUDA backend on Linux).
Known issues
"Fix" is an open pull request unless it says merged. "Needs a decision" is a design question for the maintainers. "Needs an owner" means nobody is fixing it yet. "Verified" means the policy was measured before and after the fix.
ExecuTorch
- CUDA backend: return an error when an output has no buffer #24640 (C++ abort row) is merged into main, after 1.6.0. Every other pull request in the table below is in ExecuTorch 1.6.0, which is now on PyPI.
- Decide the GIL and
__init__.pyquestions, and pick up the rows marked "needs an owner".
| Problem | Policies | Fix | Status |
|---|---|---|---|
| CUDA backend: no kernel for fused attention that Torch-TensorRT leaves to it, or for complex rotary embeddings. | lingbot_va, fastwam | #24403, #24426 | lingbot_va now compiles, in 1.6.0 |
| CUDA backend: the Triton attention kernel computes only the first 256 values for wider heads that are not a power of 2, with no error. | lingbot_va (CUDA only) | #24427 | Verified, in 1.6.0 |
CUDA backend: no kernel for varlen_attn. |
wall_x | #24326 | Verified, in 1.6.0 |
CUDA backend: same random seed in parallel processes, no bf16 scatter, an extra libgomp dependency, attention reading past the last key. |
all with a CUDA program | #24326, pytorch/pytorch#202902 | Verified, in 1.6.0 (the PyTorch part is merged into main) |
CUDA backend: no kernel for x[mask], stale shapes from CUDA graphs, a too-small output buffer is accepted. |
smolvla (CUDA only) | #24488 | In 1.6.0 |
| CUDA backend: programs in one folder overwrite each other's weights file; antialiased resize does not lower. | all with 2+ CUDA programs | #24489 | In 1.6.0 |
| Python runtime: CUDA stream rules are checked on the wrapper, not on the stream. | none (API) | #24346 | In 1.6.0 |
| Python runtime: a backend's log line can deadlock 2 threads, for example 2 TensorRT bundles in one process. | 2 bundles in one process | #24393 | Verified: 0 of 120 runs hang, 26 of 120 before; in 1.6.0 |
CUDA backend: from C++, a program whose outputs stay on the GPU aborts the process (from_blob: data pointer cannot be nullptr) when the caller gives no output buffer with Module::set_output. TensorRT returns an error (0x12) in the same case. |
C++ callers of CUDA programs | #24640 | Verified on the A100: error 0x12 instead of an abort; merged into main |
The wheel's executorch package has no __init__.py, so executorch.__file__ is None, and the common CMake prefix one-liner os.path.dirname(executorch.__file__) fails. executorch.__path__[0] works. |
C++ users of the wheel | needs a decision: add __init__.py, or document __path__ |
Measured on the 1.6.0 wheel from PyPI |
CUDA backend: bf16 F.grouped_mm (aten._grouped_mm) has no kernel choice on the A100 (sm_80), so the export fails with NoValidChoicesError. |
cosmos3, praxis | needs an owner (#24902) | Measured |
| CUDA backend: no kernel for scatter with a scalar source in deterministic mode. | none yet | needs an owner | Repro |
Python runtime: Method.execute holds the GIL, so other Python threads stall while it runs. |
multi-threaded callers | needs a decision: release the GIL during execute? | Measured |
Torch-TensorRT
- [2.15] Pin ExecuTorch 1.6.0 TensorRT#4950 (the ExecuTorch 1.6.0 pin) and fix(dynamo): save programs with no inputs, keep attention masks that are not plain causal, fix uint8 shape ops and views left to PyTorch, show the runtime TensorRT build number, keep plugins that run PyTorch out of ExecuTorch programs TensorRT#4953 are in Torch-TensorRT 2.15.
- The 2.15.0 wheels, now on PyPI, pin ExecuTorch 1.6.0 and the runtime wheel 0.2.1. Still open: an aarch64 wheel for glibc older than 2.39 (Torch-TensorRT 2.15.0 has only a manylinux_2_39 wheel on aarch64, so pip on older glibc silently installs an old release TensorRT#5034).
- Triage the issues linked in the table below, and pick up the row marked "needs an owner".
- praxis (Praxis-1) needs these pull requests on top of 2.15:
- fix(conversion): leave large aten._grouped_mm to PyTorch instead of the dense lowering TensorRT#5014: large grouped matmuls of mixture-of-experts layers run in PyTorch instead of a dense lowering
- fix(dynamo): release weights before serializing the engine, not after TensorRT#5015: frees the weights before saving the engine, so the export needs less host memory (feat(executorch): let the caller choose the folder for engine files in save() and compile_and_save() TensorRT#5026 also lets the caller choose the folder for engine files while saving, which lowers it further)
- fix(kernels): decline kernels above TensorRT's 48 KiB shared memory limit TensorRT#5016: does not use a custom kernel that needs more than TensorRT's 48 KiB shared memory limit
- fix(kernels): let triton_op kernels opt in to Triton's pointer alignment hint TensorRT#5017: lets custom kernels use Triton's pointer alignment hint
- feat(conversion): run aten._grouped_mm in TensorRT with a grouped GEMM kernel TensorRT#5021: runs the mixture-of-experts grouped matrix multiply in TensorRT with a grouped GEMM kernel
- fix(kernels): let triton_op kernels opt in to Triton's pointer alignment hint TensorRT#5017: lets custom kernels use Triton's pointer alignment hint
- fix(dynamo): keep a select of a uint8 tensor inside the TensorRT engine TensorRT#5019: keeps a select of a uint8 tensor inside the TensorRT engine
- fix(dynamo): keep a cast to uint8 inside the TensorRT engine TensorRT#5022: keeps uint8 casts inside the TensorRT engine
- feat(dynamo): convert stable sort of index tensors with a counting sort TensorRT#5020: sorts the expert indices inside TensorRT, with a stable counting sort
- fix(conversion): compute antialiased resize weights like PyTorch's CUDA kernel TensorRT#5023: computes antialiased resize weights the same way as PyTorch's CUDA kernel
- feat(conversion): convert small antialiased bilinear downscales by default TensorRT#5024: converts small antialiased bilinear downscales by default, so the image preprocessing becomes one TensorRT engine
- fix(executorch): let compile_and_save export engines whose outputs have static shapes TensorRT#5025: lets
compile_and_saveexport engines whose output shapes are static but computed through ops likenonzeroor boolean indexing. Torch-TensorRT 2.15.0 refuses them. - 10 policies export only because some of their ops go to the ExecuTorch CUDA backend next to the TensorRT engines (see "Programs"; wall_x has 41 engines and 40 CUDA programs). It would help if Torch-TensorRT could take these ops, so that each policy builds one engine or a few. The 3 rows before the runtime wheel row list what stays out. fastwam is the exception: its own code copies a tensor to the CPU, which LeRobot has to fix.
| Problem | Policies | Fix | Status |
|---|---|---|---|
index_put for the Qwen3-VL mask writes. |
groot | pytorch/TensorRT#4936 | Merged, in Torch-TensorRT 2.15 |
| A program with no inputs (the noise draw) cannot be saved. | all with noise | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified |
| A block-causal attention mask next to complex numbers becomes plain causal: wrong results, no error. | fastwam | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified on a repro |
Views above 8 dimensions reach the CUDA backend as _reshape_copy, which it cannot run. |
lingbot_vla_v2 | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified |
A shape op on a uint8 input before a cast fails (Could not get tensor shape). |
xvla, fastwam | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified |
| An engine with the ScatterAdd plugin cannot load without libtorch. | lingbot_vla_v2 | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified |
| On the Thor, 360 scatter plugin layers end up in one compiler region and the build fills host memory. | lingbot_vla_v2 | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified: 64 to 13 GiB, 32 to 4 min |
| With CPU offload, complex lowering mixes CPU and CUDA tensors. | fastwam | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified |
| A float64 output gets a cast with no metadata, so saving the program fails. | lingbot_va | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified |
| The runtime reads an input that is not row-major in the wrong order, with no error. | none so far | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified on a repro |
| float32 attention on inputs cast from bf16 does not build. | fastwam | pytorch/TensorRT#4964 | Verified, in Torch-TensorRT 2.15 |
| bf16 attention without an explicit scale loses accuracy (error 0.068, 0.0084 after). | eo1, wall_oss_05, wall_x, molmoact2 | pytorch/TensorRT#4964 | Verified on a repro, in Torch-TensorRT 2.15 |
| Softmax over a size-1 dimension followed by a matmul returns infinity. | none so far | pytorch/TensorRT#4964 | Verified on a repro, in Torch-TensorRT 2.15 |
| Attention with a constant query, key or value does not convert. | flux3 | pytorch/TensorRT#4964 | Verified on a repro, in Torch-TensorRT 2.15 |
| Causal attention with different query and key lengths uses a bottom-right mask, not top-left like PyTorch. | none so far | pytorch/TensorRT#4964 | Verified on a repro, in Torch-TensorRT 2.15 |
Integer division truncates inside engines (x.shape[0] / 2 at 15 gives 7, not 7.5). |
not known yet | pytorch/TensorRT#4964 | In Torch-TensorRT 2.15, not verified on LeRobot |
| Each weight read through a transpose is copied once per reader (a TensorRT issue, see below). | xvla, eo1 | pytorch/TensorRT#4965 (opt-in) | A100 compile peak: xvla 20.5 to 11.0 GiB; in Torch-TensorRT 2.15 |
| Constant folding keeps one copy of a weight per reader. | evo1 | pytorch/TensorRT#4965 | A100 export peak 9.8 to 3.3 GiB; in Torch-TensorRT 2.15 |
| Resource partitioning: recursion error on long chains, split tuple outputs, engines over budget. | xvla | pytorch/TensorRT#4963 | Verified, in Torch-TensorRT 2.15 |
After global partitioning, a PyTorch node cannot find a folded constant (_frozen_param0). |
none so far | pytorch/TensorRT#4966 | In Torch-TensorRT 2.15 |
| Tensors above 8 dimensions (the Qwen-VL image patch layout in the preprocessing) go to the CUDA backend. | eo1, lawam, lingbot_vla_v2, vla_jepa, wall_oss_05, wall_x | pytorch/TensorRT#5028 (opt-in collapse_high_rank_expands) |
In review; measured on wall_oss_05 only |
Antialiased resize (_upsample_bilinear2d_aa, _upsample_bicubic2d_aa) has no converter. |
dm05, evo1, lingbot_vla_v2, vla_jepa, wall_x | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) adds convert_antialiased_resize (off by default) |
Not measured on LeRobot yet |
PyTorch's packed variable-length attention (varlen_attn) has no converter: 32 of wall_x's 40 CUDA programs. uint8 tensors made inside the graph also stay out. |
wall_x, evo1, lingbot_va, wall_oss_05 | issue pytorch/TensorRT#5039 | Open |
The torch-tensorrt-executorch-runtime wheel, which every TensorRT bundle needs. pip install "torch_tensorrt[executorch]" from PyPI installs it (0.2.1) next to Torch-TensorRT 2.15.0 and ExecuTorch 1.6.0, on x86_64 and on aarch64 with glibc 2.39 or newer. On aarch64 with older glibc (for example Ubuntu 22.04), neither PyPI nor the test index has a Torch-TensorRT 2.15.0 wheel (only manylinux_2_39), so pip cannot install 2.15.0 there. It backtracks to older Torch-TensorRT releases, whose executorch extra does not bring the runtime wheel (2.14.0 asks for ExecuTorch below 1.5). The runtime wheel itself has a manylinux_2_35 aarch64 build. |
all, on aarch64 with glibc older than 2.39 | pytorch/TensorRT#4950 (merged into Torch-TensorRT 2.15) fixed the pin; issue pytorch/TensorRT#5034: an aarch64 Torch-TensorRT 2.15 wheel for older glibc | Read from PyPI, the test index and the wheel metadata on Nov 13 |
| The nightly route is not measured on LeRobot yet. The Linux nightlies run again: the newest is 2.16.0.dev from Nov 13, for the torch 2.16 nightly, and its runtime wheel still pins the ExecuTorch nightly from Nov 5. | all, on nightly | issue pytorch/TensorRT#5035 for the pin; measuring the nightly route needs an owner | Read from the nightly index on Nov 13 |
On Torch-TensorRT 2.15, torch_tensorrt.dynamo.compile accepts unknown settings and ignores them with no error. So a misspelled or unsupported setting is silently dropped. Before pytorch/TensorRT#4953 added fallback_pytorch_plugin_ops=True, that setting was dropped this way, an engine could use the ScatterAdd plugin that needs libtorch, and the bundle failed only later, when it loaded without PyTorch. Repro: torch_tensorrt.dynamo.compile(ep, arg_inputs=[x], min_blok_size=1) (misspelled) runs with no error and no warning about the setting, keeps the default min_block_size of 5, and leaves a 3-op graph in PyTorch; torch_tensorrt.compile does the same. |
lingbot_vla_v2 | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) adds the setting and refuses such an engine at save; unknown settings are still ignored: issue pytorch/TensorRT#5040 | Measured on Torch-TensorRT 2.15 with pytorch/TensorRT#4950 and pytorch/TensorRT#4953 |
| Low-memory compile for Jetsons by @cehongwang is in main and in Torch-TensorRT 2.15: pytorch/TensorRT#4853 (release weights after their engine is built) and pytorch/TensorRT#4854 (compile from memory-mapped weights; pytorch/TensorRT#4942, compile from a weights file, was merged into it first). The pi0.5 example pytorch/TensorRT#4949 is in Torch-TensorRT 2.15. It targets large models on 8 GB Jetsons. | g05, evo1, lawam, vla_jepa on Orin Nano | in Torch-TensorRT 2.15 | In Torch-TensorRT 2.15. Measured on the Orin Nano on Nov 5, before Torch-TensorRT 2.15.0 shipped. g05: with pytorch/TensorRT#4853 and a low-memory export (resource partitioning on, weights released after each engine), it exports with only 18 MiB of memory to spare, passes its check (3.48e-03), and runs at 309 ms per chunk in lerobot-rollout --bundle.path (4.7x faster than eager PyTorch). Without pytorch/TensorRT#4853 it runs out of memory while saving. The published g05 recipe does not set these options. Rerun on Nov 13 with the 2.15.0 packages, it still runs out of memory while compiling, so its coverage cell stays ➖. evo1: not with these alone; it fits only at TensorRT optimization level 0 (see the notes). lawam runs out of memory while loading, before TensorRT runs. vla_jepa runs out of GPU memory while building its engines, even with a CPU memory budget. |
With truncate_double=True, repair_double_inputs copies every input of a TensorRT part to the GPU at once, only to read their dtypes. 8 inputs of 512 MiB add 4 GiB to the compile peak; flux3_droid reached about 95 GiB. |
flux3 | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified on flux3 |
| Every input of a TensorRT part gets a random example tensor in host memory that conversion never reads. For flux3_droid that is up to 270 GiB per part: the host peak is 433 GB (134 GB without it), and it costs about 35 of the 46 minutes before the last engine build. | flux3 | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Verified on the H100: host peak 433 to 121 GiB. 23 engines then build, and the builder crashes on the 24th (see the segfault row under NVIDIA TensorRT). On the DGX Spark (119 GiB shared by CPU and GPU), an export without this fix was killed for memory at 110.7 GB. |
When a model splits into many TensorRT engines, a weight they all use is copied into each engine. On the Thor, lingbot_vla_v2 reuses its action-expert layers across 10 unrolled denoising steps, and each step's layer is its own engine, so 2.73 GB of unique weights become 28.2 GB. A minimal repro with one weight used 10 times gives 10 engines and 84 MB, against 8.5 MB in one engine. The copies are inside the engines; the ExecuTorch .ptd file is empty. |
lingbot_vla_v2 (Thor) | issue pytorch/TensorRT#5036 (for example, weight-stripped engines fed from one shared store) | Measured |
| About 90 tensors per flux3_droid flow step are 9-D (reshape and permute in its neighborhood attention). TensorRT allows at most 8, so they fall back, and partitioning then packs 1,300 to 2,600 nodes per engine and hands 164 tensors (270 GiB) across one boundary. Once all 24 engines build, loading the program needs 538 GiB of GPU memory at once; in the model's own order the peak is about 10.8 GiB. | flux3 | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) adds collapse_high_rank_permutes (off by default), which folds them to 8-D |
Measured. With the fold, flux3 becomes one engine of 52,473 nodes, and the TensorRT builder crashes on it (see the segfault row under NVIDIA TensorRT). With deduplicate_weights off, that engine builds in 31 minutes, but it needs 203.8 GiB of activation memory, so it still cannot run on an H100. |
| The float32 attention decomposition uses a plain softmax, so a query row where every key is masked (padding) returns NaN. PyTorch returns 0 there. | lingbot_vla_v2 with float32 attention | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) now sends such attention to a decomposition that returns 0 | Not measured on LeRobot yet |
The grouped_mm converter fails with a TypeError in its cast when the offsets are a frozen constant, so the op stays in PyTorch. |
cosmos3 | issue pytorch/TensorRT#5038 | Measured |
Dynamic sequence lengths do not build: the attention and split converters fail when the text length is a symbol (torch.export.Dim). The LeRobot exports use a fixed, padded text length, so none fails, but every call runs attention over the padding. |
none (speed) | issue pytorch/TensorRT#5037 | Repro |
compile_and_save keeps every engine on disk twice by the end of the save (its temporary engine files are deleted only when the call returns), so an export needs free disk for twice its engines. |
none listed (disk) | issue pytorch/TensorRT#5041 | Repro |
| A mixture-of-experts combine fused with the next residual add and RMSNorm gets a slow one-block-per-token kernel (bf16). Speed only. | mixture-of-experts models | issue pytorch/TensorRT#5042 | Repro |
| FP8: a quantizer calibrated on an all-zero input gets scale 0 from ModelOpt 0.48, and the FP8 quantize converter divides by it, so the engine returns NaN. ModelOpt's own fake quantization stays finite. | FP8 exports (not in the table) | pytorch/TensorRT#4978 (in Torch-TensorRT 2.15) | Verified on the H100: fp16 scales give no NaN and stay within 9.8e-4 of ModelOpt; float32 FP8 and INT8 are unchanged, bit for bit |
An all-zero F.pad followed by an elementwise op fails the engine build (fusePattern internal error). SmolVLA's resize_with_pad hits it on 256x256 frames. |
smolvla (256x256 frames) | pytorch/TensorRT#4995 (merged, in Torch-TensorRT 2.15; closes pytorch/TensorRT#4988) | In 2.15.0, not measured on LeRobot yet |
| int8 math with an int8 constant does not wrap on overflow: wrong results, no error. Comes with pytorch/TensorRT#4978; main refused to build these graphs. | none so far | pytorch/TensorRT#4989 | Known issue for 2.15, targeted for 2.16 |
With enable_autocast, an in-place update is lost through a view taken before it: wrong results, no error. The default path is correct. Comes with pytorch/TensorRT#4978. |
none so far | pytorch/TensorRT#4990 | Known issue for 2.15, targeted for 2.16 |
| ExecuTorch CUDA graph replay stops replaying when buffers move and shapes change often. Speed only. Comes with pytorch/TensorRT#4983. | none in steady state | pytorch/TensorRT#4991 | Known issue for 2.15, targeted for 2.16 |
NVIDIA TensorRT
These are bugs in TensorRT itself (11.4 unless noted). Each one reproduces with TensorRT alone; we can share the repros.
- Triage the rows below. "Workaround" says where Torch-TensorRT avoids one for now.
| Problem | Policies | Workaround | Status |
|---|---|---|---|
| The builder keeps a host copy of a weight for every layer that reads it through a transpose: 1 GiB of weights with 10 readers costs 10.9 GiB. | xvla, eo1, flow-matching on 8 GB Jetsons | pytorch/TensorRT#4965 (opt-in) | Filed: NVIDIA/TensorRT#4934 |
| With weight sharing on, dm05's RoPE table is one constant read by 290 matmuls, and the engine returns wrong results (0.246, 0.0039 without sharing). For flux3, weight sharing makes the TensorRT builder crash. | dm05, flux3 | turn sharing off (--backend.deduplicate_weights=false, used for the dm05 and flux3 cells) |
Does not reproduce on a newer Torch-TensorRT 2.15 build: on the H100, dm05 passes with sharing on (3.91e-03). A100 and Thor not measured again yet. |
On the Thor (sm_110) only, the fused attention kernel (_gemm_mha_v2) rounds the scores to bf16 whenever the attention has a mask, bool or float; without a mask, and on H100, A100 and Orin with the same TensorRT, it keeps float32. Seen with TensorRT 11.4.0.106 on JetPack 7.2.1 (driver 595.78, CUDA 13.2), shapes such as 8 heads, 50 queries, 805 keys, head size 64. A repro that uses only the TensorRT Python API gives 0.12 error against 0.009 for PyTorch. evo1 and lingbot_vla_v2 miss their check there (1.65 and 1.10, limit 0.075). |
evo1, lingbot_vla_v2 | none (float32 inputs avoid it but cost 2.2x) | Filed: NVIDIA/TensorRT#4938 |
The builder crashes (segfault) when one scaled query (q * c, with c a constant) is read by 2 IAttention layers. A 6-layer network with only TensorRT and numpy crashes in about 5 s on H100 and A100, with every TensorRT tried from 10.16 to 11.4.0.106. It builds with 1 attention, with no scale, or with 2 different scale constants. flux3_droid hits it because 2 unrolled flow steps run the same attention block on the same conditioning input, so after TensorRT merges the identical work, one scaled query feeds both attentions. Without the 9-D fold (Torch-TensorRT table), 23 of flux3's 24 engines build and the 24th crashes here. |
flux3 | none yet | Repro ready |
| TensorRT 10.16 (JetPack's system TensorRT) returns NaN for bf16 causal attention. | JetPack users | none | Not reproduced on Nov 13: 23 bf16 causal shapes gave finite results on Thor with its system TensorRT 10.16.2.10. Closed unless it shows up again. |
| float32 attention on inputs cast from bf16 fails to build or crashes. | fastwam | pytorch/TensorRT#4964 | Filed: NVIDIA/TensorRT#4936 |
| On the Thor, newer-interface plugin layers end up in one compiler region, and the build grows host memory by 64 GiB (14 to 16 GiB on H100 and A100). | lingbot_vla_v2 | pytorch/TensorRT#4953 (in Torch-TensorRT 2.15) | Repro |
| A constant key read through a transpose is folded wrongly in fp16 and bf16 (error 1.8). | constant-key attention | pytorch/TensorRT#4964 | Filed: NVIDIA/TensorRT#4935 |
Fused attention (bf16, with a bool mask that is a run-time tensor) never returns from its first execute at 2176 to 2304 query rows: one _gemm_mha_v2 kernel stays busy, with no error. |
none blocked today | none | Filed: NVIDIA/TensorRT#4932 |
| An engine build holds the caller's host weights, a second host copy inside the builder, and a GPU copy: about 2.3 times the weights in host memory and 1.1 times on the GPU, in every build mode (measured on A100). Where CPU and GPU share memory, that is about 3.4 times the weights. | lawam, vla_jepa on Orin Nano (one reason) | none | Filed: NVIDIA/TensorRT#4933 |
| On the Orin Nano (sm_87), for one bf16 GEMM shape the builder picks between near-tied kernels, and the 160x128x32 one runs about 24% slower than the builder measured. 9 of 10 builds pick it. | pi05 (Orin Nano), speed only | none | Filed: NVIDIA/TensorRT#4937 |
| The fused attention kernel is 12% slower than unfused for evo1's shape (8 heads, 50 queries, 805 keys, head size 112). | evo1 | none | Measured |
With an IIfConditional, rows past the optimization profile's opt size are left unwritten. Network: float16 input of shape (-1, 6), profile min/opt/max 2/1000/300000, the conditional picks x * 10 or x * 2. Run at 300,000 rows, every row from 1000 on keeps its old value in 12 of 22 builds of the same network (TensorRT 11.4.0.106, H100). The same network without the conditional is correct in 6 of 6 builds. Run at 500 rows, 4 of 6 builds also write 72 values past the end of the output. |
none so far | none | Repro ready |
PyTorch
These show up only when a program is saved and loaded, or compiled ahead of time.
- Review the pull requests below. None is in torch 2.15, so the yellow cells need a patched torch until a release has them. Could they go into a 2.15.x patch?
- Pick up the row marked "needs an owner".
| Problem | Policies | Fix | Status |
|---|---|---|---|
torch.export.save cannot save flat_apply (transformers' mask functions). |
wall_x, dm05 | pytorch/pytorch#202785 | Verified; a small repro is available on request |
torch.export.load loses metadata on autocast regions that return nothing. |
lawam, molmoact2 | pytorch/pytorch#202925 | Verified |
A program with varlen_attn cannot be loaded after a plain import torch. |
wall_x | pytorch/pytorch#202925 | Verified |
torch.export recompiles the whole graph once per no_grad or autocast region, so an export with many regions takes hours (dm05 about 40 min on an H100 host; molmoact2 over 4 h on Thor without finishing). |
dm05, molmoact2 | pytorch/pytorch#204723 | In review |
A failing check inside a no_grad region leaves grad mode off. |
none so far | pytorch/pytorch#202898 | Merged into main (after 2.15), not verified |
| AOTInductor autotuning runs a gather with a bounds check on made-up inputs, and the compile fails. | vla_jepa (CUDA only) | pytorch/pytorch#202931 | Verified, merged into main (after 2.15) |
If PyTorch first lists its device constructors while transformers has torch.linspace swapped, later linspace calls ignore their device. |
models built on the meta device | needs an owner | Found on LeRobot |
LeRobot
- Review the open pull requests:
- Import speed
- refactor: load robots, cameras and the rollout helpers without PyTorch huggingface/lerobot#4820: load robots, cameras and the rollout helpers without PyTorch
- Installing
- fix(policies): install the dataset extra with policies that render a recipe huggingface/lerobot#5365: g05, eo1, wall_x, fineart_vla and wall_oss_05 install the dataset extra that their recipe step needs
- Loading checkpoints
- feat(policies): load pi0, pi0.5 and pi0-FAST checkpoints without first building random weights huggingface/lerobot#4775: pi0, pi0.5 and pi0-FAST without random init, and with transformers 5.22's SigLIP weight names
- feat(policies): load GR00T fine-tunes without NVIDIA's base model huggingface/lerobot#4778: GR00T fine-tunes without NVIDIA's base model
- fix(groot): preprocess reloaded N1.7 frames on the policy device huggingface/lerobot#5195: GR00T N1.7 preprocesses reloaded frames on the policy device
- fix(fastwam): follow device moves, serve chunks, and run bfloat16 on the CPU huggingface/lerobot#5196: FastWAM follows device moves, serves chunks, and runs bfloat16 on the CPU
- fix(diffusion): load weights saved with the other compile_model setting huggingface/lerobot#5352: diffusion loads weights saved with the other
compile_modelsetting - refactor(policies): load a trained policy or its PEFT adapter once, straight onto its device huggingface/lerobot#5354: load a policy or its PEFT adapter once, straight onto its device
- feat(policies): load and run chosen parts of pi0.5 and GR00T N1.7 huggingface/lerobot#5359: load and run chosen parts of pi0.5 and GR00T N1.7
- Policies that pass
torch.export- fix(policies): let 11 policies pass torch.export huggingface/lerobot#5150: 11 policies
- fix(molmoact2): let single-example inference export with torch.export huggingface/lerobot#5147: molmoact2
- fix(policies): let EO-1, WALL-X and Wall-OSS 0.5 pass torch.export huggingface/lerobot#5162: eo1, wall_x, wall_oss_05, and wall_x's text attention scores kept in float32
- fix(policies): let LingBot-VLA v2, LaWAM, VLA-JEPA and the GR00T N1.7 backbone pass torch.export huggingface/lerobot#5163: lingbot_vla_v2, LaWAM, VLA-JEPA, the GR00T N1.7 backbone, and LaWAM's whole action prediction exported on a vision grid
- CPU and kernels
- fix(lawam): let the VLM-to-LAM head take bfloat16 hidden states without autocast huggingface/lerobot#5214: LaWAM head in bf16 on the CPU
- fix(flux3): pass F3_NATTEN_BACKEND, run the VAE without NATTEN, serve frame checkpoints, and skip repeated work huggingface/lerobot#5213: flux3 passes its backend to NATTEN, runs the VAE without NATTEN, serves frame checkpoints, and skips repeated work
- Import speed
- Decide the rows marked "needs a decision" and pick up the ones marked "needs an owner".
| Problem | Policies | Fix | Status |
|---|---|---|---|
lerobot-export and the torch-free lerobot-rollout --bundle.path exist only on the lerobot-export-stack branch. |
all | needs a decision: how to bring them upstream in reviewable pieces | Open |
| The export check for lingbot_va cannot work: rounding alone moves it to 0.52 against a limit of 0.2. Checking each program on its own inputs does work (correct programs within 1.85x their noise, broken ones 9x or more). | lingbot_va | needs a decision: check per program | Measured |
| evo1's check uses 1 test frame where 2 gripper choices are nearly tied, so a correct float32 run fails it (1.48). Checking 16 frames and allowing up to 4 gripper flips passed all 30 correct runs and still caught the Thor bundle. | evo1 | needs a decision: check 16 frames | Measured |
lerobot-rollout cannot feed tdmpc its environment state on the test robot, so it has no timing. |
tdmpc | a checkpoint with a camera, fed through --rename_map |
Done, all 4 cells |
| wall_x's check on the A100 lands between 0.060 and 0.125, depending on which kernels TensorRT picks. Eager PyTorch on the A100 alone moves it by 0.043 to 0.092 under standard bf16 settings, so the 0.075 limit sits at the rounding noise. Its 10 bf16 flow steps fall under LeRobot's rule for a 0.2 limit (used for pi0, pi0.5, eo1, wall_oss_05, dm05, fineart_vla and molmoact2), but the wall_x recipe keeps 0.075. On the DGX Spark it lands at 0.224 (0.186 with the CUDA backend alone, so not from TensorRT), with the same weights as the other columns. | wall_x | needs a decision: use the 0.2 limit | Measured |
| The export refused the flux3 checkpoint, which needs history conditioning. | flux3 | the flux3 fixes in huggingface/lerobot#5213 encode the task frame directly, which removes the 9-D fold, and compute the text stream once per chunk | Measured on the A100 |
| On the Orin Nano, the export loads weights the program never reads (vla_jepa 1.8 GiB, lawam 1.6 GiB) and runs out of memory. | lawam, vla_jepa | needs an owner | Open |
evo1 fits the Orin Nano only at TensorRT optimization level 0, which lerobot-export cannot pass yet. |
evo1 | needs an owner | Open |
| On the DGX Spark (aarch64), lingbot_va is slower than eager PyTorch both with TensorRT (0.7x) and with the CUDA backend alone (0.7x, 10.7 s against 7.6 s), so the cause is not TensorRT. On the H100 both are faster than eager. | lingbot_va | needs an owner: profile it | Measured, not profiled |
Thanks to Adrian Wang (@cehongwang) for the low-memory Jetson path: pytorch/TensorRT#4854 compiles from memory-mapped weights, and pytorch/TensorRT#4949 deploys pi0.5 with ExecuTorch and TensorRT.
Activity
docs: bring lerobot-export and bundle-mode docs up to date
docs: bring lerobot-export and bundle-mode docs up to date
docs: bring lerobot-export and bundle-mode docs up to date
docs: bring lerobot-export and bundle-mode docs up to date
docs: bring lerobot-export and bundle-mode docs up to date
fix(lingbot_va): check each compiled program on its own in half preci…
docs: bring lerobot-export and bundle-mode docs up to date
fix(lingbot_va): check each compiled program on its own in half preci…
docs: bring lerobot-export and bundle-mode docs up to date
fix(lingbot_va): check each compiled program on its own in half preci…
docs: bring lerobot-export and bundle-mode docs up to date
fix(lingbot_va): check each compiled program on its own in half preci…
fix(lingbot_va): check each compiled program on its own in half preci…