3
3
4
4
Original code by Martin Jones @mojones:
5
5
https://gist.github.com/mojones/b809ba565c93feb8d44becc7b93e37c6
6
+
7
+ Usage:
8
+ ann_evolve.py [-h] [-g GENERATIONS] [-u MUTATION_RATE] [-b BOTTLENECK]
9
+ [-d mutation_distance] [-i PROCESSORS] [-o OUTPUT_FILE]
10
+ [-k STARTING_POPULATION]
11
+
12
+ Options:
13
+ -h --help show this
14
+ -g GENERATIONS how many generations to run the program for [default: 100]
15
+ -u MUTATION_RATE mutation rate i.e. probability that a given value will flip [default: 0.1]
16
+ -d MUTATION_DISTANCE amount of change a mutation will cause [default: 0.1]
17
+ -b BOTTLENECK number of individuals to keep from each generation [default: 10]
18
+ -i PROCESSORS number of processors to use [default: 1]
19
+ -o OUTPUT_FILE file to write statistics to [default: ann_out.csv]
20
+ -k STARTING_POPULATION starting population size for the simulation [default: 5]
6
21
"""
7
22
23
+
8
24
from __future__ import division
9
25
10
26
import copy
11
27
import random
28
+ from multiprocessing import Pool
12
29
from statistics import mean , pstdev
13
30
14
- import axelrod
15
- from axelrod .strategies .ann import split_weights
16
-
31
+ from docopt import docopt
17
32
18
-
19
-
20
- # def split_weights(weights, input_values, hidden_layer_size):
21
- # number_of_input_to_hidden_weights = input_values * hidden_layer_size
22
- # number_of_hidden_bias_weights = hidden_layer_size
23
- # number_of_hidden_to_output_weights = hidden_layer_size
24
- #
25
- # input2hidden = []
26
- # for i in range(0, number_of_input_to_hidden_weights, input_values):
27
- # input2hidden.append(weights[i:i + input_values])
28
- #
29
- # hidden2output = weights[
30
- # number_of_input_to_hidden_weights:number_of_input_to_hidden_weights + number_of_hidden_to_output_weights]
31
- # bias = weights[
32
- # number_of_input_to_hidden_weights + number_of_hidden_to_output_weights:]
33
- #
34
- # return (input2hidden, hidden2output, bias)
33
+ import axelrod as axl
34
+ from axelrod .strategies .ann import ANN , split_weights
35
+ from axelrod_utils import mean , pstdev
35
36
36
37
37
38
def get_random_weights (number ):
38
39
return [random .uniform (- 1 , 1 ) for _ in range (number )]
39
40
40
41
41
- def score_single (my_strategy_factory , other_strategy_factory , iterations = 200 ,
42
- debug = False ):
43
- if other_strategy_factory .classifier ['stochastic' ]:
42
+ def score_single (my_strategy_factory , other_strategy_factory , length = 200 ):
43
+ if other_strategy_factory ().classifier ['stochastic' ]:
44
44
repetitions = 10
45
45
else :
46
46
repetitions = 1
47
47
all_scores = []
48
48
for _ in range (repetitions ):
49
49
me = my_strategy_factory ()
50
50
other = other_strategy_factory ()
51
- me .set_tournament_attributes (length = iterations )
52
- other .set_tournament_attributes (length = iterations )
51
+ me .set_match_attributes (length = length )
52
+ other .set_match_attributes (length = length )
53
53
54
- g = axelrod .Game ()
55
- for _ in range (iterations ):
54
+ g = axl .Game ()
55
+ for _ in range (length ):
56
56
me .play (other )
57
- # print(me.history)
58
57
iteration_score = sum ([g .score (pair )[0 ] for pair in
59
- zip (me .history , other .history )]) / iterations
58
+ zip (me .history , other .history )]) / length
60
59
all_scores .append (iteration_score )
60
+ return sum (all_scores )
61
61
62
- def score_all_weights (population ):
63
- return sorted (pool .map (score_weights , population ), reverse = True )
64
-
62
+ def score_for (my_strategy_factory , other_strategies , iterations = 200 ):
63
+ my_scores = map (
64
+ lambda x : score_single (my_strategy_factory , x , iterations ),
65
+ other_strategies )
66
+ my_average_score = sum (my_scores ) / len (my_scores )
67
+ return my_average_score
65
68
66
- def score_weights (weights ):
69
+ def score_weights (weights , strategies , input_values = 17 , hidden_layer_size = 10 ):
67
70
in2h , h2o , bias = split_weights (weights , input_values , hidden_layer_size )
68
71
return (score_for (lambda : ANN (in2h , h2o , bias ), strategies ), weights )
69
72
73
+ from itertools import repeat
70
74
71
- def score_for (my_strategy_factory , other_strategies = strategies , iterations = 200 ,
72
- debug = False ):
73
- my_scores = map (
74
- lambda x : score_single (my_strategy_factory , x , iterations , debug = debug ),
75
- other_strategies )
76
- my_average_score = sum (my_scores ) / len (my_scores )
77
- return (my_average_score )
78
-
75
+ def score_all_weights (population , strategies ):
76
+ # args = (population, strategies)
77
+ results = pool .starmap (score_weights , zip (population , repeat (strategies )))
78
+ return sorted (results , reverse = True )
79
+ # return sorted(pool.map(score_weights, *args), reverse=True)
79
80
80
81
def evolve (starting_weights , mutation_rate , mutation_distance , generations ,
81
- bottleneck , starting_pop , output_file ):
82
+ bottleneck , strategies , output_file ):
82
83
83
84
current_bests = starting_weights
84
85
85
86
for generation in range (generations ):
86
87
87
88
with open (output_file , "a" ) as output :
88
89
89
- weights_to_copy = [x [1 ] for x in current_bests ]
90
-
90
+ # weights_to_copy = [x[1] for x in current_bests]
91
+ weights_to_copy = current_bests [ 0 : 3 ]
91
92
copies = []
92
-
93
93
for w1 in weights_to_copy :
94
94
for w2 in weights_to_copy :
95
95
crossover = random .randrange (len (w1 ))
@@ -107,12 +107,12 @@ def evolve(starting_weights, mutation_rate, mutation_distance, generations,
107
107
108
108
# map the population to get a list of (score, weights) tuples
109
109
# this list will be sorted by score, best weights first
110
- results = score_all_weights (population )
110
+ results = score_all_weights (population , strategies )
111
111
112
- current_bests = results [0 :bottleneck ]
112
+ current_bests = results [0 : bottleneck ]
113
113
114
114
# get all the scores for this generation
115
- scores = [score for score , table in results ]
115
+ scores = [score for score , weights in results ]
116
116
117
117
for value in [generation , results [0 ][1 ], results [0 ][0 ],
118
118
mean (scores ), pstdev (scores ), mutation_rate ,
@@ -124,3 +124,26 @@ def evolve(starting_weights, mutation_rate, mutation_distance, generations,
124
124
mutation_distance *= 0.99
125
125
126
126
return current_bests
127
+
128
+
129
+ if __name__ == '__main__' :
130
+ arguments = docopt (__doc__ , version = 'ANN Evolver 0.1' )
131
+ # set up the process pool
132
+ pool = Pool (processes = int (arguments ['-i' ]))
133
+ # Vars for the genetic algorithm
134
+ mutation_rate = float (arguments ['-u' ])
135
+ generations = int (arguments ['-g' ])
136
+ bottleneck = int (arguments ['-b' ])
137
+ mutation_distance = float (arguments ['-d' ])
138
+ starting_population = int (arguments ['-k' ])
139
+ output_file = arguments ['-o' ]
140
+
141
+ starting_weights = [get_random_weights (190 ) for _ in range (starting_population )]
142
+
143
+ strategies = [s for s in axl .all_strategies
144
+ if not s ().classifier ['long_run_time' ]]
145
+
146
+ evolve (starting_weights , mutation_rate , mutation_distance , generations ,
147
+ bottleneck , strategies , output_file )
148
+
149
+
0 commit comments