Download bc.py from dummy033485/multi-agent-rl-navigation: direct link, hf CLI and curl.
- Browser
- Download file 3.05 kB
-
https://huggingface.co/dummy033485/multi-agent-rl-navigation/resolve/main/bc.py
- Command line
-
hf download hf://dummy033485/multi-agent-rl-navigation/bc.py
-
curl -L -o bc.py https://huggingface.co/dummy033485/multi-agent-rl-navigation/resolve/main/bc.py
3.05 kB
| """Behaviour-cloning warm-start from the classical controller. | |
| Collects (observation, classical action) pairs by running the classical | |
| PD + potential-field policy on GENERAL layouts only (trap=False, where | |
| the teacher succeeds 10/10 in sanity checks). Trap layouts are excluded | |
| deliberately: imitating the teacher there would teach the stall. | |
| Trains only the actor (mean head) of ActorCritic with MSE on the | |
| tanh-bounded action. The critic is left for PPO fine-tuning. | |
| Outputs: bc_policy.pt, bc.log via stdout. | |
| """ | |
| import argparse | |
| import numpy as np | |
| import torch | |
| import torch.nn as nn | |
| from sim import AMAX, BatchedSim, generate_layout | |
| from policies import ActorCritic, classical_action | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--episodes", type=int, default=400) | |
| ap.add_argument("--n-agents", type=int, default=4) | |
| ap.add_argument("--epochs", type=int, default=30) | |
| ap.add_argument("--seed", type=int, default=123) | |
| ap.add_argument("--out", default="bc_policy.pt") | |
| args = ap.parse_args() | |
| torch.manual_seed(args.seed) | |
| torch.set_num_threads(2) | |
| rng = np.random.default_rng(args.seed) | |
| sim = BatchedSim(16, args.n_agents, seed=args.seed) | |
| obs_list, act_list = [], [] | |
| layouts = [generate_layout(rng, args.n_agents, trap=False) for _ in range(16)] | |
| obs = sim.reset(layouts) | |
| done_eps = 0 | |
| while done_eps < args.episodes: | |
| act = classical_action(obs) | |
| obs_list.append(obs.reshape(-1, obs.shape[-1]).copy()) | |
| act_list.append(act.reshape(-1, 2).copy()) | |
| obs, _, ep_done, _ = sim.step(act) | |
| fin = np.where(ep_done)[0] | |
| if len(fin): | |
| done_eps += len(fin) | |
| obs = sim.reset_envs(fin.tolist(), | |
| [generate_layout(rng, args.n_agents, trap=False) for _ in fin]) | |
| O = torch.as_tensor(np.concatenate(obs_list, axis=0)) | |
| A = torch.as_tensor(np.concatenate(act_list, axis=0)) | |
| print(f"BC dataset: {O.shape[0]} samples, {done_eps} episodes", flush=True) | |
| net = ActorCritic() | |
| opt = torch.optim.Adam(list(net.actor.parameters()) + list(net.mean.parameters()), lr=1e-3) | |
| n = O.shape[0] | |
| for ep in range(args.epochs): | |
| perm = torch.randperm(n) | |
| tot = 0.0 | |
| for s in range(0, n, 1024): | |
| b = perm[s:s + 1024] | |
| mean, _ = net.forward(O[b]) | |
| pred = torch.tanh(mean) * AMAX | |
| loss = nn.functional.mse_loss(pred, A[b]) | |
| opt.zero_grad(); loss.backward(); opt.step() | |
| tot += float(loss) * len(b) | |
| print(f"bc epoch {ep + 1}/{args.epochs} mse={tot / n:.4f}", flush=True) | |
| # action agreement on a held-out-style check: mean |pred - teacher| | |
| with torch.no_grad(): | |
| mean, _ = net.forward(O[:4096]) | |
| pred = torch.tanh(mean) * AMAX | |
| print(f"BC final: mean |action error| = {float((pred - A[:4096]).abs().mean()):.3f} " | |
| f"(accel units)", flush=True) | |
| torch.save(net.state_dict(), args.out) | |
| print(f"saved {args.out}") | |
| if __name__ == "__main__": | |
| main() | |