File size: 1,334 Bytes
386302b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #!/usr/bin/env python3
"""Reproducibly build `model.safetensors` from the source centroid vector.
The source policy is a single 32-dimensional centroid `c` (C2 formulation). It is
identical to the linear layer: a = argmax(obs @ W), W[:, a] = c[a*8:(a+1)*8].
python export_weights.py /path/to/lunar_centroid_12.npy
"""
import argparse
import numpy as np
import torch
from safetensors.torch import save_file
OBS_DIM, N_ACTIONS = 8, 4
def centroid_to_W(c: np.ndarray, obs_dim: int = OBS_DIM, n_actions: int = N_ACTIONS) -> np.ndarray:
c = np.asarray(c, dtype=np.float32).ravel()
assert c.size == obs_dim * n_actions
return np.column_stack([c[a * obs_dim:(a + 1) * obs_dim] for a in range(n_actions)])
def main():
ap = argparse.ArgumentParser()
ap.add_argument("centroid", help="path to the 32-d centroid .npy")
ap.add_argument("--out", default="model.safetensors")
a = ap.parse_args()
c = np.load(a.centroid)
W = centroid_to_W(c) # (8, 4)
weight = torch.tensor(W.T.copy()) # nn.Linear.weight is (out, in) = (4, 8)
assert weight.shape == (N_ACTIONS, OBS_DIM)
save_file({"linear.weight": weight.contiguous()}, a.out)
print(f"wrote {a.out} | {weight.numel()} params | W=\n{np.round(W.T, 4)}")
if __name__ == "__main__":
main()
|