def build_pes(model, pes, rule): conn = rule.connection # Create input error signal error = Signal(np.zeros(rule.size_in), name="PES:error") model.add_op(Reset(error)) model.sig[rule]['in'] = error # error connection will attach here acts = filtered_signal( model, pes, model.sig[conn.pre_obj]['out'], pes.pre_tau) acts_view = acts.reshape((1, acts.size)) # Compute the correction, i.e. the scaled negative error correction = Signal(np.zeros(error.shape), name="PES:correction") local_error = correction.reshape((error.size, 1)) model.add_op(Reset(correction)) # correction = -learning_rate * (dt / n_neurons) * error n_neurons = (conn.pre_obj.n_neurons if isinstance(conn.pre_obj, Ensemble) else conn.pre_obj.size_in) lr_sig = Signal(-pes.learning_rate * model.dt / n_neurons, name="PES:learning_rate") model.add_op(DotInc(lr_sig, error, correction, tag="PES:correct")) if conn.solver.weights or ( isinstance(conn.pre_obj, Neurons) and isinstance(conn.post_obj, Neurons)): post = get_post_ens(conn) weights = model.sig[conn]['weights'] encoders = model.sig[post]['encoders'] # encoded = dot(encoders, correction) encoded = Signal(np.zeros(weights.shape[0]), name="PES:encoded") model.add_op(Reset(encoded)) model.add_op(DotInc(encoders, correction, encoded, tag="PES:encode")) local_error = encoded.reshape((encoded.size, 1)) elif not isinstance(conn.pre_obj, (Ensemble, Neurons)): raise ValueError("'pre' object '%s' not suitable for PES learning" % (conn.pre_obj)) # delta = local_error * activities model.add_op(Reset(model.sig[rule]['delta'])) model.add_op(ElementwiseInc( local_error, acts_view, model.sig[rule]['delta'], tag="PES:Inc Delta")) # expose these for probes model.sig[rule]['error'] = error model.sig[rule]['correction'] = correction model.sig[rule]['activities'] = acts model.params[rule] = None # no build-time info to return
def build_pes(model, pes, rule): # TODO: Filter activities conn = rule.connection activities = model.sig[conn.pre_obj]['out'] error = model.sig[pes.error_connection]['out'] scaled_error = Signal(np.zeros(error.shape), name="PES:error * learning_rate") scaled_error_view = scaled_error.reshape((error.size, 1)) activities_view = activities.reshape((1, activities.size)) lr_sig = Signal(pes.learning_rate * model.dt, name="PES:learning_rate") model.add_op(Reset(scaled_error)) model.add_op(DotInc(lr_sig, error, scaled_error, tag="PES:scale error")) if conn.solver.weights or ( isinstance(conn.pre_obj, Neurons) and isinstance(conn.post_obj, Neurons)): post = (conn.post_obj.ensemble if isinstance(conn.post_obj, Neurons) else conn.post_obj) transform = model.sig[conn]['transform'] encoders = model.sig[post]['encoders'] encoded_error = Signal(np.zeros(transform.shape[0]), name="PES: encoded error") model.add_op(Reset(encoded_error)) model.add_op(DotInc( encoders, scaled_error, encoded_error, tag="PES:Encode error")) encoded_error_view = encoded_error.reshape((encoded_error.size, 1)) model.add_op(ElementwiseInc( encoded_error_view, activities_view, transform, tag="PES:Inc Transform")) elif isinstance(conn.pre_obj, Neurons): transform = model.sig[conn]['transform'] model.add_op(ElementwiseInc( scaled_error_view, activities_view, transform, tag="PES:Inc Transform")) else: assert isinstance(conn.pre_obj, Ensemble) decoders = model.sig[conn]['decoders'] model.add_op(ElementwiseInc( scaled_error_view, activities_view, decoders, tag="PES:Inc Decoder")) # expose these for probes model.sig[rule]['scaled_error'] = scaled_error model.sig[rule]['activities'] = activities model.params[rule] = None # no build-time info to return
def test_signal_reshape(): """Tests Signal.reshape""" three_d = Signal(np.ones((2, 2, 2))) assert three_d.reshape((8,)).shape == (8,) assert three_d.reshape((4, 2)).shape == (4, 2) assert three_d.reshape((2, 4)).shape == (2, 4) assert three_d.reshape(-1).shape == (8,) assert three_d.reshape((4, -1)).shape == (4, 2) assert three_d.reshape((-1, 4)).shape == (2, 4) assert three_d.reshape((2, -1, 2)).shape == (2, 2, 2) assert three_d.reshape((1, 2, 1, 2, 2, 1)).shape == (1, 2, 1, 2, 2, 1)
def test_signal_reshape(): """Tests Signal.reshape""" # check proper shape after reshape three_d = Signal(np.ones((2, 2, 2))) assert three_d.reshape((8, )).shape == (8, ) assert three_d.reshape((4, 2)).shape == (4, 2) assert three_d.reshape((2, 4)).shape == (2, 4) assert three_d.reshape(-1).shape == (8, ) assert three_d.reshape((4, -1)).shape == (4, 2) assert three_d.reshape((-1, 4)).shape == (2, 4) assert three_d.reshape((2, -1, 2)).shape == (2, 2, 2) assert three_d.reshape((1, 2, 1, 2, 2, 1)).shape == (1, 2, 1, 2, 2, 1) # check with non-contiguous arrays (and with offset) value = np.arange(20).reshape(5, 4) s = Signal(np.array(value), name="s") s0slice = slice(0, 3), slice(None, None, 2) s0shape = 2, 3 s0 = s[s0slice].reshape(*s0shape) assert s.offset == 0 assert np.array_equal(s0.initial_value, value[s0slice].reshape(*s0shape)) s1slice = slice(1, None), slice(None, None, 2) s1shape = 2, 4 s1 = s[s1slice].reshape(s1shape) assert s1.offset == 4 * s1.dtype.itemsize assert np.array_equal(s1.initial_value, value[s1slice].reshape(s1shape)) # check error if non-contiguous array cannot be reshaped without copy s2slice = slice(None, None, 2), slice(None, None, 2) s2shape = 2, 3 s2 = s[s2slice] with pytest.raises(SignalError): s2.reshape(s2shape) # check that views are working properly (incrementing `s` effects views) values = SignalDict() values.init(s) values.init(s0) values.init(s1) values[s] += 1 assert np.array_equal(values[s0], value[s0slice].reshape(s0shape) + 1) assert np.array_equal(values[s1], value[s1slice].reshape(s1shape) + 1)
def test_signal_reshape(): """Tests Signal.reshape""" # check proper shape after reshape three_d = Signal(np.ones((2, 2, 2))) assert three_d.reshape((8,)).shape == (8,) assert three_d.reshape((4, 2)).shape == (4, 2) assert three_d.reshape((2, 4)).shape == (2, 4) assert three_d.reshape(-1).shape == (8,) assert three_d.reshape((4, -1)).shape == (4, 2) assert three_d.reshape((-1, 4)).shape == (2, 4) assert three_d.reshape((2, -1, 2)).shape == (2, 2, 2) assert three_d.reshape((1, 2, 1, 2, 2, 1)).shape == (1, 2, 1, 2, 2, 1) # check with non-contiguous arrays (and with offset) value = np.arange(20).reshape(5, 4) s = Signal(np.array(value), name='s') s0slice = slice(0, 3), slice(None, None, 2) s0shape = 2, 3 s0 = s[s0slice].reshape(*s0shape) assert s.offset == 0 assert np.array_equal(s0.initial_value, value[s0slice].reshape(*s0shape)) s1slice = slice(1, None), slice(None, None, 2) s1shape = 2, 4 s1 = s[s1slice].reshape(s1shape) assert s1.offset == 4 * s1.dtype.itemsize assert np.array_equal(s1.initial_value, value[s1slice].reshape(s1shape)) # check error if non-contiguous array cannot be reshaped without copy s2slice = slice(None, None, 2), slice(None, None, 2) s2shape = 2, 3 s2 = s[s2slice] with pytest.raises(SignalError): s2.reshape(s2shape) # check that views are working properly (incrementing `s` effects views) values = SignalDict() values.init(s) values.init(s0) values.init(s1) values[s] += 1 assert np.array_equal(values[s0], value[s0slice].reshape(s0shape) + 1) assert np.array_equal(values[s1], value[s1slice].reshape(s1shape) + 1)
def test_opstomerge_check_signals(): sig = Signal(np.arange(10)) sig_orig = sig.reshape(10) sig_reshaped = sig.reshape(2, 5) assert not OpsToMerge.check_signals(Copy(sig_orig, sig_orig), Copy(sig_reshaped, sig_reshaped))