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
Example #3
0
    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))
Example #13
0
    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))