Evolving XOR

  • Genotype is an array of numbers, the weights of a NN
  • Population of genotypes, randomized
  • Select good ones
  • Crossover, mates good ones
  • Mutate some values
  • Repeat

Brain - the phenotype

                                 +--------------+
                                 |   1 Output   |      Output Layer
                                 +--------------+
                                        ^
                                        |
                                 +--------------+
                                 |   3 Hiddens  |      Hidden Layer
                                 +--------------+ 
                                        ^         
                                        |         
                                  +------------+
                                  |  2 Inputs  |       Input Layer
                                  +------------+

Gene - genotype

13 numbers, the weights of a NN brain

Evolution

  • Population size: 300
  • Mutation rate: 5%
  • Crossover rate: 60%
In [60]:
calico.Image("http://www.ecs.umass.edu/mie/labs/mda/mechanism/papers/gfig1.gif")
Out[60]:
In [1]:
from ai.ga import GA, Population, Gene
from ai.conx import Network

class NNGA(GA):
    def __init__(self, cnt):
        n = Network()
        n.addLayers(2, 3, 1)
        n.setInputs([[0.0, 0.0],
                     [0.0, 1.0],
                     [1.0, 0.0],
                     [1.0, 1.0]])
        n.setOutputs([[0.0],
                      [1.0],
                      [1.0],
                      [0.0]])
        n.setVerbosity(0)
        n.setTolerance(.4)
        n.setLearning(0)
        g = n.arrayify()
        self.network = n
        GA.__init__(self,
                    Population(cnt, Gene, size=len(g), verbose=1,
                               min=-10, max=10, maxStep = 1,
                               imin=-10, imax=10, 
                               elitePercent = .01),
                    mutationRate=0.05, crossoverRate=0.6,
                    maxGeneration=400, verbose=1)
    def fitnessFunction(self, genePos):
        self.network.unArrayify(self.pop.individuals[genePos].genotype)
        error, correct, count, pcorrect = self.network.sweep()
        return 4 - error
    def isDone(self):
        self.network.unArrayify(self.pop.bestMember.genotype)
        error, correct, count, pcorrect = self.network.sweep()
        print("Correct:", correct)
        return correct == 4
