示例#1
0
    def rt_iterate(self):
        self.population.reporters.start_generation(self.population.generation)

        # Gather and report statistics.
        best = None
        worst = None
        for g in itervalues(self.population.population):
            if not hasattr(g, 'birth'):
                g.birth = self.population.generation

            if g.fitness is None:
                continue

            if best is None or g.fitness > best.fitness:
                best = g
            if (worst is None or g.fitness < worst.fitness) and \
                    self.population.generation - g.birth > self.population.config.stagnation_config.max_stagnation:
                worst = g

        population_with_fitness = dict([
            p for p in iteritems(self.population.population)
            if p[1].fitness is not None
        ])
        if population_with_fitness:
            self.population.reporters.post_evaluate(self.config,
                                                    population_with_fitness,
                                                    self.population.species,
                                                    best)

        # Track the best genome ever seen.
        if self.population.best_genome is None or best.fitness > self.population.best_genome.fitness:
            self.population.best_genome = best

        if not self.population.config.no_fitness_termination:
            # End if the fitness threshold is reached.
            fv = self.population.fitness_criterion(
                g.fitness for g in itervalues(population_with_fitness))
            if fv >= self.population.config.fitness_threshold:
                self.population.reporters.found_solution(
                    self.population.config, self.population.generation, best)
                return

        # remove worst genome and replace with new one
        if worst is not None:
            new_genomes = self.population.reproduction.reproduce(
                self.population.config, self.population.species, 1,
                self.population.generation)
            new_key = np.max(
                [g.key for g in itervalues(self.population.population)]) + 1
            for g in itervalues(new_genomes):
                del self.population.population[worst.key]
                g.key = new_key
                self.population.population[new_key] = g
                print(new_key)
                break

        # Divide the new population into species.
        if population_with_fitness:
            self.population.species.speciate(self.population.config,
                                             population_with_fitness,
                                             self.population.generation)

        # self.population.reporters.end_generation(self.population.config, self.population.population,
        #                                          self.population.species)

        self.population.generation += 1
示例#2
0
    def reproduce(self, config, species, pop_size, generation):
        """
        Handles creation of genomes, either from scratch or by sexual or
        asexual reproduction from parents.
        """
        # TODO: I don't like this modification of the species and stagnation objects,
        # because it requires internal knowledge of the objects.

        # Filter out stagnated species, collect the set of non-stagnated
        # species members, and compute their average adjusted fitness.
        # The average adjusted fitness scheme (normalized to the interval
        # [0, 1]) allows the use of negative fitness values without
        # interfering with the shared fitness scheme.
        all_fitnesses = []
        remaining_species = []
        for stag_sid, stag_s, stagnant in self.stagnation.update(
                species, generation):
            if stagnant:
                self.reporters.species_stagnant(stag_sid, stag_s)
            else:
                all_fitnesses.extend(m.fitness
                                     for m in itervalues(stag_s.members))
                remaining_species.append(stag_s)
        # The above comment was not quite what was happening - now getting fitnesses
        # only from members of non-stagnated species.

        # No species left.
        if not remaining_species:
            species.species = {}
            return {}  # was []

        self.calculate_adjusted_fitnesses(remaining_species, all_fitnesses)
        adjusted_fitnesses = [s.adjusted_fitness for s in remaining_species]
        avg_adjusted_fitness = mean(adjusted_fitnesses)  # type: float
        self.reporters.info(
            "Average adjusted fitness: {:.3f}".format(avg_adjusted_fitness))

        # Compute the number of new members for each species in the new generation.
        previous_sizes = [len(s.members) for s in remaining_species]
        min_species_size = self.reproduction_config.min_species_size
        # Isn't the effective min_species_size going to be max(min_species_size,
        # self.reproduction_config.elitism)? That would probably produce more accurate tracking
        # of population sizes and relative fitnesses... doing. TODO: document.
        min_species_size = max(min_species_size,
                               self.reproduction_config.elitism)
        spawn_amounts = self.compute_spawn(adjusted_fitnesses, previous_sizes,
                                           pop_size, min_species_size)

        new_population = {}
        species.species = {}
        for spawn, s in zip(spawn_amounts, remaining_species):
            # If elitism is enabled, each species always at least gets to retain its elites.
            spawn = max(spawn, self.reproduction_config.elitism)

            assert spawn > 0

            # The species has at least one member for the next generation, so retain it.
            old_members = list(iteritems(s.members))
            s.members = {}
            species.species[s.key] = s

            # Sort members in order of descending fitness.
            old_members.sort(reverse=True, key=lambda x: x[1].fitness)

            # Transfer elites to new generation.
            if self.reproduction_config.elitism > 0:
                for i, m in old_members[:self.reproduction_config.elitism]:
                    new_population[i] = m
                    spawn -= 1

            if spawn <= 0:
                continue

            repro_cutoff = self.calculated_cutoff(len(old_members))
            old_members = old_members[:repro_cutoff]

            # Randomly choose parents and produce the number of offspring allotted to the species.
            while spawn > 0:
                spawn -= 1

                gid, child = self.generate_child(old_members, config)
                new_population[gid] = child

        return new_population
 def get_fitnesses(self):
     return [m.fitness for m in itervalues(self.members)]
示例#4
0
    def reproduce(self, config, species, pop_size, generation):
        """
        Handles creation of genomes, either from scratch or by sexual or
        asexual reproduction from parents.
        """
        # TODO: I don't like this modification of the species and stagnation objects,
        # because it requires internal knowledge of the objects.

        # Filter out stagnated species, collect the set of non-stagnated
        # species members, and compute their average adjusted fitness.
        # The average adjusted fitness scheme (normalized to the interval
        # [0, 1]) allows the use of negative fitness values without
        # interfering with the shared fitness scheme.
        all_fitnesses = []
        remaining_species = []
        for stag_sid, stag_s, stagnant in self.stagnation.update(
                species, generation):
            if stagnant:
                self.reporters.species_stagnant(stag_sid, stag_s)
            else:
                all_fitnesses.extend(m.fitness
                                     for m in itervalues(stag_s.members))
                remaining_species.append(stag_s)
        # The above comment was not quite what was happening - now getting fitnesses
        # only from members of non-stagnated species.

        # No species left.
        if not remaining_species:
            species.species = {}
            return {}  # was []

        # Find minimum/maximum fitness across the entire population, for use in
        # species adjusted fitness computation.
        min_fitness = min(all_fitnesses)
        max_fitness = max(all_fitnesses)
        # Do not allow the fitness range to be zero, as we divide by it below.
        # TODO: The ``1.0`` below is rather arbitrary, and should be configurable.
        fitness_range = max(1.0, max_fitness - min_fitness)
        for afs in remaining_species:
            # Compute adjusted fitness.
            msf = mean([m.fitness for m in itervalues(afs.members)])
            af = (msf - min_fitness) / fitness_range
            afs.adjusted_fitness = af

        adjusted_fitnesses = [s.adjusted_fitness for s in remaining_species]
        avg_adjusted_fitness = mean(adjusted_fitnesses)  # type: float
        self.reporters.info(
            "Average adjusted fitness: {:.3f}".format(avg_adjusted_fitness))

        # Compute the number of new members for each species in the new generation.
        previous_sizes = [len(s.members) for s in remaining_species]
        min_species_size = self.reproduction_config.min_species_size
        # Isn't the effective min_species_size going to be max(min_species_size,
        # self.reproduction_config.elitism)? That would probably produce more accurate tracking
        # of population sizes and relative fitnesses... doing. TODO: document.
        min_species_size = max(min_species_size,
                               self.reproduction_config.elitism)
        spawn_amounts = self.compute_spawn(adjusted_fitnesses, previous_sizes,
                                           pop_size, min_species_size)

        new_population = {}
        species.species = {}
        for spawn, s in zip(spawn_amounts, remaining_species):
            # If elitism is enabled, each species always at least gets to retain its elites.
            spawn = max(spawn, self.reproduction_config.elitism)

            assert spawn > 0

            # The species has at least one member for the next generation, so retain it.
            old_members = list(iteritems(s.members))
            s.members = {}
            species.species[s.key] = s

            # Sort members in order of descending fitness.
            old_members.sort(reverse=True, key=lambda x: x[1].fitness)

            # Transfer elites to new generation.
            if self.reproduction_config.elitism > 0:
                for i, m in old_members[:self.reproduction_config.elitism]:
                    new_population[i] = m
                    spawn -= 1

            if spawn <= 0:
                continue

            # Only use the survival threshold fraction to use as parents for the next generation.
            repro_cutoff = int(
                math.ceil(self.reproduction_config.survival_threshold *
                          len(old_members)))
            # Use at least two parents no matter what the threshold fraction result is.
            repro_cutoff = max(repro_cutoff, 2)
            old_members = old_members[:repro_cutoff]

            # Randomly choose parents and produce the number of offspring allotted to the species.
            while spawn > 0:
                spawn -= 1

                parent1_id, parent1 = random.choice(old_members)
                parent2_id, parent2 = random.choice(old_members)

                # Note that if the parents are not distinct, crossover will produce a
                # genetically identical clone of the parent (but with a different ID).
                # gid = next(self.genome_indexer)
                # child = config.genome_type(gid)
                # child.configure_crossover(parent1, parent2, config.genome_config)
                # child.mutate(config.genome_config)
                # new_population[gid] = child
                # self.ancestors[gid] = (parent1_id, parent2_id)

                if parent1.fitness > parent2.fitness:
                    parent1.mutate(config.genome_config)
                    new_population[parent1_id] = parent1
                    self.ancestors[parent1_id] = (parent1_id, parent1_id)
                else:
                    parent2.mutate(config.genome_config)
                    new_population[parent2_id] = parent2
                    self.ancestors[parent2_id] = (parent2_id, parent2_id)
                '''
                Check cppnon sets of both parents
                If they're the same, perfrom crossover of non-cppnon-nodes and connections
                Else,
                Find parent with highest fitness
                Transfer those nodes to child
                perfrom crossover of non-cppnon-nodes and connections
                '''

        return new_population
示例#5
0
def run():
    # load the config file
    local_dir = os.path.dirname(__file__)
    config_path = os.path.join(local_dir, my_config)
    config = neat.Config(AgentGenome, neat.DefaultReproduction,
                         neat.DefaultSpeciesSet, neat.DefaultStagnation,
                         config_path)
    # uses the extended NEAT population PopulationSyn that synchronizes with singularity
    pop = PopulationSyn(config)
    # add reporters
    stats = neat.StatisticsReporter()
    pop.add_reporter(stats)
    pop.add_reporter(neat.StdOutReporter(True))
    # save a checkpoint every 100 generations or 900 seconds.
    rep = neat.Checkpointer(100, 900)
    pop.add_reporter(rep)
    # class for evaluating the population
    ec = GenomeEvaluator(ts_f, vs_f)
    # initializes genomes fitness and gen_best just for the first time
    for g in itervalues(pop.population):
        g.fitness = -10000000.0
        ec.genomes_h.append(g)
    gen_best = g
    # initializations
    avg_score_v = -10000000.0
    avg_score_v_ant = avg_score_v
    avg_score = avg_score_v
    iteration_counter = 0
    best_fitness = -2000.0
    pop_size = len(pop.population)
    # sets the nuber of continuous iterations
    num_iterations = round(200 / len(pop.population)) + 1
    # repeat NEAT iterations until solved or keyboard interrupt
    while 1:
        try:
            # if it is not the  first iteration calculate training and validation scores
            if iteration_counter > 0:
                avg_score = ec.training_validation_score(gen_best, config)
            # if it is not the first iteration
            if iteration_counter >= 0:
                # synchronizes with singularity migrating maximum 3 specimens
                # pop.syn_singularity(4, my_url, stats,avg_score,rep.current_generation, config, ec.genomes_h)
                pop.species.speciate(config, pop.population, pop.generation)
                print("\nSpeciation after migration done")
                # perform pending evaluations on the singularity network, max 2
                pop.evaluate_pending(2)
                #increment iteration counter
                iteration_counter = iteration_counter + 1
            # execute num_iterations consecutive iterations of the NEAT algorithm
            gen_best = pop.run(ec.evaluate_genomes, 2)
            # verify the training score is enough to stop the NEAT algorithm: TODO change to validation score when generalization is ok
            if avg_score < 2000000000:
                solved = False
            if solved:
                print("Solved.")
                # save the winners.
                for n, g in enumerate(best_genomes):
                    name = 'winner-{0}'.format(n)
                    with open(name + '.pickle', 'wb') as f:
                        pickle.dump(g, f)
                break
        except KeyboardInterrupt:
            print("User break.")
            break
    env.close()
