def __init__( self, n_inpt: int, input_shape: List[int], kernel_size: Union[int, Tuple[int, int]], stride: Union[int, Tuple[int, int]], n_filters: int, inh: float = 25.0, dt: float = 1.0, nu: Optional[Union[float, Sequence[float]]] = (1e-4, 1e-2), reduction: Optional[callable] = None, theta_plus: float = 0.05, tc_theta_decay: float = 1e7, wmin: float = 0.0, wmax: float = 1.0, norm: Optional[float] = 0.2, ) -> None: # language=rst """ Constructor for class ``LocallyConnectedNetwork``. Uses ``DiehlAndCookNodes`` to avoid multiple spikes per timestep in the output layer population. :param n_inpt: Number of input neurons. Matches the 1D size of the input data. :param input_shape: Two-dimensional shape of input population. :param kernel_size: Size of input windows. Integer or two-tuple of integers. :param stride: Length of horizontal, vertical stride across input space. Integer or two-tuple of integers. :param n_filters: Number of locally connected filters per input region. Integer or two-tuple of integers. :param inh: Strength of synapse weights from output layer back onto itself. :param dt: Simulation time step. :param nu: Single or pair of learning rates for pre- and post-synaptic events, respectively. :param reduction: Method for reducing parameter updates along the minibatch dimension. :param wmin: Minimum allowed weight on ``Input`` to ``DiehlAndCookNodes`` synapses. :param wmax: Maximum allowed weight on ``Input`` to ``DiehlAndCookNodes`` synapses. :param theta_plus: On-spike increment of ``DiehlAndCookNodes`` membrane threshold potential. :param tc_theta_decay: Time constant of ``DiehlAndCookNodes`` threshold potential decay. :param norm: ``Input`` to ``DiehlAndCookNodes`` layer connection weights normalization constant. """ super().__init__(dt=dt) kernel_size = _pair(kernel_size) stride = _pair(stride) self.n_inpt = n_inpt self.input_shape = input_shape self.kernel_size = kernel_size self.stride = stride self.n_filters = n_filters self.inh = inh self.dt = dt self.theta_plus = theta_plus self.tc_theta_decay = tc_theta_decay self.wmin = wmin self.wmax = wmax self.norm = norm if kernel_size == input_shape: conv_size = [1, 1] else: conv_size = ( int((input_shape[0] - kernel_size[0]) / stride[0]) + 1, int((input_shape[1] - kernel_size[1]) / stride[1]) + 1, ) input_layer = Input(n=self.n_inpt, traces=True, tc_trace=20.0) output_layer = DiehlAndCookNodes( n=self.n_filters * conv_size[0] * conv_size[1], traces=True, rest=-65.0, reset=-60.0, thresh=-52.0, refrac=5, tc_decay=100.0, tc_trace=20.0, theta_plus=theta_plus, tc_theta_decay=tc_theta_decay, ) input_output_conn = LocalConnection( input_layer, output_layer, kernel_size=kernel_size, stride=stride, n_filters=n_filters, nu=nu, reduction=reduction, update_rule=PostPre, wmin=wmin, wmax=wmax, norm=norm, input_shape=input_shape, ) w = torch.zeros(n_filters, *conv_size, n_filters, *conv_size) for fltr1 in range(n_filters): for fltr2 in range(n_filters): if fltr1 != fltr2: for i in range(conv_size[0]): for j in range(conv_size[1]): w[fltr1, i, j, fltr2, i, j] = -inh w = w.view( n_filters * conv_size[0] * conv_size[1], n_filters * conv_size[0] * conv_size[1], ) recurrent_conn = Connection(output_layer, output_layer, w=w) self.add_layer(input_layer, name="X") self.add_layer(output_layer, name="Y") self.add_connection(input_output_conn, source="X", target="Y") self.add_connection(recurrent_conn, source="Y", target="Y")
def main(seed=0, n_neurons=100, n_train=60000, n_test=10000, inhib=250, time=50, lr=1e-2, lr_decay=0.99, dt=1, theta_plus=0.05, theta_decay=1e-7, progress_interval=10, update_interval=250, train=True, plot=False, gpu=False): assert n_train % update_interval == 0 and n_test % update_interval == 0, \ 'No. examples must be divisible by update_interval' params = [ seed, n_neurons, n_train, inhib, time, lr, lr_decay, theta_plus, theta_decay, progress_interval, update_interval ] test_params = [ seed, n_neurons, n_train, n_test, inhib, time, lr, lr_decay, theta_plus, theta_decay, progress_interval, update_interval ] model_name = '_'.join([str(x) for x in params]) np.random.seed(seed) if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) if train: n_examples = n_train else: n_examples = n_test n_sqrt = int(np.ceil(np.sqrt(n_neurons))) n_classes = 10 # Build network. if train: network = Network(dt=dt) input_layer = Input(n=784, traces=True, trace_tc=5e-2) network.add_layer(input_layer, name='X') output_layer = DiehlAndCookNodes(n=n_neurons, traces=True, rest=0, reset=0, thresh=1, refrac=0, decay=1e-2, trace_tc=5e-2, theta_plus=theta_plus, theta_decay=theta_decay) network.add_layer(output_layer, name='Y') w = 0.3 * torch.rand(784, n_neurons) input_connection = Connection(source=network.layers['X'], target=network.layers['Y'], w=w, update_rule=PostPre, nu=[0, lr], wmin=0, wmax=1, norm=78.4) network.add_connection(input_connection, source='X', target='Y') w = -inhib * (torch.ones(n_neurons, n_neurons) - torch.diag(torch.ones(n_neurons))) recurrent_connection = Connection(source=network.layers['Y'], target=network.layers['Y'], w=w, wmin=-inhib, wmax=0) network.add_connection(recurrent_connection, source='Y', target='Y') else: path = os.path.join('..', '..', 'params', data, model) network = load_network(os.path.join(path, model_name + '.pt')) network.connections['X', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu) network.layers['Y'].theta_decay = 0 network.layers['Y'].theta_plus = 0 # Load Fashion-MNIST data. dataset = FashionMNIST(path=os.path.join('..', '..', 'data', 'FashionMNIST'), download=True) if train: images, labels = dataset.get_train() else: images, labels = dataset.get_test() images = images.view(-1, 784) images = images / 255 # if train: # for i in range(n_neurons): # network.connections['X', 'Y'].w[:, i] = images[i] + images[i].mean() * torch.randn(784) # Record spikes during the simulation. spike_record = torch.zeros(update_interval, time, n_neurons) # Neuron assignments and spike proportions. if train: assignments = -torch.ones_like(torch.Tensor(n_neurons)) proportions = torch.zeros_like(torch.Tensor(n_neurons, n_classes)) rates = torch.zeros_like(torch.Tensor(n_neurons, n_classes)) ngram_scores = {} else: path = os.path.join('..', '..', 'params', data, model) path = os.path.join(path, '_'.join(['auxiliary', model_name]) + '.pt') assignments, proportions, rates, ngram_scores = torch.load( open(path, 'rb')) # Sequence of accuracy estimates. curves = {'all': [], 'proportion': [], 'ngram': []} if train: best_accuracy = 0 spikes = {} for layer in set(network.layers): spikes[layer] = Monitor(network.layers[layer], state_vars=['s'], time=time) network.add_monitor(spikes[layer], name='%s_spikes' % layer) # Train the network. if train: print('\nBegin training.\n') else: print('\nBegin test.\n') inpt_axes = None inpt_ims = None spike_ims = None spike_axes = None weights_im = None assigns_im = None perf_ax = None start = t() for i in range(n_examples): if i % progress_interval == 0 and train: network.connections['X', 'Y'].update_rule.nu[1] *= lr_decay if i % progress_interval == 0: print(f'Progress: {i} / {n_examples} ({t() - start:.4f} seconds)') start = t() if i % update_interval == 0 and i > 0: if i % len(labels) == 0: current_labels = labels[-update_interval:] else: current_labels = labels[i % len(images) - update_interval:i % len(images)] # Update and print accuracy evaluations. curves, predictions = update_curves(curves, current_labels, n_classes, spike_record=spike_record, assignments=assignments, proportions=proportions, ngram_scores=ngram_scores, n=2) print_results(curves) if train: if any([x[-1] > best_accuracy for x in curves.values()]): print( 'New best accuracy! Saving network parameters to disk.' ) # Save network to disk. path = os.path.join('..', '..', 'params', data, model) if not os.path.isdir(path): os.makedirs(path) network.save(os.path.join(path, model_name + '.pt')) path = os.path.join( path, '_'.join(['auxiliary', model_name]) + '.pt') torch.save((assignments, proportions, rates, ngram_scores), open(path, 'wb')) best_accuracy = max([x[-1] for x in curves.values()]) # Assign labels to excitatory layer neurons. assignments, proportions, rates = assign_labels( spike_record, current_labels, n_classes, rates) # Compute ngram scores. ngram_scores = update_ngram_scores(spike_record, current_labels, n_classes, 2, ngram_scores) print() # Get next input sample. image = images[i % n_examples] sample = rank_order(datum=image, time=time, dt=dt) inpts = {'X': sample} # Run the network on the input. network.run(inpts=inpts, time=time) retries = 0 while spikes['Y'].get('s').sum() < 5 and retries < 3: retries += 1 image *= 2 sample = rank_order(datum=image, time=time, dt=dt) inpts = {'X': sample} network.run(inpts=inpts, time=time) # Add to spikes recording. spike_record[i % update_interval] = spikes['Y'].get('s').t() # Optionally plot various simulation information. if plot: _input = images[i % n_examples].view(28, 28) reconstruction = inpts['X'].view(time, 784).sum(0).view(28, 28) _spikes = {layer: spikes[layer].get('s') for layer in spikes} input_exc_weights = network.connections['X', 'Y'].w square_weights = get_square_weights( input_exc_weights.view(784, n_neurons), n_sqrt, 28) square_assignments = get_square_assignments(assignments, n_sqrt) # inpt_axes, inpt_ims = plot_input(_input, reconstruction, label=labels[i], axes=inpt_axes, ims=inpt_ims) spike_ims, spike_axes = plot_spikes(_spikes, ims=spike_ims, axes=spike_axes) weights_im = plot_weights(square_weights, im=weights_im, wmax=0.25) # assigns_im = plot_assignments(square_assignments, im=assigns_im) # perf_ax = plot_performance(curves, ax=perf_ax) plt.pause(1e-8) network.reset_() # Reset state variables. print(f'Progress: {n_examples} / {n_examples} ({t() - start:.4f} seconds)') i += 1 if i % len(labels) == 0: current_labels = labels[-update_interval:] else: current_labels = labels[i % len(images) - update_interval:i % len(images)] # Update and print accuracy evaluations. curves, predictions = update_curves(curves, current_labels, n_classes, spike_record=spike_record, assignments=assignments, proportions=proportions, ngram_scores=ngram_scores, n=2) print_results(curves) if train: if any([x[-1] > best_accuracy for x in curves.values()]): print('New best accuracy! Saving network parameters to disk.') # Save network to disk. if train: path = os.path.join('..', '..', 'params', data, model) if not os.path.isdir(path): os.makedirs(path) network.save(os.path.join(path, model_name + '.pt')) path = os.path.join( path, '_'.join(['auxiliary', model_name]) + '.pt') torch.save((assignments, proportions, rates, ngram_scores), open(path, 'wb')) if train: print('\nTraining complete.\n') else: print('\nTest complete.\n') print('Average accuracies:\n') for scheme in curves.keys(): print('\t%s: %.2f' % (scheme, float(np.mean(curves[scheme])))) # Save accuracy curves to disk. path = os.path.join('..', '..', 'curves', data, model) if not os.path.isdir(path): os.makedirs(path) if train: to_write = ['train'] + params else: to_write = ['test'] + params to_write = [str(x) for x in to_write] f = '_'.join(to_write) + '.pt' torch.save((curves, update_interval, n_examples), open(os.path.join(path, f), 'wb')) # Save results to disk. path = os.path.join('..', '..', 'results', data, model) if not os.path.isdir(path): os.makedirs(path) results = [ np.mean(curves['all']), np.mean(curves['proportion']), np.mean(curves['ngram']), np.max(curves['all']), np.max(curves['proportion']), np.max(curves['ngram']) ] if train: to_write = params + results else: to_write = test_params + results to_write = [str(x) for x in to_write] if train: name = 'train.csv' else: name = 'test.csv' if not os.path.isfile(os.path.join(path, name)): with open(os.path.join(path, name), 'w') as f: if train: f.write( 'random_seed,n_neurons,n_train,inhib,time,lr,lr_decay,theta_plus,theta_decay,' 'progress_interval,update_interval,mean_all_activity,mean_proportion_weighting,' 'mean_ngram,max_all_activity,max_proportion_weighting,max_ngram\n' ) else: f.write( 'random_seed,n_neurons,n_train,n_test,inhib,time,lr,lr_decay,theta_plus,theta_decay,' 'progress_interval,update_interval,mean_all_activity,mean_proportion_weighting,' 'mean_ngram,max_all_activity,max_proportion_weighting,max_ngram\n' ) with open(os.path.join(path, name), 'a') as f: f.write(','.join(to_write) + '\n')
def __init__( self, n_input: int, n_neurons: int = 100, start_inhib: float = 1.0, max_inhib: float = 100.0, dt: float = 1.0, nu: Optional[Union[float, Sequence[float]]] = (1e-4, 1e-2), reduction: Optional[callable] = None, wmin: float = 0.0, wmax: float = 1.0, norm: float = 78.4, theta_plus: float = 0.05, tc_theta_decay: float = 1e7, inpt_shape: Optional[Iterable[int]] = None, ) -> None: # language=rst """ Constructor for class ``IncreasingInhibitionNetwork``. :param n_inpt: Number of input neurons. Matches the 1D size of the input data. :param n_neurons: Number of excitatory, inhibitory neurons. :param inh: Strength of synapse weights from inhibitory to excitatory layer. :param dt: Simulation time step. :param nu: Single or pair of learning rates for pre- and post-synaptic events, respectively. :param reduction: Method for reducing parameter updates along the minibatch dimension. :param wmin: Minimum allowed weight on input to excitatory synapses. :param wmax: Maximum allowed weight on input to excitatory synapses. :param norm: Input to excitatory layer connection weights normalization constant. :param theta_plus: On-spike increment of ``DiehlAndCookNodes`` membrane threshold potential. :param tc_theta_decay: Time constant of ``DiehlAndCookNodes`` threshold potential decay. :param inpt_shape: The dimensionality of the input layer. """ super().__init__(dt=dt) self.n_input = n_input self.n_neurons = n_neurons self.n_sqrt = int(np.sqrt(n_neurons)) self.start_inhib = start_inhib self.max_inhib = max_inhib self.dt = dt self.inpt_shape = inpt_shape input_layer = Input(n=self.n_input, shape=self.inpt_shape, traces=True, tc_trace=20.0) self.add_layer(input_layer, name="X") output_layer = DiehlAndCookNodes( n=self.n_neurons, traces=True, rest=-65.0, reset=-60.0, thresh=-52.0, refrac=5, tc_decay=100.0, tc_trace=20.0, theta_plus=theta_plus, tc_theta_decay=tc_theta_decay, ) self.add_layer(output_layer, name="Y") w = 0.3 * torch.rand(self.n_input, self.n_neurons) input_output_conn = Connection( source=self.layers["X"], target=self.layers["Y"], w=w, update_rule=PostPre, nu=nu, reduction=reduction, wmin=wmin, wmax=wmax, norm=norm, ) self.add_connection(input_output_conn, source="X", target="Y") # add internal inhibitory connections w = torch.ones(self.n_neurons, self.n_neurons) - torch.diag( torch.ones(self.n_neurons)) for i in range(self.n_neurons): for j in range(self.n_neurons): if i != j: x1, y1 = i // self.n_sqrt, i % self.n_sqrt x2, y2 = j // self.n_sqrt, j % self.n_sqrt w[i, j] = np.sqrt(euclidean([x1, y1], [x2, y2])) w = w / w.max() w = (w * self.max_inhib) + self.start_inhib recurrent_output_conn = Connection(source=self.layers["Y"], target=self.layers["Y"], w=w) self.add_connection(recurrent_output_conn, source="Y", target="Y")
if not train: update_interval = n_test if kernel_size == 28: conv_size = 1 else: conv_size = int((28 - kernel_size + 2 * padding) / stride) + 1 n_sqrt = int(np.ceil(np.sqrt(n_neurons))) n_input = kernel_size ** 2 # Build network. network = Network() input_layer = Input(n=n_input, traces=True) conv_layer = DiehlAndCookNodes(n=n_neurons, traces=True) conv_conn = Connection( input_layer, conv_layer, update_rule=PostPre, norm=0.1 * n_input, nu=(0, 1e-2), wmax=1.0 ) w = -inhib * (torch.ones(n_neurons, n_neurons) - torch.diag(torch.ones(n_neurons))) recurrent_conn = Connection(conv_layer, conv_layer, w=w) network.add_layer(input_layer, name='X') network.add_layer(conv_layer, name='Y') network.add_connection(conv_conn, source='X', target='Y') network.add_connection(recurrent_conn, source='Y', target='Y') # Voltage recording for excitatory and inhibitory layers. voltage_monitor = Monitor(network.layers['Y'], ['v'], time=time) network.add_monitor(voltage_monitor, name='output_voltage')
def build_network(self) -> None: """ Build network for the agent. Returns ------- None """ # Input layer s2 = Input(shape=[2, 128], traces=True, traces_additive=True, tc_trace=1.0, trace_scale=0.0 ) # Output layer out_shape = self.environment.env.action_space.n pm = DiehlAndCookNodes(shape=[out_shape, 1], traces=True, traces_additive=True, tc_trace=1.0, trace_scale=0.0, thresh=-54., rest=-65.0, reset=-65.0, refrac=256, tc_decay=2.0, theta_plus=0.05, tc_theta_decay=1e6, one_spike=True ) # Initial weights w1 = torch.normal(torch.zeros(s2.n, pm.n), 0.01 * torch.ones(s2.n, pm.n)) # Input to output connections which will be trained using R-STDP s2_pm = Connection(s2, pm, nu=0.001, update_rule=MSTDPET, wmin=-1.0, wmax=1.0, w=w1, tc_plus=32., tc_minus=32., tc_e_trace=1280., # weight_decay=1e-6, ) # Inhibitory connection on output neurons to regulate their activation pm_pm = Connection(pm, pm, w=-0.5 * (torch.ones(pm.n)) ) # Add layers/populations to the network self.network.add_layer(s2, "S2") self.network.add_layer(pm, "PM") # Add connections to the network self.network.add_connection(s2_pm, "S2", "PM") self.network.add_connection(pm_pm, "PM", "PM") # Add monitors self.network.add_monitor( Monitor(self.network.layers["PM"], ["s", "v"]), "PM", ) self.network.add_monitor( Monitor(self.network.layers["S2"], ["s"]), "S2" ) self.network.add_monitor( Monitor(self.network.connections[("S2", "PM")], ["w"]), "S2-PM" ) self.network.to(self.device)
def __init__( self, n_inpt: int, n_neurons: int = 100, exc: float = 22.5, inh: float = 17.5, dt: float = 1.0, nu: Optional[Union[float, Sequence[float]]] = (1e-4, 1e-2), reduction: Optional[callable] = None, wmin: float = 0.0, wmax: float = 1000.0, norm: float = 78.4, theta_plus: float = 0.05 * 1000, tc_theta_decay: float = 1e7, inpt_shape: Optional[Iterable[int]] = None, ) -> None: # language=rst """ Constructor for class ``DiehlAndCook2015``. :param n_inpt: Number of input neurons. Matches the 1D size of the input data. :param n_neurons: Number of excitatory, inhibitory neurons. :param exc: Strength of synapse weights from excitatory to inhibitory layer. :param inh: Strength of synapse weights from inhibitory to excitatory layer. :param dt: Simulation time step. :param nu: Single or pair of learning rates for pre- and post-synaptic events, respectively. :param reduction: Method for reducing parameter updates along the minibatch dimension. :param wmin: Minimum allowed weight on input to excitatory synapses. :param wmax: Maximum allowed weight on input to excitatory synapses. :param norm: Input to excitatory layer connection weights normalization constant. :param theta_plus: On-spike increment of ``DiehlAndCookNodes`` membrane threshold potential. :param tc_theta_decay: Time constant of ``DiehlAndCookNodes`` threshold potential decay. :param inpt_shape: The dimensionality of the input layer. """ super().__init__(dt=dt) self.n_inpt = n_inpt self.inpt_shape = inpt_shape self.n_neurons = n_neurons self.exc = exc self.inh = inh self.dt = dt # Layers input_layer = Input(n=self.n_inpt, shape=self.inpt_shape, traces=True, tc_trace=20.0) exc_layer = DiehlAndCookNodes( n=self.n_neurons, traces=True, rest=0.0, reset=5.0, thresh=12.0 * 1000, refrac=5, tc_decay=100.0, tc_trace=20.0, theta_plus=theta_plus, tc_theta_decay=tc_theta_decay, ) inh_layer = LIFNodes( n=self.n_neurons, traces=False, rest=0.0, reset=15.0, thresh=20.0 * 1000, tc_decay=10.0, refrac=2, tc_trace=20.0, ) # Connections w = 0.3 * 1000 * torch.rand(self.n_inpt, self.n_neurons) input_exc_conn = Connection( source=input_layer, target=exc_layer, w=w, update_rule=PostPre, nu=nu, reduction=reduction, wmin=wmin, wmax=wmax, norm=norm, ) w = self.exc * torch.diag(torch.ones(self.n_neurons)) exc_inh_conn = Connection(source=exc_layer, target=inh_layer, w=w, wmin=0, wmax=self.exc) w = -self.inh * (torch.ones(self.n_neurons, self.n_neurons) - torch.diag(torch.ones(self.n_neurons))) inh_exc_conn = Connection(source=inh_layer, target=exc_layer, w=w, wmin=-self.inh, wmax=0) # Add to network self.add_layer(input_layer, name="X") self.add_layer(exc_layer, name="Ae") self.add_layer(inh_layer, name="Ai") self.add_connection(input_exc_conn, source="X", target="Ae") self.add_connection(exc_inh_conn, source="Ae", target="Ai") self.add_connection(inh_exc_conn, source="Ai", target="Ae")
def main(seed=0, n_train=60000, n_test=10000, kernel_size=(16, ), stride=(4, ), n_filters=25, padding=0, inhib=100, time=25, lr=1e-3, lr_decay=0.99, dt=1, intensity=1, progress_interval=10, update_interval=250, plot=False, train=True, gpu=False): assert n_train % update_interval == 0 and n_test % update_interval == 0, \ 'No. examples must be divisible by update_interval' params = [ seed, n_train, kernel_size, stride, n_filters, padding, inhib, time, lr, lr_decay, dt, intensity, update_interval ] model_name = '_'.join([str(x) for x in params]) if not train: test_params = [ seed, n_train, n_test, kernel_size, stride, n_filters, padding, inhib, time, lr, lr_decay, dt, intensity, update_interval ] np.random.seed(seed) if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) n_examples = n_train if train else n_test input_shape = [20, 20] if kernel_size == input_shape: conv_size = [1, 1] else: conv_size = (int((input_shape[0] - kernel_size[0]) / stride[0]) + 1, int((input_shape[1] - kernel_size[1]) / stride[1]) + 1) n_classes = 10 n_neurons = n_filters * np.prod(conv_size) total_kernel_size = int(np.prod(kernel_size)) total_conv_size = int(np.prod(conv_size)) # Build network. if train: network = Network() input_layer = Input(n=400, shape=(1, 1, 20, 20), traces=True) conv_layer = DiehlAndCookNodes(n=n_filters * total_conv_size, shape=(1, n_filters, *conv_size), thresh=-64.0, traces=True, theta_plus=0.05 * (kernel_size[0] / 20), refrac=0) conv_layer2 = LIFNodes(n=n_filters * total_conv_size, shape=(1, n_filters, *conv_size), refrac=0) conv_conn = Conv2dConnection(input_layer, conv_layer, kernel_size=kernel_size, stride=stride, update_rule=WeightDependentPostPre, norm=0.05 * total_kernel_size, nu=[0, lr], wmin=0, wmax=0.25) conv_conn2 = Conv2dConnection(input_layer, conv_layer2, w=conv_conn.w, kernel_size=kernel_size, stride=stride, update_rule=None, wmax=0.25) w = -inhib * torch.ones(n_filters, conv_size[0], conv_size[1], n_filters, conv_size[0], conv_size[1]) for f in range(n_filters): for f2 in range(n_filters): if f != f2: w[f, :, :f2, :, :] = 0 w = w.view(n_filters * conv_size[0] * conv_size[1], n_filters * conv_size[0] * conv_size[1]) recurrent_conn = Connection(conv_layer, conv_layer, w=w) network.add_layer(input_layer, name='X') network.add_layer(conv_layer, name='Y') network.add_layer(conv_layer2, name='Y_') network.add_connection(conv_conn, source='X', target='Y') network.add_connection(conv_conn2, source='X', target='Y_') network.add_connection(recurrent_conn, source='Y', target='Y') # Voltage recording for excitatory and inhibitory layers. voltage_monitor = Monitor(network.layers['Y'], ['v'], time=time) network.add_monitor(voltage_monitor, name='output_voltage') else: network = load_network(os.path.join(params_path, model_name + '.pt')) network.connections['X', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu) network.layers['Y'].theta_decay = 0 network.layers['Y'].theta_plus = 0 # Load MNIST data. dataset = MNIST(data_path, download=True) if train: images, labels = dataset.get_train() else: images, labels = dataset.get_test() images *= intensity images = images[:, 4:-4, 4:-4].contiguous() # Record spikes during the simulation. spike_record = torch.zeros(update_interval, time, n_neurons) full_spike_record = torch.zeros(n_examples, n_neurons) # Neuron assignments and spike proportions. if train: logreg_model = LogisticRegression(warm_start=True, n_jobs=-1, solver='lbfgs', max_iter=1000, multi_class='multinomial') logreg_model.coef_ = np.zeros([n_classes, n_neurons]) logreg_model.intercept_ = np.zeros(n_classes) logreg_model.classes_ = np.arange(n_classes) else: path = os.path.join(params_path, '_'.join(['auxiliary', model_name]) + '.pt') logreg_coef, logreg_intercept = torch.load(open(path, 'rb')) logreg_model = LogisticRegression(warm_start=True, n_jobs=-1, solver='lbfgs', max_iter=1000, multi_class='multinomial') logreg_model.coef_ = logreg_coef logreg_model.intercept_ = logreg_intercept logreg_model.classes_ = np.arange(n_classes) # Sequence of accuracy estimates. curves = {'logreg': []} predictions = {scheme: torch.Tensor().long() for scheme in curves.keys()} if train: best_accuracy = 0 spikes = {} for layer in set(network.layers): spikes[layer] = Monitor(network.layers[layer], state_vars=['s'], time=time) network.add_monitor(spikes[layer], name='%s_spikes' % layer) # Train the network. if train: print('\nBegin training.\n') else: print('\nBegin test.\n') inpt_ims = None inpt_axes = None spike_ims = None spike_axes = None weights_im = None plot_update_interval = 100 start = t() for i in range(n_examples): if i % progress_interval == 0: print('Progress: %d / %d (%.4f seconds)' % (i, n_examples, t() - start)) start = t() if i % update_interval == 0 and i > 0: if train: network.connections['X', 'Y'].update_rule.nu[1] *= lr_decay if i % len(labels) == 0: current_labels = labels[-update_interval:] current_record = full_spike_record[-update_interval:] else: current_labels = labels[i % len(labels) - update_interval:i % len(labels)] current_record = full_spike_record[i % len(labels) - update_interval:i % len(labels)] # Update and print accuracy evaluations. curves, preds = update_curves(curves, current_labels, n_classes, full_spike_record=current_record, logreg=logreg_model) print_results(curves) for scheme in preds: predictions[scheme] = torch.cat( [predictions[scheme], preds[scheme]], -1) # Save accuracy curves to disk. to_write = ['train'] + params if train else ['test'] + params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save((curves, update_interval, n_examples), open(os.path.join(curves_path, f), 'wb')) if train: if any([x[-1] > best_accuracy for x in curves.values()]): print( 'New best accuracy! Saving network parameters to disk.' ) # Save network to disk. network.save(os.path.join(params_path, model_name + '.pt')) path = os.path.join( params_path, '_'.join(['auxiliary', model_name]) + '.pt') torch.save((logreg_model.coef_, logreg_model.intercept_), open(path, 'wb')) best_accuracy = max([x[-1] for x in curves.values()]) # Refit logistic regression model. logreg_model = logreg_fit(full_spike_record[:i], labels[:i], logreg_model) print() # Get next input sample. image = images[i % len(images)] sample = bernoulli(datum=image, time=time, dt=dt, max_prob=1).unsqueeze(1).unsqueeze(1) inpts = {'X': sample} # Run the network on the input. network.run(inpts=inpts, time=time) network.connections['X', 'Y_'].w = network.connections['X', 'Y'].w # Add to spikes recording. spike_record[i % update_interval] = spikes['Y_'].get('s').view( time, -1) full_spike_record[i] = spikes['Y_'].get('s').view(time, -1).sum(0) # Optionally plot various simulation information. if plot and i % plot_update_interval == 0: _input = inpts['X'].view(time, 400).sum(0).view(20, 20) w = network.connections['X', 'Y'].w _spikes = { 'X': spikes['X'].get('s').view(400, time), 'Y': spikes['Y'].get('s').view(n_filters * total_conv_size, time), 'Y_': spikes['Y_'].get('s').view(n_filters * total_conv_size, time) } inpt_axes, inpt_ims = plot_input(image.view(20, 20), _input, label=labels[i % len(labels)], ims=inpt_ims, axes=inpt_axes) spike_ims, spike_axes = plot_spikes(spikes=_spikes, ims=spike_ims, axes=spike_axes) weights_im = plot_conv2d_weights( w, im=weights_im, wmax=network.connections['X', 'Y'].wmax) plt.pause(1e-2) network.reset_() # Reset state variables. print(f'Progress: {n_examples} / {n_examples} ({t() - start:.4f} seconds)') i += 1 if i % len(labels) == 0: current_labels = labels[-update_interval:] current_record = full_spike_record[-update_interval:] else: current_labels = labels[i % len(labels) - update_interval:i % len(labels)] current_record = full_spike_record[i % len(labels) - update_interval:i % len(labels)] # Update and print accuracy evaluations. curves, preds = update_curves(curves, current_labels, n_classes, full_spike_record=current_record, logreg=logreg_model) print_results(curves) for scheme in preds: predictions[scheme] = torch.cat([predictions[scheme], preds[scheme]], -1) if train: if any([x[-1] > best_accuracy for x in curves.values()]): print('New best accuracy! Saving network parameters to disk.') # Save network to disk. network.save(os.path.join(params_path, model_name + '.pt')) path = os.path.join(params_path, '_'.join(['auxiliary', model_name]) + '.pt') torch.save((logreg_model.coef_, logreg_model.intercept_), open(path, 'wb')) if train: print('\nTraining complete.\n') else: print('\nTest complete.\n') print('Average accuracies:\n') for scheme in curves.keys(): print('\t%s: %.2f' % (scheme, float(np.mean(curves[scheme])))) # Save accuracy curves to disk. to_write = ['train'] + params if train else ['test'] + params to_write = [str(x) for x in to_write] f = '_'.join(to_write) + '.pt' torch.save((curves, update_interval, n_examples), open(os.path.join(curves_path, f), 'wb')) # Save results to disk. results = [np.mean(curves['logreg']), np.std(curves['logreg'])] to_write = params + results if train else test_params + results to_write = [str(x) for x in to_write] name = 'train.csv' if train else 'test.csv' if not os.path.isfile(os.path.join(results_path, name)): with open(os.path.join(results_path, name), 'w') as f: if train: columns = [ 'seed', 'n_train', 'kernel_size', 'stride', 'n_filters', 'padding', 'inhib', 'time', 'lr', 'lr_decay', 'dt', 'intensity', 'update_interval', 'mean_logreg', 'std_logreg' ] header = ','.join(columns) + '\n' f.write(header) else: columns = [ 'seed', 'n_train', 'n_test', 'kernel_size', 'stride', 'n_filters', 'padding', 'inhib', 'time', 'lr', 'lr_decay', 'dt', 'intensity', 'update_interval', 'mean_logreg', 'std_logreg' ] header = ','.join(columns) + '\n' f.write(header) with open(os.path.join(results_path, name), 'a') as f: f.write(','.join(to_write) + '\n') if labels.numel() > n_examples: labels = labels[:n_examples] else: while labels.numel() < n_examples: if 2 * labels.numel() > n_examples: labels = torch.cat( [labels, labels[:n_examples - labels.numel()]]) else: labels = torch.cat([labels, labels]) # Compute confusion matrices and save them to disk. confusions = {} for scheme in predictions: confusions[scheme] = confusion_matrix(labels, predictions[scheme]) to_write = ['train'] + params if train else ['test'] + test_params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save(confusions, os.path.join(confusion_path, f))
def main(seed=0, n_train=60000, n_test=10000, inhib=250, kernel_size=(16, ), stride=(2, ), n_filters=25, n_output=100, time=100, crop=0, lr=1e-2, lr_decay=0.99, dt=1, theta_plus=0.05, theta_decay=1e-7, intensity=1, norm=0.2, progress_interval=10, update_interval=250, train=True, plot=False, gpu=False): assert n_train % update_interval == 0, 'No. examples must be divisible by update_interval' params = [ seed, kernel_size, stride, n_filters, crop, lr, lr_decay, n_train, inhib, time, dt, theta_plus, theta_decay, intensity, norm, progress_interval, update_interval ] model_name = '_'.join([str(x) for x in params]) if not train: test_params = [ seed, kernel_size, stride, n_filters, crop, lr, lr_decay, n_train, n_test, inhib, time, dt, theta_plus, theta_decay, intensity, norm, progress_interval, update_interval ] np.random.seed(seed) if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) side_length = 28 - crop * 2 n_inpt = side_length**2 n_examples = n_train if train else n_test n_classes = 10 # Build network. if train: network = load_network( os.path.join( ROOT_DIR, 'params', 'mnist', 'crop_locally_connected', '0_12_4_150_4_0.01_0.99_60000_250.0_250_1.0_0.05_1e-07_0.5_0.2_10_250.pt' )) for l in network.layers: network.layers[l].dt = 1 network.layers[l].lbound = None for m in network.monitors: network.monitors[m].record_length = 0 network.connections['X', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu) network.layers['Y'].theta_decay = 0 network.layers['Y'].theta_plus = 0 network.layers['Y'].theta -= 0.5 * network.layers['Y'].theta.mean() network.layers['Y'].one_spike = False del network.connections['Y', 'Y'] output_layer = DiehlAndCookNodes(n=n_output, traces=True, rest=0, reset=0, thresh=1, refrac=0, decay=1e-2, trace_tc=5e-2) hidden_output_connection = Connection( network.layers['Y'], output_layer, nu=[0, lr], update_rule=WeightDependentPostPre, wmin=0, wmax=1, norm=norm * network.layers['Y'].n) w = -inhib * (torch.ones(n_output, n_output) - torch.diag(torch.ones(n_output))) output_recurrent_connection = Connection(output_layer, output_layer, w=w, update_rule=NoOp, wmin=-inhib, wmax=0) network.add_layer(output_layer, name='Z') network.add_connection(hidden_output_connection, source='Y', target='Z') network.add_connection(output_recurrent_connection, source='Z', target='Z') else: network = load_network(os.path.join(params_path, model_name + '.pt')) network.connections['Y', 'Z'].update_rule = NoOp( connection=network.connections['Y', 'Z'], nu=0) # network.layers['Z'].theta = 0 # network.layers['Z'].theta_decay = 0 # network.layers['Z'].theta_plus = 0 # del network.connections['Z', 'Z'] conv_size = network.connections['X', 'Y'].conv_size locations = network.connections['X', 'Y'].locations conv_prod = int(np.prod(conv_size)) n_neurons = n_filters * conv_prod # Voltage recording for excitatory and inhibitory layers. voltage_monitor = Monitor(network.layers['Y'], ['v'], time=time) network.add_monitor(voltage_monitor, name='output_voltage') # Load MNIST data. dataset = MNIST(path=data_path, download=True) if train: images, labels = dataset.get_train() else: images, labels = dataset.get_test() images *= intensity images = images[:, crop:-crop, crop:-crop].contiguous().view(-1, side_length**2) spikes = {} for layer in set(network.layers): spikes[layer] = Monitor(network.layers[layer], state_vars=['s'], time=time) network.add_monitor(spikes[layer], name=f'{layer}_spikes') # Train the network. if train: print('\nBegin training.\n') else: print('\nBegin test.\n') spike_ims = None spike_axes = None weights_im = None weights2_im = None unclamps = {} per_class = int(n_output / n_classes) for label in range(n_classes): unclamp = torch.ones(n_output).byte() unclamp[label * per_class:(label + 1) * per_class] = 0 unclamps[label] = unclamp predictions = torch.zeros(n_examples) corrects = torch.zeros(n_examples) start = t() for i in range(n_examples): if i % progress_interval == 0: print(f'Progress: {i} / {n_examples} ({t() - start:.4f} seconds)') start = t() if i % update_interval == 0 and i > 0: if train: network.save(os.path.join(params_path, model_name + '.pt')) network.connections['X', 'Y'].update_rule.nu[1] *= lr_decay # Get next input sample. image = images[i % len(images)] label = labels[i % len(images)].item() sample = poisson(datum=image, time=time, dt=dt) inpts = {'X': sample} # Run the network on the input. if train: network.run(inpts=inpts, time=time, unclamp={'Z': unclamps[label]}) else: network.run(inpts=inpts, time=time) if not train: retries = 0 while spikes['Z'].get('s').sum() < 5 and retries < 3: retries += 1 image *= 1.5 sample = poisson(datum=image, time=time, dt=dt) inpts = {'X': sample} if train: network.run(inpts=inpts, time=time, unclamp={'Z': unclamps[label]}) else: network.run(inpts=inpts, time=time) output = spikes['Z'].get('s') summed_neurons = output.sum(dim=1).view(per_class, n_classes) summed_classes = summed_neurons.sum(dim=1) prediction = torch.argmax(summed_classes).item() correct = prediction == label predictions[i] = prediction corrects[i] = int(correct) # print(spikes[].get('s').sum(), spikes['Z'].get('s').sum()) # Optionally plot various simulation information. if plot: _spikes = { 'X': spikes['X'].get('s').view(side_length**2, time), 'Y': spikes['Y'].get('s').view(n_neurons, time), 'Z': spikes['Z'].get('s').view(n_output, time) } spike_ims, spike_axes = plot_spikes(spikes=_spikes, ims=spike_ims, axes=spike_axes) weights_im = plot_locally_connected_weights( network.connections['X', 'Y'].w, n_filters, kernel_size, conv_size, locations, side_length, im=weights_im) w = network.connections['Y', 'Z'].w weights2_im = plot_weights(w, im=weights2_im, wmax=1) plt.pause(1e-8) network.reset_() # Reset state variables. print(f'Progress: {n_examples} / {n_examples} ({t() - start:.4f} seconds)') if train: network.save(os.path.join(params_path, model_name + '.pt')) if train: print('\nTraining complete.\n') else: print('\nTest complete.\n') accuracy = torch.mean(corrects).item() * 100 print(f'\nAccuracy: {accuracy}\n') to_write = params + [accuracy] if train else test_params + [accuracy] to_write = [str(x) for x in to_write] name = 'train.csv' if train else 'test.csv' if not os.path.isfile(os.path.join(results_path, name)): with open(os.path.join(results_path, name), 'w') as f: if train: f.write( 'random_seed,kernel_size,stride,n_filters,crop,lr,lr_decay,n_train,inhib,time,timestep,theta_plus,' 'theta_decay,intensity,norm,progress_interval,accuracy\n') else: f.write( 'random_seed,kernel_size,stride,n_filters,crop,lr,lr_decay,n_train,n_test,inhib,time,timestep,' 'theta_plus,theta_decay,intensity,norm,progress_interval,update_interval,accuracy\n' ) with open(os.path.join(results_path, name), 'a') as f: f.write(','.join(to_write) + '\n') if labels.numel() > n_examples: labels = labels[:n_examples] else: while labels.numel() < n_examples: if 2 * labels.numel() > n_examples: labels = torch.cat( [labels, labels[:n_examples - labels.numel()]]) else: labels = torch.cat([labels, labels]) # Compute confusion matrices and save them to disk. confusion = confusion_matrix(labels, predictions) to_write = ['train'] + params if train else ['test'] + test_params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save(confusion, os.path.join(confusion_path, f))
def main(n_hidden=100, time=100, lr=5e-2, plot=False, gpu=False): if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') network = Network() input_layer = Input(n=784, traces=True) hidden_layer = DiehlAndCookNodes(n=n_hidden, rest=0, reset=0, thresh=1, traces=True) output_layer = LIFNodes(n=784, rest=0, reset=0, thresh=1, traces=True) input_hidden_connection = Connection( input_layer, hidden_layer, wmin=0, wmax=1, norm=75, update_rule=Hebbian, nu=[0, lr] ) hidden_hidden_connection = Connection( hidden_layer, hidden_layer, wmin=-500, wmax=0, w=-500 * torch.zeros(n_hidden, n_hidden) - torch.diag(torch.ones(n_hidden)) ) hidden_output_connection = Connection( hidden_layer, input_layer, wmin=0, wmax=1, norm=15, update_rule=Hebbian, nu=[lr, 0] ) network.add_layer(input_layer, name='X') network.add_layer(hidden_layer, name='H') network.add_layer(output_layer, name='Y') network.add_connection(input_hidden_connection, source='X', target='H') network.add_connection(hidden_hidden_connection, source='H', target='H') network.add_connection(hidden_output_connection, source='H', target='Y') for layer in network.layers: monitor = Monitor( obj=network.layers[layer], state_vars=('s',), time=time ) network.add_monitor(monitor, name=layer) dataset = MNIST( path=os.path.join(ROOT_DIR, 'data', 'MNIST'), shuffle=True, download=True ) images, labels = dataset.get_train() images = images.view(-1, 784) images /= 4 labels = labels.long() spikes_ims = None spikes_axes = None weights1_im = None weights2_im = None inpt_ims = None inpt_axes = None for image, label in zip(images, labels): spikes = poisson(image, time=time, dt=network.dt) inpts = {'X': spikes} clamp = {'Y': spikes} unclamp = {'Y': ~spikes} network.run( inpts=inpts, time=time, clamp=clamp, unclamp=unclamp ) if plot: spikes = { l: network.monitors[l].get('s') for l in network.layers } spikes_ims, spikes_axes = plot_spikes( spikes, ims=spikes_ims, axes=spikes_axes ) inpt = spikes['X'].float().mean(1).view(28, 28) rcstn = spikes['Y'].float().mean(1).view(28, 28) inpt_axes, inpt_ims = plot_input( inpt, rcstn, label=label, axes=inpt_axes, ims=inpt_ims ) w1 = get_square_weights( network.connections['X', 'H'].w.view(784, n_hidden), int(np.ceil(np.sqrt(n_hidden))), 28 ) w2 = get_square_weights( network.connections['H', 'Y'].w.view(n_hidden, 784).t(), int(np.ceil(np.sqrt(n_hidden))), 28 ) weights1_im = plot_weights( w1, wmin=0, wmax=1, im=weights1_im ) weights2_im = plot_weights( w2, wmin=0, wmax=1, im=weights2_im ) plt.pause(0.01)
def main(seed=0, n_train=60000, n_test=10000, inhib=250, kernel_size=(16,), stride=(2,), n_filters=25, crop=4, lr=0.01, lr_decay=1, time=100, dt=1, theta_plus=0.05, theta_decay=1e-7, intensity=1, norm=0.2, progress_interval=10, update_interval=250, plot=False, train=True, gpu=False): assert n_train % update_interval == 0 and n_test % update_interval == 0, \ 'No. examples must be divisible by update_interval' params = [ seed, kernel_size, stride, n_filters, crop, lr, lr_decay, n_train, inhib, time, dt, theta_plus, theta_decay, intensity, norm, progress_interval, update_interval ] model_name = '_'.join([str(x) for x in params]) if not train: test_params = [ seed, kernel_size, stride, n_filters, crop, lr, lr_decay, n_train, n_test, inhib, time, dt, theta_plus, theta_decay, intensity, norm, progress_interval, update_interval ] np.random.seed(seed) if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) side_length = 28 - crop * 2 n_examples = n_train if train else n_test network = load_network(os.path.join(params_path, model_name + '.pt')) network.layers['X'] = Input(n=400) network.layers['Y'] = DiehlAndCookNodes( n=network.layers['Y'].n, thresh=network.layers['Y'].thresh, rest=network.layers['Y'].rest, reset=network.layers['Y'].reset, theta_plus=network.layers['Y'].theta_plus, theta_decay=network.layers['Y'].theta_decay ) network.add_layer(network.layers['X'], name='X') network.add_layer(network.layers['Y'], name='Y') network.connections['X', 'Y'].source = network.layers['X'] network.connections['X', 'Y'].target = network.layers['Y'] network.connections['X', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu ) network.layers['Y'].theta_decay = 0 network.layers['Y'].theta_plus = 0 conv_size = network.connections['X', 'Y'].conv_size locations = network.connections['X', 'Y'].locations conv_prod = int(np.prod(conv_size)) n_neurons = n_filters * conv_prod n_classes = 10 # Voltage recording for excitatory and inhibitory layers. voltage_monitor = Monitor(network.layers['Y'], ['v'], time=time) network.add_monitor(voltage_monitor, name='output_voltage') # Load MNIST data. dataset = MNIST(path=data_path, download=True) images, labels = dataset.get_test() images *= intensity images = images[:, crop:-crop, crop:-crop] # Neuron assignments and spike proportions. path = os.path.join(params_path, '_'.join(['auxiliary', model_name]) + '.pt') assignments, proportions, rates, ngram_scores = torch.load(open(path, 'rb')) spikes = {} for layer in set(network.layers): spikes[layer] = Monitor(network.layers[layer], state_vars=['s'], time=time) network.add_monitor(spikes[layer], name=f'{layer}_spikes') # Train the network. print('\nBegin black box adversarial attack.\n') spike_ims = None spike_axes = None weights_im = None inpt_ims = None inpt_axes = None max_iters = 25 delta = 0.1 epsilon = 0.1 for i in range(n_examples): # Get next input sample. original = images[i % len(images)].contiguous().view(-1) label = labels[i % len(images)] # Check if the image is correctly classified. sample = poisson(datum=original, time=time) inpts = {'X': sample} # Run the network on the input. network.run(inpts=inpts, time=time) # Check for incorrect classification. s = spikes['Y'].get('s').view(1, n_neurons, time) prediction = ngram(spikes=s, ngram_scores=ngram_scores, n_labels=10, n=2).item() if prediction != label: continue # Create adversarial example. adversarial = False while not adversarial: adv_example = 255 * torch.rand(original.size()) sample = poisson(datum=adv_example, time=time) inpts = {'X': sample} # Run the network on the input. network.run(inpts=inpts, time=time) # Check for incorrect classification. s = spikes['Y'].get('s').view(1, n_neurons, time) prediction = ngram(spikes=s, ngram_scores=ngram_scores, n_labels=n_classes, n=2).item() if prediction == label: adversarial = True j = 0 current = original.clone() while j < max_iters: # Orthogonal perturbation. # perturb = orthogonal_perturbation(delta=delta, image=adv_example, target=original) # temp = adv_example + perturb # # Forward perturbation. # temp = temp.clone() + forward_perturbation(epsilon * get_diff(temp, original), temp, adv_example) # print(temp) perturbation = torch.randn(original.size()) unnormed_source_direction = original - perturbation source_norm = torch.norm(unnormed_source_direction) source_direction = unnormed_source_direction / source_norm dot = torch.dot(perturbation, source_direction) perturbation -= dot * source_direction perturbation *= epsilon * source_norm / torch.norm(perturbation) D = 1 / np.sqrt(epsilon ** 2 + 1) direction = perturbation - unnormed_source_direction spherical_candidate = current + D * direction spherical_candidate = torch.clamp(spherical_candidate, 0, 255) new_source_direction = original - spherical_candidate new_source_direction_norm = torch.norm(new_source_direction) # length if spherical_candidate would be exactly on the sphere length = delta * source_norm # length including correction for deviation from sphere deviation = new_source_direction_norm - source_norm length += deviation # make sure the step size is positive length = max(0, length) # normalize the length length = length / new_source_direction_norm candidate = spherical_candidate + length * new_source_direction candidate = torch.clamp(candidate, 0, 255) sample = poisson(datum=candidate, time=time) inpts = {'X': sample} # Run the network on the input. network.run(inpts=inpts, time=time) # Check for incorrect classification. s = spikes['Y'].get('s').view(1, n_neurons, time) prediction = ngram(spikes=s, ngram_scores=ngram_scores, n_labels=10, n=2).item() # Optionally plot various simulation information. if plot: _input = original.view(side_length, side_length) reconstruction = candidate.view(side_length, side_length) _spikes = { 'X': spikes['X'].get('s').view(side_length ** 2, time), 'Y': spikes['Y'].get('s').view(n_neurons, time) } w = network.connections['X', 'Y'].w spike_ims, spike_axes = plot_spikes(spikes=_spikes, ims=spike_ims, axes=spike_axes) weights_im = plot_locally_connected_weights( w, n_filters, kernel_size, conv_size, locations, side_length, im=weights_im ) inpt_axes, inpt_ims = plot_input( _input, reconstruction, label=labels[i], ims=inpt_ims, axes=inpt_axes ) plt.pause(1e-8) if prediction == label: print('Attack failed.') else: print('Attack succeeded.') adv_example = candidate j += 1 network.reset_() # Reset state variables. print('\nAdversarial attack complete.\n')
dataset_path = "../../data/SpokenMNIST" train_dataset = SpokenMNIST(dataset_path, download=True, train=True) train_dataloader = torch.utils.data.DataLoader( train_dataset, batch_size=1, shuffle=True, num_workers=0 ) sample_shape = train_dataset[0][0].shape print("SpokenMNIST has shape ", sample_shape) network = Network() # Make sure to include the batch dimension but not time input_layer = RealInput(shape=(1, *sample_shape[1:]), traces=True) out_layer = DiehlAndCookNodes(shape=(1, *sample_shape[1:]), traces=True) out_conn = Connection(input_layer, out_layer, wmin=0, wmax=1) network.add_layer(input_layer, name="X") network.add_layer(out_layer, name="Y") network.add_connection(out_conn, source="X", target="Y") for step, batch in enumerate(tqdm(train_dataloader)): inpts = {"X": batch["audio"]} # the audio has potentially a variable amount of time time = spike_audio.shape[1] network.run(inpts=inpts, time=time, input_time_dim=1)
def main(seed=0, n_train=60000, n_test=10000, c_low=1, c_high=25, p_low=0.5, kernel_size=(16,), stride=(2,), n_filters=25, crop=4, lr=0.01, lr_decay=1, time=100, dt=1, theta_plus=0.05, theta_decay=1e-7, intensity=1, norm=0.2, progress_interval=10, update_interval=250, plot=False, train=True, gpu=False): assert n_train % update_interval == 0 and n_test % update_interval == 0, \ 'No. examples must be divisible by update_interval' params = [ seed, kernel_size, stride, n_filters, crop, lr, lr_decay, n_train, c_low, c_high, p_low, time, dt, theta_plus, theta_decay, intensity, norm, progress_interval, update_interval ] model_name = '_'.join([str(x) for x in params]) if not train: test_params = [ seed, kernel_size, stride, n_filters, crop, lr, lr_decay, n_train, n_test, c_low, c_high, p_low, time, dt, theta_plus, theta_decay, intensity, norm, progress_interval, update_interval ] np.random.seed(seed) if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) side_length = 28 - crop * 2 n_inpt = side_length ** 2 input_shape = [side_length, side_length] n_examples = n_train if train else n_test n_classes = 10 if _pair(kernel_size) == input_shape: conv_size = [1, 1] else: conv_size = (int((input_shape[0] - _pair(kernel_size)[0]) / _pair(stride)[0]) + 1, int((input_shape[1] - _pair(kernel_size)[1]) / _pair(stride)[1]) + 1) # Build network. if train: network = Network() input_layer = Input(n=n_inpt, traces=True, trace_tc=5e-2) output_layer = DiehlAndCookNodes( n=n_filters * conv_size[0] * conv_size[1], traces=True, rest=-65.0, reset=-60.0, thresh=-52.0, refrac=5, decay=1e-2, trace_tc=5e-2, theta_plus=theta_plus, theta_decay=theta_decay ) input_output_conn = LocallyConnectedConnection( input_layer, output_layer, kernel_size=kernel_size, stride=stride, n_filters=n_filters, nu=[0, lr], update_rule=PostPre, wmin=0, wmax=1, norm=norm, input_shape=input_shape ) w = torch.zeros(n_filters, *conv_size, n_filters, *conv_size) for fltr1 in range(n_filters): for fltr2 in range(n_filters): if fltr1 != fltr2: for j in range(conv_size[0]): for k in range(conv_size[1]): x1, y1 = fltr1 // np.sqrt(n_filters), fltr1 % np.sqrt(n_filters) x2, y2 = fltr2 // np.sqrt(n_filters), fltr2 % np.sqrt(n_filters) w[fltr1, j, k, fltr2, j, k] = max(-c_high, -c_low * np.sqrt(euclidean([x1, y1], [x2, y2]))) w = w.view(n_filters * conv_size[0] * conv_size[1], n_filters * conv_size[0] * conv_size[1]) recurrent_conn = Connection(output_layer, output_layer, w=w) plt.matshow(w) plt.colorbar() network.add_layer(input_layer, name='X') network.add_layer(output_layer, name='Y') network.add_connection(input_output_conn, source='X', target='Y') network.add_connection(recurrent_conn, source='Y', target='Y') else: network = load_network(os.path.join(params_path, model_name + '.pt')) network.connections['X', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu ) network.layers['Y'].theta_decay = 0 network.layers['Y'].theta_plus = 0 conv_size = network.connections['X', 'Y'].conv_size locations = network.connections['X', 'Y'].locations conv_prod = int(np.prod(conv_size)) n_neurons = n_filters * conv_prod # Voltage recording for excitatory and inhibitory layers. voltage_monitor = Monitor(network.layers['Y'], ['v'], time=time) network.add_monitor(voltage_monitor, name='output_voltage') # Load MNIST data. dataset = MNIST(path=data_path, download=True) if train: images, labels = dataset.get_train() else: images, labels = dataset.get_test() images *= intensity images = images[:, crop:-crop, crop:-crop] # Record spikes during the simulation. spike_record = torch.zeros(update_interval, time, n_neurons) # Neuron assignments and spike proportions. if train: assignments = -torch.ones_like(torch.Tensor(n_neurons)) proportions = torch.zeros_like(torch.Tensor(n_neurons, 10)) rates = torch.zeros_like(torch.Tensor(n_neurons, 10)) ngram_scores = {} else: path = os.path.join(params_path, '_'.join(['auxiliary', model_name]) + '.pt') assignments, proportions, rates, ngram_scores = torch.load(open(path, 'rb')) if train: best_accuracy = 0 # Sequence of accuracy estimates. curves = {'all': [], 'proportion': [], 'ngram': []} predictions = { scheme: torch.Tensor().long() for scheme in curves.keys() } spikes = {} for layer in set(network.layers): spikes[layer] = Monitor(network.layers[layer], state_vars=['s'], time=time) network.add_monitor(spikes[layer], name=f'{layer}_spikes') # Train the network. if train: print('\nBegin training.\n') else: print('\nBegin test.\n') spike_ims = None spike_axes = None weights_im = None # Calculate linear increase every update interval. if train: n_increase = int(p_low * n_examples) / update_interval increase = (c_high - c_low) / n_increase increases = 0 inhib = c_low start = t() for i in range(n_examples): if i % progress_interval == 0: print(f'Progress: {i} / {n_examples} ({t() - start:.4f} seconds)') start = t() if i % update_interval == 0 and i > 0: if train: network.connections['X', 'Y'].update_rule.nu[1] *= lr_decay if increases < n_increase: inhib = inhib + increase print(f'\nIncreasing inhibition to {inhib}.\n') w = torch.zeros(n_filters, *conv_size, n_filters, *conv_size) for fltr1 in range(n_filters): for fltr2 in range(n_filters): if fltr1 != fltr2: for j in range(conv_size[0]): for k in range(conv_size[1]): x1, y1 = fltr1 // np.sqrt(n_filters), fltr1 % np.sqrt(n_filters) x2, y2 = fltr2 // np.sqrt(n_filters), fltr2 % np.sqrt(n_filters) w[fltr1, j, k, fltr2, j, k] = max(-c_high, -c_low * np.sqrt(euclidean([x1, y1], [x2, y2]))) w = w.view(n_filters * conv_size[0] * conv_size[1], n_filters * conv_size[0] * conv_size[1]) network.connections['Y', 'Y'].w = w if i % len(labels) == 0: current_labels = labels[-update_interval:] else: current_labels = labels[i % len(images) - update_interval:i % len(images)] # Update and print accuracy evaluations. curves, preds = update_curves( curves, current_labels, n_classes, spike_record=spike_record, assignments=assignments, proportions=proportions, ngram_scores=ngram_scores, n=2 ) print_results(curves) for scheme in preds: predictions[scheme] = torch.cat([predictions[scheme], preds[scheme]], -1) # Save accuracy curves to disk. to_write = ['train'] + params if train else ['test'] + params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save((curves, update_interval, n_examples), open(os.path.join(curves_path, f), 'wb')) if train: if any([x[-1] > best_accuracy for x in curves.values()]): print('New best accuracy! Saving network parameters to disk.') # Save network to disk. network.save(os.path.join(params_path, model_name + '.pt')) path = os.path.join(params_path, '_'.join(['auxiliary', model_name]) + '.pt') torch.save((assignments, proportions, rates, ngram_scores), open(path, 'wb')) best_accuracy = max([x[-1] for x in curves.values()]) # Assign labels to excitatory layer neurons. assignments, proportions, rates = assign_labels(spike_record, current_labels, 10, rates) # Compute ngram scores. ngram_scores = update_ngram_scores(spike_record, current_labels, 10, 2, ngram_scores) print() # Get next input sample. image = images[i % update_interval].contiguous().view(-1) sample = poisson(datum=image, time=time, dt=dt) inpts = {'X': sample} # Run the network on the input. network.run(inpts=inpts, time=time) retries = 0 while spikes['Y'].get('s').sum() < 5 and retries < 3: retries += 1 image *= 2 sample = poisson(datum=image, time=time, dt=dt) inpts = {'X': sample} network.run(inpts=inpts, time=time) # Add to spikes recording. spike_record[i % update_interval] = spikes['Y'].get('s').t() # Optionally plot various simulation information. if plot: _spikes = { 'X': spikes['X'].get('s').view(side_length ** 2, time), 'Y': spikes['Y'].get('s').view(n_filters * conv_prod, time) } spike_ims, spike_axes = plot_spikes(spikes=_spikes, ims=spike_ims, axes=spike_axes) weights_im = plot_locally_connected_weights( network.connections[('X', 'Y')].w, n_filters, kernel_size, conv_size, locations, side_length, im=weights_im ) plt.pause(1e-8) network.reset_() # Reset state variables. print(f'Progress: {n_examples} / {n_examples} ({t() - start:.4f} seconds)') i += 1 if i % len(labels) == 0: current_labels = labels[-update_interval:] else: current_labels = labels[i % len(images) - update_interval:i % len(images)] # Update and print accuracy evaluations. curves, preds = update_curves( curves, current_labels, n_classes, spike_record=spike_record, assignments=assignments, proportions=proportions, ngram_scores=ngram_scores, n=2 ) print_results(curves) for scheme in preds: predictions[scheme] = torch.cat([predictions[scheme], preds[scheme]], -1) if train: if any([x[-1] > best_accuracy for x in curves.values()]): print('New best accuracy! Saving network parameters to disk.') # Save network to disk. network.save(os.path.join(params_path, model_name + '.pt')) path = os.path.join(params_path, '_'.join(['auxiliary', model_name]) + '.pt') torch.save((assignments, proportions, rates, ngram_scores), open(path, 'wb')) if train: print('\nTraining complete.\n') else: print('\nTest complete.\n') print('Average accuracies:\n') for scheme in curves.keys(): print('\t%s: %.2f' % (scheme, float(np.mean(curves[scheme])))) # Save accuracy curves to disk. to_write = ['train'] + params if train else ['test'] + params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save((curves, update_interval, n_examples), open(os.path.join(curves_path, f), 'wb')) # Save results to disk. results = [ np.mean(curves['all']), np.mean(curves['proportion']), np.mean(curves['ngram']), np.max(curves['all']), np.max(curves['proportion']), np.max(curves['ngram']) ] to_write = params + results if train else test_params + results to_write = [str(x) for x in to_write] name = 'train.csv' if train else 'test.csv' if not os.path.isfile(os.path.join(results_path, name)): with open(os.path.join(results_path, name), 'w') as f: if train: f.write( 'random_seed,kernel_size,stride,n_filters,crop,lr,lr_decay,n_train,c_low,c_high,p_low,time,timestep,theta_plus,' 'theta_decay,intensity,norm,progress_interval,update_interval,mean_all_activity,' 'mean_proportion_weighting,mean_ngram,max_all_activity,max_proportion_weighting,max_ngram\n' ) else: f.write( 'random_seed,kernel_size,stride,n_filters,crop,lr,lr_decay,n_train,n_test,c_low,c_high,p_low,time,timestep,' 'theta_plus,theta_decay,intensity,norm,progress_interval,update_interval,mean_all_activity,' 'mean_proportion_weighting,mean_ngram,max_all_activity,max_proportion_weighting,max_ngram\n' ) with open(os.path.join(results_path, name), 'a') as f: f.write(','.join(to_write) + '\n') if labels.numel() > n_examples: labels = labels[:n_examples] else: while labels.numel() < n_examples: if 2 * labels.numel() > n_examples: labels = torch.cat([labels, labels[:n_examples - labels.numel()]]) else: labels = torch.cat([labels, labels]) # Compute confusion matrices and save them to disk. confusions = {} for scheme in predictions: confusions[scheme] = confusion_matrix(labels, predictions[scheme]) to_write = ['train'] + params if train else ['test'] + test_params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save(confusions, os.path.join(confusion_path, f))
def main(seed=0, n_train=60000, n_test=10000, kernel_size=16, stride=4, n_filters=25, padding=0, inhib=500, lr=0.01, lr_decay=0.99, time=50, dt=1, intensity=1, progress_interval=10, update_interval=250, train=True, plot=False, gpu=False): if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) if not train: update_interval = n_test if kernel_size == 32: conv_size = 1 else: conv_size = int((32 - kernel_size + 2 * padding) / stride) + 1 per_class = int((n_filters * conv_size * conv_size) / 10) # Build network. network = Network() input_layer = Input(n=1024, shape=(1, 1, 32, 32), traces=True) conv_layer = DiehlAndCookNodes(n=n_filters * conv_size * conv_size, shape=(1, n_filters, conv_size, conv_size), traces=True) conv_conn = Conv2dConnection(input_layer, conv_layer, kernel_size=kernel_size, stride=stride, update_rule=PostPre, norm=0.4 * kernel_size**2, nu=[0, lr], wmin=0, wmax=1) w = -inhib * torch.ones(n_filters, conv_size, conv_size, n_filters, conv_size, conv_size) for f in range(n_filters): for i in range(conv_size): for j in range(conv_size): w[f, i, j, f, i, j] = 0 w = w.view(n_filters * conv_size**2, n_filters * conv_size**2) recurrent_conn = Connection(conv_layer, conv_layer, w=w) network.add_layer(input_layer, name='X') network.add_layer(conv_layer, name='Y') network.add_connection(conv_conn, source='X', target='Y') network.add_connection(recurrent_conn, source='Y', target='Y') # Voltage recording for excitatory and inhibitory layers. voltage_monitor = Monitor(network.layers['Y'], ['v'], time=time) network.add_monitor(voltage_monitor, name='output_voltage') # Load CIFAR-10 data. dataset = CIFAR10(path=os.path.join('..', '..', 'data', 'CIFAR10'), download=True) if train: images, labels = dataset.get_train() else: images, labels = dataset.get_test() images *= intensity images = images.mean(-1) # Lazily encode data as Poisson spike trains. data_loader = poisson_loader(data=images, time=time, dt=dt) spikes = {} for layer in set(network.layers): spikes[layer] = Monitor(network.layers[layer], state_vars=['s'], time=time) network.add_monitor(spikes[layer], name='%s_spikes' % layer) voltages = {} for layer in set(network.layers) - {'X'}: voltages[layer] = Monitor(network.layers[layer], state_vars=['v'], time=time) network.add_monitor(voltages[layer], name='%s_voltages' % layer) inpt_axes = None inpt_ims = None spike_ims = None spike_axes = None weights_im = None voltage_ims = None voltage_axes = None # Train the network. print('Begin training.\n') start = t() for i in range(n_train): if i % progress_interval == 0: print('Progress: %d / %d (%.4f seconds)' % (i, n_train, t() - start)) start = t() if train and i > 0: network.connections['X', 'Y'].nu[1] *= lr_decay # Get next input sample. sample = next(data_loader).unsqueeze(1).unsqueeze(1) inpts = {'X': sample} # Run the network on the input. network.run(inpts=inpts, time=time) # Optionally plot various simulation information. if plot: # inpt = inpts['X'].view(time, 1024).sum(0).view(32, 32) weights1 = conv_conn.w _spikes = { 'X': spikes['X'].get('s').view(32**2, time), 'Y': spikes['Y'].get('s').view(n_filters * conv_size**2, time) } _voltages = { 'Y': voltages['Y'].get('v').view(n_filters * conv_size**2, time) } # inpt_axes, inpt_ims = plot_input( # images[i].view(32, 32), inpt, label=labels[i], axes=inpt_axes, ims=inpt_ims # ) # voltage_ims, voltage_axes = plot_voltages(_voltages, ims=voltage_ims, axes=voltage_axes) spike_ims, spike_axes = plot_spikes(_spikes, ims=spike_ims, axes=spike_axes) weights_im = plot_conv2d_weights(weights1, im=weights_im) plt.pause(1e-8) network.reset_() # Reset state variables. print('Progress: %d / %d (%.4f seconds)\n' % (n_train, n_train, t() - start)) print('Training complete.\n')
def main(seed=0, n_neurons=100, n_train=60000, n_test=10000, inhib=500, dt=1, theta_plus=0.05, theta_decay=1e-7, intensity=1 / 40, progress_interval=10, update_interval=250, plot=False, train=True, gpu=False): assert n_train % update_interval == 0 and n_test % update_interval == 0, \ 'No. examples must be divisible by update_interval' params = [ seed, n_neurons, n_train, inhib, dt, theta_plus, theta_decay, intensity, progress_interval, update_interval ] test_params = [ seed, n_neurons, n_train, n_test, inhib, dt, theta_plus, theta_decay, intensity, progress_interval, update_interval ] model_name = '_'.join([str(x) for x in params]) np.random.seed(seed) if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) n_examples = n_train if train else n_test n_sqrt = int(np.ceil(np.sqrt(n_neurons))) n_classes = 10 # Build network. if train: network = Network() input_layer = RealInput(n=40, traces=True, trace_tc=5e-2) network.add_layer(input_layer, name='X') output_layer = DiehlAndCookNodes(n=n_neurons, traces=True, rest=-65.0, reset=-65.0, thresh=-52.0, refrac=5, decay=1e-2, trace_tc=5e-2, theta_plus=theta_plus, theta_decay=theta_decay) network.add_layer(output_layer, name='Y') w = 0.3 * torch.rand(40, n_neurons) input_connection = Connection(source=network.layers['X'], target=network.layers['Y'], w=w, update_rule=PostPre, nu=(0, 1), wmin=0, wmax=1, norm=4) network.add_connection(input_connection, source='X', target='Y') w = -inhib * (torch.ones(n_neurons, n_neurons) - torch.diag(torch.ones(n_neurons))) recurrent_connection = Connection(source=network.layers['Y'], target=network.layers['Y'], w=w, wmin=-inhib, wmax=0) network.add_connection(recurrent_connection, source='Y', target='Y') else: network = load_network(os.path.join(params_path, model_name + '.pt')) network.connections['X', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu) network.layers['Y'].theta_decay = 0 network.layers['Y'].theta_plus = 0 # Load Spoken MNIST data. dataset = SpokenMNIST(path=data_path, download=True, shuffle=False) if train: audio, labels = dataset.get_train() else: audio, labels = dataset.get_test() audio = [_ * intensity for _ in audio] # Record spikes during the simulation. avg_time = int(np.mean([_.size(0) for _ in audio])) spike_record = torch.zeros(update_interval, avg_time, n_neurons) # Neuron assignments and spike proportions. if train: assignments = -torch.ones_like(torch.Tensor(n_neurons)) proportions = torch.zeros_like(torch.Tensor(n_neurons, 10)) rates = torch.zeros_like(torch.Tensor(n_neurons, 10)) ngram_scores = {} else: path = os.path.join(params_path, '_'.join(['auxiliary', model_name]) + '.pt') assignments, proportions, rates, ngram_scores = torch.load( open(path, 'rb')) # Sequence of accuracy estimates. curves = {'all': [], 'proportion': [], 'ngram': []} predictions = {scheme: torch.Tensor().long() for scheme in curves.keys()} if train: best_accuracy = 0 spikes = {} for layer in set(network.layers): spikes[layer] = Monitor(network.layers[layer], state_vars=['s'], time=avg_time) network.add_monitor(spikes[layer], name='%s_spikes' % layer) # Train the network. if train: print('\nBegin training.\n') else: print('\nBegin test.\n') inpt_axes = None inpt_ims = None spike_ims = None spike_axes = None weights_im = None assigns_im = None perf_ax = None start = t() for i in range(n_examples): if i % progress_interval == 0: print(f'Progress: {i} / {n_examples} ({t() - start:.4f} seconds)') start = t() if i % update_interval == 0 and i > 0: if i % len(labels) == 0: current_labels = labels[-update_interval:] else: current_labels = labels[i % len(audio) - update_interval:i % len(audio)] # Update and print accuracy evaluations. curves, preds = update_curves(curves, current_labels, n_classes, spike_record=spike_record, assignments=assignments, proportions=proportions, ngram_scores=ngram_scores, n=2) print_results(curves) for scheme in preds: predictions[scheme] = torch.cat( [predictions[scheme], preds[scheme]], -1) # Save accuracy curves to disk. to_write = ['train'] + params if train else ['test'] + params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save((curves, update_interval, n_examples), open(os.path.join(curves_path, f), 'wb')) if train: if any([x[-1] > best_accuracy for x in curves.values()]): print( 'New best accuracy! Saving network parameters to disk.' ) # Save network to disk. network.save(os.path.join(params_path, model_name + '.pt')) path = os.path.join( params_path, '_'.join(['auxiliary', model_name]) + '.pt') torch.save((assignments, proportions, rates, ngram_scores), open(path, 'wb')) best_accuracy = max([x[-1] for x in curves.values()]) # Assign labels to excitatory layer neurons. assignments, proportions, rates = assign_labels( spike_record, current_labels, 10, rates) # Compute ngram scores. ngram_scores = update_ngram_scores(spike_record, current_labels, 10, 2, ngram_scores) print() # Get next input sample. sample = audio[i % len(audio)] sample = sample[:40, :] inpts = {'X': sample} time = min(avg_time, sample.size(0)) # Run the network on the input. network.run(inpts=inpts, time=time) retries = 0 while spikes['Y'].get('s').sum() < 5 and retries < 3: retries += 1 sample *= 2 inpts = {'X': sample} network.run(inpts=inpts, time=time) # Add to spikes recording. spike_record[i % update_interval] = spikes['Y'].get('s').t() # Optionally plot various simulation information. if plot: # _input = image.view(28, 28) # reconstruction = inpts['X'].view(time, 40).sum(0).view(8, 5) _spikes = {layer: spikes[layer].get('s') for layer in spikes} input_exc_weights = network.connections[('X', 'Y')].w square_weights = get_square_weights( input_exc_weights.view(40, n_neurons), n_sqrt, (8, 5)) # square_assignments = get_square_assignments(assignments, n_sqrt) # inpt_axes, inpt_ims = plot_input(_input, reconstruction, label=labels[i], axes=inpt_axes, ims=inpt_ims) spike_ims, spike_axes = plot_spikes(_spikes, ims=spike_ims, axes=spike_axes) weights_im = plot_weights(square_weights, im=weights_im) # assigns_im = plot_assignments(square_assignments, im=assigns_im) # perf_ax = plot_performance(curves, ax=perf_ax) plt.pause(1e-8) network.reset_() # Reset state variables. print(f'Progress: {n_examples} / {n_examples} ({t() - start:.4f} seconds)') i += 1 if i % len(labels) == 0: current_labels = labels[-update_interval:] else: current_labels = labels[i % len(audio) - update_interval:i % len(audio)] # Update and print accuracy evaluations. curves, preds = update_curves(curves, current_labels, n_classes, spike_record=spike_record, assignments=assignments, proportions=proportions, ngram_scores=ngram_scores, n=2) print_results(curves) for scheme in preds: predictions[scheme] = torch.cat([predictions[scheme], preds[scheme]], -1) if train: if any([x[-1] > best_accuracy for x in curves.values()]): print('New best accuracy! Saving network parameters to disk.') # Save network to disk. if train: network.save(os.path.join(params_path, model_name + '.pt')) path = os.path.join( params_path, '_'.join(['auxiliary', model_name]) + '.pt') torch.save((assignments, proportions, rates, ngram_scores), open(path, 'wb')) if train: print('\nTraining complete.\n') else: print('\nTest complete.\n') print('Average accuracies:\n') for scheme in curves.keys(): print('\t%s: %.2f' % (scheme, float(np.mean(curves[scheme])))) # Save accuracy curves to disk. to_write = ['train'] + params if train else ['test'] + params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save((curves, update_interval, n_examples), open(os.path.join(curves_path, f), 'wb')) # Save results to disk. results = [ np.mean(curves['all']), np.mean(curves['proportion']), np.mean(curves['ngram']), np.max(curves['all']), np.max(curves['proportion']), np.max(curves['ngram']) ] to_write = params + results if train else test_params + results to_write = [str(x) for x in to_write] name = 'train.csv' if train else 'test.csv' if not os.path.isfile(os.path.join(results_path, name)): with open(os.path.join(results_path, name), 'w') as f: if train: f.write( 'random_seed,n_neurons,n_train,inhib,timestep,theta_plus,theta_decay,intensity,' 'progress_interval,update_interval,mean_all_activity,mean_proportion_weighting,' 'mean_ngram,max_all_activity,max_proportion_weighting,max_ngram\n' ) else: f.write( 'random_seed,n_neurons,n_train,n_test,inhib,timestep,theta_plus,theta_decay,intensity,' 'progress_interval,update_interval,mean_all_activity,mean_proportion_weighting,' 'mean_ngram,max_all_activity,max_proportion_weighting,max_ngram\n' ) with open(os.path.join(results_path, name), 'a') as f: f.write(','.join(to_write) + '\n') if labels.numel() > n_examples: labels = labels[:n_examples] else: while labels.numel() < n_examples: if 2 * labels.numel() > n_examples: labels = torch.cat( [labels, labels[:n_examples - labels.numel()]]) else: labels = torch.cat([labels, labels]) # Compute confusion matrices and save them to disk. confusions = {} for scheme in predictions: confusions[scheme] = confusion_matrix(labels, predictions[scheme]) to_write = ['train'] + params if train else ['test'] + test_params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save(confusions, os.path.join(confusion_path, f))
int((conv_size[1] - kernel_size2[1]) / stride2[1]) + 1) n_classes = 10 n_neurons = n_filters * np.prod(conv_size) per_class = int(n_neurons / n_classes) total_kernel_size = int(np.prod(kernel_size)) total_kernel_size2 = int(np.prod(kernel_size2)) total_conv_size = int(np.prod(conv_size)) total_conv_size2 = int(np.prod(conv_size2)) # Build network. network = Network() input_layer = Input(n=784, shape=(1, 1, 28, 28), traces=True) conv_layer = DiehlAndCookNodes(n=n_filters * total_conv_size, shape=(1, n_filters, *conv_size), thresh=-64.0, traces=True, theta_plus=0.05, refrac=0) conv_layer_ = DiehlAndCookNodes(n=n_filters * total_conv_size, shape=(1, n_filters, *conv_size), refrac=0, traces=True, theta_decay=5e-1) conv_conn = Conv2dConnection(input_layer, conv_layer, kernel_size=kernel_size, stride=stride, update_rule=PostPre, norm=1.0 * int(np.sqrt(total_kernel_size)), nu=(0, 1e-2), wmax=2.0)
def __init__( self, n_input: int, n_neurons: int, n_classes: int, kernel_size: Union[Sequence[int], Sequence[Tuple[int, int]]], stride: Union[Sequence[int], Sequence[Tuple[int, int]]], n_filters: Sequence[int], n_fc: int = 1, inh: float = 17.5, dt: float = 1.0, nu: Optional[Union[float, Sequence[float]]] = (1e-4, 1e-2), reduction: Optional[callable] = None, wmin: float = 0.0, wmax: float = 1.0, norm: float = 78.4, tc_decay: float = 100.0, theta_plus: float = 0.05, tc_theta_decay: float = 1e7, input_shape: Optional[Iterable[int]] = None, ) -> None: #param definitions super().__init__(dt=dt) self.n_input = n_input self.n_neurons = n_neurons self.n_fc = n_fc self.kernel_size = kernel_size self.stride = stride self.n_filters = n_filters self.inh = inh self.dt = dt self.nu = nu self.reduction = reduction self.wmin = wmin self.wmax = wmax self.norm = norm self.theta_plus = theta_plus self.tc_theta_decay = tc_theta_decay self.input_shape = input_shape input_layer = Input(n=self.n_input, shape=self.input_shape, traces=True, tc_traces=20.0) self.add_layer(input_layer, name='Input') total_neuron = 0 for i in range(n_fc): total_neuron += n_neurons fc_output = DiehlAndCookNodes( n=n_neurons, traces=True, tc_trace=20.0, thresh=-52.0, rest=-65.0, reset=-65.0, refrac=5, tc_decay=tc_decay, theta_plus=theta_plus, tc_theta_decay=tc_theta_decay, ) fc_name = 'fc_output' + str(i) self.add_layer(fc_output, name=fc_name) w = 0.3 * torch.rand(self.n_input, self.n_neurons) fc_input_output_conn = Connection( source=input_layer, target=fc_output, w=w, nu=nu, update_rule=WeightDependentPostPre, reduction=reduction, wmin=wmin, wmax=wmax, norm=norm, ) self.add_connection(fc_input_output_conn, source='Input', target=fc_name) w = -self.inh * (torch.ones(self.n_neurons, self.n_neurons) - torch.diag(torch.ones(self.n_neurons))) fc_output_comp_conn = Connection(source=self.layers[fc_name], target=self.layers[fc_name], w=w, wmin=-self.inh, wmax=0) self.add_connection(fc_output_comp_conn, source=fc_name, target=fc_name) num_lc_layers = len(n_filters) for i in range(num_lc_layers): conv_size = [0, 0] kernel_size[i] = _pair(kernel_size[i]) stride[i] = _pair(stride[i]) if kernel_size[i] == input_shape[1:]: conv_size = [1, 1] else: conv_size = ( int((input_shape[1] - kernel_size[i][0]) / stride[i][0]) + 1, int((input_shape[2] - kernel_size[i][1]) / stride[i][1]) + 1, ) total_neuron += self.n_filters[i] * conv_size[0] * conv_size[1] lc_output = DiehlAndCookNodes( n=self.n_filters[i] * conv_size[0] * conv_size[1], traces=True, tc_trace=20.0, thresh=-52.0, rest=-65.0, reset=-65.0, refrac=5, tc_decay=tc_decay, thetaplus=theta_plus, tc_theta_decay=tc_theta_decay, ) lc_name = 'lc_output' + str(i) self.add_layer(lc_output, name=lc_name) lc_input_output_conn = LocalConnection( source=input_layer, target=self.layers[lc_name], kernel_size=kernel_size[i], stride=stride[i], n_filters=n_filters[i], nu=nu, reduction=reduction, update_rule=WeightDependentPostPre, wmin=wmin, wmax=wmax, norm=0.1, input_shape=input_shape[1:], ) self.add_connection(lc_input_output_conn, source="Input", target=lc_name) #makes weights so that competition is in each receptive field w = torch.zeros(n_filters[i], *conv_size, n_filters[i], *conv_size) for fltr1 in range(n_filters[i]): for fltr2 in range(n_filters[i]): if fltr1 != fltr2: for j in range(conv_size[0]): for k in range(conv_size[1]): w[fltr1, j, k, fltr2, j, k] = -inh w = w.view( n_filters[i] * conv_size[0] * conv_size[1], n_filters[i] * conv_size[0] * conv_size[1], ) lc_output_comp_conn = Connection(source=self.layers[lc_name], target=self.layers[lc_name], w=w) self.add_connection(lc_output_comp_conn, source=lc_name, target=lc_name) '''
def main(seed=0, n_neurons=100, n_train=60000, n_test=10000, c_low=1, c_high=25, p_low=0.5, time=250, dt=1, theta_plus=0.05, theta_decay=1e-7, intensity=1, progress_interval=10, update_interval=250, plot=False, train=True, gpu=False): assert n_train % update_interval == 0 and n_test % update_interval == 0,\ 'No. examples must be divisible by update_interval' params = [ seed, n_neurons, n_train, c_low, c_high, p_low, time, dt, theta_plus, theta_decay, intensity, progress_interval, update_interval ] model_name = '_'.join([str(x) for x in params]) if not train: test_params = [ seed, n_neurons, n_train, n_test, c_low, c_high, p_low, time, dt, theta_plus, theta_decay, intensity, progress_interval, update_interval ] np.random.seed(seed) if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) n_examples = n_train if train else n_test n_sqrt = int(np.ceil(np.sqrt(n_neurons))) n_classes = 10 # Build network. if train: network = Network(dt=dt) input_layer = Input(n=784, traces=True) exc_layer = DiehlAndCookNodes(n=n_neurons, traces=True) w = torch.rand(input_layer.n, exc_layer.n) input_exc_conn = Connection(input_layer, exc_layer, w=w, update_rule=PostPre, norm=78.4, nu=(1e-4, 1e-2), wmax=1.0) w = torch.zeros(exc_layer.n, exc_layer.n) for k1 in range(n_neurons): for k2 in range(n_neurons): if k1 != k2: x1, y1 = k1 // np.sqrt(n_neurons), k1 % np.sqrt(n_neurons) x2, y2 = k2 // np.sqrt(n_neurons), k2 % np.sqrt(n_neurons) w[k1, k2] = max( -c_high, -c_low * np.sqrt(euclidean([x1, y1], [x2, y2]))) recurrent_conn = Connection(exc_layer, exc_layer, w=w) network.add_layer(input_layer, name='X') network.add_layer(exc_layer, name='Y') network.add_connection(input_exc_conn, source='X', target='Y') network.add_connection(recurrent_conn, source='Y', target='Y') else: network = load_network(os.path.join(params_path, model_name + '.pt')) network.connections['X', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu) network.layers['Y'].theta_decay = 0 network.layers['Y'].theta_plus = 0 # Load MNIST data. dataset = MNIST(data_path, download=True) if train: images, labels = dataset.get_train() else: images, labels = dataset.get_test() images = images.view(-1, 784) images *= intensity # Record spikes during the simulation. spike_record = torch.zeros(update_interval, int(time / dt), n_neurons) # Neuron assignments and spike proportions. if train: assignments = -torch.ones_like(torch.Tensor(n_neurons)) proportions = torch.zeros_like(torch.Tensor(n_neurons, 10)) rates = torch.zeros_like(torch.Tensor(n_neurons, 10)) ngram_scores = {} else: path = os.path.join(params_path, '_'.join(['auxiliary', model_name]) + '.pt') assignments, proportions, rates, ngram_scores = torch.load( open(path, 'rb')) # Sequence of accuracy estimates. curves = {'all': [], 'proportion': [], 'ngram': []} predictions = {scheme: torch.Tensor().long() for scheme in curves.keys()} if train: best_accuracy = 0 spikes = {} for layer in set(network.layers) - {'X'}: spikes[layer] = Monitor(network.layers[layer], state_vars=['s'], time=int(time / dt)) network.add_monitor(spikes[layer], name='%s_spikes' % layer) # Train the network. if train: print('\nBegin training.\n') else: print('\nBegin test.\n') inpt_axes = None inpt_ims = None spike_ims = None spike_axes = None weights_im = None assigns_im = None perf_ax = None # Calculate linear increase every update interval. if train: n_increase = int(p_low * n_examples) / update_interval increase = (c_high - c_low) / n_increase increases = 0 inhib = c_low start = t() for i in range(n_examples): if train and i % update_interval == 0 and i > 0 and increases < n_increase: inhib = inhib + increase print(f'\nIncreasing inhibition to {inhib}.\n') w = torch.zeros(n_neurons, n_neurons) for k1 in range(n_neurons): for k2 in range(n_neurons): if k1 != k2: x1, y1 = k1 // np.sqrt(n_neurons), k1 % np.sqrt( n_neurons) x2, y2 = k2 // np.sqrt(n_neurons), k2 % np.sqrt( n_neurons) w[k1, k2] = max( -c_high, -inhib * np.sqrt(euclidean([x1, y1], [x2, y2]))) network.connections['Y', 'Y'].w = w increases += 1 if i % progress_interval == 0: print(f'Progress: {i} / {n_examples} ({t() - start:.4f} seconds)') start = t() if i % update_interval == 0 and i > 0: if i % len(labels) == 0: current_labels = labels[-update_interval:] else: current_labels = labels[i % len(images) - update_interval:i % len(images)] # Update and print accuracy evaluations. curves, preds = update_curves(curves, current_labels, n_classes, spike_record=spike_record, assignments=assignments, proportions=proportions, ngram_scores=ngram_scores, n=2) print_results(curves) for scheme in preds: predictions[scheme] = torch.cat( [predictions[scheme], preds[scheme]], -1) # Save accuracy curves to disk. to_write = ['train'] + params if train else ['test'] + params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save((curves, update_interval, n_examples), open(os.path.join(curves_path, f), 'wb')) if train: if any([x[-1] > best_accuracy for x in curves.values()]): print( 'New best accuracy! Saving network parameters to disk.' ) # Save network to disk. network.save(os.path.join(params_path, model_name + '.pt')) path = os.path.join( params_path, '_'.join(['auxiliary', model_name]) + '.pt') torch.save((assignments, proportions, rates, ngram_scores), open(path, 'wb')) best_accuracy = max([x[-1] for x in curves.values()]) # Assign labels to excitatory layer neurons. assignments, proportions, rates = assign_labels( spike_record, labels[i - update_interval:i], 10, rates) # Compute ngram scores. ngram_scores = update_ngram_scores( spike_record, labels[i - update_interval:i], 10, 2, ngram_scores) print() # Get next input sample. image = images[i] sample = poisson(datum=image, time=int(time / dt)) inpts = {'X': sample} # Run the network on the input. network.run(inpts=inpts, time=time) retries = 0 while spikes['Y'].get('s').sum() < 5 and retries < 3: retries += 1 image *= 2 sample = poisson(datum=image, time=int(time / dt)) inpts = {'X': sample} network.run(inpts=inpts, time=time) # Add to spikes recording. spike_record[i % update_interval] = spikes['Y'].get('s').t() # Optionally plot various simulation information. if plot: inpt = inpts['X'].view(time, 784).sum(0).view(28, 28) _spikes = {layer: spikes[layer].get('s') for layer in spikes} input_exc_weights = network.connections['X', 'Y'].w square_weights = get_square_weights( input_exc_weights.view(784, n_neurons), n_sqrt, 28) square_assignments = get_square_assignments(assignments, n_sqrt) # inpt_axes, inpt_ims = plot_input(images[i].view(28, 28), inpt, label=labels[i], axes=inpt_axes, ims=inpt_ims) spike_ims, spike_axes = plot_spikes(_spikes, ims=spike_ims, axes=spike_axes) weights_im = plot_weights(square_weights, im=weights_im) # assigns_im = plot_assignments(square_assignments, im=assigns_im) # perf_ax = plot_performance(curves, ax=perf_ax) plt.pause(1e-8) network.reset_() # Reset state variables. print(f'Progress: {n_examples} / {n_examples} ({t() - start:.4f} seconds)') i += 1 if i % len(labels) == 0: current_labels = labels[-update_interval:] else: current_labels = labels[i % len(images) - update_interval:i % len(images)] # Update and print accuracy evaluations. curves, preds = update_curves(curves, current_labels, n_classes, spike_record=spike_record, assignments=assignments, proportions=proportions, ngram_scores=ngram_scores, n=2) print_results(curves) for scheme in preds: predictions[scheme] = torch.cat([predictions[scheme], preds[scheme]], -1) if train: if any([x[-1] > best_accuracy for x in curves.values()]): print('New best accuracy! Saving network parameters to disk.') # Save network to disk. network.save(os.path.join(params_path, model_name + '.pt')) path = os.path.join(params_path, '_'.join(['auxiliary', model_name]) + '.pt') torch.save((assignments, proportions, rates, ngram_scores), open(path, 'wb')) if train: print('\nTraining complete.\n') else: print('\nTest complete.\n') print('Average accuracies:\n') for scheme in curves.keys(): print(f'\t%s: %.2f' % (scheme, float(np.mean(curves[scheme])))) # Save accuracy curves to disk. to_write = ['train'] + params if train else ['test'] + params to_write = [str(x) for x in to_write] f = '_'.join(to_write) + '.pt' torch.save((curves, update_interval, n_examples), open(os.path.join(curves_path, f), 'wb')) results = [ np.mean(curves['all']), np.mean(curves['proportion']), np.mean(curves['ngram']), np.max(curves['all']), np.max(curves['proportion']), np.max(curves['ngram']) ] to_write = params + results if train else test_params + results to_write = [str(x) for x in to_write] name = 'train.csv' if train else 'test.csv' if not os.path.isfile(os.path.join(results_path, name)): with open(os.path.join(results_path, name), 'w') as f: if train: f.write( 'random_seed,n_neurons,n_train,excite,c_low,c_high,p_low,time,timestep,theta_plus,theta_decay,' 'intensity,progress_interval,update_interval,mean_all_activity,mean_proportion_weighting,' 'mean_ngram,max_all_activity,max_proportion_weighting,max_ngram\n' ) else: f.write( 'random_seed,n_neurons,n_train,n_test,excite,c_low,c_high,p_low,time,timestep,theta_plus,theta_decay,' 'intensity,progress_interval,update_interval,mean_all_activity,mean_proportion_weighting,' 'mean_ngram,max_all_activity,max_proportion_weighting,max_ngram\n' ) with open(os.path.join(results_path, name), 'a') as f: f.write(','.join(to_write) + '\n') if labels.numel() > n_examples: labels = labels[:n_examples] else: while labels.numel() < n_examples: if 2 * labels.numel() > n_examples: labels = torch.cat( [labels, labels[:n_examples - labels.numel()]]) else: labels = torch.cat([labels, labels]) # Compute confusion matrices and save them to disk. confusions = {} for scheme in predictions: confusions[scheme] = confusion_matrix(labels, predictions[scheme]) to_write = ['train'] + params if train else ['test'] + test_params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save(confusions, os.path.join(confusion_path, f)) print()
def main(seed=0, n_neurons=100, n_train=60000, n_test=10000, inhib=100, lr=0.01, lr_decay=1, time=350, dt=1, theta_plus=0.05, theta_decay=1e-7, progress_interval=10, update_interval=250, plot=False, train=True, gpu=False): assert n_train % update_interval == 0 and n_test % update_interval == 0, \ 'No. examples must be divisible by update_interval' params = [ seed, n_neurons, n_train, inhib, lr_decay, time, dt, theta_plus, theta_decay, progress_interval, update_interval ] model_name = '_'.join([str(x) for x in params]) np.random.seed(seed) if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) n_examples = n_train if train else n_test n_classes = 10 # Build network. if train: network = Network(dt=dt) input_layer = Input(n=784, traces=True, trace_tc=5e-2) network.add_layer(input_layer, name='X') output_layer = DiehlAndCookNodes( n=n_classes, rest=0, reset=1, thresh=1, decay=1e-2, theta_plus=theta_plus, theta_decay=theta_decay, traces=True, trace_tc=5e-2 ) network.add_layer(output_layer, name='Y') w = torch.rand(784, n_classes) input_connection = Connection( source=input_layer, target=output_layer, w=w, update_rule=MSTDPET, nu=lr, wmin=0, wmax=1, norm=78.4, tc_e_trace=0.1 ) network.add_connection(input_connection, source='X', target='Y') else: network = load(os.path.join(params_path, model_name + '.pt')) network.connections['X', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu ) network.layers['Y'].theta_decay = torch.IntTensor([0]) network.layers['Y'].theta_plus = torch.IntTensor([0]) # Load MNIST data. environment = MNISTEnvironment( dataset=MNIST(root=data_path, download=True), train=train, time=time ) # Create pipeline. pipeline = Pipeline( network=network, environment=environment, encoding=repeat, action_function=select_spiked, output='Y', reward_delay=None ) spikes = {} for layer in set(network.layers): spikes[layer] = Monitor(network.layers[layer], state_vars=('s',), time=time) network.add_monitor(spikes[layer], name='%s_spikes' % layer) if train: network.add_monitor(Monitor( network.connections['X', 'Y'].update_rule, state_vars=('tc_e_trace',), time=time ), 'X_Y_e_trace') # Train the network. if train: print('\nBegin training.\n') else: print('\nBegin test.\n') spike_ims = None spike_axes = None weights_im = None elig_axes = None elig_ims = None start = t() for i in range(n_examples): if i % progress_interval == 0: print(f'Progress: {i} / {n_examples} ({t() - start:.4f} seconds)') start = t() if i > 0 and train: network.connections['X', 'Y'].update_rule.nu[1] *= lr_decay # Run the network on the input. # print("Example",i,"Results:") # for j in range(time): # result = pipeline.env_step() # pipeline.step(result,a_plus=1, a_minus=0) # print(result) for j in range(time): pipeline.train() if not train: _spikes = {layer: spikes[layer].get('s') for layer in spikes} if plot: _spikes = {layer: spikes[layer].get('s') for layer in spikes} w = network.connections['X', 'Y'].w square_weights = get_square_weights(w.view(784, n_classes), 4, 28) spike_ims, spike_axes = plot_spikes(_spikes, ims=spike_ims, axes=spike_axes) weights_im = plot_weights(square_weights, im=weights_im) elig_ims, elig_axes = plot_voltages( {'Y': network.monitors['X_Y_e_trace'].get('e_trace').view(-1, time)[1500:2000]}, plot_type='line', ims=elig_ims, axes=elig_axes ) plt.pause(1e-8) pipeline.reset_state_variables() # Reset state variables. network.connections['X', 'Y'].update_rule.tc_e_trace = torch.zeros(784, n_classes) print(f'Progress: {n_examples} / {n_examples} ({t() - start:.4f} seconds)') if train: network.save(os.path.join(params_path, model_name + '.pt')) print('\nTraining complete.\n') else: print('\nTest complete.\n')
def main(args): if args.gpu: torch.cuda.manual_seed_all(args.seed) else: torch.manual_seed(args.seed) conv_size = int( (28 - args.kernel_size + 2 * args.padding) / args.stride) + 1 # Build network. network = Network() input_layer = Input(n=784, shape=(1, 28, 28), traces=True) conv_layer = DiehlAndCookNodes( n=args.n_filters * conv_size * conv_size, shape=(args.n_filters, conv_size, conv_size), traces=True, ) conv_conn = Conv2dConnection( input_layer, conv_layer, kernel_size=args.kernel_size, stride=args.stride, update_rule=PostPre, norm=0.4 * args.kernel_size**2, nu=[0, args.lr], reduction=max_without_indices, wmax=1.0, ) w = torch.zeros(args.n_filters, conv_size, conv_size, args.n_filters, conv_size, conv_size) for fltr1 in range(args.n_filters): for fltr2 in range(args.n_filters): if fltr1 != fltr2: for i in range(conv_size): for j in range(conv_size): w[fltr1, i, j, fltr2, i, j] = -100.0 w = w.view(args.n_filters * conv_size * conv_size, args.n_filters * conv_size * conv_size) recurrent_conn = Connection(conv_layer, conv_layer, w=w) network.add_layer(input_layer, name="X") network.add_layer(conv_layer, name="Y") network.add_connection(conv_conn, source="X", target="Y") network.add_connection(recurrent_conn, source="Y", target="Y") # Voltage recording for excitatory and inhibitory layers. voltage_monitor = Monitor(network.layers["Y"], ["v"], time=args.time) network.add_monitor(voltage_monitor, name="output_voltage") if args.gpu: network.to("cuda") # Load MNIST data. train_dataset = MNIST( PoissonEncoder(time=args.time, dt=args.dt), None, os.path.join(ROOT_DIR, "data", "MNIST"), download=True, train=True, transform=transforms.Compose([ transforms.ToTensor(), transforms.Lambda(lambda x: x * args.intensity) ]), ) spikes = {} for layer in set(network.layers): spikes[layer] = Monitor(network.layers[layer], state_vars=["s"], time=args.time) network.add_monitor(spikes[layer], name="%s_spikes" % layer) voltages = {} for layer in set(network.layers) - {"X"}: voltages[layer] = Monitor(network.layers[layer], state_vars=["v"], time=args.time) network.add_monitor(voltages[layer], name="%s_voltages" % layer) # Train the network. print("Begin training.\n") start = time() weights_im = None for epoch in range(args.n_epochs): if epoch % args.progress_interval == 0: print("Progress: %d / %d (%.4f seconds)" % (epoch, args.n_epochs, time() - start)) start = time() train_dataloader = DataLoader( train_dataset, batch_size=args.batch_size, shuffle=True, num_workers=4, pin_memory=args.gpu, ) for step, batch in enumerate(tqdm(train_dataloader)): # Get next input sample. inpts = {"X": batch["encoded_image"]} if args.gpu: inpts = {k: v.cuda() for k, v in inpts.items()} # Run the network on the input. network.run(inpts=inpts, time=args.time, input_time_dim=0) # Decay learning rate. network.connections["X", "Y"].nu[1] *= 0.99 # Optionally plot various simulation information. if args.plot: weights = conv_conn.w weights_im = plot_conv2d_weights(weights, im=weights_im) plt.pause(1e-8) network.reset_() # Reset state variables. print("Progress: %d / %d (%.4f seconds)\n" % (args.n_epochs, args.n_epochs, time() - start)) print("Training complete.\n")
def main(seed=0, n_neurons=100, n_train=60000, n_test=10000, inhib=250, lr=1e-2, lr_decay=1, time=100, dt=1, theta_plus=0.05, theta_decay=1e-7, intensity=1, progress_interval=10, update_interval=100, plot=False, train=True, gpu=False, no_inhib=False, no_theta=False): assert n_train % update_interval == 0 and n_test % update_interval == 0, \ 'No. examples must be divisible by update_interval' params = [ seed, n_neurons, n_train, inhib, lr, lr_decay, time, dt, theta_plus, theta_decay, intensity, progress_interval, update_interval ] test_params = [ seed, n_neurons, n_train, n_test, inhib, lr, lr_decay, time, dt, theta_plus, theta_decay, intensity, progress_interval, update_interval ] model_name = '_'.join([str(x) for x in params]) np.random.seed(seed) if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) n_examples = n_train if train else n_test n_sqrt = int(np.ceil(np.sqrt(n_neurons))) n_classes = 10 # Build network. if train: network = Network() input_layer = Input(n=784, traces=True, trace_tc=5e-2) network.add_layer(input_layer, name='X') output_layer = DiehlAndCookNodes(n=n_neurons, traces=True, rest=0, reset=0, thresh=5, refrac=0, decay=1e-2, trace_tc=5e-2, theta_plus=theta_plus, theta_decay=theta_decay) network.add_layer(output_layer, name='Y') w = 0.3 * torch.rand(784, n_neurons) input_connection = Connection(source=network.layers['X'], target=network.layers['Y'], w=w, update_rule=WeightDependentPostPre, nu=[0, lr], wmin=0, wmax=1, norm=78.4) network.add_connection(input_connection, source='X', target='Y') w = -inhib * (torch.ones(n_neurons, n_neurons) - torch.diag(torch.ones(n_neurons))) recurrent_connection = Connection(source=network.layers['Y'], target=network.layers['Y'], w=w, wmin=-inhib, wmax=0, update_rule=WeightDependentPostPre, nu=[0, -100 * lr], norm=inhib / 2 * n_neurons) network.add_connection(recurrent_connection, source='Y', target='Y') mask = network.connections['Y', 'Y'].w == 0 masks = {('Y', 'Y'): mask} else: network = load_network(os.path.join(params_path, model_name + '.pt')) network.connections['X', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu) network.connections['Y', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu) network.layers['Y'].theta_decay = 0 network.layers['Y'].theta_plus = 0 if no_inhib: del network.connections['Y', 'Y'] if no_theta: network.layers['Y'].theta = 0 # Load MNIST data. dataset = MNIST(path=data_path, download=True) if train: images, labels = dataset.get_train() else: images, labels = dataset.get_test() images = images.view(-1, 784) images *= intensity labels = labels.long() monitors = {} for layer in set(network.layers): if 'v' in network.layers[layer].__dict__: monitors[layer] = Monitor(network.layers[layer], state_vars=['s', 'v'], time=time) else: monitors[layer] = Monitor(network.layers[layer], state_vars=['s'], time=time) network.add_monitor(monitors[layer], name=layer) # Train the network. if train: print('\nBegin training.\n') else: print('\nBegin test.\n') inpt_axes = None inpt_ims = None spike_ims = None spike_axes = None voltage_ims = None voltage_axes = None weights_im = None weights2_im = None unclamps = {} per_class = int(n_neurons / n_classes) for label in range(n_classes): unclamp = torch.ones(n_neurons).byte() unclamp[label * per_class:(label + 1) * per_class] = 0 unclamps[label] = unclamp predictions = torch.zeros(n_examples) corrects = torch.zeros(n_examples) start = t() for i in range(n_examples): if i % progress_interval == 0: print(f'Progress: {i} / {n_examples} ({t() - start:.4f} seconds)') start = t() if i % update_interval == 0 and i > 0 and train: network.save(os.path.join(params_path, model_name + '.pt')) network.connections['X', 'Y'].update_rule.nu[1] *= lr_decay # Get next input sample. image = images[i % len(images)] label = labels[i % len(images)].item() sample = poisson(datum=image, time=time, dt=dt) inpts = {'X': sample} # Run the network on the input. if train: network.run(inpts=inpts, time=time, unclamp={'Y': unclamps[label]}, masks=masks) else: network.run(inpts=inpts, time=time) if not train: retries = 0 while monitors['Y'].get('s').sum() == 0 and retries < 3: retries += 1 image *= 1.5 sample = poisson(datum=image, time=time, dt=dt) inpts = {'X': sample} if train: network.run(inpts=inpts, time=time, unclamp={'Y': unclamps[label]}, masks=masks) else: network.run(inpts=inpts, time=time) output = monitors['Y'].get('s') summed_neurons = output.sum(dim=1).view(n_classes, per_class) summed_classes = summed_neurons.sum(dim=1) prediction = torch.argmax(summed_classes).item() correct = prediction == label predictions[i] = prediction corrects[i] = int(correct) # Optionally plot various simulation information. if plot: # _input = image.view(28, 28) # reconstruction = inpts['X'].view(time, 784).sum(0).view(28, 28) # v = {'Y': monitors['Y'].get('v')} s = {layer: monitors[layer].get('s') for layer in monitors} input_exc_weights = network.connections['X', 'Y'].w square_weights = get_square_weights( input_exc_weights.view(784, n_neurons), n_sqrt, 28) recurrent_weights = network.connections['Y', 'Y'].w # inpt_axes, inpt_ims = plot_input(_input, reconstruction, label=labels[i], axes=inpt_axes, ims=inpt_ims) # voltage_ims, voltage_axes = plot_voltages(v, ims=voltage_ims, axes=voltage_axes) spike_ims, spike_axes = plot_spikes(s, ims=spike_ims, axes=spike_axes) weights_im = plot_weights(square_weights, im=weights_im) weights2_im = plot_weights(recurrent_weights, im=weights2_im, wmin=-inhib, wmax=0) plt.pause(1e-8) network.reset_() # Reset state variables. print(f'Progress: {n_examples} / {n_examples} ({t() - start:.4f} seconds)') if train: network.save(os.path.join(params_path, model_name + '.pt')) if train: print('\nTraining complete.\n') else: print('\nTest complete.\n') accuracy = torch.mean(corrects).item() * 100 print(f'\nAccuracy: {accuracy}\n') to_write = params + [accuracy] if train else test_params + [accuracy] to_write = [str(x) for x in to_write] name = 'train.csv' if train else 'test.csv' if not os.path.isfile(os.path.join(results_path, name)): with open(os.path.join(results_path, name), 'w') as f: if train: f.write( 'random_seed,n_neurons,n_train,inhib,lr,lr_decay,time,timestep,theta_plus,' 'theta_decay,intensity,progress_interval,update_interval,accuracy\n' ) else: f.write( 'random_seed,n_neurons,n_train,n_test,inhib,lr,lr_decay,time,timestep,' 'theta_plus,theta_decay,intensity,progress_interval,update_interval,accuracy\n' ) with open(os.path.join(results_path, name), 'a') as f: f.write(','.join(to_write) + '\n') if labels.numel() > n_examples: labels = labels[:n_examples] else: while labels.numel() < n_examples: if 2 * labels.numel() > n_examples: labels = torch.cat( [labels, labels[:n_examples - labels.numel()]]) else: labels = torch.cat([labels, labels]) # Compute confusion matrices and save them to disk. confusion = confusion_matrix(labels, predictions) to_write = ['train'] + params if train else ['test'] + test_params f = '_'.join([str(x) for x in to_write]) + '.pt' torch.save(confusion, os.path.join(confusion_path, f))
else: torch.manual_seed(seed) if not train: update_interval = n_test conv_size = int((28 - kernel_size + 2 * padding) / stride) + 1 per_class = int((n_filters * conv_size * conv_size) / 10) # Build network. network = Network() input_layer = Input(n=784, shape=(1, 28, 28), traces=True) conv_layer = DiehlAndCookNodes( n=n_filters * conv_size * conv_size, shape=(n_filters, conv_size, conv_size), traces=True, ) conv_conn = Conv2dConnection( input_layer, conv_layer, kernel_size=kernel_size, stride=stride, update_rule=PostPre, norm=0.4 * kernel_size**2, nu=[1e-4, 1e-2], wmax=1.0, ) w = torch.zeros(n_filters, conv_size, conv_size, n_filters, conv_size,
def main(seed=0, n_neurons=100, n_train=60000, n_test=10000, inhib=100, lr=0.01, lr_decay=1, time=350, dt=1, theta_plus=0.05, theta_decay=1e-7, progress_interval=10, update_interval=250, plot=False, train=True, gpu=False): assert n_train % update_interval == 0 and n_test % update_interval == 0, \ 'No. examples must be divisible by update_interval' params = [ seed, n_neurons, n_train, inhib, lr_decay, time, dt, theta_plus, theta_decay, progress_interval, update_interval ] test_params = [ seed, n_neurons, n_train, n_test, inhib, lr_decay, time, dt, theta_plus, theta_decay, progress_interval, update_interval ] model_name = '_'.join([str(x) for x in params]) np.random.seed(seed) if gpu: torch.set_default_tensor_type('torch.cuda.FloatTensor') torch.cuda.manual_seed_all(seed) else: torch.manual_seed(seed) n_examples = n_train if train else n_test n_sqrt = int(np.ceil(np.sqrt(n_neurons))) n_classes = 10 # Build network. if train: network = Network(dt=dt) input_layer = RealInput(n=784, traces=True, trace_tc=5e-2) network.add_layer(input_layer, name='X') output_layer = DiehlAndCookNodes( n=n_neurons, traces=True, rest=0, reset=1, thresh=1, refrac=0, decay=1e-2, trace_tc=5e-2, theta_plus=theta_plus, theta_decay=theta_decay ) network.add_layer(output_layer, name='Y') readout = IFNodes(n=n_classes, reset=0, thresh=1) network.add_layer(readout, name='Z') w = torch.rand(784, n_neurons) input_connection = Connection( source=input_layer, target=output_layer, w=w, update_rule=MSTDP, nu=lr, wmin=0, wmax=1, norm=78.4 ) network.add_connection(input_connection, source='X', target='Y') w = -inhib * (torch.ones(n_neurons, n_neurons) - torch.diag(torch.ones(n_neurons))) recurrent_connection = Connection( source=output_layer, target=output_layer, w=w, wmin=-inhib, wmax=0 ) network.add_connection(recurrent_connection, source='Y', target='Y') readout_connection = Connection( source=network.layers['Y'], target=readout, w=torch.rand(n_neurons, n_classes), norm=10 ) network.add_connection(readout_connection, source='Y', target='Z') else: network = load_network(os.path.join(params_path, model_name + '.pt')) network.connections['X', 'Y'].update_rule = NoOp( connection=network.connections['X', 'Y'], nu=network.connections['X', 'Y'].nu ) network.layers['Y'].theta_decay = 0 network.layers['Y'].theta_plus = 0 # Load MNIST data. dataset = MNIST(path=data_path, download=True) if train: images, labels = dataset.get_train() else: images, labels = dataset.get_test() images = images.view(-1, 784) labels = labels.long() spikes = {} for layer in set(network.layers) - {'X'}: spikes[layer] = Monitor(network.layers[layer], state_vars=['s'], time=time) network.add_monitor(spikes[layer], name='%s_spikes' % layer) # Train the network. if train: print('\nBegin training.\n') else: print('\nBegin test.\n') inpt_axes = None inpt_ims = None spike_ims = None spike_axes = None weights_im = None weights2_im = None assigns_im = None perf_ax = None predictions = torch.zeros(update_interval).long() start = t() for i in range(n_examples): if i % progress_interval == 0: print(f'Progress: {i} / {n_examples} ({t() - start:.4f} seconds)') start = t() if i > 0 and train: network.connections['X', 'Y'].update_rule.nu[1] *= lr_decay # Get next input sample. image = images[i % len(images)] # Run the network on the input. for j in range(time): readout = network.layers['Z'].s if readout[labels[i % len(labels)]]: network.run(inpts={'X': image.unsqueeze(0)}, time=1, reward=1, a_minus=0, a_plus=1) else: network.run(inpts={'X': image.unsqueeze(0)}, time=1, reward=0) label = spikes['Z'].get('s').sum(1).argmax() predictions[i % update_interval] = label.long() if i > 0 and i % update_interval == 0: if i % len(labels) == 0: current_labels = labels[-update_interval:] else: current_labels = labels[i % len(images) - update_interval:i % len(images)] accuracy = 100 * (predictions == current_labels).float().mean().item() print(f'Accuracy over last {update_interval} examples: {accuracy}') # Optionally plot various simulation information. if plot: _spikes = {layer: spikes[layer].get('s') for layer in spikes} input_exc_weights = network.connections['X', 'Y'].w square_weights = get_square_weights(input_exc_weights.view(784, n_neurons), n_sqrt, 28) exc_readout_weights = network.connections['Y', 'Z'].w # _input = image.view(28, 28) # reconstruction = inpts['X'].view(time, 784).sum(0).view(28, 28) # square_assignments = get_square_assignments(assignments, n_sqrt) spike_ims, spike_axes = plot_spikes(_spikes, ims=spike_ims, axes=spike_axes) weights_im = plot_weights(square_weights, im=weights_im) weights2_im = plot_weights(exc_readout_weights, im=weights2_im) # inpt_axes, inpt_ims = plot_input(_input, reconstruction, label=labels[i], axes=inpt_axes, ims=inpt_ims) # assigns_im = plot_assignments(square_assignments, im=assigns_im) # perf_ax = plot_performance(curves, ax=perf_ax) plt.pause(1e-8) network.reset_() # Reset state variables. print(f'Progress: {n_examples} / {n_examples} ({t() - start:.4f} seconds)') if train: print('\nTraining complete.\n') else: print('\nTest complete.\n')