예제 #1
0
    def test_reproduce_too_many_elites(self):
        """Test that reproduce works as expected when too many elites are specified.
        """
        # Setup configuration
        self.config.reproduction_config.num_elites = 5
        self.config.reproduction_config.min_species_size = 3
        self.config.reproduction_config.survival_threshold = 0.75

        stagnation_scheme = Stagnation(self.config.stagnation_config,
                                       self.reporters)
        reproduction_scheme = Reproduction(self.config.reproduction_config,
                                           self.reporters, stagnation_scheme)
        pop_size = 10
        population = reproduction_scheme.create_new(Genome,
                                                    self.config.genome_config,
                                                    pop_size,
                                                    InnovationStore())
        for genome in population.values():
            genome.fitness = 1

        species_set = SpeciesSet(self.config.species_set_config,
                                 self.reporters)
        species_set.speciate(self.config, population, generation=1)

        with pytest.raises(AssertionError):
            reproduction_scheme.reproduce(self.config,
                                          species_set,
                                          pop_size,
                                          generation=1,
                                          innovation_store=InnovationStore(),
                                          refocus=False)
예제 #2
0
    def test_reproduce_no_mutation_or_crossover(self):
        """Test that the two populations are equal if no mutations or crossover are
        allowed.
        """
        self.config.reproduction_config.num_elites = 0
        self.config.reproduction_config.elitism_threshold = 4
        self.config.reproduction_config.survival_threshold = 1.0
        self.config.genome_config.weight_mutate_prob = 0.0
        self.config.genome_config.conn_add_prob = 0.0
        self.config.genome_config.node_add_prob = 0.0
        self.config.reproduction_config.crossover_prob = 0.0

        stagnation_scheme = Stagnation(self.config.stagnation_config,
                                       self.reporters)
        reproduction_scheme = Reproduction(self.config.reproduction_config,
                                           self.reporters, stagnation_scheme)
        pop_size = 10
        population = reproduction_scheme.create_new(Genome,
                                                    self.config.genome_config,
                                                    pop_size,
                                                    InnovationStore())
        for genome in population.values():
            genome.fitness = 1

        for genome_id, genome in list(population.items())[:5]:
            # Increase weights for half the genomes to ensure two species
            for g in genome.connections.values():
                g.weight += 50

        species_set = SpeciesSet(self.config.species_set_config,
                                 self.reporters)
        species_set.speciate(self.config, population, generation=1)

        assert 2 == len(species_set.species)

        new_population = reproduction_scheme.reproduce(
            self.config,
            species_set,
            pop_size,
            generation=1,
            innovation_store=InnovationStore(),
            refocus=False)

        old_genomes = population.values()
        new_genomes = new_population.values()

        for old_genome in old_genomes:
            match = False
            for new_genome in new_genomes:
                if old_genome == new_genome:
                    match = True

            if not match:
                return False
예제 #3
0
    def test_compute_num_offspring_negative(self):
        """Test method for computing the number of offspring each species is
        allocated for the next generation when genomes have negative fitnesses.
        """
        stagnation_scheme = Stagnation(self.config.stagnation_config,
                                       self.reporters)
        reproduction_scheme = Reproduction(self.config, self.reporters,
                                           stagnation_scheme)
        popn_size = 10

        # Build Species 1
        genome1 = Genome(key=0,
                         config=self.config.genome_config,
                         innovation_store=InnovationStore())
        genome1.fitness = -30
        genome2 = Genome(key=1,
                         config=self.config.genome_config,
                         innovation_store=InnovationStore())
        genome2.fitness = -40
        species1 = Species(key=1, generation=1)
        species1.update(representative=genome1,
                        members={
                            1: genome1,
                            2: genome2
                        })

        # Build Species 2
        genome3 = Genome(key=2,
                         config=self.config.genome_config,
                         innovation_store=InnovationStore())
        genome3.fitness = -10
        genome4 = Genome(key=3,
                         config=self.config.genome_config,
                         innovation_store=InnovationStore())
        genome4.fitness = -20
        species2 = Species(key=2, generation=1)
        species2.update(representative=genome3,
                        members={
                            3: genome3,
                            4: genome4
                        })

        # Test Offspring numbers
        remaining_species = {1: species1, 2: species2}
        offspring_numbers = reproduction_scheme.compute_num_offspring(
            remaining_species, popn_size)

        assert 10 == sum(offspring_numbers.values())
        assert offspring_numbers[1] == 2
        assert offspring_numbers[2] == 8
