def main(numIn, numOut, numGen, popSize, weight_mutpb, con_mutpb, node_mutpb, cxpb):
	# always maintain a global state of all existing connections innov nums
	globalInnovation = ((numIn + 1) * numOut) + 1
	pop = []
	for loop in range(popSize):
		pop.append(Genotype(numIn, numOut))
	
	### ***** MAIN EA LOOP ***** ###
	for g in range(numGen):
		print("RUNNING GENERATION " + str(g))
		# evaluate function handles speciation of population
		if(g == 145):
			visHiddenNodes(pop)
		THRESHOLD = 3.0
		THETA1 = 1.0
		THETA2 = 1.0
		THETA3 = 0.4
		tournSize = 3
		evaluationTup = evaluateFitness_nichecount(pop, THRESHOLD, THETA1, THETA2, THETA3, g)
		species = evaluationTup[0]
		print(len(species))
		AVERAGE_FITNESSES.append(evaluationTup[1])
		#print(len(species))
		popTup = getFittestFromSpecies(species)
		partialPop = popTup[0]
		pop = popTup[1]
		pop = binarySelect(pop, partialPop)
		# always apply mutation and crossover after selection
		applyWeightMutation(pop, weight_mutpb)
		globalInnovation = applyConMutation(pop, con_mutpb, globalInnovation)
		globalInnovation = applyNodeMutation(pop, node_mutpb, globalInnovation)
		#pop = applyCrossover(pop, cxpb)
	
	# return the resultant population after evolution done
	return pop#findFittest(pop)
