Skip to content

Instantly share code, notes, and snippets.

@lesguillemets
Created October 2, 2013 09:40
Show Gist options
  • Save lesguillemets/6791328 to your computer and use it in GitHub Desktop.
Save lesguillemets/6791328 to your computer and use it in GitHub Desktop.
nerve system emulator (?) license : MIT
#!/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