def compute_full_connections(self, config, direct): """ Compute connections for a fully-connected feed-forward genome--each input connected to all hidden nodes (and output nodes if ``direct`` is set or there are no hidden nodes), each hidden node connected to all output nodes. (Recurrent genomes will also include node self-connections.) """ hidden = [ i for i in iterkeys(self.nodes) if i not in config.output_keys ] output = [i for i in iterkeys(self.nodes) if i in config.output_keys] connections = [] if hidden: for input_id in config.input_keys: for h in hidden: connections.append((input_id, h)) for h in hidden: for output_id in output: connections.append((h, output_id)) if direct or (not hidden): for input_id in config.input_keys: for output_id in output: connections.append((input_id, output_id)) # For recurrent genomes, include node self-connections. if not config.feed_forward: for i in iterkeys(self.nodes): connections.append((i, i)) return connections
def distance(self, other, config): """ Returns the genetic distance between this genome and the other. This distance value is used to compute genome compatibility for speciation. """ # Compute node gene distance component. node_distance = 0.0 if self.nodes or other.nodes: disjoint_nodes = 0 # other有, self没有 的结点基因 for k2 in iterkeys(other.nodes): if k2 not in self.nodes: disjoint_nodes += 1 for k1, n1 in iteritems(self.nodes): n2 = other.nodes.get(k1) # self有, other 没有的 结点基因 if n2 is None: disjoint_nodes += 1 else: # Homologous genes compute their own distance value. node_distance += n1.distance(n2, config) max_nodes = max(len(self.nodes), len(other.nodes)) node_distance = (node_distance + (config.compatibility_disjoint_coefficient * disjoint_nodes)) / max_nodes # Compute connection gene differences. connection_distance = 0.0 if self.connections or other.connections: disjoint_connections = 0 for k2 in iterkeys(other.connections): if k2 not in self.connections: disjoint_connections += 1 for k1, c1 in iteritems(self.connections): c2 = other.connections.get(k1) if c2 is None: disjoint_connections += 1 else: # Homologous genes compute their own distance value. connection_distance += c1.distance(c2, config) max_conn = max(len(self.connections), len(other.connections)) connection_distance = (connection_distance + (config.compatibility_disjoint_coefficient * disjoint_connections)) / max_conn distance = node_distance + connection_distance return distance
def end_generation(self, config, population, species_set): ng = len(population) ns = len(species_set.species) if self.show_species_detail: print('Population of {0:d} members in {1:d} species:'.format( ng, ns)) sids = list(iterkeys(species_set.species)) sids.sort() print(" ID age size fitness adj fit stag") print(" ==== === ==== ======= ======= ====") for sid in sids: s = species_set.species[sid] a = self.generation - s.created n = len(s.members) f = "--" if s.fitness is None else "{:.1f}".format(s.fitness) af = "--" if s.adjusted_fitness is None else "{:.3f}".format( s.adjusted_fitness) st = self.generation - s.last_improved print( " {: >4} {: >3} {: >4} {: >7} {: >7} {: >4}".format( sid, a, n, f, af, st)) else: print('Population of {0:d} members in {1:d} species'.format( ng, ns)) elapsed = time.time() - self.generation_start_time self.generation_times.append(elapsed) self.generation_times = self.generation_times[-10:] average = sum(self.generation_times) / len(self.generation_times) print('Total extinctions: {0:d}'.format(self.num_extinctions)) if len(self.generation_times) > 1: print("Generation time: {0:.3f} sec ({1:.3f} average)".format( elapsed, average)) else: print("Generation time: {0:.3f} sec".format(elapsed))
def get_new_node_key(self, node_dict): if self.node_indexer is None: self.node_indexer = count(max(list(iterkeys(node_dict))) + 1) new_id = next(self.node_indexer) assert new_id not in node_dict return new_id
def connect_fs_neat_hidden(self, config): """ Randomly connect one input to all hidden and output nodes (FS-NEAT with connections to hidden, if any). """ input_id = choice(config.input_keys) others = [ i for i in iterkeys(self.nodes) if i not in config.input_keys ] for output_id in others: connection = self.create_connection(config, input_id, output_id) self.connections[connection.key] = connection
def __init__(self, param_dict, param_list): self._params = param_list param_list_names = [] for p in param_list: setattr(self, p.name, p.interpret(param_dict)) param_list_names.append(p.name) unknown_list = [ x for x in iterkeys(param_dict) if x not in param_list_names ] if unknown_list: if len(unknown_list) > 1: raise UnknownConfigItemError("Unknown configuration items:\n" + "\n\t".join(unknown_list)) raise UnknownConfigItemError( "Unknown configuration item {!s}".format(unknown_list[0]))
def compute_full_connections_with_layer(self, config): """ Compute connections for a fully-connected cnn genome--each node in one layer connected to all nodes in the next layer """ connections = [] in_channels = {} for node in self.layer[0][1]: for input_id in config.input_keys: #print(input_id, ' -- > ' , node) connections.append((input_id, node)) if in_channels.__contains__(node) == False: in_channels[node] = 1 else: in_channels[node] += 1 for i in range(len(self.layer) - 1): # 第一层 到 倒数第二层 for node1 in self.layer[i][1]: # 第 i层的每个结点node1 for node2 in self.layer[i + 1][1]: # 第 i+1层的每个结点node2 connections.append((node1, node2)) # 计算 全连接的情况下, 每个 卷积层结点 node2的输入通道数 if i + 1 < config.num_cnn_layer: if in_channels.__contains__(node2) == False: in_channels[node2] = 1 else: in_channels[node2] += 1 # 如果 有环, in_channels 可能要修改 # For recurrent genomes, include node self-connections. if not config.feed_forward: for i in iterkeys(self.nodes): connections.append((i, i)) return connections, in_channels
def __init__(self, genome_type, reproduction_type, species_set_type, stagnation_type, filename): # Check that the provided types have the required methods. assert hasattr(genome_type, 'parse_config') assert hasattr(reproduction_type, 'parse_config') assert hasattr(species_set_type, 'parse_config') assert hasattr(stagnation_type, 'parse_config') self.genome_type = genome_type self.reproduction_type = reproduction_type self.species_set_type = species_set_type self.stagnation_type = stagnation_type if not os.path.isfile(filename): raise Exception('No such config file: ' + os.path.abspath(filename)) parameters = ConfigParser() with open(filename) as f: if hasattr(parameters, 'read_file'): parameters.read_file(f) else: parameters.readfp(f) # NEAT configuration if not parameters.has_section('NEAT'): raise RuntimeError( "'NEAT' section not found in NEAT configuration file.") param_list_names = [] for p in self.__params: if p.default is None: setattr(self, p.name, p.parse('NEAT', parameters)) else: try: setattr(self, p.name, p.parse('NEAT', parameters)) except Exception: setattr(self, p.name, p.default) warnings.warn( "Using default {!r} for '{!s}'".format( p.default, p.name), DeprecationWarning) param_list_names.append(p.name) param_dict = dict(parameters.items('NEAT')) unknown_list = [ x for x in iterkeys(param_dict) if x not in param_list_names ] if unknown_list: if len(unknown_list) > 1: raise UnknownConfigItemError( "Unknown (section 'NEAT') configuration items:\n" + "\n\t".join(unknown_list)) raise UnknownConfigItemError( "Unknown (section 'NEAT') configuration item {!s}".format( unknown_list[0])) # Parse type sections. genome_dict = dict(parameters.items(genome_type.__name__)) self.genome_config = genome_type.parse_config(genome_dict) species_set_dict = dict(parameters.items(species_set_type.__name__)) self.species_set_config = species_set_type.parse_config( species_set_dict) stagnation_dict = dict(parameters.items(stagnation_type.__name__)) self.stagnation_config = stagnation_type.parse_config(stagnation_dict) reproduction_dict = dict(parameters.items(reproduction_type.__name__)) self.reproduction_config = reproduction_type.parse_config( reproduction_dict)
def mutate_delete_node(self, config): # Do nothing if there are no non-output nodes. # 只能删除隐藏层结点 available_nodes = [ k for k in iterkeys(self.nodes) if k not in config.output_keys ] if not available_nodes: return -1 del_key = choice(available_nodes) # 修改为 可以改变 第一层fc的结点 # if self.nodes[del_key].layer == config.num_cnn_layer: # return -1 # If there is only one node if len(self.layer[self.nodes[del_key].layer][1]) <= 1: return -1 connections_to_delete = set() for k, v in iteritems(self.connections): # v=(a,b), either del_key == a or b should be deleted if del_key in v.key: connections_to_delete.add(v.key) for key in connections_to_delete: if key[0] == del_key: # del_key是 输入 idx = -1 for i in range(len(self.nodes[key[1]].in_nodes)): if self.nodes[key[1]].in_nodes[i] == key[0]: idx = i break assert idx > -1 self.nodes[key[1]].in_nodes = self.nodes[key[1]].in_nodes[:idx] + \ self.nodes[key[1]].in_nodes[idx+1 : ] # TODO: 保证 结点至少有一个kernal if len(self.nodes[key[1]].in_nodes) > 0: if self.nodes[key[1]].layer % config.part_size == 0: self.nodes[key[1]].kernal = self.nodes[key[1]].kernal[:idx] + \ self.nodes[key[1]].kernal[idx+1:] else: self.nodes[key[1]].kernal1 = self.nodes[key[1]].kernal1[:idx] + \ self.nodes[key[1]].kernal1[idx+1:] else: # key[1] == del_key self.nodes[del_key].in_nodes = [] if self.nodes[key[1]].layer % config.part_size == 0: self.nodes[del_key].kernal = self.nodes[del_key].kernal[:1] else: self.nodes[del_key].kernal1 = self.nodes[ del_key].kernal1[:1] del self.connections[key] #i = self.nodes[del_key].layer self.layer[self.nodes[del_key].layer][1].remove(del_key) del self.nodes[del_key] return del_key
def mutate_add_connection(self, config): # Choose the outnode layer layer_num = randint(0, config.num_layer - 1) # If choose out_node form the first layer, the input_node should choose from input ot the network. if layer_num == 0: out_node = choice(list(self.layer[layer_num][1])) in_node = choice(config.input_keys) else: out_node = choice(list(self.layer[layer_num][1])) in_node = choice(list(self.layer[layer_num - 1][1])) # Don't duplicate connections. key = (in_node, out_node) if in_node == out_node: # 自环 return if key in self.connections: # 连接已经存在 # TODO: Should this be using mutation to/from rates? Hairy to configure... if config.check_structural_mutation_surer(): self.connections[key].enabled = True return # Don't allow connections between two output nodes if in_node in config.output_keys and out_node in config.output_keys: return # No need to check for connections between input nodes: # they cannot be the output end of a connection (see above). # For feed-forward networks, avoid creating cycles. if config.feed_forward and creates_cycle( list(iterkeys(self.connections)), key): return cg = self.create_connection(config, in_node, out_node) self.connections[cg.key] = cg if layer_num < config.num_cnn_layer: if layer_num % config.part_size == 0: tmp = randn(1, len(self.nodes[out_node].kernal[0])) if len(self.nodes[out_node].in_nodes) > 0: self.nodes[out_node].kernal += tmp.tolist() else: self.nodes[out_node].kernal = tmp.tolist() # 重新赋值 self.nodes[out_node].in_nodes.append(in_node) else: tmp = randn(1, len(self.nodes[out_node].kernal1[0])) if len(self.nodes[out_node].in_nodes) > 0: self.nodes[out_node].kernal1 += tmp.tolist() else: self.nodes[out_node].kernal1 = tmp.tolist() # 重新赋值 self.nodes[out_node].in_nodes.append(in_node)
def get_config_params(self): return [ ConfigParameter(self.config_item_name(n), self._config_items[n][0], self._config_items[n][1]) for n in iterkeys(self._config_items) ]
def __init__(self, name, **default_dict): self.name = name for n, default in iteritems(default_dict): self._config_items[n] = [self._config_items[n][0], default] for n in iterkeys(self._config_items): setattr(self, n + "_name", self.config_item_name(n))
def speciate(self, config, population, generation): """ Place genomes into species by genetic similarity. Note that this method assumes the current representatives of the species are from the old generation, and that after speciation has been performed, the old representatives should be dropped and replaced with representatives from the new generation. If you violate this assumption, you should make sure other necessary parts of the code are updated to reflect the new behavior. """ assert isinstance(population, dict) compatibility_threshold = self.species_set_config.compatibility_threshold # Find the best representatives for each existing species. unspeciated = set(iterkeys(population)) distances = GenomeDistanceCache(config.genome_config) new_representatives = {} new_members = {} for sid, s in iteritems(self.species): candidates = [] for gid in unspeciated: g = population[gid] d = distances(s.representative, g) candidates.append((d, g)) # The new representative is the genome closest to the current representative. ignored_rdist, new_rep = min(candidates, key=lambda x: x[0]) new_rid = new_rep.key new_representatives[sid] = new_rid new_members[sid] = [new_rid] unspeciated.remove(new_rid) # Partition population into species based on genetic similarity. while unspeciated: gid = unspeciated.pop() g = population[gid] # Find the species with the most similar representative. candidates = [] for sid, rid in iteritems(new_representatives): rep = population[rid] d = distances(rep, g) if d < compatibility_threshold: candidates.append((d, sid)) if candidates: ignored_sdist, sid = min(candidates, key=lambda x: x[0]) new_members[sid].append(gid) else: # No species is similar enough, create a new species, using # this genome as its representative. sid = next(self.indexer) new_representatives[sid] = gid new_members[sid] = [gid] # Update species collection based on new speciation. self.genome_to_species = {} for sid, rid in iteritems(new_representatives): s = self.species.get(sid) if s is None: s = Species(sid, generation) self.species[sid] = s members = new_members[sid] for gid in members: self.genome_to_species[gid] = sid member_dict = dict((gid, population[gid]) for gid in members) s.update(population[rid], member_dict) gdmean = mean(itervalues(distances.distances)) gdstdev = stdev(itervalues(distances.distances)) self.reporters.info( 'Mean genetic distance {0:.3f}, standard deviation {1:.3f}'.format( gdmean, gdstdev))