class_docstr: The Perceptron. One layer neural network classifier.
  
  Parameters:
  -----------
  n_iterations: float
      The number of training iterations the algorithm will tune the weights for.
  activation_function: class
      The activation that shall be used for each neuron.
      Possible choices: Sigmoid, ExpLU, ReLU, LeakyReLU, SoftPlus, TanH
  loss: class
      The loss function used to assess the model's performance.
      Possible choices: SquareLoss, CrossEntropy
  learning_rate: float
      The step length that will be used when updating the weights.
class_docstr_tok: ["The","Perceptron",".","One","layer","neural","network","classifier",".","Parameters",":","--","--","--","--","--","-","n_iterations",":","float","The","number","of","training","iterations","the","algorithm","will","tune","the","weights","for",".","activation_function",":","class","The","activation","that","shall","be","used","for","each","neuron",".","Possible","choices",":","Sigmoid",",","ExpLU",",","ReLU",",","LeakyReLU",",","SoftPlus",",","TanH","loss",":","class","The","loss","function","used","to","assess","the","model","'s","performance",".","Possible","choices",":","SquareLoss",",","CrossEntropy","learning_rate",":","float","The","step","length","that","will","be","used","when","updating","the","weights","."]
code: def fit(self, X, y):
      n_samples, n_features = np.shape(X)
      _, n_outputs = np.shape(y)
  
      # Initialize weights between [-1/sqrt(N), 1/sqrt(N)]
      limit = 1 / math.sqrt(n_features)
      self.W = np.random.uniform(-limit, limit, (n_features, n_outputs))
      self.w0 = np.zeros((1, n_outputs))
  
      for i in self.progressbar(range(self.n_iterations)):
          # Calculate outputs
          linear_output = X.dot(self.W) + self.w0
          y_pred = self.activation_func(linear_output)
          # Calculate the loss gradient w.r.t the input of the activation function
          error_gradient = self.loss.gradient(
              y, y_pred
          ) * self.activation_func.gradient(linear_output)
          # Calculate the gradient of the loss with respect to each weight
          grad_wrt_w = X.T.dot(error_gradient)
          grad_wrt_w0 = np.sum(error_gradient, axis=0, keepdims=True)
          # Update weights
          self.W -= self.learning_rate * grad_wrt_w
          self.w0 -= self.learning_rate * grad_wrt_w0
  
file_path: ML-From-Scratch/mlfromscratch/supervised_learning/perceptron.py
imports: from __future__ import print_function, division
  import math
  import numpy
  from mlfromscratch.utils import train_test_split, to_categorical, normalize, accuracy_score
  from mlfromscratch.deep_learning.activation_functions import Sigmoid, ReLU, SoftPlus, LeakyReLU, TanH, ELU
  from mlfromscratch.deep_learning.loss_functions import CrossEntropy, SquareLoss
  from mlfromscratch.utils import Plot
  from mlfromscratch.utils.misc import bar_widgets
  import progressbar
label_desc: Use image node_id 2 for calling the Perceptron obj's underlying member method code with example usage: obj.fit(X, y) without return types