Spaces:
Sleeping
Sleeping
Upload evaluator.py
Browse files- src/evaluator.py +110 -102
src/evaluator.py
CHANGED
|
@@ -1,102 +1,110 @@
|
|
| 1 |
-
import numpy as np
|
| 2 |
-
import torch
|
| 3 |
-
from itertools import chain
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class Evaluator(object):
|
| 7 |
-
def __init__(self, environment, model, logger, agents, max_steps):
|
| 8 |
-
self.env = environment
|
| 9 |
-
self.model = model
|
| 10 |
-
self.logger = logger
|
| 11 |
-
self.agents = agents
|
| 12 |
-
self.max_steps = max_steps
|
| 13 |
-
|
| 14 |
-
def play_n_episodes(self, render=False, fixed_spawn=None, silent=False):
|
| 15 |
-
"""
|
| 16 |
-
wraps play_one_episode, playing a single episode at a time and logs
|
| 17 |
-
results used when playing demos.
|
| 18 |
-
"""
|
| 19 |
-
if fixed_spawn is None:
|
| 20 |
-
num_runs = 1
|
| 21 |
-
fixed_spawn = [None]
|
| 22 |
-
else:
|
| 23 |
-
# fixed_spawn should be, for example, [0.5 , 0.5 , 0.5, 0, 0, 0] for 2 runs
|
| 24 |
-
# In the first run agents spawn in the middle and in the second they will spawn from the corner
|
| 25 |
-
fixed_spawn = np.array(fixed_spawn).reshape((-1, 3)) # 3 dimensions
|
| 26 |
-
num_runs = fixed_spawn.shape[0]
|
| 27 |
-
# Set all the agents to the same spawn point
|
| 28 |
-
fixed_spawn = np.stack([fixed_spawn for _ in range(self.agents)], axis=-1)
|
| 29 |
-
|
| 30 |
-
num_files = self.env.files.num_files
|
| 31 |
-
self.model.train(False)
|
| 32 |
-
headers = ["number"] + list(chain.from_iterable(zip(
|
| 33 |
-
[f"Filename {i}" for i in range(self.agents)],
|
| 34 |
-
[f"Agent {i} pos x" for i in range(self.agents)],
|
| 35 |
-
[f"Agent {i} pos y" for i in range(self.agents)],
|
| 36 |
-
[f"Agent {i} pos z" for i in range(self.agents)],
|
| 37 |
-
[f"Landmark {i} pos x" for i in range(self.agents)],
|
| 38 |
-
[f"Landmark {i} pos y" for i in range(self.agents)],
|
| 39 |
-
[f"Landmark {i} pos z" for i in range(self.agents)],
|
| 40 |
-
[f"Distance {i}" for i in range(self.agents)])))
|
| 41 |
-
self.logger.write_locations(headers)
|
| 42 |
-
distances = []
|
| 43 |
-
for j in range(num_runs):
|
| 44 |
-
for k in range(num_files):
|
| 45 |
-
score, start_dists, q_values, info = self.play_one_episode(render, fixed_spawn=fixed_spawn[j])
|
| 46 |
-
row = [j * num_files + k + 1] + list(chain.from_iterable(zip(
|
| 47 |
-
[info[f"filename_{i}"] for i in range(self.agents)],
|
| 48 |
-
[info[f"agent_xpos_{i}"] for i in range(self.agents)],
|
| 49 |
-
[info[f"agent_ypos_{i}"] for i in range(self.agents)],
|
| 50 |
-
[info[f"agent_zpos_{i}"] for i in range(self.agents)],
|
| 51 |
-
[info.get(f"landmark_xpos_{i}", "N/A") for i in range(self.agents)],
|
| 52 |
-
[info.get(f"landmark_ypos_{i}", "N/A") for i in range(self.agents)],
|
| 53 |
-
[info.get(f"landmark_zpos_{i}", "N/A") for i in range(self.agents)],
|
| 54 |
-
[info.get(f"distError_{i}", "N/A") for i in range(self.agents)])))
|
| 55 |
-
for i in range(self.agents):
|
| 56 |
-
key = f"distError_{i}"
|
| 57 |
-
if key in info:
|
| 58 |
-
distances.append(info[key])
|
| 59 |
-
self.logger.write_locations(row)
|
| 60 |
-
if len(distances) == 0:
|
| 61 |
-
return None, None # No distance mean and std for task "play" as there is no ground truth
|
| 62 |
-
mean = np.mean(distances, 0)
|
| 63 |
-
std = np.std(distances, 0, ddof=1)
|
| 64 |
-
if not silent:
|
| 65 |
-
self.logger.log(f"mean distances {mean}")
|
| 66 |
-
self.logger.log(f"Std distances {std}")
|
| 67 |
-
return mean, std
|
| 68 |
-
|
| 69 |
-
def play_one_episode(self, render=False, frame_history=4, fixed_spawn=None):
|
| 70 |
-
device = next(self.model.parameters()).device
|
| 71 |
-
def predict(obs_stack):
|
| 72 |
-
"""
|
| 73 |
-
Run a full episode, mapping observation to action,
|
| 74 |
-
using greedy policy.
|
| 75 |
-
"""
|
| 76 |
-
inputs = torch.from_numpy(obs_stack).float().permute(
|
| 77 |
-
0, 4, 1, 2, 3).unsqueeze(0).to(device)
|
| 78 |
-
with torch.no_grad():
|
| 79 |
-
q_vals = self.model(inputs)
|
| 80 |
-
idx = torch.max(q_vals, -1)[1]
|
| 81 |
-
greedy_steps = np.array(idx, dtype=np.int32).flatten()
|
| 82 |
-
return greedy_steps, q_vals.
|
| 83 |
-
|
| 84 |
-
obs_stack = self.env.reset(fixed_spawn)
|
| 85 |
-
# Here obs have shape (agent, *image_size, frame_history)
|
| 86 |
-
sum_r = np.zeros((self.agents))
|
| 87 |
-
isOver = [False] * self.agents
|
| 88 |
-
start_dists = None
|
| 89 |
-
steps = 0
|
| 90 |
-
while steps < self.max_steps and not np.all(isOver):
|
| 91 |
-
acts, q_values = predict(obs_stack)
|
| 92 |
-
obs_stack, r, isOver, info = self.env.step(acts, q_values, isOver)
|
| 93 |
-
steps += 1
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import torch
|
| 3 |
+
from itertools import chain
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class Evaluator(object):
|
| 7 |
+
def __init__(self, environment, model, logger, agents, max_steps):
|
| 8 |
+
self.env = environment
|
| 9 |
+
self.model = model
|
| 10 |
+
self.logger = logger
|
| 11 |
+
self.agents = agents
|
| 12 |
+
self.max_steps = max_steps
|
| 13 |
+
|
| 14 |
+
def play_n_episodes(self, render=False, fixed_spawn=None, silent=False):
|
| 15 |
+
"""
|
| 16 |
+
wraps play_one_episode, playing a single episode at a time and logs
|
| 17 |
+
results used when playing demos.
|
| 18 |
+
"""
|
| 19 |
+
if fixed_spawn is None:
|
| 20 |
+
num_runs = 1
|
| 21 |
+
fixed_spawn = [None]
|
| 22 |
+
else:
|
| 23 |
+
# fixed_spawn should be, for example, [0.5 , 0.5 , 0.5, 0, 0, 0] for 2 runs
|
| 24 |
+
# In the first run agents spawn in the middle and in the second they will spawn from the corner
|
| 25 |
+
fixed_spawn = np.array(fixed_spawn).reshape((-1, 3)) # 3 dimensions
|
| 26 |
+
num_runs = fixed_spawn.shape[0]
|
| 27 |
+
# Set all the agents to the same spawn point
|
| 28 |
+
fixed_spawn = np.stack([fixed_spawn for _ in range(self.agents)], axis=-1)
|
| 29 |
+
|
| 30 |
+
num_files = self.env.files.num_files
|
| 31 |
+
self.model.train(False)
|
| 32 |
+
headers = ["number"] + list(chain.from_iterable(zip(
|
| 33 |
+
[f"Filename {i}" for i in range(self.agents)],
|
| 34 |
+
[f"Agent {i} pos x" for i in range(self.agents)],
|
| 35 |
+
[f"Agent {i} pos y" for i in range(self.agents)],
|
| 36 |
+
[f"Agent {i} pos z" for i in range(self.agents)],
|
| 37 |
+
[f"Landmark {i} pos x" for i in range(self.agents)],
|
| 38 |
+
[f"Landmark {i} pos y" for i in range(self.agents)],
|
| 39 |
+
[f"Landmark {i} pos z" for i in range(self.agents)],
|
| 40 |
+
[f"Distance {i}" for i in range(self.agents)])))
|
| 41 |
+
self.logger.write_locations(headers)
|
| 42 |
+
distances = []
|
| 43 |
+
for j in range(num_runs):
|
| 44 |
+
for k in range(num_files):
|
| 45 |
+
score, start_dists, q_values, info = self.play_one_episode(render, fixed_spawn=fixed_spawn[j])
|
| 46 |
+
row = [j * num_files + k + 1] + list(chain.from_iterable(zip(
|
| 47 |
+
[info[f"filename_{i}"] for i in range(self.agents)],
|
| 48 |
+
[info[f"agent_xpos_{i}"] for i in range(self.agents)],
|
| 49 |
+
[info[f"agent_ypos_{i}"] for i in range(self.agents)],
|
| 50 |
+
[info[f"agent_zpos_{i}"] for i in range(self.agents)],
|
| 51 |
+
[info.get(f"landmark_xpos_{i}", "N/A") for i in range(self.agents)],
|
| 52 |
+
[info.get(f"landmark_ypos_{i}", "N/A") for i in range(self.agents)],
|
| 53 |
+
[info.get(f"landmark_zpos_{i}", "N/A") for i in range(self.agents)],
|
| 54 |
+
[info.get(f"distError_{i}", "N/A") for i in range(self.agents)])))
|
| 55 |
+
for i in range(self.agents):
|
| 56 |
+
key = f"distError_{i}"
|
| 57 |
+
if key in info:
|
| 58 |
+
distances.append(info[key])
|
| 59 |
+
self.logger.write_locations(row)
|
| 60 |
+
if len(distances) == 0:
|
| 61 |
+
return None, None # No distance mean and std for task "play" as there is no ground truth
|
| 62 |
+
mean = np.mean(distances, 0)
|
| 63 |
+
std = np.std(distances, 0, ddof=1)
|
| 64 |
+
if not silent:
|
| 65 |
+
self.logger.log(f"mean distances {mean}")
|
| 66 |
+
self.logger.log(f"Std distances {std}")
|
| 67 |
+
return mean, std
|
| 68 |
+
|
| 69 |
+
def play_one_episode(self, render=False, frame_history=4, fixed_spawn=None):
|
| 70 |
+
device = next(self.model.parameters()).device
|
| 71 |
+
def predict(obs_stack):
|
| 72 |
+
"""
|
| 73 |
+
Run a full episode, mapping observation to action,
|
| 74 |
+
using greedy policy.
|
| 75 |
+
"""
|
| 76 |
+
inputs = torch.from_numpy(obs_stack).float().permute(
|
| 77 |
+
0, 4, 1, 2, 3).unsqueeze(0).to(device)
|
| 78 |
+
with torch.no_grad():
|
| 79 |
+
q_vals = self.model(inputs)
|
| 80 |
+
idx = torch.max(q_vals, -1)[1]
|
| 81 |
+
greedy_steps = np.array(idx, dtype=np.int32).flatten()
|
| 82 |
+
return greedy_steps, q_vals.detach().cpu().numpy().squeeze(0)
|
| 83 |
+
|
| 84 |
+
obs_stack = self.env.reset(fixed_spawn)
|
| 85 |
+
# Here obs have shape (agent, *image_size, frame_history)
|
| 86 |
+
sum_r = np.zeros((self.agents))
|
| 87 |
+
isOver = [False] * self.agents
|
| 88 |
+
start_dists = None
|
| 89 |
+
steps = 0
|
| 90 |
+
while steps < self.max_steps and not np.all(isOver):
|
| 91 |
+
acts, q_values = predict(obs_stack)
|
| 92 |
+
obs_stack, r, isOver, info = self.env.step(acts, q_values, isOver)
|
| 93 |
+
steps += 1
|
| 94 |
+
# Machine-parseable trajectory log line (agent 0 only). Consumed
|
| 95 |
+
# by app.py to render the agent's search path as an animation.
|
| 96 |
+
print("STEP_LOC: {} {} {} {}".format(
|
| 97 |
+
steps,
|
| 98 |
+
info.get('agent_xpos_0', 'NA'),
|
| 99 |
+
info.get('agent_ypos_0', 'NA'),
|
| 100 |
+
info.get('agent_zpos_0', 'NA'),
|
| 101 |
+
))
|
| 102 |
+
if start_dists is None:
|
| 103 |
+
start_dists = [
|
| 104 |
+
info.get('distError_' + str(i), "N/A") for i in range(self.agents)]
|
| 105 |
+
if render:
|
| 106 |
+
self.env.render()
|
| 107 |
+
for i in range(self.agents):
|
| 108 |
+
if not isOver[i]:
|
| 109 |
+
sum_r[i] += r[i]
|
| 110 |
+
return sum_r, start_dists, q_values, info
|