After writing my first blog post on deriving batch backpropagation, it always bothered me that the post seemed to have too little diagrams. So, in this post, my goal is to derive batch backpropagation by using as many diagrams as possible.
First, let me introduce you to a diagram that we will be using for the remainder of the post.
It might not seem obvious at first, but the diagram below is a one layer feed-forward neural network, with a batch size of two (denoted by the light and dark red colors) that outputs a single value which is scored by the squared error loss. Though, pictures probably explain it better than I do. Below is a diagram of the first row of the data matrix multiplied by the first column of the weight matrix
I’m going to assume that you already have a good idea of what happens in the forward pass so the diagram above should (hopefully) make sense (though if not please comment down below and I will explain further!) Now before we get into deriving backpropagation lets first define some notation
First layer weights:
First layer bias:
First layer linear combination:
First hidden layer:
Output layer weights:
Output layer bias:
Deriving backpropagation by following lines
Before we start getting into the details, we should first understand how backpropagation works from a high level. The goal of backpropagation is to calculate how much the final error value changes given a change some node (be it a weight node or a hidden variable node).
This is done through the accumulation of gradients starting some root node, our loss node, to the leaf nodes (and any nodes along the way) that we are interested in, usually our weight and hidden variable nodes. These gradients are represented as arrows in the diagrams that are shown below.
In fact, all that you need to be able to do to understand backpropagation is to follow the arrows and multiplying their values along the way until you reach the end. This is the approach that we will be taking, we will slowly build up arrows that lead from the loss node to our input variable nodes.
During backpropagation there are 5 steps that you will need to follow, assuming that we have a neural network with layers:
- Assuming we are on layer in the backward pass, using the previously accumulated gradients from previous layers, which we will denote using the matrix , calculate the accumulated gradients for the weights of the current layer
- Using calculate the accumulated gradients for the biases of the current layer
- Using calculate the accumulated gradients of the inputs of the current layer
- Using the result from the previous step, calculate the accumulated gradients of the inputs of the current layer before the non-linearity, and then abstract these values into a matrix
- Start go back to step 1, except now we are on layer
The loss layer: setting up
As mentioned above, each of the arrows represents the change in the root node with respect to the leaf node(s). For example, in figure 3, the root node is our loss function, and the leaf nodes are our predicted values.
As we are using the squared error loss, the derivative of our loss function with respect to our predicted variables is relatively simple. So by doing some simple math, we should be able to calculate :
Now we make the abstraction, I will denote:
So let’s recap, what means. Each row of represents the derivative of the loss function with respect to our predicted values. Another way to think about it is the accumulated gradients of the loss function up to the nodes; in our case and . In fact, the latter interpretation is fundamental to deriving the backpropagation algorithm as the matrix holds all of the accumulated gradients from previous layers and allows us to abstract away those previous calculation! If you don’t get what I mean, keep reading and hopefully it will become more clear.
Alright sweet, now let us move onwards! The next step will be to calculate the gradients for the weights.
Step 1: Calculating the accumulated gradients for
To start, we won’t be calculating the accumulated gradients for all the output weights at once, but rather we will start by only considering . As once we see one example, calculating the accumulated gradients for and is very similar.
In figure 4, we see that for , there are two arrows leading into it, one from and one from . If you haven’t already, you should try to understand why this is happening by yourself before reading the explanation!
Now for the explanation… Since , is used to calculate both and a change would change both and ! Therefore, when changes it is able to change the final loss function in two ways through and , and as a result we have two arrows (representing gradients) heading into .
Now looking at the diagram we can follow the arrows from the loss node that lead to the weight node. We can see that the accumulated gradients for is simply:
Now if we follow the same steps, and follow the arrows that lead from the loss node to the and
We can see that:
Now if we do this for all the weights! We end up with this diagram below!
Step 2: Calculating the accumulated gradients for
To calculate the accumulated gradients for our bias we simply follow the same thing that we did for the weights!
Again, there are two arrows pointing into , as changing would change both and . Now to calculate the accumulated gradients we simply add up the gradients (like before!).
Now lets move on to calculating the accumulated gradients with respect to the first hidden layer!
Step 3: Calculating the accumulated gradients for
To calculate the accumulated gradients for the hidden layer, we again just follow the lines!
Looking at figure 7, we can see that:
Summary of the accumulated gradients for the output layer
So we have successfully calculated the accumulated gradients for the output layer! Here is how our diagram looks!
Now, lets take a look at the equations that calculate the accumulated gradients from the errors we derived from the previous sections:
The hidden variables:
Now, we can see that and appear in all the equations. So we know that our equations will involve:
Looking at the accumulated gradients for the weights we can see that:
For the biases, we simply sum up columns of :
Finally, for the hidden states :
Step 4: Calculating the accumulated gradients for
Alright! So we are nearly there, for the last step we need to find the derivative of the hidden layer with respect to the non-linearities, in the case of our neural network, we have used a sigmoid function! This step is the crucial step, as after this step, we can simply rinse and repeat.
A sigmoid function is defined as:
It’s derivative is defined as:
I will leave the derivation of the derivative as an exercise! For now we will continue on with the last step.
Looking at the diagram above if we follow the arrow from the loss to the nodes in the linear layer then we should be able to see that for each node in the linear layer:
Since each element of is just with a sigmoid to it:
Or put more simply, the accumulated gradients from the loss layer up to the inputs of the layer before the non-linearity is calculated as:
There are two things that I should explain here the circle, is called the Hadamard product, which is an element-wise multiplication of two vectors/matrices with the same dimension.
Also, I have abused the notation a bit where I am denoting as:
Finally, we are able to make the abstraction for :
Each element in row and column in this are the accumulated gradients from the error up to .
Step 5: Rinse and repeat
Here is our updated diagram!
Now I am not going into as much detail, though I do urge you to follow the steps that I just went through to find the accumulated gradients for the weights, biases, and inputs for the input layer.
Looking at figure 11 we can see that:
Or more generally for any batch size and any layer :
Which is the (b, j)th element of:
Note that in our neural network we have the input layer, the hidden layer, and the output layer.
Looking at figure 12 we can see that:
Or more generally, for any batch size and layer :
is the number of hidden nodes in layer
Looking at figure 13, we can see that:
Or more generally, for any batch size and layer :
Which is the (b, j)th element of:
So we have derived the backpropagation equations:
If you are interested in playing around with the diagrams that I have used here is the link (please copy the diagrams and place them in a new file so that other people can use the template). I would urge you to place around with it and derive the backpropagation equations in detail for the input layer!
Also, if you’re interested in a more non-trivial example please take a look at my other post which is an example of backpropagation in a four layer neural network using cross entropy loss.
I hope that this has made backpropagation a lot clearer! Please let me know in the comments below if I have made any mistakes or if you have any questions or any requests on what I should blog about next!