def evaluate_population(self, pop, game_ids=None): # TODO: Not used, remove? """ Evaluate the population on a set of games and create blueprints of the final positions afterwards. :param pop: Population object :param game_ids: List of game-ids """ if game_ids: self.set_games(game_ids) if len(self.games) > 20: raise Exception( "It is not advised to evaluate a whole population on more than 20 games at once" ) # Create the environment which is responsible for evaluating the genomes multi_env = get_multi_env(pop=pop, game_config=self.game_config) # Initialize the evaluation-pool pool = mp.Pool(mp.cpu_count()) manager = mp.Manager() return_dict = manager.dict() # Fetch the dictionary of genomes genomes = list(iteritems(pop.population)) # Progress bar during evaluation pbar = tqdm(total=len(genomes), desc="parallel training") def cb(*_): """Update progressbar after finishing a single genome's evaluation.""" pbar.update() # Evaluate the genomes for genome in genomes: pool.apply_async(func=multi_env.eval_genome, args=(genome, return_dict), callback=cb) pool.close() # Close the pool pool.join() # Postpone continuation until everything is finished pbar.close() # Close the progressbar # Create blueprint of final result game_objects = [get_game(g, cfg=self.game_config) for g in self.games] create_blueprints(final_observations=return_dict, games=game_objects, gen=pop.generation, save_path=get_subfolder( f'population/storage/{pop.folder_name}/{pop}/', 'images'))
def trace_genomes(self, pop: Population, given_genome: Genome = None): """ Create blueprints that contain the walking-traces for all the requested mazes. :param pop: Population object :param given_genome: Single genomes for which the trace must be made """ multi_env = get_multi_env(pop=pop, game_config=self.game_config) if len(self.games) > 20: raise Exception( "It is not advised to evaluate on more than 20 at once") multi_env.set_games(self.games) # Initialize the evaluation-pool pool = mp.Pool(mp.cpu_count()) manager = mp.Manager() return_dict = manager.dict() # Fetch the dictionary of genomes genomes = [(given_genome.key, given_genome)] if given_genome else list( iteritems(pop.population)) # Progress bar during evaluation pbar = tqdm(total=len(genomes), desc="parallel evaluating") def cb(*_): """Update progressbar after finishing a single genome's evaluation.""" pbar.update() # Evaluate the genomes for genome in genomes: pool.apply_async(func=multi_env.trace_genome, args=(genome, return_dict), callback=cb) pool.close() # Close the pool pool.join() # Postpone continuation until everything is finished # Create blueprint of final result game_objects = [get_game(g, cfg=self.game_config) for g in self.games] create_traces( traces=return_dict, games=game_objects, gen=pop.generation, save_path=get_subfolder( f'population/storage/{pop.folder_name}/{pop}/', 'images'), save_name=f'trace_{given_genome.key}' if given_genome else 'trace', )
def visualize(self, genome, game_id: int): """ Visualize the performance of a single genome. :param genome: Tuple (genome_id, genome_class) :param game_id: ID of the game that will be used for evaluation """ # Create the requested game game: Game = get_game(game_id, cfg=self.game_config) game.player.set_active_sensors( set(genome.get_used_connections().keys())) # Create space in which game will be played window = pyglet.window.Window( game.game_config.x_axis * game.game_config.p2m, game.game_config.y_axis * game.game_config.p2m, "Robot Simulator - Game {id:03d}".format(id=game_id), resizable=False, visible=True) window.set_location(100, 100) pyglet.gl.glClearColor(1, 1, 1, 1) # Setup the requested game self.state = game.reset()[D_SENSOR_LIST] self.finished = False # Make the network used during visualization net = self.make_net( genome=genome, genome_config=self.pop_config.genome, game_config=self.game_config, bs=1, initial_read=self.state, ) # Create the visualize-environment space = pymunk.Space() options = DrawOptions() # Draw static objects - walls for wall in game.walls: wall_shape = pymunk.Segment(space.static_body, a=wall.x * game.game_config.p2m, b=wall.y * game.game_config.p2m, radius=0.05 * game.game_config.p2m) # 5cm walls wall_shape.color = (0, 0, 0) space.add(wall_shape) # Draw static objects - target target_body = pymunk.Body(body_type=pymunk.Body.KINEMATIC) target_body.position = game.target * game.game_config.p2m target_shape = pymunk.Circle(body=target_body, radius=game.bot_config.radius * game.game_config.p2m) target_shape.sensor = True target_shape.color = (0, 128, 0) space.add(target_body, target_shape) # Init player² m = pymunk.moment_for_circle(mass=2, inner_radius=0, outer_radius=game.bot_config.radius * game.game_config.p2m) player_body = pymunk.Body(mass=1, moment=m) player_body.position = game.player.pos * game.game_config.p2m player_body.angle = game.player.angle player_shape = pymunk.Circle(body=player_body, radius=game.bot_config.radius * game.game_config.p2m) player_shape.color = (255, 0, 0) space.add(player_body, player_shape) label = pyglet.text.Label( f'{self.time}', # TODO: Creates error in WeakMethod after run (during termination) font_size=16, color=(100, 100, 100, 100), x=window.width - 20, y=window.height - 20, anchor_x='center', anchor_y='center') # Draw the robot's sensors def draw_sensors(): [ space.remove(s) for s in space.shapes if s.sensor and type(s) == pymunk.Segment ] for key in game.player.active_sensors: s = game.player.sensors[key] if type(s) == ProximitySensor: line = pymunk.Segment(space.static_body, a=s.start_pos * game.game_config.p2m, b=s.end_pos * game.game_config.p2m, radius=0.5) line.sensor = True touch = ((s.start_pos - s.end_pos).get_length() < game.bot_config.ray_distance - 0.05) line.color = (100, 100, 100) if touch else ( 200, 200, 200) # Brighten up ray if it makes contact space.add(line) @window.event def on_draw(): window.clear() draw_sensors() label.draw() space.debug_draw(options=options) def update_method(_): # Input dt ignored dt = 1 / game.game_config.fps self.time += dt label.text = str(int(self.time)) # Stop when target is reached if not self.finished: # Query the game for the next action action = self.query_net(net, [self.state]) if self.debug: print("Passed time:", round(dt, 3)) print("Location: x={}, y={}".format( round(player_body.position.x / game.game_config.p2m, 2), round(player_body.position.y / game.game_config.p2m, 2))) print("Action: lw={l}, rw={r}".format( l=round(action[0][0], 3), r=round(action[0][1], 3))) print("Observation:", [round(s, 3) for s in self.state]) # Progress game by one step obs = game.step_dt(dt=dt, l=action[0][0], r=action[0][1]) self.finished = obs[D_DONE] self.state = obs[D_SENSOR_LIST] # Update space's player coordinates and angle player_body.position = game.player.pos * game.game_config.p2m player_body.angle = game.player.angle space.step(dt) # Run the game pyglet.clock.schedule_interval( update_method, 1.0 / (game.game_config.fps * self.speedup)) pyglet.app.run()
# Set the title for the plot plt.title("Heatmap - Game {id:05d}".format(id=game.id)) # Create the colorbar cax = divider.append_axes('right', size='5%', pad=0.05) norm = mpl.colors.Normalize(vmin=0, vmax=max_dist) data = np.ones((256, 3)) data[:, 1] = np.linspace(0.33, 1, 256) data[:, 2] = 0 mpl.colorbar.ColorbarBase(cax, cmap=clr.ListedColormap(data), norm=norm, orientation='vertical') # Save the figure plt.savefig(f'environment/visualizations/heatmap_game{game.id:05d}') if __name__ == '__main__': os.chdir("../..") cfg = Config() # for g_id in [0]: for g_id in tqdm(range(1, 11)): # Load the game g = get_game(g_id, cfg=cfg) # Create visualizations game_blueprint(g) # path_heatmap(g)
def eval_genome( self, genome, return_dict=None, ): """ Evaluate a single genome in a pre-defined game-environment. :param genome: Tuple (genome_id, genome_class) :param return_dict: Dictionary used to return observations corresponding the genome """ # Split up genome by id and genome itself genome_id, genome = genome used_connections = set(genome.get_used_connections().keys()) # Initialize the games on which the genome is tested games = [get_game(g, cfg=self.game_config) for g in self.games] for g in games: g.player.set_active_sensors(used_connections) # Set active-sensors # Ask for each of the games the starting-state states = [g.reset()[D_SENSOR_LIST] for g in games] # Finished-state for each of the games is set to false finished = [False] * self.batch_size # Create the network used to query on, initialize it with the first-game's readings (good approximation) net = self.make_net( genome=genome, genome_config=self.pop_config.genome, game_config=self.game_config, bs=self.batch_size, initial_read=states[0], ) # Start iterating the environments step_num = 0 while True: # Check if maximum iterations is reached if step_num == self.max_steps: break # Determine the actions made by the agent for each of the states actions = self.query_net(net, states) # Check if each game received an action assert len(actions) == len(games) for i, (g, a, f) in enumerate(zip(games, actions, finished)): # Ignore if game has finished if not f: # Proceed the game with one step, based on the predicted action obs = g.step(l=a[0], r=a[1]) finished[i] = obs[D_DONE] # Update the candidate's current state states[i] = obs[D_SENSOR_LIST] # Stop if agent reached target in all the games if all(finished): break step_num += 1 # Return the final observations if return_dict is not None: return_dict[genome_id] = [g.close() for g in games]
def get_game_params(self): """Return list of all game-parameters currently in self.games.""" return [ get_game(i, cfg=self.game_config).game_params() for i in self.games ]