def run():
    # Load the config file, which is assumed to live in
    # the same directory as this script.
    local_dir = os.path.dirname(__file__)
    config_path = os.path.join(local_dir, my_config)
    config = neat.Config(LanderGenome, neat.DefaultReproduction,
                         neat.DefaultSpeciesSet, neat.DefaultStagnation,
                         config_path)

    pop = neat.Population(config)
    stats = neat.StatisticsReporter()
    pop.add_reporter(stats)
    pop2 = neat.Population(config)
    stats2 = neat.StatisticsReporter()
    pop.add_reporter(stats)
    pop2.add_reporter(stats2)
    pop.add_reporter(neat.StdOutReporter(True))
    # Checkpoint every 25 generations or 900 seconds.
    rep = neat.Checkpointer(25, 900)
    pop.add_reporter(rep)
    # Training set index
    avg_score_v = -10000000.0
    avg_score_v_ant = avg_score_v
    avg_score = avg_score_v

    # asigna un gen_best para poder cargar los demás desde syn
    for g in itervalues(pop.population):
        gen_best = g
        g.fitness = -10000000.0

    # Run until the winner from a generation is able to solve the environment
    # or the user interrupts the process.
    ec = PooledErrorCompute()
    temp = 0
    best_fitness = -2000.0

    pop_size = len(pop.population)
    # sets the nuber of continuous iterations
    num_iterations = round(200 / len(pop.population)) + 1
    while 1:
        try:
            if temp > 0:
                # Calcula training y validation fitness
                best_genomes = stats.best_unique_genomes(3)
                solved = True
                best_scores = []
                observation = env_t.reset()
                score = 0.0
                step = 0
                gen_best_nn = neat.nn.FeedForwardNetwork.create(
                    gen_best, config)

                while 1:
                    step += 1
                    output = gen_best_nn.activate(nn_format(observation))
                    action = (np.argmax(output[0:2]), output[3], output[4],
                              output[5])  # buy,sell or
                    observation, reward, done, info = env_t.step(action)
                    score += reward

                    env_t.render()
                    if done:
                        break
                ec.episode_score.append(score)
                ec.episode_length.append(step)
                best_scores.append(score)
                avg_score = sum(best_scores) / len(best_scores)
                print("Training Set Score =", score, " avg_score=", avg_score)

                # Calculate the real-validation set score
                best_genomes = stats.best_unique_genomes(3)
                solved = True
                best_scores = []
                observation = env_v.reset()
                score = 0.0
                step = 0
                gen_best_nn = neat.nn.FeedForwardNetwork.create(
                    gen_best, config)
                while 1:
                    step += 1
                    output = gen_best_nn.activate(nn_format(observation))
                    action = (np.argmax(output[0:2]), output[3], output[4],
                              output[5])  # buy,sell or
                    observation, reward, done, info = env_v.step(action)
                    score += reward
                    #env_v.render()
                    if done:
                        break
                best_scores.append(score)
                avg_score_v = sum(best_scores) / len(best_scores)
                print("Validation Set Score = ", avg_score_v)
                print(
                    "*********************************************************"
                )
                # Calcula el best_fitness (PARA SYNC)como el promedio del score de training y el promedio del fitness de los reps.
                reps_local = []
                reps = [gen_best]
                accum = 0.0
                countr = 0
                for sid, s in iteritems(pop.species.species):
                    if pop.population[
                            s.representative.key].fitness is not None:
                        accum = accum + pop.population[
                            s.representative.key].fitness
                        countr = countr + 1
                if countr > 0:
                    best_fitness = (3 * avg_score + (accum / countr)) / 4
                else:
                    best_fitness = (avg_score)
                #FIN de calculo de real validation

            if temp >= 0:
                # TODO: FUNCION DE SINCRONIZACION CON SINGULARITY
                # Lee en pop2 el último checkpoint desde syn
                # Hace request de getLastParam(process_hash,use_current) a syn TODO: HACER PROCESS CONFIGURABLE Y POR HASH no por id
                res = requests.get(
                    my_url +
                    "/processes/1?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph"
                )
                cont = res.json()
                print('\ncurrent_block_performance =',
                      cont['result'][0]['current_block_performance'])
                print('\nlast_optimum_id =',
                      cont['result'][0]['last_optimum_id'])
                last_optimum_id = cont['result'][0]['last_optimum_id']

                # Si el perf reportado pop2_champion_fitness > pop1_champion_fitness de validation training
                print("\nPerformance = ", best_fitness)
                print(
                    "*********************************************************"
                )
                if cont['result'][0][
                        'current_block_performance'] > best_fitness:
                    # hace request GetParameter(id)
                    res_p = requests.get(
                        my_url + "/parameters/" + str(last_optimum_id) +
                        "?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph"
                    )
                    cont_param = res_p.json()
                    # descarga el checkpoint del link de la respuesta si cont.parameter_link
                    print('Parameter Downloaded')
                    print('\nmigrations =')
                    if cont_param['result'][0]['parameter_link'] is not None:
                        genom_data = requests.get(
                            cont_param['result'][0]['parameter_link']).content
                        with open('remote_reps', 'wb') as handler:
                            handler.write(genom_data)
                            handler.close()
                        # carga genom descargado en nueva población pop2
                        with open('remote_reps', 'rb') as f:
                            remote_reps = pickle.load(f)
                        # OP.MIGRATION: Reemplaza el peor de la especie pop1 más cercana por el nuevo chmpion de pop2 como http://neo.lcc.uma.es/Articles/WRH98.pdf
                        # para cada elemento de remote_reps, busca el closer, si remote fitness > local, lo reemplaza
                        for i in range(len(remote_reps)):
                            closer = None
                            min_dist = None
                            # initialize for less fit search
                            less_fit = None
                            less_fitness = 10000
                            for g in itervalues(pop.population):
                                if g not in remote_reps:
                                    dist = g.distance(remote_reps[i],
                                                      config.genome_config)
                                    if dist is None:
                                        dist = 100000000
                                else:
                                    dist = 100000000
                                # do not count already migrated remote_reps
                                if closer is None or min_dist is None:
                                    closer = deepcopy(g)
                                    min_dist = dist
                                if dist < min_dist:
                                    closer = deepcopy(g)
                                    min_dist = dist
                                if g.fitness is None:
                                    g.fitness = -10
                                if g.fitness < less_fitness:
                                    less_fitness = g.fitness
                                    less_fit = deepcopy(g)
                            # For the best genom in position 0
                            if i == 0:
                                tmp_genom = deepcopy(remote_reps[i])
                                # Hack: overwrites original genome key with the replacing one
                                tmp_genom.key = closer.key
                                pop.population[closer.key] = deepcopy(
                                    tmp_genom)
                                print(" gen_best=", closer.key)
                                pop.best_genome = deepcopy(tmp_genom)
                                gen_best = deepcopy(tmp_genom)
                            else:
                                # si el remote fitness>local, reemplazar el remote de pop2 en pop1
                                if closer is None:
                                    # busca el pop con el menor fitness
                                    closer = less_fit
                                if closer is not None:
                                    if closer not in remote_reps:
                                        if closer.fitness is None:
                                            closer.fitness = less_fitness
                                        if closer.fitness is not None and remote_reps[
                                                i].fitness is not None:
                                            if remote_reps[
                                                    i].fitness > closer.fitness:
                                                tmp_genom = deepcopy(
                                                    remote_reps[i])
                                                # Hack: overwrites original genome key with the replacing one
                                                tmp_genom.key = closer.key
                                                pop.population[
                                                    closer.key] = deepcopy(
                                                        tmp_genom)
                                                print("Replaced=", closer.key)
                                                # actualiza gen_best y best_genome al remoto
                                                pop.best_genome = deepcopy(
                                                    tmp_genom)
                                                gen_best = deepcopy(tmp_genom)
                                        if closer.fitness is None:
                                            tmp_genom = deepcopy(
                                                remote_reps[i])
                                            # Hack: overwrites original genome key with the replacing one
                                            tmp_genom.key = len(
                                                pop.population) + 1
                                            pop.population[
                                                tmp_genom.key] = tmp_genom
                                            print(
                                                "Created Por closer.fitness=NONE : ",
                                                tmp_genom.key)
                                            # actualiza gen_best y best_genome al remoto
                                            pop.best_genome = deepcopy(
                                                tmp_genom)
                                            gen_best = deepcopy(tmp_genom)
                                    else:
                                        #si closer está en remote_reps es porque no hay ningun otro cercano así que lo adiciona
                                        tmp_genom = deepcopy(remote_reps[i])
                                        # Hack: overwrites original genome key with the replacing one
                                        tmp_genom.key = len(pop.population) + 1
                                        pop.population[
                                            tmp_genom.key] = tmp_genom
                                        print(
                                            "Created por Closer in rempte_reps=",
                                            tmp_genom.key)
                                        # actualiza gen_best y best_genome al remoto
                                        pop.best_genome = deepcopy(tmp_genom)
                                        gen_best = deepcopy(tmp_genom)

                        #ejecuta speciate
                        pop.species.speciate(config, pop.population,
                                             pop.generation)
                        print("\nSpeciation after migration done")
                # Si el perf reportado es menor pero no igual al de pop1
                if cont['result'][0][
                        'current_block_performance'] < best_fitness:
                    # Obtiene remote_reps
                    # hace request GetParameter(id)
                    remote_reps = None
                    res_p = requests.get(
                        my_url + "/parameters/" + str(last_optimum_id) +
                        "?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph"
                    )
                    cont_param = res_p.json()
                    # descarga el checkpoint del link de la respuesta si cont.parameter_link
                    print('\nNEW OPTIMUM - cont_param =', cont_param)
                    #print('\nmigrations =')
                    if cont_param['result'][0]['parameter_link'] is not None:
                        genom_data = requests.get(
                            cont_param['result'][0]['parameter_link']).content
                        with open('remote_reps', 'wb') as handler:
                            handler.write(genom_data)
                            handler.close()
                        # carga genom descargado en nueva población pop2
                        with open('remote_reps', 'rb') as f:
                            remote_reps = pickle.load(f)
                #Guarda los mejores reps
                    reps_local = []
                    reps = [gen_best]
                    # Para cada especie, adiciona su representative a reps
                    for sid, s in iteritems(pop.species.species):
                        #print("\ns=",s)
                        if s.representative not in reps_local:
                            reps_local.append(
                                pop.population[s.representative.key])
                            reps_local[len(reps_local) - 1] = deepcopy(
                                pop.population[s.representative.key])
                    # TODO: Conservar los mejores reps, solo reemplazarlos por los mas cercanos
                    if remote_reps is None:
                        for l in reps_local:
                            reps.append(l)
                            reps[len(reps) - 1] = deepcopy(l)
                    else:
                        # para cada reps_local l
                        for l in reps_local:
                            # busca el closer a l en reps_remote
                            for i in range(len(remote_reps)):
                                closer = None
                                min_dist = None
                                for g in reps_local:
                                    if g not in remote_reps:
                                        dist = g.distance(
                                            remote_reps[i],
                                            config.genome_config)
                                    else:
                                        dist = 100000000
                                    # do not count already migrated remote_reps
                                    if closer is None or min_dist is None:
                                        closer = deepcopy(g)
                                        min_dist = dist
                                    if dist < min_dist:
                                        closer = deepcopy(g)
                                        min_dist = dist
                #           si closer is in reps
                            if closer in reps:
                                #               adiciona l a reps si ya no estaba en reps
                                if l not in reps:
                                    reps.append(l)
                                    reps[len(reps) - 1] = deepcopy(l)
                #           sino
                            else:
                                #               si l tiene más fitness que closer,
                                if closer.fitness is not None and l.fitness is not None:
                                    if l.fitness > pop.population[
                                            closer.key].fitness:
                                        #                       adiciona l a reps si ya no estaba en reps
                                        if l not in reps:
                                            reps.append(l)
                                            reps[len(reps) - 1] = deepcopy(l)
                #               sino
                                    else:
                                        #                      adiciona closer a reps si ya no estaba en reps
                                        if l not in reps:
                                            reps.append(
                                                pop.population[closer.key])
                                            reps[len(reps) - 1] = deepcopy(
                                                pop.population[closer.key])
                                            # Guarda checkpoint de los representatives de cada especie y lo copia a ubicación para servir vía syn.
                                            # rep.save_checkpoint(config,pop,neat.DefaultSpeciesSet,rep.current_generation)
                    print("\nreps=", reps)
                    filename = '{0}{1}'.format("reps-", rep.current_generation)
                    with open(filename, 'wb') as f:
                        pickle.dump(reps, f)
                    #
                    # Hace request de CreateParam a syn
                    form_data = {
                        "process_hash":
                        "ph",
                        "app_hash":
                        "ah",
                        "parameter_link":
                        my_url + "/genoms/" + filename,
                        "parameter_text":
                        pop.best_genome.key,
                        "parameter_blob":
                        "",
                        "validation_hash":
                        "",
                        "hash":
                        "h",
                        "performance":
                        best_fitness,
                        "redir":
                        "1",
                        "username":
                        "******",
                        "pass_hash":
                        "$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q"
                    }
                    # TODO: COLOCAR DIRECCION CONFIGURABLE
                    res = requests.post(
                        my_url +
                        "/parameters?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph",
                        data=form_data)
                    res_json = res.json()
                # TODO FIN: FUNCION DE SINCRONIZACION CON SINGULARITY
            temp = temp + 1

            # EVALUATE THE GENOMES WITH THE SUBSET TRAINING DATASET
            gen_best = pop.run(ec.evaluate_genomes, num_iterations)
            # TODO:
            # VERIFY IF THERE ARE PENDING EVALUATIONS
            # EVALUATE NUM_EVALUATIONS PENDING EVALUATIONS

            #print(gen_best)
            #visualize.plot_stats(stats, ylog=False, view=False, filename="fitness.svg")
            #plt.plot(ec.episode_score, 'g-', label='score')
            #plt.plot(ec.episode_length, 'b-', label='length')
            #plt.grid()
            #plt.legend(loc='best')
            #plt.savefig("scores.svg")
            #plt.close()

            #mfs = sum(stats.get_fitness_mean()[-5:]) / 5.0
            #print("Average mean fitness over last 5 generations: {0}".format(mfs))

            #mfs = sum(stats.get_fitness_stat(min)[-5:]) / 5.0
            #print("Average min fitness over last 3 generations: {0}".format(mfs))
            if avg_score < 2000000000:
                solved = False

            if solved:
                print("Solved.")

                # Save the winners.
                for n, g in enumerate(best_genomes):
                    name = 'winner-{0}'.format(n)
                    with open(name + '.pickle', 'wb') as f:
                        pickle.dump(g, f)

                    visualize.draw_net(config,
                                       g,
                                       view=False,
                                       filename=name + "-net.gv")
                    visualize.draw_net(config,
                                       g,
                                       view=False,
                                       filename=name + "-net-enabled.gv",
                                       show_disabled=False)
                    visualize.draw_net(config,
                                       g,
                                       view=False,
                                       filename=name +
                                       "-net-enabled-pruned.gv",
                                       show_disabled=False,
                                       prune_unused=True)

                break
        except KeyboardInterrupt:
            print("User break.")
            break

    env.close()
