Sean13 commited on
Commit
867ae15
·
verified ·
1 Parent(s): 6d5f894

Add scripts/render.py

Browse files
Files changed (1) hide show
  1. scripts/render.py +161 -0
scripts/render.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Render evaluation videos from a trained checkpoint.
3
+
4
+ Usage:
5
+ python render.py --checkpoint checkpoints/halfcheetah_6x1/ours_s0.pt \
6
+ --env mamujoco_HalfCheetah_6x1 \
7
+ --output_dir videos/ \
8
+ --n_episodes 3
9
+ """
10
+
11
+ import argparse
12
+ import sys
13
+ from pathlib import Path
14
+
15
+ import numpy as np
16
+ import torch
17
+
18
+
19
+ MAMUJOCO_ENVS = {
20
+ "mamujoco_HalfCheetah_6x1": ("HalfCheetah-v2", "6x1"),
21
+ "mamujoco_Humanoid_9_8": ("Humanoid-v2", "9|8"),
22
+ "mamujoco_ManySegmentSwimmer_6x1": ("ManySegmentSwimmer", "6x1"),
23
+ }
24
+
25
+
26
+ def parse_args():
27
+ parser = argparse.ArgumentParser(description="Render evaluation videos")
28
+ parser.add_argument("--checkpoint", type=str, required=True,
29
+ help="Path to .pt checkpoint file")
30
+ parser.add_argument("--env", type=str, required=True,
31
+ choices=list(MAMUJOCO_ENVS.keys()) + ["harvest_5"],
32
+ help="Environment name")
33
+ parser.add_argument("--output_dir", type=str, default="videos",
34
+ help="Directory to save rendered videos")
35
+ parser.add_argument("--n_episodes", type=int, default=3,
36
+ help="Number of episodes to render")
37
+ parser.add_argument("--seed", type=int, default=0,
38
+ help="Rendering seed")
39
+ parser.add_argument("--fps", type=int, default=30,
40
+ help="Frames per second for video")
41
+ parser.add_argument("--width", type=int, default=640,
42
+ help="Video width in pixels")
43
+ parser.add_argument("--height", type=int, default=480,
44
+ help="Video height in pixels")
45
+ return parser.parse_args()
46
+
47
+
48
+ def make_render_env(env_name, seed=0):
49
+ """Create environment with rendering enabled."""
50
+ if env_name in MAMUJOCO_ENVS:
51
+ scenario, agent_conf = MAMUJOCO_ENVS[env_name]
52
+ try:
53
+ from mappo_lagrangian.envs.safety_ma_mujoco.safety_multiagent_mujoco import MujocoMulti
54
+ except ImportError:
55
+ print("ERROR: mappo_lagrangian package not installed.")
56
+ print("Install from: macpo_base/MAPPO-Lagrangian/")
57
+ sys.exit(1)
58
+
59
+ env_args = {
60
+ "scenario": scenario,
61
+ "agent_conf": agent_conf,
62
+ "agent_obsk": 1,
63
+ "episode_limit": 1000,
64
+ }
65
+ env = MujocoMulti(env_args=env_args)
66
+ env.seed(seed)
67
+ return env
68
+ else:
69
+ print(f"Rendering not supported for {env_name}")
70
+ sys.exit(1)
71
+
72
+
73
+ def render_episodes(env, checkpoint, n_episodes, output_dir, fps=30,
74
+ width=640, height=480):
75
+ """Render episodes and save as videos."""
76
+ try:
77
+ import imageio
78
+ except ImportError:
79
+ print("ERROR: imageio required for video rendering.")
80
+ print(" pip install imageio imageio-ffmpeg")
81
+ sys.exit(1)
82
+
83
+ output_dir = Path(output_dir)
84
+ output_dir.mkdir(parents=True, exist_ok=True)
85
+
86
+ for ep in range(n_episodes):
87
+ frames = []
88
+ obs = env.reset()
89
+ done = False
90
+ step = 0
91
+ episode_reward = 0.0
92
+ episode_cost = 0.0
93
+
94
+ while not done and step < 1000:
95
+ # Render frame
96
+ try:
97
+ frame = env.render(mode="rgb_array")
98
+ if frame is not None:
99
+ frames.append(frame)
100
+ except Exception as e:
101
+ if step == 0:
102
+ print(f" Warning: render failed ({e}). Trying offscreen...")
103
+ try:
104
+ frame = env.render(
105
+ mode="rgb_array",
106
+ width=width,
107
+ height=height,
108
+ )
109
+ if frame is not None:
110
+ frames.append(frame)
111
+ except Exception:
112
+ print(" Offscreen rendering also failed. Skipping video.")
113
+ return
114
+
115
+ # Template: replace with actual policy forward pass
116
+ n_agents = env.n_agents if hasattr(env, "n_agents") else 1
117
+ action = [env.action_space[i].sample() for i in range(n_agents)]
118
+
119
+ obs, rewards, dones, infos = env.step(action)
120
+ episode_reward += sum(rewards) if isinstance(rewards, list) else rewards
121
+ if isinstance(infos, list):
122
+ episode_cost += sum(info.get("cost", 0) for info in infos)
123
+ done = all(dones) if isinstance(dones, list) else dones
124
+ step += 1
125
+
126
+ if frames:
127
+ video_path = output_dir / f"episode_{ep:03d}.mp4"
128
+ imageio.mimwrite(str(video_path), frames, fps=fps)
129
+ print(f" Episode {ep}: {step} steps, reward={episode_reward:.1f}, "
130
+ f"cost={episode_cost:.2f} -> {video_path}")
131
+ else:
132
+ print(f" Episode {ep}: no frames captured")
133
+
134
+
135
+ def main():
136
+ args = parse_args()
137
+
138
+ print(f"Loading checkpoint: {args.checkpoint}")
139
+ ckpt = torch.load(args.checkpoint, map_location="cpu", weights_only=False)
140
+
141
+ if "final_metrics" in ckpt:
142
+ m = ckpt["final_metrics"]
143
+ print(f" Welfare: {m.get('total_welfare', 'N/A')}")
144
+ print(f" Final rho: {m.get('final_rho', 'N/A')}")
145
+
146
+ try:
147
+ env = make_render_env(args.env, seed=args.seed)
148
+ except (ImportError, SystemExit):
149
+ print("Cannot create rendering environment. Exiting.")
150
+ sys.exit(1)
151
+
152
+ print(f"\nRendering {args.n_episodes} episodes to {args.output_dir}/")
153
+ render_episodes(
154
+ env, ckpt, args.n_episodes, args.output_dir,
155
+ fps=args.fps, width=args.width, height=args.height,
156
+ )
157
+ print("Done.")
158
+
159
+
160
+ if __name__ == "__main__":
161
+ main()