Stacking Layers: Building a Multi-Layer Perceptron (MLP)

Introduction

Welcome to the first lesson of "The MLP Architecture: Activations & Initialization"! I'm excited to continue our neural network journey with you. In our previous course, Neural Network Fundamentals: Neurons and Layers, we built the foundations of neural networks by implementing individual neurons, adding activation functions, and combining neurons into a single DenseLayer capable of forward propagation.

Today, we're taking a significant step forward by learning how to stack multiple layers together to create a Multi-Layer Perceptron (MLP). MLPs are the fundamental architecture behind many neural network applications and represent the point where our implementations truly become "deep learning."

By the end of this lesson, you'll have created a fully functional MLP capable of processing data through multiple layers, bringing us much closer to solving real-world problems. Let's dive in!

Recap: Our Neural Network Building Blocks

Before we dive into Multi-Layer Perceptrons, let's quickly refresh the core components we built in our previous course. Our foundation consists of two key elements:

  1. The sigmoid activation function, which transforms linear inputs into non-linear outputs between 0 and 1:

    Python
    def sigmoid(x):
        """Sigmoid activation function."""
        return 1 / (1 + np.exp(-x))
  2. The DenseLayer class, which represents a fully-connected layer of neurons:

    class DenseLayer:
        def __init__(self, n_inputs, n_neurons):
            # Weights: (n_inputs, n_neurons), Biases: (1, n_neurons)
            self.weights = np.random.rand(n_inputs, n_neurons) * 0.1 
            self.biases = np.zeros((1, n_neurons))
            self.n_inputs = n_inputs
            self.n_neurons = n_neurons
            self.output = None 
            # For now, DenseLayer defaults to Sigmoid activation
            self.activation_fn = sigmoid
            self.activation_fn_name = "sigmoid" # For informational purposes
    
        def forward(self, inputs):
            """Perform a forward pass through the dense layer."""
            weighted_sum = np.dot(inputs, self.weights) + self.biases
            self.output = self.activation_fn(weighted_sum)
            return self.output

Our DenseLayer performs three essential operations:

  • Initializes weights and biases (note how we're currently using np.random.rand * 0.1 for weights — we'll explore why we do it as well as better initialization strategies later in this course).
  • Stores layer dimensions and activation function.
  • Performs the forward pass by computing the weighted sum and applying activation.

This single layer is powerful, but the real magic happens when we combine multiple layers together — which is exactly what we'll do today by building our Multi-Layer Perceptron!

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal