n0-vtla-base / README.md
NeoteAI's picture
docs: correct the code licence to CC BY-SA 4.0
ec12548 verified
|
Raw
History Blame Contribute Delete
3.93 kB
---
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/<asset-id>/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.