SECTION 04 / 4

Backpropagation — Hidden Units, Weights, Biases and the Full Algorithm

6 min read
On this page 10 headings
BUILD INTUITION WITH NUMBERS

Trace the chain rule through one weight

Start with one linear neuron, h = wx + b, to isolate the chain rule. Set input 2, target 4, weight 1, bias 0, and loss ½(h − y)².

  1. Forward pass and loss.

    h=1(2)+0=2,L=12(2−4)2=2h=1(2)+0=2,\qquad L=\frac12(2-4)^2=2
  2. Find the loss gradient at the neuron output.

    ∂L∂h=h−y=−2\frac{\partial L}{\partial h}=h-y=-2
  3. Pass it through the local derivatives.

    ∂L∂w=∂L∂h∂h∂w=(−2)(2)=−4∂L∂b=−2\begin{aligned}\frac{\partial L}{\partial w}&=\frac{\partial L}{\partial h}\frac{\partial h}{\partial w}\\&=(-2)(2)=-4\\\frac{\partial L}{\partial b}&=-2\end{aligned}
  4. Update with learning rate 0.1, then check the loss.

    wnew=1.4,bnew=0.2hnew=1.4(2)+0.2=3Lnew=12(3−4)2=0.5\begin{aligned}w_{new}&=1.4,\quad b_{new}=0.2\\h_{new}&=1.4(2)+0.2=3\\L_{new}&=\tfrac12(3-4)^2=0.5\end{aligned}

What changed? Backpropagation multiplies an incoming gradient by a local derivative. A sigmoid neuron adds its activation derivative to this chain.

Quick check: Why is the weight gradient −4 but the bias gradient −2?

The weight’s local derivative is the input x = 2; the bias’s local derivative is 1.

Swipe long formulas, tables or code sideways to see the rest.

Start here We know the gradient at the output: y^−e(ℓ)\hat{y} - e(\ell ). Now we push it down the network. Three short formulas do all the work: one to pass blame from a layer to the hidden units below, one to go through the activation, and one to get the gradient for the weights and biases. Put them in a loop and you have backpropagation.

1. Chain rule along many paths

In a wide network, one hidden unit hijh_{ij} (layer i, unit j) feeds every pre-activation ai+1,ma_{i+1,m} in the layer above. So its effect on the loss travels along many paths.

Multi-path chain rule: if p(z) depends on z through several intermediate values qm(z)q_m(z), then

∂p/∂z=∑m(∂p/∂qm)⋅(∂qm/∂z)\partial p/\partial z = \sum _m (\partial p/\partial q_m) \cdot (\partial q_m/\partial z)

Here: p=L(θ),z=hij,qm=ai+1,mp = L(\theta ), z = h_{ij}, q_m = a_{i+1,m}.

Add up the blame coming back along every connection.
Add up the blame coming back along every connection.
Open image ↗
One hidden unit connects to every pre-activation above it; its gradient adds up the blame from all paths

2. Gradient w.r.t. hidden units hᵢ

Since ai+1=Wi+1hi+bi+1a_{i+1} = W_{i+1} h_{i} + b_{i+1}, we have ∂ai+1,m/∂hij=Wi+1,m,j\partial a_{i+1,m}/\partial h_{ij} = W_{i+1,m,j}. So

∂L/∂hij=∑m=1k(∂L/∂ai+1,m)⋅Wi+1,m,j\partial L/\partial h_{ij} = \sum _{m=1}^{k} (\partial L/\partial a_{i+1,m}) \cdot W_{i+1,m,j}

This is the dot product of the j-th column of Wi+1W_{i+1} with ∇ai+1L\nabla a_{i+1} L:

∂L/∂hij=(Wi+1,⋅,j)T∇ai+1L\partial L/\partial h_{ij} = (W_{i+1,\cdot ,j})^{T} \nabla a_{i+1} L

Stack all j into a vector:

∇hiL=Wi+1T(∇ai+1L)\nabla h_{i} L = W_{i+1}^{T} (\nabla a_{i+1} L)

(transpose of the weight matrix times the gradient of the layer above)

3. Gradient w.r.t. pre-activations aᵢ

Since hij=g(aij)h_{ij} = g(a_{ij}), each unit only depends on its own pre-activation:

∂L/∂aij=(∂L/∂hij)⋅g′(aij)\partial L/\partial a_{ij} = (\partial L/\partial h_{ij}) \cdot g'(a_{ij})

As a vector:

