mlx-smolvla
Run SmolVLA checkpoint inference, LeRobot-protocol serving, and preview fine-tuning natively with MLX on Apple Silicon—without Torch, Transformers, or LeRobot in the base runtime.
On the pinned Apple M5 Pro test case, MLX fp32 produced a 50-action chunk in 110.75 ms median versus 204.58 ms for PyTorch-MPS (1.847× faster), while that chunk represents 1.67 s at 30 fps (about 15.0× real-time duration); scope and raw timings are in the benchmark evidence.
Hardware validation: a final 60-second no-motion loop, one valid guarded action, and a two-chunk bounded-continuous run passed on a connected SO-101. A separate 20-chunk attempt disabled torque safely but failed exact return under the temporary 10% torque profile. This is bounded integration evidence, not reliable task success or sustained 20-chunk validation. See the first-contact status and media guidance.
Requirements
| Requirement | Supported release surface |
|---|---|
| Mac | Apple Silicon |
| macOS | 14 or newer |
| Python | 3.11-3.13 for inference; 3.12-3.13 for reference, serve, train, and hardware extras |
| MLX | 0.32.0, 0.32.1, or 0.32.2 |
All three MLX versions passed conversion, strict deterministic checks,
production fp32/bf16 statistical gates, installed offline prediction, doctor,
and loopback serving on macOS-14-compatible official wheels. See the
compatibility matrix for exact wheel and
dylib inspection evidence.
Install
When the operator publishes v0.1.0 to PyPI:
python -m pip install mlx-smolvla
Until then, install from a checkout:
git clone https://github.com/daniiarabdiev/mlx-smolvla.git
cd mlx-smolvla
python -m pip install .
mlx-smolvla doctor
The first online load downloads and converts the checkpoint once. Converted
weights default to ~/.cache/mlx_smolvla; set MLX_SMOLVLA_CACHE or pass
cache_dir= to move them. A populated cache supports subsequent
HF_HUB_OFFLINE=1 loads.
Run a checkpoint
The Python path is three lines once observation contains two CHW uint8
camera arrays, a six-value float32 state, and a task string:
from mlx_smolvla import SmolVLAMLX
policy = SmolVLAMLX.from_pretrained("lerobot/smolvla_base")
action = policy.select_action(observation)
Or predict from a saved observation directory:
mlx-smolvla predict --model lerobot/smolvla_base --observation /path/to/saved-observation
select_action returns one checkpoint-domain action and queues the remainder
of the 50-action horizon; call policy.reset() between episodes. It is a
physical-unit action only when the checkpoint contains effective statistics
for the exact robot state/action interface. The upstream base checkpoint's
saved stats do not bind to observation.state and action, so do not send its
raw output to a robot. Local LeRobot-style checkpoint directories and complete
Hub repository IDs use the same strict configuration/tensor loader. Quantized
vlm-8bit and vlm-4bit presets are explicit production-only opt-ins
documented in the benchmark.
mlx-smolvla predict --observation /path/to/saved-observation --quantization vlm-8bit
mlx-smolvla predict --observation /path/to/saved-observation --quantization vlm-4bit
Dense bf16 remains the default; neither quantized preset is selected implicitly.
Serve for your robot
Install the optional protocol surface and start the trusted loopback server on the Mac:
python -m pip install "mlx-smolvla[serve]"
mlx-smolvla serve --host 127.0.0.1 --port 8080 --dtype bfloat16
A mainline LeRobot 0.6.1 client can connect using its real, operator-reviewed robot and camera configuration:
python -m lerobot.async_inference.robot_client \
--policy_type=smolvla \
--pretrained_name_or_path=<REVIEWED_LOCAL_CHECKPOINT_WITH_MATCHING_ROBOT_STATS> \
--robot.type=so101_follower \
--robot.port=<FOLLOWER_PORT> \
--robot.id=<CALIBRATION_ID> \
--robot.cameras='<CAMERA_CONFIG>' \
--actions_per_chunk=10 \
--task='pick up the object' \
--server_address=127.0.0.1:8080 \
--policy_device=cpu --client_device=cpu --fps=30
The server implements the audited four-RPC LeRobot protocol, but robot I/O and
safety remain the client's responsibility. The generic command above is a
protocol example, not authorization to actuate hardware. This repository now
ships a fail-closed Hiwonder SO-101 client under the optional hardware extra;
one guarded action and a short bounded-continuous run passed on the connected
follower. Review the hardware runbook,
current first-contact status, and
bring-your-own-robot guide. Remote
serving is an explicit trusted-network-only mode because LeRobot 0.6.1 uses
unauthenticated pickle payloads.
Run your own fine-tune
You can train with standard LeRobot on any supported accelerator, keep uploads disabled, then transfer the complete checkpoint directory to the Mac:
python -m pip install "lerobot[training,smolvla]==0.6.1"
lerobot-train \
--policy.path=lerobot/smolvla_base \
--policy.device=cuda \
--policy.push_to_hub=false \
--dataset.repo_id=<USER>/<DATASET> \
--batch_size=64 --steps=200000 \
--output_dir=outputs/smolvla-finetune \
--save_freq=20000 --save_checkpoint_to_hub=false \
--wandb.enable=false
Load its checkpoints/last/pretrained_model directory directly, or use a Hub
ID only after deliberately publishing the complete checkpoint yourself:
policy = SmolVLAMLX.from_pretrained("/path/to/checkpoints/last/pretrained_model")
# policy = SmolVLAMLX.from_pretrained("<USER>/<MODEL>")
The separately pinned public multitask fine-tune passed all eight deterministic cases and its 50-frame fp32/bf16 MAE ratios were 1.0000005749 and 0.9960502782; the public-checkpoint evidence records the immutable revision and regeneration path.
Fine-tune on your Mac (preview)
Native MLX training supports LoRA/full exports and exact resume. Step-zero gradients and 25 optimizer updates pass the fixed lockstep gates. A repaired PyTorch reference loader now preserves the native-trained fp32 weights: the retained expert-only LoRA export passes all 56 fixed-limit cases, with normalized maximum 0.0000214577, physical maximum 0.0004272461 (both below 0.005), and Torch/MLX held-out MAE ratio 1.0000007854. See the repair evidence. Training remains a research preview: this validates one retained LoRA run, while full fine-tuning has code/smoke coverage rather than a long-run task-quality study.
uv sync --extra train
mlx-smolvla train /path/to/lerobot-dataset \
--lora --dtype bfloat16 --steps 30000 --batch-size 8 --lr 1e-4 \
--checkpoint-every 100 --output .cache/training/overnight
Resume the exact output directory with the same arguments plus --resume.
Validate the exported checkpoint before serving it:
mlx-smolvla predict \
--model .cache/training/overnight/export \
--observation /path/to/saved-observation
On the measured host, effective-batch-8 LoRA bf16 ran at 0.873 updates/s, or 19.09 minutes per 1,000 updates; 30,000 updates project to 9.55 hours of optimizer work before checkpoint/export/evaluation overhead, with 2.27 GiB peak MLX memory. The full four-cell protocol and raw timing source are in the training benchmark.
Execution modes
execution_mode="production" is the default MLX Metal path and is accepted by
the pinned 50-frame statistical gate. execution_mode="strict" selects the MLX
CPU compatibility path for bit-close deterministic comparison with PyTorch CPU.
Limitations
- Connected SO-101 state/camera capture, one valid guarded action, and a two-chunk continuous run are validated. A separate 20-chunk attempt failed exact return under the temporary low-torque profile while still disabling torque; first-contact evidence records the bounded result and limitation.
- Raw
lerobot/smolvla_baseoutput is not a physical-action interface because its saved state/action statistics do not bind to the generic keys. Motion clients must use a reviewed checkpoint with effective statistics matching the robot. - Production Metal fp32 passes the statistical gate but fails the strict
0.005deterministic maximum; use strict mode for that contract and see the mode table. - Native training is a research preview. The retained LoRA export passes the post-repair fixed parity gates; this does not establish task success on a robot or generalize to every training run. The original T3B verdict is preserved as historical evidence.
- Checkpoints must match the audited SmolVLA/SmolVLM2 configuration and complete tensor inventory described in the architecture.
- The LeRobot serving protocol is suitable only for trusted peers; security boundaries are documented in the architecture and security policy.
Correctness methodology
The reference lane pins LeRobot 0.6.1, exact model/dataset revisions, fixed
noise, eight real observations, all 16 used prefix layers and K/V boundaries,
the action expert, every Euler step, normalized chunks, and physical actions.
The strict normalized-action maxima are fixed at 0.005 (fp32) and 0.05
(bf16); an independent 50-frame gate requires MLX/reference first-action MAE
<= 1.05. Thresholds are never loosened after evaluation. The
evidence index links reports,
hashes, negative results, and reproduction commands.
Contributing, citation, and license
Start with CONTRIBUTING.md; make test-fast is the iteration
lane and make test is the complete gate. AGENTS.md gives coding
agents the repository map and immutable contracts for agent-assisted work.
Citation metadata is in CITATION.cff. The project is licensed
under Apache-2.0, with upstream attribution in NOTICE.
Acknowledgments
This work builds on SmolVLA,
LeRobot, and
MLX. The SmolVLM backbone work in
mlx-vlm was also a useful architecture
reference; mlx-smolvla does not depend on it at runtime.
Related projects
tokimoa/smolvla-mlx, uploaded
to the Hugging Face Hub on 2026-07-29, is an earlier, independent inference
port of SmolVLA to MLX. This project differs in scope by adding verified parity gates,
a base runtime without Torch or Transformers at runtime,
LeRobot-protocol serving, and training; no comparative performance claim is
made against that project.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mlx_smolvla-0.1.0.tar.gz.
File metadata
- Download URL: mlx_smolvla-0.1.0.tar.gz
- Upload date:
- Size: 444.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c55afe86aa47e59e200a6297584ee3f4f8216153ce8544d0a5bc010cf88b7ce
|
|
| MD5 |
428fc881266bb11eb3dd457964001bf8
|
|
| BLAKE2b-256 |
102aa61df7ddfe44da208e4610cd66b6a6afee71b6a3ee1e35db89480f040ccb
|
File details
Details for the file mlx_smolvla-0.1.0-cp313-cp313-macosx_14_0_arm64.whl.
File metadata
- Download URL: mlx_smolvla-0.1.0-cp313-cp313-macosx_14_0_arm64.whl
- Upload date:
- Size: 378.8 kB
- Tags: CPython 3.13, macOS 14.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a0549d96a70a0b608895829c0148a442334d8741fad1258b70884c272bbada0
|
|
| MD5 |
c30d405cb4ad21c9edcecbf6491d27e2
|
|
| BLAKE2b-256 |
94f381d7807ba76076f717fc07b43e31625a3c94f2a640a616d1376c11e40e94
|
File details
Details for the file mlx_smolvla-0.1.0-cp312-cp312-macosx_14_0_arm64.whl.
File metadata
- Download URL: mlx_smolvla-0.1.0-cp312-cp312-macosx_14_0_arm64.whl
- Upload date:
- Size: 378.7 kB
- Tags: CPython 3.12, macOS 14.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
41ba7c798fa4f7553aaa68e1b22582eff620b1096005cbb895e48d274cf69542
|
|
| MD5 |
da958ab8444cdf6ed7559036fff6499b
|
|
| BLAKE2b-256 |
f27879421b0fdddeb7d5fc0a25941ec9badfbaf4b3e40131f0e6f0fcdfa36749
|
File details
Details for the file mlx_smolvla-0.1.0-cp311-cp311-macosx_14_0_arm64.whl.
File metadata
- Download URL: mlx_smolvla-0.1.0-cp311-cp311-macosx_14_0_arm64.whl
- Upload date:
- Size: 379.7 kB
- Tags: CPython 3.11, macOS 14.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
14ca4c82e55b32203dde420f217fbb064d30d5ea6796852e964205c450ba1944
|
|
| MD5 |
e703be71fbf28b240ffb2baed8c3d33a
|
|
| BLAKE2b-256 |
62fc67d14068646202ad658838728b1b586e2c456400c715fe5726b1d5eed1f5
|