예제 #4
0
    def test_reproduce_elitism(self):
        """Test that reproduce produces a population with the correct number of
        elites carried over.
        """
        self.config.reproduction_config.num_elites = 1
        self.config.reproduction_config.elitism_threshold = 1
        self.config.reproduction_config.survival_threshold = 0.8
        self.config.reproduction_config.mutate_only_prob = 1.0

        self.config.genome_config.weight_mutate_prob = 1.0
        self.config.genome_config.node_add_prob = 0.2
        self.config.genome_config.conn_add_prob = 0.5

        stagnation_scheme = Stagnation(self.config.stagnation_config,
                                       self.reporters)
        reproduction_scheme = Reproduction(self.config.reproduction_config,
                                           self.reporters, stagnation_scheme)
        pop_size = 10
        innovation_store = InnovationStore()
        population = reproduction_scheme.create_new(Genome,
                                                    self.config.genome_config,
                                                    pop_size, innovation_store)
        for genome in population.values():
            genome.fitness = 1

        for genome_id, genome in list(population.items())[:5]:
            # Increase weights for half the genomes to ensure two species
            for g in genome.connections.values():
                g.weight += 50

        species_set = SpeciesSet(self.config.species_set_config,
                                 self.reporters)
        species_set.speciate(self.config, population, generation=1)

        assert 2 == len(species_set.species)

        new_population = reproduction_scheme.reproduce(
            self.config,
            species_set,
            pop_size,
            generation=1,
            innovation_store=innovation_store,
            refocus=False)

        assert len(population) == len(new_population)

        num_duplicates = 0
        for old in population.values():
            for new in new_population.values():
                old_attrs = (old.nodes, old.connections, old.inputs,
                             old.outputs, old.biases)
                new_attrs = (new.nodes, new.connections, new.inputs,
                             new.outputs, new.biases)
                if old_attrs == new_attrs:
                    num_duplicates += 1

        assert num_duplicates == 2
예제 #5
0
    def test_reproduce_no_elitism(self):
        """Test that reproduce produces a population with all new genomes if the
        number of elites specified is zero.
        """
        self.config.reproduction_config.num_elites = 0
        self.config.reproduction_config.elitism_threshold = 4
        self.config.reproduction_config.survival_threshold = 0.8

        stagnation_scheme = Stagnation(self.config.stagnation_config,
                                       self.reporters)
        reproduction_scheme = Reproduction(self.config.reproduction_config,
                                           self.reporters, stagnation_scheme)
        pop_size = 10
        innovation_store = InnovationStore()
        population = reproduction_scheme.create_new(Genome,
                                                    self.config.genome_config,
                                                    pop_size, innovation_store)
        for genome in population.values():
            genome.fitness = 1

        for genome_id, genome in list(population.items())[:5]:
            # Increase weights for half the genomes to ensure two species
            for g in genome.connections.values():
                g.weight += 50

        species_set = SpeciesSet(self.config.species_set_config,
                                 self.reporters)
        species_set.speciate(self.config, population, generation=1)

        assert 2 == len(species_set.species)

        new_population = reproduction_scheme.reproduce(
            self.config,
            species_set,
            pop_size,
            generation=1,
            innovation_store=innovation_store,
            refocus=False)

        assert len(population) == len(new_population)
        old_genomes = population.values()
        new_genomes = new_population.values()

        for old_genome in old_genomes:
            for new_genome in new_genomes:
                assert old_genome != new_genome
예제 #6
0
    def test_create_new_population(self):
        """Test creating a new population of genomes.
        """
        # Alter configuration for this test
        self.config.genome_config.num_inputs = 2
        self.config.genome_config.num_outputs = 1
        self.config.genome_config.num_biases = 1
        self.config.genome_config.initial_conn_prob = 1.0

        stagnation_scheme = Stagnation(self.config.stagnation_config,
                                       self.reporters)
        reproduction_scheme = Reproduction(self.config, self.reporters,
                                           stagnation_scheme)
        pop_size = 10
        genomes = reproduction_scheme.create_new(Genome,
                                                 self.config.genome_config,
                                                 pop_size, InnovationStore())

        assert 10 == len(genomes)
        assert 10 == len({id for id in genomes.keys()})
        assert all([len(g.nodes) == 4 for id, g in genomes.items()])
        assert all([len(g.connections) == 3 for id, g in genomes.items()])