def create(genome, config, map_size):
    """ Receives a genome and returns its phenotype (a SwitchNeuronNetwork). """
    genome_config = config.genome_config
    #required = required_for_output(genome_config.input_keys, genome_config.output_keys, genome.connections)

    input_keys = copy.deepcopy(genome_config.input_keys)
    output_keys = copy.deepcopy(genome_config.output_keys)
    # Gather inputs and expressed connections.
    std_inputs = {}
    mod_inputs = {}
    children = {}
    node_keys = set(genome.nodes.keys())  # + list(genome_config.input_keys[:])
    aux_keys = set()

    # Here we populate the children dictionary for each unique not isolated node.
    for n in genome.nodes.keys():

        children[n] = []
        if n in output_keys:
            continue
        #For this implementation everything besides the reward and the output is a map
        #if not genome.nodes[n].is_isolated:
        for _ in range(1, map_size):
            new_idx = max(node_keys) + 1
            children[n].append(new_idx)
            node_keys.add(new_idx)

    #assume 2 input nodes: the first one will be scaled to a map and the second one will represent the reward
    n = input_keys[0]
    children[n] = []
    for _ in range(1, map_size):
        new_idx = min(input_keys) - 1
        children[n].append(new_idx)
        input_keys.append(new_idx)
    n = input_keys[1]
    children[n] = []

    # We don't scale the output with the map size to keep passing the parameters of the network easy.
    # This part can be revised in the future
    for n in output_keys:
        children[n] = []
    #Iterate over every connection
    for cg in itervalues(genome.connections):
        #If it's not enabled don't include it
        # if not cg.enabled:
        #     continue

        i, o = cg.key
        #If neither node is required for output then skip the connection
        # if o not in required and i not in required:
        #     continue

        #Find the map corresponding to each node of the connection
        in_map = [i] + children[i]
        out_map = [o] + children[o]
        #If the connection is modulatory and the output neuron a switch neuron then the new weights are stored
        #in the mod dictionary. We assume that only switch neurons have a modulatory part.
        if cg.is_mod and genome.nodes[o].is_switch:
            node_inputs = mod_inputs
        else:
            node_inputs = std_inputs
        for n in out_map:
            if n not in node_inputs.keys():
                node_inputs[n] = []

        if len(in_map) == map_size and len(out_map) == map_size:
            # Map to map connectivity
            if cg.one2one:
                if cg.extended:
                    #extended one-to-
                    #create a new intermediatery map
                    for j in range(0, map_size):
                        idx = max(node_keys.union(aux_keys)) + 1
                        children[idx] = []
                        aux_keys.add(idx)
                        for _ in range(1, map_size):
                            new_idx = max(node_keys.union(aux_keys)) + 1
                            children[idx].append(new_idx)
                            aux_keys.add(new_idx)
                        aux_map = [idx] + children[idx]
                        for node in aux_map:
                            node_inputs[node] = []
                        #add one to one connections between in_map and aux map with weight 1
                        for i in range(map_size):
                            node_inputs[aux_map[i]].append((in_map[j], 1))

                        #add one to one connections between aux map and out map with stepped weights
                        weights = calculate_weights(False, cg.weight, map_size)
                        for i in range(map_size):
                            node_inputs[out_map[j]].append(
                                (aux_map[i], weights[i]))
                else:
                    weight = cg.weight
                    for i in range(map_size):
                        node_inputs[out_map[i]].append((in_map[i], weight))

            else:
                # 1-to-all
                if not cg.uniform:
                    # Step
                    start = -cg.weight
                    end = cg.weight
                    step = (end - start) / (map_size - 1)
                    for o_n in out_map:
                        s = start
                        for i_n in in_map:
                            node_inputs[o_n].append((i_n, s))
                            s += step
                else:
                    # Uniform
                    for o_n in out_map:
                        for i_n in in_map:
                            node_inputs[o_n].append((i_n, cg.weight))

        else:
            # Map-to-isolated or isolated-to-isolated
            if not cg.uniform:
                # Step
                start = -cg.weight
                end = cg.weight
                step = (end - start) / (map_size - 1)
                for o_n in out_map:
                    s = start
                    for i_n in in_map:
                        node_inputs[o_n].append((i_n, s))
                        s += step
            else:
                # Uniform
                for o_n in out_map:
                    for i_n in in_map:
                        node_inputs[o_n].append((i_n, cg.weight))

    nodes = []

    #Sometimes the output neurons end up not having any connections during the evolutionary process. While we do not
    #desire such networks, we should still allow them to make predictions to avoid fatal errors.
    for okey in output_keys:
        if okey not in node_keys:
            node_keys.add(okey)
            std_inputs[okey] = []

    # While we cannot deduce the order of activations of the neurons due to the fact that we allow for arbitrary connection
    # schemes, we certainly want the output neurons to activate last.
    conns = {}
    for k in node_keys.union(aux_keys):
        conns[k] = []
    parents = children.keys()
    for k in conns.keys():
        if k in input_keys:
            continue
        if k not in conns.keys():
            conns[k] = []
        if k in std_inputs.keys():
            conns[k].extend([i for i, _ in std_inputs[k]])
        if k in mod_inputs.keys():
            conns[k].extend([i for i, _ in mod_inputs[k]])
    sorted_keys = order_of_activation(conns, input_keys, output_keys)

    #Edge case: when a genome has no connections, sorted keys ends up empty and crashes the program
    #If this happens, just activate the output nodes with the default activation: 0
    if not sorted_keys:
        sorted_keys = output_keys

    for node_key in sorted_keys:
        #all the children are handled with the parent
        if node_key not in parents:
            continue
        #if the node we are examining is not in our keys set then skip it. It means that it is not required for output.
        # if node_key not in node_keys:
        #     continue

        #if the node one of the originals present in the genotype, i.e. it's not one of the nodes we added for the
        #extended one to one scheme
        if node_key in genome.nodes:
            node = genome.nodes[node_key]
            node_map = [node_key] + children[node_key]
            if node.is_switch:
                # If the switch neuron does not have any incoming cnnections
                if node_key not in std_inputs.keys(
                ) and node_key not in mod_inputs.keys():
                    for n in node_map:
                        std_inputs[n] = []
                        mod_inputs[n] = []
                # if the switch neuron only has modulatory weights then we copy those weights for the standard part as well.
                # this is not the desired behaviour but it is done to avoid errors during forward pass.
                if node_key not in std_inputs.keys(
                ) and node_key in mod_inputs.keys():
                    for n in node_map:
                        std_inputs[n] = mod_inputs[n]
                if node_key not in mod_inputs.keys():
                    for n in node_map:
                        mod_inputs[n] = []
                #For the guided maps, all modulatory weights to switch neurons now weight 1/m
                if mod_inputs[node_key]:
                    for n in node_map:
                        new_w = 1 / len(std_inputs[n])
                        new_mod_w = [(inp, new_w) for inp, w in mod_inputs[n]]
                        mod_inputs[n] = new_mod_w
                for n in node_map:
                    nodes.append(SwitchNeuron(n, std_inputs[n], mod_inputs[n]))
                continue
            ###################### Switch neuron part ends here
            for n in node_map:
                if n not in std_inputs:
                    std_inputs[n] = []
                #For these guided maps, every hidden neuron that is not a switch neuron is a gating neuron
                if node_key in output_keys:
                    # Create the standard part dictionary for the neuron
                    #We also pre-determine the output neuron to help NEAT even more
                    params = {
                        'activation_function': identity,
                        'integration_function': sum,
                        'bias': node.bias,
                        'activity': 0,
                        'output': 0,
                        'weights': std_inputs[n]
                    }
                #Everything else is a gating neuron
                else:
                    params = {
                        'activation_function': identity,
                        'integration_function': prod,
                        'bias': node.bias,
                        'activity': 0,
                        'output': 0,
                        'weights': std_inputs[n]
                    }
                nodes.append(Neuron(n, params))

        #if the node is one of those we added with the extended one to one scheme
        else:
            node_map = [node_key] + children[node_key]
            for n in node_map:
                if n not in std_inputs:
                    std_inputs[n] = []

            # Create the standard part dictionary for the neuron
            for n in node_map:
                params = {
                    'activation_function': identity,
                    'integration_function': sum,
                    'bias': 0,
                    'activity': 0,
                    'output': 0,
                    'weights': std_inputs[n]
                }
                nodes.append(Neuron(n, params))

    return SwitchNeuronNetwork(input_keys, output_keys, nodes)
示例#8
0
    def reproduce(self, config, species, pop_size, generation):
        # TODO: I don't like this modification of the species and stagnation objects,
        # because it requires internal knowledge of the objects.

        # Find minimum/maximum fitness across the entire population, for use in
        # species adjusted fitness computation.
        all_fitnesses = []
        for sid, s in iteritems(species.species):
            all_fitnesses.extend(m.fitness for m in itervalues(s.members))
        min_fitness = min(all_fitnesses)
        max_fitness = max(all_fitnesses)
        # Do not allow the fitness range to be zero, as we divide by it below.
        fitness_range = max(1.0, max_fitness - min_fitness)

        # Filter out stagnated species, collect the set of non-stagnated
        # species members, and compute their average adjusted fitness.
        # The average adjusted fitness scheme (normalized to the interval
        # [0, 1]) allows the use of negative fitness values without
        # interfering with the shared fitness scheme.
        num_remaining = 0
        species_fitness = []
        avg_adjusted_fitness = 0.0
        for sid, s, stagnant in self.stagnation.update(species, generation):
            if stagnant:
                self.reporters.species_stagnant(sid, s)
            else:
                num_remaining += 1

                # Compute adjusted fitness.
                msf = mean([m.fitness for m in itervalues(s.members)])
                s.adjusted_fitness = (msf - min_fitness) / fitness_range
                species_fitness.append((sid, s, s.fitness))
                avg_adjusted_fitness += s.adjusted_fitness

        # No species left.
        if 0 == num_remaining:
            species.species = {}
            return []

        avg_adjusted_fitness /= len(species_fitness)
        self.reporters.info(
            "Average adjusted fitness: {:.3f}".format(avg_adjusted_fitness))

        # Compute the number of new individuals to create for the new generation.
        spawn_amounts = []
        for sid, s, sfitness in species_fitness:
            spawn = len(s.members)
            if sfitness > avg_adjusted_fitness:
                spawn = max(spawn + 2, spawn * 1.1)
            else:
                spawn = max(spawn * 0.9, 2)
            spawn_amounts.append(spawn)

        # Normalize the spawn amounts so that the next generation is roughly
        # the population size requested by the user.
        total_spawn = sum(spawn_amounts)
        norm = pop_size / total_spawn
        spawn_amounts = [int(round(n * norm)) for n in spawn_amounts]

        new_population = {}
        species.species = {}
        for spawn, (sid, s, sfitness) in zip(spawn_amounts, species_fitness):
            # If elitism is enabled, each species always at least gets to retain its elites.
            spawn = max(spawn, self.elitism)

            if spawn <= 0:
                continue

            # The species has at least one member for the next generation, so retain it.
            old_members = list(iteritems(s.members))
            s.members = {}
            species.species[sid] = s

            # Sort members in order of descending fitness.
            old_members.sort(reverse=True, key=lambda x: x[1].fitness)

            # Transfer elites to new generation.
            if self.elitism > 0:
                for i, m in old_members[:self.elitism]:
                    new_population[i] = m
                    spawn -= 1

            if spawn <= 0:
                continue

            # Only use the survival threshold fraction to use as parents for the next generation.
            repro_cutoff = int(
                math.ceil(self.survival_threshold * len(old_members)))
            # Use at least two parents no matter what the threshold fraction result is.
            repro_cutoff = max(repro_cutoff, 2)
            old_members = old_members[:repro_cutoff]

            # Randomly choose parents and produce the number of offspring allotted to the species.
            while spawn > 0:
                spawn -= 1

                parent1_id, parent1 = random.choice(old_members)
                parent2_id, parent2 = random.choice(old_members)

                # Note that if the parents are not distinct, crossover will produce a
                # genetically identical clone of the parent (but with a different ID).
                gid = self.genome_indexer.get_next()
                child = config.genome_type(gid)
                child.configure_crossover(parent1, parent2,
                                          config.genome_config)
                child.mutate(config.genome_config)
                new_population[gid] = child
                self.ancestors[gid] = (parent1_id, parent2_id)

        return new_population
