Skip to content

Commit f0fd3c2

Browse files
committed
Abstract out common code and refactor
1 parent f0912dc commit f0fd3c2

File tree

7 files changed

+354
-371
lines changed

7 files changed

+354
-371
lines changed

analyze_data.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ def read_top_tables(filename, n):
77
with open(filename) as data:
88
for line in data:
99
results.append(line.split(','))
10-
results.sort(reverse=True, key=itemgetter(2))
10+
11+
with open(filename) as data:
12+
reader = csv.reader(data)
13+
for line in reader:
14+
results.append((float(line[3]), int(line[0]), line[-1]))
15+
results.sort(reverse=True, key=itemgetter(0))
1116
return results[:n]
1217

1318
if __name__ == "__main__":
1419
data_filename = sys.argv[1]
1520
results = read_top_tables(data_filename, 10)
1621
for result in results:
17-
print(result[2], result[1])
22+
print(result[0], result[-1])

analyze_weights.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import csv
2+
from operator import itemgetter
3+
import sys
4+
5+
def read_top_tables(filename, n):
6+
"""Read in the n top performing results from a given file"""
7+
results = []
8+
with open(filename) as data:
9+
reader = csv.reader(data)
10+
for line in reader:
11+
results.append((float(line[5]), int(line[0]),
12+
list(map(float, line[6:]))))
13+
results.sort(reverse=True, key=itemgetter(0))
14+
return results[:n]
15+
16+
if __name__ == "__main__":
17+
data_filename = sys.argv[1]
18+
results = read_top_tables(data_filename, 1)
19+
for result in results:
20+
print(result)

ann_evolve.py

