def train_population(pop: Population, games: list, unused_cpu: int = 2): """Evaluate the given population on a training set.""" multi_env = get_multi_env(pop=pop, game_config=pop.config) multi_env.set_games(games, noise=False) pool = mp.Pool(mp.cpu_count() - unused_cpu) manager = mp.Manager() return_dict = manager.dict() pbar = tqdm(total=len(pop.population), desc="Evaluating") def update(*_): pbar.update() for genome_id, genome in pop.population.items(): pool.apply_async(func=multi_env.eval_genome, args=((genome_id, genome), return_dict), callback=update) pool.close() # Close the pool pool.join() # Postpone continuation until everything is finished pbar.close() # Calculate the fitness from the given return_dict fitness = calc_pop_fitness( fitness_cfg=pop.config.evaluation, game_cfg=pop.config.game, game_obs=return_dict, gen=pop.generation, ) for i, genome in pop.population.items(): genome.fitness = fitness[i] # Save the results pop.generation += 1 pop.save()
def trace_genomes(self, pop: Population, given_genome: Genome = None, parallel: bool = True): """ 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 :param parallel: Create the traces in parallel """ multi_env = get_multi_env(pop=pop, game_config=self.game_config) if len(self.games) > 20 and given_genome is None: raise Exception( "It is not advised to evaluate on more than 20 at once") elif len(self.games) > 100: raise Exception( "It is not advised to evaluate on more than 100 at once") # Set the games for which traces will be made multi_env.set_games(self.games, noise=False) # Fetch the dictionary of genomes genomes = [(given_genome.key, given_genome)] if given_genome else list( iteritems(pop.population)) if parallel: # Initialize the evaluation-pool pool = mp.Pool(mp.cpu_count() - self.unused_cpu) manager = mp.Manager() return_dict = manager.dict() # Evaluate the genomes for genome in genomes: pool.apply_async(func=multi_env.trace_genome, args=(genome, return_dict)) pool.close() # Close the pool pool.join() # Postpone continuation until everything is finished else: # Train sequentially return_dict = dict() for genome in tqdm(genomes, desc="sequential evaluating"): multi_env.trace_genome(genome, return_dict) # Create blueprint of final result game_objects = [get_game(g, cfg=self.game_config) for g in self.games] path = get_subfolder( f"population{'_backup' if pop.use_backup else ''}/storage/{pop.folder_name}/{pop}/", 'images') path = get_subfolder(path, 'games') create_traces( traces=return_dict, games=game_objects, gen=pop.generation, save_path=path, save_name=f'trace_{given_genome.key}' if given_genome else 'trace', )
def evaluate_population(pop: Population, cfg: Config, cpu: int, experiment_id: int): """Evaluate the given population.""" pop.log(f"{pop.name} - Evaluating the population...") _, game_ids_eval = get_game_ids(experiment_id=experiment_id) multi_env = get_multi_env(pop=pop, game_config=cfg) multi_env.set_games(game_ids_eval, noise=False) pool = mp.Pool(mp.cpu_count() - cpu) manager = mp.Manager() return_dict = manager.dict() pbar = tqdm(total=len(pop.population), desc="Evaluating") def update(*_): pbar.update() for genome_id, genome in pop.population.items(): pool.apply_async(func=multi_env.eval_genome, args=((genome_id, genome), return_dict), callback=update) pool.close() # Close the pool pool.join() # Postpone continuation until everything is finished pbar.close() # Calculate the fitness from the given return_dict pop.log(f"{pop.name} - Calculating fitness scores...") fitness = calc_pop_fitness( fitness_cfg=pop.config.evaluation, game_cfg=cfg.game, game_obs=return_dict, gen=pop.generation, ) for i, genome in pop.population.items(): genome.fitness = fitness[i] # Get the fittest genome best = None for g in pop.population.values(): if best is None or g.fitness > best.fitness: best = g pop.best_genome = best # Save the results pop.save() # Visualize most fit genome visualize_genome( debug=True, genome=best, population=pop, ) # Trace the most fit genome trace_most_fit( debug=False, games=game_ids_eval, genome=best, population=pop, unused_cpu=cpu, )
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 blueprint_genomes(self, pop: Population, parallel: bool = True): """ Create blueprints for all the requested mazes. :param pop: Population object :param parallel: Evaluate the population in parallel """ multi_env = get_multi_env(pop=pop, game_config=self.game_config) if len(self.games) > 100: raise Exception( "It is not advised to evaluate on more than 100 at once") multi_env.set_games(self.games, noise=False) # Fetch the dictionary of genomes genomes = list(iteritems(pop.population)) if parallel: # Initialize the evaluation-pool pool = mp.Pool(mp.cpu_count() - self.unused_cpu) manager = mp.Manager() return_dict = manager.dict() # Evaluate the genomes for genome in genomes: pool.apply_async(func=multi_env.eval_genome, args=(genome, return_dict)) pool.close() # Close the pool pool.join() # Postpone continuation until everything is finished else: # Evaluate sequentially return_dict = dict() for genome in genomes: multi_env.eval_genome(genome, return_dict) # Create blueprint of final result game_objects = [get_game(g, cfg=self.game_config) for g in self.games] path = get_subfolder( f"population{'_backup' if pop.use_backup else ''}/storage/{pop.folder_name}/{pop}/", 'images') path = get_subfolder(path, 'games') create_blueprints( final_observations=return_dict, games=game_objects, gen=pop.generation, save_path=path, )
def evaluate_same_games_and_evolve( self, games: list, pop: Population, n: int = 1, parallel=True, save_interval: int = 1, ): """ Evaluate the population on the same games. :param games: List of games used for training :param pop: Population object :param n: Number of generations :param parallel: Parallel the code (disable parallelization for debugging purposes) :param save_interval: Indicates how often a population gets saved """ multi_env = get_multi_env(pop=pop, game_config=self.game_config) msg = f"Repetitive evaluating games: {games}" pop.log(msg, print_result=False) multi_env.set_games(games) # Iterate and evaluate over the games saved = True for iteration in range(n): single_evaluation( multi_env=multi_env, parallel=parallel, pop=pop, unused_cpu=self.unused_cpu, ) # Save the population if (iteration + 1) % save_interval == 0: pop.save() saved = True else: saved = False # Make sure that last iterations saves if not saved: pop.save()
def evaluate_and_evolve( self, pop: Population, n: int = 1, parallel=True, save_interval: int = 1, ): """ Evaluate the population for a single evaluation-process. :param pop: Population object :param n: Number of generations :param parallel: Parallel the code (disable parallelization for debugging purposes) :param save_interval: Indicates how often a population gets saved """ multi_env = get_multi_env(pop=pop, game_config=self.game_config) saved = True for iteration in range(n): # Set random set of games self.sample_games(multi_env, pop.log) # Evaluate the population on the newly sampled games single_evaluation( multi_env=multi_env, parallel=parallel, pop=pop, unused_cpu=self.unused_cpu, ) # Save the population if (iteration + 1) % save_interval == 0: pop.save() saved = True else: saved = False # Make sure that last iterations saves if not saved: pop.save()
def train( population: Population, game_config: Config, games: list, iterations: int, unused_cpu: int = 0, save_interval: int = 10, ): """Train the population on the requested number of iterations. Manual adaptation of main's train().""" population.log("\n===> TRAINING <===\n") multi_env = get_multi_env(pop=population, game_config=game_config) msg = f"Repetitive evaluating on games: {games} for {iterations} iterations" population.log(msg, print_result=False) # Iterate and evaluate over the games saved = True for iteration in range(iterations): # Set and randomize the games multi_env.set_games(games, noise=True) # Prepare the generation's reporters for the generation population.reporters.start_generation(gen=population.generation, logger=population.log) # Fetch the dictionary of genomes genomes = list(iteritems(population.population)) # Initialize the evaluation-pool pool = mp.Pool(mp.cpu_count() - unused_cpu) manager = mp.Manager() return_dict = manager.dict() for genome in genomes: pool.apply_async(func=multi_env.eval_genome, args=(genome, return_dict)) pool.close() # Close the pool pool.join() # Postpone continuation until everything is finished # Calculate the fitness from the given return_dict fitness = calc_pop_fitness( fitness_cfg=population.config.evaluation, game_cfg=game_config.game, game_obs=return_dict, gen=population.generation, ) for i, genome in genomes: genome.fitness = fitness[i] # Gather and report statistics best = None for g in itervalues(population.population): if best is None or g.fitness > best.fitness: best = g population.reporters.post_evaluate(population=population.population, species=population.species, best_genome=best, logger=population.log) # Update the population's best_genome genomes = sorted(population.population.items(), key=lambda x: x[1].fitness, reverse=True) population.best_fitness[population.generation] = genomes[0][1].fitness population.best_genome_hist[population.generation] = genomes[0] population.best_genome = best # Let population evolve population.evolve() # Update the genomes such all have one hidden node for g in population.population.values(): n_hidden, _ = g.size() while n_hidden < 1: g.mutate_add_connection(population.config.genome) n_hidden, _ = g.size() # End generation population.reporters.end_generation(population=population.population, name=str(population), species_set=population.species, logger=population.log) # Save the population if (iteration + 1) % save_interval == 0: population.save() saved = True else: saved = False # Make sure that last iterations saves if not saved: population.save()
def evaluate_and_evolve( self, pop: Population, n: int = 1, parallel=True, save_interval: int = 1, ): """ Evaluate the population on the same set of games. :param pop: Population object :param n: Number of generations :param parallel: Parallel the code (disable parallelization for debugging purposes) :param save_interval: Indicates how often a population gets saved """ multi_env = get_multi_env(pop=pop, game_config=self.game_config) msg = f"Repetitive evaluating on games: {self.games} for {n} iterations" pop.log(msg, print_result=False) # Iterate and evaluate over the games saved = True for iteration in range(n): # Set and randomize the games multi_env.set_games(self.games, noise=True) # Prepare the generation's reporters for the generation pop.reporters.start_generation(gen=pop.generation, logger=pop.log) # Fetch the dictionary of genomes genomes = list(iteritems(pop.population)) if parallel: # Initialize the evaluation-pool pool = mp.Pool(mp.cpu_count() - self.unused_cpu) manager = mp.Manager() return_dict = manager.dict() for genome in genomes: pool.apply_async(func=multi_env.eval_genome, args=(genome, return_dict)) pool.close() # Close the pool pool.join( ) # Postpone continuation until everything is finished else: return_dict = dict() for genome in tqdm(genomes, desc="sequential training"): multi_env.eval_genome(genome, return_dict) # Calculate the fitness from the given return_dict fitness = calc_pop_fitness( fitness_cfg=pop.config.evaluation, game_cfg=self.game_config.game, game_obs=return_dict, gen=pop.generation, ) for i, genome in genomes: genome.fitness = fitness[i] # Gather and report statistics best = None for g in itervalues(pop.population): if best is None or g.fitness > best.fitness: best = g pop.reporters.post_evaluate(population=pop.population, species=pop.species, best_genome=best, logger=pop.log) # Update the population's best_genome genomes = sorted(pop.population.items(), key=lambda x: x[1].fitness, reverse=True) pop.best_fitness[pop.generation] = genomes[0][1].fitness pop.best_genome_hist[pop.generation] = genomes[0] pop.best_genome = best # Let population evolve pop.evolve() # End generation pop.reporters.end_generation(population=pop.population, name=str(pop), species_set=pop.species, logger=pop.log) # Save the population if (iteration + 1) % save_interval == 0: pop.save() saved = True else: saved = False # Make sure that last iterations saves if not saved: pop.save()