예제 #1
0
def evolve(_run,
           _epoch):

    if get_rank() != 0:
       return

    print("\n======[ Evolving ecosystem ]======\n")

    # Set the offspring count to 0
    cs.Species.Offspring = 0

    if not Conf.UnitTestMode:

        # Increase the age of all networks.
        for net in cn.Net.Ecosystem.values():
            net.age += 1

        if _epoch < Conf.Epochs:

            # Evolve networks in all species.
            wheel = Rand.RouletteWheel()

            for species_id, species in cs.Species.Populations.items():
                wheel.add(species_id, species.fitness.relative)

            while not wheel.is_empty():
                cs.Species.Populations[wheel.pop()].evolve()
예제 #2
0
def test_crossover():

    wheel = Rand.RouletteWheel()
    wheel.add('add_layer', 1)
    wheel.add('remove_layer', 1)
    wheel.add('add_node', 1)
    wheel.add('remove_node', 1)
    wheel.add('grow_kernel', 1)
    wheel.add('shrink_kernel', 1)

    nets = [ctx.cn.Net(_isolated = True) for _ in range(20)]

    for mut in range(10):
        for n in range(len(nets)):
            mutation = wheel.spin()

            net = nets[n]

            if mutation == 'add_layer':
                net.add_layer()

            elif mutation == 'add_node':
                net.add_nodes()

            elif mutation == 'grow_kernel':
                net.grow_kernel()

            if mutation == 'remove_layer':
                net.remove_layer()

            elif mutation == 'remove_node':
                net.remove_nodes()

            elif mutation == 'shrink_kernel':
                net.shrink_kernel()

            model = net.to('cpu')
            match = list(model(torch.randn(ctx.Conf.TrainBatchSize, *ctx.cn.Net.Input.Shape)).size()) == [ctx.Conf.TrainBatchSize, len(net.layers[-1].nodes)]
            if not utest.pass_fail(match, "\tEvaluating the mutated network with random input..."):
                net.print()

    for p1 in range(len(nets)):
        for p2 in range(len(nets)):

            if p1 != p2:

                offspring = ctx.cn.Net(_p1 = nets[p1], _p2 = nets[p2], _isolated = True)

                model = offspring.to('cpu')
                match = list(model(torch.randn(ctx.Conf.TrainBatchSize, *ctx.cn.Net.Input.Shape)).size()) == [ctx.Conf.TrainBatchSize, len(net.layers[-1].nodes)]
                if not utest.pass_fail(match, "\tEvaluating the offspring network with random input..."):
                    offspring.print()
