| """Minimal inference for the FARM UF850 Patch Policy specialist (L1 head). |
| Inputs: base + wrist RGB frames (any size), 7-d proprio state. |
| Output: 50-step action chunk in dataset space (6 relative joint deltas rad + gripper [0,1]).""" |
| import cv2 |
| import numpy as np |
| import torch |
|
|
| from train_patch_policy import PatchPolicy |
|
|
|
|
| class PatchPolicyRunner: |
| def __init__(self, ckpt_path, device="cuda"): |
| ck = torch.load(ckpt_path, map_location="cpu", weights_only=False) |
| self.norm = ck["norm"] |
| cfg = ck["cfg"] |
| self.model = PatchPolicy(cfg["chunk"], head=cfg["head"]).to(device).eval() |
| self.model.load_state_dict(ck["ema"], strict=False) |
| self.device = device |
|
|
| @torch.no_grad() |
| def predict(self, base_rgb, wrist_rgb, state7): |
| imgs = np.stack([cv2.resize(base_rgb, (224, 224), interpolation=cv2.INTER_AREA), |
| cv2.resize(wrist_rgb, (224, 224), interpolation=cv2.INTER_AREA)])[None] |
| st = ((np.asarray(state7, np.float32) - self.norm["s_mean"]) / self.norm["s_std"])[None] |
| with torch.autocast("cuda", torch.bfloat16): |
| chunk = self.model.predict(torch.from_numpy(imgs).to(self.device), |
| torch.from_numpy(st).float().to(self.device)) |
| return chunk[0].float().cpu().numpy() * self.norm["a_std"] + self.norm["a_mean"] |
|
|
|
|
| if __name__ == "__main__": |
| r = PatchPolicyRunner("patch_policy_task2_l1.pt") |
| dummy = np.zeros((480, 640, 3), np.uint8) |
| print("chunk:", r.predict(dummy, dummy, np.zeros(7)).shape) |
|
|