示例#9
0
def run():
    # Load the config file, which is assumed to live in
    # the same directory as this script.
    local_dir = os.path.dirname(__file__)
    config_path = os.path.join(local_dir, 'config')
    config = neat.Config(LanderGenome, neat.DefaultReproduction,
                         neat.DefaultSpeciesSet, neat.DefaultStagnation,
                         config_path)

    pop = neat.Population(config)
    stats = neat.StatisticsReporter()
    pop.add_reporter(stats)
    pop2 = neat.Population(config)
    stats2 = neat.StatisticsReporter()
    pop.add_reporter(stats)
    pop2.add_reporter(stats2)
    pop.add_reporter(neat.StdOutReporter(True))
    # Checkpoint every 25 generations or 900 seconds.
    rep = neat.Checkpointer(25, 900)
    pop.add_reporter(rep)

    # Run until the winner from a generation is able to solve the environment
    # or the user interrupts the process.
    ec = PooledErrorCompute()
    temp = 0
    while 1:
        try:
            if temp > 0:
                # TODO: FUNCION DE SINCRONIZACION CON SINGULARITY
                # Lee en pop2 el último checkpoint desde syn
                # Hace request de getLastParam(process_hash,use_current) a syn TODO: HACER PROCESS CONFIGURABLE Y POR HASH no por id
                res = requests.get(
                    my_url +
                    "/processes/1?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph"
                )
                cont = res.json()
                print('\ncurrent_block_performance =',
                      cont['result'][0]['current_block_performance'])
                print('\nlast_optimum_id =',
                      cont['result'][0]['last_optimum_id'])
                last_optimum_id = cont['result'][0]['last_optimum_id']
                # Si el perf reportado pop2_champion_fitness > pop1_champion_fitness
                best_fitness = gen_best.fitness
                print('\nbest_fitness =', best_fitness)
                if cont['result'][0][
                        'current_block_performance'] > best_fitness:
                    # hace request GetParameter(id)
                    res_p = requests.get(
                        my_url + "/parameters/" + str(last_optimum_id) +
                        "?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph"
                    )
                    cont_param = res_p.json()
                    # descarga el checkpoint del link de la respuesta si cont.parameter_link
                    print('\ncont_param =', cont_param)
                    if cont_param['result'][0]['parameter_link'] is not None:
                        genom_data = requests.get(
                            cont_param['result'][0]['parameter_link']).content
                        with open('remote_genom', 'wb') as handler:
                            handler.write(genom_data)
                            handler.close()
                        # carga genom descargado en nueva población pop2
                        with open('remote_genom', 'rb') as f:
                            remote_genom = pickle.load(f)
                        # OP.MIGRATION: Reemplaza el peor de la especie pop1 más cercana por el nuevo chmpion de pop2 como http://neo.lcc.uma.es/Articles/WRH98.pdf
                        closer = None
                        min_dist = None
                        #for g in itervalues(pop.population):
                        #   dist = g.fitness
                        #   if closer is None or min_dist is None or dist < min_dist:
                        #       closer = g
                        #       min_dist = dist
                        # se selecciona el que tenga menos distancia al pop2.champion en los representantes de  pop1
                        closer = None
                        min_dist = None
                        # descarga el checkpoint del link de la respuesta si cont.parameter_link
                        for g in itervalues(pop.population):
                            dist = g.distance(remote_genom,
                                              config.genome_config)
                            if closer is None or min_dist is None:
                                closer = deepcopy(g)
                                min_dist = dist
                            if dist < min_dist:
                                closer = deepcopy(g)
                                min_dist = dist

                        # reemplazar el champ de pop2 en pop1
                        tmp_genom = deepcopy(remote_genom)
                        # Hack: overwrites original genome key with the replacing one
                        tmp_genom.key = closer.key
                        pop.population[closer.key] = deepcopy(tmp_genom)
                        # actualiza gen_best y best_genome al remoto
                        pop.best_genome = deepcopy(tmp_genom)
                        gen_best = deepcopy(tmp_genom)
                        #ejecuta speciate
                        pop.species.speciate(config, pop.population,
                                             pop.generation)
                        print("\ndone")
                # Si el perf reportado es menor pero no igual al de pop1
                if cont['result'][0][
                        'current_block_performance'] < best_fitness:
                    # Guarda checkpoint del mejor genoma y lo copia a ubicación para servir vía syn.
                    # rep.save_checkpoint(config,pop,neat.DefaultSpeciesSet,rep.current_generation)
                    filename = '{0}{1}'.format("best-genome-",
                                               rep.current_generation)
                    with open(filename, 'wb') as f:
                        pickle.dump(gen_best, f)
                    # Hace request de CreateParam a syn
                    form_data = {
                        "process_hash":
                        "ph",
                        "app_hash":
                        "ah",
                        "parameter_link":
                        my_url + "/genoms/" + filename,
                        "parameter_text":
                        pop.best_genome.key,
                        "parameter_blob":
                        "",
                        "validation_hash":
                        "",
                        "hash":
                        "h",
                        "performance":
                        best_fitness,
                        "redir":
                        "1",
                        "username":
                        "******",
                        "pass_hash":
                        "$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q"
                    }
                    # TODO: COLOCAR DIRECCION CONFIGURABLE
                    res = requests.post(
                        my_url +
                        "/parameters?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph",
                        data=form_data)
                    res_json = res.json()
                # TODO FIN: FUNCION DE SINCRONIZACION CON SINGULARITY
            temp = temp + 1
            gen_best = pop.run(ec.evaluate_genomes, 5)

            #print(gen_best)
            visualize.plot_stats(stats,
                                 ylog=False,
                                 view=False,
                                 filename="fitness.svg")
            plt.plot(ec.episode_score, 'g-', label='score')
            plt.plot(ec.episode_length, 'b-', label='length')
            plt.grid()
            plt.legend(loc='best')
            plt.savefig("scores.svg")
            plt.close()

            mfs = sum(stats.get_fitness_mean()[-5:]) / 5.0
            print("Average mean fitness over last 5 generations: {0}".format(
                mfs))

            mfs = sum(stats.get_fitness_stat(min)[-5:]) / 5.0
            print(
                "Average min fitness over last 5 generations: {0}".format(mfs))

            # Use the best genomes seen so far as an ensemble-ish control system.
            best_genomes = stats.best_unique_genomes(3)
            best_networks = []
            for g in best_genomes:
                best_networks.append(
                    neat.nn.FeedForwardNetwork.create(g, config))
            solved = True
            best_scores = []
            for k in range(100):
                observation = env.reset()
                score = 0
                step = 0
                while 1:
                    step += 1
                    # Use the total reward estimates from all five networks to
                    # determine the best action given the current state.
                    votes = np.zeros((4, ))
                    for n in best_networks:
                        output = n.activate(nn_format(observation))
                        votes[np.argmax(output)] += 1
                    best_action = np.argmax(votes)
                    observation, reward, done, info = env.step(best_action)
                    score += reward
                    env.render()
                    if done:
                        break

                ec.episode_score.append(score)
                ec.episode_length.append(step)

                best_scores.append(score)
                avg_score = sum(best_scores) / len(best_scores)
                print(k, score, avg_score)
                if avg_score < 2000000000:
                    solved = False
                    break

            if solved:
                print("Solved.")

                # Save the winners.
                for n, g in enumerate(best_genomes):
                    name = 'winner-{0}'.format(n)
                    with open(name + '.pickle', 'wb') as f:
                        pickle.dump(g, f)

                    visualize.draw_net(config,
                                       g,
                                       view=False,
                                       filename=name + "-net.gv")
                    visualize.draw_net(config,
                                       g,
                                       view=False,
                                       filename=name + "-net-enabled.gv",
                                       show_disabled=False)
                    visualize.draw_net(config,
                                       g,
                                       view=False,
                                       filename=name +
                                       "-net-enabled-pruned.gv",
                                       show_disabled=False,
                                       prune_unused=True)

                break
        except KeyboardInterrupt:
            print("User break.")
            break

    env.close()
示例#10
0
    def run(self, fitness_function, n):
        """
        Runs NEAT's genetic algorithm for at most n generations.

        The user-provided fitness_function should take two arguments, a list of all genomes in the population,
        and its return value is ignored.  This function is free to maintain external state, perform evaluations
        in parallel, and probably any other thing you want.  Each individual genome's fitness member must be set
        to a floating point value after this function returns.

        It is assumed that fitness_function does not modify the list of genomes, the genomes themselves (apart
        from updating the fitness member), or the configuration object.
        """
        for g in range(n):
            self.generation += 1

            self.reporters.start_generation(self.generation)

            # Evaluate all individuals in the population using the user-provided function.
            # TODO: Add an option to only evaluate each genome once, to reduce number of
            # fitness evaluations in cases where the fitness is known to be the same if the
            # genome doesn't change--in these cases, evaluating unmodified elites in each
            # generation is a waste of time.  The user can always take care of this in their
            # fitness function in the time being if they wish.
            fitness_function(list(iteritems(self.population)), self.config)

            # Gather and report statistics.
            best = None
            for g in itervalues(self.population):
                if best is None or g.fitness > best.fitness:
                    best = g
            self.reporters.post_evaluate(self.config, self.population,
                                         self.species, best)

            # Track the best genome ever seen.
            if self.best_genome is None or best.fitness > self.best_genome.fitness:
                self.best_genome = best

            # End if the fitness threshold is reached.
            if best.fitness >= self.config.max_fitness_threshold:
                self.reporters.found_solution(self.config, self.generation,
                                              best)
                break

            # Create the next generation from the current generation.
            self.population = self.reproduction.reproduce(
                self.config, self.species, self.config.pop_size)

            # Check for complete extinction.
            if not self.species.species:
                self.reporters.complete_extinction()

                # If requested by the user, create a completely new population,
                # otherwise raise an exception.
                if self.config.reset_on_extinction:
                    self.population = self.reproduction.create_new(
                        self.config.pop_size)
                else:
                    raise CompleteExtinctionException()

            # Update species age.
            # TODO: Wouldn't it be easier to remember creation time?
            for s in itervalues(self.species.species):
                s.age += 1

            # Divide the new population into species.
            self.species.speciate(self.config, self.population)

            self.reporters.end_generation(self.config, self.population,
                                          self.species)

        return self.best_genome
示例#11
0
    def reproduce(self,
                  config: Config,
                  species: DefaultSpecies,
                  generation: int,
                  logger=None):
        """Handles creation of genomes, either from scratch or by sexual or asexual reproduction from parents."""
        # Check is one of the species has become stagnant (i.e. must be removed)
        remaining_fitness = []
        remaining_species = []
        for stag_sid, stag_s, stagnant in self.stagnation.update(
                config=config, species_set=species, gen=generation):
            # If specie is stagnant, then remove
            if stagnant:
                self.reporters.species_stagnant(stag_sid,
                                                stag_s,
                                                logger=logger)

            # Add the specie to remaining_species and save each of its members' fitness
            else:
                remaining_fitness.extend(m.fitness
                                         for m in itervalues(stag_s.members))
                remaining_species.append(stag_s)

        # If no species is left then force hard-reset
        if not remaining_species:
            species.species = dict()
            return dict()

        # Calculate the adjusted fitness, normalized by the minimum fitness across the entire population
        for specie in remaining_species:
            # Adjust a specie's fitness in a fitness sharing manner. A specie's fitness gets normalized by the number of
            #  members it has, this to ensure that a better performing specie does not takes over the population
            # A specie's fitness is determined by its most fit genome
            specie_fitness = max([m.fitness for m in specie.members.values()])
            specie_size = len(specie.members)
            specie.adjusted_fitness = specie_fitness / max(
                specie_size, config.population.min_specie_size)

        # Minimum specie-size is defined by the number of elites and the minimal number of genomes in a population
        spawn_amounts = self.compute_spawn(
            adjusted_fitness=[s.adjusted_fitness for s in remaining_species],
            previous_sizes=[len(s.members) for s in remaining_species],
            pop_size=config.population.pop_size,
            min_species_size=max(config.population.min_specie_size,
                                 config.population.genome_elitism))

        # Setup the next generation by filling in the new species with their elites and offspring
        new_population = dict()
        species.species = dict()
        for spawn_amount, specie in zip(spawn_amounts, remaining_species):
            # If elitism is enabled, each species will always at least gets to retain its elites
            spawn_amount = max(spawn_amount, config.population.genome_elitism)
            assert spawn_amount > 0

            # Get all the specie's old (evaluated) members
            old_members = list(iteritems(
                specie.members))  # Temporarily save members of last generation
            specie.members = dict()  # Reset members
            species.species[specie.key] = specie

            # Sort members in order of descending fitness (i.e. most fit members in front)
            old_members.sort(reverse=True, key=lambda x: x[1].fitness)

            # Make sure that all the specie's elites are added to the new generation
            if config.population.genome_elitism > 0:
                # Add the specie's elites to the global population
                for i, m in old_members[:config.population.genome_elitism]:
                    new_population[i] = m
                    spawn_amount -= 1

                # Add the specie's past elites as well if requested
                for i in range(
                        min(len(specie.elite_list),
                            config.population.genome_elite_stagnation - 1)):
                    gid, g = specie.elite_list[-(i + 1)]
                    if gid not in new_population:  # Only add genomes not yet present in the population
                        new_population[gid] = g
                        spawn_amount -= 1

                # Update the specie's elite_list
                specie.elite_list.append(old_members[0])

            # Check if the specie has the right to add more genomes to the population
            if spawn_amount <= 0: continue

            # Only use the survival threshold fraction to use as parents for the next generation, use at least all the
            #  elite of a population as parents
            reproduction_cutoff = max(
                round(config.population.parent_selection * len(old_members)),
                config.population.genome_elitism)

            # Since asexual reproduction, at least one parent must be chosen
            reproduction_cutoff = max(reproduction_cutoff, 1)
            parents = old_members[:reproduction_cutoff]

            # Add the elites again to the parent-set such that these have a greater likelihood of being chosen
            parents += old_members[:config.population.genome_elitism]

            # Fill the specie with offspring based, which is a mutation of the chosen parent
            while spawn_amount > 0:
                spawn_amount -= 1

                # Init genome dummy (values are overwritten later)
                gid = next(self.genome_indexer)
                child: Genome = Genome(gid,
                                       num_outputs=config.genome.num_outputs,
                                       bot_config=config.bot)

                # Choose the parents, note that if the parents are not distinct, crossover will produce a genetically
                #  identical clone of the parent (but with a different ID)
                p1_id, p1 = choice(parents)
                child.connections = copy.deepcopy(p1.connections)
                child.nodes = copy.deepcopy(p1.nodes)

                # Mutate the child
                child.mutate(config.genome)

                # Ensure that the child is connected
                while len(child.get_used_connections()) == 0:
                    child.mutate_add_connection(config.genome)

                # Add the child to the global population
                new_population[gid] = child

        return new_population
示例#12
0
def single_evaluation(multi_env, parallel: bool, pop: Population,
                      unused_cpu: int):
    """
    Perform a single evaluation-iteration.
    
    :param multi_env: Environment used to execute the game-simulation in
    :param parallel: Boolean indicating if training happens in parallel or not
    :param pop: Population used to evaluate on
    :param unused_cpu: Number of CPU-cores not used during evaluation
    """
    # 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:
        pbar = tqdm(total=len(genomes), desc="parallel training")

        # Initialize the evaluation-pool
        pool = mp.Pool(mp.cpu_count() - unused_cpu)
        manager = mp.Manager()
        return_dict = manager.dict()

        def cb(*_):
            """Update progressbar after finishing a single genome's evaluation."""
            pbar.update()

        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
    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
    try:
        fitness = calc_pop_fitness(
            fitness_config=pop.config.evaluation,
            game_observations=return_dict,
            game_params=multi_env.get_game_params(),
            generation=pop.generation,
        )
        for i, genome in genomes:
            genome.fitness = fitness[i]
    except Exception:  # TODO: Fix! Sometimes KeyError in fitness (path problem)
        pop.log(
            f"Exception at fitness calculation: \n{traceback.format_exc()}",
            print_result=False)
        warnings.warn(
            f"Exception at fitness calculation: \n{traceback.format_exc()}")
        # Set fitness to zero for genomes that have no fitness set yet
        for i, genome in genomes:
            if not genome.fitness: genome.fitness = 0.0

    # 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_genome_hist[
        pop.generation] = genomes[:pop.config.population.genome_elitism]
    if pop.best_genome is None or best.fitness > pop.best_genome.fitness:
        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)
