diff --git a/.gitignore b/.gitignore index 06205f5..8cfe326 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ __pycache__ *application_generated_data_files/ *reports/ .mypy_cache/ +*big_with_labels/ +*graphs/ \ No newline at end of file diff --git a/.ratexcludes b/.ratexcludes index f63e490..276e7df 100644 --- a/.ratexcludes +++ b/.ratexcludes @@ -1,5 +1,6 @@ **/*.colour_map **/*.col +**/*.npy **/SpiNNUtils/** **/SpiNNMachine/** **/SpiNNMan/** diff --git a/eprop_testing/1000 neurons - 10Hz - 100*1024s.npy b/eprop_testing/1000 neurons - 10Hz - 100*1024s.npy new file mode 100644 index 0000000..4f2337b Binary files /dev/null and b/eprop_testing/1000 neurons - 10Hz - 100*1024s.npy differ diff --git a/eprop_testing/__init__.py b/eprop_testing/__init__.py new file mode 100644 index 0000000..b5b0468 --- /dev/null +++ b/eprop_testing/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/eprop_testing/create_pops_for_incremental_learning.py b/eprop_testing/create_pops_for_incremental_learning.py new file mode 100644 index 0000000..c187782 --- /dev/null +++ b/eprop_testing/create_pops_for_incremental_learning.py @@ -0,0 +1,425 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +from spynnaker.pyNN.spynnaker_external_device_plugin_manager import SpynnakerExternalDevicePluginManager +from plot_graph import draw_graph_from_list, plot_learning_curve +from incremental_config import * + +def load_connections(npy_label, pop_size, rec=True): + in_conn = [list(ele) for ele in np.load(npy_label+' in.npy').tolist()] + if rec: + rec_conn = [list(ele) for ele in np.load(npy_label+' rec.npy').tolist()] + out_conn = [list(ele) for ele in np.load(npy_label+' out.npy').tolist()] + for ndx in range(len(in_conn)): + if in_conn[ndx][3] == 16 and in_conn[ndx][0] == 0: + in_conn[ndx][3] = 0 + if rec: + for ndx in range(len(rec_conn)): + if rec_conn[ndx][3] == 16 and rec_conn[ndx][0] == 0: + rec_conn[ndx][3] = 0 + for ndx in range(len(out_conn)): + if out_conn[ndx][3] == 16 and out_conn[ndx][0] == 0: + out_conn[ndx][3] = 0 + checking_delays = [[] for i in range(pop_size)] + list_to_check = in_conn + if rec: + list_to_check = in_conn+rec_conn + for [pre, post, weight, delay] in list_to_check: + if delay not in checking_delays[post]: + checking_delays.append(delay) + else: + print("delays are overlapped") + Exception + if not rec: + rec_conn = [] + return in_conn, rec_conn, out_conn + +def weight_distribution(pop_size): + base_weight = np.random.randn() / np.sqrt(pop_size) #+ 0.5 + # base_weight = 0 + return base_weight + +def probability_connector(pre_pop_size, post_pop_size, prob, offset=0): + connections = [] + max_syn_per_neuron = 0 + for j in range(post_pop_size): + neuron_syn_count = 0 + delay_count = offset + for i in range(pre_pop_size): + if np.random.random() < prob: + neuron_syn_count += 1 + conn = [i, j, weight_distribution(pre_pop_size), delay_count] + delay_count += 1 + connections.append(conn) + if neuron_syn_count > max_syn_per_neuron: + max_syn_per_neuron = neuron_syn_count + return connections, max_syn_per_neuron + +def range_connector(pre_min, pre_max, post_min, post_max, weight=1.5, delay_offset=0): + connections = [] + for j in range(int(post_min), int(post_max)): + # delay = delay_offset + for i in range(int(pre_min), int(pre_max)): + nd_weight = weight_distribution(pre_max-pre_min) + connections.append([i, j, weight+nd_weight, i+delay_offset]) + # delay += 1 + return connections + + +def first_create_pops(): + pynn.setup(timestep=1) + pynn.set_number_of_neurons_per_core(pynn.extra_models.EPropAdaptive, 6) + + print("Check rates: ", rates) + + input_pop = pynn.Population(input_size, + pynn.SpikeSourcePoisson(rate=rates), + label='input_pop') + neuron = pynn.Population(neuron_pop_size, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + + # Output population + readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.LeftRightReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + + # SpynnakerExternalDevicePluginManager.add_edge(readout_pop._get_vertex, input_pop._get_vertex, "CONTROL") + poisson_control_edge = SpynnakerExternalDevicePluginManager.add_edge( + readout_pop._vertex, input_pop._vertex, "CONTROL") + # pynn.external_devices.activate_live_output_to( + # readout_pop, input_pop, "CONTROL") + input_pop._vertex.set_live_poisson_control_edge(poisson_control_edge) + # pynn.external_devices.add_poisson_live_rate_control(input_pop) + + eprop_learning_neuron = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=reg_rate)) + + # from_list_in, max_syn_per_input = probability_connector(input_size, neuron_pop_size, p_connect_in) + ps = int(readout_neuron_params["poisson_pop_size"]) + from_list_in = range_connector(0, ps * 2, 0, neuron_pop_size, delay_offset=0, + weight=in_weight) # connect all 2 prompt + from_list_in += range_connector(ps * 2, ps * 4, 0, neuron_pop_size, delay_offset=0, + weight=prompt_weight) # connect all 2 prompt + + print("length ", len(from_list_in)) + + in_proj = pynn.Projection(input_pop, + neuron, + pynn.FromListConnector(from_list_in), + # pynn.AllToAllConnector(), + synapse_type=eprop_learning_neuron, + label='input_connections', + receptor_type='input_connections') + + eprop_learning_output = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=0.0)) + + from_list_out = range_connector(0, neuron_pop_size, 0, 2, weight=out_weight) # connect all + out_proj = pynn.Projection(neuron, + readout_pop, + # pynn.OneToOneConnector(), + pynn.FromListConnector(from_list_out), + synapse_type=eprop_learning_output, + label='input_connections', + receptor_type='input_connections') + + learning_proj = pynn.Projection(readout_pop, + neuron, + pynn.AllToAllConnector(), + pynn.StaticSynapse(weight=0.5, delay=0), + receptor_type='learning_signal') + + if recurrent_connections: + eprop_learning_recurrent = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=reg_rate)) + + from_list_rec = range_connector(0, neuron_pop_size, 0, neuron_pop_size, weight=rec_weight, + delay_offset=100) # recurrent connections + recurrent_proj = pynn.Projection(neuron, + neuron, + pynn.FromListConnector(from_list_rec), + synapse_type=eprop_learning_recurrent, + label='recurrent_connections', + receptor_type='recurrent_connections') + else: + from_list_rec = [] + recurrent_proj = None + + # input_pop.record('spikes') + # neuron.record('spikes') + # neuron.record(['gsyn_exc', 'v', 'gsyn_inh'], + # indexes=[i for i in range(int((neuron_pop_size / 2) - 5), int((neuron_pop_size / 2) + 5))]) + readout_pop.record('all') + + runtime = cycle_time * num_repeats + + experiment_label = "c-{} {} eta-{}_{} - size-{}_{} - " \ + "rec-{} - cycle-{}_{}_{} b-{}".format( # "weights-{} - p_conn-{}_{}_{} - " \ + readout_neuron_params["number_of_cues"], free_label, readout_neuron_params["eta"], neuron_params["eta"], input_size, neuron_pop_size, + # weight_string, p_connect_in, p_connect_rec, p_connect_out, + recurrent_connections, cycle_time, window_size, runtime, threshold_beta) + print("\n", experiment_label, "\n") + + return experiment_label, runtime, pynn, in_proj, recurrent_proj, out_proj, input_pop, neuron, readout_pop, \ + from_list_in, from_list_rec, from_list_out + + +def next_create_pops(from_list_in, from_list_rec, from_list_out): + pynn.setup(timestep=1) + input_pop = pynn.Population(input_size, + pynn.SpikeSourcePoisson(rate=rates), + # {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size)}, + # {'spike_times': frozen_poisson_variable_hz(num_repeats, cycle_time, input_split, input_split, input_size)}, + label='input_pop') + + neuron = pynn.Population(neuron_pop_size, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + + # Output population + readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.LeftRightReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + + # SpynnakerExternalDevicePluginManager.add_edge(readout_pop._get_vertex, input_pop._get_vertex, "CONTROL") + poisson_control_edge = SpynnakerExternalDevicePluginManager.add_edge( + readout_pop._vertex, input_pop._vertex, "CONTROL") + # pynn.external_devices.activate_live_output_to( + # readout_pop, input_pop, "CONTROL") + input_pop._vertex.set_live_poisson_control_edge(poisson_control_edge) + # pynn.external_devices.add_poisson_live_rate_control(input_pop) + + eprop_learning_neuron = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=reg_rate)) + + from_list_in_list = [] + for conn in from_list_in: + a = conn[0] + b = conn[1] + w = conn[2] + d = conn[3] + if a % input_size == 0: + d = 0.0 + from_list_in_list.append([a, b, w, d]) + + in_proj = pynn.Projection(input_pop, + neuron, + pynn.FromListConnector(from_list_in_list), + # pynn.AllToAllConnector(), + synapse_type=eprop_learning_neuron, + label='input_connections', + receptor_type='input_connections') + + eprop_learning_output = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=0.0)) + + from_list_out_list = [] + for conn in from_list_out: + a = conn[0] + b = conn[1] + w = conn[2] + d = conn[3] + if a % neuron_pop_size == 0: + d = 0.0 + from_list_out_list.append([a, b, w, d]) + + out_proj = pynn.Projection(neuron, + readout_pop, + # pynn.OneToOneConnector(), + pynn.FromListConnector(from_list_out_list), + synapse_type=eprop_learning_output, + label='input_connections', + receptor_type='input_connections') + + learning_proj = pynn.Projection(readout_pop, + neuron, + pynn.AllToAllConnector(), + pynn.StaticSynapse(weight=0.5, delay=0), + receptor_type='learning_signal') + recurrent_proj = None + if recurrent_connections: + eprop_learning_recurrent = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=reg_rate)) + + from_list_rec_list = [] + for conn in from_list_rec: + a = conn[0] + b = conn[1] + w = conn[2] + d = conn[3] + # might need some check for delay + from_list_rec_list.append([a, b, w, d]) + + recurrent_proj = pynn.Projection(neuron, + neuron, + pynn.FromListConnector(from_list_rec_list), + synapse_type=eprop_learning_recurrent, + label='recurrent_connections', + receptor_type='recurrent_connections') + + # input_pop.record('spikes') + # neuron.record('spikes') + # neuron.record(['gsyn_exc', 'v', 'gsyn_inh'], + # indexes=[i for i in range(int((neuron_pop_size / 2) - 5), int((neuron_pop_size / 2) + 5))]) + readout_pop.record('all') + + window_size = neuron_params["window_size"] + cycle_time = int(window_size / window_cycles) + runtime = cycle_time * num_repeats + + experiment_label = "c-{} {} eta-{}_{} - size-{}_{} - " \ + "rec-{} - cycle-{}_{}_{} b-{}".format( # "weights-{} - p_conn-{}_{}_{} - " \ + readout_neuron_params["number_of_cues"], free_label, readout_neuron_params["eta"], neuron_params["eta"], input_size, neuron_pop_size, + # weight_string, p_connect_in, p_connect_rec, p_connect_out, + recurrent_connections, cycle_time, window_size, runtime, threshold_beta) + print("\n", experiment_label, "\n") + + return experiment_label, runtime, pynn, in_proj, recurrent_proj, out_proj, input_pop, neuron, readout_pop, \ + from_list_in, from_list_rec, from_list_out + +def run_until(experiment_label, runtime, pynn, in_proj, recurrent_proj, out_proj, input_pop, neuron, readout_pop, + from_list_in, from_list_rec, from_list_out, + correct_or_not, cycle_error, threshold=0.95, cue_break=[]): + good_performance = False + current_window = 0 + current_iter = current_window * window_cycles + window_size = neuron_params["window_size"] + cycle_time = int(window_size / window_cycles) + runtime = cycle_time * num_repeats + + while current_window * window_size < runtime: + print(experiment_label) + pynn.run(window_size) + # in_spikes = input_pop.get_data('spikes', clear=True) + # neuron_res = neuron.get_data('all', clear=True) + readout_res = readout_pop.get_data('all', clear=True) + + for cycle in range(window_cycles): + cycle_error.append(0.0) + correct_or_not.append([]) + for time_index in range(cycle_time): + instantaneous_error = np.abs(float( + readout_res.segments[0].filter( + name='gsyn_inh')[0][time_index + ( + cycle * cycle_time)][0])) + # (cycle+current_iter) * cycle_time)][0])) + cycle_error[-1] += instantaneous_error + if cycle_error[-1] < 75: + correct_or_not[-1] = 1 + else: + correct_or_not[-1] = 0 + + new_connections_in = [] # in_proj.get('weight', 'delay').connections[0]#[] + for partition in in_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_in.append(conn) + new_connections_in.sort(key=lambda x: x[0]) + new_connections_in.sort(key=lambda x: x[1]) + from_list_in.sort(key=lambda x: x[0]) + from_list_in.sort(key=lambda x: x[1]) + connection_diff_in = [] + for i in range(len(from_list_in)): + connection_diff_in.append(new_connections_in[i][2] - from_list_in[i][2]) + print("Input connections\noriginal\n", np.array(from_list_in)) + print("new\n", np.array(new_connections_in)) + print("diff\n", np.array(connection_diff_in)) + + new_connections_out = [] # out_proj.get('weight', 'delay').connections[0]#[] + for partition in out_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_out.append(conn) + new_connections_out.sort(key=lambda x: x[0]) + new_connections_out.sort(key=lambda x: x[1]) + from_list_out.sort(key=lambda x: x[0]) + from_list_out.sort(key=lambda x: x[1]) + connection_diff_out = [] + for i in range(len(from_list_out)): + connection_diff_out.append(new_connections_out[i][2] - from_list_out[i][2]) + print("Output connections\noriginal\n", np.array(from_list_out)) + print("new\n", np.array(new_connections_out)) + print("diff\n", np.array(connection_diff_out)) + + new_connections_rec = [] + if recurrent_connections: + for partition in recurrent_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_rec.append(conn) + new_connections_rec.sort(key=lambda x: x[0]) + new_connections_rec.sort(key=lambda x: x[1]) + from_list_rec.sort(key=lambda x: x[0]) + from_list_rec.sort(key=lambda x: x[1]) + connection_diff_rec = [] + for i in range(len(from_list_rec)): + connection_diff_rec.append(new_connections_rec[i][2] - from_list_rec[i][2]) + print("Recurrent connections\noriginal\n", np.array(from_list_rec)) + print("new\n", np.array(new_connections_rec)) + print("diff\n", np.array(connection_diff_rec)) + + current_window += 1 + current_iter = current_window * window_cycles + + print(cycle_error) + for i in range(current_window): + print(correct_or_not[i * window_cycles:(i + 1) * window_cycles], + np.average(correct_or_not[i * window_cycles:(i + 1) * window_cycles])) + print(experiment_label) + + graph_directory = './big_with_labels/' + draw_graph_from_list( + new_connections_in, new_connections_rec, new_connections_out, + graph_directory, + experiment_label + ' {}'.format(current_window), + rec_flag=recurrent_connections, + save_flag=True) + plot_learning_curve(correct_or_not, cycle_error, graph_directory, + experiment_label + ' {}'.format(current_window), + save_flag=True, + cue_break=cue_break) + + if current_iter > 64 and \ + np.average(correct_or_not[-64:]) > threshold: + pynn.end() + print(cycle_error) + for i in range(current_window): + print(correct_or_not[i * window_cycles:(i + 1) * window_cycles], + np.average(correct_or_not[i * window_cycles:(i + 1) * window_cycles])) + print("Simulation has achieved threshold performance at window:", current_window) + print("this corresponds to itertation:", current_iter) + print(experiment_label) + good_performance = len(correct_or_not) + return new_connections_in, new_connections_rec, new_connections_out, \ + correct_or_not, cycle_error, good_performance + pynn.end() + print("Learning has failed to achieve threshold performance in runtime") + return new_connections_in, new_connections_rec, new_connections_out, \ + correct_or_not, cycle_error, good_performance diff --git a/eprop_testing/delta_synapse_test.py b/eprop_testing/delta_synapse_test.py new file mode 100644 index 0000000..e84c279 --- /dev/null +++ b/eprop_testing/delta_synapse_test.py @@ -0,0 +1,92 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + + +runtime = 100 +pynn.setup(1.0) + +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0 + } + + +inp_spike_source = pynn.Population(2, + pynn.SpikeSourceArray, + {'spike_times': [10]}, + label='Spike Source') + +pseudo_rec_spike_source = pynn.Population(2, + pynn.SpikeSourceArray, + {'spike_times': [80]}, + label='Spike Source') + +neuron = pynn.Population(2, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +inp_proj = pynn.Projection(inp_spike_source, neuron, + pynn.OneToOneConnector(), + # note that delays are now fixed to one in terms of spikes, + # but the synaptic word field indexes the synapse array + pynn.StaticSynapse(weight=[-0.5, 10] , delay=[1, 1]), + receptor_type='input_connections') + + +rec_proj = pynn.Projection(pseudo_rec_spike_source, neuron, + pynn.OneToOneConnector(), + # note that delays are now fixed to one in terms of spikes, + # but the synaptic word field indexes the synapse array + pynn.StaticSynapse(weight=[0.5, -10] , delay=[1, 1]), + receptor_type='recurrent_connections') + + + +neuron.record('all') + +pynn.run(runtime) + +res = neuron.get_data('all') +weights = inp_proj.get('weight', 'list', with_address=False) +delays = inp_proj.get('delay', 'list', with_address=False) + +for i in range(len(weights)): + print(weights[i], delays[i]) + +Figure( + Panel(res.segments[0].filter(name='v')[0], + ylabel="Membrane potential (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_exc')[0], + ylabel="gsyn excitatory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_inh')[0], + xlabel="Time (ms)", xticks=True, + ylabel="gsyn inhibitory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].spiketrains, + ylabel="Output Spikes", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + title="Single eprop neuron" +) + +plt.show() + +pynn.end() \ No newline at end of file diff --git a/eprop_testing/frozen_poisson.py b/eprop_testing/frozen_poisson.py new file mode 100644 index 0000000..d59d7ce --- /dev/null +++ b/eprop_testing/frozen_poisson.py @@ -0,0 +1,285 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import numpy as np + +def build_input_spike_train(num_repeats, cycle_time, pop_size, use_old=False): + if use_old: + pattern = pattern_50 + else: + pattern = np.load('1000 neurons - 10Hz - 100*1024s.npy').tolist() + + # if not pop_size: + # pop_size = len(pattern) + + spikes = [] + l=[] + for i in range(pop_size): + l = [] + for j in range(len(pattern[i])): + if pattern[i][j] < cycle_time: + l.append(pattern[i][j]) + else: + break + spikes.append(l) + + cycled_spikes = [[] for i in range(pop_size)] + for r in range(0, num_repeats): + for p in range(pop_size): + new_iter = [i + r * cycle_time for i in spikes[p]] + cycled_spikes[p].extend(new_iter) + + return cycled_spikes + +def frozen_poisson_variable_hz(num_repeats, cycle_time, split, speed_up, pop_size, use_old=False): + if use_old: + pattern = pattern_10 + else: + pattern = np.load('1000 neurons - 10Hz - 100*1024s.npy', allow_pickle=True).tolist() + + if split > pop_size: + print("Cannot split population into sizes smaller than 1 i.e. split > population size") + raise Exception + + spikes = [] + l=[] + for i in range(pop_size): + l = [] + for j in range(len(pattern[i])): + if pattern[i][j] < cycle_time * speed_up: + l.append(float(pattern[i][j]) / speed_up) + else: + break + spikes.append(l) + + speed_up_offset = cycle_time / split + split_spikes = [[] for i in range(pop_size)] + for neuron in range(len(spikes)): + for spike in range(len(spikes[neuron])): + split_spikes[neuron].append((spikes[neuron][spike] / split) + (speed_up_offset * int(neuron / (pop_size / split)))) + + cycled_spikes = [[] for i in range(pop_size)] + for r in range(0, num_repeats): + for p in range(pop_size): + new_iter = [i + r * cycle_time for i in split_spikes[p]] + cycled_spikes[p].extend(new_iter) + + + return cycled_spikes + +pattern_10 = [ + [158.0, 183.0, 184.0, 238.0, 315.0, 348.0, 388.0, 395.0, 403.0, 707.0, 925.0], + [101.0, 304.0, 337.0, 398.0, 402.0, 740.0, 982.0, 984.0], + [213.0, 662.0, 810.0, 904.0, 912.0, 1017.0, 1019.0], + [12.0, 139.0, 236.0, 285.0, 398.0, 407.0, 578.0, 796.0, 888.0, 899.0, 902.0], + [34.0, 37.0, 43.0, 79.0, 86.0, 116.0, 190.0, 235.0, 328.0, 346.0, 380.0, 464.0, 554.0, 595.0, 740.0, 852.0, 874.0, 929.0, 979.0, 995.0, 1009.0], + [88.0, 108.0, 121.0, 196.0, 412.0, 445.0, 746.0, 778.0, 845.0, 1005.0], + [96.0, 166.0, 351.0, 963.0, 980.0], + [3.0, 114.0, 330.0, 424.0, 540.0, 594.0, 704.0, 710.0, 796.0, 832.0, 858.0, 905.0, 906.0], + [204.0, 244.0, 442.0, 446.0, 626.0, 816.0, 838.0, 1012.0], + [89.0, 529.0, 580.0, 626.0, 658.0, 681.0, 729.0, 924.0, 993.0], + [487.0, 505.0, 705.0, 731.0, 799.0, 813.0, 1013.0], + [317.0, 328.0, 674.0, 725.0, 730.0, 750.0, 779.0], + [34.0, 40.0, 226.0, 312.0, 516.0, 743.0, 784.0, 829.0, 864.0, 898.0], + [89.0, 97.0, 174.0, 218.0, 395.0, 465.0, 543.0, 611.0, 677.0, 762.0, 843.0], + [49.0, 64.0, 142.0, 157.0, 169.0, 252.0, 379.0, 527.0, 544.0, 548.0, 576.0, 841.0, 935.0, 989.0], + [11.0, 68.0, 291.0, 368.0, 507.0, 585.0, 604.0, 626.0, 643.0, 662.0, 781.0, 891.0, 902.0, 948.0, 1014.0, 1020.0], + [4.0, 58.0, 227.0, 382.0, 404.0, 532.0, 586.0, 662.0, 728.0, 895.0, 953.0, 1002.0], + [195.0, 215.0, 542.0, 600.0, 720.0, 740.0, 786.0, 791.0, 904.0, 935.0, 1015.0], + [165.0, 200.0, 202.0, 289.0, 312.0, 338.0, 453.0, 459.0, 483.0, 638.0, 653.0, 748.0, 776.0, 856.0, 970.0], + [13.0, 22.0, 38.0, 112.0, 154.0, 378.0, 439.0, 566.0, 609.0, 675.0, 814.0, 870.0, 924.0, 944.0, 952.0], + [166.0, 300.0, 324.0, 329.0, 388.0, 444.0, 502.0], + [10.0, 131.0, 326.0, 351.0, 408.0, 412.0, 446.0, 556.0, 562.0, 625.0, 773.0, 839.0, 900.0, 916.0, 927.0, 944.0, 945.0, 991.0], + [30.0, 533.0, 561.0, 718.0, 738.0, 819.0, 930.0, 946.0], + [106.0, 178.0, 199.0, 308.0, 324.0, 382.0, 426.0, 436.0, 497.0, 509.0, 755.0, 868.0, 893.0, 900.0], + [33.0, 55.0, 95.0, 363.0, 371.0, 402.0, 403.0, 408.0, 627.0, 764.0, 890.0], + [6.0, 141.0, 411.0, 414.0, 426.0, 521.0, 550.0, 765.0, 767.0, 840.0, 947.0, 1008.0, 1012.0, 1016.0], + [387.0, 501.0, 776.0, 820.0, 853.0, 934.0, 940.0], + [31.0, 39.0, 80.0, 133.0, 197.0, 282.0, 322.0, 500.0, 505.0, 557.0, 571.0, 637.0, 713.0, 728.0, 743.0, 767.0], + [70.0, 84.0, 277.0, 289.0, 369.0, 575.0, 579.0, 665.0, 889.0], + [95.0, 139.0, 234.0, 338.0, 365.0, 366.0, 472.0, 486.0, 499.0, 662.0, 918.0, 1003.0], + [32.0, 185.0, 226.0, 311.0, 580.0, 725.0, 830.0, 1018.0], + [313.0, 418.0, 450.0, 499.0, 790.0, 1021.0], + [52.0, 66.0, 275.0, 306.0, 309.0, 474.0, 593.0, 668.0, 673.0, 741.0, 874.0, 1019.0], + [69.0, 192.0, 285.0, 315.0, 379.0, 406.0, 545.0, 574.0, 579.0, 693.0, 815.0, 945.0], + [12.0, 37.0, 165.0, 418.0, 646.0, 697.0, 799.0, 881.0, 963.0], + [40.0, 102.0, 231.0, 375.0, 510.0, 631.0, 677.0, 702.0, 768.0, 860.0, 889.0], + [38.0, 217.0, 260.0, 272.0, 338.0, 371.0, 457.0, 476.0, 576.0, 609.0, 787.0, 813.0, 880.0, 949.0, 951.0], + [78.0, 243.0, 244.0, 247.0, 355.0, 357.0, 841.0, 915.0, 963.0], + [310.0, 374.0, 397.0, 654.0, 699.0, 715.0, 863.0, 868.0, 980.0], + [16.0, 80.0, 173.0, 194.0, 206.0, 212.0, 314.0, 374.0, 418.0, 476.0, 576.0, 591.0, 712.0, 787.0, 894.0], + [52.0, 91.0, 214.0, 302.0, 311.0, 364.0, 431.0, 468.0, 791.0, 932.0], + [38.0, 76.0, 118.0, 132.0, 187.0, 214.0, 283.0, 357.0, 503.0, 810.0, 852.0, 941.0, 994.0, 995.0, 997.0], + [5.0, 142.0, 389.0, 473.0, 562.0, 571.0, 620.0, 679.0, 741.0, 923.0], + [43.0, 58.0, 177.0, 372.0, 376.0, 415.0, 466.0, 628.0, 664.0, 790.0, 831.0, 948.0, 984.0], + [55.0, 156.0, 197.0, 373.0, 375.0, 487.0, 545.0, 661.0, 662.0, 821.0], + [97.0, 182.0, 428.0, 610.0, 812.0, 971.0], + [80.0, 85.0, 86.0, 206.0, 210.0, 214.0, 473.0, 524.0, 538.0, 599.0, 687.0, 819.0, 938.0], + [135.0, 213.0, 257.0, 273.0, 361.0, 429.0, 459.0, 643.0, 727.0, 954.0, 995.0], + [91.0, 408.0, 550.0, 563.0, 908.0], + [88.0, 134.0, 186.0, 347.0, 418.0, 442.0, 578.0, 592.0, 692.0, 711.0, 905.0, 910.0, 987.0], + [9.0, 145.0, 259.0, 306.0, 308.0, 348.0, 407.0, 454.0, 534.0, 601.0, 695.0, 759.0, 805.0, 811.0, 823.0, 848.0], + [233.0, 310.0, 450.0, 645.0, 654.0, 728.0, 747.0, 883.0, 982.0, 983.0], + [256.0, 320.0, 569.0, 753.0, 849.0, 905.0, 943.0], + [24.0, 285.0, 346.0, 440.0, 575.0, 627.0, 786.0, 951.0, 973.0], + [65.0, 184.0, 444.0], + [10.0, 53.0, 70.0, 197.0, 235.0, 261.0, 330.0, 460.0, 506.0, 675.0, 681.0, 748.0, 800.0, 846.0, 854.0, 898.0, 975.0, 976.0], + [214.0, 258.0, 654.0, 815.0, 883.0, 1008.0], + [15.0, 53.0, 142.0, 194.0, 225.0, 275.0, 287.0, 716.0, 909.0, 976.0, 987.0], + [112.0, 436.0, 458.0, 556.0, 610.0, 662.0, 690.0, 778.0, 793.0, 823.0, 974.0], + [100.0, 102.0, 239.0, 389.0, 440.0, 627.0, 777.0, 882.0, 908.0, 1000.0], + [2.0, 30.0, 422.0, 445.0, 660.0, 706.0, 806.0, 895.0, 1015.0], + [34.0, 182.0, 310.0, 503.0, 507.0, 539.0, 571.0, 580.0, 704.0, 889.0, 965.0], + [26.0, 93.0, 185.0, 276.0, 294.0, 415.0, 786.0, 874.0, 877.0], + [119.0, 130.0, 183.0, 271.0, 297.0, 380.0, 384.0, 452.0, 712.0, 836.0, 866.0, 984.0, 987.0, 1016.0], + [65.0, 133.0, 252.0, 292.0, 315.0, 433.0, 642.0, 714.0, 737.0, 738.0, 769.0, 860.0], + [36.0, 114.0, 248.0, 376.0, 393.0, 686.0, 755.0, 853.0, 981.0], + [30.0, 33.0, 130.0, 304.0, 316.0, 364.0, 479.0, 690.0, 714.0, 747.0, 928.0, 1015.0], + [72.0, 111.0, 275.0, 374.0, 391.0, 446.0, 450.0, 457.0, 656.0, 943.0], + [29.0, 142.0, 201.0, 247.0, 366.0, 399.0, 488.0, 659.0, 716.0, 720.0, 922.0, 1013.0], + [70.0, 103.0, 145.0, 197.0, 224.0, 236.0, 508.0, 637.0, 696.0, 746.0, 766.0, 869.0, 966.0], + [15.0, 40.0, 107.0, 119.0, 169.0, 174.0, 403.0, 456.0, 571.0, 627.0, 666.0, 818.0, 916.0], + [85.0, 112.0, 141.0, 307.0, 324.0, 333.0, 334.0, 570.0, 845.0, 942.0], + [241.0, 271.0, 285.0, 717.0, 747.0, 757.0, 838.0, 1003.0], + [61.0, 83.0, 92.0, 120.0, 174.0, 255.0, 259.0, 349.0, 429.0, 457.0, 465.0, 477.0, 530.0, 665.0, 683.0, 846.0, 861.0, 900.0], + [82.0, 124.0, 534.0, 675.0, 897.0, 1015.0], + [189.0, 428.0, 431.0, 579.0, 660.0, 671.0, 701.0, 726.0, 763.0, 870.0, 875.0, 961.0, 965.0, 1006.0], + [75.0, 135.0, 236.0, 329.0, 356.0, 511.0, 596.0, 597.0, 663.0, 668.0, 671.0, 714.0, 786.0, 797.0], + [152.0, 383.0, 582.0, 680.0, 848.0, 886.0, 898.0, 899.0], + [12.0, 39.0, 318.0, 518.0, 583.0, 603.0, 614.0, 624.0, 680.0, 708.0, 738.0, 750.0, 766.0, 769.0, 852.0, 927.0], + [113.0, 125.0, 296.0, 355.0, 416.0, 482.0, 683.0, 774.0, 960.0, 1022.0], + [178.0, 210.0, 283.0, 318.0, 320.0, 329.0, 406.0, 419.0, 574.0, 606.0, 700.0, 841.0, 853.0, 866.0, 871.0, 957.0, 1017.0], + [70.0, 249.0, 284.0, 304.0, 322.0, 371.0, 451.0, 605.0, 650.0, 658.0, 691.0, 778.0, 821.0, 932.0, 936.0, 942.0, 943.0], + [8.0, 133.0, 257.0, 310.0, 398.0, 477.0, 630.0, 670.0, 722.0, 831.0, 916.0], + [64.0, 271.0, 302.0, 341.0, 375.0, 400.0, 522.0, 624.0, 660.0], + [28.0, 87.0, 209.0, 331.0, 414.0, 436.0, 454.0, 584.0, 628.0, 631.0, 667.0, 689.0, 935.0, 1007.0, 1014.0], + [13.0, 33.0, 271.0, 390.0, 391.0, 471.0, 487.0, 737.0, 821.0, 883.0, 956.0], + [3.0, 114.0, 240.0, 365.0, 376.0, 387.0, 525.0, 549.0, 716.0, 781.0, 873.0, 1001.0, 1011.0], + [8.0, 74.0, 182.0, 279.0, 296.0, 401.0, 687.0, 699.0, 705.0, 945.0], + [182.0, 436.0, 443.0, 447.0, 545.0, 771.0, 878.0, 932.0], + [3.0, 12.0, 51.0, 90.0, 173.0, 193.0, 396.0, 515.0, 551.0, 601.0, 641.0, 943.0, 978.0], + [119.0, 219.0, 332.0, 354.0, 421.0, 433.0, 447.0, 460.0, 595.0, 634.0], + [138.0, 225.0, 333.0, 831.0, 854.0, 879.0, 916.0, 929.0, 951.0, 985.0], + [14.0, 113.0, 229.0, 255.0, 274.0, 309.0, 460.0, 637.0, 889.0, 912.0, 941.0], + [21.0, 69.0, 303.0, 356.0, 456.0, 581.0, 613.0, 617.0, 662.0, 700.0, 722.0, 870.0, 913.0, 1001.0], + [18.0, 122.0, 132.0, 208.0, 366.0, 461.0, 580.0, 707.0, 714.0, 746.0, 799.0, 1010.0], + [12.0, 59.0, 148.0, 149.0, 189.0, 270.0, 320.0, 481.0, 622.0, 695.0, 992.0], + [31.0, 414.0, 460.0, 489.0, 499.0, 531.0, 543.0, 587.0, 593.0, 830.0, 844.0], + [140.0, 324.0, 364.0, 582.0, 733.0, 886.0], + [13.0, 86.0, 89.0, 130.0, 295.0, 340.0, 354.0, 522.0, 973.0, 986.0], + [10.0, 75.0, 85.0, 89.0, 93.0, 202.0, 339.0, 469.0, 799.0, 865.0, 899.0, 967.0, 1001.0] + ] + + +pattern_50 = [ + [7.0, 14.0, 26.0, 27.0, 42.0, 83.0, 93.0, 99.0, 109.0, 110.0, 144.0, 151.0, 153.0, 164.0, 175.0, 233.0, 245.0, 299.0, 303.0, 354.0, 355.0, 356.0, 432.0, 439.0, 447.0, 491.0, 553.0, 560.0, 583.0, 590.0, 645.0, 659.0, 667.0, 692.0, 693.0, 695.0, 714.0, 715.0, 728.0, 739.0, 756.0, 796.0, 822.0, 825.0, 829.0, 834.0, 862.0, 875.0, 880.0, 896.0, 909.0, 912.0, 940.0, 964.0, 1006.0], + [45.0, 63.0, 66.0, 88.0, 125.0, 142.0, 161.0, 167.0, 183.0, 188.0, 194.0, 207.0, 208.0, 235.0, 236.0, 252.0, 296.0, 346.0, 360.0, 384.0, 393.0, 396.0, 412.0, 474.0, 522.0, 543.0, 547.0, 616.0, 626.0, 657.0, 672.0, 681.0, 697.0, 706.0, 735.0, 770.0, 771.0, 774.0, 809.0, 811.0, 840.0, 847.0, 875.0, 965.0, 984.0, 989.0], + [26.0, 71.0, 79.0, 89.0, 94.0, 122.0, 123.0, 131.0, 138.0, 150.0, 156.0, 172.0, 195.0, 197.0, 220.0, 221.0, 246.0, 250.0, 251.0, 271.0, 272.0, 282.0, 310.0, 320.0, 351.0, 352.0, 355.0, 423.0, 493.0, 510.0, 523.0, 556.0, 577.0, 622.0, 657.0, 708.0, 748.0, 760.0, 766.0, 792.0, 835.0, 854.0, 890.0, 896.0, 898.0, 919.0, 934.0, 947.0, 948.0, 994.0, 1005.0, 1010.0, 1019.0, 1023.0], + [10.0, 21.0, 24.0, 27.0, 35.0, 47.0, 63.0, 64.0, 75.0, 90.0, 127.0, 129.0, 139.0, 145.0, 154.0, 221.0, 224.0, 256.0, 261.0, 262.0, 303.0, 305.0, 322.0, 327.0, 352.0, 369.0, 377.0, 397.0, 408.0, 413.0, 419.0, 437.0, 487.0, 489.0, 499.0, 522.0, 539.0, 607.0, 625.0, 626.0, 633.0, 649.0, 699.0, 701.0, 702.0, 724.0, 734.0, 758.0, 819.0, 835.0, 836.0, 897.0, 930.0, 954.0, 990.0, 1007.0, 1018.0], + [25.0, 31.0, 38.0, 66.0, 68.0, 81.0, 93.0, 111.0, 154.0, 163.0, 165.0, 184.0, 220.0, 272.0, 307.0, 316.0, 319.0, 335.0, 343.0, 392.0, 409.0, 459.0, 463.0, 483.0, 498.0, 507.0, 539.0, 543.0, 558.0, 559.0, 574.0, 579.0, 604.0, 605.0, 619.0, 622.0, 624.0, 626.0, 635.0, 640.0, 689.0, 704.0, 735.0, 740.0, 751.0, 758.0, 767.0, 782.0, 825.0, 836.0, 858.0, 868.0, 874.0, 886.0, 932.0, 952.0, 968.0, 970.0, 980.0, 989.0, 997.0], + [9.0, 18.0, 39.0, 43.0, 61.0, 76.0, 85.0, 121.0, 129.0, 164.0, 185.0, 227.0, 259.0, 283.0, 289.0, 335.0, 351.0, 384.0, 387.0, 392.0, 401.0, 402.0, 408.0, 413.0, 428.0, 435.0, 436.0, 451.0, 458.0, 461.0, 464.0, 476.0, 479.0, 489.0, 500.0, 518.0, 539.0, 551.0, 584.0, 589.0, 590.0, 602.0, 604.0, 605.0, 626.0, 632.0, 640.0, 641.0, 665.0, 707.0, 713.0, 730.0, 749.0, 784.0, 789.0, 837.0, 841.0, 863.0, 867.0, 870.0, 887.0, 935.0, 953.0, 956.0, 968.0, 970.0, 974.0, 984.0, 991.0, 1015.0, 1020.0, 1022.0], + [34.0, 35.0, 38.0, 77.0, 85.0, 90.0, 102.0, 122.0, 162.0, 178.0, 186.0, 187.0, 195.0, 196.0, 200.0, 205.0, 226.0, 278.0, 279.0, 284.0, 294.0, 316.0, 377.0, 402.0, 443.0, 450.0, 478.0, 497.0, 501.0, 509.0, 542.0, 560.0, 561.0, 562.0, 573.0, 590.0, 591.0, 597.0, 604.0, 608.0, 620.0, 631.0, 633.0, 654.0, 667.0, 719.0, 726.0, 739.0, 740.0, 758.0, 766.0, 767.0, 786.0, 792.0, 803.0, 806.0, 808.0, 811.0, 830.0, 842.0, 855.0, 856.0, 863.0, 878.0, 880.0, 889.0, 890.0, 906.0, 928.0, 958.0, 999.0, 1001.0, 1007.0, 1010.0], + [7.0, 31.0, 36.0, 59.0, 109.0, 110.0, 119.0, 121.0, 124.0, 126.0, 137.0, 185.0, 201.0, 218.0, 240.0, 261.0, 281.0, 306.0, 311.0, 342.0, 344.0, 349.0, 357.0, 365.0, 370.0, 380.0, 466.0, 468.0, 470.0, 489.0, 497.0, 572.0, 578.0, 584.0, 587.0, 612.0, 629.0, 657.0, 664.0, 698.0, 707.0, 711.0, 731.0, 735.0, 743.0, 773.0, 838.0, 839.0, 917.0, 923.0, 924.0, 992.0], + [17.0, 25.0, 28.0, 53.0, 70.0, 118.0, 125.0, 128.0, 142.0, 189.0, 190.0, 205.0, 224.0, 237.0, 292.0, 356.0, 357.0, 408.0, 416.0, 448.0, 459.0, 542.0, 615.0, 625.0, 629.0, 653.0, 669.0, 677.0, 716.0, 728.0, 751.0, 767.0, 772.0, 775.0, 857.0, 995.0, 1003.0, 1012.0], + [32.0, 34.0, 43.0, 70.0, 95.0, 130.0, 134.0, 139.0, 148.0, 150.0, 160.0, 163.0, 196.0, 257.0, 275.0, 302.0, 306.0, 322.0, 332.0, 354.0, 357.0, 364.0, 405.0, 432.0, 471.0, 472.0, 491.0, 516.0, 558.0, 563.0, 565.0, 577.0, 583.0, 584.0, 617.0, 626.0, 684.0, 725.0, 750.0, 768.0, 793.0, 794.0, 815.0, 821.0, 832.0, 869.0, 886.0, 894.0, 922.0, 938.0, 939.0, 968.0], + [30.0, 56.0, 59.0, 80.0, 109.0, 151.0, 159.0, 161.0, 164.0, 166.0, 191.0, 223.0, 309.0, 345.0, 378.0, 407.0, 434.0, 459.0, 470.0, 490.0, 585.0, 602.0, 634.0, 651.0, 713.0, 714.0, 779.0, 780.0, 807.0, 815.0, 829.0, 836.0, 857.0, 864.0, 898.0, 921.0, 926.0, 950.0, 969.0, 983.0, 989.0, 992.0], + [30.0, 31.0, 33.0, 63.0, 81.0, 100.0, 117.0, 128.0, 155.0, 157.0, 158.0, 192.0, 232.0, 283.0, 286.0, 295.0, 312.0, 319.0, 354.0, 362.0, 363.0, 369.0, 409.0, 452.0, 520.0, 578.0, 623.0, 624.0, 633.0, 656.0, 660.0, 681.0, 690.0, 693.0, 700.0, 715.0, 728.0, 744.0, 762.0, 781.0, 804.0, 815.0, 837.0, 867.0, 877.0, 944.0, 950.0, 957.0, 963.0, 970.0, 974.0], + [41.0, 48.0, 52.0, 91.0, 92.0, 152.0, 160.0, 163.0, 184.0, 185.0, 246.0, 251.0, 265.0, 268.0, 281.0, 294.0, 305.0, 312.0, 338.0, 346.0, 383.0, 407.0, 417.0, 437.0, 440.0, 448.0, 502.0, 510.0, 532.0, 541.0, 546.0, 573.0, 582.0, 607.0, 623.0, 742.0, 771.0, 785.0, 818.0, 828.0, 846.0, 896.0, 934.0, 965.0, 1005.0], + [34.0, 79.0, 111.0, 121.0, 133.0, 199.0, 207.0, 240.0, 243.0, 263.0, 295.0, 297.0, 330.0, 371.0, 378.0, 382.0, 419.0, 443.0, 469.0, 487.0, 492.0, 499.0, 509.0, 518.0, 525.0, 584.0, 598.0, 617.0, 624.0, 630.0, 634.0, 647.0, 651.0, 678.0, 691.0, 696.0, 703.0, 736.0, 772.0, 830.0, 840.0, 844.0, 858.0, 875.0, 1014.0], + [23.0, 51.0, 60.0, 131.0, 135.0, 147.0, 168.0, 171.0, 181.0, 184.0, 207.0, 210.0, 231.0, 270.0, 271.0, 285.0, 302.0, 309.0, 347.0, 356.0, 377.0, 385.0, 390.0, 396.0, 403.0, 436.0, 455.0, 468.0, 493.0, 515.0, 522.0, 533.0, 622.0, 653.0, 691.0, 692.0, 695.0, 710.0, 729.0, 736.0, 797.0, 800.0, 803.0, 815.0, 844.0, 848.0, 850.0, 859.0, 865.0, 878.0, 902.0, 924.0, 956.0, 967.0, 999.0, 1001.0, 1008.0, 1014.0], + [3.0, 38.0, 59.0, 74.0, 79.0, 81.0, 104.0, 116.0, 120.0, 129.0, 153.0, 170.0, 202.0, 217.0, 242.0, 244.0, 253.0, 254.0, 286.0, 287.0, 289.0, 350.0, 351.0, 390.0, 394.0, 403.0, 410.0, 433.0, 461.0, 464.0, 473.0, 476.0, 478.0, 491.0, 542.0, 543.0, 544.0, 586.0, 591.0, 595.0, 625.0, 627.0, 630.0, 659.0, 668.0, 676.0, 696.0, 702.0, 712.0, 733.0, 776.0, 777.0, 781.0, 782.0, 874.0, 877.0, 919.0, 990.0, 1006.0, 1007.0, 1010.0, 1016.0], + [4.0, 18.0, 40.0, 77.0, 119.0, 156.0, 160.0, 198.0, 243.0, 254.0, 269.0, 288.0, 311.0, 316.0, 347.0, 353.0, 354.0, 372.0, 373.0, 377.0, 413.0, 419.0, 466.0, 467.0, 471.0, 560.0, 566.0, 567.0, 579.0, 616.0, 644.0, 647.0, 667.0, 712.0, 713.0, 752.0, 753.0, 776.0, 783.0, 793.0, 812.0, 865.0, 881.0, 882.0, 884.0, 911.0, 912.0, 925.0, 941.0, 963.0, 978.0, 997.0, 1018.0], + [1.0, 32.0, 34.0, 60.0, 72.0, 95.0, 109.0, 116.0, 124.0, 165.0, 197.0, 205.0, 233.0, 243.0, 247.0, 258.0, 267.0, 274.0, 283.0, 302.0, 337.0, 350.0, 366.0, 368.0, 457.0, 462.0, 490.0, 492.0, 506.0, 571.0, 590.0, 603.0, 613.0, 712.0, 730.0, 736.0, 768.0, 788.0, 799.0, 803.0, 807.0, 808.0, 848.0, 854.0, 876.0, 878.0, 923.0, 958.0, 965.0], + [1.0, 78.0, 114.0, 119.0, 131.0, 155.0, 177.0, 198.0, 200.0, 202.0, 205.0, 241.0, 258.0, 272.0, 280.0, 288.0, 290.0, 291.0, 300.0, 323.0, 326.0, 328.0, 373.0, 375.0, 376.0, 380.0, 389.0, 390.0, 393.0, 403.0, 445.0, 456.0, 465.0, 476.0, 480.0, 481.0, 485.0, 507.0, 543.0, 563.0, 569.0, 597.0, 676.0, 707.0, 711.0, 734.0, 742.0, 777.0, 778.0, 783.0, 787.0, 802.0, 825.0, 830.0, 844.0, 858.0, 880.0, 932.0, 973.0, 1008.0, 1012.0, 1016.0], + [20.0, 23.0, 29.0, 47.0, 48.0, 51.0, 59.0, 143.0, 175.0, 176.0, 193.0, 197.0, 198.0, 202.0, 206.0, 224.0, 231.0, 232.0, 244.0, 283.0, 328.0, 330.0, 341.0, 345.0, 359.0, 361.0, 385.0, 422.0, 438.0, 449.0, 454.0, 465.0, 487.0, 490.0, 510.0, 528.0, 556.0, 580.0, 601.0, 602.0, 645.0, 651.0, 680.0, 693.0, 703.0, 704.0, 706.0, 716.0, 733.0, 782.0, 786.0, 821.0, 822.0, 829.0, 843.0, 855.0, 856.0, 875.0, 941.0, 951.0, 959.0, 990.0, 995.0], + [83.0, 110.0, 117.0, 128.0, 132.0, 154.0, 195.0, 214.0, 217.0, 234.0, 242.0, 252.0, 293.0, 338.0, 343.0, 352.0, 369.0, 412.0, 498.0, 499.0, 554.0, 566.0, 590.0, 603.0, 605.0, 606.0, 614.0, 669.0, 670.0, 671.0, 672.0, 677.0, 761.0, 767.0, 794.0, 832.0, 839.0, 869.0, 893.0, 913.0, 914.0, 915.0, 923.0, 936.0, 950.0, 1014.0], + [34.0, 100.0, 130.0, 138.0, 140.0, 172.0, 174.0, 282.0, 295.0, 303.0, 331.0, 349.0, 365.0, 376.0, 399.0, 408.0, 419.0, 515.0, 600.0, 615.0, 622.0, 626.0, 650.0, 672.0, 685.0, 700.0, 702.0, 742.0, 771.0, 849.0, 861.0, 882.0, 1019.0], + [10.0, 21.0, 67.0, 86.0, 151.0, 160.0, 187.0, 202.0, 225.0, 226.0, 237.0, 255.0, 260.0, 284.0, 300.0, 363.0, 393.0, 410.0, 435.0, 460.0, 463.0, 523.0, 528.0, 577.0, 586.0, 605.0, 611.0, 617.0, 625.0, 627.0, 639.0, 642.0, 651.0, 653.0, 698.0, 701.0, 724.0, 728.0, 729.0, 775.0, 785.0, 793.0, 844.0, 847.0, 865.0, 876.0, 890.0, 907.0, 931.0, 936.0, 961.0, 997.0, 1002.0, 1003.0, 1009.0, 1011.0], + [5.0, 13.0, 25.0, 56.0, 64.0, 65.0, 66.0, 85.0, 111.0, 120.0, 134.0, 152.0, 153.0, 168.0, 170.0, 172.0, 185.0, 199.0, 207.0, 222.0, 233.0, 234.0, 242.0, 255.0, 262.0, 309.0, 333.0, 352.0, 394.0, 395.0, 403.0, 417.0, 429.0, 452.0, 462.0, 463.0, 476.0, 482.0, 501.0, 529.0, 533.0, 534.0, 544.0, 589.0, 595.0, 599.0, 636.0, 652.0, 690.0, 692.0, 743.0, 773.0, 777.0, 840.0, 844.0, 845.0, 872.0, 878.0, 900.0, 982.0, 984.0, 997.0], + [18.0, 100.0, 113.0, 157.0, 160.0, 161.0, 166.0, 168.0, 177.0, 231.0, 234.0, 235.0, 260.0, 302.0, 363.0, 373.0, 377.0, 414.0, 422.0, 445.0, 446.0, 491.0, 508.0, 520.0, 523.0, 547.0, 553.0, 561.0, 599.0, 603.0, 665.0, 714.0, 724.0, 739.0, 741.0, 758.0, 785.0, 860.0, 874.0, 911.0, 963.0, 974.0, 979.0, 980.0, 983.0, 990.0], + [18.0, 37.0, 46.0, 88.0, 121.0, 134.0, 166.0, 198.0, 202.0, 206.0, 210.0, 220.0, 229.0, 249.0, 269.0, 301.0, 364.0, 467.0, 474.0, 482.0, 509.0, 546.0, 579.0, 603.0, 632.0, 641.0, 656.0, 750.0, 763.0, 767.0, 791.0, 828.0, 838.0, 861.0, 890.0, 895.0, 929.0, 955.0, 991.0], + [14.0, 27.0, 48.0, 65.0, 71.0, 72.0, 75.0, 78.0, 99.0, 152.0, 163.0, 183.0, 317.0, 326.0, 336.0, 379.0, 421.0, 460.0, 532.0, 533.0, 547.0, 575.0, 661.0, 680.0, 709.0, 722.0, 744.0, 805.0, 814.0, 816.0, 820.0, 826.0, 827.0, 828.0, 849.0, 853.0, 862.0, 939.0, 943.0, 944.0, 960.0], + [10.0, 27.0, 30.0, 31.0, 32.0, 89.0, 105.0, 110.0, 112.0, 130.0, 155.0, 161.0, 174.0, 221.0, 286.0, 302.0, 326.0, 360.0, 370.0, 378.0, 385.0, 387.0, 394.0, 411.0, 412.0, 423.0, 435.0, 440.0, 460.0, 472.0, 537.0, 538.0, 539.0, 541.0, 548.0, 556.0, 602.0, 619.0, 691.0, 698.0, 737.0, 744.0, 801.0, 814.0, 825.0, 836.0, 838.0, 843.0, 894.0, 909.0, 916.0, 925.0, 929.0, 946.0, 952.0, 953.0, 959.0, 984.0], + [1.0, 9.0, 31.0, 42.0, 65.0, 91.0, 109.0, 171.0, 196.0, 198.0, 203.0, 277.0, 295.0, 313.0, 340.0, 381.0, 397.0, 408.0, 425.0, 469.0, 488.0, 490.0, 505.0, 506.0, 525.0, 559.0, 597.0, 660.0, 705.0, 715.0, 718.0, 764.0, 799.0, 820.0, 893.0, 904.0, 914.0, 978.0, 981.0], + [50.0, 64.0, 90.0, 152.0, 160.0, 164.0, 180.0, 205.0, 231.0, 272.0, 284.0, 339.0, 350.0, 351.0, 374.0, 458.0, 483.0, 488.0, 592.0, 605.0, 612.0, 627.0, 639.0, 651.0, 667.0, 687.0, 711.0, 776.0, 781.0, 817.0, 820.0, 839.0, 876.0, 886.0, 888.0, 898.0, 899.0, 912.0, 921.0, 939.0, 944.0, 981.0], + [24.0, 27.0, 37.0, 42.0, 107.0, 112.0, 125.0, 136.0, 158.0, 176.0, 178.0, 185.0, 275.0, 277.0, 278.0, 350.0, 364.0, 375.0, 393.0, 395.0, 421.0, 430.0, 462.0, 504.0, 505.0, 520.0, 541.0, 555.0, 573.0, 579.0, 589.0, 602.0, 661.0, 672.0, 709.0, 729.0, 744.0, 760.0, 770.0, 778.0, 800.0, 831.0, 832.0, 885.0, 899.0, 951.0, 964.0, 971.0, 974.0, 992.0], + [34.0, 60.0, 84.0, 86.0, 94.0, 109.0, 110.0, 142.0, 154.0, 180.0, 185.0, 198.0, 249.0, 250.0, 268.0, 271.0, 286.0, 299.0, 319.0, 357.0, 395.0, 418.0, 423.0, 424.0, 432.0, 433.0, 447.0, 538.0, 542.0, 554.0, 556.0, 568.0, 584.0, 615.0, 642.0, 684.0, 692.0, 715.0, 721.0, 728.0, 737.0, 747.0, 750.0, 753.0, 758.0, 768.0, 774.0, 808.0, 831.0, 906.0, 937.0, 960.0, 967.0, 986.0, 1014.0], + [59.0, 84.0, 86.0, 91.0, 93.0, 101.0, 125.0, 127.0, 130.0, 161.0, 164.0, 165.0, 166.0, 171.0, 174.0, 197.0, 199.0, 254.0, 258.0, 303.0, 306.0, 309.0, 322.0, 342.0, 353.0, 364.0, 366.0, 367.0, 387.0, 448.0, 471.0, 490.0, 502.0, 513.0, 531.0, 575.0, 597.0, 615.0, 635.0, 650.0, 651.0, 684.0, 694.0, 702.0, 742.0, 782.0, 797.0, 818.0, 839.0, 859.0, 884.0, 903.0, 909.0, 924.0, 927.0, 944.0, 945.0, 973.0, 978.0, 984.0, 998.0], + [31.0, 53.0, 77.0, 85.0, 97.0, 153.0, 158.0, 159.0, 182.0, 204.0, 261.0, 293.0, 318.0, 398.0, 404.0, 424.0, 446.0, 480.0, 486.0, 497.0, 500.0, 520.0, 553.0, 559.0, 562.0, 576.0, 593.0, 640.0, 652.0, 670.0, 679.0, 702.0, 719.0, 721.0, 735.0, 793.0, 833.0, 862.0, 941.0, 952.0], + [42.0, 57.0, 66.0, 80.0, 83.0, 113.0, 114.0, 115.0, 124.0, 144.0, 147.0, 163.0, 169.0, 179.0, 189.0, 203.0, 237.0, 247.0, 257.0, 317.0, 346.0, 349.0, 354.0, 374.0, 389.0, 415.0, 438.0, 446.0, 503.0, 514.0, 515.0, 554.0, 575.0, 608.0, 609.0, 657.0, 666.0, 675.0, 684.0, 703.0, 780.0, 793.0, 803.0, 834.0, 849.0, 924.0, 938.0, 943.0, 951.0, 1005.0, 1019.0], + [8.0, 10.0, 11.0, 17.0, 20.0, 21.0, 47.0, 50.0, 97.0, 110.0, 148.0, 161.0, 169.0, 174.0, 202.0, 205.0, 226.0, 320.0, 345.0, 346.0, 358.0, 364.0, 365.0, 386.0, 391.0, 424.0, 432.0, 435.0, 540.0, 542.0, 587.0, 612.0, 648.0, 707.0, 745.0, 758.0, 765.0, 774.0, 808.0, 814.0, 818.0, 906.0, 909.0, 911.0, 914.0, 919.0, 943.0, 944.0, 956.0, 972.0, 982.0, 1019.0], + [8.0, 11.0, 98.0, 99.0, 113.0, 121.0, 124.0, 164.0, 165.0, 227.0, 228.0, 238.0, 245.0, 279.0, 282.0, 289.0, 310.0, 313.0, 345.0, 369.0, 408.0, 416.0, 478.0, 505.0, 515.0, 542.0, 550.0, 551.0, 613.0, 648.0, 669.0, 678.0, 687.0, 702.0, 715.0, 726.0, 728.0, 738.0, 755.0, 759.0, 787.0, 795.0, 797.0, 830.0, 835.0, 905.0, 950.0, 983.0], + [2.0, 21.0, 27.0, 87.0, 103.0, 136.0, 149.0, 155.0, 156.0, 168.0, 239.0, 249.0, 262.0, 293.0, 304.0, 328.0, 332.0, 341.0, 409.0, 417.0, 420.0, 421.0, 427.0, 435.0, 454.0, 456.0, 462.0, 473.0, 573.0, 590.0, 608.0, 627.0, 629.0, 674.0, 690.0, 697.0, 745.0, 774.0, 791.0, 803.0, 808.0, 815.0, 870.0, 891.0, 896.0, 919.0, 931.0, 946.0, 950.0, 958.0, 977.0, 1001.0, 1003.0, 1015.0], + [1.0, 23.0, 34.0, 93.0, 96.0, 98.0, 107.0, 109.0, 183.0, 188.0, 200.0, 201.0, 218.0, 231.0, 233.0, 247.0, 297.0, 334.0, 338.0, 355.0, 361.0, 369.0, 382.0, 402.0, 415.0, 468.0, 479.0, 505.0, 546.0, 554.0, 561.0, 563.0, 594.0, 603.0, 642.0, 709.0, 710.0, 723.0, 778.0, 819.0, 825.0, 845.0, 858.0, 881.0, 887.0, 930.0, 965.0, 1009.0, 1023.0], + [12.0, 32.0, 59.0, 98.0, 110.0, 137.0, 167.0, 174.0, 175.0, 224.0, 247.0, 318.0, 326.0, 400.0, 402.0, 403.0, 413.0, 440.0, 455.0, 471.0, 499.0, 500.0, 513.0, 544.0, 552.0, 587.0, 591.0, 601.0, 616.0, 623.0, 625.0, 642.0, 660.0, 662.0, 685.0, 769.0, 778.0, 794.0, 827.0, 870.0, 878.0, 885.0, 974.0, 980.0, 1011.0, 1013.0, 1015.0], + [5.0, 52.0, 116.0, 120.0, 134.0, 159.0, 171.0, 174.0, 188.0, 190.0, 194.0, 217.0, 239.0, 254.0, 320.0, 321.0, 346.0, 361.0, 369.0, 371.0, 413.0, 421.0, 435.0, 439.0, 440.0, 441.0, 462.0, 468.0, 471.0, 473.0, 500.0, 512.0, 553.0, 554.0, 590.0, 591.0, 603.0, 621.0, 648.0, 683.0, 708.0, 742.0, 759.0, 812.0, 820.0, 844.0, 853.0, 875.0, 895.0, 905.0, 986.0, 998.0, 1010.0], + [7.0, 17.0, 26.0, 34.0, 48.0, 63.0, 70.0, 87.0, 140.0, 155.0, 156.0, 180.0, 220.0, 224.0, 272.0, 284.0, 291.0, 310.0, 335.0, 340.0, 342.0, 345.0, 353.0, 364.0, 419.0, 448.0, 460.0, 461.0, 518.0, 527.0, 531.0, 534.0, 544.0, 563.0, 584.0, 613.0, 614.0, 645.0, 655.0, 661.0, 666.0, 673.0, 689.0, 827.0, 859.0, 876.0, 888.0, 893.0, 956.0, 967.0, 968.0, 987.0, 1001.0], + [35.0, 46.0, 59.0, 61.0, 64.0, 73.0, 95.0, 110.0, 118.0, 171.0, 196.0, 214.0, 225.0, 294.0, 296.0, 298.0, 360.0, 393.0, 407.0, 411.0, 412.0, 418.0, 445.0, 484.0, 507.0, 554.0, 608.0, 619.0, 628.0, 638.0, 690.0, 744.0, 820.0, 886.0, 897.0, 925.0, 930.0, 959.0, 984.0, 991.0, 1006.0], + [36.0, 37.0, 44.0, 57.0, 59.0, 69.0, 85.0, 103.0, 142.0, 143.0, 144.0, 145.0, 401.0, 474.0, 479.0, 539.0, 543.0, 546.0, 562.0, 583.0, 632.0, 655.0, 694.0, 723.0, 759.0, 771.0, 772.0, 775.0, 796.0, 801.0, 834.0, 838.0, 902.0, 903.0, 980.0, 1022.0], + [8.0, 13.0, 38.0, 56.0, 81.0, 86.0, 104.0, 128.0, 156.0, 230.0, 236.0, 252.0, 307.0, 336.0, 348.0, 352.0, 357.0, 373.0, 374.0, 389.0, 404.0, 414.0, 428.0, 437.0, 449.0, 498.0, 503.0, 590.0, 592.0, 594.0, 652.0, 675.0, 679.0, 699.0, 701.0, 712.0, 728.0, 733.0, 789.0, 814.0, 826.0, 858.0, 861.0, 877.0, 886.0, 896.0, 912.0, 954.0, 984.0, 1002.0, 1021.0], + [43.0, 45.0, 46.0, 128.0, 147.0, 153.0, 154.0, 165.0, 231.0, 235.0, 238.0, 256.0, 318.0, 323.0, 350.0, 381.0, 384.0, 502.0, 517.0, 570.0, 575.0, 591.0, 609.0, 618.0, 622.0, 649.0, 655.0, 667.0, 672.0, 673.0, 722.0, 782.0, 794.0, 825.0, 849.0, 867.0, 868.0, 874.0, 892.0, 933.0, 935.0, 976.0, 982.0, 987.0, 1008.0, 1016.0], + [32.0, 42.0, 90.0, 109.0, 127.0, 141.0, 156.0, 163.0, 164.0, 179.0, 199.0, 215.0, 227.0, 230.0, 264.0, 296.0, 300.0, 328.0, 338.0, 363.0, 366.0, 406.0, 407.0, 408.0, 409.0, 426.0, 531.0, 546.0, 562.0, 588.0, 625.0, 654.0, 676.0, 679.0, 695.0, 709.0, 710.0, 771.0, 791.0, 801.0, 838.0, 845.0, 867.0, 869.0, 879.0, 880.0, 881.0, 932.0, 961.0, 984.0, 1017.0], + [3.0, 21.0, 35.0, 38.0, 40.0, 70.0, 75.0, 86.0, 138.0, 141.0, 167.0, 176.0, 188.0, 209.0, 220.0, 240.0, 243.0, 306.0, 329.0, 356.0, 357.0, 392.0, 406.0, 427.0, 428.0, 446.0, 449.0, 451.0, 483.0, 613.0, 629.0, 647.0, 648.0, 667.0, 712.0, 730.0, 733.0, 784.0, 906.0, 909.0, 948.0, 949.0, 969.0, 973.0, 984.0, 1018.0, 1022.0], + [21.0, 28.0, 47.0, 56.0, 107.0, 114.0, 126.0, 164.0, 178.0, 179.0, 190.0, 204.0, 227.0, 231.0, 242.0, 261.0, 303.0, 350.0, 362.0, 386.0, 425.0, 440.0, 471.0, 482.0, 509.0, 599.0, 603.0, 634.0, 646.0, 693.0, 709.0, 755.0, 799.0, 811.0, 848.0, 922.0, 923.0, 924.0, 928.0, 948.0, 975.0, 1011.0, 1018.0], + [88.0, 132.0, 161.0, 194.0, 206.0, 211.0, 247.0, 270.0, 296.0, 312.0, 331.0, 333.0, 334.0, 373.0, 429.0, 430.0, 436.0, 471.0, 494.0, 523.0, 530.0, 531.0, 536.0, 574.0, 620.0, 655.0, 676.0, 677.0, 709.0, 727.0, 738.0, 776.0, 783.0, 799.0, 805.0, 840.0, 875.0, 896.0, 910.0, 932.0, 939.0, 954.0, 1000.0], + [9.0, 26.0, 33.0, 40.0, 48.0, 65.0, 72.0, 74.0, 104.0, 105.0, 106.0, 107.0, 124.0, 134.0, 189.0, 195.0, 218.0, 228.0, 232.0, 271.0, 283.0, 341.0, 352.0, 354.0, 374.0, 393.0, 414.0, 417.0, 424.0, 435.0, 443.0, 456.0, 458.0, 524.0, 525.0, 574.0, 592.0, 605.0, 617.0, 620.0, 632.0, 641.0, 695.0, 791.0, 792.0, 811.0, 862.0, 943.0, 967.0, 975.0, 985.0, 1011.0], + [45.0, 76.0, 164.0, 258.0, 310.0, 340.0, 346.0, 349.0, 363.0, 383.0, 396.0, 424.0, 446.0, 468.0, 471.0, 516.0, 544.0, 550.0, 571.0, 595.0, 686.0, 750.0, 758.0, 775.0, 782.0, 799.0, 831.0, 832.0, 864.0, 876.0, 883.0, 896.0, 939.0, 941.0, 972.0, 976.0, 1008.0], + [43.0, 48.0, 63.0, 78.0, 86.0, 96.0, 166.0, 170.0, 175.0, 195.0, 224.0, 248.0, 263.0, 270.0, 271.0, 279.0, 292.0, 355.0, 395.0, 405.0, 406.0, 423.0, 442.0, 453.0, 454.0, 458.0, 471.0, 482.0, 484.0, 490.0, 504.0, 510.0, 563.0, 604.0, 606.0, 620.0, 644.0, 652.0, 656.0, 716.0, 727.0, 730.0, 744.0, 792.0, 797.0, 802.0, 807.0, 816.0, 837.0, 846.0, 850.0, 851.0, 856.0, 897.0, 898.0, 901.0, 929.0, 932.0, 951.0, 952.0, 974.0], + [15.0, 18.0, 28.0, 57.0, 61.0, 64.0, 65.0, 112.0, 134.0, 170.0, 179.0, 186.0, 212.0, 213.0, 275.0, 280.0, 318.0, 339.0, 369.0, 380.0, 382.0, 384.0, 415.0, 427.0, 444.0, 454.0, 455.0, 457.0, 490.0, 492.0, 499.0, 504.0, 509.0, 510.0, 516.0, 519.0, 537.0, 601.0, 603.0, 615.0, 622.0, 689.0, 692.0, 710.0, 711.0, 712.0, 727.0, 752.0, 764.0, 788.0, 789.0, 790.0, 814.0, 852.0, 860.0, 866.0, 889.0, 936.0, 948.0, 950.0, 964.0, 996.0, 1007.0], + [10.0, 33.0, 44.0, 132.0, 156.0, 166.0, 192.0, 198.0, 227.0, 231.0, 246.0, 258.0, 264.0, 276.0, 372.0, 389.0, 396.0, 434.0, 449.0, 451.0, 464.0, 490.0, 502.0, 524.0, 531.0, 567.0, 587.0, 615.0, 641.0, 651.0, 686.0, 700.0, 708.0, 786.0, 790.0, 803.0, 808.0, 850.0, 864.0, 871.0, 913.0, 934.0, 944.0, 993.0, 1012.0], + [4.0, 5.0, 13.0, 25.0, 127.0, 143.0, 152.0, 172.0, 173.0, 184.0, 188.0, 217.0, 307.0, 318.0, 327.0, 334.0, 337.0, 353.0, 373.0, 388.0, 393.0, 399.0, 422.0, 490.0, 518.0, 564.0, 668.0, 706.0, 726.0, 737.0, 751.0, 760.0, 794.0, 804.0, 806.0, 828.0, 858.0, 865.0, 883.0, 953.0, 962.0, 965.0, 969.0, 971.0, 988.0], + [3.0, 44.0, 67.0, 98.0, 141.0, 180.0, 188.0, 190.0, 233.0, 236.0, 255.0, 274.0, 322.0, 342.0, 347.0, 366.0, 597.0, 606.0, 650.0, 691.0, 695.0, 758.0, 759.0, 814.0, 815.0, 824.0, 839.0, 857.0, 859.0, 860.0, 902.0, 913.0, 915.0, 921.0, 925.0, 927.0, 947.0, 964.0], + [7.0, 22.0, 37.0, 38.0, 46.0, 88.0, 91.0, 100.0, 107.0, 108.0, 134.0, 164.0, 179.0, 183.0, 184.0, 199.0, 218.0, 236.0, 255.0, 260.0, 297.0, 301.0, 309.0, 317.0, 328.0, 333.0, 338.0, 348.0, 359.0, 410.0, 412.0, 479.0, 490.0, 516.0, 517.0, 578.0, 639.0, 644.0, 653.0, 700.0, 705.0, 707.0, 719.0, 733.0, 746.0, 756.0, 766.0, 776.0, 831.0, 857.0, 896.0, 902.0, 923.0, 955.0, 1001.0, 1004.0, 1009.0, 1012.0], + [17.0, 29.0, 71.0, 72.0, 82.0, 93.0, 94.0, 96.0, 99.0, 101.0, 123.0, 129.0, 155.0, 186.0, 188.0, 189.0, 275.0, 303.0, 313.0, 335.0, 352.0, 364.0, 365.0, 366.0, 393.0, 400.0, 408.0, 427.0, 431.0, 440.0, 441.0, 448.0, 476.0, 508.0, 537.0, 553.0, 568.0, 642.0, 668.0, 684.0, 685.0, 737.0, 755.0, 758.0, 796.0, 797.0, 829.0, 851.0, 865.0, 906.0, 950.0, 961.0, 982.0, 992.0, 995.0, 1006.0, 1016.0, 1021.0], + [24.0, 36.0, 42.0, 55.0, 93.0, 196.0, 213.0, 235.0, 237.0, 258.0, 272.0, 277.0, 363.0, 395.0, 431.0, 478.0, 523.0, 529.0, 534.0, 543.0, 557.0, 582.0, 588.0, 597.0, 607.0, 631.0, 649.0, 651.0, 656.0, 688.0, 690.0, 693.0, 700.0, 722.0, 734.0, 804.0, 819.0, 837.0, 855.0, 870.0, 899.0, 900.0, 954.0, 957.0, 979.0, 986.0, 1012.0, 1016.0], + [59.0, 112.0, 144.0, 158.0, 162.0, 207.0, 210.0, 241.0, 269.0, 275.0, 286.0, 298.0, 382.0, 400.0, 412.0, 428.0, 492.0, 590.0, 597.0, 598.0, 618.0, 627.0, 706.0, 741.0, 745.0, 797.0, 828.0, 834.0, 875.0, 897.0, 898.0, 899.0, 929.0, 965.0, 997.0, 1010.0, 1017.0, 1022.0], + [1.0, 23.0, 28.0, 37.0, 42.0, 54.0, 68.0, 76.0, 99.0, 128.0, 129.0, 163.0, 193.0, 206.0, 252.0, 256.0, 316.0, 358.0, 376.0, 499.0, 500.0, 510.0, 529.0, 548.0, 555.0, 558.0, 559.0, 563.0, 571.0, 579.0, 595.0, 618.0, 620.0, 626.0, 653.0, 692.0, 702.0, 712.0, 716.0, 827.0, 852.0, 863.0, 922.0, 943.0, 968.0, 979.0, 980.0, 981.0, 982.0, 984.0, 1000.0], + [23.0, 42.0, 61.0, 86.0, 88.0, 89.0, 99.0, 124.0, 128.0, 137.0, 144.0, 162.0, 170.0, 195.0, 196.0, 230.0, 234.0, 330.0, 348.0, 355.0, 371.0, 386.0, 401.0, 413.0, 417.0, 437.0, 590.0, 624.0, 640.0, 644.0, 648.0, 660.0, 674.0, 715.0, 737.0, 769.0, 781.0, 796.0, 819.0, 820.0, 822.0, 853.0, 854.0, 912.0, 956.0, 986.0, 997.0, 1022.0], + [8.0, 63.0, 64.0, 65.0, 82.0, 84.0, 135.0, 196.0, 230.0, 235.0, 237.0, 272.0, 304.0, 352.0, 383.0, 407.0, 425.0, 429.0, 438.0, 440.0, 448.0, 478.0, 485.0, 488.0, 522.0, 552.0, 561.0, 578.0, 595.0, 621.0, 640.0, 661.0, 670.0, 671.0, 674.0, 751.0, 771.0, 772.0, 785.0, 815.0, 900.0, 915.0, 918.0, 921.0, 960.0], + [6.0, 28.0, 29.0, 39.0, 54.0, 55.0, 74.0, 88.0, 172.0, 182.0, 185.0, 190.0, 193.0, 199.0, 205.0, 210.0, 215.0, 226.0, 228.0, 229.0, 254.0, 258.0, 266.0, 269.0, 293.0, 295.0, 300.0, 313.0, 321.0, 369.0, 379.0, 387.0, 412.0, 416.0, 419.0, 452.0, 464.0, 491.0, 496.0, 502.0, 535.0, 544.0, 588.0, 616.0, 645.0, 666.0, 702.0, 706.0, 723.0, 749.0, 835.0, 839.0, 847.0, 850.0, 873.0, 896.0, 899.0, 952.0, 953.0, 959.0, 965.0, 992.0, 998.0, 1000.0, 1004.0], + [10.0, 31.0, 68.0, 70.0, 78.0, 98.0, 125.0, 141.0, 149.0, 151.0, 264.0, 268.0, 305.0, 341.0, 346.0, 414.0, 433.0, 485.0, 511.0, 544.0, 549.0, 561.0, 622.0, 647.0, 652.0, 666.0, 688.0, 706.0, 720.0, 769.0, 775.0, 784.0, 787.0, 788.0, 796.0, 845.0, 846.0, 847.0, 889.0, 914.0, 934.0, 985.0, 992.0, 997.0], + [4.0, 5.0, 18.0, 50.0, 135.0, 138.0, 139.0, 176.0, 179.0, 185.0, 190.0, 218.0, 229.0, 235.0, 322.0, 345.0, 346.0, 370.0, 404.0, 419.0, 436.0, 484.0, 509.0, 522.0, 531.0, 534.0, 536.0, 574.0, 584.0, 587.0, 618.0, 626.0, 637.0, 642.0, 643.0, 647.0, 660.0, 682.0, 698.0, 724.0, 769.0, 777.0, 778.0, 799.0, 825.0, 826.0, 832.0, 836.0, 839.0, 869.0, 870.0, 900.0, 924.0, 953.0, 975.0, 984.0], + [5.0, 55.0, 78.0, 154.0, 157.0, 196.0, 199.0, 205.0, 249.0, 265.0, 266.0, 279.0, 286.0, 323.0, 348.0, 366.0, 375.0, 386.0, 395.0, 415.0, 419.0, 425.0, 440.0, 453.0, 532.0, 553.0, 560.0, 566.0, 585.0, 617.0, 660.0, 680.0, 690.0, 741.0, 743.0, 760.0, 774.0, 777.0, 782.0, 814.0, 829.0, 902.0, 957.0, 987.0], + [19.0, 49.0, 87.0, 133.0, 135.0, 187.0, 192.0, 225.0, 233.0, 260.0, 261.0, 293.0, 310.0, 337.0, 368.0, 371.0, 375.0, 447.0, 449.0, 470.0, 486.0, 487.0, 504.0, 509.0, 523.0, 525.0, 527.0, 639.0, 689.0, 690.0, 697.0, 746.0, 781.0, 787.0, 826.0, 844.0, 850.0, 896.0, 920.0, 950.0, 953.0, 1006.0, 1014.0, 1019.0], + [35.0, 37.0, 71.0, 89.0, 113.0, 123.0, 132.0, 135.0, 171.0, 192.0, 215.0, 237.0, 270.0, 280.0, 304.0, 319.0, 328.0, 364.0, 380.0, 423.0, 459.0, 475.0, 485.0, 493.0, 536.0, 544.0, 557.0, 706.0, 753.0, 756.0, 764.0, 788.0, 789.0, 796.0, 797.0, 863.0, 866.0, 878.0, 903.0, 938.0, 977.0], + [10.0, 26.0, 49.0, 64.0, 74.0, 104.0, 105.0, 151.0, 180.0, 209.0, 231.0, 243.0, 258.0, 278.0, 291.0, 323.0, 332.0, 415.0, 419.0, 423.0, 427.0, 487.0, 491.0, 494.0, 505.0, 520.0, 538.0, 555.0, 566.0, 580.0, 582.0, 633.0, 638.0, 650.0, 667.0, 670.0, 681.0, 696.0, 718.0, 719.0, 731.0, 752.0, 782.0, 818.0, 906.0, 923.0, 929.0, 945.0, 946.0, 951.0, 952.0, 958.0, 967.0, 968.0, 969.0, 1016.0], + [15.0, 20.0, 53.0, 62.0, 68.0, 83.0, 92.0, 108.0, 116.0, 117.0, 124.0, 164.0, 180.0, 192.0, 217.0, 245.0, 247.0, 281.0, 282.0, 288.0, 291.0, 327.0, 374.0, 389.0, 421.0, 429.0, 433.0, 480.0, 498.0, 501.0, 522.0, 537.0, 539.0, 569.0, 576.0, 628.0, 682.0, 683.0, 696.0, 752.0, 754.0, 765.0, 778.0, 798.0, 823.0, 852.0, 868.0, 875.0, 885.0, 890.0, 903.0, 937.0, 945.0, 954.0, 961.0, 983.0], + [5.0, 13.0, 49.0, 65.0, 145.0, 149.0, 150.0, 184.0, 200.0, 218.0, 223.0, 238.0, 253.0, 273.0, 278.0, 287.0, 294.0, 361.0, 417.0, 451.0, 478.0, 498.0, 557.0, 592.0, 660.0, 678.0, 688.0, 710.0, 769.0, 773.0, 803.0, 827.0, 857.0, 881.0, 897.0, 908.0, 955.0, 956.0, 974.0], + [44.0, 59.0, 67.0, 97.0, 117.0, 150.0, 165.0, 168.0, 175.0, 186.0, 215.0, 227.0, 231.0, 288.0, 294.0, 306.0, 333.0, 334.0, 341.0, 365.0, 380.0, 399.0, 427.0, 455.0, 458.0, 503.0, 524.0, 536.0, 542.0, 548.0, 549.0, 557.0, 582.0, 594.0, 606.0, 608.0, 644.0, 652.0, 660.0, 671.0, 702.0, 706.0, 722.0, 754.0, 792.0, 827.0, 832.0, 848.0, 880.0, 911.0, 923.0, 925.0, 934.0, 956.0, 960.0, 980.0, 985.0, 1016.0], + [26.0, 74.0, 75.0, 76.0, 92.0, 121.0, 122.0, 169.0, 178.0, 187.0, 197.0, 200.0, 223.0, 238.0, 303.0, 323.0, 365.0, 369.0, 406.0, 433.0, 478.0, 479.0, 491.0, 497.0, 501.0, 503.0, 531.0, 544.0, 552.0, 575.0, 619.0, 632.0, 648.0, 658.0, 664.0, 730.0, 744.0, 748.0, 757.0, 791.0, 816.0, 819.0, 831.0, 847.0, 856.0, 869.0, 873.0, 887.0, 903.0, 944.0, 964.0, 983.0, 996.0, 1023.0], + [2.0, 4.0, 7.0, 28.0, 36.0, 67.0, 84.0, 93.0, 125.0, 143.0, 156.0, 201.0, 225.0, 233.0, 271.0, 293.0, 296.0, 310.0, 314.0, 323.0, 325.0, 342.0, 398.0, 400.0, 423.0, 444.0, 456.0, 460.0, 476.0, 479.0, 492.0, 531.0, 532.0, 550.0, 569.0, 586.0, 628.0, 651.0, 658.0, 700.0, 739.0, 777.0, 800.0, 804.0, 806.0, 811.0, 885.0, 892.0, 907.0, 939.0, 957.0, 969.0, 983.0, 1000.0, 1003.0], + [23.0, 24.0, 58.0, 77.0, 96.0, 127.0, 165.0, 170.0, 206.0, 214.0, 231.0, 241.0, 253.0, 328.0, 355.0, 377.0, 382.0, 415.0, 435.0, 448.0, 483.0, 485.0, 526.0, 537.0, 554.0, 573.0, 577.0, 582.0, 601.0, 652.0, 704.0, 710.0, 717.0, 725.0, 731.0, 735.0, 750.0, 807.0, 837.0, 839.0, 846.0, 880.0, 915.0, 947.0], + [7.0, 22.0, 29.0, 68.0, 111.0, 125.0, 147.0, 149.0, 189.0, 192.0, 198.0, 212.0, 231.0, 237.0, 238.0, 269.0, 310.0, 332.0, 338.0, 354.0, 383.0, 405.0, 407.0, 413.0, 419.0, 424.0, 428.0, 435.0, 437.0, 441.0, 444.0, 453.0, 471.0, 489.0, 514.0, 561.0, 580.0, 583.0, 620.0, 627.0, 659.0, 670.0, 671.0, 673.0, 685.0, 700.0, 716.0, 725.0, 737.0, 749.0, 762.0, 773.0, 782.0, 819.0, 860.0, 863.0, 887.0, 905.0, 912.0, 924.0, 934.0, 953.0, 960.0, 1003.0, 1014.0], + [3.0, 31.0, 52.0, 58.0, 59.0, 96.0, 105.0, 118.0, 122.0, 126.0, 133.0, 135.0, 140.0, 144.0, 147.0, 175.0, 199.0, 215.0, 242.0, 258.0, 304.0, 322.0, 364.0, 380.0, 384.0, 385.0, 389.0, 390.0, 399.0, 421.0, 442.0, 451.0, 479.0, 498.0, 501.0, 512.0, 528.0, 547.0, 581.0, 586.0, 590.0, 652.0, 653.0, 654.0, 668.0, 685.0, 689.0, 705.0, 726.0, 762.0, 803.0, 808.0, 809.0, 835.0, 842.0, 874.0, 910.0, 914.0, 968.0, 978.0, 993.0, 1007.0, 1008.0, 1016.0, 1022.0], + [2.0, 8.0, 16.0, 21.0, 26.0, 47.0, 52.0, 89.0, 126.0, 135.0, 143.0, 147.0, 172.0, 195.0, 227.0, 235.0, 242.0, 251.0, 337.0, 344.0, 350.0, 358.0, 371.0, 375.0, 383.0, 387.0, 411.0, 421.0, 440.0, 441.0, 470.0, 475.0, 549.0, 552.0, 554.0, 555.0, 573.0, 574.0, 587.0, 603.0, 633.0, 667.0, 713.0, 726.0, 735.0, 741.0, 755.0, 756.0, 766.0, 789.0, 802.0, 803.0, 818.0, 821.0, 824.0, 845.0, 855.0, 895.0, 919.0, 926.0, 927.0, 930.0, 940.0], + [35.0, 38.0, 53.0, 58.0, 65.0, 90.0, 103.0, 174.0, 176.0, 239.0, 245.0, 269.0, 290.0, 366.0, 375.0, 396.0, 428.0, 453.0, 472.0, 490.0, 519.0, 586.0, 618.0, 687.0, 701.0, 726.0, 728.0, 747.0, 764.0, 767.0, 794.0, 851.0, 986.0], + [27.0, 41.0, 49.0, 50.0, 54.0, 108.0, 122.0, 152.0, 154.0, 158.0, 182.0, 221.0, 250.0, 256.0, 275.0, 288.0, 305.0, 328.0, 370.0, 379.0, 419.0, 423.0, 470.0, 492.0, 523.0, 524.0, 540.0, 542.0, 612.0, 642.0, 663.0, 675.0, 699.0, 701.0, 759.0, 770.0, 777.0, 785.0, 799.0, 804.0, 867.0, 879.0, 890.0, 895.0, 930.0, 937.0, 946.0, 967.0, 968.0, 975.0, 976.0, 1008.0, 1022.0], + [52.0, 55.0, 58.0, 90.0, 129.0, 136.0, 172.0, 192.0, 234.0, 235.0, 241.0, 244.0, 247.0, 308.0, 371.0, 413.0, 414.0, 473.0, 484.0, 497.0, 507.0, 519.0, 622.0, 648.0, 659.0, 687.0, 696.0, 746.0, 781.0, 801.0, 914.0, 931.0, 966.0, 971.0, 999.0], + [9.0, 24.0, 47.0, 50.0, 79.0, 106.0, 121.0, 132.0, 150.0, 154.0, 173.0, 183.0, 200.0, 217.0, 233.0, 276.0, 283.0, 320.0, 356.0, 357.0, 362.0, 385.0, 396.0, 405.0, 407.0, 445.0, 488.0, 540.0, 542.0, 550.0, 554.0, 579.0, 603.0, 608.0, 624.0, 636.0, 684.0, 776.0, 779.0, 792.0, 817.0, 820.0, 834.0, 846.0, 847.0, 860.0, 914.0, 918.0, 922.0, 925.0, 950.0, 958.0, 976.0, 995.0, 1022.0], + [47.0, 49.0, 54.0, 60.0, 66.0, 98.0, 150.0, 152.0, 153.0, 203.0, 220.0, 233.0, 261.0, 286.0, 300.0, 308.0, 419.0, 468.0, 490.0, 541.0, 555.0, 559.0, 561.0, 607.0, 655.0, 666.0, 672.0, 687.0, 690.0, 738.0, 761.0, 781.0, 798.0, 808.0, 819.0, 838.0, 839.0, 870.0, 871.0, 901.0, 915.0, 946.0, 984.0, 986.0, 991.0, 1000.0, 1017.0], + [38.0, 59.0, 213.0, 242.0, 246.0, 263.0, 277.0, 280.0, 282.0, 298.0, 313.0, 353.0, 362.0, 363.0, 377.0, 386.0, 415.0, 416.0, 466.0, 540.0, 588.0, 609.0, 653.0, 662.0, 666.0, 668.0, 678.0, 679.0, 709.0, 721.0, 738.0, 755.0, 776.0, 792.0, 796.0, 804.0, 818.0, 836.0, 886.0, 915.0, 919.0, 994.0, 1015.0], + [8.0, 17.0, 65.0, 75.0, 87.0, 104.0, 109.0, 166.0, 178.0, 209.0, 252.0, 255.0, 258.0, 261.0, 279.0, 304.0, 331.0, 382.0, 417.0, 421.0, 462.0, 479.0, 491.0, 538.0, 543.0, 544.0, 553.0, 559.0, 566.0, 604.0, 605.0, 662.0, 663.0, 670.0, 708.0, 729.0, 732.0, 738.0, 804.0, 809.0, 833.0, 838.0, 882.0, 898.0, 902.0, 913.0, 921.0, 936.0, 966.0, 984.0, 989.0, 990.0, 1002.0, 1012.0], + [22.0, 36.0, 52.0, 76.0, 77.0, 105.0, 114.0, 117.0, 118.0, 137.0, 160.0, 171.0, 175.0, 197.0, 202.0, 248.0, 284.0, 365.0, 392.0, 409.0, 453.0, 489.0, 493.0, 508.0, 551.0, 564.0, 571.0, 602.0, 615.0, 646.0, 647.0, 678.0, 686.0, 690.0, 696.0, 697.0, 739.0, 756.0, 781.0, 792.0, 793.0, 813.0, 896.0, 918.0, 931.0, 961.0, 962.0, 972.0, 981.0, 992.0, 1010.0], + [47.0, 100.0, 101.0, 130.0, 188.0, 200.0, 206.0, 229.0, 243.0, 255.0, 276.0, 296.0, 318.0, 326.0, 347.0, 433.0, 450.0, 453.0, 471.0, 475.0, 476.0, 483.0, 493.0, 494.0, 510.0, 533.0, 537.0, 562.0, 585.0, 617.0, 631.0, 657.0, 678.0, 709.0, 712.0, 745.0, 747.0, 755.0, 766.0, 771.0, 785.0, 792.0, 797.0, 815.0, 851.0, 886.0, 899.0, 999.0], + [3.0, 4.0, 15.0, 24.0, 50.0, 72.0, 98.0, 105.0, 108.0, 134.0, 157.0, 161.0, 194.0, 235.0, 295.0, 308.0, 316.0, 329.0, 393.0, 394.0, 452.0, 455.0, 515.0, 517.0, 536.0, 576.0, 584.0, 621.0, 627.0, 631.0, 676.0, 710.0, 719.0, 726.0, 727.0, 752.0, 788.0, 810.0, 826.0, 838.0, 839.0, 861.0, 862.0, 879.0, 886.0, 916.0, 980.0, 1020.0], + [31.0, 36.0, 46.0, 68.0, 72.0, 118.0, 123.0, 125.0, 160.0, 222.0, 223.0, 270.0, 293.0, 332.0, 348.0, 373.0, 380.0, 411.0, 413.0, 434.0, 469.0, 498.0, 507.0, 521.0, 566.0, 571.0, 601.0, 611.0, 619.0, 647.0, 696.0, 705.0, 711.0, 755.0, 760.0, 772.0, 774.0, 788.0, 796.0, 820.0, 849.0, 862.0, 866.0, 878.0, 898.0, 973.0, 1023.0], + [15.0, 24.0, 34.0, 41.0, 42.0, 63.0, 67.0, 100.0, 127.0, 182.0, 200.0, 237.0, 247.0, 249.0, 290.0, 323.0, 333.0, 342.0, 368.0, 387.0, 412.0, 424.0, 427.0, 440.0, 442.0, 487.0, 533.0, 548.0, 590.0, 607.0, 639.0, 651.0, 659.0, 714.0, 716.0, 738.0, 756.0, 782.0, 794.0, 802.0, 810.0, 820.0, 824.0, 854.0, 874.0, 876.0, 877.0, 912.0, 932.0, 945.0, 976.0, 987.0, 1005.0, 1022.0], + [14.0, 17.0, 71.0, 78.0, 100.0, 118.0, 132.0, 143.0, 162.0, 170.0, 176.0, 177.0, 195.0, 201.0, 219.0, 256.0, 261.0, 264.0, 279.0, 281.0, 288.0, 357.0, 406.0, 409.0, 412.0, 442.0, 445.0, 471.0, 488.0, 516.0, 529.0, 550.0, 557.0, 559.0, 563.0, 580.0, 591.0, 599.0, 675.0, 691.0, 736.0, 738.0, 749.0, 764.0, 765.0, 776.0, 780.0, 785.0, 806.0, 823.0, 825.0, 830.0, 837.0, 843.0, 864.0, 878.0, 921.0, 930.0, 932.0, 934.0, 937.0, 959.0], + [13.0, 19.0, 35.0, 85.0, 122.0, 128.0, 135.0, 136.0, 161.0, 165.0, 166.0, 203.0, 223.0, 236.0, 241.0, 242.0, 339.0, 353.0, 370.0, 381.0, 387.0, 390.0, 400.0, 407.0, 415.0, 421.0, 454.0, 464.0, 470.0, 471.0, 496.0, 504.0, 511.0, 520.0, 560.0, 565.0, 567.0, 601.0, 635.0, 655.0, 668.0, 705.0, 768.0, 787.0, 799.0, 806.0, 814.0, 835.0, 836.0, 857.0, 862.0, 872.0, 884.0, 888.0, 951.0, 984.0, 1021.0], + [24.0, 53.0, 54.0, 79.0, 89.0, 121.0, 134.0, 155.0, 164.0, 166.0, 205.0, 221.0, 222.0, 231.0, 291.0, 302.0, 334.0, 352.0, 369.0, 387.0, 437.0, 447.0, 451.0, 594.0, 609.0, 646.0, 652.0, 662.0, 681.0, 710.0, 787.0, 829.0, 848.0, 899.0, 912.0, 926.0, 997.0, 1006.0, 1022.0], + [14.0, 20.0, 29.0, 47.0, 52.0, 69.0, 75.0, 117.0, 120.0, 127.0, 146.0, 153.0, 175.0, 181.0, 237.0, 272.0, 287.0, 301.0, 316.0, 343.0, 347.0, 349.0, 395.0, 414.0, 425.0, 487.0, 526.0, 528.0, 538.0, 546.0, 548.0, 558.0, 581.0, 593.0, 630.0, 632.0, 636.0, 642.0, 651.0, 719.0, 726.0, 836.0, 968.0, 998.0, 1006.0], + [6.0, 23.0, 55.0, 90.0, 111.0, 117.0, 118.0, 123.0, 130.0, 131.0, 160.0, 187.0, 196.0, 214.0, 247.0, 253.0, 272.0, 288.0, 292.0, 302.0, 303.0, 307.0, 310.0, 323.0, 334.0, 364.0, 382.0, 384.0, 406.0, 432.0, 433.0, 439.0, 471.0, 524.0, 530.0, 562.0, 683.0, 689.0, 755.0, 769.0, 807.0, 809.0, 813.0, 834.0, 837.0, 880.0, 900.0, 927.0, 930.0, 939.0, 940.0, 970.0, 993.0], + [41.0, 54.0, 82.0, 83.0, 99.0, 139.0, 143.0, 146.0, 150.0, 161.0, 194.0, 227.0, 287.0, 312.0, 313.0, 320.0, 324.0, 340.0, 376.0, 384.0, 393.0, 430.0, 434.0, 476.0, 512.0, 514.0, 536.0, 584.0, 599.0, 600.0, 606.0, 624.0, 708.0, 714.0, 758.0, 785.0, 824.0, 838.0, 849.0, 873.0, 877.0, 881.0, 966.0, 973.0, 997.0, 1016.0], + [14.0, 24.0, 30.0, 36.0, 50.0, 73.0, 78.0, 87.0, 89.0, 107.0, 113.0, 155.0, 165.0, 171.0, 189.0, 190.0, 193.0, 209.0, 218.0, 238.0, 244.0, 288.0, 291.0, 311.0, 318.0, 319.0, 320.0, 325.0, 338.0, 351.0, 353.0, 407.0, 429.0, 475.0, 523.0, 526.0, 530.0, 546.0, 597.0, 599.0, 600.0, 604.0, 628.0, 632.0, 656.0, 658.0, 674.0, 713.0, 726.0, 746.0, 755.0, 756.0, 833.0, 847.0, 848.0, 856.0, 896.0, 911.0, 971.0, 1005.0, 1006.0, 1009.0, 1010.0, 1012.0], + [12.0, 50.0, 121.0, 128.0, 135.0, 161.0, 191.0, 192.0, 207.0, 208.0, 231.0, 266.0, 268.0, 270.0, 298.0, 394.0, 413.0, 483.0, 487.0, 518.0, 523.0, 567.0, 601.0, 606.0, 610.0, 659.0, 660.0, 680.0, 755.0, 791.0, 797.0, 802.0, 816.0, 827.0, 945.0, 974.0, 987.0, 1023.0] + ] \ No newline at end of file diff --git a/eprop_testing/hand_crafted_left_right.py b/eprop_testing/hand_crafted_left_right.py new file mode 100644 index 0000000..92ecc4e --- /dev/null +++ b/eprop_testing/hand_crafted_left_right.py @@ -0,0 +1,445 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from frozen_poisson import build_input_spike_train, frozen_poisson_variable_hz +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel +from spynnaker.pyNN.spynnaker_external_device_plugin_manager import SpynnakerExternalDevicePluginManager +from plot_graph import draw_graph_from_list, plot_learning_curve + +def weight_distribution(pop_size): + base_weight = np.random.randn() / np.sqrt(pop_size) #+ 0.5 + # base_weight = 0 + return base_weight + +def probability_connector(pre_pop_size, post_pop_size, prob, offset=0): + connections = [] + max_syn_per_neuron = 0 + for j in range(post_pop_size): + neuron_syn_count = 0 + delay_count = offset + for i in range(pre_pop_size): + if np.random.random() < prob: + neuron_syn_count += 1 + conn = [i, j, weight_distribution(pre_pop_size), delay_count] + delay_count += 1 + connections.append(conn) + if neuron_syn_count > max_syn_per_neuron: + max_syn_per_neuron = neuron_syn_count + return connections, max_syn_per_neuron + +def range_connector(pre_min, pre_max, post_min, post_max, weight=1.5, delay_offset=0): + connections = [] + for j in range(int(post_min), int(post_max)): + # delay = delay_offset + for i in range(int(pre_min), int(pre_max)): + nd_weight = weight_distribution(pre_max-pre_min) + connections.append([i, j, weight+nd_weight, i+delay_offset]) + # delay += 1 + return connections + +np.random.seed(2727) + +number_of_cues = 7 +cycle_time = (number_of_cues*150)+1000+150 +num_repeats = 2000 +pynn.setup(1.0) + +reg_rate = 0.000 +p_connect_in = 1. +p_connect_rec = 1. +p_connect_out = 1. +recurrent_connections = False + +synapse_eta = 0.01 +tau_a = 6500 #[cycle_time - 150 + (np.random.randn() * 200) for i in range(100)] +input_split = 100 +window_cycles = 2 +window_size = cycle_time*window_cycles +threshold_beta = 10 + +max_weight = 8.0 +in_weight = 0.55 +prompt_weight = 0.55 +rec_weight = 0#-0.5 +out_weight = 0 +weight_string = "i{}-p{}-r{}-o{}".format(in_weight, prompt_weight, rec_weight, out_weight) +pynn.setup(timestep=1) + +pynn.set_number_of_neurons_per_core(pynn.extra_models.EPropAdaptive, 6) + +input_size = 40 +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "poisson_pop_size": input_size / 4, + "rate_on": 100, + "rate_off": 0, + # "tau_m": tau_a, + "w_fb": [1, -1, 0], + "eta": synapse_eta * 10., + "window_size": window_size, + "number_of_cues": number_of_cues + } +rates = [] +for i in range(input_size): + if i >= (3*input_size) / 4: + rates.append(10) + else: + rates.append(0) +input_pop = pynn.Population(input_size, + pynn.SpikeSourcePoisson(rate=rates), + # {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size)}, + # {'spike_times': frozen_poisson_variable_hz(num_repeats, cycle_time, input_split, input_split, input_size)}, + label='input_pop') + +neuron_pop_size = 4*25 +ratio_of_LIF = 0.5 +beta = [] +for i in range(neuron_pop_size): + if i < neuron_pop_size/2: + # if i % 2 == 0: + # beta.append(0) + beta.append(threshold_beta) + else: + beta.append(threshold_beta) +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0, + # "w_fb": [np.random.random() for i in range(neuron_pop_size)], # best it seems + # "w_fb": [(np.random.random() * 2) - 1. for i in range(neuron_pop_size)], + "w_fb": [4*np.random.random() - 4*np.random.random() for i in range(neuron_pop_size)], ## for both feedback weights + # "w_fb": [-3]*(neuron_pop_size/2) + [3]*(neuron_pop_size/2), + # "w_fb": [3]*int(neuron_pop_size/4) + [-3]*int(neuron_pop_size/4) + [3]*int(neuron_pop_size/4) + [-3]*int(neuron_pop_size/4), + # "B": 0.0, + "beta": beta, + "target_rate": 10, + "tau_a": tau_a, + "eta": synapse_eta * 5,#/ 20., + "window_size": window_size, + "number_of_cues": number_of_cues + } +neuron = pynn.Population(neuron_pop_size, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +# Output population +readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.LeftRightReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + +poisson_control_edge = SpynnakerExternalDevicePluginManager.add_edge( + readout_pop._vertex, input_pop._vertex, "CONTROL") +# pynn.external_devices.activate_live_output_to( +# readout_pop, input_pop, "CONTROL") +input_pop._vertex.set_live_poisson_control_edge(poisson_control_edge) +# pynn.external_devices.add_poisson_live_rate_control(input_pop) + +start_w = [weight_distribution(neuron_pop_size*input_size) for i in range(input_size)] +eprop_learning_neuron = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=reg_rate)) + +# from_list_in, max_syn_per_input = probability_connector(input_size, neuron_pop_size, p_connect_in) +ps = int(readout_neuron_params["poisson_pop_size"]) +# from_list_in = range_connector(0, ps, 0, neuron_pop_size/2, weight=in_weight) # connect 1/2st 2 left +# from_list_in += range_connector(ps, ps*2, neuron_pop_size/2, neuron_pop_size, weight=in_weight) # connect 2/2nd 2 right +# from_list_in = range_connector(0, ps*2, 0, neuron_pop_size, weight=in_weight) # connect all cues to pop +# from_list_in += range_connector(ps*2, ps*3, 0, neuron_pop_size, delay_offset=0, weight=prompt_weight) # connect all 2 prompt +from_list_in = range_connector(0, ps*2, 0, neuron_pop_size, delay_offset=0, weight=in_weight) # connect all 2 prompt +from_list_in += range_connector(ps*2, ps*4, 0, neuron_pop_size, delay_offset=0, weight=prompt_weight) # connect all 2 prompt +in_proj = pynn.Projection(input_pop, + neuron, + pynn.FromListConnector(from_list_in), + # pynn.AllToAllConnector(), + synapse_type=eprop_learning_neuron, + label='input_connections', + receptor_type='input_connections') + +eprop_learning_output = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=0.0)) + +# from_list_out = [[i, 0, weight_distribution(input_size), i] for i in range(input_size)] +# from_list_out, max_syn_per_output = probability_connector(neuron_pop_size, 2, p_connect_out) +# from_list_out = range_connector(0, neuron_pop_size/2, 1, 2, weight=out_weight) # connect 1/2st 2 right output +# from_list_out += range_connector(neuron_pop_size/2, neuron_pop_size, 0, 1, weight=out_weight) # connect 2/2nd 2 left output +# from_list_out += range_connector(0, neuron_pop_size/2, 0, 1, weight=-out_weight) # connect 1/2st -2 left output +# from_list_out += range_connector(neuron_pop_size/2, neuron_pop_size, 1, 2, weight=-out_weight) # connect 2/2nd -2 right output +from_list_out = range_connector(0, neuron_pop_size, 0, 2, weight=out_weight) # connect all +out_proj = pynn.Projection(neuron, + readout_pop, + # pynn.OneToOneConnector(), + pynn.FromListConnector(from_list_out), + synapse_type=eprop_learning_output, + label='input_connections', + receptor_type='input_connections') + +learning_proj = pynn.Projection(readout_pop, + neuron, + pynn.AllToAllConnector(), + pynn.StaticSynapse(weight=0.5, delay=0), + receptor_type='learning_signal') + +# learning_proj = pynn.Projection(readout_pop, +# readout_pop, +# pynn.AllToAllConnector(), +# pynn.StaticSynapse(weight=0.5, delay=0), +# receptor_type='learning_signal') + +if recurrent_connections: + eprop_learning_recurrent = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=reg_rate)) + + # from_list_rec, max_syn_per_rec = probability_connector(neuron_pop_size, neuron_pop_size, p_connect_rec, offset=0) + # from_list_rec = range_connector(0, neuron_pop_size/2, neuron_pop_size/2, neuron_pop_size, weight=rec_weight, delay_offset=100) # inhibitory connections between 1/2s + # from_list_rec += range_connector(neuron_pop_size/2, neuron_pop_size, 0, neuron_pop_size/2, weight=rec_weight, delay_offset=100) # inhibitory connections between 1/2s + from_list_rec = range_connector(0, neuron_pop_size, 0, neuron_pop_size, weight=rec_weight, delay_offset=100) # recurrent connections + recurrent_proj = pynn.Projection(neuron, + neuron, + pynn.FromListConnector(from_list_rec), + synapse_type=eprop_learning_recurrent, + label='recurrent_connections', + receptor_type='recurrent_connections') + +input_pop.record('spikes') +neuron.record('spikes') +# neuron.record(['gsyn_exc', 'v', 'gsyn_inh'], indexes=[i for i in range(int((neuron_pop_size/2)-5), int((neuron_pop_size/2)+5))]) +neuron[[i for i in range(int((neuron_pop_size/2)-5), int( + (neuron_pop_size/2)+5))]].record(['gsyn_exc', 'v', 'gsyn_inh']) +readout_pop.record('all') + +runtime = cycle_time * num_repeats + +experiment_label = "eta:{}/{} - size:{}/{} - weights:{} - p_conn:{}/{}/{} - rec:{} - cycle:{}/{}/{} Atau65 b:{}".format( + readout_neuron_params["eta"], neuron_params["eta"], input_size, neuron_pop_size, weight_string, p_connect_in, p_connect_rec, p_connect_out, recurrent_connections, cycle_time, window_size, runtime, threshold_beta) +print("\n", experiment_label, "\n") + +pynn.run(runtime) +in_spikes = input_pop.get_data('spikes', clear=True) +neuron_res = neuron.get_data('all', clear=True) +readout_res = readout_pop.get_data('all', clear=True) + +total_error = 0.0 +cycle_error = [0.0 for i in range(num_repeats)] +correct_or_not = [0 for i in range(num_repeats)] +soft_max = [[], []] +cross_entropy = [] # how do I extract the answer easily? final gsyn exc value? +all_cross = [[], []] +from_soft = [[], []] +for cycle in range(num_repeats): + ticks_for_mean = 0 + mean_0 = 0. + mean_1 = 0. + # mean_0_all = 0. + # mean_1_all = 0. + for time_index in range(cycle_time): + instantaneous_error = np.abs(float( + readout_res.segments[0].filter(name='gsyn_inh')[0][time_index+(cycle*cycle_time)][0])) + cycle_error[cycle] += instantaneous_error + total_error += instantaneous_error + if cycle_error[cycle] < 75: + correct_or_not[cycle] = 1 + +new_connections_in = []#in_proj.get('weight', 'delay').connections[0]#[] +for partition in in_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_in.append(conn) +new_connections_in.sort(key=lambda x:x[0]) +new_connections_in.sort(key=lambda x:x[1]) +from_list_in.sort(key=lambda x:x[0]) +from_list_in.sort(key=lambda x:x[1]) +connection_diff_in = [] +for i in range(len(from_list_in)): + connection_diff_in.append(new_connections_in[i][2] - from_list_in[i][2]) +print("Input connections\noriginal\n", np.array(from_list_in)) +print("new\n", np.array(new_connections_in)) +print("diff\n", np.array(connection_diff_in)) + +new_connections_out = []#out_proj.get('weight', 'delay').connections[0]#[] +for partition in out_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_out.append(conn) +new_connections_out.sort(key=lambda x:x[0]) +new_connections_out.sort(key=lambda x:x[1]) +from_list_out.sort(key=lambda x:x[0]) +from_list_out.sort(key=lambda x:x[1]) +connection_diff_out = [] +for i in range(len(from_list_out)): + connection_diff_out.append(new_connections_out[i][2] - from_list_out[i][2]) +print("Output connections\noriginal\n", np.array(from_list_out)) +print("new\n", np.array(new_connections_out)) +print("diff\n", np.array(connection_diff_out)) + +if recurrent_connections: + new_connections_rec = []#out_proj.get('weight', 'delay').connections[0]#[] + for partition in recurrent_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_rec.append(conn) + new_connections_rec.sort(key=lambda x:x[0]) + new_connections_rec.sort(key=lambda x:x[1]) + from_list_rec.sort(key=lambda x:x[0]) + from_list_rec.sort(key=lambda x:x[1]) + connection_diff_rec = [] + for i in range(len(from_list_rec)): + connection_diff_rec.append(new_connections_rec[i][2] - from_list_rec[i][2]) + print("Recurrent connections\noriginal\n", np.array(from_list_rec)) + print("new\n", np.array(new_connections_rec)) + print("diff\n", np.array(connection_diff_rec)) + +print(experiment_label) +print("cycle_error =", cycle_error) +print("total error =", total_error) +print("correct:")# =", correct_or_not +for i in range(int(np.ceil(len(correct_or_not) / float(window_cycles)))): + print(correct_or_not[i*window_cycles:(i+1)*window_cycles], np.average(correct_or_not[i*window_cycles:(i+1)*window_cycles])) +print("average error = ", np.average(cycle_error)) +print("weighted average", np.average(cycle_error, weights=[i for i in range(num_repeats)])) +print("minimum error = ", np.min(cycle_error)) +print("minimum iteration =", cycle_error.index(np.min(cycle_error)), "- with time stamp =", cycle_error.index(np.min(cycle_error)) * 1024) +print(experiment_label) + +# plt.figure() +# Figure( +# Panel(neuron_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(neuron_res.segments[0].spiketrains, ylabel='neuron_spikes', xlabel='neuron_spikes', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), +# +# title="neuron data for {}".format(experiment_label) +# ) +# plt.show() + +plot_start = runtime-(cycle_time*15) +plot_end = runtime +plt.figure() +Figure( + Panel(neuron_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(neuron_res.segments[0].spiketrains, ylabel='neuron_spikes', xlabel='neuron_spikes', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + title="neuron data for {}".format(experiment_label) +) +# The below only works with a Qt-based backend for matplotlib +# manager = plt.get_current_fig_manager() +# manager.resize(*manager.window.maxsize()) +plt.show() + +print("plotted neuron data") + +def moving_average(a, n=3) : + ret = np.cumsum(a, dtype=float) + ret[n:] = ret[n:] - ret[:-n] + return ret[n - 1:] / n + +ave_corr10 = moving_average(correct_or_not, 10) +ave_corr64 = moving_average(correct_or_not, 64) + +fig, axs = plt.subplots(4, 1) +axs[0].set_title(experiment_label) +axs[0].scatter([i for i in range(len(correct_or_not))], correct_or_not) +axs[0].set_xlim([-20, num_repeats+20]) +axs[1].scatter([i for i in range(len(cycle_error))], cycle_error) +axs[1].set_xlim([-20, num_repeats+20]) +axs[1].plot([0, len(cycle_error)], [75, 75], 'r') +axs[2].plot([i+5 for i in range(len(ave_corr10))], ave_corr10) +axs[2].plot([0, num_repeats], [0.9, 0.9], 'r') +axs[2].plot([0, num_repeats], [0.95, 0.95], 'g') +axs[2].set_xlim([-20, num_repeats+20]) +axs[3].plot([i+32 for i in range(len(ave_corr64))], ave_corr64) +axs[3].plot([0, num_repeats], [0.9, 0.9], 'r') +axs[3].plot([0, num_repeats], [0.95, 0.95], 'g') +axs[3].set_xlim([-20, num_repeats+20]) +# The below only works with a Qt-based backend for matplotlib +# manager = plt.get_current_fig_manager() +# manager.resize(*manager.window.maxsize()) +plt.show() + +print("plotted curves") + +pynn.end() +print("job done") + +''' +draw_graph_from_list(new_connections_in, new_connections_rec, new_connections_out) + +base_string = 'connection_lists/good 1 cue 20n recF' +np.save(base_string+' in.npy', new_connections_in) +np.save(base_string+' out.npy', new_connections_out) +np.save(base_string+' rec.npy', new_connections_rec) + +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() + +def moving_average(a, n=3) : + ret = np.cumsum(a, dtype=float) + ret[n:] = ret[n:] - ret[:-n] + return ret[n - 1:] / n + +v_mem = [] +sine_wave = [] +for timestep in readout_res.segments[0].filter(name='v')[0]: + v_mem.append(timestep[0]) + sine_wave.append(timestep[1]) + +ave_mem = moving_average(v_mem, 20) +ave_sine = moving_average(sine_wave, 20) + +plt.figure() +plt.plot([i for i in range(len(ave_mem))], cum_mem) +plt.plot([i for i in range(len(ave_sine))], cum_sine) +plt.title(experiment_label) +plt.show() + +plt.figure() +plt.plot([i for i in range(len(soft_max[0]))], soft_max[0]) +plt.plot([i for i in range(len(soft_max[1]))], soft_max[1]) +plt.title(experiment_label) +plt.show() +''' \ No newline at end of file diff --git a/eprop_testing/incremental_config.py b/eprop_testing/incremental_config.py new file mode 100644 index 0000000..0e52682 --- /dev/null +++ b/eprop_testing/incremental_config.py @@ -0,0 +1,82 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import numpy as np + +number_of_cues = 1 +cycle_time = (number_of_cues * 150) + 1000 + 150 +num_repeats = 2000 +learning_threshold = 0.9 + +reg_rate = 0.000 +p_connect_in = 1. +p_connect_rec = 1. +p_connect_out = 1. +recurrent_connections = False +synapse_eta = 0.003 +tau_a = 3500 # [cycle_time - 150 + (np.random.randn() * 200) for i in range(100)] +input_split = 100 +window_cycles = 2 +window_size = cycle_time * window_cycles +threshold_beta = 0.3 + +max_weight = 8.0 +in_weight = 0.55 +prompt_weight = 0.55 +rec_weight = 0 # -0.5 +out_weight = 0 # 0.01 +weight_string = "i{}-p{}-r{}-o{}".format(in_weight, prompt_weight, rec_weight, out_weight) +free_label = 't35 rfb.3' + +input_size = 40 +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "poisson_pop_size": input_size // 4, + "rate_on": 100, + "rate_off": 0, + "w_fb": [1, -1, 0], + "eta": synapse_eta * 10., + "window_size": window_size, + "number_of_cues": number_of_cues +} +rates = [] +for i in range(input_size): + if i >= (3 * input_size) // 4: + rates.append(10) + else: + rates.append(0) + +neuron_pop_size = 4 * 25 + +ratio_of_LIF = 0.5 +beta = [] +for i in range(neuron_pop_size): + if i < neuron_pop_size // 2: + beta.append(threshold_beta) + else: + beta.append(threshold_beta) +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0, + "w_fb": [5*np.random.random() - 5*np.random.random() for i in range(neuron_pop_size)], ## for both feedback weights + # "w_fb": [3] * int(neuron_pop_size / 4) + [-3] * int(neuron_pop_size / 4) + [3] * int(neuron_pop_size / 4) + [-3] * int(neuron_pop_size / 4), + # "B": 0.0, + "beta": beta, + "target_rate": 10, + "tau_a": tau_a, + "eta": synapse_eta * 5, # / 20., + "window_size": window_size, + "number_of_cues": number_of_cues +} diff --git a/eprop_testing/incremental_graph_drawing.py b/eprop_testing/incremental_graph_drawing.py new file mode 100644 index 0000000..f03c7fc --- /dev/null +++ b/eprop_testing/incremental_graph_drawing.py @@ -0,0 +1,519 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from frozen_poisson import build_input_spike_train, frozen_poisson_variable_hz +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel +from spynnaker.pyNN.spynnaker_external_device_plugin_manager import SpynnakerExternalDevicePluginManager +from plot_graph import draw_graph_from_list, plot_learning_curve + +def load_connections(npy_label, pop_size, rec=True): + in_conn = [list(ele) for ele in np.load(npy_label+' in.npy').tolist()] + if rec: + rec_conn = [list(ele) for ele in np.load(npy_label+' rec.npy').tolist()] + out_conn = [list(ele) for ele in np.load(npy_label+' out.npy').tolist()] + for ndx in range(len(in_conn)): + if in_conn[ndx][3] == 16 and in_conn[ndx][0] == 0: + in_conn[ndx][3] = 0 + if rec: + for ndx in range(len(rec_conn)): + if rec_conn[ndx][3] == 16 and rec_conn[ndx][0] == 0: + rec_conn[ndx][3] = 0 + for ndx in range(len(out_conn)): + if out_conn[ndx][3] == 16 and out_conn[ndx][0] == 0: + out_conn[ndx][3] = 0 + checking_delays = [[] for i in range(pop_size)] + list_to_check = in_conn + if rec: + list_to_check = in_conn+rec_conn + for [pre, post, weight, delay] in list_to_check: + if delay not in checking_delays[post]: + checking_delays.append(delay) + else: + print("delays are overlapped") + Exception + if not rec: + rec_conn = [] + return in_conn, rec_conn, out_conn + +def weight_distribution(pop_size): + base_weight = np.random.randn() / np.sqrt(pop_size) #+ 0.5 + # base_weight = 0 + return base_weight + +def probability_connector(pre_pop_size, post_pop_size, prob, offset=0): + connections = [] + max_syn_per_neuron = 0 + for j in range(post_pop_size): + neuron_syn_count = 0 + delay_count = offset + for i in range(pre_pop_size): + if np.random.random() < prob: + neuron_syn_count += 1 + conn = [i, j, weight_distribution(pre_pop_size), delay_count] + delay_count += 1 + connections.append(conn) + if neuron_syn_count > max_syn_per_neuron: + max_syn_per_neuron = neuron_syn_count + return connections, max_syn_per_neuron + +def range_connector(pre_min, pre_max, post_min, post_max, weight=1.5, delay_offset=0): + connections = [] + for j in range(int(post_min), int(post_max)): + # delay = delay_offset + for i in range(int(pre_min), int(pre_max)): + nd_weight = weight_distribution(pre_max-pre_min) + connections.append([i, j, weight+nd_weight, i+delay_offset]) + # delay += 1 + return connections + +np.random.seed(272727) + +number_of_cues = 1 +cycle_time = (number_of_cues*150)+1000+150 +num_repeats = 300 +# pynn.setup(1.0) # setup called twice? + +reg_rate = 0.000 +p_connect_in = 1. +p_connect_rec = 1. +p_connect_out = 1. +recurrent_connections = False +synapse_eta = 0.01 +tau_a = 2500#[cycle_time - 150 + (np.random.randn() * 200) for i in range(100)] +input_split = 100 +window_cycles = 2 +window_size = cycle_time*window_cycles +threshold_beta = 3 + +max_weight = 8.0 +in_weight = 0.55 +prompt_weight = 0.55 +rec_weight = 0#-0.5 +out_weight = 0#0.01 +weight_string = "i{}-p{}-r{}-o{}".format(in_weight, prompt_weight, rec_weight, out_weight) +pynn.setup(timestep=1) + +pynn.set_number_of_neurons_per_core(pynn.extra_models.EPropAdaptive, 6) + +input_size = 40 +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "poisson_pop_size": input_size // 4, + "rate_on": 100, + "rate_off": 0, + # "tau_m": tau_a, + "w_fb": [1, -1, 0], + "eta": synapse_eta * 10., + "window_size": window_size, + } +rates = [] +for i in range(input_size): + if i >= (3*input_size) // 4: + rates.append(10) + else: + rates.append(0) +input_pop = pynn.Population(input_size, + pynn.SpikeSourcePoisson(rate=rates), + # {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size)}, + # {'spike_times': frozen_poisson_variable_hz(num_repeats, cycle_time, input_split, input_split, input_size)}, + label='input_pop') + +neuron_pop_size = 4*15 +# from_list_in, from_list_rec, from_list_out = load_connections('good 1 cue 20n recT', neuron_pop_size) + +ratio_of_LIF = 0.5 +beta = [] +for i in range(neuron_pop_size): + if i < neuron_pop_size//2: + # if i % 2 == 0: + beta.append(threshold_beta) + else: + beta.append(threshold_beta) +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0, + # "w_fb": [np.random.random() for i in range(neuron_pop_size)], # best it seems + # "w_fb": [(np.random.random() * 2) - 1. for i in range(neuron_pop_size)], + # "w_fb": [4*np.random.random() - 4*np.random.random() for i in range(neuron_pop_size)], ## for both feedback weights + # "w_fb": [-3]*(neuron_pop_size/2) + [3]*(neuron_pop_size/2), + "w_fb": [3.0]*int(neuron_pop_size/4) + [-3.0]*int( + neuron_pop_size/4) + [3.0]*int(neuron_pop_size/4) + [-3.0]*int( + neuron_pop_size/4), + # "B": 0.0, + "beta": beta, + "target_rate": 10, + "tau_a": tau_a, + "eta": synapse_eta * 5,#/ 20., + "window_size": window_size, + } +neuron = pynn.Population(neuron_pop_size, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +# Output population +readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.LeftRightReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + +poisson_control_edge = SpynnakerExternalDevicePluginManager.add_edge( + readout_pop._vertex, input_pop._vertex, "CONTROL") +# pynn.external_devices.activate_live_output_to( +# readout_pop, input_pop, "CONTROL") +input_pop._vertex.set_live_poisson_control_edge(poisson_control_edge) +# pynn.external_devices.add_poisson_live_rate_control(input_pop) + +eprop_learning_neuron = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=reg_rate)) + +# from_list_in, max_syn_per_input = probability_connector(input_size, neuron_pop_size, p_connect_in) +ps = int(readout_neuron_params["poisson_pop_size"]) +# from_list_in = range_connector(0, ps, 0, neuron_pop_size/2, weight=in_weight) # connect 1/2st 2 left +# from_list_in += range_connector(ps, ps*2, neuron_pop_size/2, neuron_pop_size, weight=in_weight) # connect 2/2nd 2 right +# from_list_in = range_connector(0, ps*2, 0, neuron_pop_size, weight=in_weight) # connect all cues to pop +# from_list_in += range_connector(ps*2, ps*3, 0, neuron_pop_size, delay_offset=0, weight=prompt_weight) # connect all 2 prompt +from_list_in = range_connector(0, ps*2, 0, neuron_pop_size, delay_offset=0, weight=in_weight) # connect all 2 prompt +from_list_in += range_connector(ps*2, ps*4, 0, neuron_pop_size, delay_offset=0, weight=prompt_weight) # connect all 2 prompt +in_proj = pynn.Projection(input_pop, + neuron, + pynn.FromListConnector(from_list_in), + # pynn.AllToAllConnector(), + synapse_type=eprop_learning_neuron, + label='input_connections', + receptor_type='input_connections') + +eprop_learning_output = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=0.0)) + +# from_list_out = [[i, 0, weight_distribution(input_size), i] for i in range(input_size)] +# from_list_out, max_syn_per_output = probability_connector(neuron_pop_size, 2, p_connect_out) +# from_list_out = range_connector(0, neuron_pop_size/2, 1, 2, weight=out_weight) # connect 1/2st 2 right output +# from_list_out += range_connector(neuron_pop_size/2, neuron_pop_size, 0, 1, weight=out_weight) # connect 2/2nd 2 left output +# from_list_out += range_connector(0, neuron_pop_size/2, 0, 1, weight=-out_weight) # connect 1/2st -2 left output +# from_list_out += range_connector(neuron_pop_size/2, neuron_pop_size, 1, 2, weight=-out_weight) # connect 2/2nd -2 right output +from_list_out = range_connector(0, neuron_pop_size, 0, 2, weight=out_weight) # connect all +out_proj = pynn.Projection(neuron, + readout_pop, + # pynn.OneToOneConnector(), + pynn.FromListConnector(from_list_out), + synapse_type=eprop_learning_output, + label='input_connections', + receptor_type='input_connections') + +learning_proj = pynn.Projection(readout_pop, + neuron, + pynn.AllToAllConnector(), + pynn.StaticSynapse(weight=0.5, delay=0), + receptor_type='learning_signal') + +# learning_proj = pynn.Projection(readout_pop, +# readout_pop, +# pynn.AllToAllConnector(), +# pynn.StaticSynapse(weight=0.5, delay=0), +# receptor_type='learning_signal') + +if recurrent_connections: + eprop_learning_recurrent = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-max_weight, w_max=max_weight, reg_rate=reg_rate)) + + # from_list_rec, max_syn_per_rec = probability_connector(neuron_pop_size, neuron_pop_size, p_connect_rec, offset=0) + # from_list_rec = range_connector(0, neuron_pop_size/2, neuron_pop_size/2, neuron_pop_size, weight=rec_weight, delay_offset=100) # inhibitory connections between 1/2s + # from_list_rec += range_connector(neuron_pop_size/2, neuron_pop_size, 0, neuron_pop_size/2, weight=rec_weight, delay_offset=100) # inhibitory connections between 1/2s + from_list_rec = range_connector(0, neuron_pop_size, 0, neuron_pop_size, weight=rec_weight, delay_offset=100) # recurrent connections + recurrent_proj = pynn.Projection(neuron, + neuron, + pynn.FromListConnector(from_list_rec), + synapse_type=eprop_learning_recurrent, + label='recurrent_connections', + receptor_type='recurrent_connections') + +input_pop.record('spikes') +neuron.record('spikes') +# neuron.record(['gsyn_exc', 'v', 'gsyn_inh'], indexes=[i for i in range(int((neuron_pop_size/2)-5), int((neuron_pop_size/2)+5))]) +neuron[[i for i in range(int((neuron_pop_size/2)-5), + int((neuron_pop_size/2)+5))]].record(['gsyn_exc', 'v', 'gsyn_inh']) +readout_pop.record('all') + +runtime = cycle_time * num_repeats + +experiment_label = "eta-{}_{} - size-{}_{} - weights-{} - p_conn-{}_{}_{} - rec-{} - cycle-{}_{}_{} regoff 40hz nd b-{}".format( + readout_neuron_params["eta"], neuron_params["eta"], input_size, neuron_pop_size, weight_string, p_connect_in, p_connect_rec, p_connect_out, recurrent_connections, cycle_time, window_size, runtime, threshold_beta) +print("\n", experiment_label, "\n") + +current_window = 0 +while current_window*window_size < runtime: + pynn.run(window_size) + in_spikes = input_pop.get_data('spikes', clear=True) + neuron_res = neuron.get_data('all', clear=True) + readout_res = readout_pop.get_data('all', clear=True) + plot_start = (window_size*current_window) + current_window += 1 + plot_end = (window_size*current_window) + + total_error = 0.0 + cycle_error = [0.0 for i in range(current_window*window_cycles)] + correct_or_not = [0 for i in range(current_window*window_cycles)] + # for cycle in range(current_window*window_cycles): + for cycle in range(window_cycles): + for time_index in range(cycle_time): + instantaneous_error = np.abs(float( + readout_res.segments[0].filter(name='gsyn_inh')[0][time_index+(cycle*cycle_time)][0])) + cycle_error[cycle] += instantaneous_error + total_error += instantaneous_error + if cycle_error[cycle] < 75: + correct_or_not[cycle] = 1 + + new_connections_in = []#in_proj.get('weight', 'delay').connections[0]#[] + for partition in in_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_in.append(conn) + new_connections_in.sort(key=lambda x:x[0]) + new_connections_in.sort(key=lambda x:x[1]) + from_list_in.sort(key=lambda x:x[0]) + from_list_in.sort(key=lambda x:x[1]) + connection_diff_in = [] + for i in range(len(from_list_in)): + connection_diff_in.append(new_connections_in[i][2] - from_list_in[i][2]) + print("Input connections\noriginal\n", np.array(from_list_in)) + print("new\n", np.array(new_connections_in)) + print("diff\n", np.array(connection_diff_in)) + + new_connections_out = []#out_proj.get('weight', 'delay').connections[0]#[] + for partition in out_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_out.append(conn) + new_connections_out.sort(key=lambda x:x[0]) + new_connections_out.sort(key=lambda x:x[1]) + from_list_out.sort(key=lambda x:x[0]) + from_list_out.sort(key=lambda x:x[1]) + connection_diff_out = [] + for i in range(len(from_list_out)): + connection_diff_out.append(new_connections_out[i][2] - from_list_out[i][2]) + print("Output connections\noriginal\n", np.array(from_list_out)) + print("new\n", np.array(new_connections_out)) + print("diff\n", np.array(connection_diff_out)) + + new_connections_rec = [] + if recurrent_connections: + for partition in recurrent_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_rec.append(conn) + new_connections_rec.sort(key=lambda x:x[0]) + new_connections_rec.sort(key=lambda x:x[1]) + from_list_rec.sort(key=lambda x:x[0]) + from_list_rec.sort(key=lambda x:x[1]) + connection_diff_rec = [] + for i in range(len(from_list_rec)): + connection_diff_rec.append(new_connections_rec[i][2] - from_list_rec[i][2]) + print("Recurrent connections\noriginal\n", np.array(from_list_rec)) + print("new\n", np.array(new_connections_rec)) + print("diff\n", np.array(connection_diff_rec)) + + print(cycle_error) + for i in range(int(np.ceil(len(correct_or_not) / float(window_cycles)))): + print(correct_or_not[i*window_cycles:(i+1)*window_cycles], np.average(correct_or_not[i*window_cycles:(i+1)*window_cycles])) + + graph_directory = './graphs/' + draw_graph_from_list(new_connections_in, new_connections_rec, new_connections_out, graph_directory, experiment_label+' {}'.format(current_window), rec_flag=recurrent_connections, save_flag=True) + plot_learning_curve(correct_or_not, cycle_error, graph_directory, + experiment_label+' {}'.format(current_window), + save_flag=True) + + +total_error = 0.0 +cycle_error = [0.0 for i in range(num_repeats)] +correct_or_not = [0 for i in range(num_repeats)] +soft_max = [[], []] +cross_entropy = [] # how do I extract the answer easily? final gsyn exc value? +all_cross = [[], []] +from_soft = [[], []] +for cycle in range(num_repeats): + for time_index in range(cycle_time): + instantaneous_error = np.abs(float( + readout_res.segments[0].filter(name='gsyn_inh')[0][time_index+(cycle*cycle_time)][0])) + cycle_error[cycle] += instantaneous_error + total_error += instantaneous_error + if cycle_error[cycle] < 75: + correct_or_not[cycle] = 1 + +new_connections_in = []#in_proj.get('weight', 'delay').connections[0]#[] +for partition in in_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_in.append(conn) +new_connections_in.sort(key=lambda x:x[0]) +new_connections_in.sort(key=lambda x:x[1]) +from_list_in.sort(key=lambda x:x[0]) +from_list_in.sort(key=lambda x:x[1]) +connection_diff_in = [] +for i in range(len(from_list_in)): + connection_diff_in.append(new_connections_in[i][2] - from_list_in[i][2]) +print("Input connections\noriginal\n", np.array(from_list_in)) +print("new\n", np.array(new_connections_in)) +print("diff\n", np.array(connection_diff_in)) + +new_connections_out = []#out_proj.get('weight', 'delay').connections[0]#[] +for partition in out_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_out.append(conn) +new_connections_out.sort(key=lambda x:x[0]) +new_connections_out.sort(key=lambda x:x[1]) +from_list_out.sort(key=lambda x:x[0]) +from_list_out.sort(key=lambda x:x[1]) +connection_diff_out = [] +for i in range(len(from_list_out)): + connection_diff_out.append(new_connections_out[i][2] - from_list_out[i][2]) +print("Output connections\noriginal\n", np.array(from_list_out)) +print("new\n", np.array(new_connections_out)) +print("diff\n", np.array(connection_diff_out)) + +if recurrent_connections: + new_connections_rec = []#out_proj.get('weight', 'delay').connections[0]#[] + for partition in recurrent_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_rec.append(conn) + new_connections_rec.sort(key=lambda x:x[0]) + new_connections_rec.sort(key=lambda x:x[1]) + from_list_rec.sort(key=lambda x:x[0]) + from_list_rec.sort(key=lambda x:x[1]) + connection_diff_rec = [] + for i in range(len(from_list_rec)): + connection_diff_rec.append(new_connections_rec[i][2] - from_list_rec[i][2]) + print("Recurrent connections\noriginal\n", np.array(from_list_rec)) + print("new\n", np.array(new_connections_rec)) + print("diff\n", np.array(connection_diff_rec)) + +print(experiment_label) +print("cycle_error =", cycle_error) +print("total error =", total_error) +print("correct:") # =", correct_or_not +for i in range(int(np.ceil(len(correct_or_not) / float(window_cycles)))): + print(correct_or_not[i*window_cycles:(i+1)*window_cycles], np.average(correct_or_not[i*window_cycles:(i+1)*window_cycles])) +print("average error = ", np.average(cycle_error)) +print("weighted average", np.average(cycle_error, weights=[i for i in range(num_repeats)])) +print("minimum error = ", np.min(cycle_error)) +print("minimum iteration =", cycle_error.index(np.min(cycle_error)), "- with time stamp =", cycle_error.index(np.min(cycle_error)) * 1024) +print(experiment_label) + +# plt.figure() +# Figure( +# Panel(neuron_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(neuron_res.segments[0].spiketrains, ylabel='neuron_spikes', xlabel='neuron_spikes', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), +# +# Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), +# +# title="neuron data for {}".format(experiment_label) +# ) +# plt.show() + +plot_start = runtime-(cycle_time*15) +plot_end = runtime +plt.figure() +Figure( + Panel(neuron_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(neuron_res.segments[0].spiketrains, ylabel='neuron_spikes', xlabel='neuron_spikes', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(plot_start, plot_end)), + + title="neuron data for {}".format(experiment_label) +) +plt.show() + +print("plotted neuron data") + +fig, axs = plt.subplots(2, 1) +axs[0].set_title(experiment_label) +axs[0].scatter([i for i in range(len(correct_or_not))], correct_or_not) +axs[1].scatter([i for i in range(len(cycle_error))], cycle_error) +axs[1].plot([0, len(cycle_error)], [75, 75], 'r') +plt.show() + +print("plotted curves") + +pynn.end() +print("job done") + +''' +draw_graph_from_list(new_connections_in, new_connections_rec, new_connections_out) + +base_string = 'connection_lists/good 1 cue 20n recF' +np.save(base_string+' in.npy', new_connections_in) +np.save(base_string+' out.npy', new_connections_out) +np.save(base_string+' rec.npy', new_connections_rec) + +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() + +def moving_average(a, n=3) : + ret = np.cumsum(a, dtype=float) + ret[n:] = ret[n:] - ret[:-n] + return ret[n - 1:] / n + +v_mem = [] +sine_wave = [] +for timestep in readout_res.segments[0].filter(name='v')[0]: + v_mem.append(timestep[0]) + sine_wave.append(timestep[1]) + +ave_mem = moving_average(v_mem, 20) +ave_sine = moving_average(sine_wave, 20) + +plt.figure() +plt.plot([i for i in range(len(ave_mem))], cum_mem) +plt.plot([i for i in range(len(ave_sine))], cum_sine) +plt.title(experiment_label) +plt.show() + +plt.figure() +plt.plot([i for i in range(len(soft_max[0]))], soft_max[0]) +plt.plot([i for i in range(len(soft_max[1]))], soft_max[1]) +plt.title(experiment_label) +plt.show() +''' \ No newline at end of file diff --git a/eprop_testing/incremental_learning.py b/eprop_testing/incremental_learning.py new file mode 100644 index 0000000..b55e750 --- /dev/null +++ b/eprop_testing/incremental_learning.py @@ -0,0 +1,60 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import numpy as np +from plot_graph import draw_graph_from_list, plot_learning_curve +from create_pops_for_incremental_learning import first_create_pops, next_create_pops, run_until +from incremental_config import * + +np.random.seed(272727) + +# create populations for the first time +experiment_label, runtime, pynn, in_proj, recurrent_proj, out_proj, input_pop, neuron, readout_pop, \ +from_list_in, from_list_rec, from_list_out = first_create_pops() + +correct_or_not_full_list = [] +cycle_error_full_list = [] +transiterations = [] + +for interative_cue in range(1, 9, 2): + # run until learning threshold criteria met + new_connections_in, new_connections_rec, new_connections_out, \ + correct_or_not_full_list, cycle_error_full_list, final_iteration = \ + run_until(experiment_label, runtime, pynn, in_proj, recurrent_proj, out_proj, + input_pop, neuron, readout_pop, + from_list_in, from_list_rec, from_list_out, + correct_or_not_full_list, cycle_error_full_list, + threshold=learning_threshold, + cue_break=transiterations) + + if not final_iteration: + print("Ending simulation") + break + transiterations.append(final_iteration) + + # update cues in params + cycle_time = ((interative_cue+2) * 150) + 1000 + 150 + window_size = cycle_time * window_cycles + readout_neuron_params["number_of_cues"] += 2 + neuron_params["number_of_cues"] += 2 + neuron_params["window_size"] = window_size + + # create pops for next run + experiment_label, runtime, pynn, in_proj, recurrent_proj, out_proj, input_pop, neuron, readout_pop, \ + from_list_in, from_list_rec, from_list_out = \ + next_create_pops(new_connections_in, new_connections_rec, new_connections_out) + +plot_learning_curve(correct_or_not_full_list, cycle_error_full_list, './big_with_labels/', + 'full', save_flag=True) + +print("job done") \ No newline at end of file diff --git a/eprop_testing/input_buffer_overflow_test.py b/eprop_testing/input_buffer_overflow_test.py new file mode 100644 index 0000000..b2aa547 --- /dev/null +++ b/eprop_testing/input_buffer_overflow_test.py @@ -0,0 +1,348 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from frozen_poisson import build_input_spike_train, frozen_poisson_variable_hz +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel +from spynnaker.pyNN.spynnaker_external_device_plugin_manager import SpynnakerExternalDevicePluginManager + +def weight_distribution(pop_size): + base_weight = np.random.randn() / np.sqrt(pop_size) #+ 0.5 + # base_weight = 0 + return base_weight + +def probability_connector(pre_pop_size, post_pop_size, prob, offset=0): + connections = [] + max_syn_per_neuron = 0 + for j in range(post_pop_size): + neuron_syn_count = 0 + delay_count = offset + for i in range(pre_pop_size): + if np.random.random() < prob: + neuron_syn_count += 1 + conn = [i, j, weight_distribution(pre_pop_size), delay_count] + delay_count += 1 + connections.append(conn) + if neuron_syn_count > max_syn_per_neuron: + max_syn_per_neuron = neuron_syn_count + return connections, max_syn_per_neuron + +def range_connector(pre_min, pre_max, post_min, post_max, weight=1.5, delay_offset=0): + connections = [] + for j in range(post_min, post_max): + delay = delay_offset + for i in range(pre_min, pre_max): + connections.append([i, j, weight, i+delay_offset]) + delay += 1 + return connections + +np.random.seed(272727) + +number_of_cues = 1 +cycle_time = (number_of_cues*150)+1000+150 +num_repeats = 4 +pynn.setup(1.0) + +target_data = [] +for i in range(1024): + target_data.append(#1) + 0 + 2 * np.sin(2 * i * 2* np.pi / 1024) \ + + 2 * np.sin((4 * i * 2* np.pi / 1024)) + ) + + +reg_rate = 0.000 +p_connect_in = 1. +p_connect_rec = 1. +p_connect_out = 1. +recurrent_connections = False +synapse_eta = 0.5 +tau_a = 5500#[cycle_time - 150 + (np.random.randn() * 200) for i in range(100)] +input_split = 100 +window_size = 1300*10 + +in_weight = 2 +prompt_weight = 2 +rec_weight = -1.9 +out_weight = 1 + + +pynn.setup(timestep=1) + +pynn.set_number_of_neurons_per_core(pynn.extra_models.EPropAdaptive, 6) + +input_size = 24 +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "poisson_pop_size": input_size // 4, + "rate_on": 40, + "rate_off": 0, + # "tau_m": tau_a, + "w_fb": [1, -1, 0], + "eta": synapse_eta / 5., + "window_size": window_size, + } +rates = [] +for i in range(input_size): + if i >= (3*input_size) // 4: + rates.append(10) + else: + rates.append(0) +input_pop = pynn.Population(input_size, + pynn.SpikeSourcePoisson(rate=rates), + # {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size)}, + # {'spike_times': frozen_poisson_variable_hz(num_repeats, cycle_time, input_split, input_split, input_size)}, + label='input_pop') + +neuron_pop_size = 10 +ratio_of_LIF = 0.5 +beta = [] +for i in range(neuron_pop_size): + if i < neuron_pop_size//2: + # if i % 2 == 0: + beta.append(25.8) + else: + beta.append(25.8) +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0, + # "w_fb": [np.random.random() for i in range(neuron_pop_size)], # best it seems + # "w_fb": [(np.random.random() * 2) - 1. for i in range(neuron_pop_size)], + "w_fb": [np.random.random() - np.random.random() for i in range(neuron_pop_size)], ## for both feedback weights + # "B": 0.0, + "beta": beta, + "target_rate": 10, + "tau_a": tau_a, + "eta": 0.0,#synapse_eta / 20., + "window_size": window_size, + } +neuron = pynn.Population(neuron_pop_size, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +# Output population +readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.LeftRightReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + +poisson_control_edge = SpynnakerExternalDevicePluginManager.add_edge( + readout_pop._vertex, input_pop._vertex, "CONTROL") +# pynn.external_devices.activate_live_output_to( +# readout_pop, input_pop, "CONTROL") +input_pop._vertex.set_live_poisson_control_edge(poisson_control_edge) +# pynn.external_devices.add_poisson_live_rate_control(input_pop) + +start_w = [weight_distribution(neuron_pop_size*input_size) for i in range(input_size)] +eprop_learning_neuron = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=reg_rate)) + +# from_list_in, max_syn_per_input = probability_connector(input_size, neuron_pop_size, p_connect_in) +ps = readout_neuron_params["poisson_pop_size"] +from_list_in = range_connector(0, ps, 0, neuron_pop_size//2, weight=in_weight) +from_list_in += range_connector(ps, ps*2, neuron_pop_size//2, neuron_pop_size, weight=in_weight) +from_list_in += range_connector(ps*2, ps*3, 0, neuron_pop_size, delay_offset=0, weight=prompt_weight) +in_proj = pynn.Projection(input_pop, + neuron, + pynn.FromListConnector(from_list_in), + # pynn.AllToAllConnector(), + synapse_type=eprop_learning_neuron, + label='input_connections', + receptor_type='input_connections') + +eprop_learning_output = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=0.0)) + +overflow_pop_size = 20 +overflow_spike_times = [] +inhibitory_spike_times = [] +dt = 100 +for i in range(overflow_pop_size): + overflow_spike_times.append([(overflow_pop_size - i) * dt for i in range(i+1)]) + inhibitory_spike_times.append([(overflow_pop_size*dt) + (overflow_pop_size - i) * dt for i in range(i+1)]) + +# from_list_out = [[i, 0, weight_distribution(input_size), i] for i in range(input_size)] +# from_list_out, max_syn_per_output = probability_connector(neuron_pop_size, 2, p_connect_out) +# from_list_out = range_connector(0, neuron_pop_size/2, 1, 2, weight=out_weight) +# from_list_out += range_connector(neuron_pop_size/2, neuron_pop_size, 0, 1, weight=out_weight) +from_list_out = range_connector(0, overflow_pop_size, 0, 2, weight=out_weight) +from_list_inhib = range_connector(0, overflow_pop_size, 0, 2, weight=-out_weight) +overflow_neurons = pynn.Population(overflow_pop_size, + pynn.SpikeSourceArray(spike_times=overflow_spike_times), + # {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size)}, + # {'spike_times': frozen_poisson_variable_hz(num_repeats, cycle_time, input_split, input_split, input_size)}, + label='overflow_pop') +inhib_neurons = pynn.Population(overflow_pop_size, + pynn.SpikeSourceArray(spike_times=inhibitory_spike_times), + # {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size)}, + # {'spike_times': frozen_poisson_variable_hz(num_repeats, cycle_time, input_split, input_split, input_size)}, + label='overflow_pop') + +out_proj = pynn.Projection(overflow_neurons, + readout_pop, + # pynn.OneToOneConnector(), + pynn.FromListConnector(from_list_out), + synapse_type=eprop_learning_output, + label='input_connections', + receptor_type='input_connections') + +inh_proj = pynn.Projection(inhib_neurons, + readout_pop, + # pynn.OneToOneConnector(), + pynn.FromListConnector(from_list_inhib), + synapse_type=eprop_learning_output, + label='input_connections', + receptor_type='input_connections') + +learning_proj = pynn.Projection(readout_pop, + neuron, + pynn.AllToAllConnector(), + pynn.StaticSynapse(weight=0.5, delay=0), + receptor_type='learning_signal') + +input_pop.record('spikes') +neuron.record('spikes') +neuron.record(['gsyn_exc', 'v', 'gsyn_inh'])#, indexes=[i for i in range(45, 55)]) +readout_pop.record('all') + +runtime = cycle_time * num_repeats + +experiment_label = "eta:{}/{} - size:{}/{} - reg_rate:{} - p_conn:{}/{}/{} - rec:{} - cycle:{}/{}/{} regoff delai".format( + readout_neuron_params["eta"], neuron_params["eta"], input_size, neuron_pop_size, reg_rate, p_connect_in, p_connect_rec, p_connect_out, recurrent_connections, cycle_time, window_size, runtime) +print("\n", experiment_label, "\n") + +pynn.run(runtime) +in_spikes = input_pop.get_data('spikes') +neuron_res = neuron.get_data('all') +readout_res = readout_pop.get_data('all') + +total_error = 0.0 +cycle_error = [0.0 for i in range(num_repeats)] +soft_max = [[], []] +cross_entropy = [] # how do I extract the answer easily? final gsyn exc value? +all_cross = [[], []] +from_soft = [[], []] +for cycle in range(num_repeats): + ticks_for_mean = 0 + mean_0 = 0. + mean_1 = 0. + # mean_0_all = 0. + # mean_1_all = 0. + for time_index in range(cycle_time): + instantaneous_error = np.abs(float( + readout_res.segments[0].filter(name='gsyn_inh')[0][time_index+(cycle*cycle_time)][0])) + cycle_error[cycle] += instantaneous_error + total_error += instantaneous_error + +new_connections_in = []#in_proj.get('weight', 'delay').connections[0]#[] +for partition in in_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_in.append(conn) +new_connections_in.sort(key=lambda x:x[1]) +from_list_in.sort(key=lambda x:x[1]) +connection_diff_in = [] +for i in range(len(from_list_in)): + connection_diff_in.append(new_connections_in[i][2] - from_list_in[i][2]) +print("Input connections\noriginal\n", np.array(from_list_in)) +print("new\n", np.array(new_connections_in)) +print("diff\n", np.array(connection_diff_in)) + +new_connections_out = []#out_proj.get('weight', 'delay').connections[0]#[] +for partition in out_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_out.append(conn) +new_connections_out.sort(key=lambda x:x[1]) +from_list_out.sort(key=lambda x:x[1]) +connection_diff_out = [] +for i in range(len(from_list_out)): + connection_diff_out.append(new_connections_out[i][2] - from_list_out[i][2]) +print("Output connections\noriginal\n", np.array(from_list_out)) +print("new\n", np.array(new_connections_out)) +print("diff\n", np.array(connection_diff_out)) + +print(experiment_label) +print("cycle_error =", cycle_error) +print("total error =", total_error) +print("average error = ", np.average(cycle_error)) +print("weighted average", np.average(cycle_error, weights=[i for i in range(num_repeats)])) +print("minimum error = ", np.min(cycle_error)) +print("minimum iteration =", cycle_error.index(np.min(cycle_error)), "- with time stamp =", cycle_error.index(np.min(cycle_error)) * 1024) + +plt.figure() +Figure( + Panel(neuron_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].spiketrains, ylabel='neuron_spikes', xlabel='neuron_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), + + title="neuron data for {}".format(experiment_label) +) +plt.show() + +pynn.end() +print("job done") + +''' +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() + +def moving_average(a, n=3) : + ret = np.cumsum(a, dtype=float) + ret[n:] = ret[n:] - ret[:-n] + return ret[n - 1:] / n + +v_mem = [] +sine_wave = [] +for timestep in readout_res.segments[0].filter(name='v')[0]: + v_mem.append(timestep[0]) + sine_wave.append(timestep[1]) + +ave_mem = moving_average(v_mem, 20) +ave_sine = moving_average(sine_wave, 20) + +plt.figure() +plt.plot([i for i in range(len(ave_mem))], cum_mem) +plt.plot([i for i in range(len(ave_sine))], cum_sine) +plt.title(experiment_label) +plt.show() + +plt.figure() +plt.plot([i for i in range(len(soft_max[0]))], soft_max[0]) +plt.plot([i for i in range(len(soft_max[1]))], soft_max[1]) +plt.title(experiment_label) +plt.show() +''' \ No newline at end of file diff --git a/eprop_testing/learn_sinusoid_from_frozen_poisson.py b/eprop_testing/learn_sinusoid_from_frozen_poisson.py new file mode 100644 index 0000000..0e9025c --- /dev/null +++ b/eprop_testing/learn_sinusoid_from_frozen_poisson.py @@ -0,0 +1,338 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from frozen_poisson import build_input_spike_train, frozen_poisson_variable_hz +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + +def weight_distribution(pop_size): + base_weight = np.random.randn() / np.sqrt(pop_size) + # base_weight = 0 + return base_weight + +def probability_connector(pre_pop_size, post_pop_size, prob, offset=0, base_weight=0.0): + connections = [] + max_syn_per_neuron = 0 + for j in range(post_pop_size): + neuron_syn_count = 0 + delay_count = offset + for i in range(pre_pop_size): + if np.random.random() < prob: + neuron_syn_count += 1 + conn = [i, j, weight_distribution(pre_pop_size)+base_weight, delay_count] + delay_count += 1 + connections.append(conn) + if neuron_syn_count > max_syn_per_neuron: + max_syn_per_neuron = neuron_syn_count + return connections, max_syn_per_neuron + +np.random.seed(272727) + +cycle_time = 1024 +num_repeats = 100 # 100 +pynn.setup(1.0) + +target_data = [] +for i in range(1024): + target_data.append(#1) + 0 + 2 * np.sin(2 * i * 2* np.pi / 1024) \ + + 2 * np.sin((4 * i * 2* np.pi / 1024)) + ) + + +reg_rate = 0.00001 +p_connect_in = 1. +p_connect_rec = 1. +p_connect_out = 1. +recurrent_connections = False +synapse_eta = 0.001 +input_split = 20 +input_speed_up = 1. +base_weight = 0.55 + +pynn.setup(timestep=1) + +pynn.set_number_of_neurons_per_core(pynn.extra_models.EPropAdaptive, 6) + +input_size = 100 +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "target_data": target_data, + "eta": synapse_eta + 0.0, + "update_ready": cycle_time + } +input_pop = pynn.Population(input_size, + pynn.SpikeSourceArray, + # {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size)}, + {'spike_times': frozen_poisson_variable_hz(num_repeats, cycle_time, input_split, input_speed_up, input_size, use_old=False)}, + label='input_pop') + +neuron_pop_size = 100 +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0, + "w_fb": [np.random.random() for i in range(neuron_pop_size)], # best it seems + # "w_fb": [(np.random.random() * 2) - 1. for i in range(neuron_pop_size)], + # "B": 0.0, + "beta": 0.0, + "target_rate": 10,#[10 + np.random.randn() for i in range(neuron_pop_size)], + "eta": synapse_eta, #/ 4. + "window_size": 1 + } +if neuron_pop_size: + neuron = pynn.Population(neuron_pop_size, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +# Output population +readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.SinusoidReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + +eprop_learning_output = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2, w_max=2, reg_rate=0.0)) + +if neuron_pop_size: + start_w = [weight_distribution(neuron_pop_size*input_size) for i in range(input_size)] + eprop_learning_neuron = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=reg_rate)) + + from_list_in, max_syn_per_input = probability_connector(input_size, neuron_pop_size, p_connect_in, base_weight=base_weight) + if max_syn_per_input > 100: + Exception + else: + print("max number of synapses per neuron:", max_syn_per_input) + in_proj = pynn.Projection(input_pop, + neuron, + pynn.FromListConnector(from_list_in), + synapse_type=eprop_learning_neuron, + label='input_connections', + receptor_type='input_connections') + + # from_list_out = [[i, 0, weight_distribution(input_size), i] for i in range(input_size)] + from_list_out, max_syn_per_output = probability_connector(neuron_pop_size, 1, p_connect_out) + if max_syn_per_output > 100: + Exception + else: + print("max number of synapses per readout:", max_syn_per_output) + out_proj = pynn.Projection(neuron, + readout_pop, + # pynn.OneToOneConnector(), + pynn.FromListConnector(from_list_out), + synapse_type=eprop_learning_output, + label='input_connections', + receptor_type='input_connections') + + learning_proj = pynn.Projection(readout_pop, + neuron, + # pynn.OneToOneConnector(), + # pynn.StaticSynapse(weight=[0.5], delay=[0]), + pynn.AllToAllConnector(), + pynn.StaticSynapse(weight=0.5, delay=0), + receptor_type='learning_signal') +else: + from_list_out, max_syn_per_output = probability_connector(input_size, 1, p_connect_out, base_weight=base_weight) + if max_syn_per_output > 100: + Exception + else: + print("max number of synapses per readout:", max_syn_per_output) + out_proj = pynn.Projection(input_pop, + readout_pop, + # pynn.OneToOneConnector(), + pynn.FromListConnector(from_list_out), + synapse_type=eprop_learning_output, + label='input_connections', + receptor_type='input_connections') + +if recurrent_connections: + eprop_learning_recurrent = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2, w_max=2, reg_rate=reg_rate)) + + from_list_rec, max_syn_per_rec = probability_connector(neuron_pop_size, neuron_pop_size, p_connect_rec, offset=0) + if max_syn_per_rec > 150: + Exception + else: + print("max number of synapses per neuron:", max_syn_per_rec) + recurrent_proj = pynn.Projection(neuron, + neuron, + pynn.FromListConnector(from_list_rec), + synapse_type=eprop_learning_recurrent, + label='recurrent_connections', + receptor_type='recurrent_connections') + +input_pop.record('spikes') +if neuron_pop_size: + # neuron.record('all') + neuron.record('spikes') + # neuron.record(['gsyn_exc', 'v', 'gsyn_inh'], indexes=[0, 1, 9, 17, 25, 33]) + neuron[0, 1, 9, 17, 25, 33].record(['gsyn_exc', 'v', 'gsyn_inh']) +readout_pop.record('all') + +experiment_label = "eta:{}/{} - size:{}/{} - reg_rate:{} - p_conn:{}/{}/{} - rec:{} - 10*{}hz all2all".format( + readout_neuron_params["eta"], neuron_params["eta"], input_size, neuron_pop_size, reg_rate, p_connect_in, p_connect_rec, p_connect_out, recurrent_connections, input_split) +print("\n", experiment_label, "\n") + +runtime = cycle_time * num_repeats +pynn.run(runtime) +in_spikes = input_pop.get_data('spikes') +if neuron_pop_size: + neuron_res = neuron.get_data('all') +readout_res = readout_pop.get_data('all') + +total_error = 0.0 +cycle_error = [0.0 for i in range(num_repeats)] +for cycle in range(num_repeats): + for time_index in range(1024): + instantaneous_error = np.abs(float( + readout_res.segments[0].filter(name='v')[0][time_index+(cycle*1024)][0]) - target_data[time_index]) + cycle_error[cycle] += instantaneous_error + total_error += instantaneous_error + +if neuron_pop_size: + new_connections_in = []#in_proj.get('weight', 'delay').connections[0]#[] + for partition in in_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_in.append(conn) + new_connections_in.sort(key=lambda x:x[1]) + from_list_in.sort(key=lambda x:x[1]) + connection_diff_in = [] + for i in range(len(from_list_in)): + connection_diff_in.append(new_connections_in[i][2] - from_list_in[i][2]) + print("Input connections\noriginal\n", np.array(from_list_in)) + print("new\n", np.array(new_connections_in)) + print("diff\n", np.array(connection_diff_in)) + +new_connections_out = []#out_proj.get('weight', 'delay').connections[0]#[] +for partition in out_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_out.append(conn) +new_connections_out.sort(key=lambda x:x[1]) +from_list_out.sort(key=lambda x:x[1]) +connection_diff_out = [] +for i in range(len(from_list_out)): + connection_diff_out.append(new_connections_out[i][2] - from_list_out[i][2]) +print("Output connections\noriginal\n", np.array(from_list_out)) +print("new\n", np.array(new_connections_out)) +print("diff\n", np.array(connection_diff_out)) + +if recurrent_connections: + new_connections_rec = []#out_proj.get('weight', 'delay').connections[0]#[] + for partition in recurrent_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_rec.append(conn) + new_connections_rec.sort(key=lambda x:x[1]) + from_list_rec.sort(key=lambda x:x[1]) + connection_diff_rec = [] + for i in range(len(from_list_out)): + connection_diff_rec.append(new_connections_rec[i][2] - from_list_rec[i][2]) + print("Recurrent connections\noriginal\n", np.array(from_list_out)) + print("new\n", np.array(new_connections_out)) + print("diff\n", np.array(connection_diff_out)) + +print(experiment_label) +print("cycle_error =", cycle_error) +print("total error =", total_error) +print("average error = ", np.average(cycle_error)) +print("weighted average", np.average(cycle_error, weights=[i for i in range(num_repeats)])) +print("minimum error = ", np.min(cycle_error)) +print("minimum iteration = ", cycle_error.index(np.min(cycle_error)), "- with time stamp =", cycle_error.index(np.min(cycle_error)) * 1024) + + +if neuron_pop_size: + plt.figure() + Figure( + Panel(neuron_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].spiketrains, ylabel='neuron_spikes', xlabel='neuron_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(runtime-cycle_time*3, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), + + title="neuron data for {}".format(experiment_label) + ) + plt.show() +else: + plt.figure() + Figure( + Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, + xlim=(runtime-cycle_time*3, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, + xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, + xlim=(0, runtime)), + + title="neuron data for {}".format(experiment_label) + ) + plt.show() + +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() + +pynn.end() +print("job done") + +''' +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() + +def moving_average(a, n=3) : + ret = np.cumsum(a, dtype=float) + ret[n:] = ret[n:] - ret[:-n] + return ret[n - 1:] / n + +v_mem = [] +sine_wave = [] +for timestep in readout_res.segments[0].filter(name='v')[0]: + v_mem.append(timestep[0]) + sine_wave.append(timestep[1]) + +ave_mem = moving_average(v_mem, 20) +ave_sine = moving_average(sine_wave, 20) + +plt.figure() +plt.plot([i for i in range(len(ave_mem))], cum_mem) +plt.plot([i for i in range(len(ave_sine))], cum_sine) +plt.title(experiment_label) +plt.show() +''' \ No newline at end of file diff --git a/eprop_testing/learn_sinusoid_only_readout.py b/eprop_testing/learn_sinusoid_only_readout.py new file mode 100644 index 0000000..6b315ac --- /dev/null +++ b/eprop_testing/learn_sinusoid_only_readout.py @@ -0,0 +1,172 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from frozen_poisson import build_input_spike_train, frozen_poisson_variable_hz +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + +def weight_distribution(pop_size): + base_weight = np.random.randn() / np.sqrt(pop_size) + # base_weight = 0 + return base_weight + +def probability_connector(pre_pop_size, post_pop_size, prob, offset=0): + connections = [] + max_syn_per_neuron = 0 + for j in range(post_pop_size): + neuron_syn_count = 0 + delay_count = offset + for i in range(pre_pop_size): + if np.random.random() < prob: + neuron_syn_count += 1 + conn = [i, j, weight_distribution(pre_pop_size), delay_count] + delay_count += 1 + connections.append(conn) + if neuron_syn_count > max_syn_per_neuron: + max_syn_per_neuron = neuron_syn_count + return connections, max_syn_per_neuron + +np.random.seed(272727) + +cycle_time = 1024 +num_repeats =250 +pynn.setup(1.0) + +target_data = [] +for i in range(1024): + target_data.append(#1) + 0 + 2 * np.sin(2 * i * 2* np.pi / 1024) \ + + 2 * np.sin((4 * i * 2* np.pi / 1024)) + ) + +synapse_eta = 40 +input_split = 30 +input_speed_up = 1. + +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "target_data": target_data, + "eta": synapse_eta + } + +pynn.setup(timestep=1) + +# pynn.set_number_of_neurons_per_core(pynn.extra_models.EPropAdaptive, 6) + +input_size = 100 +input_pop = pynn.Population(input_size, + pynn.SpikeSourceArray, + # {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size)}, + {'spike_times': frozen_poisson_variable_hz(num_repeats, cycle_time, input_split, input_speed_up, input_size)}, + label='input_pop') + +# Output population +readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.SinusoidReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + +reg_rate = 0.00 +eprop_learning_neuron = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=reg_rate)) + +from_list_in, max_syn_per_neuron = probability_connector(input_size, 1, 1.) +if max_syn_per_neuron > 250: + Exception +else: + print("max number fo synapses per neuron:", max_syn_per_neuron) +in_proj = pynn.Projection(input_pop, + readout_pop, + pynn.FromListConnector(from_list_in), + # pynn.AllToAllConnector(), + synapse_type=eprop_learning_neuron, + label='input_connections', + receptor_type='input_connections') + +input_pop.record('spikes') +readout_pop.record('all') + +experiment_label = "eta:{} - in size:{} - reg_rate: {} - 10*{}hz".format(readout_neuron_params["eta"], input_size, reg_rate, input_split) +print("\n", experiment_label, "\n") + +runtime = cycle_time * num_repeats +pynn.run(runtime) +in_spikes = input_pop.get_data('spikes') +readout_res = readout_pop.get_data('all') + +total_error = 0.0 +cycle_error = [0.0 for i in range(num_repeats)] +for cycle in range(num_repeats): + for time_index in range(1024): + instantaneous_error = np.abs(float( + readout_res.segments[0].filter(name='v')[0][time_index+(cycle*1024)][0]) - target_data[time_index]) + cycle_error[cycle] += instantaneous_error + total_error += instantaneous_error + +new_connections_in = []#in_proj.get('weight', 'delay').connections[0]#[] +for partition in in_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_in.append(conn) +new_connections_in.sort(key=lambda x:x[1]) +from_list_in.sort(key=lambda x:x[1]) +connection_diff_in = [] +for i in range(len(from_list_in)): + connection_diff_in.append(new_connections_in[i][2] - from_list_in[i][2]) +print("Input connections\noriginal\n", np.array(from_list_in)) +print("new\n", np.array(new_connections_in)) +print("diff\n", np.array(connection_diff_in)) +print(experiment_label) +print("cycle_error =", cycle_error) +print("total error =", total_error) +print("average error = ", np.average(cycle_error)) +print("weighted average", np.average(cycle_error, weights=[i for i in range(num_repeats)])) +print("minimum error = ", np.min(cycle_error)) +print("minimum iteration = ", cycle_error.index(np.min(cycle_error))) + +plt.figure() +Figure( + + Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), + + title="neuron data for {}".format(experiment_label) +) +plt.show() + +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() + +pynn.end() +print("job done") + +''' +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() +''' \ No newline at end of file diff --git a/eprop_testing/learn_sinusoid_only_readout_single_cycle_input.py b/eprop_testing/learn_sinusoid_only_readout_single_cycle_input.py new file mode 100644 index 0000000..593a011 --- /dev/null +++ b/eprop_testing/learn_sinusoid_only_readout_single_cycle_input.py @@ -0,0 +1,173 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from frozen_poisson import build_input_spike_train, frozen_poisson_variable_hz +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + +def weight_distribution(pop_size): + base_weight = np.random.randn() / np.sqrt(pop_size) + # base_weight = 0 + return base_weight + +def probability_connector(pre_pop_size, post_pop_size, prob, offset=0): + connections = [] + max_syn_per_neuron = 0 + for j in range(post_pop_size): + neuron_syn_count = 0 + delay_count = offset + for i in range(pre_pop_size): + if np.random.random() < prob: + neuron_syn_count += 1 + conn = [i, j, weight_distribution(pre_pop_size), delay_count] + delay_count += 1 + connections.append(conn) + if neuron_syn_count > max_syn_per_neuron: + max_syn_per_neuron = neuron_syn_count + return connections, max_syn_per_neuron + +np.random.seed(272727) + +cycle_time = 1024 +num_repeats = 400 # 200 +pynn.setup(1.0) + +target_data = [] +for i in range(1024): + target_data.append(#1) + 0 + 2 * np.sin(2 * i * 2* np.pi / 1024) \ + + 2 * np.sin((4 * i * 2* np.pi / 1024)) + ) + +synapse_eta = 20 + +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "tau_m": 100, + "target_data": target_data, + "eta": synapse_eta + } + +pynn.setup(timestep=1) + +input_size = 100 +input_pop = pynn.Population(input_size, + pynn.SpikeSourceArray, + {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size, use_old=True)}, + label='input_pop') + +# Output population +readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.SinusoidReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + +reg_rate = 0.00 +eprop_learning_neuron = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=reg_rate)) + +from_list_in, max_syn_per_neuron = probability_connector(input_size, 1, 1.) +if max_syn_per_neuron > 250: + Exception +else: + print("max number fo synapses per neuron:", max_syn_per_neuron) +in_proj = pynn.Projection(input_pop, + readout_pop, + pynn.FromListConnector(from_list_in), + # pynn.AllToAllConnector(), + synapse_type=eprop_learning_neuron, + label='input_connections', + receptor_type='input_connections') + +input_pop.record('spikes') +readout_pop.record('all') + +experiment_label = "eta:{} - in size:{} - reg_rate: {}".format(readout_neuron_params["eta"], input_size, reg_rate) +print("\n", experiment_label, "\n") + +runtime = cycle_time * num_repeats + +for i in range(num_repeats): + print('\nrepeat: {}\n'.format(i)) + pynn.run(cycle_time) + +in_spikes = input_pop.get_data('spikes') +readout_res = readout_pop.get_data('all') + +total_error = 0.0 +cycle_error = [0.0 for i in range(num_repeats)] +for cycle in range(num_repeats): + for time_index in range(1024): + instantaneous_error = np.abs(float( + readout_res.segments[0].filter(name='v')[0][time_index+(cycle*1024)][0]) - target_data[time_index]) + cycle_error[cycle] += instantaneous_error + total_error += instantaneous_error + +new_connections_in = []#in_proj.get('weight', 'delay').connections[0]#[] +for partition in in_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_in.append(conn) +new_connections_in.sort(key=lambda x:x[1]) +from_list_in.sort(key=lambda x:x[1]) +connection_diff_in = [] +for i in range(len(from_list_in)): + connection_diff_in.append(new_connections_in[i][2] - from_list_in[i][2]) + +print("Input connections\noriginal\n", np.array(from_list_in)) +print("new\n", np.array(new_connections_in)) +print("diff\n", np.array(connection_diff_in)) +print(experiment_label) +print("cycle_error =", cycle_error) +print("total error =", total_error) +print("average error = ", np.average(cycle_error)) +print("weighted average", np.average(cycle_error, weights=[i for i in range(num_repeats)])) +print("minimum error = ", np.min(cycle_error)) +print("minimum iteration = ", cycle_error.index(np.min(cycle_error))) + +plt.figure() +Figure( + + Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), + + title="neuron data for {}".format(experiment_label) +) +plt.show() + +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() + +pynn.end() +print("job done") + +''' +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() +''' \ No newline at end of file diff --git a/eprop_testing/one_neuron.py b/eprop_testing/one_neuron.py new file mode 100644 index 0000000..93494f2 --- /dev/null +++ b/eprop_testing/one_neuron.py @@ -0,0 +1,69 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + + +runtime = 100 +pynn.setup(1.0) + +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0 + } + + + +spike_source = pynn.Population(2, + pynn.SpikeSourceArray, + {'spike_times': [10]}, + label='Spike Source') + +neuron = pynn.Population(2, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +proj = pynn.Projection(spike_source, neuron, + pynn.OneToOneConnector(), + pynn.StaticSynapse(weight=[-0.5, 2] , delay=[1, 5]), + receptor_type='input_connections') + + +neuron.record('all') + +pynn.run(runtime) + +res = neuron.get_data('all') + +Figure( + Panel(res.segments[0].filter(name='v')[0], + ylabel="Membrane potential (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_exc')[0], + ylabel="gsyn excitatory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_inh')[0], + xlabel="Time (ms)", xticks=True, + ylabel="gsyn inhibitory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + title="Single eprop neuron" +) + +plt.show() + +pynn.end() \ No newline at end of file diff --git a/eprop_testing/plot_graph.py b/eprop_testing/plot_graph.py new file mode 100644 index 0000000..3dce00b --- /dev/null +++ b/eprop_testing/plot_graph.py @@ -0,0 +1,314 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import matplotlib.pyplot as plt +import networkx as nx +import numpy as np +import imageio +import os + +def load_connections(npy_label, pop_size, rec=True): + in_conn = [list(ele) for ele in np.load(npy_label+' in.npy').tolist()] + if rec: + rec_conn = [list(ele) for ele in np.load(npy_label+' rec.npy').tolist()] + out_conn = [list(ele) for ele in np.load(npy_label+' out.npy').tolist()] + for ndx in range(len(in_conn)): + if in_conn[ndx][3] == 16 and in_conn[ndx][0] == 0: + in_conn[ndx][3] = 0 + if rec: + for ndx in range(len(rec_conn)): + if rec_conn[ndx][3] == 16 and rec_conn[ndx][0] == 0: + rec_conn[ndx][3] = 0 + for ndx in range(len(out_conn)): + if out_conn[ndx][3] == 16 and out_conn[ndx][0] == 0: + out_conn[ndx][3] = 0 + checking_delays = [[] for i in range(pop_size)] + list_to_check = in_conn + if rec: + list_to_check = in_conn+rec_conn + for [pre, post, weight, delay] in list_to_check: + if delay not in checking_delays[post]: + checking_delays.append(delay) + else: + print("delays are overlapped") + Exception + if not rec: + rec_conn = [] + return in_conn, rec_conn, out_conn + +def add_edges(conn_list, G, pre, post): + for conn in conn_list: + G.add_edge(pre+'{}'.format(conn[0]), post+'{}'.format(conn[1]), weight=conn[2]) + return G + +def create_lists(conn_list, pre, post): + edge_list = [] + weight_list = [] + colour_list = [] + for conn in conn_list: + # G.add_edge(pre+'{}'.format(conn[0]), post+'{}'.format(conn[1]), weight=conn[2]) + edge_list.append([pre+'{}'.format(conn[0]), post+'{}'.format(conn[1])]) + weight_list.append(conn[2]*4) + colour_list.append(conn[2]*4) + return edge_list, weight_list, colour_list + +def condense_inputs(conn_list): + new_list = [] + for [pre, post, weight, delay] in conn_list: + new_list.append([np.floor(pre / 10), post, weight, delay]) + combined_weights = [{} for i in range(4)] + for [pre, post, weight, delay] in new_list: + if '{}'.format(post) in combined_weights[int(pre)]: + combined_weights[int(pre)]['{}'.format(post)] += weight + else: + combined_weights[int(pre)]['{}'.format(post)] = weight + condensed_list = [] + for dict in combined_weights: + for post in dict: + condensed_list.append([combined_weights.index(dict), int(post), dict[post]/10.]) + return condensed_list + +def create_pos(in_size, rec_size, out_size): + pos = {} + for node in range(in_size): + pos['in{}'.format(node)] = np.array([0, (node * (100. / in_size) + (100. / (in_size * 2.)))]) + # for node in range(in_size): + # x = 0.5 - 0.5*(np.sin((np.pi*(node/float(in_size))/2) + np.pi/4.)) + # y = (node * (150. / in_size) + (150. / (in_size * 2.))) - 25 + # pos['in{}'.format(node)] = np.array([x, y]) + for node in range(rec_size): + pos['h{}'.format(node)] = np.array([1, (node * (100. / rec_size) + (100. / (rec_size * 2.)))]) + # for node in range(rec_size): + # x = 1 + 0.5*(np.sin(2.*np.pi*(node/float(rec_size)))) + # y = 50 + 50*(np.cos(2.*np.pi*(node/float(rec_size)))) + # pos['h{}'.format(node)] = np.array([x, y]) + for node in range(out_size): + pos['out{}'.format(node)] = np.array([2, (node * (100. / out_size) + (100. / (out_size * 2.)))]) + return pos + +def draw_graph_from_file(address_string, test_label, rec_flag, save_flag=False): + G = nx.Graph() + + from_list_in, from_list_rec, from_list_out = load_connections(address_string+test_label, 20, rec=rec_flag) + from_list_in = condense_inputs(from_list_in) + G = add_edges(from_list_in, G, 'in', 'h') + G = add_edges(from_list_rec, G, 'h', 'h') + G = add_edges(from_list_out, G, 'h', 'out') + all_edges = [] + all_weights = [] + all_colours = [] + edges, weights, colours = create_lists(from_list_in, 'in', 'h') + all_edges += edges + all_weights += weights + all_colours += colours + edges, weights, colours = create_lists(from_list_rec, 'h', 'h') + all_edges += edges + all_weights += weights + all_colours += colours + edges, weights, colours = create_lists(from_list_out, 'h', 'out') + all_edges += edges + all_weights += weights + all_colours += colours + + hidden_nodes = int(np.amax(from_list_in, axis=0)[1] + 1) + + pos = create_pos(4, hidden_nodes, 2) + + # nodes + nx.draw_networkx_nodes(G, pos, node_size=700) + + # edges + nx.draw_networkx_edges(G, pos, edgelist=all_edges, width=all_weights, edge_color=all_colours) + + # labels + nx.draw_networkx_labels(G, pos, font_size=20, font_family='sans-serif') + + plt.axis('off') + # plt.tight_layout() + # manager = plt.get_current_fig_manager() + # manager.resize(*manager.window.maxsize()) + # print(manager.window.maxsize()) + figure = plt.gcf() # get current figure + figure.set_size_inches(16, 9) + plt.tight_layout() + if save_flag: + plt.savefig(address_string+test_label+".png", bbox_inches='tight') # save as png + # plt.show() # display + plt.close() + +def draw_graph_from_list(from_list_in, from_list_rec, from_list_out, address_string=None, test_label=None, rec_flag=False, save_flag=False, plot_flag=False): + G = nx.Graph() + + # from_list_in, from_list_rec, from_list_out = load_connections(address_string+test_label, 20, rec=rec_flag) + from_list_in = condense_inputs(from_list_in) + G = add_edges(from_list_in, G, 'in', 'h') + G = add_edges(from_list_rec, G, 'h', 'h') + G = add_edges(from_list_out, G, 'h', 'out') + all_edges = [] + all_weights = [] + all_colours = [] + edges, weights, colours = create_lists(from_list_in, 'in', 'h') + all_edges += edges + all_weights += weights + all_colours += colours + edges, weights, colours = create_lists(from_list_rec, 'h', 'h') + all_edges += edges + all_weights += weights + all_colours += colours + edges, weights, colours = create_lists(from_list_out, 'h', 'out') + all_edges += edges + all_weights += weights + all_colours += colours + + hidden_nodes = int(np.amax(from_list_in, axis=0)[1] + 1) + + pos = create_pos(4, hidden_nodes, 2) + + # nodes + nx.draw_networkx_nodes(G, pos, node_size=700) + + # edges + nx.draw_networkx_edges(G, pos, edgelist=all_edges, width=all_weights, edge_color=all_colours) + + # labels + nx.draw_networkx_labels(G, pos, font_size=20, font_family='sans-serif') + + plt.axis('off') + # plt.tight_layout() + # manager = plt.get_current_fig_manager() + # manager.resize(*manager.window.maxsize()) + figure = plt.gcf() # get current figure + figure.set_size_inches(16, 9) + # print(manager.window.maxsize()) + plt.tight_layout() + if save_flag: + plt.savefig(address_string+test_label+" SNN.png", bbox_inches='tight') # save as png + if plot_flag: + plt.show() # display + plt.close() + +def moving_average(a, n=3): + ret = np.cumsum(a, dtype=float) + ret[n:] = ret[n:] - ret[:-n] + return ret[n - 1:] / n + +def plot_learning_curve(correct_or_not, cycle_error, address_string, test_label, save_flag=False, cue_break=[]): + # if not isinstance(data[0], list): + # data = [data] + num_repeats = len(correct_or_not) + ave_corr10 = moving_average(correct_or_not, 10) + ave_corr64 = moving_average(correct_or_not, 64) + + fig, axs = plt.subplots(4, 1) + fig.suptitle(test_label, fontsize=16) + axs[0].scatter([i for i in range(len(correct_or_not))], correct_or_not) + axs[0].set_xlim([0, num_repeats]) + for iteration_break in cue_break: + axs[0].axvline(x=iteration_break, color='b') + axs[0].set_title('Thresholded performance') + axs[1].scatter([i for i in range(len(cycle_error))], cycle_error) + axs[1].set_xlim([0, num_repeats]) + axs[1].plot([0, len(cycle_error)], [75, 75], 'r') + for iteration_break in cue_break: + axs[1].axvline(x=iteration_break, color='b') + axs[1].set_title('Iteration error') + axs[2].plot([i + 5 for i in range(len(ave_corr10))], ave_corr10) + axs[2].plot([0, num_repeats], [0.9, 0.9], 'r') + axs[2].plot([0, num_repeats], [0.95, 0.95], 'g') + for iteration_break in cue_break: + axs[2].axvline(x=iteration_break-5, color='b') + axs[2].set_xlim([0, num_repeats]) + axs[2].set_title('Averaged performance over 10 cycles') + axs[3].plot([i + 32 for i in range(len(ave_corr64))], ave_corr64) + axs[3].plot([0, num_repeats], [0.9, 0.9], 'r') + axs[3].plot([0, num_repeats], [0.95, 0.95], 'g') + axs[3].set_xlim([0, num_repeats]) + for iteration_break in cue_break: + axs[3].axvline(x=iteration_break-32, color='b') + axs[3].set_title('Averaged performance over 64 cycles') + + # plt.tight_layout() + # manager = plt.get_current_fig_manager() + # manager.resize(*manager.window.maxsize()) + # manager.full_screen_toggle() + figure = plt.gcf() # get current figure + figure.set_size_inches(16, 9) + # print(manager.window.maxsize()) + # plt.tight_layout() + plt.tight_layout(rect=[0, 0.03, 1, 0.95]) + if save_flag: + plt.savefig(address_string+test_label+" learning curve.png", bbox_inches='tight') + # plt.show() + plt.close() + + +def create_video(top_directory, base_label, string_end=' SNN.png'): + files_for_video = [[], [], [], []] + for root, dirs, files in os.walk(top_directory): + for filename in files: + if base_label in filename and string_end in filename: + if 'c-1' in filename: + iteration = filename.replace(string_end, '') + for i in range(2, 5, 1): + if iteration[-i] == ' ': + break + iteration = int(iteration[-i+1:]) + files_for_video[0].append([filename, iteration]) + elif 'c-3' in filename: + iteration = filename.replace(string_end, '') + for i in range(2, 5, 1): + if iteration[-i] == ' ': + break + iteration = int(iteration[-i+1:]) + files_for_video[1].append([filename, iteration]) + elif 'c-5' in filename: + iteration = filename.replace(string_end, '') + for i in range(2, 5, 1): + if iteration[-i] == ' ': + break + iteration = int(iteration[-i+1:]) + files_for_video[2].append([filename, iteration]) + elif 'c-7' in filename: + iteration = filename.replace(string_end, '') + for i in range(2, 5, 1): + if iteration[-i] == ' ': + break + iteration = int(iteration[-i+1:]) + files_for_video[3].append([filename, iteration]) + else: + print("incorrect file name", filename) + files_for_video[0] = sorted(files_for_video[0], key=lambda l: l[1]) + files_for_video[1] = sorted(files_for_video[1], key=lambda l: l[1]) + files_for_video[2] = sorted(files_for_video[2], key=lambda l: l[1]) + files_for_video[3] = sorted(files_for_video[3], key=lambda l: l[1]) + + print("creating video") + images = [] + for filenames in files_for_video: + for filename in filenames: + images.append(imageio.imread(top_directory+'/'+filename[0])) + imageio.mimsave(top_directory+'/videos/'+base_label+string_end+'.gif', images) + +if __name__ == '__main__': + directory = '/localhome/mbaxrap7/eprop_python3/PyNN8Examples/eprop_testing/big_with_labels' + # label = 'eta-0.1_0.05 - size-40_100 - rec-False' + # label = 'eta-0.03_0.015 - size-40_100 - rec-False' + label = 't35 eta-0.03_0.015 - size-40_100 - rec-False' + create_video(directory, label, + # string_end=' learning curve.png') + string_end=' SNN.png') + create_video(directory, label, + string_end=' learning curve.png') + # string_end=' SNN.png') + + print("done") diff --git a/eprop_testing/pop_rate_test.py b/eprop_testing/pop_rate_test.py new file mode 100644 index 0000000..f9b2654 --- /dev/null +++ b/eprop_testing/pop_rate_test.py @@ -0,0 +1,98 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import numpy as np +import matplotlib.pyplot as plt + + +def frozen_poisson_variable_hz(num_repeats, cycle_time, split, speed_up, pop_size): + pattern = np.load('1000 neurons - 10Hz - 100*1024s.npy').tolist() + + if split > pop_size: + print("Cannot split population into sizes smaller than 1 i.e. split > population size") + raise Exception + + spikes = [] + l=[] + for i in range(pop_size): + l = [] + for j in range(len(pattern[i])): + if pattern[i][j] < cycle_time:# * speed_up: + l.append(float(pattern[i][j]) / speed_up) + else: + break + spikes.append(l) + + speed_up_offset = cycle_time / split + split_spikes = [[] for i in range(pop_size)] + for neuron in range(len(spikes)): + for spike in range(len(spikes[neuron])): + split_spikes[neuron].append((spikes[neuron][spike] / split) + (speed_up_offset * int(neuron / (pop_size / split)))) + + cycled_spikes = [[] for i in range(pop_size)] + for r in range(0, num_repeats): + for p in range(pop_size): + new_iter = [i + r * cycle_time for i in split_spikes[p]] + cycled_spikes[p].extend(new_iter) + + return cycled_spikes + + +cycle_time = 2200 +repeats = 5 +pop_size = 8 +spike_times = frozen_poisson_variable_hz(repeats, cycle_time, 8, 10, pop_size) + +scatterable_spike_times = [[], []] +for neuron in range(len(spike_times)): + for spike_time in range(len(spike_times[neuron])): + scatterable_spike_times[0].append(spike_times[neuron][spike_time]) + scatterable_spike_times[1].append(neuron) + spike_times[neuron][spike_time] = int(spike_times[neuron][spike_time]) + +instantaneous_rate = 0 +rate_decay_over_time = [] +decay = np.exp(-1./1000.) +total_spikes = 0 +running_average = [] +reset_time = cycle_time +runtime = cycle_time*repeats +time_since_reset = 0 + +for time_step in range(1, runtime): + if time_step % reset_time == 0: + total_spikes = 0 + time_since_reset = 0 + time_since_reset += 1 + instantaneous_rate *= decay + for neuron in range(len(spike_times)): + for spike_time in spike_times[neuron]: + if spike_time == time_step: + total_spikes += 1 + instantaneous_rate += 1 + elif spike_time > time_step: + break + rate_decay_over_time.append(instantaneous_rate / pop_size) + running_average.append((total_spikes / (time_since_reset / 1000.)) / pop_size) + +fig, axs = plt.subplots(2, 1) +axs[0].set_title('rates calculated different ways') +axs[0].plot([i for i in range(len(rate_decay_over_time))], rate_decay_over_time, label='exponential') +axs[0].plot([i for i in range(len(running_average))], running_average, label='running average') +axs[0].legend(loc="bottom right") +axs[0].plot([0, runtime], [10, 10], 'r') +axs[1].scatter(scatterable_spike_times[0], scatterable_spike_times[1]) +axs[0].set_xlim([-100, runtime+100]) +axs[1].set_xlim([-100, runtime+100]) +plt.show() +print("done") \ No newline at end of file diff --git a/eprop_testing/readout_input_test.py b/eprop_testing/readout_input_test.py new file mode 100644 index 0000000..2886dc8 --- /dev/null +++ b/eprop_testing/readout_input_test.py @@ -0,0 +1,413 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from frozen_poisson import build_input_spike_train, frozen_poisson_variable_hz +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel +from spynnaker.pyNN.spynnaker_external_device_plugin_manager import SpynnakerExternalDevicePluginManager + +def weight_distribution(pop_size): + base_weight = np.random.randn() / np.sqrt(pop_size) #+ 0.5 + # base_weight = 0 + return base_weight + +def probability_connector(pre_pop_size, post_pop_size, prob, offset=0): + connections = [] + max_syn_per_neuron = 0 + for j in range(post_pop_size): + neuron_syn_count = 0 + delay_count = offset + for i in range(pre_pop_size): + if np.random.random() < prob: + neuron_syn_count += 1 + conn = [i, j, weight_distribution(pre_pop_size), delay_count] + delay_count += 1 + connections.append(conn) + if neuron_syn_count > max_syn_per_neuron: + max_syn_per_neuron = neuron_syn_count + return connections, max_syn_per_neuron + +def range_connector(pre_min, pre_max, post_min, post_max, weight=1.5, delay_offset=0): + connections = [] + for j in range(post_min, post_max): + delay = delay_offset + for i in range(pre_min, pre_max): + connections.append([i, j, weight, i+delay_offset]) + delay += 1 + return connections + +np.random.seed(272727) + +number_of_cues = 1 +cycle_time = (number_of_cues*150)+1000+150 +num_repeats = 4 +pynn.setup(1.0) + +target_data = [] +for i in range(1024): + target_data.append(#1) + 0 + 2 * np.sin(2 * i * 2* np.pi / 1024) \ + + 2 * np.sin((4 * i * 2* np.pi / 1024)) + ) + + +reg_rate = 0.000 +p_connect_in = 1. +p_connect_rec = 1. +p_connect_out = 1. +recurrent_connections = False +synapse_eta = 0.5 +tau_a = 5500#[cycle_time - 150 + (np.random.randn() * 200) for i in range(100)] +input_split = 100 +window_size = 1300*10 + +in_weight = 2 +prompt_weight = 2 +rec_weight = -1.9 +out_weight = 1 + + +pynn.setup(timestep=1) + +pynn.set_number_of_neurons_per_core(pynn.extra_models.EPropAdaptive, 6) + +input_size = 24 +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "poisson_pop_size": input_size // 4, + "rate_on": 40, + "rate_off": 0, + # "tau_m": tau_a, + "w_fb": [1, -1, 0], + "eta": synapse_eta / 5., + "window_size": window_size, + } +rates = [] +for i in range(input_size): + if i >= (3*input_size) // 4: + rates.append(10) + else: + rates.append(0) +input_pop = pynn.Population(input_size, + pynn.SpikeSourcePoisson(rate=rates), + # {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size)}, + # {'spike_times': frozen_poisson_variable_hz(num_repeats, cycle_time, input_split, input_split, input_size)}, + label='input_pop') + +neuron_pop_size = 10 +ratio_of_LIF = 0.5 +beta = [] +for i in range(neuron_pop_size): + if i < neuron_pop_size//2: + # if i % 2 == 0: + beta.append(25.8) + else: + beta.append(25.8) +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0, + # "w_fb": [np.random.random() for i in range(neuron_pop_size)], # best it seems + # "w_fb": [(np.random.random() * 2) - 1. for i in range(neuron_pop_size)], + "w_fb": [np.random.random() - np.random.random() for i in range(neuron_pop_size)], ## for both feedback weights + # "B": 0.0, + "beta": beta, + "target_rate": 10, + "tau_a": tau_a, + "eta": 0.0,#synapse_eta / 20., + "window_size": window_size, + } +neuron = pynn.Population(neuron_pop_size, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +# Output population +readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.LeftRightReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + +poisson_control_edge = SpynnakerExternalDevicePluginManager.add_edge( + readout_pop._vertex, input_pop._vertex, "CONTROL") +# pynn.external_devices.activate_live_output_to( +# readout_pop, input_pop, "CONTROL") +input_pop._vertex.set_live_poisson_control_edge(poisson_control_edge) +# pynn.external_devices.add_poisson_live_rate_control(input_pop) + +start_w = [weight_distribution(neuron_pop_size*input_size) for i in range(input_size)] +eprop_learning_neuron = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=reg_rate)) + +# from_list_in, max_syn_per_input = probability_connector(input_size, neuron_pop_size, p_connect_in) +ps = readout_neuron_params["poisson_pop_size"] +from_list_in = range_connector(0, ps, 0, neuron_pop_size//2, weight=in_weight) +from_list_in += range_connector(ps, ps*2, neuron_pop_size//2, neuron_pop_size, weight=in_weight) +from_list_in += range_connector(ps*2, ps*3, 0, neuron_pop_size, delay_offset=0, weight=prompt_weight) +in_proj = pynn.Projection(input_pop, + neuron, + pynn.FromListConnector(from_list_in), + # pynn.AllToAllConnector(), + synapse_type=eprop_learning_neuron, + label='input_connections', + receptor_type='input_connections') + +eprop_learning_output = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=0.0)) + +# from_list_out = [[i, 0, weight_distribution(input_size), i] for i in range(input_size)] +# from_list_out, max_syn_per_output = probability_connector(neuron_pop_size, 2, p_connect_out) +from_list_out = range_connector(0, neuron_pop_size//2, 1, 2, weight=out_weight) +from_list_out += range_connector(neuron_pop_size//2, neuron_pop_size, 0, 1, weight=out_weight) +out_proj = pynn.Projection(neuron, + readout_pop, + # pynn.OneToOneConnector(), + pynn.FromListConnector(from_list_out), + synapse_type=eprop_learning_output, + label='input_connections', + receptor_type='input_connections') + +learning_proj = pynn.Projection(readout_pop, + neuron, + pynn.AllToAllConnector(), + pynn.StaticSynapse(weight=0.5, delay=0), + receptor_type='learning_signal') + +# learning_proj = pynn.Projection(readout_pop, +# readout_pop, +# pynn.AllToAllConnector(), +# pynn.StaticSynapse(weight=0.5, delay=0), +# receptor_type='learning_signal') + +if recurrent_connections: + eprop_learning_recurrent = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=reg_rate)) + + # from_list_rec, max_syn_per_rec = probability_connector(neuron_pop_size, neuron_pop_size, p_connect_rec, offset=0) + from_list_rec = range_connector(0, 50, 50, 100, weight=rec_weight, delay_offset=100) + from_list_rec += range_connector(50, 100, 0, 50, weight=rec_weight, delay_offset=100) + recurrent_proj = pynn.Projection(neuron, + neuron, + pynn.FromListConnector(from_list_rec), + synapse_type=eprop_learning_recurrent, + label='recurrent_connections', + receptor_type='recurrent_connections') + +input_pop.record('spikes') +neuron.record('spikes') +neuron.record(['gsyn_exc', 'v', 'gsyn_inh'])#, indexes=[i for i in range(45, 55)]) +readout_pop.record('all') + +runtime = cycle_time * num_repeats + +experiment_label = "eta:{}/{} - size:{}/{} - reg_rate:{} - p_conn:{}/{}/{} - rec:{} - cycle:{}/{}/{} regoff delai".format( + readout_neuron_params["eta"], neuron_params["eta"], input_size, neuron_pop_size, reg_rate, p_connect_in, p_connect_rec, p_connect_out, recurrent_connections, cycle_time, window_size, runtime) +print("\n", experiment_label, "\n") + +pynn.run(runtime) +in_spikes = input_pop.get_data('spikes') +neuron_res = neuron.get_data('all') +readout_res = readout_pop.get_data('all') + +total_error = 0.0 +cycle_error = [0.0 for i in range(num_repeats)] +soft_max = [[], []] +cross_entropy = [] # how do I extract the answer easily? final gsyn exc value? +all_cross = [[], []] +from_soft = [[], []] +print("size of readout_res (gsyn inh) ", + len(readout_res.segments[0].filter(name='gsyn_inh')[0])) +print("size of readout_res (gsyn exc) ", + len(readout_res.segments[0].filter(name='gsyn_exc')[0])) +print("size of readout_res (v) ", + len(readout_res.segments[0].filter(name='v')[0])) +for cycle in range(num_repeats): + ticks_for_mean = 0 + mean_0 = 0. + mean_1 = 0. + # mean_0_all = 0. + # mean_1_all = 0. + for time_index in range(cycle_time): + # print("cycle, cycle_time, time_index ", cycle, cycle_time, time_index) + instantaneous_error = np.abs(float( + readout_res.segments[0].filter( + name='gsyn_inh')[0][time_index+(cycle*cycle_time)][0])) + cycle_error[cycle] += instantaneous_error + total_error += instantaneous_error + + # if time_index > cycle_time - 150: + # ticks_for_mean = 1 + # instantaneous_v0 = float(readout_res.segments[0].filter(name='v')[0][time_index+(cycle*cycle_time)][0]) + # instantaneous_v1 = float(readout_res.segments[0].filter(name='v')[0][time_index+(cycle*cycle_time)][1]) + # mean_0 = instantaneous_v0 * 0.1 + # mean_1 = instantaneous_v1 * 0.1 + # exp_0 = np.exp(mean_0 / ticks_for_mean) + # exp_1 = np.exp(mean_1 / ticks_for_mean) + # if exp_0 == 0 and exp_1 == 0: + # if instantaneous_v0 > instantaneous_v1: + # soft_max[0].append(1) + # soft_max[1].append(0) + # else: + # soft_max[0].append(0) + # soft_max[1].append(1) + # else: + # soft_max[0].append(-np.log(exp_0 / (exp_0 + exp_1))) + # soft_max[1].append(-np.log(exp_1 / (exp_0 + exp_1))) + # if float(readout_res.segments[0].filter(name='gsyn_exc')[0][time_index+(cycle*cycle_time)][2]) < 3.5: + # cross_entropy.append(soft_max[0][-1]) + # else: + # cross_entropy.append(soft_max[1][-1]) + # + # from_soft[0].append(-np.log(float(readout_res.segments[0].filter(name='gsyn_exc')[0][time_index+(cycle*cycle_time)][0]))) + # from_soft[1].append(-np.log(float(readout_res.segments[0].filter(name='gsyn_exc')[0][time_index+(cycle*cycle_time)][1]))) + # else: + # soft_max[0].append(0) + # soft_max[1].append(0) + # from_soft[0].append(0) + # from_soft[1].append(0) + # cross_entropy.append(0) + # + # instantaneous_v0 = float(readout_res.segments[0].filter(name='v')[0][time_index + (cycle * cycle_time)][0]) + # instantaneous_v1 = float(readout_res.segments[0].filter(name='v')[0][time_index + (cycle * cycle_time)][1]) + # # mean_0_all += instantaneous_v0 + # # mean_1_all += instantaneous_v1 + # exp_0 = np.exp(instantaneous_v0 * 0.1) + # exp_1 = np.exp(instantaneous_v1 * 0.1) + # all_cross[0].append(-np.log(exp_0 / (exp_0 + exp_1))) + # all_cross[1].append(-np.log(exp_1 / (exp_0 + exp_1))) +new_connections_in = []#in_proj.get('weight', 'delay').connections[0]#[] +for partition in in_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_in.append(conn) +new_connections_in.sort(key=lambda x:x[1]) +from_list_in.sort(key=lambda x:x[1]) +connection_diff_in = [] +for i in range(len(from_list_in)): + connection_diff_in.append(new_connections_in[i][2] - from_list_in[i][2]) +print("Input connections\noriginal\n", np.array(from_list_in)) +print("new\n", np.array(new_connections_in)) +print("diff\n", np.array(connection_diff_in)) + +new_connections_out = []#out_proj.get('weight', 'delay').connections[0]#[] +for partition in out_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_out.append(conn) +new_connections_out.sort(key=lambda x:x[1]) +from_list_out.sort(key=lambda x:x[1]) +connection_diff_out = [] +for i in range(len(from_list_out)): + connection_diff_out.append(new_connections_out[i][2] - from_list_out[i][2]) +print("Output connections\noriginal\n", np.array(from_list_out)) +print("new\n", np.array(new_connections_out)) +print("diff\n", np.array(connection_diff_out)) + +if recurrent_connections: + new_connections_rec = []#out_proj.get('weight', 'delay').connections[0]#[] + for partition in recurrent_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_rec.append(conn) + new_connections_rec.sort(key=lambda x:x[1]) + from_list_rec.sort(key=lambda x:x[1]) + connection_diff_rec = [] + for i in range(len(from_list_rec)): + connection_diff_rec.append(new_connections_rec[i][2] - from_list_rec[i][2]) + print("Recurrent connections\noriginal\n", np.array(from_list_rec)) + print("new\n", np.array(new_connections_rec)) + print("diff\n", np.array(connection_diff_rec)) + +print(experiment_label) +print("cycle_error =", cycle_error) +print("total error =", total_error) +print("average error = ", np.average(cycle_error)) +print("weighted average", np.average(cycle_error, weights=[i for i in range(num_repeats)])) +print("minimum error = ", np.min(cycle_error)) +print("minimum iteration =", cycle_error.index(np.min(cycle_error)), "- with time stamp =", cycle_error.index(np.min(cycle_error)) * 1024) + +plt.figure() +Figure( + Panel(neuron_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].spiketrains, ylabel='neuron_spikes', xlabel='neuron_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), + + title="neuron data for {}".format(experiment_label) +) +plt.show() + +fig, axs = plt.subplots(1, 1) +axs.set_title(experiment_label) +# axs[0].plot([i for i in range(len(cross_entropy))], cross_entropy) +# axs[1].plot([i for i in range(len(all_cross[0]))], all_cross[0]) +# axs[2].plot([i for i in range(len(all_cross[1]))], all_cross[1]) +axs.scatter([i for i in range(len(cycle_error))], cycle_error) +# axs[1].plot([i for i in range(len(from_soft[0]))], from_soft[0]) +# axs[2].plot([i for i in range(len(from_soft[1]))], from_soft[1]) +plt.show() + +pynn.end() +print("job done") + +''' +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() + +def moving_average(a, n=3) : + ret = np.cumsum(a, dtype=float) + ret[n:] = ret[n:] - ret[:-n] + return ret[n - 1:] / n + +v_mem = [] +sine_wave = [] +for timestep in readout_res.segments[0].filter(name='v')[0]: + v_mem.append(timestep[0]) + sine_wave.append(timestep[1]) + +ave_mem = moving_average(v_mem, 20) +ave_sine = moving_average(sine_wave, 20) + +plt.figure() +plt.plot([i for i in range(len(ave_mem))], cum_mem) +plt.plot([i for i in range(len(ave_sine))], cum_sine) +plt.title(experiment_label) +plt.show() + +plt.figure() +plt.plot([i for i in range(len(soft_max[0]))], soft_max[0]) +plt.plot([i for i in range(len(soft_max[1]))], soft_max[1]) +plt.title(experiment_label) +plt.show() +''' \ No newline at end of file diff --git a/eprop_testing/signed_weights_test.py b/eprop_testing/signed_weights_test.py new file mode 100644 index 0000000..c7cb19d --- /dev/null +++ b/eprop_testing/signed_weights_test.py @@ -0,0 +1,78 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + + +runtime = 100 +pynn.setup(1.0) + +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0 + } + + +spike_source = pynn.Population(2, + pynn.SpikeSourceArray, + {'spike_times': [10]}, + label='Spike Source') + +neuron = pynn.Population(2, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +proj = pynn.Projection(spike_source, neuron, + pynn.OneToOneConnector(), + # note that delays are now fixed to one in terms of spikes, + # but the synaptic word field indexes the synapse array + pynn.StaticSynapse(weight=[-0.5, 2] , delay=[1, 5]), + receptor_type='input_connections') + + +neuron.record('all') + +pynn.run(runtime) + +res = neuron.get_data('all') +weights = proj.get('weight', 'list', with_address=False) +delays = proj.get('delay', 'list', with_address=False) + +for i in range(len(weights)): + print(weights[i], delays[i]) + +Figure( + Panel(res.segments[0].filter(name='v')[0], + ylabel="Membrane potential (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_exc')[0], + ylabel="gsyn excitatory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_inh')[0], + xlabel="Time (ms)", xticks=True, + ylabel="gsyn inhibitory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].spiketrains, + ylabel="Output Spikes", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + title="Single eprop neuron" +) + +plt.show() + +pynn.end() \ No newline at end of file diff --git a/eprop_testing/spynnaker.cfg b/eprop_testing/spynnaker.cfg new file mode 100644 index 0000000..98e8ef3 --- /dev/null +++ b/eprop_testing/spynnaker.cfg @@ -0,0 +1,6 @@ +# set time scale factor to somewhere between 3 and 10 +[Machine] +time_scale_factor = 3 + +[Simulation] +n_colour_bits = 0 \ No newline at end of file diff --git a/eprop_testing/store_recall.py b/eprop_testing/store_recall.py new file mode 100644 index 0000000..2b8fd10 --- /dev/null +++ b/eprop_testing/store_recall.py @@ -0,0 +1,366 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import spynnaker8 as p +from spinn_front_end_common.utility_models import ( +ReverseIpTagMultiCastSource) +from spynnaker.pyNN.spynnaker_external_device_plugin_manager import (SpynnakerExternalDevicePluginManager) +from spynnaker.pyNN.utilities import constants +import numpy +import math +import unittest +from pyNN.utility.plotting import Figure, Panel +import matplotlib.pyplot as plt +import numpy as np + +# @staticmethod +def add_poisson_live_rate_control(poisson_population, controller): + vertex = poisson_population._get_vertex + SpynnakerExternalDevicePluginManager.add_edge( + controller._get_vertex, vertex, constants.LIVE_POISSON_CONTROL_PARTITION_ID) + + +batches = 40 +num_repeats = 10 # in a batch +cycle_time = 2047 +timestep = 1 +p.setup(timestep) # simulation timestep (ms) +runtime = num_repeats * cycle_time * batches + + +# # Post-synapse population +erbp_neuron_params = { + "tau_err": 1000, +# "tau_refrac": 50 + # "v_thresh": 30.0, # do not change - hard-coded in C for now + "v_reset": 0.0, + 'small_b': 0, + 'v_rest': 0.0, + 'v': 0, + 'tau_m': 20.0, + 'cm': 20, # Updated to suit tau_m of 20 and make membrane resistance 1 + 'B': 10.0, + 'small_b_0': 10, + 'i_offset': 0, + 'tau_a': 1200, + 'beta': 1.7, + 'tau_refrac':3 + } + +# Store recall parameters +prob_command = 1. / 6. +rate_on = 50 +rate_off = 0 +input_pop_size = 25 + +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "poisson_pop_size": input_pop_size, + } + +tau_err = 20 + +init_weight = 0.2 + +p.set_number_of_neurons_per_core(p.extra_models.EPropAdaptive, 32) +p.set_number_of_neurons_per_core(p.SpikeSourcePoisson, 32) + +w_in_rec_exc_dist = p.RandomDistribution( + distribution='normal_clipped', mu=init_weight, sigma=init_weight, + low=0.0, high=2*init_weight) + +w_in_rec_inh_dist = p.RandomDistribution( + distribution='normal_clipped', mu=init_weight, sigma=init_weight, + low=0.0, high=2*init_weight) + +w_rec_rec_dist = p.RandomDistribution( + distribution='normal_clipped', mu=init_weight, sigma=init_weight, + low=0.0, high=2*init_weight) + +w_rec_out = init_weight +w_rec_out_dist = p.RandomDistribution( + distribution='normal_clipped', mu=w_rec_out, sigma=w_rec_out, + low=0.0, high=2*w_rec_out) + +w_out_out = init_weight +w_out_out_dist = p.RandomDistribution( + distribution='normal_clipped', mu=w_out_out, sigma=w_out_out, + low=0.0, high=2*w_out_out) + + +############################################################################### +# Build Populations +############################################################################### + +# Input population +pop_in = p.Population(4*input_pop_size, + p.SpikeSourcePoisson, + {'rate': rate_on}, + label='pop_in') + +# Recurrent population +pop_rec = p.Population(20, + p.extra_models.EPropAdaptive, + # {10 LIF, 10 adaptive}, + label='pop_rec') + +# Output population +pop_out = p.Population(3, # HARDCODED 3: One readout; one exc err, one inh err todo check the new neuron ids + p.extra_models.StoreRecallReadout( + **readout_neuron_params + ), # Neuron model + label="pop_out" # identifier + ) + +############################################################################### +# Build Projections +############################################################################### + +####################################### +# readout to poisson sources +####################################### + +add_poisson_live_rate_control(poisson_population=pop_in, controller=pop_out) + +# hidden_pop_timing_dependence=p.TimingDependenceERBP( +# tau_plus=tau_err, A_plus=0.01, A_minus=0.01) +# hidden_pop_weight_dependence=p.WeightDependenceERBP( +# w_min=0.0, w_max=1, reg_rate=0.1) +hidden_pop_timing_dependence=p.TimingDependenceERBP( + tau_plus=tau_err, A_plus=0.025, A_minus=0.025, is_readout=False) +hidden_pop_weight_dependence=p.WeightDependenceERBP( + w_min=0.0, w_max=3, reg_rate=0.0) + +out_pop_timing_dependence=p.TimingDependenceERBP( + tau_plus=tau_err, A_plus=0.025, A_minus=0.025, is_readout=True) +out_pop_weight_dependence=p.WeightDependenceERBP( + w_min=0.0, w_max=3, reg_rate=0.0) + +####################################### +# input to recurrent excitatory +####################################### + +# Define learning rule object +learning_rule = p.STDPMechanism( + timing_dependence=hidden_pop_timing_dependence, + weight_dependence=hidden_pop_weight_dependence, + weight=w_in_rec_exc_dist, + delay=timestep) + +# Create excitatory projection from input to hidden neuron using learning rule +inp_rec_exc = p.Projection( + pop_in, + pop_rec, + p.AllToAllConnector(), +# p.StaticSynapse(weight=w_in_rec_exc_dist, delay=timestep), + synapse_type=learning_rule, + receptor_type="exc_err") + +# input to recurrent inhibitory +# Define learning rule object +learning_rule = p.STDPMechanism( + timing_dependence=hidden_pop_timing_dependence, + weight_dependence=hidden_pop_weight_dependence, + weight=w_in_rec_inh_dist, + delay=timestep) + +# Create inhibitory projection from input to hidden neuron using learning rule +inp_rec_inh = p.Projection( + pop_in, + pop_rec, + p.AllToAllConnector(), +# p.StaticSynapse(weight=w_in_rec_inh_dist, delay=timestep), + synapse_type=learning_rule, + receptor_type="exc_err") + + +####################################### +# recurrent to recurrent +####################################### +# Define learning rule object +learning_rule = p.STDPMechanism( + timing_dependence=hidden_pop_timing_dependence, + weight_dependence=hidden_pop_weight_dependence, + weight=w_rec_rec_dist, + delay=timestep) + +# Create excitatory recurrent projection +rec_rec_exc = p.Projection( + pop_rec, + pop_rec, + p.FixedProbabilityConnector(1.0), + synapse_type=learning_rule, + receptor_type="excitatory") + +# input to recurrent inhibitory +# Define learning rule object +learning_rule = p.STDPMechanism( + timing_dependence=hidden_pop_timing_dependence, + weight_dependence=hidden_pop_weight_dependence, + weight=w_rec_rec_dist, + delay=timestep) + +# Create inhibitory recurrent projection from input to hidden neuron using +# learning rule +rec_rec_inh = p.Projection( + pop_rec, + pop_rec, + p.FixedProbabilityConnector(1.0), + synapse_type=learning_rule, + receptor_type="inhibitory") + +####################################### +# recurrent to output +####################################### + +# Only connect to neuron '0' of readout population +# rand_out_w.next(), +conn_list_exc = [[x, 0, w_rec_out_dist.next(), 1] for x in range(100)] +conn_list_inh = [[x, 0, w_rec_out_dist.next(), 1] for x in range(100)] + +for i in range(0,100,2): + conn_list_exc[i][2] = 0 + conn_list_inh[i+1][2] = 0 + + +# Define learning rule object +learning_rule = p.STDPMechanism( + timing_dependence=out_pop_timing_dependence, + weight_dependence=out_pop_weight_dependence, + weight=w_rec_out_dist, + delay=timestep) + +# Create excitatory recurrent to out projection +rec_out_exc = p.Projection( + pop_rec, + pop_out, + p.FromListConnector(conn_list_exc), +# synapse_type=p.StaticSynapse(weight=0.1, delay=1), + synapse_type=learning_rule, + receptor_type="excitatory") + +# recurrent to out inhibitory +# Define learning rule object +learning_rule = p.STDPMechanism( + timing_dependence=out_pop_timing_dependence, + weight_dependence=out_pop_weight_dependence, + weight=w_rec_out_dist, + delay=timestep) + +# Create inhibitory recurrent projection from recurrent to hidden neuron using +# learning rule +rec_out_inh = p.Projection( + pop_rec, + pop_out, + p.FromListConnector(conn_list_inh), +# p.StaticSynapse(weight=0.1, delay=1), + synapse_type=learning_rule, + receptor_type="inhibitory") + +####################################### +# Feedback connections +####################################### + +# # Connect excitatory fb neuron (1) to all recurrent neurons +# # rand_out_w.next() +# exc_fb_rec_conn_list = [[1, x, 0.01*w_rec_out_dist.next(), 1] for x in range(100)] +# # Connect inhibitory fb neuron (2) to all recurrent neurons +# # rand_out_w.next() +# inh_fb_rec_conn_list = [[2, x, 0.01*w_rec_out_dist.next(), 1] for x in range(100)] +# +# fb_out_rec_exc = p.Projection( +# pop_out, pop_rec, p.FromListConnector(exc_fb_rec_conn_list), +# p.StaticSynapse(weight=10, delay=1), receptor_type="exc_err") +# +# fb_out_rec_inh = p.Projection( +# pop_out, pop_rec, p.FromListConnector(inh_fb_rec_conn_list), +# p.StaticSynapse(weight=10, delay=1), receptor_type="inh_err") + + +# Now to output layer to gate plasticity on output weights +# rand_out_w.next() +# rand_out_w.next() +exc_fb_out_conn_list = [1, 0, w_out_out_dist.next(), 1] +inh_fb_out_conn_list = [2, 0, w_out_out_dist.next(), 1] + +fb_out_out_exc = p.Projection( + pop_out, pop_out, p.FromListConnector([exc_fb_out_conn_list]), + p.StaticSynapse(weight=0.5, delay=1), receptor_type="exc_err") + +fb_out_out_inh = p.Projection( + pop_out, pop_out, p.FromListConnector([inh_fb_out_conn_list]), + p.StaticSynapse(weight=0.5, delay=1), receptor_type="inh_err") + +############################################################################### +# Run Simulation +############################################################################### + +pop_in.record('spikes') +pop_rec.record("spikes") +pop_out.record("all") + + +# p.run(runtime) +plot_start = 0 +window = num_repeats * cycle_time +plot_end = plot_start + window + + +for i in range(batches): + + print "run: {}".format(i) + p.run(runtime/batches) + + in_spikes = pop_in.get_data('spikes') + pop_rec_data = pop_rec.get_data('spikes') + pop_out_data = pop_out.get_data() + + # Plot + F = Figure( +# # plot data for postsynaptic neuron + Panel(in_spikes.segments[0].spiketrains, + yticks=True, markersize=2, xlim=(plot_start, plot_end)), + Panel(pop_rec_data.segments[0].spiketrains, + yticks=True, markersize=2, xlim=(plot_start, plot_end) + ), + Panel(pop_out_data.segments[0].filter(name='v')[0], + ylabel="Membrane potential (mV)", + data_labels=[pop_out.label], yticks=True, xlim=(plot_start, plot_end) + ), + Panel(pop_out_data.segments[0].filter(name='gsyn_exc')[0], + ylabel="gsyn excitatory (mV)", + data_labels=[pop_out.label], yticks=True, xlim=(plot_start, plot_end) + ), + Panel(pop_out_data.segments[0].filter(name='gsyn_inh')[0], + ylabel="gsyn inhibitory (mV)", + data_labels=[pop_out.label], yticks=True, xlim=(plot_start, plot_end) + ), + Panel(pop_out_data.segments[0].spiketrains, + yticks=True, markersize=2, xlim=(plot_start, plot_end)), + annotations="Batch: {}".format(i) + ) + + plt.pause(1) +# plt.draw() + + plot_start = plot_end + plot_end += window + + +p.end() + + +print "job done" + +plt.show() \ No newline at end of file diff --git a/eprop_testing/test_8_neuron_regularisation.py b/eprop_testing/test_8_neuron_regularisation.py new file mode 100644 index 0000000..db67e6c --- /dev/null +++ b/eprop_testing/test_8_neuron_regularisation.py @@ -0,0 +1,86 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + + +runtime = 100000 +dt = 1 + +pynn.setup(dt) + +n_neurons = 8 + +neuron_params = { + "v": 0, + "target_rate": 10, + "beta": 0.0 # Stops any adaptation occurring + } + + + +neuron = pynn.Population(n_neurons, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +poisson_src = pynn.Population(n_neurons, + pynn.SpikeSourcePoisson(rate= + 10 +# [15.0, 5.0] + ), + label='Poisson Src') + +proj = pynn.Projection( + poisson_src, + neuron, + pynn.OneToOneConnector(), + pynn.StaticSynapse(weight=3.5, delay=dt), + # weight set to cause postsynaptic neuron to fire + receptor_type='input_connections' + ) + +poisson_src.record('spikes') +neuron.record('all') + +pynn.run(runtime) + +res = neuron.get_data('all') +poisson_spikes = poisson_src.get_data('spikes') + +Figure( + Panel(poisson_spikes.segments[0].spiketrains, + ylabel="Input Spikes", + data_labels=poisson_src.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='v')[0], + ylabel="Membrane potential (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_exc')[0], + ylabel="gsyn excitatory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_inh')[0], + xlabel="Time (ms)", xticks=True, + ylabel="Global Rate Approx (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].spiketrains, + ylabel="Output Spikes", + data_labels=poisson_src.label, yticks=True, xlim=(0, runtime)), + title="Single eprop neuron" +) + +plt.show() + +pynn.end() \ No newline at end of file diff --git a/eprop_testing/test_adaptive_threshold.py b/eprop_testing/test_adaptive_threshold.py new file mode 100644 index 0000000..05f53b1 --- /dev/null +++ b/eprop_testing/test_adaptive_threshold.py @@ -0,0 +1,59 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + + +runtime = 10000 +pynn.setup(1.0) + +neuron_params = { + "v": 0, + "i_offset": 1, + "v_rest": 0 + } + +neuron = pynn.Population(1, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +neuron.record('all') + +pynn.run(runtime) + +res = neuron.get_data('all') + +Figure( + Panel(res.segments[0].filter(name='v')[0], + ylabel="Membrane potential (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_exc')[0], + ylabel="gsyn excitatory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_inh')[0], + xlabel="Time (ms)", xticks=True, + ylabel="gsyn inhibitory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].spiketrains, + ylabel="Output Spikes", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + title="Single eprop neuron" +) + +plt.show() + +pynn.end() \ No newline at end of file diff --git a/eprop_testing/test_learning_signal_by_payload.py b/eprop_testing/test_learning_signal_by_payload.py new file mode 100644 index 0000000..3f3daa9 --- /dev/null +++ b/eprop_testing/test_learning_signal_by_payload.py @@ -0,0 +1,117 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + + +runtime = 1024 +pynn.setup(1.0) + +neuron_params = { + "v": 0, + "i_offset": 0.8, + "v_rest": 0, + "w_fb": 0.75 + } + +target_data = [] +for i in range(1024): + target_data.append( + 5 + 2 * np.sin(2 * i * 2* np.pi / 1024) \ + + 2 * np.sin((4 * i * 2* np.pi / 1024)) + ) + +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "target_data": target_data, + } + +input_pop = pynn.Population(1, + pynn.SpikeSourceArray, + {'spike_times': [200, 210]}, + label='input_pop') + +neuron = pynn.Population(1, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +in_proj = pynn.Projection(input_pop, + neuron, + pynn.OneToOneConnector(), + pynn.StaticSynapse(weight=[-0.5], delay=[0]), + receptor_type='input_connections') + +# Output population +readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.SinusoidReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + +learning_proj = pynn.Projection(readout_pop, + neuron, + pynn.OneToOneConnector(), + pynn.StaticSynapse(weight=[-0.5], delay=[0]), + receptor_type='learning_signal') + +input_pop.record('spikes') +neuron.record('all') +readout_pop.record('all') + +pynn.run(runtime) +in_spikes = input_pop.get_data('spikes') +neuron_res = neuron.get_data('all') +readout_res = readout_pop.get_data('all') + + + +# Plot rec neuron output +plt.figure() +plt.tight_layout() + +plt.subplot(4, 1, 1) +plt.plot(neuron_res.segments[0].filter(name='v')[0].magnitude, label='Membrane potential (mV)') + +plt.subplot(4, 1, 2) +plt.plot(neuron_res.segments[0].filter(name='gsyn_exc')[0].magnitude, label='gsyn_exc') + +plt.subplot(4, 1, 3) +plt.plot(neuron_res.segments[0].filter(name='gsyn_inh')[0].magnitude, label='gsyn_inh') + +plt.subplot(4,1,4) +plt.plot(in_spikes.segments[0].spiketrains, label='in_spikes') + +# Plot Readout output +plt.figure() +plt.tight_layout() + +plt.subplot(3, 1, 1) +plt.plot(readout_res.segments[0].filter(name='v')[0].magnitude, label='Membrane potential (mV)') + +plt.subplot(3, 1, 2) +plt.plot(readout_res.segments[0].filter(name='gsyn_exc')[0].magnitude, label='gsyn_exc') + +plt.subplot(3, 1, 3) +plt.plot(readout_res.segments[0].filter(name='gsyn_inh')[0].magnitude, label='gsyn_inh') + + +plt.show() + +pynn.end() +print("job done") \ No newline at end of file diff --git a/eprop_testing/test_left_right_readout.py b/eprop_testing/test_left_right_readout.py new file mode 100644 index 0000000..95317c5 --- /dev/null +++ b/eprop_testing/test_left_right_readout.py @@ -0,0 +1,445 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +# from frozen_poisson import build_input_spike_train, frozen_poisson_variable_hz +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel +from spynnaker.pyNN.spynnaker_external_device_plugin_manager import SpynnakerExternalDevicePluginManager + +def weight_distribution(pop_size): + base_weight = np.random.randn() / np.sqrt(pop_size) #+ 0.5 + if abs(base_weight) < np.exp(-10): # checking because if too many are small neurons can't learn + print("\nweight too small: {}\n".format(base_weight)) + # base_weight = 0 + return base_weight + +def probability_connector(pre_pop_size, post_pop_size, prob, offset=0, added_weight=0.): + connections = [] + max_syn_per_neuron = 0 + for j in range(post_pop_size): + neuron_syn_count = 0 + delay_count = offset + for i in range(pre_pop_size): + if np.random.random() < prob: + neuron_syn_count += 1 + conn = [i, j, weight_distribution(pre_pop_size)+added_weight, delay_count] + delay_count += 1 + connections.append(conn) + if neuron_syn_count > max_syn_per_neuron: + max_syn_per_neuron = neuron_syn_count + return connections, max_syn_per_neuron + +np.random.seed(272727) + +number_of_cues = 1 +cycle_time = (number_of_cues*150)+1000+150 +num_repeats = 800 +pynn.setup(1.0) + +target_data = [] +for i in range(1024): + target_data.append(#1) + 0 + 2 * np.sin(2 * i * 2* np.pi / 1024) \ + + 2 * np.sin((4 * i * 2* np.pi / 1024)) + ) + + +reg_rate = 0.000 +p_connect_in = 1. +p_connect_rec = 1. +p_connect_out = 1. +recurrent_connections = True +synapse_eta = 0.0005 +tau_a = 2500#[cycle_time - 150 + (np.random.randn() * 200) for i in range(100)] +input_split = 20 +window_cycles = 10 +window_size = cycle_time*window_cycles +eprop_beta = 3 + +in_weight = 0.75 +prompt_weight = 0.75 +rec_weight = 0#-0.5 +out_weight = 0#0.01 +weight_string = "i{}-p{}-r{}-o{}".format(in_weight, prompt_weight, rec_weight, out_weight) + + +pynn.setup(timestep=1) + +pynn.set_number_of_neurons_per_core(pynn.extra_models.EPropAdaptive, 6) + +input_size = 40 +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "poisson_pop_size": input_size / 4, + "rate_on": 100, + # "tau_m": tau_a, + "w_fb": [1, -1, 0], + "eta": synapse_eta * 5., + "window_size": window_size, + } +rates = [] +for i in range(input_size): + if i >= (3*input_size) / 4: + rates.append(10) + else: + rates.append(0) +input_pop = pynn.Population(input_size, + pynn.SpikeSourcePoisson(rate=rates), + # {'spike_times': build_input_spike_train(num_repeats, cycle_time, input_size)}, + # {'spike_times': frozen_poisson_variable_hz(num_repeats, cycle_time, input_split, input_split, input_size)}, + label='input_pop') + +neuron_pop_size = 100 +ratio_of_LIF = 0.5 +beta = [] +for i in range(neuron_pop_size): + if i < neuron_pop_size/2: + # if i % 2 == 0: + beta.append(0) #this should be 0, just testing all ALIF + else: + beta.append(eprop_beta) +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0, + # "w_fb": [np.random.random() for i in range(neuron_pop_size)], # best it seems + # "w_fb": [(np.random.random() * 2) - 1. for i in range(neuron_pop_size)], + "w_fb": [4*np.random.random() - 4*np.random.random() for i in range(neuron_pop_size)], ## for both feedback weights + # "w_fb": [3]*(neuron_pop_size/4) + [-3]*(neuron_pop_size/4) + [3]*(neuron_pop_size/4) + [-3]*(neuron_pop_size/4), + # "B": 0.0, + "beta": beta, + "target_rate": 10, + "tau_a": tau_a, + "eta": synapse_eta * 5., + "window_size": window_size, + } +neuron = pynn.Population(neuron_pop_size, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +# Output population +readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.LeftRightReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + +poisson_control_edge = SpynnakerExternalDevicePluginManager.add_edge( + readout_pop._vertex, input_pop._vertex, "CONTROL") +# pynn.external_devices.activate_live_output_to( +# readout_pop, input_pop, "CONTROL") +input_pop._vertex.set_live_poisson_control_edge(poisson_control_edge) +# pynn.external_devices.add_poisson_live_rate_control(input_pop) + +# start_w = [weight_distribution(neuron_pop_size*input_size) for i in range(input_size)] +eprop_learning_neuron = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=reg_rate)) + +from_list_in, max_syn_per_input = probability_connector(input_size, neuron_pop_size, p_connect_in, added_weight=in_weight) +if max_syn_per_input > 100: + Exception +else: + print("max number of synapses per neuron:", max_syn_per_input) +in_proj = pynn.Projection(input_pop, + neuron, + pynn.FromListConnector(from_list_in), + # pynn.AllToAllConnector(), + synapse_type=eprop_learning_neuron, + label='input_connections', + receptor_type='input_connections') + +eprop_learning_output = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=0.0)) + +# from_list_out = [[i, 0, weight_distribution(input_size), i] for i in range(input_size)] +from_list_out, max_syn_per_output = probability_connector(neuron_pop_size, 2, p_connect_out, added_weight=out_weight) +if max_syn_per_output > 100: + Exception +else: + print("max number of synapses per readout:", max_syn_per_output) +out_proj = pynn.Projection(neuron, + readout_pop, + # pynn.OneToOneConnector(), + pynn.FromListConnector(from_list_out), + synapse_type=eprop_learning_output, + label='input_connections', + receptor_type='input_connections') + +learning_proj = pynn.Projection(readout_pop, + neuron, + pynn.AllToAllConnector(), + pynn.StaticSynapse(weight=0.5, delay=0), + receptor_type='learning_signal') + +# learning_proj = pynn.Projection(readout_pop, +# readout_pop, +# pynn.AllToAllConnector(), +# pynn.StaticSynapse(weight=0.5, delay=0), +# receptor_type='learning_signal') + +if recurrent_connections: + eprop_learning_recurrent = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=reg_rate)) + + from_list_rec, max_syn_per_rec = probability_connector(neuron_pop_size, neuron_pop_size, p_connect_rec, offset=0, added_weight=rec_weight) + if max_syn_per_rec > 150: + Exception + else: + print("max number of synapses per neuron:", max_syn_per_rec) + recurrent_proj = pynn.Projection(neuron, + neuron, + pynn.FromListConnector(from_list_rec), + synapse_type=eprop_learning_recurrent, + label='recurrent_connections', + receptor_type='recurrent_connections') + +input_pop.record('spikes') +neuron.record('spikes') +# neuron.record(['gsyn_exc', 'v', 'gsyn_inh'], indexes=[i for i in range(45, 55)]) +neuron[[i for i in range(45, 55)]].record(['gsyn_exc', 'v', 'gsyn_inh']) +readout_pop.record('all') + +runtime = cycle_time * num_repeats + +experiment_label = "eta:{}/{} - size:{}/{} - reg_rate:{} - p_conn:{}/{}/{} - rec:{} - cycle:{}/{}/{} noresetv 0d b:{}".format( + readout_neuron_params["eta"], neuron_params["eta"], input_size, neuron_pop_size, + reg_rate, p_connect_in, p_connect_rec, p_connect_out, recurrent_connections, + cycle_time, window_size, runtime, eprop_beta) +print("\n", experiment_label, "\n") + +pynn.run(runtime) +in_spikes = input_pop.get_data('spikes') +neuron_res = neuron.get_data('all') +readout_res = readout_pop.get_data('all') + +total_error = 0.0 +cycle_error = [0.0 for i in range(num_repeats)] +correct_or_not = [0 for i in range(num_repeats)] +soft_max = [[], []] +cross_entropy = [] # how do I extract the answer easily? final gsyn exc value? +all_cross = [[], []] +from_soft = [[], []] +for cycle in range(num_repeats): + ticks_for_mean = 0 + mean_0 = 0. + mean_1 = 0. + # mean_0_all = 0. + # mean_1_all = 0. + for time_index in range(cycle_time): + instantaneous_error = np.abs(float( + readout_res.segments[0].filter(name='gsyn_inh')[0][time_index+(cycle*cycle_time)][0])) + cycle_error[cycle] += instantaneous_error + total_error += instantaneous_error + if cycle_error[cycle] < 75: + correct_or_not[cycle] = 1 + + # if time_index > cycle_time - 150: + # ticks_for_mean = 1 + # instantaneous_v0 = float(readout_res.segments[0].filter(name='v')[0][time_index+(cycle*cycle_time)][0]) + # instantaneous_v1 = float(readout_res.segments[0].filter(name='v')[0][time_index+(cycle*cycle_time)][1]) + # mean_0 = instantaneous_v0 * 0.1 + # mean_1 = instantaneous_v1 * 0.1 + # exp_0 = np.exp(mean_0 / ticks_for_mean) + # exp_1 = np.exp(mean_1 / ticks_for_mean) + # if exp_0 == 0 and exp_1 == 0: + # if instantaneous_v0 > instantaneous_v1: + # soft_max[0].append(1) + # soft_max[1].append(0) + # else: + # soft_max[0].append(0) + # soft_max[1].append(1) + # else: + # soft_max[0].append(-np.log(exp_0 / (exp_0 + exp_1))) + # soft_max[1].append(-np.log(exp_1 / (exp_0 + exp_1))) + # if float(readout_res.segments[0].filter(name='gsyn_exc')[0][time_index+(cycle*cycle_time)][2]) < 3.5: + # cross_entropy.append(soft_max[0][-1]) + # else: + # cross_entropy.append(soft_max[1][-1]) + # + # from_soft[0].append(-np.log(float(readout_res.segments[0].filter(name='gsyn_exc')[0][time_index+(cycle*cycle_time)][0]))) + # from_soft[1].append(-np.log(float(readout_res.segments[0].filter(name='gsyn_exc')[0][time_index+(cycle*cycle_time)][1]))) + # else: + # soft_max[0].append(0) + # soft_max[1].append(0) + # from_soft[0].append(0) + # from_soft[1].append(0) + # cross_entropy.append(0) + # + # instantaneous_v0 = float(readout_res.segments[0].filter(name='v')[0][time_index + (cycle * cycle_time)][0]) + # instantaneous_v1 = float(readout_res.segments[0].filter(name='v')[0][time_index + (cycle * cycle_time)][1]) + # # mean_0_all += instantaneous_v0 + # # mean_1_all += instantaneous_v1 + # exp_0 = np.exp(instantaneous_v0 * 0.1) + # exp_1 = np.exp(instantaneous_v1 * 0.1) + # all_cross[0].append(-np.log(exp_0 / (exp_0 + exp_1))) + # all_cross[1].append(-np.log(exp_1 / (exp_0 + exp_1))) + + + +new_connections_in = []#in_proj.get('weight', 'delay').connections[0]#[] +for partition in in_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_in.append(conn) +new_connections_in.sort(key=lambda x:x[1]) +new_connections_in.sort(key=lambda x:x[0]) +from_list_in.sort(key=lambda x:x[1]) +from_list_in.sort(key=lambda x:x[0]) +connection_diff_in = [] +for i in range(len(from_list_in)): + connection_diff_in.append(new_connections_in[i][2] - from_list_in[i][2]) +print("Input connections\noriginal\n", np.array(from_list_in)) +print("new\n", np.array(new_connections_in)) +print("diff\n", np.array(connection_diff_in)) + +new_connections_out = []#out_proj.get('weight', 'delay').connections[0]#[] +for partition in out_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_out.append(conn) +new_connections_out.sort(key=lambda x:x[1]) +new_connections_out.sort(key=lambda x:x[0]) +from_list_out.sort(key=lambda x:x[1]) +from_list_out.sort(key=lambda x:x[0]) +connection_diff_out = [] +for i in range(len(from_list_out)): + connection_diff_out.append(new_connections_out[i][2] - from_list_out[i][2]) +print("Output connections\noriginal\n", np.array(from_list_out)) +print("new\n", np.array(new_connections_out)) +print("diff\n", np.array(connection_diff_out)) + +if recurrent_connections: + new_connections_rec = []#out_proj.get('weight', 'delay').connections[0]#[] + for partition in recurrent_proj.get('weight', 'delay').connections: + for conn in partition: + new_connections_rec.append(conn) + new_connections_rec.sort(key=lambda x:x[1]) + new_connections_rec.sort(key=lambda x:x[0]) + from_list_rec.sort(key=lambda x:x[1]) + from_list_rec.sort(key=lambda x:x[0]) + connection_diff_rec = [] + for i in range(len(from_list_out)): + connection_diff_rec.append(new_connections_rec[i][2] - from_list_rec[i][2]) + print("Recurrent connections\noriginal\n", np.array(from_list_out)) + print("new\n", np.array(new_connections_out)) + print("diff\n", np.array(connection_diff_out)) + +print(experiment_label) +print("cycle_error =", cycle_error) +print("total error =", total_error) +print("correct:")# =", correct_or_not +for i in range(int(np.ceil(len(correct_or_not) / float(window_cycles)))): + print(correct_or_not[i*window_cycles:(i+1)*window_cycles], np.average(correct_or_not[i*window_cycles:(i+1)*window_cycles])) +print("average error = ", np.average(cycle_error)) +print("weighted average", np.average(cycle_error, weights=[i for i in range(num_repeats)])) +print("minimum error = ", np.min(cycle_error)) +print("minimum iteration =", cycle_error.index(np.min(cycle_error)), "- with time stamp =", cycle_error.index(np.min(cycle_error)) * 1024) + +plt.figure() +Figure( + Panel(neuron_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].spiketrains, ylabel='neuron_spikes', xlabel='neuron_spikes', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(0, runtime)), + + title="neuron data for {}".format(experiment_label) +) +plt.show() + +# plt.figure() +# Figure( +# Panel(neuron_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(runtime-(window_size*1.5), runtime)), +# +# Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(runtime-(window_size*1.5), runtime)), +# +# Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(runtime-(window_size*1.5), runtime)), +# +# Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', xlabel='in_spikes', yticks=True, xticks=True, xlim=(runtime-(window_size*1.5), runtime)), +# +# Panel(neuron_res.segments[0].spiketrains, ylabel='neuron_spikes', xlabel='neuron_spikes', yticks=True, xticks=True, xlim=(runtime-(window_size*1.5), runtime)), +# +# Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xticks=True, xlim=(runtime-(window_size*1.5), runtime)), +# +# Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xticks=True, xlim=(runtime-(window_size*1.5), runtime)), +# +# Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xticks=True, xlim=(runtime-(window_size*1.5), runtime)), +# +# title="neuron data for {}".format(experiment_label) +# ) +# plt.show() + +fig, axs = plt.subplots(1, 1) +axs.set_title(experiment_label) +# axs[0].plot([i for i in range(len(cross_entropy))], cross_entropy) +# axs[1].plot([i for i in range(len(all_cross[0]))], all_cross[0]) +# axs[2].plot([i for i in range(len(all_cross[1]))], all_cross[1]) +axs.scatter([i for i in range(len(cycle_error))], cycle_error) +# axs[1].plot([i for i in range(len(from_soft[0]))], from_soft[0]) +# axs[2].plot([i for i in range(len(from_soft[1]))], from_soft[1]) +plt.show() + +pynn.end() +print("job done") + +''' +plt.figure() +plt.scatter([i for i in range(num_repeats)], cycle_error) +plt.title(experiment_label) +plt.show() + +def moving_average(a, n=3) : + ret = np.cumsum(a, dtype=float) + ret[n:] = ret[n:] - ret[:-n] + return ret[n - 1:] / n + +v_mem = [] +sine_wave = [] +for timestep in readout_res.segments[0].filter(name='v')[0]: + v_mem.append(timestep[0]) + sine_wave.append(timestep[1]) + +ave_mem = moving_average(v_mem, 20) +ave_sine = moving_average(sine_wave, 20) + +plt.figure() +plt.plot([i for i in range(len(ave_mem))], cum_mem) +plt.plot([i for i in range(len(ave_sine))], cum_sine) +plt.title(experiment_label) +plt.show() + +plt.figure() +plt.plot([i for i in range(len(soft_max[0]))], soft_max[0]) +plt.plot([i for i in range(len(soft_max[1]))], soft_max[1]) +plt.title(experiment_label) +plt.show() +''' \ No newline at end of file diff --git a/eprop_testing/test_regularisation.py b/eprop_testing/test_regularisation.py new file mode 100644 index 0000000..07ac19b --- /dev/null +++ b/eprop_testing/test_regularisation.py @@ -0,0 +1,337 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import spynnaker8 as p +import numpy +import math +import unittest +from pyNN.utility.plotting import Figure, Panel +import matplotlib.pyplot as plt + +batches = 10 +num_repeats = 5 # in a batch +cycle_time = 1023 +timestep = 1 +p.setup(timestep) # simulation timestep (ms) +runtime = num_repeats * cycle_time * batches + + +# # Post-synapse population +erbp_neuron_params = { + "v_thresh": 30, + "v_reset": 0, + "v_rest": 0, + "i_offset": 0, # DC input + "v": 0, + "tau_err": 1000 +# "tau_refrac": 50 + } + +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + } + +tau_err = 20 +p.set_number_of_neurons_per_core(p.extra_models.IFCurrExpERBP, 32) +p.set_number_of_neurons_per_core(p.SpikeSourceArray, 32) + +w_in_rec_exc = 0.1 +w_in_rec_exc_dist = p.RandomDistribution( + distribution='normal_clipped', mu=w_in_rec_exc, sigma=w_in_rec_exc, + low=0.0, high=2*w_in_rec_exc) + + +w_in_rec_inh = 0.5*w_in_rec_exc +w_in_rec_inh_dist = p.RandomDistribution( + distribution='normal_clipped', mu=w_in_rec_inh, sigma=w_in_rec_inh, + low=0.0, high=2*w_in_rec_inh) + + +w_rec_rec = 0.1 +w_rec_rec_dist = p.RandomDistribution( + distribution='normal_clipped', mu=w_rec_rec, sigma=w_rec_rec, + low=0.0, high=2*w_rec_rec) + + + + + +def build_input_spike_train(num_repeats, cycle_time): + pattern = [ + [7.0, 14.0, 26.0, 27.0, 42.0, 83.0, 93.0, 99.0, 109.0, 110.0, 144.0, 151.0, 153.0, 164.0, 175.0, 233.0, 245.0, 299.0, 303.0, 354.0, 355.0, 356.0, 432.0, 439.0, 447.0, 491.0, 553.0, 560.0, 583.0, 590.0, 645.0, 659.0, 667.0, 692.0, 693.0, 695.0, 714.0, 715.0, 728.0, 739.0, 756.0, 796.0, 822.0, 825.0, 829.0, 834.0, 862.0, 875.0, 880.0, 896.0, 909.0, 912.0, 940.0, 964.0, 1006.0], + [45.0, 63.0, 66.0, 88.0, 125.0, 142.0, 161.0, 167.0, 183.0, 188.0, 194.0, 207.0, 208.0, 235.0, 236.0, 252.0, 296.0, 346.0, 360.0, 384.0, 393.0, 396.0, 412.0, 474.0, 522.0, 543.0, 547.0, 616.0, 626.0, 657.0, 672.0, 681.0, 697.0, 706.0, 735.0, 770.0, 771.0, 774.0, 809.0, 811.0, 840.0, 847.0, 875.0, 965.0, 984.0, 989.0], + [26.0, 71.0, 79.0, 89.0, 94.0, 122.0, 123.0, 131.0, 138.0, 150.0, 156.0, 172.0, 195.0, 197.0, 220.0, 221.0, 246.0, 250.0, 251.0, 271.0, 272.0, 282.0, 310.0, 320.0, 351.0, 352.0, 355.0, 423.0, 493.0, 510.0, 523.0, 556.0, 577.0, 622.0, 657.0, 708.0, 748.0, 760.0, 766.0, 792.0, 835.0, 854.0, 890.0, 896.0, 898.0, 919.0, 934.0, 947.0, 948.0, 994.0, 1005.0, 1010.0, 1019.0, 1023.0], + [10.0, 21.0, 24.0, 27.0, 35.0, 47.0, 63.0, 64.0, 75.0, 90.0, 127.0, 129.0, 139.0, 145.0, 154.0, 221.0, 224.0, 256.0, 261.0, 262.0, 303.0, 305.0, 322.0, 327.0, 352.0, 369.0, 377.0, 397.0, 408.0, 413.0, 419.0, 437.0, 487.0, 489.0, 499.0, 522.0, 539.0, 607.0, 625.0, 626.0, 633.0, 649.0, 699.0, 701.0, 702.0, 724.0, 734.0, 758.0, 819.0, 835.0, 836.0, 897.0, 930.0, 954.0, 990.0, 1007.0, 1018.0], + [25.0, 31.0, 38.0, 66.0, 68.0, 81.0, 93.0, 111.0, 154.0, 163.0, 165.0, 184.0, 220.0, 272.0, 307.0, 316.0, 319.0, 335.0, 343.0, 392.0, 409.0, 459.0, 463.0, 483.0, 498.0, 507.0, 539.0, 543.0, 558.0, 559.0, 574.0, 579.0, 604.0, 605.0, 619.0, 622.0, 624.0, 626.0, 635.0, 640.0, 689.0, 704.0, 735.0, 740.0, 751.0, 758.0, 767.0, 782.0, 825.0, 836.0, 858.0, 868.0, 874.0, 886.0, 932.0, 952.0, 968.0, 970.0, 980.0, 989.0, 997.0], + [9.0, 18.0, 39.0, 43.0, 61.0, 76.0, 85.0, 121.0, 129.0, 164.0, 185.0, 227.0, 259.0, 283.0, 289.0, 335.0, 351.0, 384.0, 387.0, 392.0, 401.0, 402.0, 408.0, 413.0, 428.0, 435.0, 436.0, 451.0, 458.0, 461.0, 464.0, 476.0, 479.0, 489.0, 500.0, 518.0, 539.0, 551.0, 584.0, 589.0, 590.0, 602.0, 604.0, 605.0, 626.0, 632.0, 640.0, 641.0, 665.0, 707.0, 713.0, 730.0, 749.0, 784.0, 789.0, 837.0, 841.0, 863.0, 867.0, 870.0, 887.0, 935.0, 953.0, 956.0, 968.0, 970.0, 974.0, 984.0, 991.0, 1015.0, 1020.0, 1022.0], + [34.0, 35.0, 38.0, 77.0, 85.0, 90.0, 102.0, 122.0, 162.0, 178.0, 186.0, 187.0, 195.0, 196.0, 200.0, 205.0, 226.0, 278.0, 279.0, 284.0, 294.0, 316.0, 377.0, 402.0, 443.0, 450.0, 478.0, 497.0, 501.0, 509.0, 542.0, 560.0, 561.0, 562.0, 573.0, 590.0, 591.0, 597.0, 604.0, 608.0, 620.0, 631.0, 633.0, 654.0, 667.0, 719.0, 726.0, 739.0, 740.0, 758.0, 766.0, 767.0, 786.0, 792.0, 803.0, 806.0, 808.0, 811.0, 830.0, 842.0, 855.0, 856.0, 863.0, 878.0, 880.0, 889.0, 890.0, 906.0, 928.0, 958.0, 999.0, 1001.0, 1007.0, 1010.0], + [7.0, 31.0, 36.0, 59.0, 109.0, 110.0, 119.0, 121.0, 124.0, 126.0, 137.0, 185.0, 201.0, 218.0, 240.0, 261.0, 281.0, 306.0, 311.0, 342.0, 344.0, 349.0, 357.0, 365.0, 370.0, 380.0, 466.0, 468.0, 470.0, 489.0, 497.0, 572.0, 578.0, 584.0, 587.0, 612.0, 629.0, 657.0, 664.0, 698.0, 707.0, 711.0, 731.0, 735.0, 743.0, 773.0, 838.0, 839.0, 917.0, 923.0, 924.0, 992.0], + [17.0, 25.0, 28.0, 53.0, 70.0, 118.0, 125.0, 128.0, 142.0, 189.0, 190.0, 205.0, 224.0, 237.0, 292.0, 356.0, 357.0, 408.0, 416.0, 448.0, 459.0, 542.0, 615.0, 625.0, 629.0, 653.0, 669.0, 677.0, 716.0, 728.0, 751.0, 767.0, 772.0, 775.0, 857.0, 995.0, 1003.0, 1012.0], + [32.0, 34.0, 43.0, 70.0, 95.0, 130.0, 134.0, 139.0, 148.0, 150.0, 160.0, 163.0, 196.0, 257.0, 275.0, 302.0, 306.0, 322.0, 332.0, 354.0, 357.0, 364.0, 405.0, 432.0, 471.0, 472.0, 491.0, 516.0, 558.0, 563.0, 565.0, 577.0, 583.0, 584.0, 617.0, 626.0, 684.0, 725.0, 750.0, 768.0, 793.0, 794.0, 815.0, 821.0, 832.0, 869.0, 886.0, 894.0, 922.0, 938.0, 939.0, 968.0], + [30.0, 56.0, 59.0, 80.0, 109.0, 151.0, 159.0, 161.0, 164.0, 166.0, 191.0, 223.0, 309.0, 345.0, 378.0, 407.0, 434.0, 459.0, 470.0, 490.0, 585.0, 602.0, 634.0, 651.0, 713.0, 714.0, 779.0, 780.0, 807.0, 815.0, 829.0, 836.0, 857.0, 864.0, 898.0, 921.0, 926.0, 950.0, 969.0, 983.0, 989.0, 992.0], + [30.0, 31.0, 33.0, 63.0, 81.0, 100.0, 117.0, 128.0, 155.0, 157.0, 158.0, 192.0, 232.0, 283.0, 286.0, 295.0, 312.0, 319.0, 354.0, 362.0, 363.0, 369.0, 409.0, 452.0, 520.0, 578.0, 623.0, 624.0, 633.0, 656.0, 660.0, 681.0, 690.0, 693.0, 700.0, 715.0, 728.0, 744.0, 762.0, 781.0, 804.0, 815.0, 837.0, 867.0, 877.0, 944.0, 950.0, 957.0, 963.0, 970.0, 974.0], + [41.0, 48.0, 52.0, 91.0, 92.0, 152.0, 160.0, 163.0, 184.0, 185.0, 246.0, 251.0, 265.0, 268.0, 281.0, 294.0, 305.0, 312.0, 338.0, 346.0, 383.0, 407.0, 417.0, 437.0, 440.0, 448.0, 502.0, 510.0, 532.0, 541.0, 546.0, 573.0, 582.0, 607.0, 623.0, 742.0, 771.0, 785.0, 818.0, 828.0, 846.0, 896.0, 934.0, 965.0, 1005.0], + [34.0, 79.0, 111.0, 121.0, 133.0, 199.0, 207.0, 240.0, 243.0, 263.0, 295.0, 297.0, 330.0, 371.0, 378.0, 382.0, 419.0, 443.0, 469.0, 487.0, 492.0, 499.0, 509.0, 518.0, 525.0, 584.0, 598.0, 617.0, 624.0, 630.0, 634.0, 647.0, 651.0, 678.0, 691.0, 696.0, 703.0, 736.0, 772.0, 830.0, 840.0, 844.0, 858.0, 875.0, 1014.0], + [23.0, 51.0, 60.0, 131.0, 135.0, 147.0, 168.0, 171.0, 181.0, 184.0, 207.0, 210.0, 231.0, 270.0, 271.0, 285.0, 302.0, 309.0, 347.0, 356.0, 377.0, 385.0, 390.0, 396.0, 403.0, 436.0, 455.0, 468.0, 493.0, 515.0, 522.0, 533.0, 622.0, 653.0, 691.0, 692.0, 695.0, 710.0, 729.0, 736.0, 797.0, 800.0, 803.0, 815.0, 844.0, 848.0, 850.0, 859.0, 865.0, 878.0, 902.0, 924.0, 956.0, 967.0, 999.0, 1001.0, 1008.0, 1014.0], + [3.0, 38.0, 59.0, 74.0, 79.0, 81.0, 104.0, 116.0, 120.0, 129.0, 153.0, 170.0, 202.0, 217.0, 242.0, 244.0, 253.0, 254.0, 286.0, 287.0, 289.0, 350.0, 351.0, 390.0, 394.0, 403.0, 410.0, 433.0, 461.0, 464.0, 473.0, 476.0, 478.0, 491.0, 542.0, 543.0, 544.0, 586.0, 591.0, 595.0, 625.0, 627.0, 630.0, 659.0, 668.0, 676.0, 696.0, 702.0, 712.0, 733.0, 776.0, 777.0, 781.0, 782.0, 874.0, 877.0, 919.0, 990.0, 1006.0, 1007.0, 1010.0, 1016.0], + [4.0, 18.0, 40.0, 77.0, 119.0, 156.0, 160.0, 198.0, 243.0, 254.0, 269.0, 288.0, 311.0, 316.0, 347.0, 353.0, 354.0, 372.0, 373.0, 377.0, 413.0, 419.0, 466.0, 467.0, 471.0, 560.0, 566.0, 567.0, 579.0, 616.0, 644.0, 647.0, 667.0, 712.0, 713.0, 752.0, 753.0, 776.0, 783.0, 793.0, 812.0, 865.0, 881.0, 882.0, 884.0, 911.0, 912.0, 925.0, 941.0, 963.0, 978.0, 997.0, 1018.0], + [1.0, 32.0, 34.0, 60.0, 72.0, 95.0, 109.0, 116.0, 124.0, 165.0, 197.0, 205.0, 233.0, 243.0, 247.0, 258.0, 267.0, 274.0, 283.0, 302.0, 337.0, 350.0, 366.0, 368.0, 457.0, 462.0, 490.0, 492.0, 506.0, 571.0, 590.0, 603.0, 613.0, 712.0, 730.0, 736.0, 768.0, 788.0, 799.0, 803.0, 807.0, 808.0, 848.0, 854.0, 876.0, 878.0, 923.0, 958.0, 965.0], + [1.0, 78.0, 114.0, 119.0, 131.0, 155.0, 177.0, 198.0, 200.0, 202.0, 205.0, 241.0, 258.0, 272.0, 280.0, 288.0, 290.0, 291.0, 300.0, 323.0, 326.0, 328.0, 373.0, 375.0, 376.0, 380.0, 389.0, 390.0, 393.0, 403.0, 445.0, 456.0, 465.0, 476.0, 480.0, 481.0, 485.0, 507.0, 543.0, 563.0, 569.0, 597.0, 676.0, 707.0, 711.0, 734.0, 742.0, 777.0, 778.0, 783.0, 787.0, 802.0, 825.0, 830.0, 844.0, 858.0, 880.0, 932.0, 973.0, 1008.0, 1012.0, 1016.0], + [20.0, 23.0, 29.0, 47.0, 48.0, 51.0, 59.0, 143.0, 175.0, 176.0, 193.0, 197.0, 198.0, 202.0, 206.0, 224.0, 231.0, 232.0, 244.0, 283.0, 328.0, 330.0, 341.0, 345.0, 359.0, 361.0, 385.0, 422.0, 438.0, 449.0, 454.0, 465.0, 487.0, 490.0, 510.0, 528.0, 556.0, 580.0, 601.0, 602.0, 645.0, 651.0, 680.0, 693.0, 703.0, 704.0, 706.0, 716.0, 733.0, 782.0, 786.0, 821.0, 822.0, 829.0, 843.0, 855.0, 856.0, 875.0, 941.0, 951.0, 959.0, 990.0, 995.0], + [83.0, 110.0, 117.0, 128.0, 132.0, 154.0, 195.0, 214.0, 217.0, 234.0, 242.0, 252.0, 293.0, 338.0, 343.0, 352.0, 369.0, 412.0, 498.0, 499.0, 554.0, 566.0, 590.0, 603.0, 605.0, 606.0, 614.0, 669.0, 670.0, 671.0, 672.0, 677.0, 761.0, 767.0, 794.0, 832.0, 839.0, 869.0, 893.0, 913.0, 914.0, 915.0, 923.0, 936.0, 950.0, 1014.0], + [34.0, 100.0, 130.0, 138.0, 140.0, 172.0, 174.0, 282.0, 295.0, 303.0, 331.0, 349.0, 365.0, 376.0, 399.0, 408.0, 419.0, 515.0, 600.0, 615.0, 622.0, 626.0, 650.0, 672.0, 685.0, 700.0, 702.0, 742.0, 771.0, 849.0, 861.0, 882.0, 1019.0], + [10.0, 21.0, 67.0, 86.0, 151.0, 160.0, 187.0, 202.0, 225.0, 226.0, 237.0, 255.0, 260.0, 284.0, 300.0, 363.0, 393.0, 410.0, 435.0, 460.0, 463.0, 523.0, 528.0, 577.0, 586.0, 605.0, 611.0, 617.0, 625.0, 627.0, 639.0, 642.0, 651.0, 653.0, 698.0, 701.0, 724.0, 728.0, 729.0, 775.0, 785.0, 793.0, 844.0, 847.0, 865.0, 876.0, 890.0, 907.0, 931.0, 936.0, 961.0, 997.0, 1002.0, 1003.0, 1009.0, 1011.0], + [5.0, 13.0, 25.0, 56.0, 64.0, 65.0, 66.0, 85.0, 111.0, 120.0, 134.0, 152.0, 153.0, 168.0, 170.0, 172.0, 185.0, 199.0, 207.0, 222.0, 233.0, 234.0, 242.0, 255.0, 262.0, 309.0, 333.0, 352.0, 394.0, 395.0, 403.0, 417.0, 429.0, 452.0, 462.0, 463.0, 476.0, 482.0, 501.0, 529.0, 533.0, 534.0, 544.0, 589.0, 595.0, 599.0, 636.0, 652.0, 690.0, 692.0, 743.0, 773.0, 777.0, 840.0, 844.0, 845.0, 872.0, 878.0, 900.0, 982.0, 984.0, 997.0], + [18.0, 100.0, 113.0, 157.0, 160.0, 161.0, 166.0, 168.0, 177.0, 231.0, 234.0, 235.0, 260.0, 302.0, 363.0, 373.0, 377.0, 414.0, 422.0, 445.0, 446.0, 491.0, 508.0, 520.0, 523.0, 547.0, 553.0, 561.0, 599.0, 603.0, 665.0, 714.0, 724.0, 739.0, 741.0, 758.0, 785.0, 860.0, 874.0, 911.0, 963.0, 974.0, 979.0, 980.0, 983.0, 990.0], + [18.0, 37.0, 46.0, 88.0, 121.0, 134.0, 166.0, 198.0, 202.0, 206.0, 210.0, 220.0, 229.0, 249.0, 269.0, 301.0, 364.0, 467.0, 474.0, 482.0, 509.0, 546.0, 579.0, 603.0, 632.0, 641.0, 656.0, 750.0, 763.0, 767.0, 791.0, 828.0, 838.0, 861.0, 890.0, 895.0, 929.0, 955.0, 991.0], + [14.0, 27.0, 48.0, 65.0, 71.0, 72.0, 75.0, 78.0, 99.0, 152.0, 163.0, 183.0, 317.0, 326.0, 336.0, 379.0, 421.0, 460.0, 532.0, 533.0, 547.0, 575.0, 661.0, 680.0, 709.0, 722.0, 744.0, 805.0, 814.0, 816.0, 820.0, 826.0, 827.0, 828.0, 849.0, 853.0, 862.0, 939.0, 943.0, 944.0, 960.0], + [10.0, 27.0, 30.0, 31.0, 32.0, 89.0, 105.0, 110.0, 112.0, 130.0, 155.0, 161.0, 174.0, 221.0, 286.0, 302.0, 326.0, 360.0, 370.0, 378.0, 385.0, 387.0, 394.0, 411.0, 412.0, 423.0, 435.0, 440.0, 460.0, 472.0, 537.0, 538.0, 539.0, 541.0, 548.0, 556.0, 602.0, 619.0, 691.0, 698.0, 737.0, 744.0, 801.0, 814.0, 825.0, 836.0, 838.0, 843.0, 894.0, 909.0, 916.0, 925.0, 929.0, 946.0, 952.0, 953.0, 959.0, 984.0], + [1.0, 9.0, 31.0, 42.0, 65.0, 91.0, 109.0, 171.0, 196.0, 198.0, 203.0, 277.0, 295.0, 313.0, 340.0, 381.0, 397.0, 408.0, 425.0, 469.0, 488.0, 490.0, 505.0, 506.0, 525.0, 559.0, 597.0, 660.0, 705.0, 715.0, 718.0, 764.0, 799.0, 820.0, 893.0, 904.0, 914.0, 978.0, 981.0], + [50.0, 64.0, 90.0, 152.0, 160.0, 164.0, 180.0, 205.0, 231.0, 272.0, 284.0, 339.0, 350.0, 351.0, 374.0, 458.0, 483.0, 488.0, 592.0, 605.0, 612.0, 627.0, 639.0, 651.0, 667.0, 687.0, 711.0, 776.0, 781.0, 817.0, 820.0, 839.0, 876.0, 886.0, 888.0, 898.0, 899.0, 912.0, 921.0, 939.0, 944.0, 981.0], + [24.0, 27.0, 37.0, 42.0, 107.0, 112.0, 125.0, 136.0, 158.0, 176.0, 178.0, 185.0, 275.0, 277.0, 278.0, 350.0, 364.0, 375.0, 393.0, 395.0, 421.0, 430.0, 462.0, 504.0, 505.0, 520.0, 541.0, 555.0, 573.0, 579.0, 589.0, 602.0, 661.0, 672.0, 709.0, 729.0, 744.0, 760.0, 770.0, 778.0, 800.0, 831.0, 832.0, 885.0, 899.0, 951.0, 964.0, 971.0, 974.0, 992.0], + [34.0, 60.0, 84.0, 86.0, 94.0, 109.0, 110.0, 142.0, 154.0, 180.0, 185.0, 198.0, 249.0, 250.0, 268.0, 271.0, 286.0, 299.0, 319.0, 357.0, 395.0, 418.0, 423.0, 424.0, 432.0, 433.0, 447.0, 538.0, 542.0, 554.0, 556.0, 568.0, 584.0, 615.0, 642.0, 684.0, 692.0, 715.0, 721.0, 728.0, 737.0, 747.0, 750.0, 753.0, 758.0, 768.0, 774.0, 808.0, 831.0, 906.0, 937.0, 960.0, 967.0, 986.0, 1014.0], + [59.0, 84.0, 86.0, 91.0, 93.0, 101.0, 125.0, 127.0, 130.0, 161.0, 164.0, 165.0, 166.0, 171.0, 174.0, 197.0, 199.0, 254.0, 258.0, 303.0, 306.0, 309.0, 322.0, 342.0, 353.0, 364.0, 366.0, 367.0, 387.0, 448.0, 471.0, 490.0, 502.0, 513.0, 531.0, 575.0, 597.0, 615.0, 635.0, 650.0, 651.0, 684.0, 694.0, 702.0, 742.0, 782.0, 797.0, 818.0, 839.0, 859.0, 884.0, 903.0, 909.0, 924.0, 927.0, 944.0, 945.0, 973.0, 978.0, 984.0, 998.0], + [31.0, 53.0, 77.0, 85.0, 97.0, 153.0, 158.0, 159.0, 182.0, 204.0, 261.0, 293.0, 318.0, 398.0, 404.0, 424.0, 446.0, 480.0, 486.0, 497.0, 500.0, 520.0, 553.0, 559.0, 562.0, 576.0, 593.0, 640.0, 652.0, 670.0, 679.0, 702.0, 719.0, 721.0, 735.0, 793.0, 833.0, 862.0, 941.0, 952.0], + [42.0, 57.0, 66.0, 80.0, 83.0, 113.0, 114.0, 115.0, 124.0, 144.0, 147.0, 163.0, 169.0, 179.0, 189.0, 203.0, 237.0, 247.0, 257.0, 317.0, 346.0, 349.0, 354.0, 374.0, 389.0, 415.0, 438.0, 446.0, 503.0, 514.0, 515.0, 554.0, 575.0, 608.0, 609.0, 657.0, 666.0, 675.0, 684.0, 703.0, 780.0, 793.0, 803.0, 834.0, 849.0, 924.0, 938.0, 943.0, 951.0, 1005.0, 1019.0], + [8.0, 10.0, 11.0, 17.0, 20.0, 21.0, 47.0, 50.0, 97.0, 110.0, 148.0, 161.0, 169.0, 174.0, 202.0, 205.0, 226.0, 320.0, 345.0, 346.0, 358.0, 364.0, 365.0, 386.0, 391.0, 424.0, 432.0, 435.0, 540.0, 542.0, 587.0, 612.0, 648.0, 707.0, 745.0, 758.0, 765.0, 774.0, 808.0, 814.0, 818.0, 906.0, 909.0, 911.0, 914.0, 919.0, 943.0, 944.0, 956.0, 972.0, 982.0, 1019.0], + [8.0, 11.0, 98.0, 99.0, 113.0, 121.0, 124.0, 164.0, 165.0, 227.0, 228.0, 238.0, 245.0, 279.0, 282.0, 289.0, 310.0, 313.0, 345.0, 369.0, 408.0, 416.0, 478.0, 505.0, 515.0, 542.0, 550.0, 551.0, 613.0, 648.0, 669.0, 678.0, 687.0, 702.0, 715.0, 726.0, 728.0, 738.0, 755.0, 759.0, 787.0, 795.0, 797.0, 830.0, 835.0, 905.0, 950.0, 983.0], + [2.0, 21.0, 27.0, 87.0, 103.0, 136.0, 149.0, 155.0, 156.0, 168.0, 239.0, 249.0, 262.0, 293.0, 304.0, 328.0, 332.0, 341.0, 409.0, 417.0, 420.0, 421.0, 427.0, 435.0, 454.0, 456.0, 462.0, 473.0, 573.0, 590.0, 608.0, 627.0, 629.0, 674.0, 690.0, 697.0, 745.0, 774.0, 791.0, 803.0, 808.0, 815.0, 870.0, 891.0, 896.0, 919.0, 931.0, 946.0, 950.0, 958.0, 977.0, 1001.0, 1003.0, 1015.0], + [1.0, 23.0, 34.0, 93.0, 96.0, 98.0, 107.0, 109.0, 183.0, 188.0, 200.0, 201.0, 218.0, 231.0, 233.0, 247.0, 297.0, 334.0, 338.0, 355.0, 361.0, 369.0, 382.0, 402.0, 415.0, 468.0, 479.0, 505.0, 546.0, 554.0, 561.0, 563.0, 594.0, 603.0, 642.0, 709.0, 710.0, 723.0, 778.0, 819.0, 825.0, 845.0, 858.0, 881.0, 887.0, 930.0, 965.0, 1009.0, 1023.0], + [12.0, 32.0, 59.0, 98.0, 110.0, 137.0, 167.0, 174.0, 175.0, 224.0, 247.0, 318.0, 326.0, 400.0, 402.0, 403.0, 413.0, 440.0, 455.0, 471.0, 499.0, 500.0, 513.0, 544.0, 552.0, 587.0, 591.0, 601.0, 616.0, 623.0, 625.0, 642.0, 660.0, 662.0, 685.0, 769.0, 778.0, 794.0, 827.0, 870.0, 878.0, 885.0, 974.0, 980.0, 1011.0, 1013.0, 1015.0], + [5.0, 52.0, 116.0, 120.0, 134.0, 159.0, 171.0, 174.0, 188.0, 190.0, 194.0, 217.0, 239.0, 254.0, 320.0, 321.0, 346.0, 361.0, 369.0, 371.0, 413.0, 421.0, 435.0, 439.0, 440.0, 441.0, 462.0, 468.0, 471.0, 473.0, 500.0, 512.0, 553.0, 554.0, 590.0, 591.0, 603.0, 621.0, 648.0, 683.0, 708.0, 742.0, 759.0, 812.0, 820.0, 844.0, 853.0, 875.0, 895.0, 905.0, 986.0, 998.0, 1010.0], + [7.0, 17.0, 26.0, 34.0, 48.0, 63.0, 70.0, 87.0, 140.0, 155.0, 156.0, 180.0, 220.0, 224.0, 272.0, 284.0, 291.0, 310.0, 335.0, 340.0, 342.0, 345.0, 353.0, 364.0, 419.0, 448.0, 460.0, 461.0, 518.0, 527.0, 531.0, 534.0, 544.0, 563.0, 584.0, 613.0, 614.0, 645.0, 655.0, 661.0, 666.0, 673.0, 689.0, 827.0, 859.0, 876.0, 888.0, 893.0, 956.0, 967.0, 968.0, 987.0, 1001.0], + [35.0, 46.0, 59.0, 61.0, 64.0, 73.0, 95.0, 110.0, 118.0, 171.0, 196.0, 214.0, 225.0, 294.0, 296.0, 298.0, 360.0, 393.0, 407.0, 411.0, 412.0, 418.0, 445.0, 484.0, 507.0, 554.0, 608.0, 619.0, 628.0, 638.0, 690.0, 744.0, 820.0, 886.0, 897.0, 925.0, 930.0, 959.0, 984.0, 991.0, 1006.0], + [36.0, 37.0, 44.0, 57.0, 59.0, 69.0, 85.0, 103.0, 142.0, 143.0, 144.0, 145.0, 401.0, 474.0, 479.0, 539.0, 543.0, 546.0, 562.0, 583.0, 632.0, 655.0, 694.0, 723.0, 759.0, 771.0, 772.0, 775.0, 796.0, 801.0, 834.0, 838.0, 902.0, 903.0, 980.0, 1022.0], + [8.0, 13.0, 38.0, 56.0, 81.0, 86.0, 104.0, 128.0, 156.0, 230.0, 236.0, 252.0, 307.0, 336.0, 348.0, 352.0, 357.0, 373.0, 374.0, 389.0, 404.0, 414.0, 428.0, 437.0, 449.0, 498.0, 503.0, 590.0, 592.0, 594.0, 652.0, 675.0, 679.0, 699.0, 701.0, 712.0, 728.0, 733.0, 789.0, 814.0, 826.0, 858.0, 861.0, 877.0, 886.0, 896.0, 912.0, 954.0, 984.0, 1002.0, 1021.0], + [43.0, 45.0, 46.0, 128.0, 147.0, 153.0, 154.0, 165.0, 231.0, 235.0, 238.0, 256.0, 318.0, 323.0, 350.0, 381.0, 384.0, 502.0, 517.0, 570.0, 575.0, 591.0, 609.0, 618.0, 622.0, 649.0, 655.0, 667.0, 672.0, 673.0, 722.0, 782.0, 794.0, 825.0, 849.0, 867.0, 868.0, 874.0, 892.0, 933.0, 935.0, 976.0, 982.0, 987.0, 1008.0, 1016.0], + [32.0, 42.0, 90.0, 109.0, 127.0, 141.0, 156.0, 163.0, 164.0, 179.0, 199.0, 215.0, 227.0, 230.0, 264.0, 296.0, 300.0, 328.0, 338.0, 363.0, 366.0, 406.0, 407.0, 408.0, 409.0, 426.0, 531.0, 546.0, 562.0, 588.0, 625.0, 654.0, 676.0, 679.0, 695.0, 709.0, 710.0, 771.0, 791.0, 801.0, 838.0, 845.0, 867.0, 869.0, 879.0, 880.0, 881.0, 932.0, 961.0, 984.0, 1017.0], + [3.0, 21.0, 35.0, 38.0, 40.0, 70.0, 75.0, 86.0, 138.0, 141.0, 167.0, 176.0, 188.0, 209.0, 220.0, 240.0, 243.0, 306.0, 329.0, 356.0, 357.0, 392.0, 406.0, 427.0, 428.0, 446.0, 449.0, 451.0, 483.0, 613.0, 629.0, 647.0, 648.0, 667.0, 712.0, 730.0, 733.0, 784.0, 906.0, 909.0, 948.0, 949.0, 969.0, 973.0, 984.0, 1018.0, 1022.0], + [21.0, 28.0, 47.0, 56.0, 107.0, 114.0, 126.0, 164.0, 178.0, 179.0, 190.0, 204.0, 227.0, 231.0, 242.0, 261.0, 303.0, 350.0, 362.0, 386.0, 425.0, 440.0, 471.0, 482.0, 509.0, 599.0, 603.0, 634.0, 646.0, 693.0, 709.0, 755.0, 799.0, 811.0, 848.0, 922.0, 923.0, 924.0, 928.0, 948.0, 975.0, 1011.0, 1018.0], + [88.0, 132.0, 161.0, 194.0, 206.0, 211.0, 247.0, 270.0, 296.0, 312.0, 331.0, 333.0, 334.0, 373.0, 429.0, 430.0, 436.0, 471.0, 494.0, 523.0, 530.0, 531.0, 536.0, 574.0, 620.0, 655.0, 676.0, 677.0, 709.0, 727.0, 738.0, 776.0, 783.0, 799.0, 805.0, 840.0, 875.0, 896.0, 910.0, 932.0, 939.0, 954.0, 1000.0], + [9.0, 26.0, 33.0, 40.0, 48.0, 65.0, 72.0, 74.0, 104.0, 105.0, 106.0, 107.0, 124.0, 134.0, 189.0, 195.0, 218.0, 228.0, 232.0, 271.0, 283.0, 341.0, 352.0, 354.0, 374.0, 393.0, 414.0, 417.0, 424.0, 435.0, 443.0, 456.0, 458.0, 524.0, 525.0, 574.0, 592.0, 605.0, 617.0, 620.0, 632.0, 641.0, 695.0, 791.0, 792.0, 811.0, 862.0, 943.0, 967.0, 975.0, 985.0, 1011.0], + [45.0, 76.0, 164.0, 258.0, 310.0, 340.0, 346.0, 349.0, 363.0, 383.0, 396.0, 424.0, 446.0, 468.0, 471.0, 516.0, 544.0, 550.0, 571.0, 595.0, 686.0, 750.0, 758.0, 775.0, 782.0, 799.0, 831.0, 832.0, 864.0, 876.0, 883.0, 896.0, 939.0, 941.0, 972.0, 976.0, 1008.0], + [43.0, 48.0, 63.0, 78.0, 86.0, 96.0, 166.0, 170.0, 175.0, 195.0, 224.0, 248.0, 263.0, 270.0, 271.0, 279.0, 292.0, 355.0, 395.0, 405.0, 406.0, 423.0, 442.0, 453.0, 454.0, 458.0, 471.0, 482.0, 484.0, 490.0, 504.0, 510.0, 563.0, 604.0, 606.0, 620.0, 644.0, 652.0, 656.0, 716.0, 727.0, 730.0, 744.0, 792.0, 797.0, 802.0, 807.0, 816.0, 837.0, 846.0, 850.0, 851.0, 856.0, 897.0, 898.0, 901.0, 929.0, 932.0, 951.0, 952.0, 974.0], + [15.0, 18.0, 28.0, 57.0, 61.0, 64.0, 65.0, 112.0, 134.0, 170.0, 179.0, 186.0, 212.0, 213.0, 275.0, 280.0, 318.0, 339.0, 369.0, 380.0, 382.0, 384.0, 415.0, 427.0, 444.0, 454.0, 455.0, 457.0, 490.0, 492.0, 499.0, 504.0, 509.0, 510.0, 516.0, 519.0, 537.0, 601.0, 603.0, 615.0, 622.0, 689.0, 692.0, 710.0, 711.0, 712.0, 727.0, 752.0, 764.0, 788.0, 789.0, 790.0, 814.0, 852.0, 860.0, 866.0, 889.0, 936.0, 948.0, 950.0, 964.0, 996.0, 1007.0], + [10.0, 33.0, 44.0, 132.0, 156.0, 166.0, 192.0, 198.0, 227.0, 231.0, 246.0, 258.0, 264.0, 276.0, 372.0, 389.0, 396.0, 434.0, 449.0, 451.0, 464.0, 490.0, 502.0, 524.0, 531.0, 567.0, 587.0, 615.0, 641.0, 651.0, 686.0, 700.0, 708.0, 786.0, 790.0, 803.0, 808.0, 850.0, 864.0, 871.0, 913.0, 934.0, 944.0, 993.0, 1012.0], + [4.0, 5.0, 13.0, 25.0, 127.0, 143.0, 152.0, 172.0, 173.0, 184.0, 188.0, 217.0, 307.0, 318.0, 327.0, 334.0, 337.0, 353.0, 373.0, 388.0, 393.0, 399.0, 422.0, 490.0, 518.0, 564.0, 668.0, 706.0, 726.0, 737.0, 751.0, 760.0, 794.0, 804.0, 806.0, 828.0, 858.0, 865.0, 883.0, 953.0, 962.0, 965.0, 969.0, 971.0, 988.0], + [3.0, 44.0, 67.0, 98.0, 141.0, 180.0, 188.0, 190.0, 233.0, 236.0, 255.0, 274.0, 322.0, 342.0, 347.0, 366.0, 597.0, 606.0, 650.0, 691.0, 695.0, 758.0, 759.0, 814.0, 815.0, 824.0, 839.0, 857.0, 859.0, 860.0, 902.0, 913.0, 915.0, 921.0, 925.0, 927.0, 947.0, 964.0], + [7.0, 22.0, 37.0, 38.0, 46.0, 88.0, 91.0, 100.0, 107.0, 108.0, 134.0, 164.0, 179.0, 183.0, 184.0, 199.0, 218.0, 236.0, 255.0, 260.0, 297.0, 301.0, 309.0, 317.0, 328.0, 333.0, 338.0, 348.0, 359.0, 410.0, 412.0, 479.0, 490.0, 516.0, 517.0, 578.0, 639.0, 644.0, 653.0, 700.0, 705.0, 707.0, 719.0, 733.0, 746.0, 756.0, 766.0, 776.0, 831.0, 857.0, 896.0, 902.0, 923.0, 955.0, 1001.0, 1004.0, 1009.0, 1012.0], + [17.0, 29.0, 71.0, 72.0, 82.0, 93.0, 94.0, 96.0, 99.0, 101.0, 123.0, 129.0, 155.0, 186.0, 188.0, 189.0, 275.0, 303.0, 313.0, 335.0, 352.0, 364.0, 365.0, 366.0, 393.0, 400.0, 408.0, 427.0, 431.0, 440.0, 441.0, 448.0, 476.0, 508.0, 537.0, 553.0, 568.0, 642.0, 668.0, 684.0, 685.0, 737.0, 755.0, 758.0, 796.0, 797.0, 829.0, 851.0, 865.0, 906.0, 950.0, 961.0, 982.0, 992.0, 995.0, 1006.0, 1016.0, 1021.0], + [24.0, 36.0, 42.0, 55.0, 93.0, 196.0, 213.0, 235.0, 237.0, 258.0, 272.0, 277.0, 363.0, 395.0, 431.0, 478.0, 523.0, 529.0, 534.0, 543.0, 557.0, 582.0, 588.0, 597.0, 607.0, 631.0, 649.0, 651.0, 656.0, 688.0, 690.0, 693.0, 700.0, 722.0, 734.0, 804.0, 819.0, 837.0, 855.0, 870.0, 899.0, 900.0, 954.0, 957.0, 979.0, 986.0, 1012.0, 1016.0], + [59.0, 112.0, 144.0, 158.0, 162.0, 207.0, 210.0, 241.0, 269.0, 275.0, 286.0, 298.0, 382.0, 400.0, 412.0, 428.0, 492.0, 590.0, 597.0, 598.0, 618.0, 627.0, 706.0, 741.0, 745.0, 797.0, 828.0, 834.0, 875.0, 897.0, 898.0, 899.0, 929.0, 965.0, 997.0, 1010.0, 1017.0, 1022.0], + [1.0, 23.0, 28.0, 37.0, 42.0, 54.0, 68.0, 76.0, 99.0, 128.0, 129.0, 163.0, 193.0, 206.0, 252.0, 256.0, 316.0, 358.0, 376.0, 499.0, 500.0, 510.0, 529.0, 548.0, 555.0, 558.0, 559.0, 563.0, 571.0, 579.0, 595.0, 618.0, 620.0, 626.0, 653.0, 692.0, 702.0, 712.0, 716.0, 827.0, 852.0, 863.0, 922.0, 943.0, 968.0, 979.0, 980.0, 981.0, 982.0, 984.0, 1000.0], + [23.0, 42.0, 61.0, 86.0, 88.0, 89.0, 99.0, 124.0, 128.0, 137.0, 144.0, 162.0, 170.0, 195.0, 196.0, 230.0, 234.0, 330.0, 348.0, 355.0, 371.0, 386.0, 401.0, 413.0, 417.0, 437.0, 590.0, 624.0, 640.0, 644.0, 648.0, 660.0, 674.0, 715.0, 737.0, 769.0, 781.0, 796.0, 819.0, 820.0, 822.0, 853.0, 854.0, 912.0, 956.0, 986.0, 997.0, 1022.0], + [8.0, 63.0, 64.0, 65.0, 82.0, 84.0, 135.0, 196.0, 230.0, 235.0, 237.0, 272.0, 304.0, 352.0, 383.0, 407.0, 425.0, 429.0, 438.0, 440.0, 448.0, 478.0, 485.0, 488.0, 522.0, 552.0, 561.0, 578.0, 595.0, 621.0, 640.0, 661.0, 670.0, 671.0, 674.0, 751.0, 771.0, 772.0, 785.0, 815.0, 900.0, 915.0, 918.0, 921.0, 960.0], + [6.0, 28.0, 29.0, 39.0, 54.0, 55.0, 74.0, 88.0, 172.0, 182.0, 185.0, 190.0, 193.0, 199.0, 205.0, 210.0, 215.0, 226.0, 228.0, 229.0, 254.0, 258.0, 266.0, 269.0, 293.0, 295.0, 300.0, 313.0, 321.0, 369.0, 379.0, 387.0, 412.0, 416.0, 419.0, 452.0, 464.0, 491.0, 496.0, 502.0, 535.0, 544.0, 588.0, 616.0, 645.0, 666.0, 702.0, 706.0, 723.0, 749.0, 835.0, 839.0, 847.0, 850.0, 873.0, 896.0, 899.0, 952.0, 953.0, 959.0, 965.0, 992.0, 998.0, 1000.0, 1004.0], + [10.0, 31.0, 68.0, 70.0, 78.0, 98.0, 125.0, 141.0, 149.0, 151.0, 264.0, 268.0, 305.0, 341.0, 346.0, 414.0, 433.0, 485.0, 511.0, 544.0, 549.0, 561.0, 622.0, 647.0, 652.0, 666.0, 688.0, 706.0, 720.0, 769.0, 775.0, 784.0, 787.0, 788.0, 796.0, 845.0, 846.0, 847.0, 889.0, 914.0, 934.0, 985.0, 992.0, 997.0], + [4.0, 5.0, 18.0, 50.0, 135.0, 138.0, 139.0, 176.0, 179.0, 185.0, 190.0, 218.0, 229.0, 235.0, 322.0, 345.0, 346.0, 370.0, 404.0, 419.0, 436.0, 484.0, 509.0, 522.0, 531.0, 534.0, 536.0, 574.0, 584.0, 587.0, 618.0, 626.0, 637.0, 642.0, 643.0, 647.0, 660.0, 682.0, 698.0, 724.0, 769.0, 777.0, 778.0, 799.0, 825.0, 826.0, 832.0, 836.0, 839.0, 869.0, 870.0, 900.0, 924.0, 953.0, 975.0, 984.0], + [5.0, 55.0, 78.0, 154.0, 157.0, 196.0, 199.0, 205.0, 249.0, 265.0, 266.0, 279.0, 286.0, 323.0, 348.0, 366.0, 375.0, 386.0, 395.0, 415.0, 419.0, 425.0, 440.0, 453.0, 532.0, 553.0, 560.0, 566.0, 585.0, 617.0, 660.0, 680.0, 690.0, 741.0, 743.0, 760.0, 774.0, 777.0, 782.0, 814.0, 829.0, 902.0, 957.0, 987.0], + [19.0, 49.0, 87.0, 133.0, 135.0, 187.0, 192.0, 225.0, 233.0, 260.0, 261.0, 293.0, 310.0, 337.0, 368.0, 371.0, 375.0, 447.0, 449.0, 470.0, 486.0, 487.0, 504.0, 509.0, 523.0, 525.0, 527.0, 639.0, 689.0, 690.0, 697.0, 746.0, 781.0, 787.0, 826.0, 844.0, 850.0, 896.0, 920.0, 950.0, 953.0, 1006.0, 1014.0, 1019.0], + [35.0, 37.0, 71.0, 89.0, 113.0, 123.0, 132.0, 135.0, 171.0, 192.0, 215.0, 237.0, 270.0, 280.0, 304.0, 319.0, 328.0, 364.0, 380.0, 423.0, 459.0, 475.0, 485.0, 493.0, 536.0, 544.0, 557.0, 706.0, 753.0, 756.0, 764.0, 788.0, 789.0, 796.0, 797.0, 863.0, 866.0, 878.0, 903.0, 938.0, 977.0], + [10.0, 26.0, 49.0, 64.0, 74.0, 104.0, 105.0, 151.0, 180.0, 209.0, 231.0, 243.0, 258.0, 278.0, 291.0, 323.0, 332.0, 415.0, 419.0, 423.0, 427.0, 487.0, 491.0, 494.0, 505.0, 520.0, 538.0, 555.0, 566.0, 580.0, 582.0, 633.0, 638.0, 650.0, 667.0, 670.0, 681.0, 696.0, 718.0, 719.0, 731.0, 752.0, 782.0, 818.0, 906.0, 923.0, 929.0, 945.0, 946.0, 951.0, 952.0, 958.0, 967.0, 968.0, 969.0, 1016.0], + [15.0, 20.0, 53.0, 62.0, 68.0, 83.0, 92.0, 108.0, 116.0, 117.0, 124.0, 164.0, 180.0, 192.0, 217.0, 245.0, 247.0, 281.0, 282.0, 288.0, 291.0, 327.0, 374.0, 389.0, 421.0, 429.0, 433.0, 480.0, 498.0, 501.0, 522.0, 537.0, 539.0, 569.0, 576.0, 628.0, 682.0, 683.0, 696.0, 752.0, 754.0, 765.0, 778.0, 798.0, 823.0, 852.0, 868.0, 875.0, 885.0, 890.0, 903.0, 937.0, 945.0, 954.0, 961.0, 983.0], + [5.0, 13.0, 49.0, 65.0, 145.0, 149.0, 150.0, 184.0, 200.0, 218.0, 223.0, 238.0, 253.0, 273.0, 278.0, 287.0, 294.0, 361.0, 417.0, 451.0, 478.0, 498.0, 557.0, 592.0, 660.0, 678.0, 688.0, 710.0, 769.0, 773.0, 803.0, 827.0, 857.0, 881.0, 897.0, 908.0, 955.0, 956.0, 974.0], + [44.0, 59.0, 67.0, 97.0, 117.0, 150.0, 165.0, 168.0, 175.0, 186.0, 215.0, 227.0, 231.0, 288.0, 294.0, 306.0, 333.0, 334.0, 341.0, 365.0, 380.0, 399.0, 427.0, 455.0, 458.0, 503.0, 524.0, 536.0, 542.0, 548.0, 549.0, 557.0, 582.0, 594.0, 606.0, 608.0, 644.0, 652.0, 660.0, 671.0, 702.0, 706.0, 722.0, 754.0, 792.0, 827.0, 832.0, 848.0, 880.0, 911.0, 923.0, 925.0, 934.0, 956.0, 960.0, 980.0, 985.0, 1016.0], + [26.0, 74.0, 75.0, 76.0, 92.0, 121.0, 122.0, 169.0, 178.0, 187.0, 197.0, 200.0, 223.0, 238.0, 303.0, 323.0, 365.0, 369.0, 406.0, 433.0, 478.0, 479.0, 491.0, 497.0, 501.0, 503.0, 531.0, 544.0, 552.0, 575.0, 619.0, 632.0, 648.0, 658.0, 664.0, 730.0, 744.0, 748.0, 757.0, 791.0, 816.0, 819.0, 831.0, 847.0, 856.0, 869.0, 873.0, 887.0, 903.0, 944.0, 964.0, 983.0, 996.0, 1023.0], + [2.0, 4.0, 7.0, 28.0, 36.0, 67.0, 84.0, 93.0, 125.0, 143.0, 156.0, 201.0, 225.0, 233.0, 271.0, 293.0, 296.0, 310.0, 314.0, 323.0, 325.0, 342.0, 398.0, 400.0, 423.0, 444.0, 456.0, 460.0, 476.0, 479.0, 492.0, 531.0, 532.0, 550.0, 569.0, 586.0, 628.0, 651.0, 658.0, 700.0, 739.0, 777.0, 800.0, 804.0, 806.0, 811.0, 885.0, 892.0, 907.0, 939.0, 957.0, 969.0, 983.0, 1000.0, 1003.0], + [23.0, 24.0, 58.0, 77.0, 96.0, 127.0, 165.0, 170.0, 206.0, 214.0, 231.0, 241.0, 253.0, 328.0, 355.0, 377.0, 382.0, 415.0, 435.0, 448.0, 483.0, 485.0, 526.0, 537.0, 554.0, 573.0, 577.0, 582.0, 601.0, 652.0, 704.0, 710.0, 717.0, 725.0, 731.0, 735.0, 750.0, 807.0, 837.0, 839.0, 846.0, 880.0, 915.0, 947.0], + [7.0, 22.0, 29.0, 68.0, 111.0, 125.0, 147.0, 149.0, 189.0, 192.0, 198.0, 212.0, 231.0, 237.0, 238.0, 269.0, 310.0, 332.0, 338.0, 354.0, 383.0, 405.0, 407.0, 413.0, 419.0, 424.0, 428.0, 435.0, 437.0, 441.0, 444.0, 453.0, 471.0, 489.0, 514.0, 561.0, 580.0, 583.0, 620.0, 627.0, 659.0, 670.0, 671.0, 673.0, 685.0, 700.0, 716.0, 725.0, 737.0, 749.0, 762.0, 773.0, 782.0, 819.0, 860.0, 863.0, 887.0, 905.0, 912.0, 924.0, 934.0, 953.0, 960.0, 1003.0, 1014.0], + [3.0, 31.0, 52.0, 58.0, 59.0, 96.0, 105.0, 118.0, 122.0, 126.0, 133.0, 135.0, 140.0, 144.0, 147.0, 175.0, 199.0, 215.0, 242.0, 258.0, 304.0, 322.0, 364.0, 380.0, 384.0, 385.0, 389.0, 390.0, 399.0, 421.0, 442.0, 451.0, 479.0, 498.0, 501.0, 512.0, 528.0, 547.0, 581.0, 586.0, 590.0, 652.0, 653.0, 654.0, 668.0, 685.0, 689.0, 705.0, 726.0, 762.0, 803.0, 808.0, 809.0, 835.0, 842.0, 874.0, 910.0, 914.0, 968.0, 978.0, 993.0, 1007.0, 1008.0, 1016.0, 1022.0], + [2.0, 8.0, 16.0, 21.0, 26.0, 47.0, 52.0, 89.0, 126.0, 135.0, 143.0, 147.0, 172.0, 195.0, 227.0, 235.0, 242.0, 251.0, 337.0, 344.0, 350.0, 358.0, 371.0, 375.0, 383.0, 387.0, 411.0, 421.0, 440.0, 441.0, 470.0, 475.0, 549.0, 552.0, 554.0, 555.0, 573.0, 574.0, 587.0, 603.0, 633.0, 667.0, 713.0, 726.0, 735.0, 741.0, 755.0, 756.0, 766.0, 789.0, 802.0, 803.0, 818.0, 821.0, 824.0, 845.0, 855.0, 895.0, 919.0, 926.0, 927.0, 930.0, 940.0], + [35.0, 38.0, 53.0, 58.0, 65.0, 90.0, 103.0, 174.0, 176.0, 239.0, 245.0, 269.0, 290.0, 366.0, 375.0, 396.0, 428.0, 453.0, 472.0, 490.0, 519.0, 586.0, 618.0, 687.0, 701.0, 726.0, 728.0, 747.0, 764.0, 767.0, 794.0, 851.0, 986.0], + [27.0, 41.0, 49.0, 50.0, 54.0, 108.0, 122.0, 152.0, 154.0, 158.0, 182.0, 221.0, 250.0, 256.0, 275.0, 288.0, 305.0, 328.0, 370.0, 379.0, 419.0, 423.0, 470.0, 492.0, 523.0, 524.0, 540.0, 542.0, 612.0, 642.0, 663.0, 675.0, 699.0, 701.0, 759.0, 770.0, 777.0, 785.0, 799.0, 804.0, 867.0, 879.0, 890.0, 895.0, 930.0, 937.0, 946.0, 967.0, 968.0, 975.0, 976.0, 1008.0, 1022.0], + [52.0, 55.0, 58.0, 90.0, 129.0, 136.0, 172.0, 192.0, 234.0, 235.0, 241.0, 244.0, 247.0, 308.0, 371.0, 413.0, 414.0, 473.0, 484.0, 497.0, 507.0, 519.0, 622.0, 648.0, 659.0, 687.0, 696.0, 746.0, 781.0, 801.0, 914.0, 931.0, 966.0, 971.0, 999.0], + [9.0, 24.0, 47.0, 50.0, 79.0, 106.0, 121.0, 132.0, 150.0, 154.0, 173.0, 183.0, 200.0, 217.0, 233.0, 276.0, 283.0, 320.0, 356.0, 357.0, 362.0, 385.0, 396.0, 405.0, 407.0, 445.0, 488.0, 540.0, 542.0, 550.0, 554.0, 579.0, 603.0, 608.0, 624.0, 636.0, 684.0, 776.0, 779.0, 792.0, 817.0, 820.0, 834.0, 846.0, 847.0, 860.0, 914.0, 918.0, 922.0, 925.0, 950.0, 958.0, 976.0, 995.0, 1022.0], + [47.0, 49.0, 54.0, 60.0, 66.0, 98.0, 150.0, 152.0, 153.0, 203.0, 220.0, 233.0, 261.0, 286.0, 300.0, 308.0, 419.0, 468.0, 490.0, 541.0, 555.0, 559.0, 561.0, 607.0, 655.0, 666.0, 672.0, 687.0, 690.0, 738.0, 761.0, 781.0, 798.0, 808.0, 819.0, 838.0, 839.0, 870.0, 871.0, 901.0, 915.0, 946.0, 984.0, 986.0, 991.0, 1000.0, 1017.0], + [38.0, 59.0, 213.0, 242.0, 246.0, 263.0, 277.0, 280.0, 282.0, 298.0, 313.0, 353.0, 362.0, 363.0, 377.0, 386.0, 415.0, 416.0, 466.0, 540.0, 588.0, 609.0, 653.0, 662.0, 666.0, 668.0, 678.0, 679.0, 709.0, 721.0, 738.0, 755.0, 776.0, 792.0, 796.0, 804.0, 818.0, 836.0, 886.0, 915.0, 919.0, 994.0, 1015.0], + [8.0, 17.0, 65.0, 75.0, 87.0, 104.0, 109.0, 166.0, 178.0, 209.0, 252.0, 255.0, 258.0, 261.0, 279.0, 304.0, 331.0, 382.0, 417.0, 421.0, 462.0, 479.0, 491.0, 538.0, 543.0, 544.0, 553.0, 559.0, 566.0, 604.0, 605.0, 662.0, 663.0, 670.0, 708.0, 729.0, 732.0, 738.0, 804.0, 809.0, 833.0, 838.0, 882.0, 898.0, 902.0, 913.0, 921.0, 936.0, 966.0, 984.0, 989.0, 990.0, 1002.0, 1012.0], + [22.0, 36.0, 52.0, 76.0, 77.0, 105.0, 114.0, 117.0, 118.0, 137.0, 160.0, 171.0, 175.0, 197.0, 202.0, 248.0, 284.0, 365.0, 392.0, 409.0, 453.0, 489.0, 493.0, 508.0, 551.0, 564.0, 571.0, 602.0, 615.0, 646.0, 647.0, 678.0, 686.0, 690.0, 696.0, 697.0, 739.0, 756.0, 781.0, 792.0, 793.0, 813.0, 896.0, 918.0, 931.0, 961.0, 962.0, 972.0, 981.0, 992.0, 1010.0], + [47.0, 100.0, 101.0, 130.0, 188.0, 200.0, 206.0, 229.0, 243.0, 255.0, 276.0, 296.0, 318.0, 326.0, 347.0, 433.0, 450.0, 453.0, 471.0, 475.0, 476.0, 483.0, 493.0, 494.0, 510.0, 533.0, 537.0, 562.0, 585.0, 617.0, 631.0, 657.0, 678.0, 709.0, 712.0, 745.0, 747.0, 755.0, 766.0, 771.0, 785.0, 792.0, 797.0, 815.0, 851.0, 886.0, 899.0, 999.0], + [3.0, 4.0, 15.0, 24.0, 50.0, 72.0, 98.0, 105.0, 108.0, 134.0, 157.0, 161.0, 194.0, 235.0, 295.0, 308.0, 316.0, 329.0, 393.0, 394.0, 452.0, 455.0, 515.0, 517.0, 536.0, 576.0, 584.0, 621.0, 627.0, 631.0, 676.0, 710.0, 719.0, 726.0, 727.0, 752.0, 788.0, 810.0, 826.0, 838.0, 839.0, 861.0, 862.0, 879.0, 886.0, 916.0, 980.0, 1020.0], + [31.0, 36.0, 46.0, 68.0, 72.0, 118.0, 123.0, 125.0, 160.0, 222.0, 223.0, 270.0, 293.0, 332.0, 348.0, 373.0, 380.0, 411.0, 413.0, 434.0, 469.0, 498.0, 507.0, 521.0, 566.0, 571.0, 601.0, 611.0, 619.0, 647.0, 696.0, 705.0, 711.0, 755.0, 760.0, 772.0, 774.0, 788.0, 796.0, 820.0, 849.0, 862.0, 866.0, 878.0, 898.0, 973.0, 1023.0], + [15.0, 24.0, 34.0, 41.0, 42.0, 63.0, 67.0, 100.0, 127.0, 182.0, 200.0, 237.0, 247.0, 249.0, 290.0, 323.0, 333.0, 342.0, 368.0, 387.0, 412.0, 424.0, 427.0, 440.0, 442.0, 487.0, 533.0, 548.0, 590.0, 607.0, 639.0, 651.0, 659.0, 714.0, 716.0, 738.0, 756.0, 782.0, 794.0, 802.0, 810.0, 820.0, 824.0, 854.0, 874.0, 876.0, 877.0, 912.0, 932.0, 945.0, 976.0, 987.0, 1005.0, 1022.0], + [14.0, 17.0, 71.0, 78.0, 100.0, 118.0, 132.0, 143.0, 162.0, 170.0, 176.0, 177.0, 195.0, 201.0, 219.0, 256.0, 261.0, 264.0, 279.0, 281.0, 288.0, 357.0, 406.0, 409.0, 412.0, 442.0, 445.0, 471.0, 488.0, 516.0, 529.0, 550.0, 557.0, 559.0, 563.0, 580.0, 591.0, 599.0, 675.0, 691.0, 736.0, 738.0, 749.0, 764.0, 765.0, 776.0, 780.0, 785.0, 806.0, 823.0, 825.0, 830.0, 837.0, 843.0, 864.0, 878.0, 921.0, 930.0, 932.0, 934.0, 937.0, 959.0], + [13.0, 19.0, 35.0, 85.0, 122.0, 128.0, 135.0, 136.0, 161.0, 165.0, 166.0, 203.0, 223.0, 236.0, 241.0, 242.0, 339.0, 353.0, 370.0, 381.0, 387.0, 390.0, 400.0, 407.0, 415.0, 421.0, 454.0, 464.0, 470.0, 471.0, 496.0, 504.0, 511.0, 520.0, 560.0, 565.0, 567.0, 601.0, 635.0, 655.0, 668.0, 705.0, 768.0, 787.0, 799.0, 806.0, 814.0, 835.0, 836.0, 857.0, 862.0, 872.0, 884.0, 888.0, 951.0, 984.0, 1021.0], + [24.0, 53.0, 54.0, 79.0, 89.0, 121.0, 134.0, 155.0, 164.0, 166.0, 205.0, 221.0, 222.0, 231.0, 291.0, 302.0, 334.0, 352.0, 369.0, 387.0, 437.0, 447.0, 451.0, 594.0, 609.0, 646.0, 652.0, 662.0, 681.0, 710.0, 787.0, 829.0, 848.0, 899.0, 912.0, 926.0, 997.0, 1006.0, 1022.0], + [14.0, 20.0, 29.0, 47.0, 52.0, 69.0, 75.0, 117.0, 120.0, 127.0, 146.0, 153.0, 175.0, 181.0, 237.0, 272.0, 287.0, 301.0, 316.0, 343.0, 347.0, 349.0, 395.0, 414.0, 425.0, 487.0, 526.0, 528.0, 538.0, 546.0, 548.0, 558.0, 581.0, 593.0, 630.0, 632.0, 636.0, 642.0, 651.0, 719.0, 726.0, 836.0, 968.0, 998.0, 1006.0], + [6.0, 23.0, 55.0, 90.0, 111.0, 117.0, 118.0, 123.0, 130.0, 131.0, 160.0, 187.0, 196.0, 214.0, 247.0, 253.0, 272.0, 288.0, 292.0, 302.0, 303.0, 307.0, 310.0, 323.0, 334.0, 364.0, 382.0, 384.0, 406.0, 432.0, 433.0, 439.0, 471.0, 524.0, 530.0, 562.0, 683.0, 689.0, 755.0, 769.0, 807.0, 809.0, 813.0, 834.0, 837.0, 880.0, 900.0, 927.0, 930.0, 939.0, 940.0, 970.0, 993.0], + [41.0, 54.0, 82.0, 83.0, 99.0, 139.0, 143.0, 146.0, 150.0, 161.0, 194.0, 227.0, 287.0, 312.0, 313.0, 320.0, 324.0, 340.0, 376.0, 384.0, 393.0, 430.0, 434.0, 476.0, 512.0, 514.0, 536.0, 584.0, 599.0, 600.0, 606.0, 624.0, 708.0, 714.0, 758.0, 785.0, 824.0, 838.0, 849.0, 873.0, 877.0, 881.0, 966.0, 973.0, 997.0, 1016.0], + [14.0, 24.0, 30.0, 36.0, 50.0, 73.0, 78.0, 87.0, 89.0, 107.0, 113.0, 155.0, 165.0, 171.0, 189.0, 190.0, 193.0, 209.0, 218.0, 238.0, 244.0, 288.0, 291.0, 311.0, 318.0, 319.0, 320.0, 325.0, 338.0, 351.0, 353.0, 407.0, 429.0, 475.0, 523.0, 526.0, 530.0, 546.0, 597.0, 599.0, 600.0, 604.0, 628.0, 632.0, 656.0, 658.0, 674.0, 713.0, 726.0, 746.0, 755.0, 756.0, 833.0, 847.0, 848.0, 856.0, 896.0, 911.0, 971.0, 1005.0, 1006.0, 1009.0, 1010.0, 1012.0], + [12.0, 50.0, 121.0, 128.0, 135.0, 161.0, 191.0, 192.0, 207.0, 208.0, 231.0, 266.0, 268.0, 270.0, 298.0, 394.0, 413.0, 483.0, 487.0, 518.0, 523.0, 567.0, 601.0, 606.0, 610.0, 659.0, 660.0, 680.0, 755.0, 791.0, 797.0, 802.0, 816.0, 827.0, 945.0, 974.0, 987.0, 1023.0] + ] + + spikes = [] + l=[] + for i in range(len(pattern)): + l = [] + for j in pattern[i]: + l.append(j) + spikes.append(l) + + for r in range(1, num_repeats): + for p in range(len(pattern)): + new_iter = [i + r * cycle_time for i in pattern[p]] + spikes[p].extend(new_iter) + + return spikes + + +############################################################################### +# Build Populations +############################################################################### + +# input population + + +pop_in = p.Population(100, + p.SpikeSourceArray, + {'spike_times': build_input_spike_train( + num_repeats*batches, cycle_time)}, + label='pop_in') + +pop_rec = p.Population(100, # number of neurons + p.extra_models.IFCurrExpERBP(**erbp_neuron_params), + label="pop_rec") + + +############################################################################### +# Build Projections +############################################################################### + +hidden_pop_timing_dependence=p.TimingDependenceERBP( + tau_plus=tau_err, A_plus=1, A_minus=1) +hidden_pop_weight_dependence=p.WeightDependenceERBP( + w_min=0.0, w_max=1, reg_rate=0.001) + + + +####################################### +# input to recurrent excitatory +####################################### + +# Define learning rule object +learning_rule = p.STDPMechanism( + timing_dependence=hidden_pop_timing_dependence, + weight_dependence=hidden_pop_weight_dependence, + weight=w_in_rec_exc_dist, + delay=timestep) + +# Create excitatory projection from input to hidden neuron using learning rule +inp_rec_exc = p.Projection( + pop_in, + pop_rec, + p.AllToAllConnector(), +# p.StaticSynapse(weight=w_in_rec_exc_dist, delay=timestep), + synapse_type=learning_rule, + receptor_type="excitatory") + +# input to recurrent inhibitory +# Define learning rule object +learning_rule = p.STDPMechanism( + timing_dependence=hidden_pop_timing_dependence, + weight_dependence=hidden_pop_weight_dependence, + weight=w_in_rec_inh_dist, + delay=timestep) + +# Create inhibitory projection from input to hidden neuron using learning rule +inp_rec_inh = p.Projection( + pop_in, + pop_rec, + p.AllToAllConnector(), +# p.StaticSynapse(weight=w_in_rec_inh_dist, delay=timestep), + synapse_type=learning_rule, + receptor_type="inhibitory") + + +####################################### +# recurrent to recurrent +####################################### +# Define learning rule object +learning_rule = p.STDPMechanism( + timing_dependence=hidden_pop_timing_dependence, + weight_dependence=hidden_pop_weight_dependence, + weight=w_rec_rec_dist, + delay=timestep) + +# Create excitatory recurrent projection +rec_rec_exc = p.Projection( + pop_rec, + pop_rec, + p.FixedProbabilityConnector(0.4), + synapse_type=learning_rule, + receptor_type="excitatory") + +# input to recurrent inhibitory +# Define learning rule object +learning_rule = p.STDPMechanism( + timing_dependence=hidden_pop_timing_dependence, + weight_dependence=hidden_pop_weight_dependence, + weight=w_rec_rec_dist, + delay=timestep) + +# Create inhibitory recurrent projection from input to hidden neuron using +# learning rule +rec_rec_inh = p.Projection( + pop_rec, + pop_rec, + p.FixedProbabilityConnector(0.4), + synapse_type=learning_rule, + receptor_type="inhibitory") + + + +############################################################################### +# Run Simulation +############################################################################### + +pop_in.record('spikes') +pop_rec.record(["spikes", 'gsyn_inh']) + +plot_start = 0 +window = num_repeats * cycle_time +plot_end = plot_start + window + +for i in range(batches): + + print("run: {}".format(i)) + p.run(runtime/batches) + + in_spikes = pop_in.get_data('spikes') + pop_rec_data = pop_rec.get_data(['spikes', 'gsyn_inh']) + + # Plot + F = Figure( + # plot data for postsynaptic neuron + Panel(in_spikes.segments[0].spiketrains, + yticks=True, markersize=2, xlim=(plot_start, plot_end)), + Panel(pop_rec_data.segments[0].spiketrains, + yticks=True, markersize=2, xlim=(plot_start, plot_end) + ), + Panel(pop_rec_data.segments[0].filter(name='gsyn_inh')[0], + ylabel="gsyn inhibitory (mV)", + data_labels=[pop_rec.label], yticks=True, xlim=(0, runtime) + ) + ) + + plt.pause(0.5) +# plt.draw() + + plot_start = plot_end + plot_end += window + +plt.show() +p.end() + + +print("job done") \ No newline at end of file diff --git a/eprop_testing/test_single_plastic_update.py b/eprop_testing/test_single_plastic_update.py new file mode 100644 index 0000000..8c3c073 --- /dev/null +++ b/eprop_testing/test_single_plastic_update.py @@ -0,0 +1,76 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + + +runtime = 2000 +pynn.setup(1.0) + +neuron_params = { + "v": 0, + "i_offset": 0, + "v_rest": 0 + } + + +spike_source = pynn.Population(2, + pynn.SpikeSourceArray, + {'spike_times': [1025]}, + label='Spike Source') + +neuron = pynn.Population(2, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + + +start_w = [-0.5, 2] +eprop_learning = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=1.5), + weight=start_w, delay=[0, 0]) + +proj = pynn.Projection(spike_source, neuron, + pynn.OneToOneConnector(), + synapse_type=eprop_learning, + label='input_connections', + receptor_type='input_connections') + +neuron.record('all') + +pynn.run(runtime) + +res = neuron.get_data('all') + +Figure( + Panel(res.segments[0].filter(name='v')[0], + ylabel="Membrane potential (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_exc')[0], + ylabel="gsyn excitatory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(res.segments[0].filter(name='gsyn_inh')[0], + xlabel="Time (ms)", xticks=True, + ylabel="gsyn inhibitory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + title="Single eprop neuron" +) + +plt.show() + +pynn.end() \ No newline at end of file diff --git a/eprop_testing/test_sinusoid_learning.py b/eprop_testing/test_sinusoid_learning.py new file mode 100644 index 0000000..f20ae42 --- /dev/null +++ b/eprop_testing/test_sinusoid_learning.py @@ -0,0 +1,168 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + +runtime_factor = 1000 +runtime = 1024 * runtime_factor +pynn.setup(1.0) + +neuron_params = { + "v": 0, + "i_offset": 0.8, + "v_rest": 0, + "w_fb": 0.75 + } + +target_data = [] +for i in range(1024): + target_data.append( + 5 + 2 * np.sin(2 * i * 2* np.pi / 1024) \ + + 2 * np.sin((4 * i * 2* np.pi / 1024)) + ) + +readout_neuron_params = { + "v": 0, + "v_thresh": 30, # controls firing rate of error neurons + "target_data": target_data, + "eta": 0.01 + } + +input_size = 1 +input_pop = pynn.Population(input_size, + pynn.SpikeSourceArray, + {'spike_times': [np.linspace(0, 1000, 10) for i in range(input_size)]}, + label='input_pop') + +neuron = pynn.Population(1, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +# Output population +readout_pop = pynn.Population(3, # HARDCODED 1 + pynn.extra_models.SinusoidReadout( + **readout_neuron_params + ), + label="readout_pop" + ) + +start_w = [-0.5] +eprop_learning = pynn.STDPMechanism( + timing_dependence=pynn.extra_models.TimingDependenceEprop(), + weight_dependence=pynn.extra_models.WeightDependenceEpropReg( + w_min=-2.0, w_max=2.0, reg_rate=0.0), + weight=start_w, delay=0)#[0, 0]) + +in_proj = pynn.Projection(input_pop, + neuron, + pynn.OneToOneConnector(), + synapse_type=eprop_learning, + label='input_connections', + receptor_type='input_connections') + +out_proj = pynn.Projection(neuron, + readout_pop, + pynn.OneToOneConnector(), + synapse_type=eprop_learning, + label='output_connections', + receptor_type='input_connections') + +learning_proj = pynn.Projection(readout_pop, + neuron, + pynn.OneToOneConnector(), + pynn.StaticSynapse(weight=[0.5], delay=[0]), + receptor_type='learning_signal') + +# self_learning_proj = pynn.Projection(readout_pop, +# readout_pop, +# pynn.OneToOneConnector(), +# pynn.StaticSynapse(weight=[0.5], delay=[0]), +# receptor_type='learning_signal') + +input_pop.record('spikes') +neuron.record('all') +readout_pop.record('all') + +pynn.run(runtime) +in_spikes = input_pop.get_data('spikes') +neuron_res = neuron.get_data('all') +readout_res = readout_pop.get_data('all') + + + +# Plot rec neuron output +# plt.figure() +# # plt.tight_layout() +# +# plt.subplot(4, 1, 1) +# plt.plot(neuron_res.segments[0].filter(name='v')[0].magnitude, label='Membrane potential (mV)') +# +# plt.subplot(4, 1, 2) +# plt.plot(neuron_res.segments[0].filter(name='gsyn_exc')[0].magnitude, label='gsyn_exc') +# +# plt.subplot(4, 1, 3) +# plt.plot(neuron_res.segments[0].filter(name='gsyn_inh')[0].magnitude, label='gsyn_inh') +# +# plt.subplot(4,1,4) +# plt.plot(in_spikes.segments[0].spiketrains, label='in_spikes') + +plt.figure() +Figure( + Panel(neuron_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xlim=(0, runtime)), + + Panel(in_spikes.segments[0].spiketrains, ylabel='in_spikes', yticks=True, xlim=(0, runtime)), + + Panel(neuron_res.segments[0].spiketrains, ylabel='neuron_spikes', yticks=True, xlim=(0, runtime)), + +# title="eprop neuron" +# ) +# plt.show() +# +# plt.figure() +# Figure( + Panel(readout_res.segments[0].filter(name='v')[0], ylabel='Membrane potential (mV)', yticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_exc')[0], ylabel='gsyn_exc', yticks=True, xlim=(0, runtime)), + + Panel(readout_res.segments[0].filter(name='gsyn_inh')[0], ylabel='gsyn_inh', yticks=True, xlim=(0, runtime)), + + title="readout neuron" +) +# plt.show() + +# Plot Readout output +# plt.figure() +# # plt.tight_layout() +# +# plt.subplot(3, 1, 1) +# plt.plot(readout_res.segments[0].filter(name='v')[0].magnitude, label='Membrane potential (mV)') +# +# plt.subplot(3, 1, 2) +# plt.plot(readout_res.segments[0].filter(name='gsyn_exc')[0].magnitude, label='gsyn_exc') +# +# plt.subplot(3, 1, 3) +# plt.plot(readout_res.segments[0].filter(name='gsyn_inh')[0].magnitude, label='gsyn_inh') + + +plt.show() + +pynn.end() +print("job done") \ No newline at end of file diff --git a/eprop_testing/test_synapse_state_evol.py b/eprop_testing/test_synapse_state_evol.py new file mode 100644 index 0000000..24291ae --- /dev/null +++ b/eprop_testing/test_synapse_state_evol.py @@ -0,0 +1,76 @@ +# Copyright (c) 2019 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pyNN.spiNNaker as pynn +import numpy as np +import matplotlib.pyplot as plt +from pyNN.random import NumpyRNG, RandomDistribution +from pyNN.utility.plotting import Figure, Panel + + +runtime = 1000 +pynn.setup(1.0) + +neuron_params = { + "v": 0, + "i_offset": 0.8, + "v_rest": 0 + } + + +input_pop = pynn.Population(1, + pynn.SpikeSourceArray, + {'spike_times': [200]}, + label='input_pop') + +neuron = pynn.Population(1, + pynn.extra_models.EPropAdaptive(**neuron_params), + label='eprop_pop') + +in_proj = pynn.Projection(input_pop, + neuron, + pynn.OneToOneConnector(), + pynn.StaticSynapse(weight=[-0.5], delay=[0]), + receptor_type='input_connections') + + +input_pop.record('spikes') +neuron.record('all') + +pynn.run(runtime) +in_spikes = input_pop.get_data('spikes') +neuron_res = neuron.get_data('all') + +Figure( + Panel(in_spikes.segments[0].spiketrains, + ylabel="Input Spikes", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(neuron_res.segments[0].filter(name='v')[0], + ylabel="Membrane potential (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(neuron_res.segments[0].filter(name='gsyn_exc')[0], + ylabel="gsyn excitatory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(neuron_res.segments[0].filter(name='gsyn_inh')[0], + xlabel="Time (ms)", xticks=True, + ylabel="gsyn inhibitory (mV)", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + Panel(neuron_res.segments[0].spiketrains, + ylabel="Output Spikes", + data_labels=neuron.label, yticks=True, xlim=(0, runtime)), + title="Single eprop neuron" +) + +plt.show() + +pynn.end() \ No newline at end of file