def test_running_average(): inp = np.arange(5) processor = RunningAverage() out = [processor(el) for el in inp] assert out == [0, 0.5, 1, 1.5, 2] inp = np.random.randn(10, 5) processor = RunningAverage() out = [processor(el) for el in inp] assert all( np.allclose(out[i], np.mean(inp[:i + 1], axis=0)) for i in xrange(len(inp)))
def test_running_average(): inp = np.arange(5) processor = RunningAverage() out = [processor(el) for el in inp] assert out == [0, 0.5, 1, 1.5, 2] assert np.array_equal(out, RunningAverage.batch(inp)) inp = np.random.randn(10, 5) processor = RunningAverage() out = [processor(el) for el in inp] assert all(np.allclose(out[i], np.mean(inp[:i+1], axis = 0)) for i in xrange(len(inp)))
def test_recent_running_average(): inp = np.arange(5) processor = RecentRunningAverage() out = [processor(el) for el in inp] out2 = processor.batch(inp) assert np.allclose(out, out2) assert np.allclose(out, [ 0.0, 0.7071067811865475, 1.4535590291019362, 2.226779514550968, 3.019787823462811 ]) inp = np.random.randn(10, 5) processor = RunningAverage() out = [processor(el) for el in inp] out2 = processor.batch(inp) assert np.allclose(out, out2)
def experiment_mnist_eqprop( layer_constructor, n_epochs=10, hidden_sizes=(500, ), minibatch_size=20, beta=.5, random_flip_beta=True, learning_rate=.05, n_negative_steps=20, n_positive_steps=4, initial_weight_scale=1., online_checkpoints_period=None, epoch_checkpoint_period=.25, skip_zero_epoch_test=False, n_test_samples=None, prop_direction: Union[str, Tuple] = 'neutral', bidirectional=True, renew_activations=True, do_fast_forward_pass=False, rebuild_coders=True, l2_loss=None, splitstream=True, seed=1234, ): """ Replicate the results of Scellier & Bengio: Equilibrium Propagation: Bridging the Gap between Energy-Based Models and Backpropagation https://www.frontiersin.org/articles/10.3389/fncom.2017.00024/full Specifically, the train_model demo here: https://github.com/bscellier/Towards-a-Biologically-Plausible-Backprop Differences between our code and theirs: - We do not keep persistent layer activations tied to data points over epochs. So our results should only really match for the first epoch. - We evaluate training score periodically, rather than online average (however you can see online score by setting online_checkpoints_period to something that is not None) """ print('Params:\n' + '\n'.join(list(f' {k} = {v}' for k, v in locals().items()))) rng = get_rng(seed) n_in = 784 n_out = 10 dataset = get_mnist_dataset(flat=True, n_test_samples=None).to_onehot() x_train, y_train = dataset.training_set.xy x_test, y_test = dataset.test_set.xy # Their 'validation set' is our 'test set' if is_test_mode(): x_train, y_train, x_test, y_test = x_train[: 100], y_train[: 100], x_test[: 100], y_test[: 100] n_epochs = 1 layer_sizes = [n_in] + list(hidden_sizes) + [n_out] rng = get_rng(rng) y_train = y_train.astype(np.float32) ra = RunningAverage() sp = Speedometer(mode='last') is_online_checkpoint = Checkpoints( online_checkpoints_period, skip_first=skip_zero_epoch_test ) if online_checkpoints_period is not None else lambda: False is_epoch_checkpoint = Checkpoints(epoch_checkpoint_period, skip_first=skip_zero_epoch_test) results = Duck() training_states = initialize_states( layer_constructor=layer_constructor, n_samples=minibatch_size, params=initialize_params(layer_sizes=layer_sizes, initial_weight_scale=initial_weight_scale, rng=rng)) if isinstance(prop_direction, str): fwd_prop_direction, backward_prop_direction = prop_direction, prop_direction else: fwd_prop_direction, backward_prop_direction = prop_direction for i, (ixs, info) in enumerate( minibatch_index_info_generator(n_samples=x_train.shape[0], minibatch_size=minibatch_size, n_epochs=n_epochs)): epoch = i * minibatch_size / x_train.shape[0] if is_epoch_checkpoint(epoch): n_samples = n_test_samples if n_test_samples is not None else len( x_test) y_pred_test, y_pred_train = [ run_inference( x_data=x[:n_test_samples], states=initialize_states( layer_constructor=layer_constructor, params=[s.params for s in training_states], n_samples=min(len(x), n_test_samples) if n_test_samples is not None else len(x)), n_steps=n_negative_steps, prop_direction=fwd_prop_direction, ) for x in (x_test, x_train) ] # y_pred_train = run_inference(x_data=x_train[:n_test_samples], states=initialize_states(params=[s.params for s in training_states], n_samples=min(len(x_train), n_test_samples) if n_test_samples is not None else len(x_train))) test_error = percent_argmax_incorrect(y_pred_test, y_test[:n_test_samples]) train_error = percent_argmax_incorrect(y_pred_train, y_train[:n_test_samples]) print( f'Epoch: {epoch:.3g}, Iter: {i}, Test Error: {test_error:.3g}%, Train Error: {train_error:.3g}, Mean Rate: {sp(i):.3g}iter/s' ) results[next, :] = dict(iter=i, epoch=epoch, train_error=train_error, test_error=test_error) yield results if epoch > 2 and train_error > 50: return # The Original training loop, just taken out here: x_data_sample, y_data_sample = x_train[ixs], y_train[ixs] training_states = run_eqprop_training_update( x_data=x_data_sample, y_data=y_data_sample, layer_states=training_states, beta=beta, random_flip_beta=random_flip_beta, learning_rate=learning_rate, layer_constructor=layer_constructor, bidirectional=bidirectional, l2_loss=l2_loss, renew_activations=renew_activations, n_negative_steps=n_negative_steps, n_positive_steps=n_positive_steps, prop_direction=prop_direction, splitstream=splitstream, rng=rng) this_train_score = ra( percent_argmax_correct(output_from_state(training_states), y_train[ixs])) if is_online_checkpoint(): print( f'Epoch {epoch:.3g}: Iter {i}: Score {this_train_score:.3g}%: Mean Rate: {sp(i):.2g}' )
def experiment_mnist_eqprop_torch( layer_constructor: Callable[[int, LayerParams], IDynamicLayer], n_epochs=10, hidden_sizes=(500, ), minibatch_size=10, # update mini-batch size batch_size=500, # total batch size beta=.5, random_flip_beta=True, learning_rate=.05, n_negative_steps=120, n_positive_steps=80, initial_weight_scale=1., online_checkpoints_period=None, epoch_checkpoint_period=1.0, #'100s', #{0: .25, 1: .5, 5: 1, 10: 2, 50: 4}, skip_zero_epoch_test=False, n_test_samples=10000, prop_direction: Union[str, Tuple] = 'neutral', bidirectional=True, renew_activations=True, do_fast_forward_pass=False, rebuild_coders=True, l2_loss=None, splitstream=False, seed=1234, prediction_inp_size=17, ## prediction input size delay=18, ## delay size for the clamped phase pred=True, ## if you want to use the prediction check_flg=False, ): """ Replicate the results of Scellier & Bengio: Equilibrium Propagation: Bridging the Gap between Energy-Based Models and Backpropagation https://www.frontiersin.org/articles/10.3389/fncom.2017.00024/full Specifically, the train_model demo here: https://github.com/bscellier/Towards-a-Biologically-Plausible-Backprop Differences between our code and theirs: - We do not keep persistent layer activations tied to data points over epochs. So our results should only really match for the first epoch. - We evaluate training score periodically, rather than online average (however you can see online score by setting online_checkpoints_period to something that is not None) """ torch.manual_seed(seed) device = 'cuda' if torch.cuda.is_available( ) and USE_CUDA_WHEN_AVAILABLE else 'cpu' if device == 'cuda': torch.set_default_tensor_type(torch.cuda.FloatTensor) print(f'Using Device: {device}') print('Params:\n' + '\n'.join(list(f' {k} = {v}' for k, v in locals().items()))) rng = get_rng(seed) n_in = 784 n_out = 10 dataset = input_data.read_data_sets('MNIST_data', one_hot=True) x_train, y_train = torch.tensor( dataset.train.images, dtype=torch.float32 ).to(device), torch.tensor(dataset.train.labels, dtype=torch.float32).to( device ) #(torch.tensor(a.astype(np.float32)).to(device) for a in dataset.mnist.train.images.xy) x_test, y_test = torch.tensor( dataset.test.images, dtype=torch.float32).to(device), torch.tensor( dataset.test.labels, dtype=torch.float32).to( device) # Their 'validation set' is our 'test set' x_val, y_val = torch.tensor( dataset.validation.images, dtype=torch.float32).to(device), torch.tensor( dataset.validation.labels, dtype=torch.float32).to( device) # Their 'validation set' is our 'test set' if is_test_mode(): x_train, y_train, x_test, y_test, x_val, y_val = x_train[: 100], y_train[: 100], x_test[: 100], y_test[: 100], x_val[: 100], y_val[: 100] n_epochs = 1 n_negative_steps = 3 n_positive_steps = 3 layer_sizes = [n_in] + list(hidden_sizes) + [n_out] ra = RunningAverage() sp = Speedometer(mode='last') is_online_checkpoint = Checkpoints( online_checkpoints_period, skip_first=skip_zero_epoch_test ) if online_checkpoints_period is not None else lambda: False is_epoch_checkpoint = Checkpoints(epoch_checkpoint_period, skip_first=skip_zero_epoch_test) training_states = initialize_states( layer_constructor=layer_constructor, #n_samples=minibatch_size, n_samples=batch_size, params=initialize_params(layer_sizes=layer_sizes, initial_weight_scale=initial_weight_scale, rng=rng)) # dbplot(training_states[0].params.w_fore[:10, :10], str(rng.randint(265))) if isinstance(prop_direction, str): fwd_prop_direction, backward_prop_direction = prop_direction, prop_direction else: fwd_prop_direction, backward_prop_direction = prop_direction def do_test(): # n_samples = n_test_samples if n_test_samples is not None else len(x_test) test_error, train_error, val_error = [ percent_argmax_incorrect( run_inference( x_data=x[:n_test_samples], states=initialize_states( layer_constructor=layer_constructor, params=[s.params for s in training_states], n_samples=n_samples), n_steps=n_negative_steps, prop_direction=fwd_prop_direction, ), y[:n_samples]).item() for x, y in [(x_test, y_test), (x_train, y_train), (x_val, y_val)] for n_samples in [ min(len(x), n_test_samples ) if n_test_samples is not None else len(x) ] ] # Not an actal loop... just hack for assignment in comprehensions print( f'Epoch: {epoch:.3g}, Iter: {i}, Test Error: {test_error:.3g}%, Train Error: {train_error:.3g}, Validation Error: {val_error:.3g}, Mean Rate: {sp(i):.3g}iter/s' ) return dict(iter=i, epoch=epoch, train_error=train_error, test_error=test_error, val_error=val_error), train_error, test_error, val_error results = Duck() pi = ProgressIndicator(expected_iterations=n_epochs * dataset.train.num_examples / minibatch_size, update_every='10s') dy_squared = [] dy_squared.append(None) dy_squared.append(None) for i, (ixs, info) in enumerate( minibatch_index_info_generator(n_samples=x_train.size()[0], minibatch_size=batch_size, n_epochs=n_epochs)): epoch = i * batch_size / x_train.shape[0] if is_epoch_checkpoint(epoch): check_flg = False x_train, y_train = shuffle_data(x_train, y_train) with pi.pause_measurement(): results[next, :], train_err, test_err, val_err = do_test() ## prepare for saving the parameters ws, bs = zip(*((s.params.w_aft, s.params.b) for s in training_states[1:])) f = None if os.path.isfile(directory + '/log.txt'): f = open(directory + '/log.txt', 'a') else: os.mkdir(directory) f = open(directory + '/log.txt', 'w') f.write("Epoch: " + str(epoch) + '\n') f.write("accuracy for training: " + str(train_err) + '\n') f.write("accuracy for testing: " + str(test_err) + '\n') f.write("accuracy for validation: " + str(val_err) + '\n') f.close() np.save(directory + '/w_epoch_' + str(epoch) + '.npy', ws) np.save(directory + '/b_epoch_' + str(epoch) + '.npy', bs) np.save(directory + '/dy_squared_epoch_' + str(epoch) + '.npy', dy_squared) yield results if epoch > 100 and results[-1, 'train_error'] > 50: return # The Original training loop, just taken out here: ixs = ixs.astype(np.int32) # this is for python version 3.7 x_data_sample, y_data_sample = x_train[ixs], y_train[ixs] training_states, dy_squared = run_eqprop_training_update( x_data=x_data_sample, y_data=y_data_sample, layer_states=training_states, beta=beta, random_flip_beta=random_flip_beta, learning_rate=learning_rate, layer_constructor=layer_constructor, bidirectional=bidirectional, l2_loss=l2_loss, renew_activations=renew_activations, n_negative_steps=n_negative_steps, n_positive_steps=n_positive_steps, prop_direction=prop_direction, splitstream=splitstream, rng=rng, prediction_inp_size=prediction_inp_size, delay=delay, device=device, epoch_check=check_flg, epoch=epoch, pred=pred, batch_size=batch_size, minibatch_size=minibatch_size, dy_squared=dy_squared) check_flg = False this_train_score = ra( percent_argmax_incorrect(output_from_state(training_states), y_train[ixs])) if is_online_checkpoint(): print( f'Epoch {epoch:.3g}: Iter {i}: Score {this_train_score:.3g}%: Mean Rate: {sp(i):.2g}' ) pi.print_update(info=f'Epoch: {epoch}') results[next, :], train_err, test_err, val_err = do_test() yield results
def test_uoro_estimates_grad_correctly(n_steps=5, n_runs=100, n_in=4, n_hid=6, n_out=3, seed=1234, plot_it=True): """ Plan: run T of RTRL without learning-rate 0. Then, on the nth step, get dl_dtheta. Then, starting with the same parameters, do N independent runs of UORO for T steps. Verify that s_tilde x t_tilde is, on average, the same as dl_dtheta. :return: """ torch.manual_seed(seed) x = Variable(torch.randn(n_steps, 1, n_in)) y = Variable( torch.LongTensor([y_ % n_out for y_ in range(n_steps)])[:, None]) rtrl = RTRL(forward_update_module=StatelessPredictorRNN(n_in=n_in, n_hid=n_hid, n_out=n_out, rnn_type='gru'), loss='xe', optimizer_factory=get_named_torch_optimizer_factory('sgd', 0.)) for x_, y_ in zip(x, y): rtrl.train_it(x_, y_) r = Namespace() r.theta, r.state, r.d_state_d_theta = rtrl.get_state() uoro = UOROVec(forward_update_module=StatelessPredictorRNN(n_in=n_in, n_hid=n_hid, n_out=n_out, rnn_type='gru'), loss='xe', optimizer_factory=get_named_torch_optimizer_factory( 'sgd', 0.), nu_policy='random') u = Namespace() u.theta, u.state, u.s_toupee, u.theta_toupee = uoro.get_state() errors = [] ra = RunningAverage() for _ in range(n_runs): uoro.set_state((r.theta, u.state, u.s_toupee, u.theta_toupee)) for x_, y_ in zip(x, y): uoro.train_it(x_, y_) _, _, s_toupee, theta_toupee = uoro.get_state() new_average = ra(torch.ger(s_toupee, theta_toupee)) errors.append((r.d_state_d_theta - new_average).norm().data.numpy()[0]) print(errors) if plot_it: from matplotlib import pyplot as plt plt.loglog(range(1, n_runs + 1), errors) funplot(lambda t: errors[0] / t**.5) plt.show()