Skip to content

Commit 8dad162

Browse files
This revision is mostly not working. Now with extra violent refactoring/redesign!
Introduced attributes and config parameters intended to reduce the amount of boilerplate code required for configuration parsing. Added rough implementation of saving configuration data to file. Attempted to factor out more common gene/genome behavior. Change reported genome "size" to just be (# nodes, # active connections). Added refactoring notes and placeholders in documentation. Added activation function facility tests.
1 parent 03d3beb commit 8dad162

18 files changed

+627
-439
lines changed

docs/customization.rst

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ it with an object which implements the same interface as `BaseReporter`.
3232
<https://github.com/CodeReclaimers/neat-python/blob/master/neat/reporting.py#L56>`_ may be useful as examples of the
3333
behavior you can add using a reporter.
3434

35-
Species stagnation
36-
------------------
35+
Species stagnation scheme
36+
-------------------------
3737

3838
To use a different species stagnation scheme, you must create and register a custom class whose interface matches that
3939
of `DefaultStagnation` and set the `stagnation_type` of your Config instance to this class.
@@ -49,13 +49,17 @@ is encapsulated in the DefaultReproduction class.
4949

5050
TODO: document, include example
5151

52+
EXAMPLE: ???
53+
5254
Speciation
5355
----------
5456

5557
If you need to change the speciation scheme, you should subclass `Population` and override the `_speciate` method (or,
5658
if you must, `monkey patch/duck punch
5759
<https://en.wikipedia.org/wiki/Monkey_patch>`_ it).
5860

61+
EXAMPLE: ???
62+
5963
Diversity
6064
---------
6165

@@ -64,20 +68,35 @@ To use a different diversity scheme, you can create a custom class whose interfa
6468

6569
TODO: document, include example
6670

71+
EXAMPLE: ???
72+
6773
Using different genome types
68-
--------------------------
74+
----------------------------
6975

7076
To use a different genome type, you can create a custom class whose interface matches that of
7177
`Genome` or `FFGenome`, and set the `genotype` member of your Config instance to this class.
7278

7379
TODO: document, include example
7480

81+
EXAMPLE: genome with an additional set of genes (used for?)
82+
7583
Using a different gene type
76-
-----------------------------
84+
---------------------------
7785

7886
To use a different gene type, you can create a custom class whose interface matches that of
7987
`NodeGene` or `ConnectionGene`, and set the `node_gene_type` or `conn_gene_type` member,
8088
respectively, of your Config instance to this class.
8189

8290
TODO: document, include example
8391

92+
EXAMPLE: ??? reference the IZNN genes?
93+
94+
Using a different network type
95+
------------------------------
96+
97+
EXAMPLE: ???
98+
99+
Cross-validation
100+
----------------
101+
102+
EXAMPLE: ???

examples/memory/nn_config

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,59 @@
1-
# Parameters for the bit-sequence memory experiment.
2-
3-
# The `Types` section specifies which classes should be used for various
4-
# tasks in the NEAT algorithm. If you use a non-default class here, you
5-
# must register it with your Config instance before loading the config file.
6-
[Types]
7-
genome_type = DefaultGenome
8-
reproduction_type = DefaultReproduction
9-
stagnation_type = DefaultStagnation
1+
# NEAT configuration for the bit-sequence memory experiment.
102

113
# The `NEAT` section specifies parameters particular to the NEAT algorithm
12-
# or the experiment itself.
4+
# or the experiment itself. This is the only required section.
135
[NEAT]
146
pop_size = 150
157
max_fitness_threshold = -0.05
168
reset_on_extinction = 0
9+
collect_statistics = True
10+
report = True
11+
save_best = False
1712

1813
[DefaultGenome]
1914
num_inputs = 2
2015
num_hidden = 0
2116
num_outputs = 1
2217
initial_connection = partial 0.5
2318
feed_forward = 0
24-
activation = clamped sigmoid tanh my_sinc_function
25-
aggregation = sum
19+
compatibility_threshold = 3.0
20+
excess_coefficient = 1.0
21+
disjoint_coefficient = 1.0
22+
weight_coefficient = 0.5
2623
conn_add_prob = 0.5
2724
conn_delete_prob = 0.25
2825
node_add_prob = 0.5
2926
node_delete_prob = 0.25
30-
bias_mutate_prob = 0.8
27+
activation_default = sigmoid
28+
activation_options = clamped sigmoid tanh my_sinc_function
29+
activation_mutate_rate = 0.02
30+
aggregation_default = sum
31+
aggregation_options = sum
32+
aggregation_mutate_rate = 0.0
33+
bias_init_mean = 0.0
34+
bias_init_stdev = 1.0
35+
bias_replace_rate = 0.1
36+
bias_mutate_rate = 0.7
3137
bias_mutate_power = 0.5
32-
response_mutate_prob = 0.8
38+
bias_max_value = 30.0
39+
bias_min_value = -30.0
40+
response_init_mean = 0.0
41+
response_init_stdev = 1.0
42+
response_replace_rate = 0.1
43+
response_mutate_rate = 0.7
3344
response_mutate_power = 0.5
34-
weight_max = 30
35-
weight_min = -30
36-
weight_mean = 0.0
37-
weight_stdev = 1.0
38-
weight_mutate_prob = 0.8
39-
weight_replace_prob = 0.1
45+
response_max_value = 30.0
46+
response_min_value = -30.0
47+
48+
weight_max_value = 30
49+
weight_min_value = -30
50+
weight_init_mean = 0.0
51+
weight_init_stdev = 1.0
52+
weight_mutate_rate = 0.8
53+
weight_replace_rate = 0.1
4054
weight_mutate_power = 0.5
41-
activation_mutate_prob = 0.002
42-
aggregation_mutate_prob = 0.0
43-
link_toggle_prob = 0.01
44-
compatibility_threshold = 3.0
45-
excess_coefficient = 1.0
46-
disjoint_coefficient = 1.0
47-
weight_coefficient = 0.5
55+
enabled_default = True
56+
enabled_mutate_rate = 0.01
4857

4958
[DefaultStagnation]
5059
species_fitness = median

examples/memory/nn_evolve.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
from neat.config import Config
1616
from neat import nn, population, statistics, parallel
17+
from neat.genome import DefaultGenome
18+
from neat.reproduction import DefaultReproduction
19+
from neat.stagnation import DefaultStagnation
1720

1821
# num_tests is the number of random examples each network is tested against.
1922
num_tests = 16
@@ -59,13 +62,15 @@ def run():
5962
# Determine path to configuration file.
6063
local_dir = os.path.dirname(__file__)
6164
config_path = os.path.join(local_dir, 'nn_config')
62-
config = Config(config_path)
65+
config = Config(DefaultGenome, DefaultReproduction, DefaultStagnation, config_path)
66+
67+
config.save('test_save_config.txt')
6368

6469
# This sinc function will be available if my_sinc_function is included in the
6570
# config file activation_functions option under the pheotype section.
6671
# Note that sinc is not necessarily useful for this example, it was chosen
6772
# arbitrarily just to demonstrate adding a custom activation function.
68-
config.genome_config.activation_defs.add('my_sinc_function', sinc)
73+
config.genome_config.add_activation('my_sinc_function', sinc)
6974

7075
pop = population.Population(config)
7176
#pe = parallel.ParallelEvaluator(4, eval_fitness)

neat/attributes.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
from random import choice, gauss, random
2+
from neat.config import ConfigParameter
3+
4+
# TODO: There is probably a lot of room for simplification of these classes using metaprogramming.
5+
6+
class BaseAttribute(object):
7+
def __init__(self, name):
8+
self.name = name
9+
for n, cname in zip(self.__config_items__, self.config_item_names()):
10+
setattr(self, n + "_name", cname)
11+
12+
def config_item_names(self):
13+
return ["{0}_{1}".format(self.name, i) for i in self.__config_items__]
14+
15+
16+
class FloatAttribute(BaseAttribute):
17+
__config_items__ = ["init_mean",
18+
"init_stdev",
19+
"replace_rate",
20+
"mutate_rate",
21+
"mutate_power",
22+
"max_value",
23+
"min_value"]
24+
25+
def get_config_params(self):
26+
return [ConfigParameter(n, float) for n in self.config_item_names()]
27+
28+
def clamp(self, value, config):
29+
min_value = getattr(config, self.min_value_name)
30+
max_value = getattr(config, self.max_value_name)
31+
return max(min(value, max_value), min_value)
32+
33+
def init_value(self, config):
34+
mean = getattr(config, self.init_mean_name)
35+
stdev = getattr(config, self.init_stdev_name)
36+
return self.clamp(gauss(mean, stdev), config)
37+
38+
def mutate_value(self, value, config):
39+
replace_rate = getattr(config, self.replace_rate_name)
40+
41+
r = random()
42+
if r < replace_rate:
43+
return self.init_value(config)
44+
45+
mutate_rate = getattr(config, self.mutate_rate_name)
46+
if r < replace_rate + mutate_rate:
47+
mutate_power = getattr(config, self.mutate_power_name)
48+
return value + gauss(0.0, mutate_power)
49+
50+
return self.clamp(value, config)
51+
52+
def validate(self, config):
53+
pass
54+
55+
56+
class BoolAttribute(BaseAttribute):
57+
__config_items__ = ["default",
58+
"mutate_rate"]
59+
60+
def get_config_params(self):
61+
default_name, rate_name = self.config_item_names()
62+
return [ConfigParameter(default_name, bool), ConfigParameter(rate_name, float)]
63+
64+
def init_value(self, config):
65+
default = getattr(config, self.default_name)
66+
67+
if default is None:
68+
return random() < 0.5
69+
70+
return default
71+
72+
def mutate_value(self, value, config):
73+
mutate_rate = getattr(config, self.mutate_rate_name)
74+
75+
r = random()
76+
if r < mutate_rate:
77+
# NOTE: we choose a random value here so that the mutation rate has the
78+
# same exact meaning as the rates given for the string and bool
79+
# attributes (the mutation operation *may* change the value but is not
80+
# guaranteed to do so).
81+
return random() < 0.5
82+
83+
return value
84+
85+
def validate(self, config):
86+
pass
87+
88+
89+
class StringAttribute(BaseAttribute):
90+
__config_items__ = ["default",
91+
"options",
92+
"mutate_rate"]
93+
94+
def get_config_params(self):
95+
default_name, opt_name, rate_name = self.config_item_names()
96+
return [ConfigParameter(default_name, str),
97+
ConfigParameter(opt_name, list),
98+
ConfigParameter(rate_name, float)]
99+
100+
def init_value(self, config):
101+
default = getattr(config, self.default_name)
102+
103+
if default is None:
104+
options = getattr(config, self.options_name)
105+
return choice(options)
106+
107+
return default
108+
109+
def mutate_value(self, value, config):
110+
mutate_rate = getattr(config, self.mutate_rate_name)
111+
112+
r = random()
113+
if r < mutate_rate:
114+
options = getattr(config, self.options_name)
115+
return choice(options)
116+
117+
return value
118+
119+
def validate(self, config):
120+
pass

0 commit comments

Comments
 (0)