∇aiL=∇hiL⊙[g′(ai1),…,g′(ain)]\nabla a_{i} L = \nabla h_{i} L \odot [g'(a_{i1}), \ldots , g'(a_{in})]

⊙ means element-wise multiplication (multiply position by position).

Now we can compute ∇ai\nabla a_{i} for every layer: start from ∇aL\nabla a_L (known), get∇hL−1get \nabla h_{L-1}, then ∇aL−1\nabla a_{L-1}, then ∇hL−2,…\nabla h_{L-2}, \ldots down to layer 1.

4. Gradient w.r.t. weights Wₖ

Recall ak=bk+Wkhk−1a_k = b_k + W_k h_{k-1}, so aki=bki+∑jWkijhk−1,ja_{\mathrm{ki}} = b_{\mathrm{ki}} + \sum _{j} W_{\mathrm{kij}} h_{k-1,j}. Then ∂aki/∂Wkij=hk−1,j\partial a_{\mathrm{ki}}/\partial W_{\mathrm{kij}} = h_{k-1,j}, and

∂L/∂Wkij=(∂L/∂aki)⋅hk−1,j\partial L/\partial W_{\mathrm{kij}} = (\partial L/\partial a_{\mathrm{ki}}) \cdot h_{k-1,j}

Lecture example — a 3 × 3 weight matrix

∇WkL,row\nabla W_k L, row by row:

  • Row1:∂L/∂ak1⋅hk−1,1,∂L/∂ak1⋅hk−1,2,∂L/∂ak1⋅hk−1,3Row 1: \partial L/\partial a_k1 \cdot h_{k-1,1}, \partial L/\partial a_k1 \cdot h_{k-1,2}, \partial L/\partial a_k1 \cdot h_{k-1,3}
  • Row2:∂L/∂ak2⋅hk−1,1,∂L/∂ak2⋅hk−1,2,∂L/∂ak2⋅hk−1,3Row 2: \partial L/\partial a_k2 \cdot h_{k-1,1}, \partial L/\partial a_k2 \cdot h_{k-1,2}, \partial L/\partial a_k2 \cdot h_{k-1,3}
  • Row3:∂L/∂ak3⋅hk−1,1,∂L/∂ak3⋅hk−1,2,∂L/∂ak3⋅hk−1,3Row 3: \partial L/\partial a_k3 \cdot h_{k-1,1}, \partial L/\partial a_k3 \cdot h_{k-1,2}, \partial L/\partial a_k3 \cdot h_{k-1,3}

Row i uses ∂L/∂aki\partial L/\partial a_{\mathrm{ki}}; column j uses hk−1,jh_{k-1,j}. This is exactly an outer product.

∇WkL=∇akL⋅hk−1T\nabla W_k L = \nabla a_k L \cdot h_{k-1}^{T}

(column vector times row vector =a= a matrix of the same shape as WkW_k)

5. Gradient w.r.t. biases bₖ

aki=bki+∑jWkijhk−1,ja_{\mathrm{ki}} = b_{\mathrm{ki}} + \sum _{j} W_{\mathrm{kij}} h_{k-1,j}, so ∂aki/∂bki=1\partial a_{\mathrm{ki}}/\partial b_{\mathrm{ki}} = 1, and

∇bkL=∇akL\nabla b_k L = \nabla a_k L

6. The full algorithm

Forward to compute everything; backward to compute every gradient; then update.
Forward to compute everything; backward to compute every gradient; then update.
Open image ↗
Forward pass, output gradient, weight and bias gradients, pass the blame down, update — repeated

Training loop

t ← 0;  max_iterations ← 1000
initialise θ₀ = [W₁, …, W_L, b₁, …, b_L]
while t++ < max_iterations:
    a₁, h₁, …, a_{L−1}, h_{L−1}, a_L, ŷ = forward_propagation(θ_t)
    ∇θ_t = backward_propagation(h₁ … h_{L−1}, a₁ … a_L, y, ŷ)
    θ_{t+1} ← θ_t − η ∇θ_t

Forward propagation

for k = 1 to L−1:
    a_k = b_k + W_k h_{k−1}
    h_k = g(a_k)
a_L = b_L + W_L h_{L−1}
ŷ = O(a_L)

Backward propagation

∇a_L L = −(e(y) − ŷ)                         # output gradient
for k = L down to 1:
    ∇W_k L = ∇a_k L · h_{k−1}ᵀ                # weights
    ∇b_k L = ∇a_k L                           # biases
    ∇h_{k−1} L = W_kᵀ ∇a_k L                  # pass to layer below
    ∇a_{k−1} L = ∇h_{k−1} L ⊙ [… g′(a_{k−1,j}) …]   # through activation

(Atk=1At k = 1 the last two lines are not needed — h0h_{0} is the input x, which we don’t update.)

7. Derivatives of the activation functions

The only missing piece is g′.

Both derivatives are largest at z = 0 and almost zero far away.
Both derivatives are largest at z = 0 and almost zero far away.
Open image ↗
Sigmoid and its bell-shaped derivative; tanh and its taller bell-shaped derivative

Logistic:g(z)=σ(z)=11+e−z g(z) = \sigma (z) = \frac{1}{1 + e^{-z}}

g′(z)=(−1)/(1+e−z)2⋅(−e−z)=[11+e−z]⋅[e−z/(1+e−z)]=[11+e−z]⋅[(1+e−z−1)/(1+e−z)]g'(z) = (-1)/(1 + e^{-z})^{2} \cdot (-e^{-z}) = [\frac{1}{1 + e^{-z}}] \cdot [e^{-z}/(1 + e^{-z})] = [\frac{1}{1 + e^{-z}}] \cdot [(1 + e^{-z} - 1)/(1 + e^{-z})]

σ′(z)=g(z)(1−g(z))\sigma '(z) = g(z)(1 - g(z))

tanh:g(z)=(ez−e−z)/(ez+e−z) g(z) = (e^{z} - e^{-z})/(e^{z} + e^{-z})

g′(z)=[(ez+e−z)(ez+e−z)−(ez−e−z)(ez−e−z)]/(ez+e−z)2=1−(ez−e−z)2/(ez+e−z)2g'(z) = [(e^{z} + e^{-z})(e^{z} + e^{-z}) - (e^{z} - e^{-z})(e^{z} - e^{-z})] / (e^{z} + e^{-z})^{2} = 1 - (e^{z} - e^{-z})^{2}/(e^{z} + e^{-z})^{2}

tanh⁡′(z)=1−(g(z))2\tanh '(z) = 1 - (g(z))^{2}

z σ(z)\sigma (z) σ′(z)\sigma '(z) tanh(z) tanh′(z)
0 0.5 0.25 (max) 0 1 (max)
0.5 0.6225 0.2350 0.4621 0.7864

Nice property: both derivatives use the output g(z) we already stored in the forward pass — no extra exponentials needed.

8. A full worked example (checked with code)

Network: 2 inputs → 2 sigmoid hidden units → 2 softmax outputs. All biases 0. x=[1,0.5],W1=[[0.1,0.2],[0.3,−0.1]],W2=[[0.5,−0.4],[0.2,0.3]]x = [1, 0.5], W_{1} = [[0.1, 0.2], [0.3, -0.1]], W_{2} = [[0.5, -0.4], [0.2, 0.3]], true class ℓ=1\ell = 1.

Forward:

  1. a1=W1x=[0.1×1+0.2×0.5,0.3×1+(−0.1)×0.5]=[0.2,0.25]a_{1} = W_{1}x = [0.1\times 1 + 0.2\times 0.5, 0.3\times 1 + (-0.1)\times 0.5] = [0.2, 0.25]
  2. h1=σ(a1)=[0.5498,0.5622]h_{1} = \sigma (a_{1}) = [0.5498, 0.5622]
  3. a2=W2h1=[0.5×0.5498−0.4×0.5622,0.2×0.5498+0.3×0.5622]=[0.0500,0.2786]a_{2} = W_{2}h_{1} = [0.5\times 0.5498 - 0.4\times 0.5622, 0.2\times 0.5498 + 0.3\times 0.5622] = [0.0500, 0.2786]
  4. y^=softmax⁡(a2)=[0.4431,0.5569]\hat{y} = \operatorname{softmax}(a_{2}) = [0.4431, 0.5569]
  5. L=−log⁡0.4431=0.814L = -\log 0.4431 = 0.814