Lines changed: 83 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -6,125 +6,122 @@
66
77
Usage:
88
ann_evolve.py [-h] [-g GENERATIONS] [-u MUTATION_RATE] [-b BOTTLENECK]
9-
[-d mutation_distance] [-i PROCESSORS] [-o OUTPUT_FILE]
10-
[-k STARTING_POPULATION]
9+
[-d MUTATION_DISTANCE] [-i PROCESSORS] [-o OUTPUT_FILE]
10+
[-k STARTING_POPULATION] [-n NOISE]
1111
1212
Options:
1313
-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.5]
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]
14+
-g GENERATIONS how many generations to run the program for [default: 10000]
15+
-u MUTATION_RATE mutation rate i.e. probability that a given value will flip [default: 0.4]
16+
-d MUTATION_DISTANCE amount of change a mutation will cause [default: 10]
17+
-b BOTTLENECK number of individuals to keep from each generation [default: 6]
18+
-i PROCESSORS number of processors to use [default: 4]
19+
-o OUTPUT_FILE file to write statistics to [default: weights.csv]
2020
-k STARTING_POPULATION starting population size for the simulation [default: 5]
21+
-n NOISE match noise [default: 0.0]
2122
"""
2223

23-
24-
from __future__ import division
25-
26-
import copy
27-
import random
24+
import csv
25+
from copy import deepcopy
26+
from itertools import repeat
2827
from multiprocessing import Pool
28+
import os
29+
import random
2930
from statistics import mean, pstdev
3031

3132
from docopt import docopt
33+
import numpy as np
3234

33-
import axelrod as axl
3435
from axelrod.strategies.ann import ANN, split_weights
35-
from axelrod_utils import mean, pstdev
36+
from axelrod_utils import score_for, objective_match_score, objective_match_moran_win
3637

38+
## Neural network specifics
3739

3840
def get_random_weights(number):
3941
return [random.uniform(-1, 1) for _ in range(number)]
4042

41-
def score_single(my_strategy_factory, other_strategy_factory, length=200):
42-
if other_strategy_factory().classifier['stochastic']:
43-
repetitions = 10
44-
else:
45-
repetitions = 1
46-
all_scores = []
47-
for _ in range(repetitions):
48-
me = my_strategy_factory()
49-
other = other_strategy_factory()
50-
me.set_match_attributes(length=length)
51-
other.set_match_attributes(length=length)
52-
53-
g = axl.Game()
54-
for _ in range(length):
55-
me.play(other)
56-
iteration_score = sum([g.score(pair)[0] for pair in
57-
zip(me.history, other.history)]) / length
58-
all_scores.append(iteration_score)
59-
return sum(all_scores) / repetitions
60-
61-
def score_for(my_strategy_factory, other_strategies, iterations=200):
62-
my_scores = list(map(
63-
lambda x: score_single(my_strategy_factory, x, iterations),
64-
other_strategies))
65-
my_average_score = sum(my_scores) / len(my_scores)
66-
return my_average_score
67-
68-
def score_weights(weights, strategies, input_values=17, hidden_layer_size=10):
43+
def score_weights(weights, strategies, noise, input_values=17,
44+
hidden_layer_size=10):
6945
in2h, h2o, bias = split_weights(weights, input_values, hidden_layer_size)
70-
return (score_for(lambda: ANN(in2h, h2o, bias), strategies), weights)
71-
72-
from itertools import repeat
73-
74-
def score_all_weights(population, strategies):
75-
results = pool.starmap(score_weights, zip(population, repeat(strategies)))
46+
args = [in2h, h2o, bias]
47+
return (score_for(ANN, args=args, opponents=strategies, noise=noise,
48+
objective=objective_match_score), weights)
49+
50+
def score_all_weights(population, strategies, noise, hidden_layer_size=10):
51+
results = pool.starmap(score_weights,
52+
zip(population, repeat(strategies), repeat(noise),
53+
repeat(10), repeat(hidden_layer_size)))
7654
return list(sorted(results, reverse=True))
7755

56+
## Evolutionary Algorithm
57+
58+
def crossover(weights_collection):
59+
copies = []
60+
for i, w1 in enumerate(weights_collection):
61+
for j, w2 in enumerate(weights_collection):
62+
if i == j:
63+
continue
64+
crosspoint = random.randrange(len(w1))
65+
new_weights = deepcopy(w1[0:crosspoint]) + deepcopy(w2[crosspoint:])
66+
copies.append(new_weights)
67+
return copies
68+
69+
def mutate(copies, mutation_rate):
70+
randoms = np.random.random((len(copies), 190))
71+
for i, c in enumerate(copies):
72+
for j in range(len(c)):
73+
if randoms[i][j] < mutation_rate:
74+
r = 1 + random.uniform(-1, 1) * mutation_distance
75+
c[j] = c[j] * r
76+
return copies
77+
7878
def evolve(starting_weights, mutation_rate, mutation_distance, generations,
79-
bottleneck, strategies, output_file):
79+
bottleneck, strategies, output_file, noise, hidden_layer_size=10):
8080

81-
# Append scores
81+
# Append scores of 0 to starting parameters
8282
current_bests = [[0, x] for x in starting_weights]
8383

84-
for generation in range(generations):
85-
with open(output_file, "a") as output:
86-
weights_to_copy = [x[1] for x in current_bests]
87-
copies = []
88-
# Crossover
89-
for w1 in weights_to_copy:
90-
for w2 in weights_to_copy:
91-
crossover = random.randrange(len(w1))
92-
new_weights = copy.deepcopy(
93-
w1[0:crossover]) + copy.deepcopy(w2[crossover:])
94-
copies.append(new_weights)
84+
with open(output_file, 'w') as output:
85+
writer = csv.writer(output)
9586

87+
for generation in range(generations):
88+
print("Generation " + str(generation))
89+
90+
weights_to_copy = [x[1] for x in current_bests] + \
91+
[get_random_weights(19 * hidden_layer_size) for _ in
92+
range(2)]
93+
# Crossover
94+
copies = crossover(weights_to_copy)
9695
# Mutate
97-
for _, c in copies:
98-
for i in range(len(c)):
99-
if random.random() < mutation_rate:
100-
r = 1 + random.uniform(-1, 1) * mutation_distance
101-
c[i] = c[i] * r
96+
copies = mutate(copies, mutation_rate)
10297

10398
population = copies + weights_to_copy
10499

105100
# map the population to get a list of (score, weights) tuples
106101
# this list will be sorted by score, best weights first
107-
results = score_all_weights(population, strategies)
102+
results = score_all_weights(population, strategies, noise=noise,
103+
hidden_layer_size=hidden_layer_size)
108104

109105
current_bests = results[0: bottleneck]
110106

111107
# get all the scores for this generation
112-
scores = [score for score, weights in results]
108+
scores = [score for (score, weights) in results]
113109

114-
for value in [generation, results[0][1], results[0][0],
115-
mean(scores), pstdev(scores), mutation_rate,
116-
mutation_distance]:
117-
output.write(str(value) + "\t")
118-
output.write("\n")
119-
print("Generation", generation, "| Best Score:", scores[0])
120-
mutation_rate *= 0.99
121-
mutation_distance *= 0.99
110+
# Write the data
111+
row = [generation, mean(scores), pstdev(scores), mutation_rate,
112+
mutation_distance, results[0][0]]
113+
row.extend(results[0][1])
114+
writer.writerow(row)
115+
output.flush()
116+
os.fsync(output.fileno())
117+
118+
print("Generation", generation, "| Best Score:", results[0][0])
122119

123120
return current_bests
124121

125122

126123
if __name__ == '__main__':
127-
arguments = docopt(__doc__, version='ANN Evolver 0.1')
124+
arguments = docopt(__doc__, version='ANN Evolver 0.2')
128125
# set up the process pool
129126
pool = Pool(processes=int(arguments['-i']))
130127
# Vars for the genetic algorithm
@@ -134,13 +131,15 @@ def evolve(starting_weights, mutation_rate, mutation_distance, generations,
134131
mutation_distance = float(arguments['-d'])
135132
starting_population = int(arguments['-k'])
136133
output_file = arguments['-o']
134+
noise = float(arguments['-n'])
137135

138-
starting_weights = [[0, get_random_weights(190)] for _ in range(starting_population)]
139-
140-
strategies = [s for s in axl.strategies
141-
if not s().classifier['long_run_time']]
136+
hidden_layer_size = 10
137+
size = 19 * hidden_layer_size
142138

143-
evolve(starting_weights, mutation_rate, mutation_distance, generations,
144-
bottleneck, strategies, output_file)
139+
starting_weights = [get_random_weights(size) for _ in range(starting_population)]
145140

141+
# strategies = axl.short_run_time_strategies
146142

143+
evolve(starting_weights, mutation_rate, mutation_distance, generations,
144+
bottleneck, strategies, output_file, noise,
145+
hidden_layer_size=hidden_layer_size)

0 commit comments

Comments
 (0)