Exemple #1
0
 def test_predict(self):
     """
     Test prediction for dataset. Returns a list of np.arrays.
     """
     # defining model
     layerSizes = [2,2,1]
     nn = MultilayerPerceptron(layerSizes)
     
     # setting up nn
     parameters = []
     parameters.append(np.ones((3,2)))
     parameters.append(np.ones((3,1)))
     nn.set_params(parameters)
     
     # preparing input NumericalDataSet
     inputSet = np.array([[2,2]])
     inputVec = np.array([[2,2]])
     nrObs = 10
     for _ in range(nrObs-1):
         inputSet = np.vstack((inputSet,inputVec))
     dataSet = NumericalDataSet(inputSet, None)
     
     # run function
     predictions = nn.predict(dataSet)
     
     # check nr of observations
     self.assertEqual(len(predictions), nrObs, "number of observations mismatch")
     for prediction in predictions:
         assert_equal(prediction, np.array([[2.9866142981514305]]), "wrong output")
Exemple #2
0
 def test_set_params_positive(self):
     layerSizes = [3,2,1]
     NN = MultilayerPerceptron(layerSizes)
     
     parameters = []
     parameters.append(np.ones((4,2)))
     parameters.append(np.ones((3,1)))
     NN.set_params(parameters)
Exemple #3
0
 def test_set_params_negative(self):
     layerSizes = [3,2,1]
     NN = MultilayerPerceptron(layerSizes)
     
     parameters = []
     parameters.append(np.ones((4,2)))
     parameters.append(np.ones((2,1)))
     try:
         NN.set_params(parameters)
     except Exception, e: 
         expected_errmsg = "overwriting parameters have not the same shape as the model"
         assert(e.message.startswith(expected_errmsg))
 def __init__(self, nns=None, arr_weights=None):
     if nns is not None:
         self.nets = nns
     elif arr_weights is not None:
         arr_layer_sizes = [ len(layer)-1 for layer in arr_weights[0] ]
         self.nets = []
         for weights in arr_weights:
             net = MultilayerPerceptron(arr_layer_sizes, do_classification=True)
             net.weights_arr = [ np.array(w) for w in weights ]
             self.nets.append(net)
     else:
         raise ValueError()
Exemple #5
0
 def __init__(self,
              iterations=1,
              learning_rate=0.5,
              topo=[('c', 3, 4), ('p', 2), ('c', 3, 4), ('p', 9),
                    ('mlp', 4, 4, 2)],
              activation_func=(np.tanh, nputils.tanh_deriv)):
     """
     Creates a new convolutional neural network with the given topology
     (architecture), learning rate and number of iterations.
     :param iterations: number of iterations for training.
     :param learning_rate: rate for updating the weights
     :param topo: defines the architecture of the net. It is a list of
     tuples. Each tuple represents a layer, where the first element is a
     character that specifies the type of layer. E.g. 'c' convolutional
     layer, 'p' pooling layer, 'mlp' fully connected conventional neural
     network. The next elements in the tuple are layer
     specific.
     Convolutional: 2nd element defines the kernel size, e.g. 3 for
     a 3x3 kernel. 3rd element specifies the number of maps in the layer.
     Pooling: 2nd element defines the pool patch size, e.g. 2 for a pool
     patch size of 2x2.
     MLP: each element defines the layer size for the network.
     A complete example looks like this: [('c', 3, 4), ('p', 2), ('c', 3, 4),
     ('p', 9), ('mlp', 4, 4, 2)]
     """
     self.split_ratio = 0.8
     self.iterations = iterations
     self.learning_rate = learning_rate
     self.layers = []
     self.activ_func = activation_func[0]
     self.deriv_acitv_func = activation_func[1]
     num_prev_maps = 1
     self.topo = topo
     # parse topology
     for layer in topo:
         # convolutional layer
         if layer[0] == 'c':
             conv_layer = ConvLayer(num_prev_maps=num_prev_maps,
                                    kernel_size=layer[1],
                                    num_maps=layer[2])
             self.add_layer(conv_layer)
             num_prev_maps = layer[2]
         # pooling layer
         elif layer[0] == 'p':
             self.add_layer(MaxPoolLayer(layer[1], num_prev_maps))
         # multilayer perceptron
         elif layer[0] == 'mlp':
             self.mlp = MultilayerPerceptron(
                 list(layer[1:]),
                 do_classification=True,
                 update_method=SimpleUpdate(self.learning_rate),
                 activ_func=(self.activ_func, self.deriv_acitv_func))
 def decode(self, encoded):
     alg_list = []
     # encode is a list of encoded algorithm instances
     for alg_weightsArr in encoded:
         # turn each element of the list(list) into an npArray
         npWeightsArr = []
         for arr in alg_weightsArr:
             npWeightsArr.append(np.array(arr))
         # predictinNN can be created since we have a list of npArrays
         newPredictionNN = MultilayerPerceptron(self.arrLayerSizes)
         newPredictionNN.set_params(npWeightsArr)
         alg_list.append(newPredictionNN)
     return alg_list
 def __init__(self, nns=None, arr_weights=None):
     if nns is not None:
         self.nets = nns
     elif arr_weights is not None:
         arr_layer_sizes = [len(layer) - 1 for layer in arr_weights[0]]
         self.nets = []
         for weights in arr_weights:
             net = MultilayerPerceptron(arr_layer_sizes,
                                        do_classification=True)
             net.weights_arr = [np.array(w) for w in weights]
             self.nets.append(net)
     else:
         raise ValueError()