示例#2
0
def main(nGen, weightMutpb, nodeMutpb, conMutpb, cxPb, actMutpb, thresh, alpha, theta1, theta2, theta3, numIn, numOut):
	pop = toolbox.population()
	# use global innovation object to track the creation of new innovation numbers during evolution
	gb = GlobalInnovation(numIn, numOut)
	
	# the following variables are used to track the improvement of species over generations
	# if a species' fitness becomes stagnant - it is penalized
	MIN_NUM_STAGNANT_GENERATIONS = 35
	STAGNATION_THRESHOLD = 1.05
	LAST_FITNESS = []
	CURRENT_STAG_GENS = []

	# the following is used for modifying the speciation threshold
	GENERATION_TO_MODIFY_THRESH = 30 # this is the first generation that the threshold can begin being adjusted
	DESIRED_NUM_SPECIES = 5
	THRESH_MOD = .1
	LAST_NUM_SPECIES = -1


	for g in range(NGEN):
		print("RUNNING GENERATION " + str(g))

		# use the following conditional to visualize certain properties of population near end of evolution
		if(g == NGEN - 1):
			visConnections(pop)
			visHiddenNodes(pop)

		# create a 2D array representing species from the population
		if(g == 0):
			species = speciatePopulationFirstTime(pop, thresh, theta1, theta2, theta3)
		else:
			species = speciatePopulationNotFirstTime(pop, thresh, theta1, theta2, theta3)

		# determine if speciation threshold needs to be modified and apply modification
		if(g >= GENERATION_TO_MODIFY_THRESH):
			numSpecies = len(species)
			# increase threshold if there are too many species and the number is still increasing
			if(numSpecies > DESIRED_NUM_SPECIES):
				if(LAST_NUM_SPECIES == -1 or numSpecies > LAST_NUM_SPECIES):
					thresh += THRESH_MOD
			# decrease theshold if there are too many species and the number of species is not increasing
			elif(numSpecies < DESIRED_NUM_SPECIES):
				if(LAST_NUM_SPECIES == -1 or numSpecies <= LAST_NUM_SPECIES):
					thresh -= (THRESH_MOD/2.0)


		# find all fitness values for individuals in population, update fitness tracking for species
		for specInd in range(len(species)):
			avgSpecFit = 0.0
			fitnesses = toolbox.map(toolbox.evaluate, species[specInd])
			org_index = 0
			for fit in fitnesses:
				# actual fitness value must be divided by the number of individuals in a given species
				# this keeps any given species from taking over a population - speciation fosters diversity
				fitness = fit[0]/len(species[specInd])
				avgSpecFit += fitness
				species[specInd][org_index].fit_obj.values = (fitness,)
				species[specInd][org_index].fitness = fitness
				org_index += 1
			# must find average fitness of species to compare against previous generation and see if species is stagnant
			avgSpecFit /= len(species[specInd])
			
			# check if fitness is stagnant for current generations and update stagnant counter appropriately
			if(specInd < len(LAST_FITNESS)):
				if(avgSpecFit/LAST_FITNESS[specInd] <= STAGNATION_THRESHOLD):
					CURRENT_STAG_GENS[specInd] = CURRENT_STAG_GENS[specInd] + 1
				else:
					# reset stagnation counter is a species improves enough to be above the threshold
					CURRENT_STAG_GENS[specInd] = 0
			
			# if this is the first generation for a species, append values for it into both stagnation-tracking lists
			else:
				LAST_FITNESS.append(avgSpecFit)
				CURRENT_STAG_GENS.append(0)

		# traverse the list of stagnance counters to see if any species need to be penalized for being stagnant
		index = 0
		for spec in CURRENT_STAG_GENS:
			# if stagnant generations too high, penalize the species
			if(spec >= MIN_NUM_STAGNANT_GENERATIONS):
				# penalizing stagnant species
				for org in species[index]:
					# penalization increases as the number of stagnant generations increases
					org.fitness /= (float(2*spec)/MIN_NUM_STAGNANT_GENERATIONS)
					org.fit_obj.values = (org.fitness,)	
			index += 1

		tournamentSelectSpecies = []

		# speciate the population after finding corresponding fitnesses
		print("Num Species: " + str(len(species)))
		# go through each species and select the best individuals from each species
		for specInd in range(len(species)):
			# set all species back to 0 first:
			for org in species[specInd]:
				org.species = sys.maxsize
			bestInd = toolbox.tournSelect(species[specInd], tournsize = 2, k = 1)[0]
			bestInd = bestInd.getCopy()
			tournamentSelectSpecies.append(bestInd)
		
		# fittest from species function selects all species representatives
		# and sets the species variable for the rest of the population to sys.maxsize
		fitTup = getFittestFromSpecies(species)
		bestInSpecies = fitTup[0]
		pop = fitTup[1]

		for org in tournamentSelectSpecies:
			bestInSpecies.append(org)	

		# select from rest of population to form the full sized population
		pop = toolbox.select(pop, bestInSpecies)

		# only apply mutation if there will be another iteration of selection following this
		if(g < NGEN - 1):
			# apply weight mutations
			for ind in pop:
				if(ind.species == sys.maxsize and np.random.uniform() <= weightMutpb):
					toolbox.weightMutate(ind)
					# must invalidate individuals fitness if mutation applied
					del ind.fit_obj.values
			
			# apply node mutations
			for ind in pop:
				if(ind.species == sys.maxsize and np.random.uniform() <= nodeMutpb):
					toolbox.nodeMutate(ind, gb)
					del ind.fit_obj.values

			# apply connection mutations
			for ind in pop:
				if(ind.species == sys.maxsize and np.random.uniform() <= conMutpb):
					toolbox.connectionMutate(ind, gb)
					del ind.fit_obj.values
			
			# apply crossover
			# go through population looking at every pair of individuals next to each other 
			for child1Ind, child2Ind in zip(range(0,len(pop),2), range(1,len(pop),2)):
				interspecies_probability = .001 # probability individuals crossed over if not in same species
				child1 = pop[child1Ind]
				child2 = pop[child2Ind]
				dist = child1.getDistance(child2, theta1, theta2, theta3)

				# crossover happens with different probability depending if individuals in question are in same species
				if(child1.species == sys.maxsize and child2.species == sys.maxsize and dist < thresh and np.random.uniform() <= cxPb):
					# cross individuals over and put them into the population
					xTup = toolbox.mate(child1, child2)
					pop[child1Ind] = xTup[0]
					pop[child2Ind] = xTup[1]
					del pop[child1Ind].fit_obj.values
					del pop[child2Ind].fit_obj.values
				elif(child1.species == sys.maxsize and child2.species == sys.maxsize and np.random.uniform() <= interspecies_probability):
					xTup = toolbox.mate(child1, child2)
					pop[child1Ind] = xTup[0]
					pop[child2Ind] = xTup[1]
					del pop[child1Ind].fit_obj.values
					del pop[child2Ind].fit_obj.values
			
			# apply activation mutation
			for ind in pop:
				if(ind.species == sys.maxsize and np.random.uniform() <= actMutpb):
					toolbox.activationMutate(ind)
					del ind.fit_obj.values

		# must clear the dictionary of innovation numbers for the coming generation
		# only check to see if same innovation occurs twice in a single generation
		gb.clearDict()

	# return the population after it has been evolved
	return pop
