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:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Upload tinyvla2/scripts/eval_libero_canon.py with huggingface_hub
Browse files
tinyvla2/scripts/eval_libero_canon.py
CHANGED
|
@@ -47,6 +47,14 @@ def main():
|
|
| 47 |
p.add_argument("--n-action-steps", type=int, default=25,
|
| 48 |
help="actions executed per predicted chunk before re-planning")
|
| 49 |
p.add_argument("--grip-mode", default="threshold", choices=["threshold", "linear"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
p.add_argument("--save-video-dir", type=Path, default=None)
|
| 51 |
args = p.parse_args()
|
| 52 |
|
|
@@ -117,18 +125,30 @@ def main():
|
|
| 117 |
"morphology": morph,
|
| 118 |
"embodiment_id": torch.tensor([0], device="cuda")}
|
| 119 |
|
| 120 |
-
def
|
| 121 |
-
"""(chunk, >=7) normalized canonical -> (chunk-1, 7)
|
| 122 |
-
|
| 123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
osc = np.zeros((len(phys), 7), dtype=np.float32)
|
| 125 |
osc[:, :6] = phys[:, :6] * mscale
|
| 126 |
-
|
| 127 |
-
osc[:, 6] = np.where(phys[:, 6] > fit["grip_threshold"], -1.0, 1.0)
|
| 128 |
-
else:
|
| 129 |
-
osc[:, 6] = phys[:, 6] * fit["grip_a"] + fit["grip_b"]
|
| 130 |
return np.clip(osc, -1.0, 1.0)
|
| 131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
fps = meta.fps
|
| 133 |
total = succ = 0
|
| 134 |
per_task = {}
|
|
@@ -149,6 +169,7 @@ def main():
|
|
| 149 |
frames = [] if args.save_video_dir else None
|
| 150 |
latent, last_refresh = None, -1e9
|
| 151 |
queue, done, step_i, ep_succ = [], False, 0, False
|
|
|
|
| 152 |
while not done and step_i < args.max_steps:
|
| 153 |
if not queue:
|
| 154 |
batch = to_batch(obs, task_text)
|
|
@@ -159,8 +180,24 @@ def main():
|
|
| 159 |
batch["semantic_latent"] = latent
|
| 160 |
with torch.autocast("cuda", torch.bfloat16):
|
| 161 |
pred = policy.predict_action_chunk(batch)[0].float().cpu().numpy()
|
| 162 |
-
|
| 163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
try:
|
| 165 |
obs, _, terminated, truncated, info = env.step(act[None])
|
| 166 |
except ValueError:
|
|
|
|
| 47 |
p.add_argument("--n-action-steps", type=int, default=25,
|
| 48 |
help="actions executed per predicted chunk before re-planning")
|
| 49 |
p.add_argument("--grip-mode", default="threshold", choices=["threshold", "linear"])
|
| 50 |
+
p.add_argument("--decode", default="servo", choices=["servo", "scaled"],
|
| 51 |
+
help="servo (default): integrate predicted deltas into a desired EE pose and "
|
| 52 |
+
"command the error against the measured pose. The naive scaled decode "
|
| 53 |
+
"replays achieved motion as a command, which the OSC controller "
|
| 54 |
+
"under-tracks: GT round-trip replay scores 1/5 scaled vs 3/5 servo "
|
| 55 |
+
"against a 4/5 raw-GT ceiling.")
|
| 56 |
+
p.add_argument("--kp", type=float, default=120.0)
|
| 57 |
+
p.add_argument("--kr", type=float, default=12.0)
|
| 58 |
p.add_argument("--save-video-dir", type=Path, default=None)
|
| 59 |
args = p.parse_args()
|
| 60 |
|
|
|
|
| 125 |
"morphology": morph,
|
| 126 |
"embodiment_id": torch.tensor([0], device="cuda")}
|
| 127 |
|
| 128 |
+
def to_physical(chunk_norm):
|
| 129 |
+
"""(chunk, >=7) normalized canonical -> (chunk-1, 7) physical deltas.
|
| 130 |
+
|
| 131 |
+
Drops the anchor delta: sidecars built from observation state have
|
| 132 |
+
a_pose == s_pose, so chunk[0] is identically zero.
|
| 133 |
+
"""
|
| 134 |
+
return (chunk_norm[:, :7] * span / 2 + mid)[1:]
|
| 135 |
+
|
| 136 |
+
def grip_cmd(openness):
|
| 137 |
+
if args.grip_mode == "threshold":
|
| 138 |
+
return -1.0 if openness > fit["grip_threshold"] else 1.0
|
| 139 |
+
return float(np.clip(openness * fit["grip_a"] + fit["grip_b"], -1, 1))
|
| 140 |
+
|
| 141 |
+
def decode_scaled(phys):
|
| 142 |
osc = np.zeros((len(phys), 7), dtype=np.float32)
|
| 143 |
osc[:, :6] = phys[:, :6] * mscale
|
| 144 |
+
osc[:, 6] = [grip_cmd(g) for g in phys[:, 6]]
|
|
|
|
|
|
|
|
|
|
| 145 |
return np.clip(osc, -1.0, 1.0)
|
| 146 |
|
| 147 |
+
def measured_pose(obs):
|
| 148 |
+
rs = obs["robot_state"]
|
| 149 |
+
return (np.asarray(rs["eef"]["pos"]).flatten(),
|
| 150 |
+
Rotation.from_quat(np.asarray(rs["eef"]["quat"]).flatten()))
|
| 151 |
+
|
| 152 |
fps = meta.fps
|
| 153 |
total = succ = 0
|
| 154 |
per_task = {}
|
|
|
|
| 169 |
frames = [] if args.save_video_dir else None
|
| 170 |
latent, last_refresh = None, -1e9
|
| 171 |
queue, done, step_i, ep_succ = [], False, 0, False
|
| 172 |
+
des_p, des_R = None, None
|
| 173 |
while not done and step_i < args.max_steps:
|
| 174 |
if not queue:
|
| 175 |
batch = to_batch(obs, task_text)
|
|
|
|
| 180 |
batch["semantic_latent"] = latent
|
| 181 |
with torch.autocast("cuda", torch.bfloat16):
|
| 182 |
pred = policy.predict_action_chunk(batch)[0].float().cpu().numpy()
|
| 183 |
+
phys = to_physical(pred)[: args.n_action_steps]
|
| 184 |
+
if args.decode == "servo":
|
| 185 |
+
queue = list(phys) # consumed as deltas, servoed below
|
| 186 |
+
des_p, des_R = measured_pose(obs) # re-anchor each re-plan
|
| 187 |
+
else:
|
| 188 |
+
queue = list(decode_scaled(phys))
|
| 189 |
+
if args.decode == "servo":
|
| 190 |
+
d = queue.pop(0)
|
| 191 |
+
cur_p, cur_R = measured_pose(obs)
|
| 192 |
+
des_p = des_p + d[:3]
|
| 193 |
+
des_R = Rotation.from_rotvec(d[3:6]) * des_R
|
| 194 |
+
act = np.zeros(7, dtype=np.float32)
|
| 195 |
+
act[:3] = args.kp * (des_p - cur_p)
|
| 196 |
+
act[3:6] = args.kr * (des_R * cur_R.inv()).as_rotvec()
|
| 197 |
+
act[6] = grip_cmd(d[6])
|
| 198 |
+
act = np.clip(act, -1, 1)
|
| 199 |
+
else:
|
| 200 |
+
act = queue.pop(0)
|
| 201 |
try:
|
| 202 |
obs, _, terminated, truncated, info = env.step(act[None])
|
| 203 |
except ValueError:
|