Welcome back to our course "Neural Network Fundamentals: Neurons and Layers"! You're making excellent progress. In the previous units, we built a single artificial neuron, enhanced it with the sigmoid
activation function, and then combined multiple neurons into a DenseLayer
class using JavaScript
and mathjs
.
In this final lesson, we'll bring our dense layer to life by implementing forward propagation — the process by which information travels through a neural network from input to output. This is where our layer actually processes data and produces meaningful activations.
By the end of this lesson, you'll have a functional dense layer that can take inputs, process them through multiple neurons simultaneously, and produce outputs that could be fed to another layer or used directly for predictions.
Before we dive into code, let's clarify what forward propagation means in the context of neural networks.
Forward propagation (or forward pass) is the process of taking input data and passing it through the network to generate an output. It's called "forward" because information flows forward through the network, from the input layer, through any hidden layers, to the output layer.
For our dense layer, forward propagation involves three key steps:
- Weighted sum calculation: Multiply each input feature by its corresponding weight.
- Bias addition: Add the bias term to each weighted sum.
- Activation: Apply the activation function to introduce non-linearity.
This process transforms the input data into activations (outputs) that represent what the layer has "learned" about the input. These activations can then be used as inputs to subsequent layers in deeper networks.
As we learned in the previous units, we're using matrices to represent the weights and biases of our dense layer. This allows us to process multiple neurons simultaneously through efficient matrix operations using mathjs
.
Let's clarify what we mean by a sample: a sample is a unit of input that the model processes to produce a prediction. For example, suppose you're building a neural network to predict whether a person will buy a product based on 3 features: Age, Income, and Number of previous purchases (in that order). Then each sample would be one person’s data, like [25, 40000, 2]
, where 25 is the age, 40000 is the income, and 2 is the number of previous purchases.
Let's review the key matrices involved in forward propagation:
- Inputs: Shape
[nSamples, nInputs]
— each row represents one data sample. - Weights: Shape
[nInputs, nNeurons]
— each column represents the weights for one neuron. - Biases: Shape
[nNeurons]
— one bias per neuron. - Outputs: Shape
[nSamples, nNeurons]
— each row will be the output for one sample.
The beauty of this approach is that it works not only for a single input sample but also for batches of samples. When we have multiple samples (a batch), we can process them all at once without writing additional code.
For example, if we have a batch of 4 samples, each with 3 features, and our layer has 2 neurons:
- Inputs shape:
[4, 3]
(4 samples, each with 3 features) - Weights shape:
[3, 2]
(3 inputs connected to 2 neurons) - Result of matrix multiplication:
[4, 2]
(4 samples, each producing 2 outputs)
This efficient batch processing is one of the key advantages of using matrix operations in neural networks.
Now, let's implement the forward
method in our DenseLayer
class. We'll focus first on calculating the weighted sum using mathjs
:
In this code:
- The
forward
method takes an input array, which can contain multiple samples. - We use
mathjs
'smath.multiply
to perform matrix multiplication between the inputs and weights. - This operation computes the weighted sum for every neuron in the layer, for every sample in the batch.
The matrix multiplication creates a new matrix where each element is the dot product of a row from the inputs and a column from the weights. Each row in the result corresponds to a sample, and each column corresponds to a neuron.
After calculating the weighted sum, we need to add the biases and apply the activation function. Since our biases are now stored as a [1, nNeurons]
matrix, we can use math.add
to broadcast the biases across all rows of the weighted sum.
We'll also use the sigmoid
activation function we defined earlier:
Now, let's complete the forward
method:
Here's what happens in this code:
- We add the biases to each row of the weighted sum. Since
this.biases
is a[1, nNeurons]
matrix,math.add
broadcasts it across all rows. - We apply the
sigmoid
activation function to the result. This transforms every value in the matrix to be between 0 and 1, introducing non-linearity. - We store the result in
this.output
and also return it, making it available for the next layer or for the final prediction.
This completes the forward propagation process for our dense layer. Each neuron in our layer has now processed the input data, and we have the resulting activations.
One significant advantage of our implementation is that it can process data in batches. A batch is simply a collection of multiple input samples that we process simultaneously. This is much more efficient than processing samples one at a time.
Let's see how our code handles a batch of input data:
In this example:
- We have a batch of 2 samples, each with 3 features.
- Our layer will process both samples at once.
- The output will have 2 rows (one for each sample) and as many columns as there are neurons in our layer.
This batch processing capability is essential for efficient training and inference in neural networks, especially when dealing with large datasets.
To solidify our understanding, let's visualize the forward propagation process step by step for a single sample using JavaScript
and mathjs
:
-
Input:
[1.0, 2.0, 3.0]
(shape:[1, 3]
) -
Weights (example):
-
Weighted sum:
Calculation:
- First neuron:
- Second neuron:
-
Add biases:
-
Apply sigmoid:
The final output [[0.577, 0.572]]
represents the activations of the two neurons in our layer for the first sample. The exact numbers will vary based on the random initialization of weights, but this process illustrates how a single sample flows through the layer.
Congratulations! You've successfully implemented forward propagation in your dense layer using JavaScript
and mathjs
. This is a significant milestone, and it marks the completion of the lessons in our "Neural Network Fundamentals: Neurons and Layers" course. Your layer can now accept input data (either a single sample or a batch), process it through multiple neurons simultaneously, and produce output activations that are ready for further processing. The forward pass is the foundation of how neural networks make predictions, transforming raw inputs into meaningful outputs through a series of mathematical operations.
Coming up next, you'll have the opportunity to put everything you've learned in this course into practice in the final practice section. You'll work with the code we've developed, experimenting with different inputs and seeing how they flow through the layer.
This will prepare you for the next step in our journey: continuing your neural network implementation in our second course, "The MLP Architecture: Activations & Initialization". There, we'll build upon the foundations laid here, focusing on connecting multiple layers together — using the activations your layer now produces — to form complete neural networks capable of solving complex problems. Happy learning!