예제 #7
0
    def test_generate_parent_pools(self):
        """Test that the worst performing members of each species are being
        culled from the parent pool.
        """
        self.config.reproduction_config.survival_threshold = 0.5
        self.config.genome_config.compatibility_disjoint_coefficient = 0.0
        self.config.genome_config.compatibility_weight_coefficient = 0.0
        self.config.species_set_config.compatibility_threshold = 1.0

        stagnation_scheme = Stagnation(self.config.stagnation_config,
                                       self.reporters)
        reproduction_scheme = Reproduction(self.config.reproduction_config,
                                           self.reporters, stagnation_scheme)
        pop_size = 10

        # Create new population
        population = reproduction_scheme.create_new(Genome,
                                                    self.config.genome_config,
                                                    pop_size,
                                                    InnovationStore())

        # Assign different fitnesses to each member of the population
        for i, genome in enumerate(population.values()):
            genome.fitness = i

        # Speciate the population
        species_set = SpeciesSet(self.config.species_set_config,
                                 self.reporters)
        species_set.speciate(self.config, population, generation=1)

        assert len(species_set.species) == 1

        parent_pools = reproduction_scheme.generate_parent_pools(
            species_set.species)

        # Check that only half of the genomes in the species survived
        assert len(parent_pools) == 1
        assert len(parent_pools[0]) == len(population) / 2
예제 #8
0
    def test_reproduce_filter_stagnant(self):
        """Test that a stagnant population is filtered out.
        """
        self.config.reproduction_config.num_elites = 0
        self.config.reproduction_config.elitism_threshold = 4
        self.config.reproduction_config.survival_threshold = 1.0
        self.config.reproduction_config.crossover_prob = 0.0
        self.config.stagnation_config.species_fitness_func = 'max'
        self.config.stagnation_config.max_stagnation = 10
        self.config.stagnation_config.species_elitism = 0
        self.config.genome_config.weight_mutate_prob = 0.0
        self.config.genome_config.conn_add_prob = 0.0
        self.config.genome_config.node_add_prob = 0.0
        self.config.reproduction_config.crossover_prob = 0.0

        stagnation_scheme = Stagnation(self.config.stagnation_config,
                                       self.reporters)
        reproduction_scheme = Reproduction(self.config.reproduction_config,
                                           self.reporters, stagnation_scheme)
        pop_size = 10
        population0 = reproduction_scheme.create_new(Genome,
                                                     self.config.genome_config,
                                                     pop_size,
                                                     InnovationStore())
        for genome in population0.values():
            genome.fitness = 1

        for genome_id, genome in list(population0.items())[:5]:
            # Increase weights for half the genomes to ensure two species
            for g in genome.connections.values():
                g.weight += 50

        species_set = SpeciesSet(self.config.species_set_config,
                                 self.reporters)
        species_set.speciate(self.config, population0, generation=0)

        assert 2 == len(species_set.species)

        population1 = reproduction_scheme.reproduce(
            self.config,
            species_set,
            pop_size,
            generation=1,
            innovation_store=InnovationStore(),
            refocus=False)
        species_set.speciate(self.config, population1, generation=10)
        for genome in population1.values():
            genome.fitness = 1

        assert 2 == len(species_set.species)

        # Skip to generation 11 to stagnate all species
        population2 = reproduction_scheme.reproduce(
            self.config,
            species_set,
            pop_size,
            generation=11,
            innovation_store=InnovationStore(),
            refocus=False)
        species_set.speciate(self.config, population2, generation=11)
        for genome in population2.values():
            genome.fitness = 1

        assert 0 == len(species_set.species)