示例#13
0
    def reproduce(self, config, species, pop_size, generation, exp, syllabus):
        all_fitnesses = []
        for sid, s in iteritems(species.species):
            all_fitnesses.extend(m.fitness for m in itervalues(s.members))
        min_fitness = min(all_fitnesses)
        max_fitness = max(all_fitnesses)
        fitness_range = max(1.0, max_fitness - min_fitness)
        num_remaining = 0
        species_fitness = []
        avg_adjusted_fitness = 0.0
        for sid, s, stagnant in self.stagnation.update(species, generation):
            if stagnant:
                self.reporters.species_stagnant(sid, s)
            else:
                num_remaining += 1
                msf = mean([m.fitness for m in itervalues(s.members)])
                s.adjusted_fitness = (msf - min_fitness) / fitness_range
                species_fitness.append((sid, s, s.fitness))
                avg_adjusted_fitness += s.adjusted_fitness
        if 0 == num_remaining:
            species.species = {}
            return []
        avg_adjusted_fitness /= len(species_fitness)
        self.reporters.info(
            "Average adjusted fitness: {:.3f}".format(avg_adjusted_fitness))
        spawn_amounts = []
        for sid, s, sfitness in species_fitness:
            spawn = len(s.members)
            if sfitness > avg_adjusted_fitness:
                spawn = max(spawn + 2, spawn * 1.1)
            else:
                spawn = max(spawn * 0.9, 2)
            spawn_amounts.append(spawn)
        total_spawn = sum(spawn_amounts)
        norm = pop_size / total_spawn
        spawn_amounts = [int(round(n * norm)) for n in spawn_amounts]
        new_population = {}
        species.species = {}

        learning_function = None
        if exp.learning_function == 'BP':
            learning_function = backpropagation
        elif exp.learning_function == 'BT':
            learning_function = batch

        has_learning = not learning_function is None
        if has_learning:
            (writer, lessons) = syllabus
            if exp.syllabus_source == 'EXP':
                lessons_to_learn = random.sample(
                    lessons, min(exp.syllabus_size, len(lessons)))
            elif exp.syllabus_source == 'RND':
                lessons_to_learn = lessons

        for spawn, (sid, s, sfitness) in zip(spawn_amounts, species_fitness):
            spawn = max(spawn, self.elitism)
            if spawn <= 0:
                continue
            old_members = list(iteritems(s.members))
            s.members = {}
            species.species[sid] = s
            old_members.sort(reverse=True, key=lambda x: x[1].fitness)
            if self.elitism > 0:
                for i, m in old_members[:self.elitism]:
                    new_population[i] = m
                    spawn -= 1
            if spawn <= 0:
                continue
            repro_cutoff = int(
                math.ceil(self.survival_threshold * len(old_members)))
            repro_cutoff = max(repro_cutoff, 2)
            old_members = old_members[:repro_cutoff]

            if has_learning and (exp.learning_target == 'Ambos'
                                 or exp.learning_target == 'Pais'):
                for (_, g) in old_members:
                    if g != writer:
                        learning_function(g, lessons_to_learn,
                                          exp.learning_rate)

            while spawn > 0:
                spawn -= 1
                parent1_id, parent1 = random.choice(old_members)
                parent2_id, parent2 = random.choice(old_members)
                gid = self.genome_indexer.next()
                child = config.genome_type(gid)
                child.configure_crossover(parent1, parent2,
                                          config.genome_config)
                child.mutate(config.genome_config)
                child.net = FeedForwardNetwork.create(child, self.config)

                if has_learning and (exp.learning_target == 'Ambos'
                                     or exp.learning_target == 'Filhos'):
                    if exp.children_inclusion == 'Inicial' or (
                            exp.children_inclusion == 'Tardia'
                            and generation >= exp.generations / 2):
                        learning_function(child, lessons_to_learn,
                                          exp.learning_rate)

                new_population[gid] = child
                self.ancestors[gid] = (parent1_id, parent2_id)
        return new_population
示例#14
0
def neat_manual_looping(pop, generation_limit=None):
    if pop.config.no_fitness_termination and (generation_limit is None):
        raise RuntimeError(
            "Cannot have no generational limit with no fitness termination")

    yield

    k = 0
    while generation_limit is None or k < generation_limit:
        k += 1

        pop.reporters.start_generation(pop.generation)

        genomes = list(iteritems(pop.population))

        finesses = yield genomes

        for (genome_id, genome), fitness in zip(genomes, finesses):
            genome.fitness = fitness

        # 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(pop.config, pop.population, pop.species,
                                    best)

        # Track the best genome ever seen.
        if pop.best_genome is None or best.fitness > pop.best_genome.fitness:
            pop.best_genome = best

        if not pop.config.no_fitness_termination:
            # End if the fitness threshold is reached.
            fv = pop.fitness_criterion(g.fitness
                                       for g in itervalues(pop.population))
            if fv >= pop.config.fitness_threshold:
                pop.reporters.found_solution(pop.config, pop.generation, best)
                break

        # Create the next generation from the current generation.
        pop.population = pop.reproduction.reproduce(pop.config, pop.species,
                                                    pop.config.pop_size,
                                                    pop.generation)

        # Check for complete extinction.
        if not pop.species.species:
            pop.reporters.complete_extinction()

            # If requested by the user, create a completely new population,
            # otherwise raise an exception.
            if pop.config.reset_on_extinction:
                pop.population = pop.reproduction.create_new(
                    pop.config.genome_type, pop.config.genome_config,
                    pop.config.pop_size)
            else:
                raise CompleteExtinctionException()

        # Divide the new population into species.
        pop.species.speciate(pop.config, pop.population, pop.generation)

        pop.reporters.end_generation(pop.config, pop.population, pop.species)

        pop.generation += 1

    if pop.config.no_fitness_termination:
        pop.reporters.found_solution(pop.config, pop.generation,
                                     pop.best_genome)
示例#15
0
import neat
import itertools
from neat.six_util import itervalues
import game_ret
from collections import Counter

CONFIG = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
                     neat.DefaultSpeciesSet, neat.DefaultStagnation,
                     'config-feedforward')
NUM_CHAMPIONS = 5
match_files = ["match190", "match193", "match196", "match199"]
mismatch_files = ["mismatch190", "mismatch193", "mismatch196", "mismatch199"]

matches = [[
    g for g in itervalues(
        neat.checkpoint.Checkpointer.restore_checkpoint(match_file).population)
] for match_file in match_files]
mismatches = [[
    g for g in itervalues(
        neat.checkpoint.Checkpointer.restore_checkpoint(
            mismatch_file).population)
] for mismatch_file in mismatch_files]


def get_champions(gs):
    champions = []
    for i in range(NUM_CHAMPIONS):
        champion = max(gs, key=lambda g: g.fitness)
        gs.remove(max(gs, key=lambda g: g.fitness))
        champions.append(neat.nn.FeedForwardNetwork.create(champion, CONFIG))
