human
Can you provide a the Python code you requested given the following:
I am working on the file "Scikit - 12 Neural Network using Numpy.ipynb".
The first task is:
Neural Networks Classifier
Author: Abul Basar
Can you write Python code for it?
assistant
#Here is the Python code you requested.

class NeuralNetwork:

    def __init__(self, layers, learning_rate, random_state = None):
        self.layers_ = layers
        self.num_features = layers[0]
        self.num_classes = layers[-1]
        self.hidden = layers[1:-1]
        self.learning_rate = learning_rate
        
        if not random_state:
            np.random.seed(random_state)
        
        self.W_sets = []
        for i in range(len(self.layers_) - 1):
            n_prev = layers[i]
            n_next = layers[i + 1]
            m = np.random.normal(0.0, pow(n_next, -0.5), (n_next, n_prev))
            self.W_sets.append(m)
    
    def activation_function(self, z):
        return 1 / (1 + np.exp(-z))
    
    def fit(self, training, targets):
        inputs0 = inputs = np.array(training, ndmin=2).T
        assert inputs.shape[0] == self.num_features, \
                "no of features {0}, it must be {1}".format(inputs.shape[0], self.num_features)

        targets = np.array(targets, ndmin=2).T
        
        assert targets.shape[0] == self.num_classes, \
                "no of classes {0}, it must be {1}".format(targets.shape[0], self.num_classes)

        
        outputs  = []
        for i in range(len(self.layers_) - 1):
            W = self.W_sets[i]
            inputs = self.activation_function(W.dot(inputs))
            outputs.append(inputs)
        
        errors = [None] * (len(self.layers_) - 1)
        errors[-1] = targets - outputs[-1]
        #print("Last layer", targets.shape, outputs[-1].shape, errors[-1].shape)
        #print("Last layer", targets, outputs[-1])
        
        #Back propagation
        for i in range(len(self.layers_) - 1)[::-1]:
            W = self.W_sets[i]
            E = errors[i]
            O = outputs[i] 
            I = outputs[i - 1] if i > 0 else inputs0
            #print("i: ", i, ", E: ", E.shape, ", O:", O.shape, ", I: ", I.shape, ",W: ", W.shape)
            W += self.learning_rate * (E * O * (1 - O)).dot(I.T)
            if i > 0:
                errors[i-1] = W.T.dot(E)
     ...