Created
October 2, 2013 09:40
-
-
Save lesguillemets/6791328 to your computer and use it in GitHub Desktop.
nerve system emulator (?)
license : MIT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# encoding:utf-8 | |
import random | |
THRESHOLD = 1 # threshold for neuron's firing. | |
SYNAPSE_LIMIT = 4 # how strong synapses are allowed to be. | |
LTPRATIO = 1.1 # LTP : strength = strength*LTPRATIO | |
FORGETRATIO = 0.95 # A little forgetfullness | |
SUPPRESSION_RATIO = 0.5 # the frequency of suppressive synapses | |
SUP_WEAKNESS = 0.7 # when initialising, | |
# set the strength of suppressive synapses | |
class Neuron(object): | |
# 神経細胞体 class. | |
# i) synapse からの入力を受けることができ, | |
# ii) ある間にうけた入力の総和が threshold を超えれば | |
# iii) 発火し,本人から出ていく synapse に伝達される. | |
# Neuron 同士の結合情報は Synapse class, NSystem class に任せ, | |
# Neuron class から能動的に特定のシナプスに情報を与えることはない. | |
# ... はずだったが, | |
# postsynapses に PostNeuron を '持つ' ことに. | |
def __init__(self, number=None, threshold = THRESHOLD): | |
self.threshold = threshold | |
self.inputstack = 0 | |
self.number = number | |
self.isfiring = False | |
self.wasfiring = False | |
self.isalive = True | |
self.postsynapses = [] | |
def getinput(self, x): | |
# 大きさ x の入力を受ける. | |
# 入力は self.inputstack に蓄えられ,'1 世代' の入力となる | |
self.inputstack += x | |
def update(self): | |
self.wasfiring = self.isfiring | |
self.isfiring = self.doesfire() | |
self.clear() | |
def add_synapse(self, postneuron, x): | |
self.postsynapses.append(Synapse(postneuron, x)) | |
def clear(self): | |
# inputstack を空に.次の'世代'の入力を受けられる | |
self.inputstack = 0 | |
def doesfire(self): | |
# 発火するか | |
return self.inputstack >= self.threshold | |
def __repr__(self): | |
return int(self.isfiring) | |
def __str__(self): | |
return str(int(self.isfiring)) | |
class Synapse(object): | |
# シナプス class. | |
# 結合元 neuron に保持され, 結合先 neuron を保持する. | |
# pre-synaptic cell の fire に対し, | |
# {x <- R | -limit <= x <= limit } を満たす出力を | |
# post-synaptic cell に与える. | |
# 両端が active になるとき LTPratio を x に乗じる形での学習を行う. | |
# active な入力を受けても出力先が active にならなかった場合は逆を行う. | |
def __init__(self, postn, x, | |
limit = SYNAPSE_LIMIT, LTPratio = LTPRATIO, | |
forgetratio = FORGETRATIO, isactive = True): | |
self.postn = postn | |
self.x = x | |
self.limit = 2 | |
self.isactive = True | |
self.LTPratio = LTPratio | |
self.forgetratio = forgetratio | |
def givefire(self): | |
if self.isactive: | |
self.postn.getinput(self.x) | |
def LTP(self): | |
# this function doesn't check if LTP can occur or not. | |
# because Synapse class doesn't know whether | |
# its postneuron fires or not. | |
self.x *= self.LTPratio | |
if -self.limit > self.x: | |
self.x = -self.limit | |
elif self.x > self.limit: | |
self.x = self.limit | |
def reverseLTP(self): | |
self.x /= self.LTPratio | |
def forgetalittle(self): | |
# LTP, LTD にかかわらずシナプス強度を少し弱める場合. | |
self.x *= self.forgetratio | |
class NSystem(object): | |
def __init__(self, number_of_neurons, inneurons, outneurons, | |
suppression_ratio = SUPPRESSION_RATIO, | |
sup_weakness = SUP_WEAKNESS): | |
# number_of_neurons :: Int, inneurons :: [Int], outneurons :: [Int] | |
# neurons : [Neuron], numbered. | |
self.neurons = [] # neurons in the system | |
self.inneurons = [] # neurons to (conveniently) receive input from us. | |
self.outneurons = [] # neurons from which we get output. | |
self.n_of_neurons = number_of_neurons | |
self.suppression_ratio = suppression_ratio | |
self.sup_weakness = sup_weakness | |
for i in xrange(number_of_neurons): | |
self.neurons.append(Neuron(i)) | |
for n in inneurons: | |
self.inneurons.append( self.neurons[n] ) | |
for n in outneurons: | |
self.outneurons.append( self.neurons[n] ) | |
def step(self): | |
# if a neuron is firing, its postsynapses gives fire. | |
for neuron in self.neurons: | |
if neuron.isfiring: | |
for synapse in neuron.postsynapses: | |
synapse.givefire() | |
# updates the states of the neurons. | |
for neuron in self.neurons: | |
neuron.update() | |
# LTP: for each synapse, | |
# if the two neurons at its ends is/was firing, | |
# let its LTP occur. | |
# preneuron.wasfiring and not postneuron.isfiring | |
# -> reversed LTP (LTD). | |
for neuron in self.neurons: | |
if neuron.wasfiring: | |
for synapse in neuron.postsynapses: | |
if synapse.postn.isfiring: | |
synapse.LTP() | |
else: | |
synapse.reverseLTP() | |
def connect(self, n,m, x): | |
# connects neuron n to neuron m with a synapse with strength x. | |
self.neurons[n].add_synapse(self.neurons[m], x) | |
def connect_with_random_strength(self, n,m): | |
# connects neuron n to neuron m with a synapse | |
# with random strength (-SYNAPSE_LIMIT < s <SYNAPSE_LIMIT) | |
sgn = ((random.random() < self.suppression_ratio) | |
and -self.sup_weakness) or 1 | |
self.connect( n,m, random.uniform(0, SYNAPSE_LIMIT)*sgn ) | |
def makeweb(self, n, ms): | |
# neuron n から list で与えられる neurons ms のそれぞれへ | |
# synapse を形作る,syntax sugar のようなもの. | |
for m in ms: | |
self.connect_with_random_strength(n,m) | |
def give_input(self, xs): | |
# 予め指定していた inneurons に (synapse が与えるのと同様の)刺激を与える | |
for (x,n) in zip(xs, self.inneurons): | |
n.getinput(x) | |
def get_output(self): | |
# receives output from outneurons, return as a list. | |
output = [] | |
for (i,n) in enumerate(self.outneurons): | |
output.append((i, str(n))) | |
return output | |
def stimulate(self, n, x): | |
# stimulate the specified neuron. | |
self.inneurons[n].getinput(x) | |
def __repr__(self): | |
rep = '' | |
for (i,n) in enumerate(self.neurons): | |
for syn in n.postsynapses: | |
rep += str(i)+' ' | |
rep += str(syn.postn.number) + ' ' | |
rep += str(syn.x) + '\n' | |
rep += str(self.get_output()) | |
return rep |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment