Lesson 2 of 10
A dense layer: forward and backward
A dense (fully connected) layer with a ReLU computes a = relu(h @ W + b) for a batch h of shape (N, in), weights W of shape (in, out) and bias b of shape (out,).
Backpropagation runs the chain rule backwards. Given g = dL/da (same shape as a), you need three things:
gz = g * (z > 0), wherez = h @ W + b. ReLU passes gradient only where it was active.dW = h.T @ gzanddb = gz.sum(axis=0): how the loss changes with each parameter.dh = gz @ W.T: the gradient to hand to the layer below.
Every network in lab/nn.py is a stack of these. MLP.backward is this function in a loop.
Your code
Tab indents. Press Esc, then Tab, to leave the editor. Ctrl or Cmd + Enter checks your code.
Pigeon's hint, 1 of 2
Keep z (before the ReLU) in the cache; the ReLU mask is z > 0.
Pigeon's hint, 2 of 2
Check shapes: dW must be (in, out) like W, so it's h.T @ gz.
import numpy as np
def dense_forward(h, W, b):
z = h @ W + b
return np.maximum(z, 0), (h, W, z)
def dense_backward(g, cache):
h, W, z = cache
gz = g * (z > 0)
return gz @ W.T, h.T @ gz, gz.sum(axis=0)
Pigeon's tip
Pigeon's warning
Pigeon's note
Where this is used
- Knowledge distillation (Hinton)Runs hereTrain a small model to match a big model's softened output probabilities instead of (or as well as) the one-hot labels.
- Magnitude pruningRuns hereSet the smallest weights to zero. Cheap and surprisingly effective, as long as you let the network recover afterwards.