def crossover(self): new = [] self.individuals = sorted(self.individuals, key = lambda ind: ind.score, reverse = True) for _ in range(self.size): p1 = self.select() p2 = self.select() g = Genome(10) g.crossover(p1, p2) new.append(g) self.individuals = new
def crossover(self): new = [] self.individuals = sorted(self.individuals, key=lambda ind: ind.score, reverse=True) for _ in range(self.size): p1 = self.select() p2 = self.select() g = Genome(10) g.crossover(p1, p2) new.append(g) self.individuals = new
class Organism(object): """ Wrapper class that provides fitness metrics. """ def __init__(self, genome): self.genome = Genome(genome) self.policy = Network(self.genome) self.evals = list() def __cmp__(self, other): return cmp(self.fitness, other.fitness) def __str__(self): return '%.3f' % self.fitness def crossover(self, other): """ Return a new organism by recombining the parents. """ return Organism(self.genome.crossover(other.genome)) def mutate(self, frac=0.1, std=1.0, repl=0.25): """ Mutate the organism by mutating its genome. """ self.genome.mutate(frac, std, repl) self.policy = Network(self.genome) def copy(self): """ Return a deep copy of this organism. """ org = Organism(self.genome) org.evals = list(self.evals) return org @property def fitness(self): """ Average return. """ try: return sum(self.evals, 0.) / len(self.evals) except ZeroDivisionError: return 0.
class Organism(object): """ Wrapper class that provides fitness metrics. """ def __init__(self, genome): self.genome = Genome(genome) self.policy = Network(self.genome) self.evals = list() def __cmp__(self, other): return cmp(self.fitness, other.fitness) def __str__(self): return '%.3f' % self.fitness def crossover(self, other): """ Return a new organism by recombining the parents. """ return Organism(self.genome.crossover(other.genome)) def mutate(self, frac=0.1, std=1.0, repl=0.25): """ Mutate the organism by mutating its genome. """ self.genome.mutate(frac, std, repl) self.policy = Network(self.genome) def copy(self): """ Return a deep copy of this organism. """ org = Organism(self.genome) org.evals = list(self.evals) return org @property def fitness(self): """ Average return. """ try: return sum(self.evals, 0.) / len(self.evals) except ZeroDivisionError: return 0.
class Player: def __init__(self): self.fitness = 0 self.vision = [] self.decision = [] self.lifespan = 0 self.max_lifespan = 500 self.best_score = 0 self.dead = False self.score = 0 self.gen = 0 self.genome_inputs = 8 self.genome_outputs = 2 self.brain = Genome(self.genome_inputs, self.genome_outputs) def reward(self, reward): self.score += reward self.max_lifespan += reward if self.score < 1: self.max_lifespan -= 1 def update(self): self.lifespan += 1 # self.score -= 0.02 if self.lifespan > self.max_lifespan or self.score < -5: self.dead = True self.calculate_fitness() def look(self, inputs): self.vision = [] self.vision = inputs def think(self): # choice_max = 0 # max_index = 0 self.decision = self.brain.feed_forward(self.vision) # for i in range(len(self.decision)): # if self.decision[i] > choice_max: # choice_max = self.decision[i] # max_index = i return self.decision # max_index def clone(self): clone = Player() clone.brain = self.brain.clone() clone.fitness = self.fitness clone.brain.generate_network() clone.gen = self.gen clone.best_score = self.score return clone def calculate_fitness(self): self.fitness = (self.score * self.score) + self.lifespan def crossover(self, parent2): child = Player() child.brain = self.brain.crossover(parent2.brain) child.brain.generate_network() return child
def crossover(agents): next_generation = [] agents = sorted(agents, key=lambda x: x.get_fitness()) # random.shuffle(agents) s = int((1-SELECT_PERC)*POPULATION) for _ in range(s): p1 = random.choice(agents) p2 = random.choice(agents) next_generation += Genome.crossover(p1, p2) return next_generation
def test_crossover(): a = Genome() for i in range(3): a.add_node(Node(NodeType.inp, i + 1)) a.add_node(Node(NodeType.out, 4)) a.add_node(Node(NodeType.hidden, 5)) a.add_connection(Connection(1, 4, 1.0, True, 1)) a.add_connection(Connection(2, 4, 1.0, False, 2)) a.add_connection(Connection(3, 4, 1.0, True, 3)) a.add_connection(Connection(2, 5, 1.0, True, 4)) a.add_connection(Connection(5, 4, 1.0, True, 5)) a.add_connection(Connection(1, 5, 1.0, True, 8)) a.conn_innovation = 9 a.node_innovation = 6 b = Genome() for i in range(3): b.add_node(Node(NodeType.inp, i + 1)) b.add_node(Node(NodeType.out, 4)) b.add_node(Node(NodeType.hidden, 5)) b.add_node(Node(NodeType.hidden, 6)) b.add_connection(Connection(1, 4, 1.0, True, 1)) b.add_connection(Connection(2, 4, 1.0, False, 2)) b.add_connection(Connection(3, 4, 1.0, True, 3)) b.add_connection(Connection(2, 5, 1.0, True, 4)) b.add_connection(Connection(5, 4, 1.0, False, 5)) b.add_connection(Connection(5, 6, 1.0, True, 6)) b.add_connection(Connection(6, 4, 1.0, True, 7)) b.add_connection(Connection(3, 5, 1.0, True, 9)) b.add_connection(Connection(1, 6, 1.0, True, 10)) a.conn_innovation = 11 a.node_innovation = 7 c = Genome.crossover(b, a) a.render("render/crossover_a.gv") b.render("render/crossover_b.gv") c.render("render/crossover_c.gv")
def get_new_population(self, adjusted_species_sizes, remaining_species, species_set, generation_tracker, backprop_mutation): """ Creates the dictionary of the new genomes for the next generation population :param: genetation_tracker: :param adjusted_species_sizes: :param remaining_species: :param species_set: :param new_population: :return: """ new_population = {} for species_size, species in zip(adjusted_species_sizes, remaining_species): assert (species_size > 0) # List of old species members old_species_members = list(species.members.values()) # Reset the members for the current species species.members = {} # Save the species in the species set object species_set.species[species.key] = species # Sort the members into the descending fitness old_species_members.sort(reverse=True, key=lambda x: x.fitness) # Double check that it is descending if len(old_species_members) > 1: assert (old_species_members[0].fitness >= old_species_members[1].fitness) # If we have specified a number of genomes to carry over, carry them over to the new population num_genomes_without_crossover = int( round(species_size * self.config.chance_for_mutation_without_crossover)) if num_genomes_without_crossover > 0: for member in old_species_members[: num_genomes_without_crossover]: # Check if we should carry over a member un-mutated or not if not self.config.keep_unmutated_top_percentage: child = copy.deepcopy(member) child.mutate( reproduction_instance=self, innovation_tracker=self.innovation_tracker, config=self.config, backprop_mutation=backprop_mutation) if not child.check_connection_enabled_amount( ) and not child.check_num_paths( only_add_enabled_connections=True): raise Exception( 'This child has no enabled connections') new_population[child.key] = child self.ancestors[child.key] = () # new_population[member.key] = member species_size -= 1 assert (species_size >= 0) else: # Else we just add the current member to the new population new_population[member.key] = member species_size -= 1 assert (species_size >= 0) # If there are no more genomes for the current species, then restart the loop for the next species if species_size <= 0: continue # Only use the survival threshold fraction to use as parents for the next generation. reproduction_cutoff = int( math.ceil( (1 - self.config.chance_for_mutation_without_crossover) * len(old_species_members))) # Need at least two parents no matter what the previous result reproduction_cutoff = max(reproduction_cutoff, 2) old_species_members = old_species_members[:reproduction_cutoff] # Randomly choose parents and choose whilst there can still be additional genomes for the given species while species_size > 0: species_size -= 1 # TODO: If you don't allow them to mate with themselves then it's a problem because if the species previous # TODO: size is 1, then how can you do with or without crossover? parent_1 = copy.deepcopy(random.choice(old_species_members)) parent_2 = copy.deepcopy(random.choice(old_species_members)) # Has to be a deep copy otherwise the connections which are crossed over are also modified if mutation # occurs on the child. parent_1 = copy.deepcopy(parent_1) parent_2 = copy.deepcopy(parent_2) self.genome_indexer += 1 genome_id = self.genome_indexer child = Genome(key=genome_id) # TODO: Save the parent_1 and parent_2 mutation history as well as what connections they had # Create the genome from the parents num_connections_enabled = child.crossover(genome_1=parent_1, genome_2=parent_2, config=self.config) # If there are no connections enabled we forget about this child and don't add it to the existing # population if num_connections_enabled: child.mutate(reproduction_instance=self, innovation_tracker=self.innovation_tracker, config=self.config, generation_tracker=generation_tracker, backprop_mutation=backprop_mutation) if not child.check_connection_enabled_amount( ) and not child.check_num_paths( only_add_enabled_connections=True): raise Exception( 'This child has no enabled connections') new_population[child.key] = child self.ancestors[child.key] = (parent_1.key, parent_2.key) else: # Else if the crossover resulted in an invalid genome. assert num_connections_enabled == 0 species_size += 1 self.genome_indexer -= 1 return new_population
class Player: size_x = 100 size_y = 50 genome_inputs = 4 genome_outputs = 2 # Up or down? def __init__(self, game): self.game = game self.top = game.top self.middle = game.middle self.bottom = game.bottom self.position_x = 0.075 * game.width self.position_y = game.middle self.speed_x = 0 self.speed_y = 0 self.color = (255, 255, 255) self.speed = 10 self.dead = False self.next_lane = None self.fitness = 0 self.unadjusted_fitness = 0 self.lifespan = 0 self.best_score = 0 self.replay = False self.score = 0 self.gen = 0 self.vision = [0 for _ in range(self.genome_inputs)] self.decision = [0 for _ in range(self.genome_outputs)] self.brain = Genome(self.genome_inputs, self.genome_outputs) def draw(self): arcade.draw_rectangle_filled(self.position_x, self.position_y, self.size_x, self.size_y, self.color) def update(self): self.increment_counters() if self.next_lane == None: if self.speed_y > 0: if self.position_y == self.bottom: self.next_lane = self.middle elif self.position_y == self.middle: self.next_lane = self.top elif self.speed_y < 0: if self.position_y == self.top: self.next_lane = self.middle elif self.position_y == self.middle: self.next_lane = self.bottom else: if self.speed_y > 0: if (self.next_lane == self.middle and self.position_y >= self.middle): self.next_lane = None self.position_y = self.middle self.speed_y = 0 elif (self.next_lane == self.top and self.position_y >= self.top): self.next_lane = None self.position_y = self.top self.speed_y = 0 else: self.position_y += self.speed_y if self.speed_y < 0: if (self.next_lane == self.middle and self.position_y <= self.middle): self.next_lane = None self.position_y = self.middle self.speed_y = 0 elif (self.next_lane == self.bottom and self.position_y <= self.bottom): self.next_lane = None self.position_y = self.bottom self.speed_y = 0 else: self.position_y += self.speed_y for enemy in self.game.enemy_list: if enemy.collided(self): self.dead = True break def move(self, direction): if self.next_lane == None: if direction == 'up': self.speed_y = self.speed elif direction == 'down': self.speed_y = -self.speed def clone(self): clone = Player(self.game) clone.brain = self.brain.clone() clone.fitness = self.fitness clone.unadjusted_fitness = self.unadjusted_fitness clone.brain.generate_network() clone.gen = self.gen clone.best_score = self.best_score clone.color = self.color return clone def calculate_fitness(self): self.unadjusted_fitness = self.score * self.score self.fitness = self.unadjusted_fitness def crossover(self, parent_2): child = Player(self.game) child.color = self.color child.brain = self.brain.crossover(parent_2.brain) child.brain.generate_network() return child def look(self): if len(self.game.enemy_list) > 0: dist_min_bot = 1e6 dist_min_mid = 1e6 dist_min_top = 1e6 for enemy in self.game.enemy_list: dist = enemy.position_x - self.position_x if dist <= 0: continue if enemy.position_y == self.bottom: if dist < dist_min_bot: dist_min_bot = dist if enemy.position_y == self.middle: if dist < dist_min_mid: dist_min_mid = dist if enemy.position_y == self.top: if dist < dist_min_top: dist_min_top = dist self.vision[0] = (dist_min_bot / self.game.width if dist_min_bot != 1e6 else 1) self.vision[1] = (dist_min_mid / self.game.width if dist_min_mid != 1e6 else 1) self.vision[2] = (dist_min_top / self.game.width if dist_min_top != 1e6 else 1) else: self.vision[0] = 1 self.vision[1] = 1 self.vision[2] = 1 self.vision[3] = self.position_y / self.game.height def think(self): decision = self.brain.feed_forward(self.vision) action_certainty = max(decision) action_taken = decision.index(action_certainty) if action_taken == 0: self.move('up') elif action_taken == 1: self.move('down') def increment_counters(self): self.lifespan += 1 if self.lifespan % 5 == 0: self.score += 1
class Player: MAX_ROTATION = 25 IMGS = [pygame.transform.scale2x(pygame.image.load( os.path.join("imgs", "bird" + str(x) + ".png"))) for x in range(1, 4)] ROT_VEL = 20 ANIMATION_TIME = 5 genome_inputs = 3 # Flappy-Bird Vision! If you change vision parameter in look(), change here too! genome_outputs = 1 # To jump or not to jump! def __init__(self, x, y): self.dead = False self.x = x self.y = y self.tilt = 0 self.tick_count = 0 self.vel = 0 self.height = self.y self.img_count = 0 self.img = self.IMGS[0] self.fitness = 1 self.unadjusted_fitness = 0 self.lifespan = 0 self.best_score = 0 #self.replay = False self.score = 1 #self.gen = 0 self.vision = [0 for _ in range(self.genome_inputs)] self.decision = 0 self.brain = Genome(self.genome_inputs, self.genome_outputs) def draw(self, win): self.img_count += 1 if self.img_count <= self.ANIMATION_TIME: self.img = self.IMGS[0] elif self.img_count <= self.ANIMATION_TIME*2: self.img = self.IMGS[1] elif self.img_count <= self.ANIMATION_TIME*3: self.img = self.IMGS[2] elif self.img_count <= self.ANIMATION_TIME*4: self.img = self.IMGS[1] elif self.img_count == self.ANIMATION_TIME*4 + 1: self.img = self.IMGS[0] self.img_count = 0 if self.tilt <= -80: self.img = self.IMGS[1] self.img_count = self.ANIMATION_TIME*2 self.blitRotateCenter(win, self.img, (self.x, self.y), self.tilt) def blitRotateCenter(self, surf, image, topleft, angle): rotated_image = pygame.transform.rotate(image, angle) new_rect = rotated_image.get_rect( center=image.get_rect(topleft=topleft).center) surf.blit(rotated_image, new_rect.topleft) def get_mask(self): return pygame.mask.from_surface(self.img) def jump(self): self.vel = -10.5 self.tick_count = 0 self.height = self.y def move(self): self.tick_count += 1 displacement = self.vel*(self.tick_count) + 0.5 * \ (3)*(self.tick_count)**2 if displacement >= 16: displacement = (displacement/abs(displacement)) * 16 if displacement < 0: displacement -= 2 self.y = self.y + displacement if displacement < 0 or self.y < self.height + 50: if self.tilt < self.MAX_ROTATION: self.tilt = self.MAX_ROTATION else: if self.tilt > -90: self.tilt -= self.ROT_VEL def clone(self): clone = Player(230, randint(200,400)) clone.brain = self.brain.clone() clone.fitness = self.fitness clone.unadjusted_fitness = self.unadjusted_fitness clone.brain.generate_network() clone.best_score = self.best_score return clone def calculate_fitness(self): self.unadjusted_fitness = self.score*self.score self.fitness = self.unadjusted_fitness def crossover(self, parent_2): child = Player(230, randint(200,400)) child.brain = self.brain.crossover(parent_2.brain) child.brain.generate_network() return child def look(self, pipes, pipe_ind): self.vision[0] = self.y self.vision[1] = abs(self.y - pipes[pipe_ind].height) self.vision[2] = abs(self.y - pipes[pipe_ind].bottom) def think_and_act(self): decision = self.brain.feed_forward(self.vision)[0] if decision > 0: self.jump() #def increment_counters(self): # self.lifespan += 1 # # if self.lifespan % 5 == 0: # self.score += 1 def increment_score_by(self, number): self.score += number