Download runtime/policy.py from BAAI/PingPongRealWorldRL: direct link, hf CLI and curl.
- Browser
- Download file 3.95 kB
-
https://huggingface.co/BAAI/PingPongRealWorldRL/resolve/main/runtime/policy.py
- Command line
-
hf download hf://BAAI/PingPongRealWorldRL/runtime/policy.py
-
curl -L -o policy.py https://huggingface.co/BAAI/PingPongRealWorldRL/resolve/main/runtime/policy.py
3.95 kB
| """ONNX policy wrapper with the training-side metadata.""" | |
| from __future__ import annotations | |
| from dataclasses import dataclass | |
| import numpy as np | |
| try: | |
| import onnxruntime as ort | |
| except Exception: # pragma: no cover - optional at import time | |
| ort = None | |
| def _csv_floats(value: str | None) -> list[float]: | |
| return [float(x) for x in value.split(",") if x.strip()] if value else [] | |
| def _csv_strings(value: str | None) -> list[str]: | |
| return [x.strip() for x in value.split(",") if x.strip()] if value else [] | |
| class PolicyMetadata: | |
| joint_names: list[str] # Isaac articulation order, with "_joint" suffix | |
| action_scale: list[float] | |
| default_joint_pos: list[float] | |
| body_names: list[str] | |
| observation_names: list[str] | |
| raw: dict | |
| class OnnxPolicy: | |
| """``actions = policy(obs)``; the observation normaliser is baked into the graph.""" | |
| def __init__(self, path: str, device: str = "cpu"): | |
| if ort is None: | |
| raise ImportError("onnxruntime is required to run an exported policy (pip install onnxruntime).") | |
| available = set(ort.get_available_providers()) | |
| if device == "cuda" and "CUDAExecutionProvider" in available: | |
| providers = ["CUDAExecutionProvider", "CPUExecutionProvider"] | |
| elif device in ("cpu", "cuda"): | |
| providers = ["CPUExecutionProvider"] | |
| if device == "cuda": | |
| print("[WARN] ONNX Runtime has no CUDA provider; the 182-D policy will run on CPU.") | |
| else: | |
| raise ValueError(f"unsupported policy device {device!r}; expected 'cpu' or 'cuda'") | |
| self.session = ort.InferenceSession(path, providers=providers) | |
| inputs = [i.name for i in self.session.get_inputs()] | |
| outputs = [o.name for o in self.session.get_outputs()] | |
| if inputs != ["obs"] or "actions" not in outputs: | |
| raise RuntimeError(f"expected an action-only policy with input ['obs'] and output 'actions', got {inputs}/{outputs}") | |
| self.obs_dim = int(self.session.get_inputs()[0].shape[-1]) | |
| self.act_dim = int([o for o in self.session.get_outputs() if o.name == "actions"][0].shape[-1]) | |
| meta = self.session.get_modelmeta().custom_metadata_map | |
| self.metadata = PolicyMetadata( | |
| joint_names=_csv_strings(meta.get("joint_names")), | |
| action_scale=_csv_floats(meta.get("action_scale")), | |
| default_joint_pos=_csv_floats(meta.get("default_joint_pos")), | |
| body_names=_csv_strings(meta.get("body_names")), | |
| observation_names=_csv_strings(meta.get("observation_names")), | |
| raw=dict(meta), | |
| ) | |
| if not self.metadata.joint_names: | |
| raise RuntimeError("policy.onnx carries no joint_names metadata; export with attach_onnx_metadata") | |
| def __call__(self, obs: np.ndarray) -> np.ndarray: | |
| obs = np.asarray(obs, dtype=np.float32).reshape(-1) | |
| if obs.size != self.obs_dim or not np.isfinite(obs).all(): | |
| raise ValueError(f"policy observation must be finite shape ({self.obs_dim},), got {obs.shape}") | |
| out = self.session.run(["actions"], {"obs": obs.reshape(1, -1)})[0] | |
| action = out.reshape(-1).astype(np.float32) | |
| if action.size != self.act_dim or not np.isfinite(action).all(): | |
| raise RuntimeError(f"policy returned invalid action shape/values: {action.shape}") | |
| return action | |
| class HoldPosePolicy: | |
| """Stand-in policy (zero actions = default pose) for pipeline self-tests without ONNX.""" | |
| def __init__(self, num_actions: int, obs_dim: int, joint_names: list[str], default_joint_pos: list[float], action_scale: list[float]): | |
| self.obs_dim = obs_dim | |
| self.act_dim = num_actions | |
| self.metadata = PolicyMetadata(joint_names, action_scale, default_joint_pos, [], [], {}) | |
| def __call__(self, obs: np.ndarray) -> np.ndarray: | |
| return np.zeros(self.act_dim, dtype=np.float32) | |