예제 #9
0
    def test_xor_highly_redundant_genome(self):
        """Check to see that the correct evaluation is performed for an XOR
         genome that has very high redundancy.
        """
        genome = Genome(0, self.config.genome_config, InnovationStore())

        genome.nodes = {
            0: NodeGene(0, NodeType.INPUT, None),
            1: NodeGene(1, NodeType.INPUT, None),
            2: NodeGene(2, NodeType.OUTPUT, steep_sigmoid_activation),
            3: NodeGene(3, NodeType.BIAS, None),
            10: NodeGene(10, NodeType.HIDDEN, steep_sigmoid_activation),
            33: NodeGene(33, NodeType.HIDDEN, steep_sigmoid_activation),
            44: NodeGene(44, NodeType.HIDDEN, steep_sigmoid_activation),
            77: NodeGene(77, NodeType.HIDDEN, steep_sigmoid_activation),
        }
        genome.connections = {
            4:
            ConnectionGene(4,
                           node_in=0,
                           node_out=2,
                           weight=-2.25,
                           expressed=False),
            5:
            ConnectionGene(5,
                           node_in=1,
                           node_out=2,
                           weight=-2.20,
                           expressed=False),
            6:
            ConnectionGene(6,
                           node_in=3,
                           node_out=2,
                           weight=-3.45,
                           expressed=True),
            11:
            ConnectionGene(11,
                           node_in=1,
                           node_out=10,
                           weight=1.38,
                           expressed=False),
            12:
            ConnectionGene(12,
                           node_in=10,
                           node_out=2,
                           weight=7.61,
                           expressed=True),
            18:
            ConnectionGene(18,
                           node_in=3,
                           node_out=10,
                           weight=-2.19,
                           expressed=True),
            34:
            ConnectionGene(34,
                           node_in=1,
                           node_out=33,
                           weight=1.69,
                           expressed=True),
            35:
            ConnectionGene(35,
                           node_in=33,
                           node_out=10,
                           weight=3.9,
                           expressed=False),
            36:
            ConnectionGene(36,
                           node_in=0,
                           node_out=33,
                           weight=0.5,
                           expressed=True),
            45:
            ConnectionGene(45,
                           node_in=33,
                           node_out=44,
                           weight=-2.01,
                           expressed=False),
            46:
            ConnectionGene(46,
                           node_in=44,
                           node_out=10,
                           weight=0.38,
                           expressed=False),
            78:
            ConnectionGene(78,
                           node_in=33,
                           node_out=77,
                           weight=-0.33,
                           expressed=False),
            79:
            ConnectionGene(79,
                           node_in=77,
                           node_out=44,
                           weight=0.87,
                           expressed=True)
        }

        genome.inputs = [0, 1]
        genome.outputs = [2]
        genome.biases = [3]

        network = NN.create(genome)

        # 2-input XOR inputs
        xor_inputs = [(0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (1.0, 1.0)]

        # Inputs are disconnected from the outputs so the output should be constant
        expected_output = steep_sigmoid_activation(
            7.61 * steep_sigmoid_activation(1 * -2.19) + 1 * -3.45)
        for xi in xor_inputs:
            output = network.forward(xi)
            assert output[0] == pytest.approx(expected_output)
예제 #10
0
    def test_xor(self):
        """Check to see that a correct XOR network is evaluated correctly.
        """
        genome = Genome(0, self.config.genome_config, InnovationStore())

        genome.add_node(-1, -1, NodeType.INPUT)  # Node 0
        genome.add_node(-3, -3, NodeType.INPUT)  # Node 1
        genome.add_node(-2, -2, NodeType.OUTPUT)  # Node 2
        genome.add_bias_node(0)  # Node 3

        genome.add_node(0, 2, NodeType.HIDDEN)  # Node 4
        genome.add_node(1, 2, NodeType.HIDDEN)  # Node 5

        # Connect inputs to hiddens
        genome.add_connection(node_in=0,
                              node_out=4,
                              weight=1.0,
                              expressed=True)
        genome.add_connection(node_in=0,
                              node_out=5,
                              weight=-1.0,
                              expressed=True)
        genome.add_connection(node_in=1,
                              node_out=4,
                              weight=-1.0,
                              expressed=True)
        genome.add_connection(node_in=1,
                              node_out=5,
                              weight=1.0,
                              expressed=True)

        # Connect hiddens to outputs
        genome.add_connection(node_in=4,
                              node_out=2,
                              weight=1.0,
                              expressed=True)
        genome.add_connection(node_in=5,
                              node_out=2,
                              weight=1.0,
                              expressed=True)

        # Add bias connections
        genome.add_connection(node_in=3,
                              node_out=4,
                              weight=-0.5,
                              expressed=True)
        genome.add_connection(node_in=3,
                              node_out=5,
                              weight=-0.5,
                              expressed=True)
        genome.add_connection(node_in=3,
                              node_out=2,
                              weight=-0.5,
                              expressed=True)

        network = NN.create(genome)

        for inputs in ([0, 0], [0, 1], [1, 0], [1, 1]):
            x1, x2 = inputs
            assert network.forward(inputs)[0] == pytest.approx(
                TestFeedForward.xor_output(x1, x2))