In [2]:
nnga = NNGA(300)
Conx using seed: 1398411316.62
crossoverRate  = 0.600
mutationRate   = 0.050
populationSize = 300
elitePercent   = 0.010
maxGeneration  = 400
================================================================================
------------------------------------------------------------
Initial population
Fitness: Total  657.84 Best  3.58 Average  2.19 Worst  1.01
Elite fitness: [3.308496314673213, 3.3424960937066777, 3.58200941080535]
In [3]:
nnga.evolve()
------------------------------------------------------------
Generation 1
Fitness: Total  667.46 Best  3.58 Average  2.22 Worst  1.21
Elite fitness: [3.58200941080535, 3.58200941080535, 3.58200941080535]
Correct: 3.0
------------------------------------------------------------
Generation 2
Fitness: Total  668.94 Best  3.66 Average  2.23 Worst  1.05
Elite fitness: [3.5820094108053504, 3.5820094108053504, 3.657290782142972]
Correct: 3.0
------------------------------------------------------------
Generation 3
Fitness: Total  682.89 Best  3.66 Average  2.28 Worst  1.14
Elite fitness: [3.5820094108053504, 3.657290782142972, 3.657290782142972]
Correct: 3.0
------------------------------------------------------------
Generation 4
Fitness: Total  683.60 Best  3.66 Average  2.28 Worst  0.89
Elite fitness: [3.657290782142972, 3.657290782142972, 3.661899746940796]
Correct: 3.0
------------------------------------------------------------
Generation 5
Fitness: Total  689.95 Best  3.66 Average  2.30 Worst  1.13
Elite fitness: [3.657290782142972, 3.657290782142972, 3.661899746940796]
Correct: 3.0
------------------------------------------------------------
Generation 6
Fitness: Total  687.92 Best  3.71 Average  2.29 Worst  1.05
Elite fitness: [3.657290782142972, 3.661899746940796, 3.7089245321872717]
Correct: 3.0
------------------------------------------------------------
Generation 7
Fitness: Total  702.34 Best  3.96 Average  2.34 Worst  1.08
Elite fitness: [3.799702771137147, 3.8825180848896026, 3.959332998998237]
Correct: 4.0
------------------------------------------------------------
Done evolving at generation 7
Current best individual [#198] 6.73 5.56 -3.76 8.77 4.22 -3.13 7.08 -8.31 6.29 -8.19 -5.27 -5.86 8.40 Fitness 3.95933299900
In [4]:
nnga.network.unArrayify(nnga.pop.bestMember.genotype)
nnga.network.setInteractive(1)
nnga.network.sweep()
-----------------------------------Pattern # 4
Display network 'Backprop Network':
=============================
Layer 'output': (Kind: Output, Size: 1, Active: 1, Frozen: 0)
Target    :  1.00 
Activation:  0.91 
=============================
Layer 'hidden': (Kind: Hidden, Size: 3, Active: 1, Frozen: 0)
Activation:  1.00 0.69 0.17 
=============================
Layer 'input': (Kind: Input, Size: 2, Active: 1, Frozen: 0)
Activation:  0.00 1.00 
<q>uit, <g>o, or press Ok: 
-----------------------------------Pattern # 1
Display network 'Backprop Network':
=============================
Layer 'output': (Kind: Output, Size: 1, Active: 1, Frozen: 0)
Target    :  0.00 
Activation:  0.07 
=============================
Layer 'hidden': (Kind: Hidden, Size: 3, Active: 1, Frozen: 0)
Activation:  1.00 0.00 0.00 
=============================
Layer 'input': (Kind: Input, Size: 2, Active: 1, Frozen: 0)
Activation:  1.00 1.00 
<q>uit, <g>o, or press Ok: 
-----------------------------------Pattern # 3
Display network 'Backprop Network':
=============================
Layer 'output': (Kind: Output, Size: 1, Active: 1, Frozen: 0)
Target    :  1.00 
Activation:  0.89 
=============================
Layer 'hidden': (Kind: Hidden, Size: 3, Active: 1, Frozen: 0)
Activation:  0.33 0.00 0.00 
=============================
Layer 'input': (Kind: Input, Size: 2, Active: 1, Frozen: 0)
Activation:  1.00 0.00 
<q>uit, <g>o, or press Ok: 
-----------------------------------Pattern # 2
Display network 'Backprop Network':
=============================
Layer 'output': (Kind: Output, Size: 1, Active: 1, Frozen: 0)
Target    :  0.00 
Activation:  0.30 
=============================
Layer 'hidden': (Kind: Hidden, Size: 3, Active: 1, Frozen: 0)
Activation:  0.98 0.23 0.03 
=============================
Layer 'input': (Kind: Input, Size: 2, Active: 1, Frozen: 0)
Activation:  0.00 0.00 
<q>uit, <g>o, or press Ok: 
Out[4]:
(0.11747453708187991, 4.0, 4, {'output': [4.0, 4, 4, 4]})
In [5]:
nnga.network.setInteractive(0)
In [6]:
nnga.network.propagate(input=[1, 0])
Out[6]:
array('d', [0.89166720221140705])
In [7]:
nnga.network.propagate(input=[0, 0])
Out[7]:
array('d', [0.30248469746855439])
In [4]:
from Graphics import Picture, Color

res = 50 # resolution
picture = Picture(res, res)
for x in range(res):
    for y in range(res):
        out = nnga.network.propagate(input=[x/res, y/res])[0]
        g = int(out * 255)
        picture.setColor(x, y, Color(g,g,g))
Picture(picture, 10.0)
Out[4]:
In [5]:
res = 50 # resolution
picture = Picture(res, res)
for x in range(res):
    for y in range(res):
        out = nnga.network.propagate(input=[x/res, y/res])[0]
        g = int(round(out) * 255)
        picture.setColor(x, y, Color(g,g,g))
Picture(picture, 10)
Out[5]:
In [ ]: