--- license: other license_name: gemma-terms-of-use license_link: https://ai.google.dev/gemma/terms library_name: n0vtla tags: - robotics - vision-language-action - tactile - pi0.5 --- # $\mathcal{N}_0$-VTLA — pretrained base Pretrained base weights for [N0-VTLA](https://github.com/neoteai/N0-VTLA), a vision–tactile–language–action policy: a π0.5-style VLA with a latent tactile pathway. ## Files ``` model.safetensors the full checkpoint (~8.25 GB): π0.5 VLM, flow-matching action expert, latent tactile predictor, and frozen DINOv2, in one state dict config.json architecture summary ``` ## Load ```python from huggingface_hub import snapshot_download import safetensors.torch as st from n0vtla.training.config import get_config from n0vtla.models_pytorch.n0vtla_policy import N0VTLAPolicy ckpt = snapshot_download("NeoteAI/n0-vtla-base") cfg = get_config("vtla_tactile_posttrain") model = N0VTLAPolicy(cfg.model).eval().cuda() missing, unexpected = st.load_model(model, f"{ckpt}/model.safetensors", strict=False, device="cuda") assert not unexpected, unexpected ``` `missing` is expected to contain exactly `paligemma_with_expert.paligemma.model.language_model.embed_tokens.weight`: it is tied to `lm_head.weight` and safetensors stores tied weights once. `unexpected` must be empty. In practice you do not call this yourself — point `VTLA_PRETRAINED_CHECKPOINT` at the download directory and use the post-training recipe: ```bash hf download NeoteAI/n0-vtla-base --local-dir checkpoints/n0-vtla-base export VTLA_PRETRAINED_CHECKPOINT="$PWD/checkpoints/n0-vtla-base" ``` See **Post-training on your own robot data** in the [repository README](https://github.com/neoteai/N0-VTLA). ## Normalization statistics **Not included, by design.** Normalization depends on your dataset, robot action layout, and delta-action convention, so it has to be computed on your own data: ```bash python scripts/compute_canonical_norm.py \ --repo-id /path/to/your/canonical_dataset \ --robot flexiv \ --train-config-name vtla_tactile_posttrain \ --asset-id your_asset_id ``` The result lands in `assets/vtla_tactile_posttrain//norm_stats.json`, and `VTLA_ASSET_ID` must match the `--asset-id` you used. ## Action format The policy outputs normalized element-wise delta actions. To run them on a robot: 1. **De-normalize** in the same element-wise (subtraction) space the model was trained in. The quantile inverse is `x = (x_norm + 1) / 2 * (q99 - q01) + q01`, applied to the active dims only — 10 for single-arm, 20 for dual-arm. 2. **Add back to the current state**, `abs = state + delta`, on the delta dims. Grippers and padding are already absolute. This is the standard `AbsoluteActions` step; there is no relative-rotation or rotation-matrix math, because the rotation delta is element-wise. 3. **Execute the full chunk.** The action horizon is 50 — execute all 50 steps before requesting the next prediction. Executing fewer clips the tail of the chunk, which is where the grasp-closing motion lives, and the gripper will look stuck open. ### 32-dim action/state layout ``` left arm [0:10]: xyz [0:3], rot6d [3:9], gripper [9] right arm [10:20]: xyz [10:13], rot6d [13:19], gripper [19] [20:32]: reserved / unused ``` Rotation is rot6d, not quaternion or Euler. On disk the `action` field is the absolute end-effector pose; the training transforms form the delta target as `action[t+k] - state[t]`. ## License These weights are derived from Google's PaliGemma/Gemma parameters and are therefore made available under the [Gemma Terms of Use](https://ai.google.dev/gemma/terms) and the [Gemma Prohibited Use Policy](https://ai.google.dev/gemma/prohibited_use_policy), **not** under the CC BY-SA 4.0 licence that covers the source code. This is inherited from the base model, not a restriction added on top.