def process():
    global program_state, p
    global config
    global obj_topo, road_topo
    global CAR_ROW_START, CAR_COL_START, CAR_SHAPE_COL, sand_stall
    global frame, new_distance, distance_stall, old_distance, base_distance
    global old_time, new_time, base_time
    global fitness_val, genome_fitness, generation_fitness, generation_fitness_index, generation_average_fitness
    global genome_rank, generation_rank, generation_rank_index
    global generation_count, genome_count, genome_list, genome, current_net, best_genome
    global key_press
    global winner

    print(program_state)

    # Stop the data processing if the agent is currently training
    if program_state == STATE_BUFFERING:
        time.sleep(0.1)
        pass

    elif program_state == STATE_BEGIN:
        program_state = STATE_BUFFERING

        # Report the current generation
        p.reporters.start_generation(p.generation)
        genome_list = list(iteritems(p.population))
        program_state = STATE_PRESSING_F1
        time.sleep(0.1)
        pass

    elif program_state == STATE_PRESSING_F1:
        time.sleep(0.1)
        pass

    elif program_state == STATE_RESETTED:
        program_state = STATE_BUFFERING

        # Grab the genome if there is still genome to check
        if genome_count < NUM_GENOMES:
            _, genome = genome_list[genome_count]
            current_net = neat.nn.FeedForwardNetwork.create(genome, config)
            program_state = STATE_EVALUATING
        else:
            genome_count = 0
            program_state = STATE_POST_PROCESSING
        pass

        # Sleep for the stability of the algorithm
        time.sleep(0.1)

    elif program_state == STATE_EVALUATING:

        old_distance = new_distance
        old_time = new_time

        # Get the data from the request
        start = time.time()
        data = request.body.read().decode('utf8')
        data = json.loads(data)

        #
        pixels = data["Pixels"]
        speed = data["Speed"]
        new_time = data["Time"]
        if new_time > BASE_TIME: new_time = 0
        new_distance = data["Distance"]
        if new_distance == BASE_DISTANCE: new_distance = 0
        rank = data["Rank"]
        nitro = data["Nitro"]

        # Determine a set of background color, we will try to remove this color from the game.
        road_topo = topo_from_original_array(pixels)[: TOPO_SHAPE[0] // 2, :]
        end = time.time()

        # Calculate decision from current net
        input_arr = road_topo.flatten()
        key_press = generate_key_presses(current_net, input_arr) + "0" # Don't press F1 to reset

        # Update frame counter and distance_stall and time
        if new_distance < old_distance: base_distance += BASE_DISTANCE
        if new_distance == old_distance:
            distance_stall += 1
        else:
            distance_stall = 0
        frame += 1
        if new_time < old_time: base_time += BASE_TIME
        if not road_topo[CAR_ROW_START + SHAPE_ROW, CAR_COL_START: CAR_COL_START + SHAPE_COL].any():
            sand_stall += 1
        else:
            sand_stall = 0

        fitness_val = (base_distance + new_distance) * DIST_C \
                      - (base_time + new_time) * TIME_C \
                      - rank * RANK_C \
                      + BASE_FITNESS

        # Print necessary information
        os.system('cls')
        print("Current generation: " + str(generation_count) + "/" + str(NUM_GENERATIONS))
        print("----")
        print_topo(road_topo)
        print(end - start)
        print_key_presses(key_press, BUTTONS)
        print("Speed:    " + str(speed))
        print("Time:     " + str(base_time + new_time))
        print("Distance: " + str(base_distance + new_distance))
        print("Rank:     " + str(rank))
        print("Nitro:    " + str(nitro))
        print("Current genome: " + str(genome_count + 1) + "/" + str(NUM_GENOMES))
        print("Fitness value: " + str(fitness_val))
        print('--------------')
        print('| Gen | Best Agent | Score      | Rank | Avg Score   |')
        print('|----------------------------------------------------|')
        for i in range(len(generation_fitness)):
            print("| {:3d} | {:10d} | {:10d} | {:4d} | {:11.3f} |".format( \
                i, generation_fitness_index[i], generation_fitness[i], generation_rank[i], generation_average_fitness[i]))

        # Stop the running if stall limit is reached
        if distance_stall > STALL_LIMIT:
            genome.fitness = fitness_val
            print("- Evaluated Genome " + str(genome_count) + ": " + str(fitness_val))

            # Add a bunch of statistical variables
            genome_fitness.append(fitness_val)
            genome_rank.append(rank)

            # Reset
            reset_variables()
            genome_count += 1
            program_state = STATE_PRESSING_F1

        # Return something cuz a post go with a get
        pass

    elif program_state == STATE_POST_PROCESSING:

        program_state = STATE_BUFFERING

        # Gather and report statistics.
        best = None
        for g in itervalues(p.population):
            if best is None or g.fitness > best.fitness:
                best = g
        p.reporters.post_evaluate(p.config, p.population, p.species, best)

        # Track the best gen ome ever seen.
        if p.best_genome is None or best.fitness > p.best_genome.fitness:
            p.best_genome = best

        # End if the fitness threshold is reached.
        fv = p.fitness_criterion(g.fitness for g in itervalues(p.population))
        if fv >= p.config.fitness_threshold:
            p.reporters.found_solution(p.config, p.generation, best)
            program_state = STATE_RETURN_BEST

        # Create the next generation from the current generation.
        p.population = p.reproduction.reproduce(p.config, p.species,
                                                p.config.pop_size, p.generation)

        # Check for complete extinction.
        if not p.species.species:
            p.reporters.complete_extinction()

            # If requested by the user, create a completely new population,
            # otherwise raise an exception.

            if p.config.reset_on_extinction:
                p.population = p.reproduction.create_new(p.config.genome_type,
                                                         p.config.genome_config,
                                                         p.config.pop_size)
            else:
                raise neat.CompleteExtinctionException()

        # Divide the new population into species.
        p.species.speciate(p.config, p.population, p.generation)
        p.reporters.end_generation(p.config, p.population, p.species)
        p.generation += 1

        # Add the best genome value into the statistics
        generation_fitness.append(max(genome_fitness))
        generation_average_fitness.append(np.average(genome_fitness))
        generation_fitness_index.append(np.argmax(genome_fitness))
        genome_fitness = []

        generation_rank.append(min(genome_rank))
        generation_rank_index.append(np.argmin(genome_rank))
        genome_rank = []

        # Increment generation count and switch state
        np.savetxt("best_genome_by_generation.npy",generation_fitness_index)
        generation_count += 1
        if generation_count == NUM_GENERATIONS: program_state = STATE_RETURN_BEST
        else: program_state = STATE_BEGIN
        pass

    elif program_state == STATE_RETURN_BEST:
        best_genome = p.best_genome
        program_state = STATE_TEST_BEST
        pass

    elif program_state == STATE_TEST_BEST:
        print("Should start testing stuff now")
        pass

    return("Finished")
示例#17
0
    def create(genome, config, quantize=8):
        """ Receives a genome and returns its phenotype (a FeedForwardNetwork). """
        idx = 0
        valueIDMap_neat2fpga = dict()
        valueIDMap_fpga2neat = dict()
        for o_id in config.genome_config.input_keys + config.genome_config.output_keys:
            valueIDMap_neat2fpga[o_id] = idx
            valueIDMap_fpga2neat[idx] = o_id
            idx += 1
        # Gather expressed connections.
        connections = [
            cg.key for cg in itervalues(genome.connections) if cg.enabled
        ]
        layers = feed_forward_layers(config.genome_config.input_keys,
                                     config.genome_config.output_keys,
                                     connections)
        layer = []
        for c in connections:
            for i in range(2):
                if c[i] not in valueIDMap_neat2fpga:
                    o_id = c[i]
                    valueIDMap_neat2fpga[o_id] = idx
                    valueIDMap_fpga2neat[idx] = o_id
                    idx += 1
        total_nodes = idx
        command_layer = len(layers) + 1
        command_init_total_node = len(valueIDMap_neat2fpga)
        command_init_in_nodes = len(config.genome_config.input_keys)
        command_s = [
            command_layer, command_init_total_node, command_init_in_nodes
        ]
        resp_s = [0] * total_nodes
        bias_s = [0] * total_nodes
        for idx in range(command_init_in_nodes, total_nodes, 1):
            o_id = valueIDMap_fpga2neat[idx]
            ng = genome.nodes[o_id]
            resp_s[idx] = int(ng.response * 2**quantize)
            bias_s[idx] = int(ng.bias * 2**(quantize + quantize + quantize))
        serial_in_pre = command_s
        serial_in_post = []
        for idx, layer in enumerate(layers):
            inputVectorThisLayer = []
            i_id = []
            outputVectorThisLayer = []
            o_id = []
            key_weight_dict = dict()
            for node in layer:
                for conn_key in connections:
                    inode, onode = conn_key
                    if onode == node:
                        if inode not in inputVectorThisLayer:
                            inputVectorThisLayer.append(inode)
                            i_id.append(valueIDMap_neat2fpga[inode])
                        if onode not in outputVectorThisLayer:
                            outputVectorThisLayer.append(onode)
                            o_id.append(valueIDMap_neat2fpga[onode])
                        indx_i = inputVectorThisLayer.index(inode)
                        indx_o = outputVectorThisLayer.index(onode)
                        cg = genome.connections[conn_key]
                        key_weight_dict.update({(indx_i, indx_o): cg.weight})

                weight_matrix = np.zeros(
                    (len(outputVectorThisLayer), len(inputVectorThisLayer)))
            for key, val in key_weight_dict.items():
                indx_i, indx_o = key
                weight_matrix[indx_o][indx_i] = int(val * 2**quantize)
            # if idx ==0:
            #     print("init_in_total: ", command_init_in_nodes, "in_first :", len(inputVectorThisLayer))
            serial_in_pre.append(len(inputVectorThisLayer))
            serial_in_pre.append(len(outputVectorThisLayer))
            serial_in_post = serial_in_post + o_id + i_id + list(
                np.ravel(weight_matrix))
        serial_in_pre = serial_in_pre + resp_s + bias_s
        return FeedForwardNetworkFPGA(serial_in_pre,
                                      serial_in_post, command_init_in_nodes,
                                      len(layer), quantize)
示例#18
0
 def reset(self):
     """Reset all neurons to their default state."""
     for n in itervalues(self.neurons):
         n.reset()
示例#19
0
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()
示例#20
0
    def syn_singularity(self, num_replacements, my_url, stats, gen_best,
                        avg_score, rep, config):
        # requests the last optimization state TODO: HACER PROCESS CONFIGURABLE Y POR HASH no por id for multi-process
        res = requests.get(
            my_url +
            "/processes/1?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph"
        )
        cont = res.json()
        # print results of request
        print('\ncurrent_block_performance =',
              cont['result'][0]['current_block_performance'])
        print('\nlast_optimum_id =', cont['result'][0]['last_optimum_id'])
        last_optimum_id = cont['result'][0]['last_optimum_id']
        # calcualte the best fitness as the weitgthed average of the best performers
        best_genomes = stats.best_unique_genomes(num_replacements)
        reps_local = []
        reps = [gen_best]
        accum = 0.0
        countr = 0
        for g in best_genomes:
            if g.fitness is not None:
                accum = accum + g.fitness
                countr = countr + 1
        if countr > 0:
            best_fitness = (3 * avg_score + (accum / countr)) / 4
        else:
            best_fitness = (avg_score)

        print("\nPerformance = ", best_fitness)
        print("*********************************************************")
        # Si el perf reportado pop2_champion_fitness > pop1_champion_fitness de validation training
        if cont['result'][0]['current_block_performance'] > best_fitness:
            # hace request GetParameter(id)
            res_p = requests.get(
                my_url + "/parameters/" + str(last_optimum_id) +
                "?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph"
            )
            cont_param = res_p.json()
            # descarga el checkpoint del link de la respuesta si cont.parameter_link
            print('Parameter Downloaded')
            print('\nmigrations =')
            if cont_param['result'][0]['parameter_link'] is not None:
                genom_data = requests.get(
                    cont_param['result'][0]['parameter_link']).content
                with open('remote_reps', 'wb') as handler:
                    handler.write(genom_data)
                    handler.close()
                # carga genom descargado en nueva población pop2
                with open('remote_reps', 'rb') as f:
                    remote_reps = pickle.load(f)
                # OP.MIGRATION: Reemplaza el peor de la especie pop1 más cercana por el nuevo chmpion de pop2 como http://neo.lcc.uma.es/Articles/WRH98.pdf
                # para cada elemento de remote_reps, busca el closer, si remote fitness > local, lo reemplaza
                for i in range(len(remote_reps)):
                    closer = None
                    min_dist = None
                    # initialize for less fit search
                    less_fit = None
                    less_fitness = 10000
                    for g in itervalues(self.population):
                        if g not in remote_reps:
                            dist = g.distance(remote_reps[i],
                                              config.genome_config)
                            if dist is None:
                                dist = 100000000
                        else:
                            dist = 100000000
                        # do not count already migrated remote_reps
                        if closer is None or min_dist is None:
                            closer = deepcopy(g)
                            min_dist = dist
                        if dist < min_dist:
                            closer = deepcopy(g)
                            min_dist = dist
                        if g.fitness is None:
                            g.fitness = -10
                        if g.fitness < less_fitness:
                            less_fitness = g.fitness
                            less_fit = deepcopy(g)
                    # For the best genom in position 0
                    if i == 0 and remote_reps[0].fitness > gen_best.fitness:
                        if closer is None:
                            # busca el pop con el menor fitness
                            closer = less_fit
                        tmp_genom = deepcopy(remote_reps[i])
                        # Hack: overwrites original genome key with the replacing one
                        tmp_genom.key = closer.key
                        self.population[closer.key] = deepcopy(tmp_genom)
                        print("gen_best=", closer.key)
                        self.best_genome = deepcopy(tmp_genom)
                        #gen_best = deepcopy(tmp_genom)
                    else:
                        # si el remote fitness>local, reemplazar el remote de pop2 en pop1
                        if closer is None:
                            # busca el pop con el menor fitness
                            closer = less_fit
                        if closer is not None:
                            if closer not in remote_reps:
                                if closer.fitness is None:
                                    closer.fitness = less_fitness
                                if closer.fitness is not None and remote_reps[
                                        i].fitness is not None:
                                    if remote_reps[i].fitness > closer.fitness:
                                        tmp_genom = deepcopy(remote_reps[i])
                                        # Hack: overwrites original genome key with the replacing one
                                        tmp_genom.key = closer.key
                                        self.population[closer.key] = deepcopy(
                                            tmp_genom)
                                        print("Replaced=", closer.key)
                                        # actualiza gen_best y best_genome al remoto
                                        self.best_genome = deepcopy(tmp_genom)
                                        #gen_best = deepcopy(tmp_genom)
                                if closer.fitness is None:
                                    tmp_genom = deepcopy(remote_reps[i])
                                    # Hack: overwrites original genome key with the replacing one
                                    tmp_genom.key = len(self.population) + 1
                                    self.population[tmp_genom.key] = tmp_genom
                                    print("Created Por closer.fitness=NONE : ",
                                          tmp_genom.key)
                                    # actualiza gen_best y best_genome al remoto
                                    self.best_genome = deepcopy(tmp_genom)
                                    #gen_best = deepcopy(tmp_genom)
                            else:
                                #si closer está en remote_reps es porque no hay ningun otro cercano así que lo adiciona
                                tmp_genom = deepcopy(remote_reps[i])
                                # Hack: overwrites original genome key with the replacing one
                                tmp_genom.key = len(self.population) + 1
                                self.population[tmp_genom.key] = tmp_genom
                                print("Created por Closer in rempte_reps=",
                                      tmp_genom.key)
                                # actualiza gen_best y best_genome al remoto
                                self.best_genome = deepcopy(tmp_genom)
                                #gen_best = deepcopy(tmp_genom)

                #ejecuta speciate
                self.species.speciate(config, self.population, self.generation)
                print("\nSpeciation after migration done")
        # Si el perf reportado es menor pero no igual al de pop1
        if cont['result'][0]['current_block_performance'] < best_fitness:
            # Obtiene remote_reps
            # hace request GetParameter(id)
            remote_reps = None
            res_p = requests.get(
                my_url + "/parameters/" + str(last_optimum_id) +
                "?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph"
            )
            cont_param = res_p.json()
            # descarga el checkpoint del link de la respuesta si cont.parameter_link
            print('\nNEW OPTIMUM - cont_param =', cont_param)
            #print('\nmigrations =')
            if cont_param['result'][0]['parameter_link'] is not None:
                genom_data = requests.get(
                    cont_param['result'][0]['parameter_link']).content
                with open('remote_reps', 'wb') as handler:
                    handler.write(genom_data)
                    handler.close()
                # carga genom descargado en nueva población pop2
                with open('remote_reps', 'rb') as f:
                    remote_reps = pickle.load(f)
        #Guarda los mejores reps
            reps_local = []
            reps = [gen_best]
            # Para los mejores genes
            best_genomes = stats.best_unique_genomes(num_replacements)
            for g in best_genomes:
                #print("\ns=",s)
                if g not in reps_local:
                    reps_local.append(g)
                    reps_local[len(reps_local) - 1] = deepcopy(g)
            # TODO: Conservar los mejores reps, solo reemplazarlos por los mas cercanos
            if remote_reps is None:
                for l in reps_local:
                    reps.append(l)
                    reps[len(reps) - 1] = deepcopy(l)
            else:
                # para cada reps_local l
                for l in reps_local:
                    # busca el closer a l en reps_remote
                    for i in range(len(remote_reps)):
                        closer = None
                        min_dist = None
                        for g in reps_local:
                            if g not in remote_reps:
                                dist = g.distance(remote_reps[i],
                                                  config.genome_config)
                            else:
                                dist = 100000000
                            # do not count already migrated remote_reps
                            if closer is None or min_dist is None:
                                closer = deepcopy(g)
                                min_dist = dist
                            if dist < min_dist:
                                closer = deepcopy(g)
                                min_dist = dist
        #           si closer is in reps
                    if closer in reps:
                        #               adiciona l a reps si ya no estaba en reps
                        if l not in reps:
                            reps.append(l)
                            reps[len(reps) - 1] = deepcopy(l)
        #           sino
                    else:
                        #               si l tiene más fitness que closer,
                        if closer.fitness is not None and l.fitness is not None:
                            if l.fitness > closer.fitness:
                                #                       adiciona l a reps si ya no estaba en reps
                                if l not in reps:
                                    reps.append(l)
                                    reps[len(reps) - 1] = deepcopy(l)
        #               sino
                            else:
                                #                      adiciona closer a reps si ya no estaba en reps
                                if l not in reps:
                                    reps.append(closer)
                                    reps[len(reps) - 1] = deepcopy(closer)
                                    # Guarda checkpoint de los representatives de cada especie y lo copia a ubicación para servir vía syn.
                                    # rep.save_checkpoint(config,pop,neat.DefaultSpeciesSet,rep.current_generation)
            print("\nreps=", reps)
            filename = '{0}{1}'.format("reps-", rep.current_generation)
            with open(filename, 'wb') as f:
                pickle.dump(reps, f)
            #
            # Hace request de CreateParam a syn
            form_data = {
                "process_hash":
                "ph",
                "app_hash":
                "ah",
                "parameter_link":
                my_url + "/genoms/" + filename,
                "parameter_text":
                self.best_genome.key,
                "parameter_blob":
                "",
                "validation_hash":
                "",
                "hash":
                "h",
                "performance":
                best_fitness,
                "redir":
                "1",
                "username":
                "******",
                "pass_hash":
                "$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q"
            }
            # TODO: COLOCAR DIRECCION CONFIGURABLE
            res = requests.post(
                my_url +
                "/parameters?username=harveybc&pass_hash=$2a$04$ntNHmofQoMoajG89mTEM2uSR66jKXBgRQJnCgqfNN38aq9UkN4Y6q&process_hash=ph",
                data=form_data)
            res_json = res.json()
        # TODO FIN: FUNCION DE SINCRONIZACION CON SINGULARITY
        return 0
示例#21
0
    def continue_processing(self, current_genome_list):
        print("Continue processing")
        # self.population = {}
        for genome_key in current_genome_list:
            print("Currently opening: ", genome_key)
            with open(
                    neat_path + "pklDumps/genome_" + str(genome_key) + ".pkl",
                    'rb') as nnPklRead:
                current_gen = pickle.load(nnPklRead)
                self.population[genome_key].fitness = current_gen.fitness
        best = None
        for g in itervalues(self.population):
            if best is None or g.fitness > best.fitness:
                best = g
        self.reporters.post_evaluate(self.config, self.population,
                                     self.species, best)

        print("Chosen current best as: ", best.key)

        # Track the best genome ever seen.
        if self.best_genome is None or best.fitness > self.best_genome.fitness:
            self.best_genome = best

        print("Chosen overall best as: ", self.best_genome.key)

        if not self.config.no_fitness_termination:
            # End if the fitness threshold is reached.
            fv = self.fitness_criterion(g.fitness
                                        for g in itervalues(self.population))
            if fv >= self.config.fitness_threshold:
                self.reporters.found_solution(self.config, self.generation,
                                              best)
                return

        # Create the next generation from the current generation.
        self.population = self.reproduction.reproduce(self.config,
                                                      self.species,
                                                      self.config.pop_size,
                                                      self.generation)

        # Check for complete extinction.
        if not self.species.species:
            self.reporters.complete_extinction()

            # If requested by the user, create a completely new population,
            # otherwise raise an exception.
            if self.config.reset_on_extinction:
                self.population = self.reproduction.create_new(
                    self.config.genome_type, self.config.genome_config,
                    self.config.pop_size)
            else:
                raise CompleteExtinctionException()

        # Divide the new population into species.
        self.species.speciate(self.config, self.population, self.generation)

        self.reporters.end_generation(self.config, self.population,
                                      self.species)

        self.generation += 1

        # continue to top of loop for next k
        self.dump_genomes_pop(current_genome_list)
    def run(self, fitness_function, n=None):
        # Variables needed to save archive on each update
        winner_name_prefix = "archive_checkpoint_" + self.winner_name

        if self.config.no_fitness_termination and (n is None):
            raise RuntimeError("Cannot have no generational limit with no fitness termination")

        k = 0
        while n is None or k < n:
            k += 1

            self.reporters.start_generation(self.generation)

            not_evaluated = {}
            evaluated = []
            # len(population) = 2*pop_size
            for gid, g in self.population.items():
                if g.fitness is None:
                    not_evaluated[gid] = g
                else:
                    evaluated.append((gid, g))

            # Evaluate all genomes using the user-provided function.
            fitness_function(list(iteritems(not_evaluated)), self.config)
            self.KNNdistances(self.population, self.novelty_archive, self.n_neighbors)

            if len(evaluated) != 0:
                self.species.speciate(self.config, self.population, self.generation)
                dim = 0
                max_spec_dim = 0
                max_sid = -1
                for sid, s in iteritems(self.species.species):

                    s.members = self.get_best_n_members(s.members, math.ceil(len(s.members) / 2))
                    d = len(s.members)
                    if d > max_spec_dim:
                        max_spec_dim = d
                        max_sid = sid
                    dim += d
                diff = dim - self.config.pop_size
                if diff > 0 and diff > max_spec_dim:
                    s = self.species.species[max_sid]
                    s.members = self.get_best_n_members(s.members, len(s.members) - diff)

                new_population = {}
                for sid, s in iteritems(self.species.species):
                    for gid, g in s.members.items():
                        new_population[gid] = g
                self.population = new_population

            self.species.speciate(self.config, self.population, self.generation)

            # Check for complete extinction.
            if not self.species.species:
                self.reporters.complete_extinction()

                # If requested by the user, create a completely new population,
                # otherwise raise an exception.
                if self.config.reset_on_extinction:
                    self.population = self.reproduction.create_new(self.config.genome_type,
                                                                   self.config.genome_config,
                                                                   self.config.pop_size)
                else:
                    raise CompleteExtinctionException()

            # Gather and report statistics.
            best = None
            for g in itervalues(self.population):
                if best is None or g.dist > best.dist:
                    best = g
                if g.dist > self.novelty_threshold:
                    if g not in self.novelty_archive:
                        self.novelty_archive.append(g)
                        print("Distanza di aggiunta: ", g.dist)
                        self.n_add_archive += 1
                        self.last_archive_modified = self.generation
                        with open(winner_name_prefix, "wb") as f:
                            pickle.dump(self.novelty_archive, f)

            self.reporters.post_evaluate(self.config, self.population, self.species, best)

            if not self.config.no_fitness_termination:
                # End if the fitness threshold is reached.
                fv = self.fitness_criterion(g.dist for g in itervalues(self.population))
                if fv >= self.config.fitness_threshold:
                    self.reporters.found_solution(self.config, self.generation, best)
                    break

            # Create the next generation from the current generation.
            self.population = self.reproduction.reproduce(self.config, self.species,
                                                          self.config.pop_size, self.generation)

            # Check for complete extinction.
            if not self.species.species:
                self.reporters.complete_extinction()

                # If requested by the user, create a completely new population,
                # otherwise raise an exception.
                if self.config.reset_on_extinction:
                    self.population = self.reproduction.create_new(self.config.genome_type,
                                                                   self.config.genome_config,
                                                                   self.config.pop_size)
                else:
                    raise CompleteExtinctionException()

            # Divide the new population into species.
            self.species.speciate(self.config, self.population, self.generation)

            self.reporters.end_generation(self.config, self.population, self.species)

            time_diff = self.generation - self.last_archive_modified

            if time_diff > 60:
                self.novelty_threshold -= self.novelty_threshold * 0.05

            if self.n_add_archive > 4 and time_diff <= 30:
                self.novelty_threshold += self.novelty_threshold * 0.05
                self.n_add_archive = 0

            if time_diff > 30:
                self.n_add_archive = 0

            self.reporters.info("Novelty's archive size: {}\n".format(len(self.novelty_archive)))
            if len(self.novelty_archive) > 0:
                self.reporters.info("Archive's best: {}".format(
                    max(self.novelty_archive, key=lambda x: x.fitness[0]).fitness[0]))
            else:
                self.reporters.info("Archive's best: 0")
            self.generation += 1

        if self.config.no_fitness_termination:
            self.reporters.found_solution(self.config, self.generation, self.best_genome)

        return self.novelty_archive
    def run(self, fitness_function, n=None):
        # Variables needed to save archive on each update
        winner_name_prefix = "archive_checkpoint_" + self.winner_name

        if self.config.no_fitness_termination and (n is None):
            raise RuntimeError(
                "Cannot have no generational limit with no fitness termination"
            )

        k = 0
        while n is None or k < n:
            k += 1

            self.reporters.start_generation(self.generation)

            # Evaluate all genomes using the user-provided function.
            fitness_function(list(iteritems(self.population)), self.config)
            self.KNNdistances(self.population, self.novelty_archive,
                              self.n_neighbors)

            # Gather and report statistics.
            best = None
            for g in itervalues(self.population):
                if best is None or g.dist > best.dist:
                    best = g
                if g.dist > self.novelty_threshold:
                    if g not in self.novelty_archive:
                        self.novelty_archive.append(g)
                        print("Distanza di aggiunta: ", g.dist)
                        self.n_add_archive += 1
                        self.last_archive_modified = self.generation
                        with open(winner_name_prefix, "wb") as f:
                            pickle.dump(self.novelty_archive, f)

            self.reporters.post_evaluate(self.config, self.population,
                                         self.species, best)

            # if self.last_genome_added is None:
            #     self.last_genome_added = best

            # Track the best genome ever seen.
            # if self.last_genome_added.fitness != best.fitness and best.dist > self.novelty_threshold:
            #     print("Distanza di aggiunta: ", best.dist)
            #     self.last_genome_added = best
            #     self.last_archive_modified = self.generation
            #     self.n_add_archive += 1
            #     self.novelty_archive.append(best)
            #     with open(winner_name_prefix, "wb") as f:
            #         pickle.dump(self.novelty_archive, f)

            if not self.config.no_fitness_termination:
                # End if the fitness threshold is reached.
                fv = self.fitness_criterion(
                    g.dist for g in itervalues(self.population))
                if fv >= self.config.fitness_threshold:
                    self.reporters.found_solution(self.config, self.generation,
                                                  best)
                    break

            # Create the next generation from the current generation.
            self.population = self.reproduction.reproduce(
                self.config, self.species, self.config.pop_size,
                self.generation)

            # Check for complete extinction.
            if not self.species.species:
                self.reporters.complete_extinction()

                # If requested by the user, create a completely new population,
                # otherwise raise an exception.
                if self.config.reset_on_extinction:
                    self.population = self.reproduction.create_new(
                        self.config.genome_type, self.config.genome_config,
                        self.config.pop_size)
                else:
                    raise CompleteExtinctionException()

            # Divide the new population into species.
            self.species.speciate(self.config, self.population,
                                  self.generation)

            self.reporters.end_generation(self.config, self.population,
                                          self.species)

            time_diff = self.generation - self.last_archive_modified

            if time_diff > 60:
                self.novelty_threshold -= self.novelty_threshold * 0.05

            if self.n_add_archive > 4 and time_diff <= 30:
                self.novelty_threshold += self.novelty_threshold * 0.05
                self.n_add_archive = 0

            if time_diff > 30:
                self.n_add_archive = 0

            self.reporters.info("Novelty's archive size: {}\n".format(
                len(self.novelty_archive)))
            self.generation += 1

        if self.config.no_fitness_termination:
            self.reporters.found_solution(self.config, self.generation,
                                          self.best_genome)

        return self.novelty_archive
示例#24
0
    def reproduce(self, config, species, pop_size, generation):
        """
        Handles creation of genomes, either from scratch or by sexual or
        asexual reproduction from parents.
        """
        # TODO: I don't like this modification of the species and stagnation objects,
        # because it requires internal knowledge of the objects.

        # Filter out stagnated species, collect the set of non-stagnated
        # species members, and compute their average adjusted fitness.
        # The average adjusted fitness scheme (normalized to the interval
        # [0, 1]) allows the use of negative fitness values without
        # interfering with the shared fitness scheme.
        all_fitnesses = []
        remaining_species = []

        old_population = []

        for stag_sid, stag_s, stagnant in self.stagnation.update(
                species, generation):

            old_population.append(itervalues(stag_s.members))

            if stagnant:
                self.reporters.species_stagnant(stag_sid, stag_s)
            else:
                all_fitnesses.extend(m.fitness
                                     for m in itervalues(stag_s.members))
                remaining_species.append(stag_s)

        # The above comment was not quite what was happening - now getting fitnesses
        # only from members of non-stagnated species.

        # No species left.
        if not remaining_species:
            species.species = {}
            return {}  # was []

        # Find minimum/maximum fitness across the entire population, for use in
        # species adjusted fitness computation.
        min_fitness = min(all_fitnesses)
        max_fitness = max(all_fitnesses)
        # Do not allow the fitness range to be zero, as we divide by it below.
        # TODO: The ``1.0`` below is rather arbitrary, and should be configurable.
        fitness_range = max(1.0, max_fitness - min_fitness)
        for afs in remaining_species:
            # Compute adjusted fitness.
            msf = mean([m.fitness for m in itervalues(afs.members)])
            af = (msf - min_fitness) / fitness_range
            afs.adjusted_fitness = af

        adjusted_fitnesses = [s.adjusted_fitness for s in remaining_species]
        avg_adjusted_fitness = mean(adjusted_fitnesses)  # type: float
        self.reporters.info(
            "Average adjusted fitness: {:.3f}".format(avg_adjusted_fitness))

        # Compute the number of new members for each species in the new generation.
        previous_sizes = [len(s.members) for s in remaining_species]
        min_species_size = self.reproduction_config.min_species_size
        # Isn't the effective min_species_size going to be max(min_species_size,
        # self.reproduction_config.elitism)? That would probably produce more accurate tracking
        # of population sizes and relative fitnesses... doing. TODO: document.
        min_species_size = max(min_species_size,
                               self.reproduction_config.elitism)
        spawn_amounts = self.compute_spawn(adjusted_fitnesses, previous_sizes,
                                           pop_size, min_species_size)

        # Bandit Update
        # TODO Reconsider reward scheme to be invariant of actual fitness value
        # Percentage improvement to fitness?
        # Fitness improvement as a fraction of best improvement? - seems good, then one mutation is always 1, rest are < 1
        # How to reward or perceive "failure"? Same as fraction but for decreases?
        # 1 if best arm in generation else 0?
        if generation > 0:
            mutation_delta = []

            for mutant, old_fitness, mutations in self.records[-1]:
                fit_delta = mutant.fitness - old_fitness

                for m in mutations:
                    mutation_delta.append((m, fit_delta))
            # print(mutation_delta)
            self.bandit.update_all(mutation_delta)
            #         if m not in mutations_deltas:
            #             mutations_deltas[m] = [fit_delta]
            #         else:
            #             mutations_deltas[m].append(fit_delta)

            # for mutations, deltas in mutations_deltas.items():
            #     self.bandit.update(mutations, deltas) # len deltas can be removed, the number of rewards is the number of plays

            # print([(g.key, g.fitness-f, m) for g,f,m in self.records[-1]])

        self.reporters.post_reproduction(config, self.bandit, None)

        self.records.append([])

        new_population = {}
        species.species = {}
        for spawn, s in zip(spawn_amounts, remaining_species):
            # If elitism is enabled, each species always at least gets to retain its elites.
            spawn = max(spawn, self.reproduction_config.elitism)

            assert spawn > 0

            # The species has at least one member for the next generation, so retain it.
            old_members = list(iteritems(s.members))
            s.members = {}
            species.species[s.key] = s

            # Sort members in order of descending fitness.
            old_members.sort(reverse=True, key=lambda x: x[1].fitness)

            # Transfer elites to new generation.
            if self.reproduction_config.elitism > 0:
                for i, m in old_members[:self.reproduction_config.elitism]:
                    new_population[i] = m
                    spawn -= 1

            if spawn <= 0:
                continue

            # Only use the survival threshold fraction to use as parents for the next generation.
            repro_cutoff = int(
                math.ceil(self.reproduction_config.survival_threshold *
                          len(old_members)))
            # Use at least two parents no matter what the threshold fraction result is.
            repro_cutoff = max(repro_cutoff, 2)
            old_members = old_members[:repro_cutoff]

            # Randomly choose parents and produce the number of offspring allotted to the species.
            while spawn > 0:
                spawn -= 1

                parent1_id, parent1 = choice(old_members)
                parent2_id, parent2 = (parent1_id, parent1)

                gid = next(self.genome_indexer)
                child = config.genome_type(gid)

                child.configure_crossover(parent1, parent2,
                                          config.genome_config)

                mutation_directives = self.bandit.play(generation)
                child.mutate(config.genome_config, mutation_directives)

                new_population[gid] = child
                self.ancestors[gid] = (parent1_id, parent2_id)

                self.records[-1].append(
                    (child, parent1.fitness, mutation_directives))

        return new_population
示例#25
0
    def run(self, fitness_function, n=None):
        """
        Runs NEAT's genetic algorithm for at most n generations.  If n
        is None, run until solution is found or extinction occurs.

        The user-provided fitness_function must take only two arguments:
            1. The population as a list of (genome id, genome) tuples.
            2. The current configuration object.

        The return value of the fitness function is ignored, but it must assign
        a Python float to the `fitness` member of each genome.

        The fitness function is free to maintain external state, perform
        evaluations in parallel, etc.

        It is assumed that fitness_function does not modify the list of genomes,
        the genomes themselves (apart from updating the fitness member),
        or the configuration object.
        """

        if self.config.no_fitness_termination and (n is None):
            raise RuntimeError("Cannot have no generational limit with no fitness termination")

        k = 0
        while n is None or k < n:
            if not (self.state):
                print("Training: break")
                self.reached_limit  = False
                break
            k += 1

            self.reporters.start_generation(self.generation)

            # Evaluate all genomes using the user-provided function.
            fitness_function(list(iteritems(self.population)), self.config)

            # Gather and report statistics.
            best = None
            for g in itervalues(self.population):
                if best is None or g.fitness > best.fitness:
                    best = g
            self.reporters.post_evaluate(self.config, self.population, self.species, best)

            # Track the best genome ever seen.
            if self.best_genome is None or best.fitness > self.best_genome.fitness:
                self.best_genome = best

            if not self.config.no_fitness_termination:
                # End if the fitness threshold is reached.
                fv = self.fitness_criterion(g.fitness for g in itervalues(self.population))
                if fv >= self.config.fitness_threshold:
                    self.reporters.found_solution(self.config, self.generation, best)
                    self.reached_limit  = False
                    break

            # Create the next generation from the current generation.
            self.population = self.reproduction.reproduce(self.config, self.species,
                                                          self.config.pop_size, self.generation)

            # Check for complete extinction.
            if not self.species.species:
                self.reporters.complete_extinction()

                # If requested by the user, create a completely new population,
                # otherwise raise an exception.
                if self.config.reset_on_extinction:
                    self.population = self.reproduction.create_new(self.config.genome_type,
                                                                   self.config.genome_config,
                                                                   self.config.pop_size)
                else:
                    raise CompleteExtinctionException()

            # Divide the new population into species.
            self.species.speciate(self.config, self.population, self.generation)

            self.reporters.end_generation(self.config, self.population, self.species)

            self.generation += 1

        if self.config.no_fitness_termination:
            self.reporters.found_solution(self.config, self.generation, self.best_genome)

        return self.best_genome
示例#26
0
 def get_fitnesses(self):
     return [
         m.fitness for m in itervalues(self.members)
         if not np.isneginf(m.fitness)
     ]
    def run(self, fitness_function, n=None):
        # Variables needed to save winner
        winner_interval = 10
        winner_name_prefix = "winner_checkpoint_"
        last_winner_checkpoint = 0

        if self.config.no_fitness_termination and (n is None):
            raise RuntimeError("Cannot have no generational limit with no fitness termination")

        k = 0
        while n is None or k < n:
            k += 1
            self.reporters.start_generation(self.generation)
            start_time_gen = time.time()

            # Evaluate all genomes using the user-provided function.
            not_evaluated = {}
            evaluated = []
            # len(population) = 2*pop_size
            for gid, g in self.population.items():
                if g.fitness is None:
                    not_evaluated[gid] = g
                else:
                    evaluated.append((gid, g))

            diff = round(time.time() - start_time_gen, 3)
            self.sum_times += diff

            fitness_function(list(iteritems(not_evaluated)), self.config)

            start_time_gen = time.time()
            if self.random_replace:
                i = 0
                self.population = {}
                for gid, g in not_evaluated.items():
                    if len(evaluated) <= i or g.fitness > evaluated[i][1].fitness:
                        self.population[gid] = g
                    else:
                        self.population[evaluated[i][0]] = evaluated[i][1]
                    i = i + 1
                self.species.speciate(self.config, self.population, self.generation)
            elif self.mu_lambda:
                self.population = []
                self.population += evaluated
                for key, v in not_evaluated.items():
                    self.population.append((key, v))
                self.population.sort(reverse=True, key=lambda x: x[1].fitness)
                self.population = from_list_to_dict(self.population[:self.config.pop_size])
                self.species.speciate(self.config, self.population, self.generation)
            else:
                self.species.speciate(self.config, self.population, self.generation)
                dim = 0
                max_spec_dim = 0
                max_sid = -1
                for sid, s in iteritems(self.species):
                    s.members = self.get_best_half_members(s.members)
                    d = len(s.members)
                    if d > max_spec_dim:
                        max_spec_dim = d
                        max_sid = sid
                    dim += d
                diff = dim - self.config.pop_size
                if diff > 0 and diff > max_spec_dim:
                    s = self.species[max_sid]
                    s.members = s.members[:len(s.members) - diff]

            # Check for complete extinction.
            if not self.species.species:
                self.reporters.complete_extinction()

                # If requested by the user, create a completely new population,
                # otherwise raise an exception.
                if self.config.reset_on_extinction:
                    self.population = self.reproduction.create_new(self.config.genome_type,
                                                                   self.config.genome_config,
                                                                   self.config.pop_size)
                else:
                    raise CompleteExtinctionException()

            # Gather and report statistics.
            best = None
            for g in itervalues(self.population):
                if best is None or g.fitness > best.fitness:
                    best = g
            self.reporters.post_evaluate(self.config, self.population, self.species, best)

            # Track the best genome ever seen.
            if self.best_genome is None or best.fitness > self.best_genome.fitness:
                self.best_genome = best
                # Code to save the best after winner_interval generations
                if self.overwrite:
                    filename = winner_name_prefix
                else:
                    filename = '{0}{1}'.format(winner_name_prefix, self.generation)
                last_winner_checkpoint = self.generation
                with open(filename, 'wb') as f:
                    pickle.dump(self.best_genome, f)

            if not self.config.no_fitness_termination:
                # End if the fitness threshold is reached.
                fv = self.fitness_criterion(g.fitness for g in itervalues(self.population))
                if fv >= self.config.fitness_threshold:
                    self.reporters.found_solution(self.config, self.generation, best)
                    break

            self.reporters.end_generation(self.config, self.population, self.species)

            # Create the next generation from the current generation.
            self.population = self.reproduction.reproduce(self.config, self.species,
                                                          self.config.pop_size, self.generation)

            self.generation += 1

            print_file("\nGen: " + str(k) + " tempo: " + str(round(time.time() - start_time_gen,3)) + " sec\n")
            diff = round(time.time() - start_time_gen, 3)
            self.sum_times += diff
            self.reporters.info("\nGen: " + str(k) + " tempo: " + str(diff) + " sec\n")

        if self.config.no_fitness_termination:
            self.reporters.found_solution(self.config, self.generation, self.best_genome)

        self.reporters.info("Computation mean time: " + str(self.sum_times / (self.generation + 1)))

        return self.best_genome
def create(genome, config, map_size):
    """ Receives a genome and returns its phenotype (a SwitchNeuronNetwork). """
    genome_config = config.genome_config
    required = required_for_output(genome_config.input_keys,
                                   genome_config.output_keys,
                                   genome.connections)

    input_keys = genome_config.input_keys
    output_keys = genome_config.output_keys
    # Gather inputs and expressed connections.
    std_inputs = {}
    mod_inputs = {}
    children = {}
    node_keys = set(genome.nodes.keys())  # + list(genome_config.input_keys[:])

    # Here we populate the children dictionay for each unique not isolated node.
    for n in genome.nodes.keys():
        children[n] = []
        if not genome.nodes[n].is_isolated:
            for _ in range(1, map_size):
                new_idx = max(node_keys) + 1
                children[n].append(new_idx)
                node_keys.add(new_idx)
    # We don't scale the output with the map size to keep passing the parameters of the network easy.
    # This part can be revised in the future
    for n in chain(input_keys, output_keys):
        children[n] = []
    #Iterate over every connection
    for cg in itervalues(genome.connections):
        #If it's not enabled don't include it
        if not cg.enabled:
            continue

        i, o = cg.key
        #If neither node is required for output then skip the connection
        if o not in required and i not in required:
            continue

        #Find the map corresponding to each node of the connection
        in_map = [i] + children[i]
        out_map = [o] + children[o]
        #If the connection is modulatory and the output neuron a switch neuron then the new weights are stored
        #in the mod dictionary. We assume that only switch neurons have a modulatory part.
        if cg.is_mod and genome.nodes[o].is_switch:
            node_inputs = mod_inputs
        else:
            node_inputs = std_inputs
        for n in out_map:
            if n not in node_inputs.keys():
                node_inputs[n] = []

        if len(in_map) == map_size and len(out_map) == map_size:
            # Map to map connectivity
            if cg.one2one:
                # 1-to-1 mapping
                weight = cg.weight
                for i in range(map_size):
                    node_inputs[out_map[i]].append((in_map[i], weight))

            else:
                # 1-to-all
                if not cg.uniform:
                    # Step
                    start = -cg.weight
                    end = cg.weight
                    step = (end - start) / (map_size - 1)
                    for o_n in out_map:
                        s = start
                        for i_n in in_map:
                            node_inputs[o_n].append((i_n, s))
                            s += step
                else:
                    # Uniform
                    for o_n in out_map:
                        for i_n in in_map:
                            node_inputs[o_n].append((i_n, cg.weight))

        else:
            # Map-to-isolated or isolated-to-isolated
            if not cg.uniform:
                # Step
                start = -cg.weight
                end = cg.weight
                step = (end - start) / (map_size - 1)
                for o_n in out_map:
                    s = start
                    for i_n in in_map:
                        node_inputs[o_n].append((i_n, s))
                        s += step
            else:
                # Uniform
                for o_n in out_map:
                    for i_n in in_map:
                        node_inputs[o_n].append((i_n, cg.weight))

    nodes = []

    #Sometimes the output neurons end up not having any connections during the evolutionary process. While we do not
    #desire such networks, we should still allow them to make predictions to avoid fatal errors.
    for okey in output_keys:
        if okey not in node_keys:
            node_keys.add(okey)
            std_inputs[okey] = []

    # While we cannot deduce the order of activations of the neurons due to the fact that we allow for arbitrary connection
    # schemes, we certainly want the output neurons to activate last.
    input_keys = genome_config.input_keys
    output_keys = genome_config.output_keys
    conns = {}
    for k in genome.nodes.keys():
        if k not in std_inputs:
            std_inputs[k] = []
            if k in children:
                for c in children[k]:
                    std_inputs[c] = []
        conns[k] = [i for i, _ in std_inputs[k]]
    sorted_keys = order_of_activation(conns, input_keys, output_keys)

    for node_key in sorted_keys:
        #if the node we are examining is not in our keys set then skip it. It means that it is not required for output.
        if node_key not in node_keys:
            continue

        node = genome.nodes[node_key]
        node_map = [node_key] + children[node_key]
        if node.is_switch:

            #If the node doesn't have any inputs then it is not needed
            if node_key not in std_inputs.keys(
            ) and node_key not in mod_inputs.keys():
                continue
            # if the switch neuron only has modulatory weights then we copy those weights for the standard part as well.
            # this is not the desired behaviour but it is done to avoid errors during forward pass.
            if node_key not in std_inputs.keys(
            ) and node_key in mod_inputs.keys():
                for n in node_map:
                    std_inputs[n] = mod_inputs[n]
            if node_key not in mod_inputs:
                for n in node_map:
                    mod_inputs[n] = []
            for n in node_map:
                nodes.append(SwitchNeuron(n, std_inputs[n], mod_inputs[n]))
            continue
        for n in node_map:
            if n not in std_inputs:
                std_inputs[n] = []

        # Create the standard part dictionary for the neuron
        for n in node_map:
            params = {
                'activation_function':
                genome_config.activation_defs.get(node.activation),
                'integration_function':
                genome_config.aggregation_function_defs.get(node.aggregation),
                'bias':
                node.bias,
                'activity':
                0,
                'output':
                0,
                'weights':
                std_inputs[n]
            }
            nodes.append(Neuron(n, params))

    return SwitchNeuronNetwork(input_keys, output_keys, nodes)
    def speciate(self, config, population, generation):
        """
        Place genomes into species by genetic similarity.

        Note that this method assumes the current representatives of the species are from the old
        generation, and that after speciation has been performed, the old representatives should be
        dropped and replaced with representatives from the new generation.  If you violate this
        assumption, you should make sure other necessary parts of the code are updated to reflect
        the new behavior.
        """
        assert isinstance(population, dict)

        compatibility_threshold = self.species_set_config.compatibility_threshold

        # Find the best representatives for each existing species.
        unspeciated = set(iterkeys(population))
        distances = GenomeDistanceCache(config.genome_config)
        new_representatives = {}
        new_members = {}
        for sid, s in iteritems(self.species):
            candidates = []
            for gid in unspeciated:
                g = population[gid]
                d = distances(s.representative, g)
                candidates.append((d, g))

            # The new representative is the genome closest to the current representative.
            ignored_rdist, new_rep = min(candidates, key=lambda x: x[0])
            new_rid = new_rep.key
            new_representatives[sid] = new_rid
            new_members[sid] = [new_rid]
            unspeciated.remove(new_rid)

        # Partition population into species based on genetic similarity.
        while unspeciated:
            gid = unspeciated.pop()
            g = population[gid]

            # Find the species with the most similar representative.
            candidates = []
            for sid, rid in iteritems(new_representatives):
                rep = population[rid]
                d = distances(rep, g)
                if d < compatibility_threshold:
                    candidates.append((d, sid))

            if candidates:
                ignored_sdist, sid = min(candidates, key=lambda x: x[0])
                new_members[sid].append(gid)
            else:
                # No species is similar enough, create a new species, using
                # this genome as its representative.
                sid = next(self.indexer)
                new_representatives[sid] = gid
                new_members[sid] = [gid]

        # Update species collection based on new speciation.
        self.genome_to_species = {}
        for sid, rid in iteritems(new_representatives):
            s = self.species.get(sid)
            if s is None:
                s = Species(sid, generation)
                self.species[sid] = s

            members = new_members[sid]
            for gid in members:
                self.genome_to_species[gid] = sid

            member_dict = dict((gid, population[gid]) for gid in members)
            s.update(population[rid], member_dict)

        gdmean = mean(itervalues(distances.distances))
        gdstdev = stdev(itervalues(distances.distances))
        '''
示例#30
0
    def create(genome, config):
        """ Receives a genome and returns its phenotype (a GRUNetwork). """
        genome_config = config.genome_config
        required = required_for_output(genome_config.input_keys,
                                       genome_config.output_keys,
                                       genome.connections, genome.nodes)

        connections = [
            cg.key for cg in itervalues(genome.connections) if cg.enabled
        ]

        node_evals = []

        node_inputs = {}
        for cg in itervalues(genome.connections):
            if not cg.enabled:
                continue

            i, o = cg.key
            if o not in required and i not in required:
                continue

            if o not in node_inputs:
                node_inputs[o] = [(i, cg.weight)]
            else:
                node_inputs[o].append((i, cg.weight))

        node_evals = []
        gate_list = set()

        # Add the gates first for proper computation order
        for node_key, inputs in iteritems(node_inputs):
            ng = genome.nodes[node_key]

            if type(ng) is GRUNodeGene:
                for gate_key in [ng.read_gate, ng.forget_gate]:
                    if type(gate_key) is int and gate_key not in gate_list:
                        gate_list = gate_list.union(gate_key)
                        gate_g = genome.nodes[gate_key]
                        activation_function = genome_config.activation_defs.get(
                            gate_g.activation)
                        aggregation_function = genome_config.aggregation_function_defs.get(
                            gate_g.aggregation)
                        node_evals.append(
                            (gate_key, activation_function,
                             aggregation_function, gate_g.bias,
                             gate_g.response, inputs,
                             [gate_g.read_gate, gate_g.forget_gate]
                             if type(gate_g) is GRUNodeGene else None))

        for node_key, inputs in iteritems(node_inputs):
            if node_key not in gate_list:
                ng = genome.nodes[node_key]
                activation_function = genome_config.activation_defs.get(
                    ng.activation)
                aggregation_function = genome_config.aggregation_function_defs.get(
                    ng.aggregation)

                node_evals.append((node_key, activation_function,
                                   aggregation_function, ng.bias, ng.response,
                                   inputs, [ng.read_gate, ng.forget_gate]
                                   if type(ng) is GRUNodeGene else None))

        nw = GRUNetwork(genome_config.input_keys, genome_config.output_keys,
                        node_evals, gate_list)
        nw.genome = genome
        return nw