Instructions to use AlexWortega/tinyvla with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LeRobot
How to use AlexWortega/tinyvla with LeRobot:
- Notebooks
- Google Colab
- Kaggle
| #!/usr/bin/env python | |
| """Evaluate the new wds embodiments against their own trivial baseline. | |
| The ratio metric used for the canonical robots integrates EE deltas, which is | |
| wrong for these packs, so each action space gets the trivial baseline that | |
| actually applies to it: | |
| nav (recon/sacson/go-stanford/scand/tartandrive): actions are step deltas / | |
| local waypoints -> integrate the chunk and compare endpoints. Floor = | |
| predicting zero motion, exactly as for the canonical robots. | |
| unitree (G1/Z1): actions are ABSOLUTE joint positions, so integrating is | |
| meaningless. Floor = "hold still", i.e. predict the current joint state for | |
| the whole chunk. ratio < 1 means the model beats not moving. | |
| Both are computed in the packs' normalized units, so numbers are comparable | |
| across packs but not to millimetres. | |
| """ | |
| from __future__ import annotations | |
| import sys | |
| from pathlib import Path | |
| import numpy as np | |
| import torch | |
| import yaml | |
| from transformers import AutoTokenizer | |
| from tinyvla.data.wds_shards import WdsShardSource | |
| from tinyvla.modeling_tinyvla import TinyVLAPolicy | |
| from tinyvla.modules.embodiment import MORPH_FIELDS | |
| CKPT = sys.argv[1] if len(sys.argv) > 1 else "outputs/tv2_joint/final" | |
| WDS = Path.home() / "tinyvla_data" / "wds" | |
| _SC = {"arm_dof": 0.1, "reach_m": 2, "gripper_width_m": 10, "num_cameras": 1 / 3, | |
| "control_hz": 1 / 30, "joint_lo_mean": 1 / 3.1416, "joint_hi_mean": 1 / 3.1416, | |
| "workspace_x": 2, "workspace_y": 2, "workspace_z": 2, "payload_kg": 0.2} | |
| # (label, path, morph_key, embodiment_id, kind) | |
| TARGETS = [ | |
| ("G1 Dex3 ToastedBread", "wds-unitree/G1_Dex3_ToastedBread_Dataset", "g1", 15, "joint"), | |
| ("G1 Dex1 DualArm", "wds-unitree/G1_Dex1_DiverseManip_DualArm_256x256", "g1", 15, "joint"), | |
| ("Z1 StackBox", "wds-unitree/Z1_StackBox_Dataset", "z1", 19, "joint"), | |
| ("recon (outdoor nav)", "wds-recon", "recon", 16, "nav"), | |
| ("sacson (indoor nav)", "wds-sacson", "sacson", 21, "nav"), | |
| ("go-stanford (nav)", "wds-go-stanford", "go_stanford", 20, "nav"), | |
| ("scand (social nav)", "wds-scand", "scand", 18, "nav"), | |
| ("tartandrive (ATV)", "wds-tartandrive", "tartandrive", 17, "nav"), | |
| ] | |
| def main(): | |
| pol = TinyVLAPolicy.from_pretrained(CKPT).cuda().eval() | |
| cfg = pol.config | |
| tok = AutoTokenizer.from_pretrained(cfg.lm_model_name) | |
| desc = yaml.safe_load(open("configs/morphology/descriptors.yaml")) | |
| print(f"=== {CKPT} on the new embodiments (ratio to trivial baseline) ===") | |
| rows = [] | |
| for label, rel, mkey, emb, kind in TARGETS: | |
| try: | |
| morph = torch.tensor([desc[mkey].get(f, 0) * _SC.get(f, 1) for f in MORPH_FIELDS], | |
| dtype=torch.float32) | |
| src = WdsShardSource(WDS / rel, embodiment_id=emb, chunk=cfg.chunk_size, | |
| image_size=cfg.image_size, max_state_dim=cfg.max_state_dim, | |
| max_action_dim=cfg.max_action_dim, morphology=morph) | |
| n = len(src) | |
| # held-out tail: the packs are written in episode order, so the last | |
| # slice is unseen episodes rather than unseen frames of seen ones | |
| idxs = range(int(n * 0.98), n, max(1, int(n * 0.02) // 120)) | |
| errs, floors = [], [] | |
| for i in idxs: | |
| it = src[i] | |
| t = tok([it["task"]], padding=True, truncation=True, max_length=48, | |
| return_tensors="pt") | |
| b = {"observation.images.cam0": it["observation.images.cam0"][None].cuda(), | |
| "observation.images.cam1": it["observation.images.cam1"][None].cuda(), | |
| "observation.state": it["observation.state"][None].cuda(), | |
| "observation.language.tokens": t["input_ids"].cuda(), | |
| "observation.language.attention_mask": t["attention_mask"].bool().cuda(), | |
| "morphology": morph[None].cuda(), | |
| "embodiment_id": torch.tensor([emb]).cuda()} | |
| with torch.autocast("cuda", torch.bfloat16): | |
| pr = pol.predict_action_chunk(b)[0].cpu().float().numpy() | |
| d = int(it["action_dim_mask"].sum()) | |
| gt = it["action"][:, :d].numpy() | |
| pd = pr[:, :d] | |
| if kind == "nav": | |
| gp, pp = np.cumsum(gt, 0)[-1], np.cumsum(pd, 0)[-1] | |
| errs.append(np.linalg.norm(pp - gp)) | |
| floors.append(np.linalg.norm(gp)) # predict zero motion | |
| else: | |
| st = it["observation.state"][:d].numpy() # hold-still baseline | |
| errs.append(np.linalg.norm(pd - gt, axis=1).mean()) | |
| floors.append(np.linalg.norm(st[None] - gt, axis=1).mean()) | |
| err, floor = float(np.mean(errs)), float(np.mean(floors)) | |
| rows.append((label, kind, err / floor)) | |
| print(f"{label:26} [{kind:5}] n={len(errs):>4} err {err:7.3f} floor {floor:7.3f} " | |
| f"ratio {err/floor:.2f}", flush=True) | |
| except Exception as ex: | |
| print(f"{label:26} FAILED {type(ex).__name__}: {str(ex)[:80]}", flush=True) | |
| for kind in ("joint", "nav"): | |
| sel = [r[2] for r in rows if r[1] == kind] | |
| if sel: | |
| print(f"mean ratio, {kind:5}: {np.mean(sel):.2f}") | |
| print("ratio < 1.0 beats the trivial baseline (zero motion / hold still)") | |
| if __name__ == "__main__": | |
| main() | |