Source code for pyneat.reporting

"""Additional reporters (on top of what are offered by NEAT-Python) that are
triggered on particular events.
"""
import logging
import time

from neat.reporting import BaseReporter
from numpy import mean, std


[docs]class LogFileReporter(BaseReporter): """Write the same information as the StdOutReporter, but instead of printing to standard out, the outputs are written to a log file. Attributes: filename (str): The name of the log file to use. log_level (logging.level): The log level (either DEBUG, INFO, WARNING, ERROR, or CRITICAL). Note: All LogFileReporter logs are INFO level. show_species_detail (bool): Whether to show detailed species information. generation (int): The current generation. generation_start_time (int): The start time of the current generation. generation_times (list): The length of time to complete each generation. num_extinctions (int): The number of extinctions that have occurred. """ def __init__(self, filename, log_level=logging.INFO, show_species_detail=True): """Initialise a new LogFileReporter. Args: filename (str): The name of the log file to use. log_level (logging.level): The log level (either DEBUG, INFO, WARNING, ERROR, or CRITICAL). Note: All LogFileReporter logs are INFO level. show_species_detail (bool): Whether to show detailed species information. """ self.filename = filename self.log_level = log_level self.show_species_detail = show_species_detail self.generation = None self.generation_start_time = None self.generation_times = [] self.num_extinctions = 0 logging.basicConfig(filename=self.filename, level=self.log_level)
[docs] def start_generation(self, generation): """The log message to write when a generation is started. Args: generation (int): The current generation number. """ self.generation = generation logging.info('\n ****** Running generation {0} ****** \n'.format(generation)) self.generation_start_time = time.time()
[docs] def end_generation(self, config, population, species_set): """The log message to write when a generation is ended. Args: config (CustomConfig): The global configuration settings for the entire algorithm. population (dict): The population of individuals. A dictionary of genome key, genome pairs. species_set (SpeciesSet): The speciation scheme for dividing the population into species. """ ng = len(population) ns = len(species_set.species) if self.show_species_detail: logging.info('Population of {0:d} members in {1:d} species:'.format(ng, ns)) logging.info(" ID age size fitness adj fit stag") logging.info(" ==== === ==== ======= ======= ====") for sid in sorted(species_set.species): s = species_set.species[sid] a = self.generation - s.created n = len(s.members) f = "--" if s.fitness is None else "{:.1f}".format(s.fitness) af = "--" if s.adjusted_fitness is None else "{:.3f}".format(s.adjusted_fitness) st = self.generation - s.last_improved logging.info( " {: >4} {: >3} {: >4} {: >7} {: >7} {: >4}".format(sid, a, n, f, af, st)) else: logging.info('Population of {0:d} members in {1:d} species'.format(ng, ns)) elapsed = time.time() - self.generation_start_time self.generation_times.append(elapsed) self.generation_times = self.generation_times[-10:] average = sum(self.generation_times) / len(self.generation_times) logging.info('Total extinctions: {0:d}'.format(self.num_extinctions)) if len(self.generation_times) > 1: logging.info("Generation time: {0:.3f} sec ({1:.3f} average)".format(elapsed, average)) else: logging.info("Generation time: {0:.3f} sec".format(elapsed))
[docs] def post_evaluate(self, config, population, species, best_genome): """The log message to write after evaluating the fitness of the population. Args: config (CustomConfig): The global configuration settings for the entire algorithm. population (dict): The population of individuals. A dictionary of genome key, genome pairs. species (SpeciesSet): The speciation scheme for dividing the population into species. best_genome (Genome): The best genome from the population. """ # pylint: disable=no-self-use fitnesses = [c.fitness for c in population.values()] fit_mean = mean(fitnesses) fit_std = std(fitnesses) best_species_id = species.get_species_id(best_genome.key) logging.info('Population\'s average fitness: {0:3.5f} stdev: {1:3.5f}'.format(fit_mean, fit_std)) logging.info( 'Best fitness: {0:3.5f} - size: {1!r} - species {2} - id {3}'.format(best_genome.fitness, best_genome.size(), best_species_id, best_genome.key))
[docs] def complete_extinction(self): """The log message to write after a complete extinction has occurred. """ self.num_extinctions += 1 logging.info('All species extinct.')
[docs] def found_solution(self, config, generation, best): """The log message to write after a solution has been found. """ logging.info('\nBest individual in generation {0} meets fitness threshold - complexity: {1!r}'.format( self.generation, best.size()))
[docs] def species_stagnant(self, sid, species): """The log message to write when a species has stagnated. """ if self.show_species_detail: logging.info("\nSpecies {0} with {1} members is stagnated: removing it".format(sid, len(species.members)))
[docs] def info(self, msg): """Write a custom log message. Args: msg (str): The log message to write. """ logging.info(msg)