Binary operations using spiking neurons ======================================= We want to investigate how neurons can be used to solve binary tasks. The two states we consider are spiking and not spiking. In the following you are asked to implement some basic logic operations. The OR-operation ---------------- To realize the OR-operation we consider a network of three neurons. There are two input neurons connected to one output neuron. The output neuron is supposed to elicit a spike, if neuron 1 or neuron 2 fires. This logic is also shown in a truth table. .. raw:: html
neuron 1 neuron 2 output neuron
- - -
x - x
- x x
x x x
In order to implement this network, we need two excitatory synapses. Their weight must be chosen such that a stimulation coming from neuron 1 or 2 is strong enough to elicit a spike in the output neuron. .. code:: ipython3 import pynn_brainscales.brainscales2 as pynn import matplotlib.pyplot as plt %matplotlib inline # set the environment from _static.common.helpers import setup_hardware_client, get_nightly_calibration setup_hardware_client() # load automatic calibration and set up pynn calib = get_nightly_calibration() pynn.setup(initial_config=calib) # create input neurons # these forward spikes at the times specified in `spike_time` ########## change here ########## spike_time1 = [0.2] spike_time2 = [] ################################# neuron1 = pynn.Population(1, pynn.cells.SpikeSourceArray(spike_times=spike_time1)) neuron2 = pynn.Population(1, pynn.cells.SpikeSourceArray(spike_times=spike_time2)) # create output neuron output_neuron = pynn.Population(1, pynn.cells.HXNeuron()) # monitor its activity output_neuron.record(["spikes", "v"]) # define synapses and set their weights (range: 0 - 63) ########## change here ########## synapse_weight1 = 63 synapse_weight2 = 32 ################################# synapse1 = pynn.synapses.StaticSynapse(weight=synapse_weight1) synapse2 = pynn.synapses.StaticSynapse(weight=synapse_weight2) # create neuron connections pynn.Projection(neuron1, output_neuron, pynn.AllToAllConnector(), synapse_type=synapse1, receptor_type="excitatory") pynn.Projection(neuron2, output_neuron, pynn.AllToAllConnector(), synapse_type=synapse2, receptor_type="excitatory") # run the network for a specified time, # the duration is set in milliseconds duration = 0.5 pynn.run(duration) # examine the spikes of the output neuron spiketrain = output_neuron.get_data("spikes").segments[0].spiketrains[0] print(f"The output neuron fired {len(spiketrain)} times.") print(f"The spiketimes were: {spiketrain}") # the membrane potential of the output neuron can be visualized, too mem_v = output_neuron.get_data("v").segments[0].irregularlysampledsignals[0] plt.figure() plt.plot(mem_v.times, mem_v) plt.xlabel("time [ms]") plt.ylabel("membrane potential [LSB]") plt.show() pynn.end() Check if the network works correctly. To do so, try different combinations of stimuli of the input neurons and different synaptic weights. Maybe, even with maximum weight the input is not strong enough to forward a spike. What ways can you think of to overcome this problem? Check your hypotheses! The AND-operation ----------------- Now it is your turn to implement a network. The next operation we consider is the AND-operation. Similar to the OR-operation, we again have two input neurons and one output neuron. This time, however, the latter should only fire exactly if neuron 1 and neuron 2 fire. .. raw:: html
neuron 1 neuron 2 output neuron
- - -
x - -
- x -
x x x
Think about how the network could look like and program it using the previous code. .. code:: ipython3 import pynn_brainscales.brainscales2 as pynn import matplotlib.pyplot as plt %matplotlib inline # set the environment from _static.common.helpers import setup_hardware_client, get_nightly_calibration setup_hardware_client() # load automatic calibration and set up pynn calib = get_nightly_calibration() pynn.setup(initial_config=calib) # your code pynn.end() The NOT-operation ----------------- Furthermore, let’s consider the NOT-operation. Here, we only have one input neuron whose signal is to be negated by the output neuron. .. raw:: html
input neuron output neuron
- x
x -
Think about how a network can look like that fulfills this task. Hint: You will need a help-neuron. .. code:: ipython3 import pynn_brainscales.brainscales2 as pynn import matplotlib.pyplot as plt %matplotlib inline # set the environment from _static.common.helpers import setup_hardware_client, get_nightly_calibration setup_hardware_client() # load automatic calibration and set up pynn calib = get_nightly_calibration() pynn.setup(initial_config=calib) # your code pynn.end() The XOR-operation ----------------- Lastly, let’s consider the XOR-operation (e**X**\ clusive **OR**). Here, the output neuron should only fire if exactly one of the input neurons fires, but not if both of them fire. .. raw:: html
neuron 1 neuron 2 output neuron
- - -
x - x
- x x
x x -
Start by sketching a network that in your opinion should fulfill this task. Then, implement it and prove its functioning. .. code:: ipython3 import pynn_brainscales.brainscales2 as pynn import matplotlib.pyplot as plt %matplotlib inline # set the environment from _static.common.helpers import setup_hardware_client, get_nightly_calibration setup_hardware_client() # load automatic calibration and set up pynn calib = get_nightly_calibration() pynn.setup(initial_config=calib) # your code pynn.end() These operations are quite simple, but very powerful. Connected in series, it is possible to build any Boolean expression however complicated it might be. This is the basis for what modern processors do. Concluding, we see that neurons are Turing-complete, i.e. in principle they can do anything a computer does, too.