This is assignment is a part of DL-systems course presented by CMU.
This HW is the first step for building our own DL library. In this HW we will use the NUMPY as our own backend. But in the HW3 we will develop our own backend implementation.
In this HW, we start defining the operations that can be applied to tenors; we draft both the forward and backward implementation for the operation then we build and use a backward automatic differentiator to compute the backward computation stream.
Navigating this repo you will find an implementation for the following:
- Forward and Backward computation for the following operations
- divide
- divide scalar
- matrix multiplication
- summation
- reshaping
- negation
- Transpose
- Topolgical sort
- Implement reverse mode differentiation
- Implement softmax loss using needle operations
- BUilding a 2 layer NN using needle operations
To run tests you can use the following commands in the repo directory:
ps if you are running in jupyter add !
before the following commands
python3 -m pytest -v -k "forward"
python3 -m pytest -l -v -k "backward"
python3 -m pytest -k "topo_sort"
python3 -m pytest -k "compute_gradient"
python3 -m pytest -k "softmax_loss_ndl"
!python3 -m pytest -l -k "nn_epoch_ndl"
-
why do we run out of memory if we run the code below in pytoch?
The answer is basically due to the fact that the tensor does store the operation that it came from. And the operation does store its input tensors.
So you are not overloading the above variable; rather, you are storing every intermediate stage that happened in the memory, as this would be the way to compute the computational graph.
To solve this, we may call detach if we are not interested in the gradient calculations.
-
How can we intuitavely imagine the gradient calculations? First of all we have to consider that sometimes we are doing derivatives
- scalar w.r.t vectors
- vector w.r.t vectors
- matrix w.r.t vectors
$\vdots$ not let's say for example we have vector
let's assume that we have
y= sum(x) =
if we wanted to get
then we will have
This is equivalent to
Hence, we can see that on the back-propagation stream the summation does not alter or change the value of the propagted value. In addition it will backpropgate the gradients of the nodes that only participated in getting the output of the summation layer y.
The same goes for reshaping, let's assume that we have matrix
if we rehsaped it to be like
now if we wanted again to get derivative of the output "y" w.r.t the input "x"
Then we are having a derivative of a vector wrt matrix.
which is a derivative of a sclar w.r.t matrix. evaluating it intuitavely, we will conclude that
and we can have the same conclusion as the one we had for the summation process above which is:
reshaping does not alter the back-propagation. In addition it will backpropgate the upstream gradients for the nodes that have only participated in getting the output of the summation layer y.