Exemple #8
0
    def test_digits_prediction(self):
        training_data = np.loadtxt('../../data/pendigits-training.txt')[:500, :]
        testing_data = np.loadtxt('../../data/pendigits-testing.txt')

        layer_sizes = [16, 16, 10]
        update_method = Rprop(layer_sizes, init_step=0.01)
        nn = MultilayerPerceptron(layer_sizes, iterations=100, do_classification=True,
                           update_method=update_method,
                           batch_update_size=30,
                           activation_function=nputils.rectifier,
                           deriv_activation_function=nputils.rectifier_deriv)

        training_targets = nputils.convert_targets(training_data[:, -1], 10)
        training_input = training_data[:, 0:-1]
        maxs = np.max(training_input, axis=0)
        mins = np.min(training_input, axis=0)
        normalized_training_input = np.array(
            [(r - mins) / (maxs - mins) for r in training_input])

        training_data_set = NumericalDataSet(normalized_training_input,
                                              training_targets)

        testing_targets = nputils.convert_targets(testing_data[:, -1], 10)
        testing_input = testing_data[:, 0:-1]
        maxs = np.max(testing_input, axis=0)
        mins = np.min(testing_input, axis=0)
        normalized_testing_input = np.array(
            [(r - mins) / (maxs - mins) for r in testing_input])

        testing_data_set = NumericalDataSet(normalized_testing_input, testing_targets)

        nn.train(training_data_set)
        predictions = nn.predict(testing_data_set)

        predictions = [np.argmax(p) for p in predictions]

        conf_matrix = np.zeros((10, 10))
        conf_matrix = np.concatenate(([np.arange(0, 10)], conf_matrix), axis=0)
        conf_matrix = np.concatenate((np.transpose([np.arange(-1, 10)]), conf_matrix), axis=1)
        targets = testing_data[:, -1]
        for i in range(len(targets)):
            conf_matrix[targets[i] + 1, predictions[i] + 1] += 1

        print("Detection rate: " + str(np.sum(np.diagonal(conf_matrix[1:, 1:])) / len(targets)))
        print(str(conf_matrix))
Exemple #9
0
 def test_feedforward(self):
     """
     test feed forward for sample input. activations should coincide with calculated values
     shape (1,x)
     """
     layerSizes = [2,2,1]
     nn = MultilayerPerceptron(layerSizes)
     
     parameters = []
     parameters.append(np.ones((3,2)))
     parameters.append(np.ones((3,1)))
     nn.set_params(parameters)
     
     inputVec = np.array([[2,2]])
     activations = nn.feedforward(inputVec)
     assert_equal(activations[0], np.array([[2,2]]), "input activations wrong")
     assert_equal(activations[1], np.array([[0.9933071490757153, 0.9933071490757153]]), "hidden activations wrong")
     assert_equal(activations[2], np.array([[2.9866142981514305]]), "output activations wrong")
