Conditiondark's picture
Add rigid-body manipulation workstation artifacts (v1)
87d0bc2 verified
Raw History Blame Contribute Delete
3.87 kB
"""Online evaluation of the fine-tuned OpenVLA policy at 224x224 in the eval env."""
import argparse, os, json, time, statistics
import numpy as np, torch, gymnasium as gym, ogbench, mujoco
from PIL import Image
from transformers import AutoModelForVision2Seq, AutoProcessor
from peft import PeftModel
from common import wilson_ci
from vla_finetune import ActionHead, prompt_for
MID = "openvla/openvla-7b"
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--run", required=True) # runs_vla/vla_b1000_seed0
ap.add_argument("--env", default="visual-cube-single-v0")
ap.add_argument("--rollouts", type=int, default=20) # per task
ap.add_argument("--tasks", type=int, default=5)
ap.add_argument("--base_seed", type=int, default=20260825)
a = ap.parse_args()
dev = "cuda:0"
proc = AutoProcessor.from_pretrained(MID, trust_remote_code=True)
vla = AutoModelForVision2Seq.from_pretrained(
MID, attn_implementation="sdpa", torch_dtype=torch.bfloat16,
low_cpu_mem_usage=True, trust_remote_code=True).to(dev)
vla = PeftModel.from_pretrained(vla, os.path.join(a.run, "lora")).eval()
ck = torch.load(os.path.join(a.run, "head.pt"), map_location=dev, weights_only=False)
head = ActionHead(act=5).to(dev).float(); head.load_state_dict(ck["head"]); head.eval()
env = gym.make(a.env); u = env.unwrapped
env.reset(seed=0, options=dict(task_id=1, render_goal=False))
u.model.vis.global_.offwidth = 224; u.model.vis.global_.offheight = 224
u._renderer = mujoco.Renderer(u.model, height=224, width=224)
u._render_height = 224; u._render_width = 224
def act_fn(gx, gy):
img = Image.fromarray(np.asarray(u.get_pixel_observation()))
inp = proc(prompt_for(gx, gy), img).to(dev, dtype=torch.bfloat16)
with torch.no_grad():
out = vla(input_ids=inp["input_ids"], attention_mask=inp["attention_mask"],
pixel_values=inp["pixel_values"], output_hidden_states=True)
h = out.hidden_states[-1][:, -1, :].float()
return head(h)[0].cpu().numpy()
per_task, all_k, all_n, steps_s = {}, 0, 0, []
t0 = time.time()
for task_id in range(1, a.tasks + 1):
k = 0
for r in range(a.rollouts):
ob, info = env.reset(seed=a.base_seed + 1000 * task_id + r,
options=dict(task_id=task_id, render_goal=False))
gxyz = np.asarray(u.task_infos[task_id - 1]["goal_xyzs"])[0]
gx, gy = float(gxyz[0]), float(gxyz[1]) # goal cube world xy
succ, sstep = 0, None
for t in range(1000):
ob, rew, term, trunc, info = env.step(np.clip(act_fn(gx, gy), -1, 1))
if info.get("success"):
succ = 1
if sstep is None: sstep = t + 1
if term or trunc: break
k += succ; all_n += 1
if succ: steps_s.append(sstep)
p, lo, hi = wilson_ci(k, a.rollouts)
per_task[task_id] = dict(k=k, n=a.rollouts, rate=p, ci=[lo, hi])
all_k += k
print(f" task{task_id}: {k}/{a.rollouts} = {p:.3f} [{time.time()-t0:.0f}s]", flush=True)
p, lo, hi = wilson_ci(all_k, all_n)
med = statistics.median(steps_s) if steps_s else None
res = dict(model="openvla-7b-oft-style", env=a.env, rollouts_per_task=a.rollouts,
overall=dict(k=all_k, n=all_n, rate=p, ci=[lo, hi]), per_task=per_task,
median_steps_to_success=med, timeout_rate=1 - all_k / all_n,
eval_seconds=time.time() - t0)
print("OVERALL: %d/%d = %.3f 95%% Wilson CI [%.3f, %.3f] | median steps=%s | %.0fs"
% (all_k, all_n, p, lo, hi, med, time.time() - t0))
json.dump(res, open(os.path.join(a.run, "eval.json"), "w"), indent=2)
if __name__ == "__main__":
main()