def next_generation(self): self._increment_generation() self._current_individual = 0 # Calculate fitness of individuals for individual in self.population.individuals: individual.calculate_fitness() self.population.individuals = elitism_selection(self.population, self.settings['num_parents']) random.shuffle(self.population.individuals) next_pop: List[Snake] = [] # parents + offspring selection type ('plus') if self.settings['selection_type'].lower() == 'plus': # Decrement lifespan for individual in self.population.individuals: individual.lifespan -= 1 for individual in self.population.individuals: params = individual.network.params board_size = individual.board_size hidden_layer_architecture = individual.hidden_layer_architecture hidden_activation = individual.hidden_activation output_activation = individual.output_activation lifespan = individual.lifespan apple_and_self_vision = individual.apple_and_self_vision start_pos = individual.start_pos apple_seed = individual.apple_seed starting_direction = individual.starting_direction # If the individual is still alive, they survive if lifespan > 0: s = Snake(board_size, chromosome=params, hidden_layer_architecture=hidden_layer_architecture, hidden_activation=hidden_activation, output_activation=output_activation, lifespan=lifespan, apple_and_self_vision=apple_and_self_vision)#, next_pop.append(s) while len(next_pop) < self._next_gen_size: p1, p2 = roulette_wheel_selection(self.population, 2) L = len(p1.network.layer_nodes) c1_params = {} c2_params = {} # Each W_l and b_l are treated as their own chromosome. # Because of this I need to perform crossover/mutation on each chromosome between parents for l in range(1, L): p1_W_l = p1.network.params['W' + str(l)] p2_W_l = p2.network.params['W' + str(l)] p1_b_l = p1.network.params['b' + str(l)] p2_b_l = p2.network.params['b' + str(l)] # Crossover # @NOTE: I am choosing to perform the same type of crossover on the weights and the bias. c1_W_l, c2_W_l, c1_b_l, c2_b_l = self._crossover(p1_W_l, p2_W_l, p1_b_l, p2_b_l) # Mutation # @NOTE: I am choosing to perform the same type of mutation on the weights and the bias. self._mutation(c1_W_l, c2_W_l, c1_b_l, c2_b_l) # Assign children from crossover/mutation c1_params['W' + str(l)] = c1_W_l c2_params['W' + str(l)] = c2_W_l c1_params['b' + str(l)] = c1_b_l c2_params['b' + str(l)] = c2_b_l # Clip to [-1, 1] np.clip(c1_params['W' + str(l)], -1, 1, out=c1_params['W' + str(l)]) np.clip(c2_params['W' + str(l)], -1, 1, out=c2_params['W' + str(l)]) np.clip(c1_params['b' + str(l)], -1, 1, out=c1_params['b' + str(l)]) np.clip(c2_params['b' + str(l)], -1, 1, out=c2_params['b' + str(l)]) # Create children from chromosomes generated above c1 = Snake(p1.board_size, chromosome=c1_params, hidden_layer_architecture=p1.hidden_layer_architecture, hidden_activation=p1.hidden_activation, output_activation=p1.output_activation, lifespan=self.settings['lifespan']) c2 = Snake(p2.board_size, chromosome=c2_params, hidden_layer_architecture=p2.hidden_layer_architecture, hidden_activation=p2.hidden_activation, output_activation=p2.output_activation, lifespan=self.settings['lifespan']) # Add children to the next generation next_pop.extend([c1, c2]) # Set the next generation random.shuffle(next_pop) self.population.individuals = next_pop
def next_generation(self) -> None: if self.state == States.NEXT_GEN: self.stats_window.pop_size.setText(str(self._next_gen_size)) self.current_batch = 0 # Set next state to copy parents if its plus, otherwise comma is just going to create offspring if get_ga_constant('selection_type').lower() == 'plus': self.state = States.NEXT_GEN_COPY_PARENTS_OVER elif get_ga_constant('selection_type').lower() == 'comma': self.state = States.NEXT_GEN_CREATE_OFFSPRING else: raise Exception('Invalid selection_type: "{}"'.format( get_ga_constant('selection_type'))) self._offset_into_population = 0 self._total_individuals_ran = 0 # Reset back to the first individual self.population.individuals = self._next_pop self._next_pop = [] # Reset the next pop # Calculate fit for individual in self.population.individuals: individual.calculate_fitness() # Should we save the pop if args.save_pop: path = os.path.join( args.save_pop, 'pop_gen{}'.format(self.current_generation)) if os.path.exists(path): raise Exception( '{} already exists. This would overwrite everything, choose a different folder or delete it and try again' .format(path)) os.makedirs(path) save_population(path, self.population, settings.settings) # Save best? if args.save_best: save_car(args.save_best, 'car_{}'.format(self.current_generation), self.population.fittest_individual, settings.settings) self._set_previous_gen_avg_fitness() self._set_previous_gen_num_winners() self._increment_generation() # Grab the best individual and compare to best fitness best_ind = self.population.fittest_individual if best_ind.fitness > self.max_fitness: self.max_fitness = best_ind.fitness self._set_max_fitness() self.gen_without_improvement = 0 else: self.gen_without_improvement += 1 # Set text for gen improvement self.stats_window.gens_without_improvement.setText( str(self.gen_without_improvement)) # Set the population to be just the parents allowed for reproduction. Only really matters if `plus` method is used. # If `plus` method is used, there can be more individuals in the next generation, so this limits the number of parents. self.population.individuals = elitism_selection( self.population, get_ga_constant('num_parents')) random.shuffle(self.population.individuals) # Parents + offspring selection type ('plus') if get_ga_constant('selection_type').lower() == 'plus': # Decrement lifespan for individual in self.population.individuals: individual.lifespan -= 1 num_offspring = min(self._next_gen_size - len(self._next_pop), get_boxcar_constant('run_at_a_time')) self.cars = self._create_num_offspring(num_offspring) # Set number of cars alive self.num_cars_alive = len(self.cars) self.batch_size = self.num_cars_alive self.current_batch += 1 self._set_number_of_cars_alive() self._next_pop.extend(self.cars) # Add to next_pop self.game_window.cars = self.cars leader = self.find_new_leader() self.leader = leader self.game_window.leader = leader if get_ga_constant('selection_type').lower() == 'comma': self.state = States.NEXT_GEN_CREATE_OFFSPRING elif get_ga_constant('selection_type').lower( ) == 'plus' and self._offset_into_population >= len( self.population.individuals): self.state = States.NEXT_GEN_CREATE_OFFSPRING
def next_generation(self): self._increment_generation() self._current_individual = 0 self.population.individuals = elitism_selection( self.population, self.settings['num_parents']) random.shuffle(self.population.individuals) next_pop: List[Puzzle] = [] # parents + offspring selection type ('plus') if self.settings['selection_type'].lower() == 'plus': for individual in self.population.individuals: params = individual.network.params board_size = individual.board_size hidden_layer_architecture = individual.hidden_layer_architecture hidden_activation = individual.hidden_activation output_activation = individual.output_activation # If the individual is still alive, they survive if individual._fitness < 1000: nrG = random.randint(self.nrGroupRange[0], self.nrGroupRange[1]) nrC = random.randint(self.nrBlocksRange[0], self.nrBlocksRange[1]) s = Puzzle( board_size, nrG, nrC, chromosome=params, hidden_layer_architecture=hidden_layer_architecture, hidden_activation=hidden_activation, output_activation=output_activation) next_pop.append(s) while len(next_pop) < self._next_gen_size: p1, p2 = roulette_wheel_selection(self.population, 2) L = len(p1.network.layer_nodes) c1_params = {} c2_params = {} # Each W_l and b_l are treated as their own chromosome. # Because of this I need to perform crossover/mutation on each chromosome between parents for l in range(1, L): p1_W_l = p1.network.params['W' + str(l)] p2_W_l = p2.network.params['W' + str(l)] p1_b_l = p1.network.params['b' + str(l)] p2_b_l = p2.network.params['b' + str(l)] # Crossover # @NOTE: I am choosing to perform the same type of crossover on the weights and the bias. c1_W_l, c2_W_l, c1_b_l, c2_b_l = self._crossover( p1_W_l, p2_W_l, p1_b_l, p2_b_l) # Mutation # @NOTE: I am choosing to perform the same type of mutation on the weights and the bias. self._mutation(c1_W_l, c2_W_l, c1_b_l, c2_b_l) # Assign children from crossover/mutation c1_params['W' + str(l)] = c1_W_l c2_params['W' + str(l)] = c2_W_l c1_params['b' + str(l)] = c1_b_l c2_params['b' + str(l)] = c2_b_l # Clip to [-1, 1] np.clip(c1_params['W' + str(l)], -1, 1, out=c1_params['W' + str(l)]) np.clip(c2_params['W' + str(l)], -1, 1, out=c2_params['W' + str(l)]) np.clip(c1_params['b' + str(l)], -1, 1, out=c1_params['b' + str(l)]) np.clip(c2_params['b' + str(l)], -1, 1, out=c2_params['b' + str(l)]) # Create children from chromosomes generated above nrG = random.randint(self.nrGroupRange[0], self.nrGroupRange[1]) nrC = random.randint(self.nrBlocksRange[0], self.nrBlocksRange[1]) c1 = Puzzle(p1.board_size, nrG, nrC, chromosome=c1_params, hidden_layer_architecture=p1.hidden_layer_architecture, hidden_activation=p1.hidden_activation, output_activation=p1.output_activation) nrG = random.randint(self.nrGroupRange[0], self.nrGroupRange[1]) nrC = random.randint(self.nrBlocksRange[0], self.nrBlocksRange[1]) c2 = Puzzle(p2.board_size, nrG, nrC, chromosome=c2_params, hidden_layer_architecture=p2.hidden_layer_architecture, hidden_activation=p2.hidden_activation, output_activation=p2.output_activation) # Add children to the next generation next_pop.extend([c1, c2]) # Set the next generation random.shuffle(next_pop) self.population.individuals = next_pop
def next_generation(self) -> None: self._increment_generation() self._current_individual = 0 if not args.no_display: self.info_window.current_individual.setText('{}/{}'.format( self._current_individual + 1, self._next_gen_size)) # Calculate fitness # print(', '.join(['{:.2f}'.format(i.fitness) for i in self.population.individuals])) if args.debug: print( f'----Current Gen: {self.current_generation}, True Zero: {self._true_zero_gen}' ) fittest = self.population.fittest_individual print( f'Best fitness of gen: {fittest.fitness}, Max dist of gen: {fittest.farthest_x}' ) num_wins = sum(individual.did_win for individual in self.population.individuals) pop_size = len(self.population.individuals) print( f'Wins: {num_wins}/{pop_size} (~{(float(num_wins)/pop_size*100):.2f}%)' ) if self.config.Statistics.save_best_individual_from_generation: folder = self.config.Statistics.save_best_individual_from_generation best_ind_name = 'best_ind_gen{}'.format(self.current_generation - 1) best_ind = self.population.fittest_individual save_mario(folder, best_ind_name, best_ind) if self.config.Statistics.save_population_stats: fname = self.config.Statistics.save_population_stats save_stats(self.population, fname) self.population.individuals = elitism_selection( self.population, self.config.Selection.num_parents) random.shuffle(self.population.individuals) next_pop = [] # Parents + offspring if self.config.Selection.selection_type == 'plus': # Decrement lifespan for individual in self.population.individuals: individual.lifespan -= 1 for individual in self.population.individuals: config = individual.config chromosome = individual.network.params hidden_layer_architecture = individual.hidden_layer_architecture hidden_activation = individual.hidden_activation output_activation = individual.output_activation lifespan = individual.lifespan name = individual.name # If the indivdual would be alve, add it to the next pop if lifespan > 0: m = Mario(config, chromosome, hidden_layer_architecture, hidden_activation, output_activation, lifespan) # Set debug if needed if args.debug: m.name = f'{name}_life{lifespan}' m.debug = True next_pop.append(m) num_loaded = 0 while len(next_pop) < self._next_gen_size: selection = self.config.Crossover.crossover_selection if selection == 'tournament': p1, p2 = tournament_selection( self.population, 2, self.config.Crossover.tournament_size) elif selection == 'roulette': p1, p2 = roulette_wheel_selection(self.population, 2) else: raise Exception( 'crossover_selection "{}" is not supported'.format( selection)) L = len(p1.network.layer_nodes) c1_params = {} c2_params = {} # Each W_l and b_l are treated as their own chromosome. # Because of this I need to perform crossover/mutation on each chromosome between parents for l in range(1, L): p1_W_l = p1.network.params['W' + str(l)] p2_W_l = p2.network.params['W' + str(l)] p1_b_l = p1.network.params['b' + str(l)] p2_b_l = p2.network.params['b' + str(l)] # Crossover # @NOTE: I am choosing to perform the same type of crossover on the weights and the bias. c1_W_l, c2_W_l, c1_b_l, c2_b_l = self._crossover( p1_W_l, p2_W_l, p1_b_l, p2_b_l) # Mutation # @NOTE: I am choosing to perform the same type of mutation on the weights and the bias. self._mutation(c1_W_l, c2_W_l, c1_b_l, c2_b_l) # Assign children from crossover/mutation c1_params['W' + str(l)] = c1_W_l c2_params['W' + str(l)] = c2_W_l c1_params['b' + str(l)] = c1_b_l c2_params['b' + str(l)] = c2_b_l # Clip to [-1, 1] np.clip(c1_params['W' + str(l)], -1, 1, out=c1_params['W' + str(l)]) np.clip(c2_params['W' + str(l)], -1, 1, out=c2_params['W' + str(l)]) np.clip(c1_params['b' + str(l)], -1, 1, out=c1_params['b' + str(l)]) np.clip(c2_params['b' + str(l)], -1, 1, out=c2_params['b' + str(l)]) c1 = Mario(self.config, c1_params, p1.hidden_layer_architecture, p1.hidden_activation, p1.output_activation, p1.lifespan) c2 = Mario(self.config, c2_params, p2.hidden_layer_architecture, p2.hidden_activation, p2.output_activation, p2.lifespan) # Set debug if needed if args.debug: c1_name = f'm{num_loaded}_new' c1.name = c1_name c1.debug = True num_loaded += 1 c2_name = f'm{num_loaded}_new' c2.name = c2_name c2.debug = True num_loaded += 1 next_pop.extend([c1, c2]) # Set next generation random.shuffle(next_pop) self.population.individuals = next_pop
def next_generation(self): self._increment_generation() self._current_individual = 0 # Calculate fitness of individuals for individual in self.population.individuals: individual.calculate_fitness() self.population.individuals = elitism_selection( self.population, self.settings['num_parents']) random.shuffle(self.population.individuals) next_pop: List[Snake] = [] # parents + offspring selection type ('plus') if self.settings['selection_type'].lower() == 'plus': # Giảm tuổi thọ for individual in self.population.individuals: individual.lifespan -= 1 for individual in self.population.individuals: params = individual.network.params board_size = individual.board_size hidden_layer_architecture = individual.hidden_layer_architecture hidden_activation = individual.hidden_activation output_activation = individual.output_activation lifespan = individual.lifespan apple_and_self_vision = individual.apple_and_self_vision start_pos = individual.start_pos apple_seed = individual.apple_seed starting_direction = individual.starting_direction # Nếu cá thể vẫn còn sống, nó vẫn tồn tại if lifespan > 0: s = Snake( board_size, chromosome=params, hidden_layer_architecture=hidden_layer_architecture, hidden_activation=hidden_activation, output_activation=output_activation, lifespan=lifespan, apple_and_self_vision=apple_and_self_vision) #, next_pop.append(s) while len(next_pop) < self._next_gen_size: p1, p2 = roulette_wheel_selection(self.population, 2) L = len(p1.network.layer_nodes) c1_params = {} c2_params = {} # Mỗi W_l và b_l được coi là nhiễm sắc thể của riêng họ. # Vì điều này, ta cần thực hiện trao đổi chéo / đột biến trên mỗi nhiễm sắc thể giữa cha mẹ for l in range(1, L): p1_W_l = p1.network.params['W' + str(l)] p2_W_l = p2.network.params['W' + str(l)] p1_b_l = p1.network.params['b' + str(l)] p2_b_l = p2.network.params['b' + str(l)] # Crossover # @NOTE: I am choosing to perform the same type of crossover on the weights and the bias. c1_W_l, c2_W_l, c1_b_l, c2_b_l = self._crossover( p1_W_l, p2_W_l, p1_b_l, p2_b_l) # Mutation # @NOTE: Ta đang chọn để thực hiện cùng một loại đột biến về trọng lượng và sai lệch. self._mutation(c1_W_l, c2_W_l, c1_b_l, c2_b_l) # Chỉ định con cái từ chéo / đột biến c1_params['W' + str(l)] = c1_W_l c2_params['W' + str(l)] = c2_W_l c1_params['b' + str(l)] = c1_b_l c2_params['b' + str(l)] = c2_b_l # Clip to [-1, 1] np.clip(c1_params['W' + str(l)], -1, 1, out=c1_params['W' + str(l)]) np.clip(c2_params['W' + str(l)], -1, 1, out=c2_params['W' + str(l)]) np.clip(c1_params['b' + str(l)], -1, 1, out=c1_params['b' + str(l)]) np.clip(c2_params['b' + str(l)], -1, 1, out=c2_params['b' + str(l)]) # Tạo con từ nhiễm sắc thể được tạo ở trên c1 = Snake(p1.board_size, chromosome=c1_params, hidden_layer_architecture=p1.hidden_layer_architecture, hidden_activation=p1.hidden_activation, output_activation=p1.output_activation, lifespan=self.settings['lifespan']) c2 = Snake(p2.board_size, chromosome=c2_params, hidden_layer_architecture=p2.hidden_layer_architecture, hidden_activation=p2.hidden_activation, output_activation=p2.output_activation, lifespan=self.settings['lifespan']) # Thêm con vào thế hệ tiếp theo next_pop.extend([c1, c2]) # Đặt thế hệ tiếp theo random.shuffle(next_pop) self.population.individuals = next_pop
def next_generation(self): self._increment_generation() # Calculate fitness of individuals for individual in self.population.individuals: individual.calculate_fitness() self.population.individuals = elitism_selection( self.population, self.cfg['num_parents']) random.shuffle(self.population.individuals) next_pop: List[Player] = [] while len(next_pop) < self._next_gen_size: p1, p2 = roulette_wheel_selection(self.population, 2) L = p1.brain.layer_nodes c1_params = {} c2_params = {} # Each W_l and b_l are treated as their own chromosome. # Because of this I need to perform crossover/mutation on each chromosome between parents for l in range(0, L, 2): p1_W_l = p1.brain.net[l].weight.data.numpy() p2_W_l = p2.brain.net[l].weight.data.numpy() p1_b_l = np.array([p1.brain.net[l].bias.data.numpy()]) p2_b_l = np.array([p2.brain.net[l].bias.data.numpy()]) # Crossover # @NOTE: I am choosing to perform the same type of crossover on the weights and the bias. c1_W_l, c2_W_l, c1_b_l, c2_b_l = self._crossover( p1_W_l, p2_W_l, p1_b_l, p2_b_l) # Mutation # @NOTE: I am choosing to perform the same type of mutation on the weights and the bias. self._mutation(c1_W_l, c2_W_l, c1_b_l, c2_b_l) # Assign children from crossover/mutation c1_params['W' + str(l)] = c1_W_l c2_params['W' + str(l)] = c2_W_l c1_params['b' + str(l)] = c1_b_l c2_params['b' + str(l)] = c2_b_l # Clip to [-1, 1] np.clip(c1_params['W' + str(l)], -1, 1, out=c1_params['W' + str(l)]) np.clip(c2_params['W' + str(l)], -1, 1, out=c2_params['W' + str(l)]) np.clip(c1_params['b' + str(l)], -1, 1, out=c1_params['b' + str(l)]) np.clip(c2_params['b' + str(l)], -1, 1, out=c2_params['b' + str(l)]) # Create children from chromosomes generated above brain = NN() boat = Boat() brain.transform_weights(c1_params) p1 = Player(brain, boat) brain = NN() boat = Boat() brain.transform_weights(c2_params) p2 = Player(brain, boat) # Add children to the next generation next_pop.extend([p1, p2]) # Set the next generation random.shuffle(next_pop) self.group = next_pop self.population = Population(self.group)
def next_generation(self): self.current_generation += 1 # reset for new game self.score = 0 self.pipe_list.clear() self.pipe_list.extend(self.create_pipe()) # reset timer so don't have the second pipe comming too soon # pygame.time.set_timer(self.SPAWNPIPE, 0) # pygame.time.set_timer(self.SPAWNPIPE, 1200) ## TODO: test if this is neccessary self.spawn_pipe_counter = 0 # Calculate fitness of individuals for individual in self.population.individuals: individual.calculate_fitness() # Find winner from each generation and champion self.winner = self.population.fittest_individual self.winner_index = self.population.individuals.index(self.winner) if self.winner.fitness > self.champion_fitness: self.champion_fitness = self.winner.fitness self.champion = self.winner self.champion_index = self.winner_index # Save the network of best birds from each generation if self.current_generation <= 100: individual_name = 'bird' + str(self.current_generation) self.save_bird('Flappy_Genetic/plot/best_birds_each_generation', individual_name, self.winner, settings) self.winner.reset() self.champion.reset() # Print results from each generation print('======================= Gneration {} ======================='. format(self.current_generation)) print('----Max fitness:', self.population.fittest_individual.fitness) # print('----Best Score:', self.population.fittest_individual.score) print('----Average fitness:', self.population.average_fitness) self.population.individuals = elitism_selection( self.population, settings['num_parents']) random.shuffle(self.population.individuals) next_pop: List[Bird] = [] # parents + offspring selection type ('plus') if settings['selection_type'].lower() == 'plus': next_pop.append(self.winner) next_pop.append(self.champion) while len(next_pop) < self._next_gen_size: p1, p2 = roulette_wheel_selection(self.population, 2) L = len(p1.network.layer_nodes) c1_params = {} c2_params = {} # Each W_l and b_l are treated as their own chromosome. # Because of this I need to perform crossover/mutation on each chromosome between parents for l in range(1, L): p1_W_l = p1.network.params['W' + str(l)] p2_W_l = p2.network.params['W' + str(l)] p1_b_l = p1.network.params['b' + str(l)] p2_b_l = p2.network.params['b' + str(l)] # Crossover # @NOTE: I am choosing to perform the same type of crossover on the weights and the bias. c1_W_l, c2_W_l, c1_b_l, c2_b_l = self._crossover( p1_W_l, p2_W_l, p1_b_l, p2_b_l) # Mutation # @NOTE: I am choosing to perform the same type of mutation on the weights and the bias. self._mutation(c1_W_l, c2_W_l, c1_b_l, c2_b_l) # Assign children from crossover/mutation c1_params['W' + str(l)] = c1_W_l c2_params['W' + str(l)] = c2_W_l c1_params['b' + str(l)] = c1_b_l c2_params['b' + str(l)] = c2_b_l # Clip to [-1, 1] np.clip(c1_params['W' + str(l)], -1, 1, out=c1_params['W' + str(l)]) np.clip(c2_params['W' + str(l)], -1, 1, out=c2_params['W' + str(l)]) np.clip(c1_params['b' + str(l)], -1, 1, out=c1_params['b' + str(l)]) np.clip(c2_params['b' + str(l)], -1, 1, out=c2_params['b' + str(l)]) # Create children from chromosomes generated above c1 = Bird(chromosome=c1_params, hidden_layer_architecture=p1.hidden_layer_architecture, hidden_activation=p1.hidden_activation, output_activation=p1.output_activation) c2 = Bird(chromosome=c2_params, hidden_layer_architecture=p2.hidden_layer_architecture, hidden_activation=p2.hidden_activation, output_activation=p2.output_activation) # Add children to the next generation next_pop.extend([c1, c2]) # Set the next generation random.shuffle(next_pop) self.population.individuals = next_pop