Download runtime/rl/models.py from BAAI/PingPongRealWorldRL: direct link, hf CLI and curl.
- Browser
- Download file 4.11 kB
-
https://huggingface.co/BAAI/PingPongRealWorldRL/resolve/main/runtime/rl/models.py
- Command line
-
hf download hf://BAAI/PingPongRealWorldRL/runtime/rl/models.py
-
curl -L -o models.py https://huggingface.co/BAAI/PingPongRealWorldRL/resolve/main/runtime/rl/models.py
4.11 kB
| """H2 adaptation of residual TD3 networks from sim commit 4fa48dd. | |
| Layer layout and zero actor initialization are preserved; dimensions come | |
| from the H2 contract. Normalizer checkpoints retain full running statistics. | |
| """ | |
| from __future__ import annotations | |
| import numpy as np | |
| import torch | |
| from torch import nn | |
| from .data import ACTOR_INPUT_DIM, RESIDUAL_ACTION_DIM | |
| class Actor(nn.Module): | |
| def __init__(self) -> None: | |
| super().__init__() | |
| self.net = nn.Sequential( | |
| nn.Linear(ACTOR_INPUT_DIM, 256), | |
| nn.LayerNorm(256), | |
| nn.ReLU(), | |
| nn.Linear(256, 256), | |
| nn.LayerNorm(256), | |
| nn.ReLU(), | |
| nn.Linear(256, RESIDUAL_ACTION_DIM), | |
| nn.Tanh(), | |
| ) | |
| output = self.net[-2] | |
| nn.init.zeros_(output.weight) | |
| nn.init.zeros_(output.bias) | |
| def forward(self, inputs: torch.Tensor) -> torch.Tensor: | |
| return self.net(inputs) | |
| class Critic(nn.Module): | |
| def __init__(self) -> None: | |
| super().__init__() | |
| self.net = nn.Sequential( | |
| nn.Linear(ACTOR_INPUT_DIM, 256), | |
| nn.LayerNorm(256), | |
| nn.ReLU(), | |
| nn.Linear(256, 256), | |
| nn.LayerNorm(256), | |
| nn.ReLU(), | |
| nn.Linear(256, 1), | |
| ) | |
| def forward(self, inputs: torch.Tensor) -> torch.Tensor: | |
| return self.net(inputs) | |
| def parameter_count(module: nn.Module) -> int: | |
| return sum(parameter.numel() for parameter in module.parameters()) | |
| def actor_parameter_count() -> int: | |
| with torch.random.fork_rng(devices=[]): | |
| return parameter_count(Actor()) | |
| def flatten_parameters(module: nn.Module) -> np.ndarray: | |
| values = [parameter.detach().cpu().reshape(-1) for parameter in module.parameters()] | |
| return torch.cat(values).numpy().astype(np.float32, copy=True) | |
| def load_flat_parameters(module: nn.Module, values: np.ndarray) -> None: | |
| flat = np.asarray(values, dtype=np.float32).reshape(-1) | |
| if flat.size != parameter_count(module) or not np.isfinite(flat).all(): | |
| raise ValueError("actor parameter payload is invalid") | |
| offset = 0 | |
| with torch.no_grad(): | |
| for parameter in module.parameters(): | |
| count = parameter.numel() | |
| source = torch.from_numpy(flat[offset : offset + count]).reshape(parameter.shape) | |
| parameter.copy_(source.to(device=parameter.device, dtype=parameter.dtype)) | |
| offset += count | |
| class RunningNormalizer: | |
| def __init__(self, size: int, *, min_std: float, clip: float) -> None: | |
| self.size = int(size) | |
| self.min_std = float(min_std) | |
| self.clip = float(clip) | |
| self.count = 0 | |
| self.mean = np.zeros(self.size, dtype=np.float64) | |
| self.m2 = np.zeros(self.size, dtype=np.float64) | |
| self.frozen = False | |
| def update(self, values: np.ndarray) -> None: | |
| if self.frozen: | |
| return | |
| value = np.asarray(values, dtype=np.float64).reshape(self.size) | |
| self.count += 1 | |
| delta = value - self.mean | |
| self.mean += delta / self.count | |
| self.m2 += delta * (value - self.mean) | |
| def freeze(self) -> None: | |
| self.frozen = True | |
| def std(self) -> np.ndarray: | |
| if self.count < 2: | |
| variance = np.ones(self.size, dtype=np.float64) | |
| else: | |
| variance = self.m2 / self.count | |
| return np.maximum(np.sqrt(variance), self.min_std).astype(np.float32) | |
| def normalize_tensor(self, values: torch.Tensor) -> torch.Tensor: | |
| mean = torch.as_tensor(self.mean, dtype=values.dtype, device=values.device) | |
| std = torch.as_tensor(self.std, dtype=values.dtype, device=values.device) | |
| return torch.clamp((values - mean) / std, -self.clip, self.clip) | |
| def state_dict(self) -> dict: | |
| return { | |
| "size": self.size, | |
| "min_std": self.min_std, | |
| "clip": self.clip, | |
| "count": self.count, | |
| "mean": self.mean.copy(), | |
| "std": self.std, | |
| "m2": self.m2.copy(), | |
| "frozen": self.frozen, | |
| } | |