Backward:

  1. ∇a2=y^−e(1)=[0.4431−1,0.5569]=[−0.5569,0.5569]\nabla a_{2} = \hat{y} - e(1) = [0.4431 - 1, 0.5569] = [-0.5569, 0.5569]
  2. ∇W2=∇a2h1T=[[−0.5569×0.5498,−0.5569×0.5622],[0.5569×0.5498,0.5569×0.5622]]=[[−0.3062,−0.3131],[0.3062,0.3131]]\nabla W_{2} = \nabla a_{2} h_{1}^{T} = [[-0.5569\times 0.5498, -0.5569\times 0.5622], [0.5569\times 0.5498, 0.5569\times 0.5622]] = [[-0.3062, -0.3131], [0.3062, 0.3131]]
  3. ∇b2=[−0.5569,0.5569]\nabla b_{2} = [-0.5569, 0.5569]
  4. ∇h1=W2T∇a2=[0.5×(−0.5569)+0.2×0.5569,−0.4×(−0.5569)+0.3×0.5569]=[−0.1671,0.3898]\nabla h_{1} = W_{2}^{T}\nabla a_{2} = [0.5\times (-0.5569) + 0.2\times 0.5569, -0.4\times (-0.5569) + 0.3\times 0.5569] = [-0.1671, 0.3898]
  5. g′(a1)=h1(1−h1)=[0.2475,0.2461]g'(a_{1}) = h_{1}(1 - h_{1}) = [0.2475, 0.2461]
  6. ∇a1=∇h1⊙g′(a1)=[−0.0414,0.0959]\nabla a_{1} = \nabla h_{1} \odot g'(a_{1}) = [-0.0414, 0.0959]
  7. ∇W1=∇a1xT=[[−0.0414,−0.0207],[0.0959,0.0480]]\nabla W_{1} = \nabla a_{1} x^{T} = [[-0.0414, -0.0207], [0.0959, 0.0480]]

A numerical check (nudging each weight by 10−610^{-6} and re-computing the loss) gives the same ∇W1\nabla W_{1}.

In one line: Backprop == start with ∇aL=y^−e(ℓ)\nabla a_L = \hat{y} - e(\ell ), then for each layer going down: ∇W=∇ahT,∇b=∇a,∇hbelow=WT∇a,∇abelow=∇hbelow⊙g′\nabla W = \nabla a h^{T}, \nabla b = \nabla a, \nabla h_{\mathrm{below}} = W^{T}\nabla a, \nabla a_{\mathrm{below}} = \nabla h_{\mathrm{below}} \odot g'.

Exam words: multi-path chain rule, ∇hiL=Wi+1T∇ai+1L\nabla h_{i} L = W_{i+1}^{T}\nabla a_{i+1} L, element-wise product ⊙,∇WkL=∇akLhk−1T\odot , \nabla W_k L = \nabla a_k L h_{k-1}^{T} (outer product), ∇bkL=∇akL\nabla b_k L = \nabla a_k L, forward propagation, backward propagation, σ′=σ(1−σ),tanh⁡′=1−tanh⁡2\sigma ' = \sigma (1 - \sigma ), \tanh ' = 1 - \tanh ^{2}.

Quick check

  1. W=[[1,2],[3,4]],∇a=[1,−1]W = [[1, 2], [3, 4]], \nabla a = [1, -1]. Find ∇h\nabla h below =WT∇a= W^{T}\nabla a.
WT=[[1,3],[2,4]].WT∇a=[1×1+3×(−1),2×1+4×(−1)]=[−2,−2]. W^{T} = [[1, 3], [2, 4]]. W^{T}\nabla a = [1\times 1 + 3\times (-1), 2\times 1 + 4\times (-1)] = [-2, -2].
  1. ∇ak=[0.5,−0.2],hk−1=[1,2,3]\nabla a_k = [0.5, -0.2], h_{k-1} = [1, 2, 3]. Shape and value of ∇Wk\nabla W_k?
2 × 3: [[0.5, 1.0, 1.5], [−0.2, −0.4, −0.6]].
  1. ∇h=[0.4,−0.8]\nabla h = [0.4, -0.8], hidden activations (sigmoid⁡)h=[0.5,0.9](\operatorname{sigmoid}) h = [0.5, 0.9]. Find ∇a\nabla a.
g′=h(1−h)=[0.25,0.09].∇a=[0.4×0.25,−0.8×0.09]=[0.1,−0.072]. g' = h(1 - h) = [0.25, 0.09]. \nabla a = [0.4\times 0.25, -0.8\times 0.09] = [0.1, -0.072].
  1. tanh⁡(z)=0.6.tanh⁡′(z)=?\tanh (z) = 0.6. \tanh '(z) = ?
1−0.62=1−0.36=0.64. 1 - 0.6^{2} = 1 - 0.36 = 0.64.
  1. Why must forward propagation run before backward propagation?
Backprop needs the stored values ak,hka_{k}, h_{k} and y^:hk−1\hat{y}: h_{k-1} for the weight gradients, g′(ak)g'(a_{k}) for passing through activations, and y^\hat{y} for the output gradient.
YOUR STUDY PROGRESS

Finished this section? Save your progress.

Back to top ↑