Exemple #10
0
 def test_train(self):
     """
     Testing only execution of train function
     """
     layerSizes = [2,2,1]
     nn = MultilayerPerceptron(layerSizes)
     
     # preparing input NumericalDataSet
     inputSet = np.array([[2,2]])
     inputVec = np.array([[2,2]])
     targetSet = np.array([[1]])
     targetVec = np.array([[1]])
     nrObs = 10
     for _ in range(nrObs-1):
         inputSet = np.vstack((inputSet,inputVec))
         targetSet = np.vstack((targetSet,targetVec))
     dataSet = NumericalDataSet(inputSet, targetSet)
     nn.train(dataSet)
 def get_instance(self):
     '''Create a PredictionNN Object
     :return: Object implementing AbstractAlgorithm
     '''
     return MultilayerPerceptron(self.arrLayerSizes,
                                 iterations=self.iterations,
                                 update_method=self.update_method,
                                 batch_update_size=self.batch_update_size,
                                 activ_func=self.activ_func,
                                 do_classification=self.do_classification)
Exemple #12
0
 def test_constructor_big_nn(self):
     """
     Testing if members initialized correctly.
     9 - layer NN
     """ 
     layerSizes = [1, 2, 3, 4, 5, 6, 7, 8, 9]
     NN = MultilayerPerceptron(layerSizes)
     # n layers -> n - 1 weight matrices
     assert_equal(len(NN.weights_arr), len(layerSizes) - 1, "number of layers not equal")
     assert_equal(NN.arr_layer_sizes, layerSizes, "layerSize member not right size")
     for i in range(len(layerSizes) - 1):
         assert_equal(NN.weights_arr[i].shape, (layerSizes[i] + 1, layerSizes[i+1]), "weight Matrix size not equal")
Exemple #13
0
 def test_backprop(self):
     layerSizes = [1,1,2,1]
     nn = MultilayerPerceptron(layerSizes)
     parameters = [];
     parameters.append(np.ones((2,1)))
     parameters.append(np.ones((2,2)))
     parameters.append(np.ones((3,1)))
     nn.set_params(parameters)
     
     inputVec = np.array([[1]])
     activations = nn.feedforward(inputVec)
     nn.backpropagation(activations, np.array([0.5]))
     
     # value computed through backpropagation by hand
     assert_equal(round(nn.weights_arr[0][0,0], 7), 0.9973057)
Exemple #14
0
 def __init__(self, iterations=1, learning_rate=0.5, topo=[('c', 3, 4), ('p', 2), ('c', 3, 4), ('p', 9), ('mlp', 4, 4, 2)], activation_func=(np.tanh, nputils.tanh_deriv)):
     """
     Creates a new convolutional neural network with the given topology
     (architecture), learning rate and number of iterations.
     :param iterations: number of iterations for training.
     :param learning_rate: rate for updating the weights
     :param topo: defines the architecture of the net. It is a list of
     tuples. Each tuple represents a layer, where the first element is a
     character that specifies the type of layer. E.g. 'c' convolutional
     layer, 'p' pooling layer, 'mlp' fully connected conventional neural
     network. The next elements in the tuple are layer
     specific.
     Convolutional: 2nd element defines the kernel size, e.g. 3 for
     a 3x3 kernel. 3rd element specifies the number of maps in the layer.
     Pooling: 2nd element defines the pool patch size, e.g. 2 for a pool
     patch size of 2x2.
     MLP: each element defines the layer size for the network.
     A complete example looks like this: [('c', 3, 4), ('p', 2), ('c', 3, 4),
     ('p', 9), ('mlp', 4, 4, 2)]
     """
     self.split_ratio = 0.8
     self.iterations = iterations
     self.learning_rate = learning_rate
     self.layers = []
     self.activ_func = activation_func[0]
     self.deriv_acitv_func = activation_func[1]
     num_prev_maps = 1
     self.topo = topo
     # parse topology
     for layer in topo:
         # convolutional layer
         if layer[0] == 'c':
             conv_layer = ConvLayer(num_prev_maps=num_prev_maps, kernel_size=layer[1], num_maps=layer[2])
             self.add_layer(conv_layer)
             num_prev_maps = layer[2]
         # pooling layer
         elif layer[0] == 'p':
             self.add_layer(MaxPoolLayer(layer[1], num_prev_maps))
         # multilayer perceptron
         elif layer[0] == 'mlp':
             self.mlp = MultilayerPerceptron(list(layer[1:]), do_classification=True, update_method=SimpleUpdate(self.learning_rate), activ_func=(self.activ_func, self.deriv_acitv_func))
Exemple #15
0
class ConvNet(AbstractAlgorithm):

    def __init__(self, iterations=1, learning_rate=0.5, topo=[('c', 3, 4), ('p', 2), ('c', 3, 4), ('p', 9), ('mlp', 4, 4, 2)], activation_func=(np.tanh, nputils.tanh_deriv)):
        """
        Creates a new convolutional neural network with the given topology
        (architecture), learning rate and number of iterations.
        :param iterations: number of iterations for training.
        :param learning_rate: rate for updating the weights
        :param topo: defines the architecture of the net. It is a list of
        tuples. Each tuple represents a layer, where the first element is a
        character that specifies the type of layer. E.g. 'c' convolutional
        layer, 'p' pooling layer, 'mlp' fully connected conventional neural
        network. The next elements in the tuple are layer
        specific.
        Convolutional: 2nd element defines the kernel size, e.g. 3 for
        a 3x3 kernel. 3rd element specifies the number of maps in the layer.
        Pooling: 2nd element defines the pool patch size, e.g. 2 for a pool
        patch size of 2x2.
        MLP: each element defines the layer size for the network.
        A complete example looks like this: [('c', 3, 4), ('p', 2), ('c', 3, 4),
        ('p', 9), ('mlp', 4, 4, 2)]
        """
        self.split_ratio = 0.8
        self.iterations = iterations
        self.learning_rate = learning_rate
        self.layers = []
        self.activ_func = activation_func[0]
        self.deriv_acitv_func = activation_func[1]
        num_prev_maps = 1
        self.topo = topo
        # parse topology
        for layer in topo:
            # convolutional layer
            if layer[0] == 'c':
                conv_layer = ConvLayer(num_prev_maps=num_prev_maps, kernel_size=layer[1], num_maps=layer[2])
                self.add_layer(conv_layer)
                num_prev_maps = layer[2]
            # pooling layer
            elif layer[0] == 'p':
                self.add_layer(MaxPoolLayer(layer[1], num_prev_maps))
            # multilayer perceptron
            elif layer[0] == 'mlp':
                self.mlp = MultilayerPerceptron(list(layer[1:]), do_classification=True, update_method=SimpleUpdate(self.learning_rate), activ_func=(self.activ_func, self.deriv_acitv_func))

    def add_layer(self, layer):
        """
        Adds the given layer to this network.
        :param layer: layer that is added
        """
        self.layers.append(layer)

    def feedforward(self, inputs):
        """
        Feed input forward through net calculating the ouput of each layer.
        :param inputs: 3D numpy array (usually a list of images)
        :return: List of 3D numpy arrays each representing the output of a layer
        except the first array in the list which is the input.
        """
        outputs = [inputs]
        for layer in self.layers:
            outputs.append(layer.feedforward(outputs[-1]))
        outputs.extend(self.mlp.feedforward(outputs[-1])[1:])
        return outputs

    def predict(self, inputs):
        predictions = self.predict_extended(inputs)
        if predictions[0].shape == (1,1):
            #binary output
            predictions = np.array(predictions).ravel()
            predictions[predictions <= 0] = 0
            predictions[predictions > 0] = 1
            return predictions[:, np.newaxis].astype(int)
        # multiclass
        sparse = np.zeros((len(predictions), predictions[0].shape[1]))
        for ix, _ in enumerate(sparse):
            sparse[ix][predictions[ix].argmax()] = 1
        assert sparse.sum() == len(predictions)
        return sparse

    def predict_extended(self, inputs):
        """
        Predicts targets for given data set.
        @param data_set: data Set inheriting AbstractDataSet
        :return: List of predictions, i.e. output of this net for each
        observation in the data set.
        """
        data_set = NumericalDataSet(inputs)
        predictions = []
        # loop through dataset
        for observation, _ in data_set.gen_observations( ):
            # make sure it is a numpy array
            input_arr = np.array(observation)
            outputs = self.feedforward(input_arr)
            predictions.append(outputs[-1])
        return predictions

    def predict_single(self, input_arr):
        """
        Predict class for a single observation.
        :param input_arr: Observation
        :return: Prediction for given observation
        """
        return self.feedforward(input_arr)[-1]

    def fit(self, inputs, targets):
        """
        Train net with given data set.
        :param data_set: Data set for training.
        n times random sampling for online learning 
        """
        split_point = int(len(inputs) * self.split_ratio)
        data_set = NumericalDataSet(inputs[:split_point], targets[:split_point])
        val_in = inputs[split_point:]
        val_targets = targets[split_point:]
        prev_layers = None
        prev_mlp = None

        self.train_acc_err = []
        self.val_acc_err = []

        for it in range(self.iterations):
            # randomly select observations as many times as there are
            # observations
            it_error = 0
            start = time.time()
            for _ in range(data_set.get_nr_observations()):
                input_arr, target_arr = data_set.rand_observation()
                # feed-forward
                outputs = self.feedforward(input_arr)
                current_error = nputils.calc_squared_error(target_arr, outputs[-1])
                it_error += current_error

                # mlp backpropagation and gradient descent
                mlp_outputs = outputs[-len(self.mlp.arr_layer_sizes):]
                mlp_deltas = self.mlp.backpropagation(mlp_outputs, target_arr)
                mlp_weight_updates = self.mlp.calculate_weight_updates(mlp_deltas, mlp_outputs)
                self.mlp.update_method.perform_update(self.mlp.weights_arr, mlp_weight_updates, current_error)
                # layer backpropagation and gradient descent
                # calculate backpropagated error of first mlp layer
                backprop_error = np.array([[x] for x in np.dot(self.mlp.weights_arr[0], mlp_deltas[0].transpose())])
                for layer in reversed(self.layers):
                    backprop_error = layer.backpropagate(backprop_error)
                # calculate the weight gradients and update the weights
                for layer in self.layers:
                    layer.calc_gradients()
                    layer.update(self.learning_rate)

            avg_error = it_error / data_set.nrObservations
            acc_err = self._accuracy_err(inputs, targets)
            self.train_acc_err.append(acc_err)

            #validation error
            acc_err = self._accuracy_err(val_in, val_targets)
            self.val_acc_err.append(acc_err)

            logging.info("Iteration #{} MSE: {}, TrainErr: {:.6f}, ValErr: {:.6f} ({:.2f}s)\n"\
                         .format(it + 1, avg_error, self.train_acc_err[-1], self.val_acc_err[-1], time.time()-start))

            #break cond
            if it > 3 and val_in is not None and self.val_acc_err[-1] > self.val_acc_err[-4]:
                # revert
                self.layers = prev_layers
                self.mlp = prev_mlp
                plt.figure()
                plt.plot(self.train_acc_err)
                plt.plot(self.val_acc_err)
                plt.show(block=False)
                break

            #prev
            if it > 0:
                prev_layers = copy.deepcopy(self.layers)
                prev_mlp = copy.deepcopy(self.mlp)


    def _accuracy_err(self, inputs, targets):
        if targets.shape[1] == 1:
            predictions = self.predict(inputs)
            acc_err = 1 - (predictions == targets).sum() / float(len(inputs))
        else:
            predictions = self.predict_extended(inputs)
            acc_err = 1 - ((np.vstack(predictions)).argmax(axis=1)==targets.argmax(axis=1)).sum() / float(len(inputs))
        return acc_err
    
    def set_params(self, parameters):
        pass
    
    def get_params(self):
        dct = {}
        dct["learning_rate"] = self.learning_rate
        dct["topo"] = self.topo
        return dct
Exemple #16
0
class ConvNet(AbstractAlgorithm):
    def __init__(self,
                 iterations=1,
                 learning_rate=0.5,
                 topo=[('c', 3, 4), ('p', 2), ('c', 3, 4), ('p', 9),
                       ('mlp', 4, 4, 2)],
                 activation_func=(np.tanh, nputils.tanh_deriv)):
        """
        Creates a new convolutional neural network with the given topology
        (architecture), learning rate and number of iterations.
        :param iterations: number of iterations for training.
        :param learning_rate: rate for updating the weights
        :param topo: defines the architecture of the net. It is a list of
        tuples. Each tuple represents a layer, where the first element is a
        character that specifies the type of layer. E.g. 'c' convolutional
        layer, 'p' pooling layer, 'mlp' fully connected conventional neural
        network. The next elements in the tuple are layer
        specific.
        Convolutional: 2nd element defines the kernel size, e.g. 3 for
        a 3x3 kernel. 3rd element specifies the number of maps in the layer.
        Pooling: 2nd element defines the pool patch size, e.g. 2 for a pool
        patch size of 2x2.
        MLP: each element defines the layer size for the network.
        A complete example looks like this: [('c', 3, 4), ('p', 2), ('c', 3, 4),
        ('p', 9), ('mlp', 4, 4, 2)]
        """
        self.split_ratio = 0.8
        self.iterations = iterations
        self.learning_rate = learning_rate
        self.layers = []
        self.activ_func = activation_func[0]
        self.deriv_acitv_func = activation_func[1]
        num_prev_maps = 1
        self.topo = topo
        # parse topology
        for layer in topo:
            # convolutional layer
            if layer[0] == 'c':
                conv_layer = ConvLayer(num_prev_maps=num_prev_maps,
                                       kernel_size=layer[1],
                                       num_maps=layer[2])
                self.add_layer(conv_layer)
                num_prev_maps = layer[2]
            # pooling layer
            elif layer[0] == 'p':
                self.add_layer(MaxPoolLayer(layer[1], num_prev_maps))
            # multilayer perceptron
            elif layer[0] == 'mlp':
                self.mlp = MultilayerPerceptron(
                    list(layer[1:]),
                    do_classification=True,
                    update_method=SimpleUpdate(self.learning_rate),
                    activ_func=(self.activ_func, self.deriv_acitv_func))

    def add_layer(self, layer):
        """
        Adds the given layer to this network.
        :param layer: layer that is added
        """
        self.layers.append(layer)

    def feedforward(self, inputs):
        """
        Feed input forward through net calculating the ouput of each layer.
        :param inputs: 3D numpy array (usually a list of images)
        :return: List of 3D numpy arrays each representing the output of a layer
        except the first array in the list which is the input.
        """
        outputs = [inputs]
        for layer in self.layers:
            outputs.append(layer.feedforward(outputs[-1]))
        outputs.extend(self.mlp.feedforward(outputs[-1])[1:])
        return outputs

    def predict(self, inputs):
        predictions = self.predict_extended(inputs)
        if predictions[0].shape == (1, 1):
            #binary output
            predictions = np.array(predictions).ravel()
            predictions[predictions <= 0] = 0
            predictions[predictions > 0] = 1
            return predictions[:, np.newaxis].astype(int)
        # multiclass
        sparse = np.zeros((len(predictions), predictions[0].shape[1]))
        for ix, _ in enumerate(sparse):
            sparse[ix][predictions[ix].argmax()] = 1
        assert sparse.sum() == len(predictions)
        return sparse

    def predict_extended(self, inputs):
        """
        Predicts targets for given data set.
        @param data_set: data Set inheriting AbstractDataSet
        :return: List of predictions, i.e. output of this net for each
        observation in the data set.
        """
        data_set = NumericalDataSet(inputs)
        predictions = []
        # loop through dataset
        for observation, _ in data_set.gen_observations():
            # make sure it is a numpy array
            input_arr = np.array(observation)
            outputs = self.feedforward(input_arr)
            predictions.append(outputs[-1])
        return predictions

    def predict_single(self, input_arr):
        """
        Predict class for a single observation.
        :param input_arr: Observation
        :return: Prediction for given observation
        """
        return self.feedforward(input_arr)[-1]

    def fit(self, inputs, targets):
        """
        Train net with given data set.
        :param data_set: Data set for training.
        n times random sampling for online learning 
        """
        split_point = int(len(inputs) * self.split_ratio)
        data_set = NumericalDataSet(inputs[:split_point],
                                    targets[:split_point])
        val_in = inputs[split_point:]
        val_targets = targets[split_point:]
        prev_layers = None
        prev_mlp = None

        self.train_acc_err = []
        self.val_acc_err = []

        for it in range(self.iterations):
            # randomly select observations as many times as there are
            # observations
            it_error = 0
            start = time.time()
            for _ in range(data_set.get_nr_observations()):
                input_arr, target_arr = data_set.rand_observation()
                # feed-forward
                outputs = self.feedforward(input_arr)
                current_error = nputils.calc_squared_error(
                    target_arr, outputs[-1])
                it_error += current_error

                # mlp backpropagation and gradient descent
                mlp_outputs = outputs[-len(self.mlp.arr_layer_sizes):]
                mlp_deltas = self.mlp.backpropagation(mlp_outputs, target_arr)
                mlp_weight_updates = self.mlp.calculate_weight_updates(
                    mlp_deltas, mlp_outputs)
                self.mlp.update_method.perform_update(self.mlp.weights_arr,
                                                      mlp_weight_updates,
                                                      current_error)
                # layer backpropagation and gradient descent
                # calculate backpropagated error of first mlp layer
                backprop_error = np.array([[x] for x in np.dot(
                    self.mlp.weights_arr[0], mlp_deltas[0].transpose())])
                for layer in reversed(self.layers):
                    backprop_error = layer.backpropagate(backprop_error)
                # calculate the weight gradients and update the weights
                for layer in self.layers:
                    layer.calc_gradients()
                    layer.update(self.learning_rate)

            avg_error = it_error / data_set.nrObservations
            acc_err = self._accuracy_err(inputs, targets)
            self.train_acc_err.append(acc_err)

            #validation error
            acc_err = self._accuracy_err(val_in, val_targets)
            self.val_acc_err.append(acc_err)

            logging.info("Iteration #{} MSE: {}, TrainErr: {:.6f}, ValErr: {:.6f} ({:.2f}s)\n"\
                         .format(it + 1, avg_error, self.train_acc_err[-1], self.val_acc_err[-1], time.time()-start))

            #break cond
            if it > 3 and val_in is not None and self.val_acc_err[
                    -1] > self.val_acc_err[-4]:
                # revert
                self.layers = prev_layers
                self.mlp = prev_mlp
                plt.figure()
                plt.plot(self.train_acc_err)
                plt.plot(self.val_acc_err)
                plt.show(block=False)
                break

            #prev
            if it > 0:
                prev_layers = copy.deepcopy(self.layers)
                prev_mlp = copy.deepcopy(self.mlp)

    def _accuracy_err(self, inputs, targets):
        if targets.shape[1] == 1:
            predictions = self.predict(inputs)
            acc_err = 1 - (predictions == targets).sum() / float(len(inputs))
        else:
            predictions = self.predict_extended(inputs)
            acc_err = 1 - ((np.vstack(predictions)).argmax(
                axis=1) == targets.argmax(axis=1)).sum() / float(len(inputs))
        return acc_err

    def set_params(self, parameters):
        pass

    def get_params(self):
        dct = {}
        dct["learning_rate"] = self.learning_rate
        dct["topo"] = self.topo
        return dct