Backpropagation Through a Dense Layer

Intuition

DL-10 differentiated one neuron for one example. A dense layer is many neurons applied to a batch at once: Y=XW+bY = XW + b. The same chain rule gives compact matrix formulas, and there is a simple check: every gradient has exactly the same shape as the thing it is the gradient of.

Precise explanation

Shapes: XX is (n,din)(n, d_{in}), WW is (din,dout)(d_{in}, d_{out}), bb is (dout,)(d_{out},), and the upstream gradient dY=∂L/∂YdY = \partial L/\partial Y is (n,dout)(n, d_{out}). Then

dW=X⊤dY  (din,dout),db=∑rowsdY  (dout,),dX=dY W⊤  (n,din).dW = X^\top dY \;(d_{in}, d_{out}), \qquad db = \textstyle\sum_{\text{rows}} dY \;(d_{out},), \qquad dX = dY\, W^\top \;(n, d_{in}).

Each entry Yij=∑kXikWkj+bjY_{ij} = \sum_k X_{ik}W_{kj} + b_j, so ∂Yij/∂Wkj=Xik\partial Y_{ij}/\partial W_{kj} = X_{ik}; summing over examples ii gives X⊤dYX^\top dY. The bias is added to every row, so its gradient sums rows.

ReLU A=max⁡(0,Z)A = \max(0, Z): dZ=dA⋅[Z>0]dZ = dA \cdot [Z > 0] (gradient passes where the input was positive).

MSE loss over all entries: L=1m∑(Y^−Y)2L = \frac{1}{m}\sum (\hat Y - Y)^2 with mm the number of entries, so ∂L/∂Y^=2m(Y^−Y)\partial L/\partial \hat Y = \frac{2}{m}(\hat Y - Y).

Two-layer network H=ReLU(XW1+b1)H = \mathrm{ReLU}(XW_1 + b_1), Y^=HW2+b2\hat Y = HW_2 + b_2: start from dY^d\hat Y, apply the dense rule for layer 2 (giving dW2,db2,dHdW_2, db_2, dH), the ReLU rule, then the dense rule for layer 1.

Worked example

X=[[1,2]]X = [[1, 2]], W=[[1],[−1]]W = [[1], [-1]], dY=[[3]]dY = [[3]]: dW=X⊤dY=[[3],[6]]dW = X^\top dY = [[3], [6]], db=[3]db = [3], dX=dYW⊤=[[3,−3]]dX = dY W^\top = [[3, -3]].

Common mistakes

  • dW=dY⊤XdW = dY^\top X — the transpose of the right answer (shape (dout,din)(d_{out}, d_{in})).
  • Averaging dbdb over the batch when the loss already divided by nn (dividing twice).
  • ReLU backward using A>0A > 0 vs Z>0Z > 0 is fine, but using dA > 0 is wrong.

Why this matters

These four lines are the backward pass of every fully connected network; DL-13 verifies them numerically and DL-19 uses them to train.

Library implementation

In PyTorch the layer is torch.nn.Linear(d_in, d_out) (it stores the weight transposed, shape (d_out, d_in)) and loss.backward() computes exactly these gradients. The comparison below builds the same two-layer network in PyTorch and checks the gradients match; it runs only when PyTorch is installed.

References