Skip to content

Instantly share code, notes, and snippets.

@joshlemer
Last active December 20, 2015 10:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshlemer/6114769 to your computer and use it in GitHub Desktop.
Save joshlemer/6114769 to your computer and use it in GitHub Desktop.
The idea behind this project is that the functionality of a neuron is really simple (as far as my knowledge goes). There are inputs and an output. If there are enough inputs firing at a time, then the neuron will output 1. Otherwise 0. And also there can be "negative" inputs - inputs which decrement the count when turned on rather than increment…
from neuron import *
import sys
class Brain:
def __init__(self, ins, middles, outs):
input_string = "0" * ins
input_bits = self.get_input(input_string)
#print input_string
self.input_neurons = []
self.middle_neurons = []
self.output_neurons = []
for i in range(0,ins):
dummy = Neuron(not input_bits[i] + 0)
self.input_neurons.append(dummy)
for i in range(0, middles):
dummy = Neuron(1)
self.middle_neurons.append(dummy)
for i in range(0,outs):
dummy = Neuron(1)
self.output_neurons.append(dummy)
def destroy(self):
for neuron in self.input_neurons:
neuron.destroy()
del(neuron)
for neuron in self.middle_neurons:
neuron.destroy()
del(neuron)
for neuron in self.output_neurons:
neuron.destroy()
del(neuron)
def add_neuron(self, neuron ):
self.middle_neurons.append(neuron)
def cycle(self, num_cycles):
for neuron in self.input_neurons:
neuron.update_count()
neuron.update_signal()
for i in range(0, num_cycles):
for neuron in self.middle_neurons:
neuron.update_count()
for neuron in self.middle_neurons:
neuron.update_signal()
for neuron in self.output_neurons:
neuron.update_count()
for neuron in self.output_neurons:
neuron.update_signal()
def set_input(self, input_string):
length = len(input_string)
maxLen = len(self.input_neurons)
if (length > maxLen):
input_string = input_string[-1 * length:]
while(len(input_string) < maxLen):
input_string = "0" + input_string
input_bits = self.get_input(input_string)
for i in range(0, maxLen):
self.input_neurons[i].threshhold = (not input_bits[i] + 0)
def get_input(self, input_string):
input_bits = []
for i in range(0, len(input_string)):
input_bits.insert(0, ord(input_string[i]) - 48)
return input_bits
def get_output(self):
string = ''
for i in range(len(self.output_neurons) - 1, -1, -1):
string += chr(48 + self.output_neurons[i].signal)
return string
def print_output(self):
for i in range(len(self.output_neurons) - 1, -1, -1):
sys.stdout.write(chr(48 + self.output_neurons[i].signal))
print
def print_brain(self):
print "Input Neurons:"
i = 0
for neuron in self.input_neurons:
print "\tinput_neurons[%d]\tsignal: %d\tcount%d" % (i, neuron.signal, neuron.count)
i += 1
print "Middle Neurons:"
i=0
for neuron in self.middle_neurons:
print "\tmiddle_neurons[%d]\tsignal: %d\tcount%d" % (i, neuron.signal, neuron.count)
i+=1
print "Output Neurons:"
i=0
for neuron in self.middle_neurons:
print "\toutput_neurons[%d]\tsignal: %d\tcount%d" % (i, neuron.signal, neuron.count)
i+=1
The idea behind this project is that the functionality of a neuron is really simple (as far as my knowledge goes). There are inputs and an output. If there are enough inputs firing at a time, then the neuron will output 1. Otherwise 0. And also there can be "negative" inputs - inputs which decrement the count when turned on rather than increment it. So something like:
if(positive inputs - negative inputs >= threshhold):
output 1
else:
output 0
The goal is to be able to simulate how a collection of these neurons would react when connected to each other. Specificially, designate "input" and "output" neurons for the system so the 'brain' can be fed input information, perform some computation, then send it to output.
The mechanism by which these would be designed is by evolution. evolve.py provides the functions to take a template brain and mutate it by tweaking some of the parameters. evaluate.py then can take those mutated brains together with intended input/output pairs, and score how closely the brain performs what we want it to do. So the thought was that we could make a trivial brain as is made in inEqualsOut.py, then iteratively make batches of mutated brains, pick the best performing one(s), and repeat until desired.
neuron,py provides the object code for individual neurons
brain.py provides the object code for collections of neurons, with so-called 'input neurons', those which hold the input value, 'output neurons' which are read for output, and 'middle neurons', which are subject to the mutations in evolve.py, and which are responsible for the computation of the brain.
inEqualsOut.py constructs and saves the trivial case brain, where input = output. Simply change inString to whichever string, and the brain will output that string.
To run, save the python files, and in powershell or whichever, simply enter "python inEqualsOut.py". This will save the trivial brain, then run "python evolve.py". This takes the trivial brain and each time you press enter, the program will do a random amount of mutations, outputing the number of neurons at each mutation, then the resulting output string the brain computed, then finally
from brain import *
from neuron import *
import pickle, copy
class test:
class entry:
def __init__ (self, input_str, target):
self.input_str = input_str
self.target = target
self.score = 0.0
self.observed = None
def calc_score(self):
if(self.observed != None):
score = 0.0
inc = 0.5 / len(self.target)
for i in range(0, len(self.target)):
if (self.target[i] == self.observed[i]):
score += inc
if (score == 0.5):
score = 1
self.score = score
else:
self.score = 0.0
return score
def __init__(self):
self.entries = []
self.recent_score = -1.0
def calc_score(self):
score = 0.0
for entry in self.entries:
score += entry.calc_score()
score = score / len(self.entries)
return score
def perform_test(self, the_brain, cycles):
for entry in self.entries:
new_brain = copy.deepcopy(the_brain)
new_brain.set_input(entry.input_str)
new_brain.cycle(cycles)
entry.observed = new_brain.get_output()
entry.calc_score()
self.recent_score = self.calc_score()
def add_entry(self, input_str, target):
self.entries.append(self.entry(input_str, target))
from evaluate import *
import random
def get_mutants(the_brain, num_brains):
new_brains = []
random.seed(None)
for i in range(0,num_brains):
new_brains.append(mutate(the_brain))
return new_brains
def mutate(the_brain):
mutations = 1
while(random.randint(0,1)):
mutations += 1
new_brain = copy.deepcopy(the_brain)
mute_strats = [duplicate,adjust_threshhold,add_outputs,remove_rand_neuron]
for i in range(0,mutations):
randy = random.randint(0,len(mute_strats) - 1)
mute_strats[randy](new_brain)
return new_brain
def rand_neuron(the_brain):
print len(the_brain.middle_neurons)
randy = random.randint(0, len(the_brain.middle_neurons) - 1)
return the_brain.middle_neurons[randy]
def duplicate(the_brain):
the_brain.add_neuron(copy.deepcopy(rand_neuron(the_brain)))
def adjust_threshhold(the_brain):
nums = [-1,1]
rand_neuron(the_brain).threshhold += random.randrange(-1,2,2)
def add_outputs(the_brain):
rand_neuron(the_brain).add_output(rand_neuron(the_brain), random.randrange(-1,2,2))
def remove_rand_neuron(the_brain):
if(len(the_brain.middle_neurons) > 10):
randy = rand_neuron(the_brain)
for neuron in the_brain.middle_neurons:
while(randy in neuron.pos_inputs):
neuron.pos_inputs.remove(randy)
while(randy in neuron.neg_inputs):
neuron.neg_inputs.remove(randy)
while(randy in the_brain.middle_neurons):
the_brain.middle_neurons.remove(randy)
del(randy)
old = pickle.load(open("save.p", "rb"))
old.set_input("0000000000000011")
new = mutate(old)
while(raw_input("") != '0'):
new = mutate(old)
new.cycle(10)
new.print_output()
print len(new.middle_neurons)
old.destroy()
del(old)
old = new
from brain import *
from evolve import *
import pickle
inString = "0000000000000000"
a = Brain(len(inString), len(inString), len(inString))
a.set_input(inString)
for i in range(0, len(inString)):
a.input_neurons[i].add_output(a.middle_neurons[i], 1)
a.middle_neurons[i].add_output(a.output_neurons[i], 1)
a.cycle(100)
a.print_output()
pickle.dump(a, open("save.p", "wb"))
class Neuron:
def __init__(self, threshhold):
self.threshhold = threshhold
self.pos_inputs = []
self.neg_inputs = []
self.outputs = []
self.count = 0
self.signal = 0
def destroy(self):
del (self.threshhold)
del(self.pos_inputs)
del(self.neg_inputs)
del(self.outputs)
del(self.count)
del(self.signal)
def add_output(self, new_output, sign):
self.outputs.append(new_output)
new_output.add_input(self, sign)
def add_input(self, new_input, sign):
if (sign == 1):
self.pos_inputs.append(new_input)
else:
self.neg_inputs.append(new_input)
def remove_output(self, rem_out):
if(rem_out in self.outputs):
self.outputs.remove(rem_out)
def remove_input(self, rem_in):
removed = self.remove_input_sign(rem_in, 1)
if (not removed):
self.remove_input_sign(rem_in, -1)
def remove_input_sign(self, rem_in, sign):
if(sign == 1 and rem_in in self.pos_inputs):
self.pos_inputs.remove(rem_in)
else:
self.neg_inputs.remove(rem_in)
def update_count(self):
self.count = 0
for x in self.pos_inputs:
if(x.signal == 1):
self.count += 1
for x in self.neg_inputs:
if(x.signal == 1):
self.count += -1
def update_signal(self):
if(self.count >= self.threshhold):
self.signal = 1
else:
self.signal = 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment