def run_evolution(use_palette=False): # get the start time start_time = time.time() # initialize new population population = Population(POPULATION_SIZE, ELITE_SIZE, MUTATIONS_NUMBER, use_palette) # report the state of population report(population, 0, time.time() - start_time) generations = np.array([]) fitness = np.array([]) # develop the population declared number of times for generation in range(GENERATIONS_NUMBER): # get the start time start_time = time.time() # perform the selection, crossover and mutation over the population population.selection() population.crossover() population.mutation() # report the state of population report(population, generation + 1, time.time() - start_time) generations = np.append(generations, generation) fitness = np.append(fitness, get_fitness(population)) if generation % 20 == 0: plot_fitness(generations, fitness) # resultant individual will be the fittest one in the list of individuals result = Image.fromarray( utils.restore_image(population.population[0]['individual'])) return result
def report(population, generation, runtime): """ Method that report current information about the state of the population and saves the fittest individual. :param population: current state of population. :param generation: generation sequence number. :param runtime: execution time of program on this generation. """ # get the fittest individual fittest = population.population[0] # create directory if needed try: # try to save a RGB image result = Image.fromarray(utils.restore_image(fittest['individual'])) result = result.convert('RGB') generation_str = str(generation) nulls = '' for i in range(5 - len(generation_str)): nulls += '0' filename = f'documents/output/{FILE_NAME}/{nulls + generation_str}.jpeg' os.makedirs(os.path.dirname(filename), exist_ok=True) result.save(filename) status = 'Saved' except Exception: status = 'Not saved' print( f"Generation #{generation}: Fitness achieved is {get_fitness(population)}, runtime is {runtime} seconds, {status}" )
def _multiprocessing_mutation(individual): """ Method used for multiprocessing computations at the mutation stage. Mutate the chromosome of individual. Restore image from chromosome and calculates fitness of individual. :param individual: member of population. :return: dictionary comprising of individual and its fitness. """ individual['individual'].mutate() individual_image = utils.restore_image(individual['individual']) individual_fitness = _calculate_fitness(individual_image) individual['fitness'] = individual_fitness return individual
def _multiprocessing_init(individual): """ Method used for multiprocessing computations at the initial stage. Restore image from the chromosome of individual and calculates its fitness. :param individual: member of population. :return: dictionary comprising of individual and its fitness. """ individual_image = utils.restore_image(individual) individual_fitness = _calculate_fitness(individual_image) population_entry = { 'individual': individual, 'fitness': individual_fitness } return population_entry
def _multiprocessing_crossover(parents, number_mutations): # unpack parents of the spring parent1, parent2 = parents # observation showed that passing random genes to an offspring yields better in terms of fitness function result # rather than using a crossover point offspring_chromosome = [] for i in range(GENES_NUMBER): # randomly choose gene either from first or second parent gene = choice([ parent1['individual'].chromosome[i], parent2['individual'].chromosome[i] ]) offspring_chromosome.append(gene) offspring = Individual(offspring_chromosome, number_mutations, parent1['individual'].use_palette) offspring_image = utils.restore_image(offspring) offspring_fitness = _calculate_fitness(offspring_image) offspring_entry = {'individual': offspring, 'fitness': offspring_fitness} return offspring_entry