Some sections of this article were generated by AI and are maintained by the author.
Building a neural network for MNIST from scratch is a fantastic pen-and-paper exercise. We will break down the mechanics step by step—from raw pixels to calculus-driven learning—so you have complete clarity before writing a single line of code. I’ll guide you through each piece with questions along the way.
To classify handwritten digits ( through ), a standard feedforward neural network relies on three core conceptual pillars:
-
Architecture & Dimensions 📐: Turning a grayscale image into vectors, and defining the matrix shapes for layers, weights (), and biases ().
-
Forward Propagation & Activation Functions ⚡: Computing the linear transformations () and applying non-linearities like ReLU for hidden layers and Softmax for multi-class probabilities.
-
Loss & Backpropagation 🔄: Measuring prediction error using Cross-Entropy Loss, applying the multivariable Chain Rule to compute gradients, and updating parameters via Gradient Descent.
Let’s set up the network architecture on paper! 📝
1. The Input Layer 🖼️
Each MNIST image is a grayscale image with a grid size of pixels. Before feeding an image into a standard fully connected (dense) neural network, we need to flatten that 2D grid into a single 1D column vector, which we’ll call .
To get started with our dimensions:
[Q]
If we flatten a pixel image into a single column vector, how many elements (features) will the vector have? What are its matrix dimensions ?
, so our input vector has 784 features with dimensions .
2. The Hidden Layer 🧠
Let’s design a simple 2-layer network (1 hidden layer + 1 output layer).
Suppose we choose our hidden layer to have neurons.
In the linear equation for this first layer:
- has dimensions .
We want the output of this layer, , to have a value for each of the neurons, giving it dimensions .
[Q]
Using the rules of matrix multiplication (), what must the dimensions of the weight matrix and the bias vector be?
For the weight matrix , having dimensions of allows to produce a output.
The bias vector is added directly to that result, so it matches the output shape: .
3. Hidden Layer Activation ⚡
Before passing to the next layer, we apply a non-linear activation function element-wise, commonly ReLU(Rectified Linear Unit):
Because it operates element-by-element, the dimensions of the activated hidden layer remain .
4. The Output Layer 🎯
Now we need to project from the hidden layer ( features) to our final predictions:
We want the final output to produce a prediction score for each possible digit in MNIST ().
[Q]
How many output neurons do we need, and what must the dimensions of the second weight matrix and bias vector be?
We need 10 output neurons (one for each digit ). We now have our full network structure mapped out:
- Input :
- Layer 1: ,
- Layer 2: ,
5. Output Activation: Softmax 📊
The vector gives us 10 raw real-numbered scores (logits), but we want output probabilities that sum to for the classes through .
We apply the Softmax function to compute the final activation :
Now we have a probability vector of size .
6. The Target Label 🎯
To calculate our loss (how wrong the prediction is), we need to compare our output probability vector to the true label .
If the true image is the digit :
[Q]
How do we represent this target digit as a vector (known as a one-hot encoded vector) so it matches the shape of ? What would that vector look like?
Because index represents the digit , the digit actually sits at the 4th position (index 3):
With 0-based indexing, the goes at index 3, and all other entries are .
7. Measuring Error: Categorical Cross-Entropy Loss 📉
Now that we have the prediction vector and the true one-hot vector , we compute the loss for a single sample using Categorical Cross-Entropy:
[Q]
Since has a only at the true class index (index 3 here) and everywhere else, what does this entire summation simplify to?
The loss simplifies down to:
In general, for any true label class , the cross-entropy loss simply measures the negative natural log of our predicted probability for that correct class: . If , ; if , .
8. Backpropagation: The Output Gradient 🔄
To update our weights using gradient descent, we need to calculate how changing each parameter affects the loss using the multivariable Chain Rule ⛓️.
We start at the very end and work backwards. The first key quantity is the derivative of the loss with respect to the output logits , which we denote as :
When you combine the derivative of the Categorical Cross-Entropy loss with the Softmax activation function using the chain rule (), an algebraic cancellation occurs.
[Q]
In terms of our prediction vector and the true label vector , do you know (or would you like to derive) the formula for ?
When you combine Categorical Cross-Entropy with Softmax, the calculus cancels out cleanly to:
This is the error vector 🎯: it is simply our predicted probability vector minus the true one-hot vector.
- Its dimensions are , exactly matching .
9. Gradients for Layer 2 ( and ) 📐
Now we use to find how the loss changes with respect to the weights and biases .
Recall the forward relationship:
By the chain rule:
- The bias gradient is simply: (shape: ).
- For the weight gradient , we combine (shape ) and the hidden activation (shape ).
We know must match the shape of , which is .
[Q]
How should we multiply and (using the transpose ) so that the resulting matrix has dimensions ?
To obtain a matrix from a vector and a vector, we multiply by the transpose of :
- Matrix dimensions: .