示例#3
0
def main(nGen, weightMutpb, nodeMutpb, conMutpb, cxPb, actMutpb, thresh, alpha,
         theta1, theta2, theta3, numIn, numOut):
    pop = toolbox.population()
    # use global innovation object to track the creation of new innovation numbers during evolution
    gb = GlobalInnovation(numIn, numOut)

    # used to check whether a species fitness becomes stagnant
    LAST_FITNESS = []
    CURRENT_STAG_GENS = []

    for g in range(NGEN):
        print("RUNNING GENERATION " + str(g))

        # use the following conditional to visualize certain properties of population near end of evolution
        #if(g == NGEN - 1):
        #	visConnections(pop)
        #	visHiddenNodes(pop)

        # create a 2D array representing species from the population
        if (g == 0):
            species = speciatePopulationFirstTime(pop, thresh, theta1, theta2,
                                                  theta3)
        else:
            species = speciatePopulationNotFirstTime(pop, thresh, theta1,
                                                     theta2, theta3)

        # determine if speciation threshold needs to be modified and apply modification
        # decrease threshold slowly to increase species, but increase quickly to keep to many
        # species from forming - thus the terms being different sizes
        if (g >= GENERATION_TO_MODIFY_THRESH):
            numSpecies = len(species)
            # increase threshold if there are too many species and the number is still increasing
            if (numSpecies > DESIRED_NUM_SPECIES):
                if (LAST_NUM_SPECIES == -1 or numSpecies > LAST_NUM_SPECIES):
                    thresh += THRESH_MOD * 2.0
            # decrease theshold if there are too many species and the number of species is not increasing
            elif (numSpecies < DESIRED_NUM_SPECIES):
                if (LAST_NUM_SPECIES == -1 or numSpecies <= LAST_NUM_SPECIES):
                    thresh -= (THRESH_MOD / 2.0)

        # find all fitness values for individuals in population, update fitness tracking for species
        for specInd in range(len(species)):
            avgSpecFit = 0.0
            # only the output pixels are mapped back, all evaluation must be done below
            outputs = toolbox.map(toolbox.evaluate, species[specInd])
            output_tups = []
            for o in outputs:
                output_tups.append((o[0], PIXELS, len(species[specInd]),
                                    MATERIAL_PENALIZATION_THRESHOLD,
                                    MATERIAL_UNPRESENT_PENALIZATION))

            # map all outputs to the genotypes with their actual fitness assigned
            fitnesses = toolbox.map(toolbox.assign_fit, output_tups)
            org_ind = 0
            for f in fitnesses:
                gen = species[specInd][org_ind]
                avgSpecFit += f[0]
                gen.fit_obj.values = f
                gen.fitness = f[0]
                org_ind += 1

            # must find average fitness of species to compare against previous generation and see if species is stagnant
            avgSpecFit /= len(species[specInd])
            '''
			org_ind = 0
			for out in outputs:
				gen = species[specInd][org_ind]
				out = out[0] # original list is inside of a tuple with the genotype
				proportion_mat_used = float(np.sum(out))/len(PIXELS)
				penalization = 1.0
				if(proportion_mat_used <= MATERIAL_PENALIZATION_THRESHOLD):
					penalization = 2.0 * (MATERIAL_PENALIZATION_THRESHOLD / (proportion_mat_used + .001))
				# find difference between the two pixel arrays
				ones_arr = np.ones((1, len(PIXELS)))
				diff = np.subtract(PIXELS, out)
				diff[diff>=.5] *= MATERIAL_UNPRESENT_PENALIZATION
				diff = np.fabs(diff)
				total_fit = (np.sum(np.subtract(ones_arr, diff)))/(len(species[specInd])*penalization)

				# actual fitness value must be divided by the number of individuals in a given species
				# this keeps any given species from taking over a population - speciation fosters diversity
				avgSpecFit += total_fit
				gen.fit_obj.values = (total_fit,)
				gen.fitness = total_fit
				spec_list.append(gen)
				org_ind += 1
			'''

            # check if fitness is stagnant for current generations and update stagnant counter appropriately
            if (specInd < len(LAST_FITNESS)):
                if (avgSpecFit / LAST_FITNESS[specInd] <=
                        STAGNATION_THRESHOLD):
                    CURRENT_STAG_GENS[specInd] = CURRENT_STAG_GENS[specInd] + 1
                else:
                    # reset stagnation counter is a species improves enough to be above the threshold
                    CURRENT_STAG_GENS[specInd] = 0

            # if this is the first generation for a species, append values for it into both stagnation-tracking lists
            else:
                LAST_FITNESS.append(avgSpecFit)
                CURRENT_STAG_GENS.append(0)

        # traverse the list of stagnance counters to see if any species need to be penalized for being stagnant
        index = 0
        for spec in CURRENT_STAG_GENS:
            # if stagnant generations too high, penalize the species
            if (spec >= MIN_NUM_STAGNANT_GENERATIONS):
                # penalizing stagnant species
                for org in species[index]:
                    # penalization increases as the number of stagnant generations increases
                    org.fitness /= (float(2 * spec) /
                                    MIN_NUM_STAGNANT_GENERATIONS)
                    org.fit_obj.values = (org.fitness, )
            index += 1

        tournamentSelectSpecies = []

        # speciate the population after finding corresponding fitnesses
        print("Num Species: " + str(len(species)))
        # go through each species and select the best individuals from each species
        for specInd in range(len(species)):
            # set all species back to 0 first:
            for org in species[specInd]:
                org.species = sys.maxsize
            bestInd = toolbox.tournSelect(species[specInd], tournsize=2,
                                          k=1)[0]
            bestInd = bestInd.getCopy()
            tournamentSelectSpecies.append(bestInd)

        # fittest from species function selects all species representatives
        # and sets the species variable for the rest of the population to sys.maxsize
        fitTup = getFittestFromSpecies(species)
        bestInSpecies = fitTup[0]
        pop = fitTup[1]

        for org in tournamentSelectSpecies:
            bestInSpecies.append(org)

        # select from rest of population to form the full sized population
        pop = toolbox.select(pop, bestInSpecies)

        # only apply mutation if there will be another iteration of selection following this
        if (g < NGEN - 1):
            # apply weight mutations
            for ind in pop:
                if (ind.species == sys.maxsize
                        and np.random.uniform() <= weightMutpb):
                    toolbox.weightMutate(ind)
                    # must invalidate individuals fitness if mutation applied
                    del ind.fit_obj.values

            # apply node mutations
            for ind in pop:
                if (ind.species == sys.maxsize
                        and np.random.uniform() <= nodeMutpb):
                    toolbox.nodeMutate(ind, gb)
                    del ind.fit_obj.values

            # apply connection mutations
            for ind in pop:
                if (ind.species == sys.maxsize
                        and np.random.uniform() <= conMutpb):
                    toolbox.connectionMutate(ind, gb)
                    del ind.fit_obj.values

            # apply crossover
            # go through population looking at every pair of individuals next to each other
            for child1Ind, child2Ind in zip(range(0, len(pop), 2),
                                            range(1, len(pop), 2)):
                interspecies_probability = .001  # probability individuals crossed over if not in same species
                child1 = pop[child1Ind]
                child2 = pop[child2Ind]
                dist = child1.getDistance(child2, theta1, theta2, theta3)

                # crossover happens with different probability depending if individuals in question are in same species
                if (child1.species == sys.maxsize
                        and child2.species == sys.maxsize and dist < thresh
                        and np.random.uniform() <= cxPb):
                    # cross individuals over and put them into the population
                    xTup = toolbox.mate(child1, child2)
                    pop[child1Ind] = xTup[0]
                    pop[child2Ind] = xTup[1]
                    del pop[child1Ind].fit_obj.values
                    del pop[child2Ind].fit_obj.values
                elif (child1.species == sys.maxsize
                      and child2.species == sys.maxsize
                      and np.random.uniform() <= interspecies_probability):
                    xTup = toolbox.mate(child1, child2)
                    pop[child1Ind] = xTup[0]
                    pop[child2Ind] = xTup[1]
                    del pop[child1Ind].fit_obj.values
                    del pop[child2Ind].fit_obj.values

            # apply activation mutation
            for ind in pop:
                if (ind.species == sys.maxsize
                        and np.random.uniform() <= actMutpb):
                    toolbox.activationMutate(ind)
                    del ind.fit_obj.values

        # must clear the dictionary of innovation numbers for the coming generation
        # only check to see if same innovation occurs twice in a single generation
        gb.clearDict()

    # return the population after it has been evolved
    return pop