예제 #3
0
def get_random_stride(
    _input_shape,
    _stride=[]
):  # Pre-determined stride. Dimensions with value 0 are populated with random values.

    wheel = Rand.RouletteWheel()

    print('Input shape: {}'.format(_input_shape))

    strides = []
    # Possible strides.
    for dim, radius in enumerate(_input_shape[1:]):

        if (len(_stride) > 0 and _stride[dim] > 0):
            stride = [_stride[dim]]

        else:
            if radius <= 1:
                stride = [1]

            else:
                stride = [s for s in range(1, radius // 2 + 1)]

        if len(strides) == 0:
            strides = [[s] for s in stride]

        else:
            new_strides = []

            for old_stride in strides:
                for new_stride in stride:
                    new_strides.append([*old_stride, new_stride])

            strides = new_strides

        print('Stride: {}'.format(stride))
        print('Strides: {}'.format(strides))

    for s in strides:
        wheel.add(s, Func.exp_prod(s))


#        for idx in range(len(wheel.elements)):
#            print(wheel.elements[idx], "\t", wheel.weights[Rand.WeightType.Raw][idx], "\t", wheel.weights[Rand.WeightType.Inverse][idx])

    return wheel.spin()
예제 #4
0
def test_random_kernel_size(_max=28, _draws=1000):

    wheel = Rand.RouletteWheel()

    for i in range(1, _max):
        if i % 2 == 1:
            wheel.add(i, math.exp(-i))

    kernels = {}
    for draw in range(_draws):
        k = wheel.spin()

        if k not in kernels.keys():
            kernels[k] = 0
        kernels[k] += 1

    for key in sorted(kernels):
        print(key, ":", kernels[key])
예제 #5
0
def cull():

    if get_rank() != 0:
        return

    print("\n======[ Culling ecosystem ]======\n")

    wheel = Rand.RouletteWheel(Rand.WeightType.Inverse)

    for net_id, net in cn.Net.Ecosystem.items():
        if (net.age > 0 and
            net_id != cn.Net.Champion):
            # Old, unfit and simple networks
            # are more likely to be eliminated.
            wheel.add(net_id, net.fitness.relative * net.complexity / net.age)

    removed_nets = []
    removed_species = []
    while len(cn.Net.Ecosystem) > cn.Net.Max.Count:

        # Get a random network ID
        net_id = wheel.pop()

        if net_id is not None:

            species_id = cn.Net.Ecosystem[net_id].species_id

#            print('Removing network {} from species {}'.format(net_id, species_id))
            removed_nets.append(net_id)

            # Remove the network from the species.
            cs.Species.Populations[species_id].nets.remove(net_id)

            # Remove the network from the ecosystem.
            del cn.Net.Ecosystem[net_id]

        if len(cs.Species.Populations[species_id].nets) == 0:
            removed_species.append(species_id)
            del cs.Species.Populations[species_id]

    if len(removed_nets) > 0:
        print(f'Removed nets: {removed_nets}')
    if len(removed_species) > 0:
        print(f'Removed species: {removed_species}')
예제 #6
0
def test_random_functions():

    print("ND:", Rand.ND())
    print("negND:", Rand.negND())
    print("posND:", Rand.posND())
    print("uni_real(-100.0,100.0):", Rand.uni_real(-100.0, 100.0))
    print("uni_int(-100,100):", Rand.uni_int(-100, 100))

    print("\n===[ Roulette wheel selection ]===\n")
    weights = [5, 3, 100, 67, 22, 0, 1e-3]
    array = [n for n in range(len(weights))]

    wheel = Rand.RouletteWheel()
    print("Array:", array)
    print("Weights:", weights)
    for index, elem in enumerate(array):
        wheel.add(elem, weights[index])

    samples = {}
    draws = 10000
    for _ in range(draws):
        sample = wheel.spin()
        if sample in samples:
            samples[sample] += 1
        else:
            samples[sample] = 1

    print("\nArray samples ({} draws):".format(draws))
    for key in sorted(samples.keys()):
        print("\t", key, ":", samples[key])

    print("\n===[ Random key and value from table ]===\n")

    table = {1: "one", 2: "two", 3: "three", 4: "four", 5: "five"}

    print("Table:")
    for key in sorted(table.keys()):
        print("\t", key, ":", table[key])

    print("key:", Rand.key(table))
    print("val:", Rand.val(table))
예제 #7
0
def test_random_mutations():

    for i in range(10):

        wheel = Rand.RouletteWheel()
        wheel.add('add_layer', 1)
        wheel.add('add_node', 1)
        wheel.add('grow_kernel', 1)

        original_net = ctx.Net(_isolated=True)

        # Clone the network
        net = ctx.Net(_p1=original_net, _isolated=True)

        assert (utest.pass_fail(
            net.matches(original_net),
            "Comparing the original network with the cloned one..."))

        mutations = []

        for mut in range(100):
            mutation = wheel.spin()
            success = False
            if mutation == 'add_layer':
                success, layer = net.add_layer(_test=True)
                if success:
                    mutations.append((mutation, layer))
            elif mutation == 'add_node':
                success, layer, nodes = net.add_nodes()
                if success:
                    mutations.append((mutation, layer, nodes))
            elif mutation == 'grow_kernel':
                success, layer, kernel, delta = net.grow_kernel()
                if success:
                    mutations.append((mutation, layer, kernel, delta))

            if success:
                print("(", mut + 1, ") Mutation:", *mutations[-1])
            model = net.to('cpu')
            assert (model(torch.randn(ctx.TrainBatchSize,
                                      *ctx.Net.Input.Shape)).size())

        print("\n==============[ Reversing mutations ]==============\n")

        for mut in range(len(mutations)):
            mutation = mutations[len(mutations) - mut - 1]
            success = False
            if mutation[0] == 'add_layer':
                success, layer = net.remove_layer(mutation[1])
                #if success:
                #print("Layer", layer, "removed")
            elif mutation[0] == 'add_node':
                success, layer, node = net.remove_nodes(
                    mutation[1], _node_indices=mutation[2])
                #if success:
                #print("Node", *nodes, "removed from layer", layer)
            elif mutation[0] == 'grow_kernel':
                success, layer, kernel, delta = net.shrink_kernel(
                    mutation[1], mutation[2], mutation[3])
                #if success:
                #print("Dimension", *delta.keys(), "of kernel", kernel, "in layer", layer, "decreased by", abs(*delta.values()))

            assert (utest.pass_fail(success, "Reversing mutation",
                                    len(mutations) - mut, "(", mutation,
                                    ")..."))
            model = net.to('cpu')
            output = model(
                torch.randn(ctx.TrainBatchSize, *ctx.Net.Input.Shape))

        assert (utest.pass_fail(
            net.matches(original_net),
            "Comparing the original network with the one with reversed mutations..."
        ))

        print(
            "======================[ Original network ]======================")
        original_net.print()

        print(
            "======================[ Mutated network ]=======================")
        net.print()

        model1 = net.to('cpu')
        model2 = original_net.to('cpu')

        input1 = torch.randn(ctx.TrainBatchSize, *ctx.Net.Input.Shape)
        input2 = torch.zeros(input1.size())
        input2.data = input1.data

        print("Input1:", input1, ", size:", input1.size())
        print("Input2:", input2, ", size:", input2.size())

        output1 = model1(input1)
        output2 = model2(input2)

        assert (utest.pass_fail(torch.allclose(output1, output2),
                                "Comparing the two outputs..."))

        print(output1)
        print(output2)
예제 #8
0
    def evolve(self):

        import cortex.network as cn

        # Populate the parent wheel.
        # Networks that have been selected for crossover
        # will pick a partner at random by spinning the wheel.
        parent1_wheel = Rand.RouletteWheel()
        parent2_wheel = Rand.RouletteWheel()
        for net_id in self.nets:
            if cn.Net.Ecosystem[net_id].age > 0:
                parent1_wheel.add(net_id,
                                  cn.Net.Ecosystem[net_id].fitness.relative)
                parent2_wheel.add(net_id,
                                  cn.Net.Ecosystem[net_id].fitness.relative)

        # Iterate over the networks and check if we should perform crossover or mutation
        while not parent1_wheel.is_empty():

            # Choose one parent
            p1 = cn.Net.Ecosystem[parent1_wheel.pop()]

            # Choose a partner
            p2 = cn.Net.Ecosystem[parent2_wheel.spin()]

            # Fitter networks have a better chance of mating.
            # Take the average of the two parents' relative fitness values
            mating_chance = 0.5 * (p1.fitness.relative + p2.fitness.relative
                                   ) / (Species.Offspring + 1)
            if not Species.Enabled:
                mating_chance *= p1.genome_overlap(p2)

#            print(f'Chance of mating nets {p1.ID} and {p2.ID}: {mating_chance}')

            if (Species.Offspring < len(cn.Net.Ecosystem) // 2
                    and Rand.chance(mating_chance)):

                if p1 != p2:
                    # Crossover
                    offspring = cn.Net(_p1=p1, _p2=p2)

                else:
                    # Clone
                    offspring = cn.Net(_p1=p1)
                    offspring.mutate(_structure=False)

                # Increase the offspring count
                Species.Offspring += 1

            elif (p1 != self.champion
                  and Rand.chance(1.0 - self.fitness.stat.get_offset())):

                #                probabilities = {
                #                                'layer': 1,
                #                                'node': 1,
                #                                'stride': 1,
                #                                'kernel': 1
                #                                }
                #                p1.mutate(_probabilities = probabilities)

                p1.mutate()

                if p1.species_id != self.ID:
                    # The network has moved to another species.
                    # Remove it from the other wheel.
                    parent2_wheel.remove(p1.ID)