def reproducible_network_train(seed=0, epochs=500, **additional_params): """ Make a reproducible train for Gradient Descent based neural network with a XOR problem and return trained network. Parameters ---------- seed : int Random State seed number for reproducibility. Defaults to ``0``. epochs : int Number of epochs for training. Defaults to ``500``. **additional_params Aditional parameters for Neural Network. Returns ------- GradientDescent instance Returns trained network. """ environment.reproducible(seed) xavier_normal = init.XavierNormal() tanh_weight1 = xavier_normal.sample((2, 5), return_array=True) tanh_weight2 = xavier_normal.sample((5, 1), return_array=True) network = algorithms.GradientDescent(connection=[ layers.Input(2), layers.Tanh(5, weight=tanh_weight1), layers.Tanh(1, weight=tanh_weight2), ], batch_size='all', **additional_params) network.train(xor_input_train, xor_target_train, epochs=epochs) return network
def test_full_batch_training(self): fullbatch_identifiers = BatchSizeProperty.fullbatch_identifiers x_train, _, y_train, _ = simple_classification() xavier_normal = init.XavierNormal() weight1 = xavier_normal.sample((10, 20), return_array=True) weight2 = xavier_normal.sample((20, 1), return_array=True) for network_class in self.network_classes: errors = [] for fullbatch_value in fullbatch_identifiers: net = network_class( [ layers.Input(10), layers.Sigmoid(20, weight=weight1), layers.Sigmoid(1, weight=weight2), ], batch_size=fullbatch_value, ) net.train(x_train, y_train, epochs=10) errors.append(net.errors.last()) self.assertTrue( np.all(np.abs(errors - errors[0]) < 1e-3), msg=errors, )
class Relu(ActivationLayer): """ The layer with the rectifier (ReLu) activation function. Parameters ---------- alpha : float Alpha parameter defines the decreasing rate for the negative values. If ``alpha`` is non-zero value then layer behave like a leaky ReLu. Defaults to ``0``. {ActivationLayer.Parameters} Methods ------- {ActivationLayer.Methods} Attributes ---------- {ActivationLayer.Attributes} """ alpha = NumberProperty(default=0, minval=0) weight = ParameterProperty(default=init.XavierNormal(gain='relu')) def activation_function(self, input_value): alpha = asfloat(self.alpha) return T.nnet.relu(input_value, alpha)
def test_xavier_normal(self): n_inputs, n_outputs = 30, 30 xavier_normal = init.XavierNormal() weight = self.eval(xavier_normal.sample((n_inputs, n_outputs))) self.assertNormalyDistributed(weight) self.assertAlmostEqual(weight.mean(), 0, places=1) self.assertAlmostEqual(weight.std(), math.sqrt(1. / (n_inputs + n_outputs)), places=2)
def assertCanNetworkOverfit(self, network_class, epochs=100, min_accepted_loss=0.001): x_train = 2 * np.random.random((10, 2)) - 1 # zero centered y_train = np.random.random((10, 1)) relu_xavier_normal = init.XavierNormal(gain=4) relu_weight = relu_xavier_normal.sample((2, 20), return_array=True) xavier_normal = init.XavierNormal(gain=2) sigmoid_weight = xavier_normal.sample((20, 1), return_array=True) optimizer = network_class([ layers.Input(2), layers.Relu(20, weight=relu_weight), layers.Sigmoid(1, weight=sigmoid_weight), ]) optimizer.train(x_train, y_train, epochs=epochs) self.assertLess(optimizer.errors.train[-1], min_accepted_loss)
class RBM(BaseAlgorithm, BaseNetwork, MinibatchTrainingMixin): """ Boolean/Bernoulli Restricted Boltzmann Machine (RBM). Algorithm assumes that inputs are either binary values or values between 0 and 1. Parameters ---------- n_visible : int Number of visible units. n_hidden : int Number of hidden units. {MinibatchTrainingMixin.batch_size} weight : array-like, Theano variable, Initializer or scalar Default initialization methods you can find :ref:`here <init-methods>`. Defaults to :class:`XavierNormal <neupy.init.XavierNormal>`. hidden_bias : array-like, Theano variable, Initializer or scalar Default initialization methods you can find :ref:`here <init-methods>`. Defaults to :class:`Constant(value=0) <neupy.init.Constant>`. visible_bias : array-like, Theano variable, Initializer or scalar Default initialization methods you can find :ref:`here <init-methods>`. Defaults to :class:`Constant(value=0) <neupy.init.Constant>`. {BaseNetwork.Parameters} Methods ------- train(input_train, epochs=100) Trains network. {BaseSkeleton.fit} visible_to_hidden(visible_input) Populates data throught the network and returns output from the hidden layer. hidden_to_visible(hidden_input) Propagates output from the hidden layer backward to the visible. gibbs_sampling(visible_input, n_iter=1) Makes Gibbs sampling ``n`` times using visible input. Examples -------- >>> import numpy as np >>> from neupy import algorithms >>> >>> data = np.array([ ... [1, 0, 1, 0], ... [1, 0, 1, 0], ... [1, 0, 0, 0], # incomplete sample ... [1, 0, 1, 0], ... ... [0, 1, 0, 1], ... [0, 0, 0, 1], # incomplete sample ... [0, 1, 0, 1], ... [0, 1, 0, 1], ... [0, 1, 0, 1], ... [0, 1, 0, 1], ... ]) >>> >>> rbm = algorithms.RBM(n_visible=4, n_hidden=1) >>> rbm.train(data, epochs=100) >>> >>> hidden_states = rbm.visible_to_hidden(data) >>> hidden_states.round(2) array([[ 0.99], [ 0.99], [ 0.95], [ 0.99], [ 0. ], [ 0.01], [ 0. ], [ 0. ], [ 0. ], [ 0. ]]) References ---------- [1] G. Hinton, A Practical Guide to Training Restricted Boltzmann Machines, 2010. http://www.cs.toronto.edu/~hinton/absps/guideTR.pdf """ n_visible = IntProperty(minval=1) n_hidden = IntProperty(minval=1) weight = ParameterProperty(default=init.XavierNormal()) hidden_bias = ParameterProperty(default=init.Constant(value=0)) visible_bias = ParameterProperty(default=init.Constant(value=0)) def __init__(self, n_visible, n_hidden, **options): self.theano_random = theano_random_stream() super(ConfigurableABC, self).__init__(n_hidden=n_hidden, n_visible=n_visible, **options) self.weight = create_shared_parameter(value=self.weight, name='algo:rbm/matrix:weight', shape=(n_visible, n_hidden)) self.hidden_bias = create_shared_parameter( value=self.hidden_bias, name='algo:rbm/vector:hidden-bias', shape=(n_hidden, ), ) self.visible_bias = create_shared_parameter( value=self.visible_bias, name='algo:rbm/vector:visible-bias', shape=(n_visible, ), ) super(RBM, self).__init__(**options) def init_input_output_variables(self): self.variables.update( network_input=T.matrix(name='algo:rbm/var:network-input'), ) def init_variables(self): self.variables.update(h_samples=theano.shared( name='algo:rbm/matrix:hidden-samples', value=asint(np.zeros((self.batch_size, self.n_hidden))), ), ) def init_methods(self): def free_energy(visible_sample): wx_b = T.dot(visible_sample, self.weight) + self.hidden_bias visible_bias_term = T.dot(visible_sample, self.visible_bias) hidden_term = T.log(asfloat(1) + T.exp(wx_b)).sum(axis=1) return -visible_bias_term - hidden_term def visible_to_hidden(visible_sample): wx_b = T.dot(visible_sample, self.weight) + self.hidden_bias return T.nnet.sigmoid(wx_b) def hidden_to_visible(hidden_sample): wx_b = T.dot(hidden_sample, self.weight.T) + self.visible_bias return T.nnet.sigmoid(wx_b) def sample_hidden_from_visible(visible_sample): theano_random = self.theano_random hidden_prob = visible_to_hidden(visible_sample) hidden_sample = theano_random.binomial(n=1, p=hidden_prob, dtype=theano.config.floatX) return hidden_sample def sample_visible_from_hidden(hidden_sample): theano_random = self.theano_random visible_prob = hidden_to_visible(hidden_sample) visible_sample = theano_random.binomial(n=1, p=visible_prob, dtype=theano.config.floatX) return visible_sample network_input = self.variables.network_input n_samples = asfloat(network_input.shape[0]) theano_random = self.theano_random weight = self.weight h_bias = self.hidden_bias v_bias = self.visible_bias h_samples = self.variables.h_samples step = asfloat(self.step) sample_indeces = theano_random.random_integers( low=0, high=n_samples - 1, size=(self.batch_size, )) v_pos = ifelse( T.eq(n_samples, self.batch_size), network_input, # In case if final batch has less number of # samples then expected network_input[sample_indeces]) h_pos = visible_to_hidden(v_pos) v_neg = sample_visible_from_hidden(h_samples) h_neg = visible_to_hidden(v_neg) weight_update = v_pos.T.dot(h_pos) - v_neg.T.dot(h_neg) h_bias_update = (h_pos - h_neg).mean(axis=0) v_bias_update = (v_pos - v_neg).mean(axis=0) # Stochastic pseudo-likelihood feature_index_to_flip = theano_random.random_integers( low=0, high=self.n_visible - 1, ) rounded_input = T.round(network_input) rounded_input = network_input rounded_input_flip = T.set_subtensor( rounded_input[:, feature_index_to_flip], 1 - rounded_input[:, feature_index_to_flip]) error = T.mean(self.n_visible * T.log( T.nnet.sigmoid( free_energy(rounded_input_flip) - free_energy(rounded_input)))) self.methods.update(train_epoch=theano.function( [network_input], error, name='algo:rbm/func:train-epoch', updates=[ (weight, weight + step * weight_update / n_samples), (h_bias, h_bias + step * h_bias_update), (v_bias, v_bias + step * v_bias_update), (h_samples, asint(theano_random.binomial(n=1, p=h_neg))), ]), prediction_error=theano.function( [network_input], error, name='algo:rbm/func:prediction-error', ), visible_to_hidden=theano.function( [network_input], visible_to_hidden(network_input), name='algo:rbm/func:visible-to-hidden', ), hidden_to_visible=theano.function( [network_input], hidden_to_visible(network_input), name='algo:rbm/func:hidden-to-visible', ), gibbs_sampling=theano.function( [network_input], sample_visible_from_hidden( sample_hidden_from_visible(network_input)), name='algo:rbm/func:gibbs-sampling', )) def train(self, input_train, input_test=None, epochs=100, summary='table'): """ Train RBM. Parameters ---------- input_train : 1D or 2D array-like input_test : 1D or 2D array-like or None Defaults to ``None``. epochs : int Number of training epochs. Defaults to ``100``. summary : {'table', 'inline'} Training summary type. Defaults to ``'table'``. """ return super(RBM, self).train(input_train=input_train, target_train=None, input_test=input_test, target_test=None, epochs=epochs, epsilon=None, summary=summary) def train_epoch(self, input_train, target_train=None): """ Train one epoch. Parameters ---------- input_train : array-like (n_samples, n_features) Returns ------- float """ errors = self.apply_batches( function=self.methods.train_epoch, input_data=input_train, description='Training batches', show_error_output=True, ) n_samples = len(input_train) return average_batch_errors(errors, n_samples, self.batch_size) def visible_to_hidden(self, visible_input): """ Populates data throught the network and returns output from the hidden layer. Parameters ---------- visible_input : array-like (n_samples, n_visible_features) Returns ------- array-like """ is_input_feature1d = (self.n_visible == 1) visible_input = format_data(visible_input, is_input_feature1d) outputs = self.apply_batches(function=self.methods.visible_to_hidden, input_data=visible_input, description='Hidden from visible batches', show_progressbar=True, show_error_output=False) return np.concatenate(outputs, axis=0) def hidden_to_visible(self, hidden_input): """ Propagates output from the hidden layer backward to the visible. Parameters ---------- hidden_input : array-like (n_samples, n_hidden_features) Returns ------- array-like """ is_input_feature1d = (self.n_hidden == 1) hidden_input = format_data(hidden_input, is_input_feature1d) outputs = self.apply_batches(function=self.methods.hidden_to_visible, input_data=hidden_input, description='Visible from hidden batches', show_progressbar=True, show_error_output=False) return np.concatenate(outputs, axis=0) def prediction_error(self, input_data, target_data=None): """ Compute the pseudo-likelihood of input samples. Parameters ---------- input_data : array-like Values of the visible layer Returns ------- float Value of the pseudo-likelihood. """ is_input_feature1d = (self.n_visible == 1) input_data = format_data(input_data, is_input_feature1d) errors = self.apply_batches( function=self.methods.prediction_error, input_data=input_data, description='Validation batches', show_error_output=True, ) return average_batch_errors(errors, n_samples=len(input_data), batch_size=self.batch_size) def gibbs_sampling(self, visible_input, n_iter=1): """ Makes Gibbs sampling n times using visible input. Parameters ---------- visible_input : 1d or 2d array n_iter : int Number of Gibbs sampling iterations. Defaults to ``1``. Returns ------- array-like Output from the visible units after perfoming n Gibbs samples. Array will contain only binary units (0 and 1). """ is_input_feature1d = (self.n_visible == 1) visible_input = format_data(visible_input, is_input_feature1d) gibbs_sampling = self.methods.gibbs_sampling input_ = visible_input for iteration in range(n_iter): input_ = gibbs_sampling(input_) return input_
class ParameterBasedLayer(BaseLayer): """ Layer that creates weight and bias parameters. Parameters ---------- size : int Layer's output size. weight : array-like, Theano variable, scalar or Initializer Defines layer's weights. Default initialization methods you can find :ref:`here <init-methods>`. Defaults to :class:`XavierNormal() <neupy.init.XavierNormal>`. bias : 1D array-like, Theano variable, scalar, Initializer or None Defines layer's bias. Default initialization methods you can find :ref:`here <init-methods>`. Defaults to :class:`Constant(0) <neupy.init.Constant>`. The ``None`` value excludes bias from the calculations and do not add it into parameters list. {BaseLayer.Parameters} Methods ------- {BaseLayer.Methods} Attributes ---------- {BaseLayer.Attributes} """ size = IntProperty(minval=1) weight = ParameterProperty(default=init.XavierNormal()) bias = ParameterProperty(default=init.Constant(value=0), allow_none=True) def __init__(self, size, **options): super(ParameterBasedLayer, self).__init__(size=size, **options) @property def weight_shape(self): return as_tuple(self.input_shape, self.output_shape) @property def bias_shape(self): if self.bias is not None: return as_tuple(self.output_shape) def initialize(self): super(ParameterBasedLayer, self).initialize() self.add_parameter(value=self.weight, name='weight', shape=self.weight_shape, trainable=True) if self.bias is not None: self.add_parameter(value=self.bias, name='bias', shape=self.bias_shape, trainable=True) def __repr__(self): classname = self.__class__.__name__ return '{name}({size})'.format(name=classname, size=self.size)
class Oja(BaseNetwork): """ Oja is an unsupervised technique used for the dimensionality reduction tasks. Notes ----- - In practice use step as very small value. For instance, value ``1e-7`` can be a good choice. - Normalize the input data before use Oja algorithm. Input data shouldn't contains large values. - Set up smaller values for weight if error for a few first iterations is big compare to the input values scale. For instance, if your input data have values between ``0`` and ``1`` error value equal to ``100`` is big. - During the training network report mean absolute error (MAE) Parameters ---------- minimized_data_size : int Expected number of features after minimization, defaults to ``1``. weight : array-like or ``None`` Defines networks weights. Defaults to :class:`XavierNormal() <neupy.init.XavierNormal>`. {BaseNetwork.Parameters} Methods ------- reconstruct(X) Reconstruct original dataset from the minimized input. train(X, epochs=100) Trains the network to the data X. Network trains until maximum number of ``epochs`` was reached. predict(X) Returns hidden representation of the input data ``X``. Basically, it applies dimensionality reduction. {BaseSkeleton.fit} Examples -------- >>> import numpy as np >>> from neupy import algorithms >>> >>> data = np.array([[2, 2], [1, 1], [4, 4], [5, 5]]) >>> >>> ojanet = algorithms.Oja( ... minimized_data_size=1, ... step=0.01, ... verbose=False ... ) >>> >>> ojanet.train(data, epochs=100) >>> minimized = ojanet.predict(data) >>> minimized array([[-2.82843122], [-1.41421561], [-5.65686243], [-7.07107804]]) >>> ojanet.reconstruct(minimized) array([[ 2.00000046, 2.00000046], [ 1.00000023, 1.00000023], [ 4.00000093, 4.00000093], [ 5.00000116, 5.00000116]]) """ minimized_data_size = IntProperty(minval=1) weight = ParameterProperty(default=init.XavierNormal()) def one_training_update(self, X, y_train): weight = self.weight minimized = np.dot(X, weight) reconstruct = np.dot(minimized, weight.T) error = X - reconstruct weight += self.step * np.dot(error.T, minimized) mae = np.sum(np.abs(error)) / X.size # Clean objects from the memory del minimized del reconstruct del error return mae def train(self, X, epochs=100): X = format_data(X) n_input_features = X.shape[1] if isinstance(self.weight, init.Initializer): weight_shape = (n_input_features, self.minimized_data_size) self.weight = self.weight.sample(weight_shape, return_array=True) if n_input_features != self.weight.shape[0]: raise ValueError("Invalid number of features. Expected {}, got {}" "".format(self.weight.shape[0], n_input_features)) super(Oja, self).train(X, epochs=epochs) def reconstruct(self, X): if not isinstance(self.weight, np.ndarray): raise NotTrained("Network hasn't been trained yet") X = format_data(X) if X.shape[1] != self.minimized_data_size: raise ValueError("Invalid input data feature space, expected " "{}, got {}.".format(X.shape[1], self.minimized_data_size)) return np.dot(X, self.weight.T) def predict(self, X): if not isinstance(self.weight, np.ndarray): raise NotTrained("Network hasn't been trained yet") X = format_data(X) return np.dot(X, self.weight)
class Oja(UnsupervisedLearningMixin, BaseNetwork): """ Oja unsupervised algorithm that minimize input data feature space. Notes ----- * In practice use step as very small value. For example ``1e-7``. * Normalize the input data before use Oja algorithm. Input data \ shouldn't contains large values. * Set up smaller values for weight if error for a few first iterations \ is big compare to the input values scale. For example, if your input \ data have values between 0 and 1 error value equal to 100 is big. Parameters ---------- minimized_data_size : int Expected number of features after minimization, defaults to ``1`` weight : array-like or ``None`` Defines networks weights. Defaults to :class:`XavierNormal() <neupy.core.init.XavierNormal>`. {BaseNetwork.step} {BaseNetwork.show_epoch} {BaseNetwork.epoch_end_signal} {BaseNetwork.train_end_signal} {Verbose.verbose} Methods ------- reconstruct(input_data): Reconstruct your minimized data. {BaseSkeleton.predict} {UnsupervisedLearningMixin.train} {BaseSkeleton.fit} Raises ------ ValueError * Try reconstruct without training. * Invalid number of input data features for ``train`` and \ ``reconstruct`` methods. Examples -------- >>> import numpy as np >>> from neupy import algorithms >>> >>> data = np.array([[2, 2], [1, 1], [4, 4], [5, 5]]) >>> >>> ojanet = algorithms.Oja( ... minimized_data_size=1, ... step=0.01, ... verbose=False ... ) >>> >>> ojanet.train(data, epsilon=1e-5) >>> minimized = ojanet.predict(data) >>> minimized array([[-2.82843122], [-1.41421561], [-5.65686243], [-7.07107804]]) >>> ojanet.reconstruct(minimized) array([[ 2.00000046, 2.00000046], [ 1.00000023, 1.00000023], [ 4.00000093, 4.00000093], [ 5.00000116, 5.00000116]]) """ minimized_data_size = IntProperty(minval=1) weight = ParameterProperty(default=init.XavierNormal()) def init_properties(self): del self.shuffle_data super(Oja, self).init_properties() def train_epoch(self, input_data, target_train): weight = self.weight minimized = np.dot(input_data, weight) reconstruct = np.dot(minimized, weight.T) error = input_data - reconstruct weight += self.step * np.dot(error.T, minimized) mae = np.sum(np.abs(error)) / input_data.size # Clear memory del minimized del reconstruct del error return mae def train(self, input_data, epsilon=1e-2, epochs=100): input_data = format_data(input_data) n_input_features = input_data.shape[1] if isinstance(self.weight, init.Initializer): weight_shape = (n_input_features, self.minimized_data_size) self.weight = self.weight.sample(weight_shape) if n_input_features != self.weight.shape[0]: raise ValueError( "Invalid number of features. Expected {}, got {}".format( self.weight.shape[0], n_input_features ) ) super(Oja, self).train(input_data, epsilon=epsilon, epochs=epochs) def reconstruct(self, input_data): if not isinstance(self.weight, np.ndarray): raise NotTrainedException("Train network before use " "reconstruct method.") input_data = format_data(input_data) if input_data.shape[1] != self.minimized_data_size: raise ValueError( "Invalid input data feature space, expected " "{}, got {}.".format( input_data.shape[1], self.minimized_data_size ) ) return np.dot(input_data, self.weight.T) def predict(self, input_data): if not isinstance(self.weight, np.ndarray): raise NotTrainedException("Train network before use " "prediction method.") input_data = format_data(input_data) return np.dot(input_data, self.weight)
def test_prelu_alpha_init_random_params(self): prelu_layer = layers.PRelu(10, alpha=init.XavierNormal()) prelu_layer.create_variables((None, 5)) alpha = self.eval(prelu_layer.alpha) self.assertEqual(10, np.unique(alpha).size)
def test_prelu_random_params(self): prelu_layer = layers.PRelu(10, alpha=init.XavierNormal()) layers.Input(10) > prelu_layer alpha = self.eval(prelu_layer.alpha) self.assertEqual(10, np.unique(alpha).size)
class Oja(BaseNetwork): """ Oja is an unsupervised technique used for the dimensionality reduction tasks. Notes ----- - In practice use step as very small value. For instance, value ``1e-7`` can be a good choice. - Normalize the input data before use Oja algorithm. Input data shouldn't contains large values. - Set up smaller values for weight if error for a few first iterations is big compare to the input values scale. For instance, if your input data have values between ``0`` and ``1`` error value equal to ``100`` is big. Parameters ---------- minimized_data_size : int Expected number of features after minimization, defaults to ``1``. weight : array-like or ``None`` Defines networks weights. Defaults to :class:`XavierNormal() <neupy.init.XavierNormal>`. {BaseNetwork.step} {BaseNetwork.show_epoch} {BaseNetwork.epoch_end_signal} {BaseNetwork.train_end_signal} {Verbose.verbose} Methods ------- reconstruct(input_data) Reconstruct original dataset from the minimized input. train(input_data, epsilon=1e-2, epochs=100) Trains algorithm based on the input dataset. For the dimensionality reduction input dataset assumes to be also a target. {BaseSkeleton.predict} {BaseSkeleton.fit} Raises ------ ValueError - Triggers when you try to reconstruct output without training. - Invalid number of input data features for the ``train`` and ``reconstruct`` methods. Examples -------- >>> import numpy as np >>> from neupy import algorithms >>> >>> data = np.array([[2, 2], [1, 1], [4, 4], [5, 5]]) >>> >>> ojanet = algorithms.Oja( ... minimized_data_size=1, ... step=0.01, ... verbose=False ... ) >>> >>> ojanet.train(data, epsilon=1e-5) >>> minimized = ojanet.predict(data) >>> minimized array([[-2.82843122], [-1.41421561], [-5.65686243], [-7.07107804]]) >>> ojanet.reconstruct(minimized) array([[ 2.00000046, 2.00000046], [ 1.00000023, 1.00000023], [ 4.00000093, 4.00000093], [ 5.00000116, 5.00000116]]) """ minimized_data_size = IntProperty(minval=1) weight = ParameterProperty(default=init.XavierNormal()) def train_epoch(self, input_data, target_train): weight = self.weight minimized = np.dot(input_data, weight) reconstruct = np.dot(minimized, weight.T) error = input_data - reconstruct weight += self.step * np.dot(error.T, minimized) mae = np.sum(np.abs(error)) / input_data.size # Clean objects from the memory del minimized del reconstruct del error return mae def train(self, input_data, epsilon=1e-2, epochs=100): input_data = format_data(input_data) n_input_features = input_data.shape[1] if isinstance(self.weight, init.Initializer): weight_shape = (n_input_features, self.minimized_data_size) self.weight = self.weight.sample(weight_shape) if n_input_features != self.weight.shape[0]: raise ValueError( "Invalid number of features. Expected {}, got {}".format( self.weight.shape[0], n_input_features)) super(Oja, self).train(input_data, epsilon=epsilon, epochs=epochs) def reconstruct(self, input_data): if not isinstance(self.weight, np.ndarray): raise NotTrained("Network hasn't been trained yet") input_data = format_data(input_data) if input_data.shape[1] != self.minimized_data_size: raise ValueError("Invalid input data feature space, expected " "{}, got {}.".format(input_data.shape[1], self.minimized_data_size)) return np.dot(input_data, self.weight.T) def predict(self, input_data): if not isinstance(self.weight, np.ndarray): raise NotTrained("Network hasn't been trained yet") input_data = format_data(input_data) return np.dot(input_data, self.weight)