lunarlander-lin32 / export_weights.py
Dimitrius174's picture
32-parameter linear LunarLander-v3 policy (mean 247.2, 60/60 seeds)
386302b verified
Raw History Blame Contribute Delete
1.33 kB
#!/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()