A forward pass, every intermediate written down
numeric▲△△All values are exact here; they are printed to 4 d.p. so that they line up with the reproduction snippet.
STATEMENT
A network with two inputs, two hidden units and one output is fully specified below. Carry out the forward computation by hand and report every intermediate quantity, not only the final number.
GIVEN
The input, as a row vector:
The first layer, with and a bias row :
The hidden nonlinearity is , applied to each entry separately. The second layer, with and :
The output layer has no nonlinearity.
FIND
The pre-activations (a row), the activations (a row), and the output (a scalar).
STRATEGY
Follow the definition one operation at a time and name each result, because a wrong final number is only useful if you can say which step produced it.
SOLUTION
Step 0 — fix the convention. Elementa is row-major (Vectors, matrices and the row-major convention 0.LA.01): a row of is one example, and a layer is applied on the right as . The shapes must meet as , and they do.
Getting this wrong is the single most common error in a first hand-computation. If you write instead, you are computing with and every number below changes.
Step 1 — the first pre-activation. Each entry of is one inner product of with one column of , plus the matching bias.
Column 1 of is :
Column 2 is :
Step 2 — the nonlinearity. ReLU acts on each entry independently. There is no mixing here at all; that is what “elementwise” means.
The first hidden unit has been switched off. It contributes nothing to the output, and — as Chapter I.6 will show — it also receives no gradient on this example.
Step 3 — the output layer. Shapes :
Answer
and are ; is a scalar and carries whatever units the target carries.
Check — numeric · i-1-b01-forward-pass.py
def relu(v): return [max(0.0, t) for t in v]
def matvec(x, W, b): return [sum(x[i] * W[i][j] for i in range(len(x))) + b[j]
for j in range(len(b))]
z1 = matvec(x, W1, b1); a1 = relu(z1); z2 = matvec(a1, W2, b2)Prints z1 = -0.5000 3.0000, a1 = 0.0000 3.0000, yhat = 2.0000.
Executed in CI. The digits above are the digits it printed.
Check — sanity
Three independent reasons the answer is right.
The shapes conform at every step. , then elementwise, then . A forward pass whose shapes conform is not necessarily correct, but one whose shapes do not conform is certainly wrong, and it costs nothing to check.
The dead unit is consistent. , so the first row of — the value — cannot influence . Change it to and recompute: still . That is a real test, and it passes.
Removing the nonlinearity changes the answer. Without ReLU, . Since , the nonlinearity is doing something on this input — which is the whole content of Chapter I.3.
Where this breaks
The answer depends on ReLU being applied before the second layer. Swap the order — apply the second layer to and take ReLU afterwards — and becomes . Two networks with identical weights and identical shapes, differing only in the order of two operations, give different outputs. The shape check cannot catch this; only reading the definition can.
Variation
Recompute with . Before doing any arithmetic, predict which hidden unit switches off — and then check whether your prediction was right and why.