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 | |
| """Gate 1: per-dataset SO101 FK calibration audit. | |
| Same recorded degrees can map to different physical poses across lerobot | |
| zero-conventions → FK garbage that would poison B/C canonical labels while | |
| leaving A untouched (a confound AGAINST the hypothesis). Drop datasets whose | |
| FK produces non-physical EE trajectories. | |
| Checks per dataset (sampled frames across episodes): | |
| - reach in [0.02, 0.40] m (SO101 max reach ~0.35) | |
| - z above a floor (> -0.20 m; base frame origin at arm mount) | |
| - trajectory smoothness (median consecutive EE step < 0.05 m at 30fps) | |
| - FK(state) vs FK(action-target) diffs correlate (both go through FK, deltas | |
| should track since action = commanded target of the same arm) | |
| Writes ~/tinyvla_data/so101_fk_audit.json with per-dataset verdict. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from pathlib import Path | |
| import numpy as np | |
| DATA_ROOT = Path.home() / "tinyvla_data" / "so101_v3" | |
| OUT = Path.home() / "tinyvla_data" / "so101_fk_audit.json" | |
| def audit_one(name, root, fk, n_frames=200): | |
| from lerobot.datasets.lerobot_dataset import LeRobotDataset | |
| ds = LeRobotDataset(name, root=root) | |
| anames = ds.meta.features["action"]["shape"][0] | |
| if anames != 6: | |
| return {"verdict": "SKIP", "reason": f"action dim {anames} != 6"} | |
| # smoothness needs CONSECUTIVE frames → sample a few contiguous windows; | |
| # reach/corr can use sparse knots across the whole dataset | |
| n = len(ds) | |
| eps = ds.meta.episodes | |
| sparse = np.linspace(0, n - 1, min(n_frames, n)).astype(int) | |
| pos_state, pos_act = [], [] | |
| for i in sparse: | |
| item = ds[int(i)] | |
| pos_state.append(fk.ee_pose(item["observation.state"].numpy())[:3, 3]) | |
| pos_act.append(fk.ee_pose(item["action"].numpy())[:3, 3]) | |
| ps = np.array(pos_state) | |
| pa = np.array(pos_act) | |
| reach = np.linalg.norm(ps, axis=1) | |
| # consecutive-frame EE steps within the first episode (real per-frame motion) | |
| e0, e1 = int(eps["dataset_from_index"][0]), int(eps["dataset_to_index"][0]) | |
| consec = [] | |
| prev = None | |
| for i in range(e0, min(e1, e0 + 150)): | |
| p = fk.ee_pose(ds[i]["observation.state"].numpy())[:3, 3] | |
| if prev is not None: | |
| consec.append(np.linalg.norm(p - prev)) | |
| prev = p | |
| steps = np.array(consec) if consec else np.array([0.0]) | |
| # correlation of state-vs-target displacement over sampled knots | |
| d_state = np.diff(ps, axis=0).flatten() | |
| d_act = np.diff(pa, axis=0).flatten() | |
| corr = float(np.corrcoef(d_state, d_act)[0, 1]) if d_state.std() > 1e-9 else 0.0 | |
| ok_reach = bool(0.02 < reach.mean() < 0.40 and reach.max() < 0.50) | |
| ok_z = bool(ps[:, 2].min() > -0.20) | |
| ok_smooth = bool(np.median(steps) < 0.06) | |
| ok_corr = bool(corr > 0.5) | |
| verdict = "KEEP" if (ok_reach and ok_z and ok_smooth and ok_corr) else "DROP" | |
| return { | |
| "verdict": verdict, | |
| "reach_mean": round(float(reach.mean()), 3), | |
| "reach_max": round(float(reach.max()), 3), | |
| "z_min": round(float(ps[:, 2].min()), 3), | |
| "step_median": round(float(np.median(steps)), 4), | |
| "corr_state_target": round(corr, 3), | |
| "flags": {"reach": ok_reach, "z": ok_z, "smooth": ok_smooth, "corr": ok_corr}, | |
| } | |
| def main(): | |
| from tinyvla.data.kinematics_so101 import SO101FK | |
| fk = SO101FK() | |
| results = {} | |
| roots = sorted(DATA_ROOT.iterdir()) | |
| for r in roots: | |
| if not (r / "meta" / "info.json").exists(): | |
| continue | |
| try: | |
| res = audit_one(r.name, r, fk) | |
| except Exception as e: | |
| res = {"verdict": "ERROR", "reason": f"{type(e).__name__}: {str(e)[:120]}"} | |
| results[r.name] = res | |
| print(f"{res['verdict']:6} {r.name}: {res}") | |
| OUT.write_text(json.dumps(results, indent=1)) | |
| keep = sum(1 for v in results.values() if v["verdict"] == "KEEP") | |
| print(f"\nKEEP {keep}/{len(results)} -> {OUT}") | |
| if __name__ == "__main__": | |
| main() | |