Level 5 — MasteryNeural Network Fundamentals

Neural Network Fundamentals

90 minutes60 marksprintable — key stays hidden on paper

Level: 5 (Mastery — cross-domain: math + coding + proof) Time limit: 90 minutes Total marks: 60

Notation: for a layer, z=Wx+bz = Wx + b, a=ϕ(z)a = \phi(z). Vectors are columns. Use natural log for cross-entropy. Show all derivations; state assumptions.


Question 1 — Backpropagation from first principles + autograd (24 marks)

Consider a 2-layer network for multiclass classification with KK classes and input xRdx\in\mathbb{R}^d:

z(1)=W1x+b1,a(1)=ϕ(z(1)),z(2)=W2a(1)+b2,y^=softmax(z(2))z^{(1)} = W_1 x + b_1,\quad a^{(1)} = \phi(z^{(1)}),\quad z^{(2)} = W_2 a^{(1)} + b_2,\quad \hat y = \mathrm{softmax}(z^{(2)})

with loss L=k=1Kyklny^kL = -\sum_{k=1}^K y_k \ln \hat y_k (one-hot target yy).

(a) Prove that Lz(2)=y^y\dfrac{\partial L}{\partial z^{(2)}} = \hat y - y. Show the softmax Jacobian step explicitly. (6)

(b) Derive LW2\dfrac{\partial L}{\partial W_2}, Lb2\dfrac{\partial L}{\partial b_2}, and the backpropagated signal δ(1)=Lz(1)\delta^{(1)} = \dfrac{\partial L}{\partial z^{(1)}} in terms of δ(2)=y^y\delta^{(2)}=\hat y-y, W2W_2, and ϕ\phi'. (6)

(c) Take ϕ=tanh\phi=\tanh. A concrete forward pass gives (numbers exact): z(1)=[0ln3] (so a(1)=[0, 0.8]T approx? — use tanh(ln3)=0.8),y^=[0.2, 0.3, 0.5]T,y=[0,1,0]T.z^{(1)}=\begin{bmatrix}0\\ \ln 3\end{bmatrix}\ (\text{so } a^{(1)}=[\,0,\ 0.8\,]^T \text{ approx? — use } \tanh(\ln 3)=0.8),\quad \hat y=[0.2,\ 0.3,\ 0.5]^T,\quad y=[0,1,0]^T. Given W2=[120111]W_2=\begin{bmatrix}1&2\\0&1\\-1&1\end{bmatrix}, compute δ(2)\delta^{(2)}, then δ(1)=(W2Tδ(2))(1(a(1))2)\delta^{(1)}=\big(W_2^T\delta^{(2)}\big)\odot(1-(a^{(1)})^2) numerically. (8)

(d) Explain, referring to a computational graph, why reverse-mode autodiff computes all these gradients in one backward sweep at cost O(forward cost)O(\text{forward cost}), whereas forward-mode would cost O(d)O(d) passes. (4)


Question 2 — Activations, gradient flow, and initialization (22 marks)

(a) For sigmoid σ(z)=11+ez\sigma(z)=\frac1{1+e^{-z}}, prove σ(z)=σ(z)(1σ(z))\sigma'(z)=\sigma(z)(1-\sigma(z)) and find maxzσ(z)\max_z \sigma'(z). Using this bound, show that in a deep chain of LL sigmoid layers with weights of magnitude w\le w, the gradient magnitude is bounded by (w/4)L(w/4)^L, and state the condition on ww for vanishing gradients. (7)

(b) Compare ReLU, Leaky ReLU (α=0.01\alpha=0.01), ELU, and GELU: give each function, its derivative, and one sentence on how each mitigates the vanishing-gradient problem or the "dying ReLU" problem. (7)

(c) Xavier vs He. For a linear layer zi=j=1ninWijxjz_i=\sum_{j=1}^{n_\text{in}} W_{ij}x_j with i.i.d. zero-mean inputs of variance σx2\sigma_x^2 and i.i.d. zero-mean weights of variance σw2\sigma_w^2, derive Var(zi)\mathrm{Var}(z_i). Hence justify why He initialization uses σw2=2/nin\sigma_w^2 = 2/n_\text{in} for ReLU networks (account for ReLU halving the variance), while Xavier uses σw2=1/nin\sigma_w^2=1/n_\text{in} (or 2/(nin+nout)2/(n_\text{in}+n_\text{out})). (8)


Question 3 — Universal approximation, coding, and bias (14 marks)

(a) State the Universal Approximation Theorem for a single hidden layer. Then constructively show that a 1-hidden-layer network with step (or sigmoid) activations can approximate the "bump" indicator 1[axb]\mathbf{1}[a\le x\le b] on R\mathbb{R}, by specifying weights/biases of 2 hidden units and 1 output. Explain the essential role of the bias terms here. (7)

(b) Write a NumPy function forward(X, W1, b1, W2, b2) implementing forward propagation for one hidden layer with ReLU and a softmax output, returning class probabilities for a batch X of shape (N, d). Show the code and briefly justify the numerically-stable softmax. (7)

Answer keyMark scheme & solutions

Question 1

(a) (6 marks) Softmax: y^k=ezkjezj\hat y_k = \dfrac{e^{z_k}}{\sum_j e^{z_j}}. Jacobian: y^kzi=y^k(δkiy^i)\dfrac{\partial \hat y_k}{\partial z_i}=\hat y_k(\delta_{ki}-\hat y_i) (1 mark). L=kyklny^kLzi=kyky^ky^kziL=-\sum_k y_k\ln\hat y_k \Rightarrow \dfrac{\partial L}{\partial z_i}=-\sum_k \dfrac{y_k}{\hat y_k}\dfrac{\partial\hat y_k}{\partial z_i} (2). =kyky^ky^k(δkiy^i)=kyk(δkiy^i)=yi+y^ikyk=-\sum_k \dfrac{y_k}{\hat y_k}\hat y_k(\delta_{ki}-\hat y_i)=-\sum_k y_k(\delta_{ki}-\hat y_i)=-y_i+\hat y_i\sum_k y_k (2). Since kyk=1\sum_k y_k=1 (one-hot): Lzi=y^iyi\dfrac{\partial L}{\partial z_i}=\hat y_i-y_i, i.e. y^y\hat y - y. (1)

(b) (6 marks) Let δ(2)=y^y\delta^{(2)}=\hat y-y.

  • LW2=δ(2)(a(1))T\dfrac{\partial L}{\partial W_2}=\delta^{(2)}(a^{(1)})^T (outer product) — from z(2)=W2a(1)+b2z^{(2)}=W_2 a^{(1)}+b_2. (2)
  • Lb2=δ(2)\dfrac{\partial L}{\partial b_2}=\delta^{(2)}. (1)
  • Backprop: La(1)=W2Tδ(2)\dfrac{\partial L}{\partial a^{(1)}}=W_2^T\delta^{(2)}; then δ(1)=Lz(1)=(W2Tδ(2))ϕ(z(1))\delta^{(1)}=\dfrac{\partial L}{\partial z^{(1)}}=\big(W_2^T\delta^{(2)}\big)\odot\phi'(z^{(1)}). (3)

(c) (8 marks) δ(2)=y^y=[0.2, 0.31, 0.5]T=[0.2, 0.7, 0.5]T\delta^{(2)}=\hat y-y=[0.2,\ 0.3-1,\ 0.5]^T=[0.2,\ -0.7,\ 0.5]^T. (2) W2T=[101211]W_2^T=\begin{bmatrix}1&0&-1\\2&1&1\end{bmatrix}. W2Tδ(2)=[10.2+0(0.7)+(1)(0.5)2(0.2)+1(0.7)+1(0.5)]=[0.20.50.40.7+0.5]=[0.30.2]W_2^T\delta^{(2)}=\begin{bmatrix}1\cdot0.2+0\cdot(-0.7)+(-1)(0.5)\\ 2(0.2)+1(-0.7)+1(0.5)\end{bmatrix}=\begin{bmatrix}0.2-0.5\\0.4-0.7+0.5\end{bmatrix}=\begin{bmatrix}-0.3\\0.2\end{bmatrix}. (3) tanh=1tanh2\tanh'=1-\tanh^2; a(1)=[0,0.8]a^{(1)}=[0,0.8] so (1(a(1))2)=[1, 10.64]=[1, 0.36](1-(a^{(1)})^2)=[1,\ 1-0.64]=[1,\ 0.36]. (1) δ(1)=[0.31, 0.20.36]=[0.3, 0.072]T\delta^{(1)}=[-0.3\cdot1,\ 0.2\cdot0.36]=[-0.3,\ 0.072]^T. (2)

(d) (4 marks) The network is a DAG of primitive ops. Reverse-mode: one forward pass caches intermediate values; one backward pass propagates ˉ\bar{\cdot} (adjoints) from the scalar loss using the chain rule, reusing shared subexpressions — each edge traversed once, so cost \propto forward cost, independent of parameter count (2). Forward-mode propagates one input-direction derivative per pass, needing O(d)O(d) passes to get all input sensitivities; since #outputs (scalar loss) \ll #inputs, reverse mode is optimal for gradients (2).


Question 2

(a) (7 marks) σ(z)=(1+ez)1\sigma(z)=(1+e^{-z})^{-1}, σ=ez(1+ez)2=σez1+ez=σ(1σ)\sigma'=\dfrac{e^{-z}}{(1+e^{-z})^2}=\sigma\cdot\dfrac{e^{-z}}{1+e^{-z}}=\sigma(1-\sigma). (2) Maximize σ(1σ)\sigma(1-\sigma): max at σ=1/2\sigma=1/2 (i.e. z=0z=0), value =1/4=1/4. (2) Chain of LL layers: Lz(1)\left|\dfrac{\partial L}{\partial z^{(1)}}\right| multiplies LL factors each =Wσ=W\cdot\sigma'; σ1/4|\sigma'|\le1/4, Ww|W|\le w, so bound (w/4)L(w/4)^L. (2) Vanishing when w/4<1w<4w/4<1\Rightarrow w<4; gradient 0\to0 exponentially. (1)

(b) (7 marks) (1 mark each function+derivative, ~0.75 explanation)

  • ReLU: f=max(0,z)f=\max(0,z), f=1[z>0]f'=\mathbf1[z>0]. Derivative is 1 for positive → no vanishing on active units; dying ReLU when stuck at z<0z<0.
  • Leaky ReLU: f=zf=z if z>0z>0 else 0.01z0.01z; f=1f'=1 or 0.010.01. Nonzero negative slope prevents dead units.
  • ELU: f=zf=z if z>0z>0 else α(ez1)\alpha(e^z-1); f=1f'=1 or αez\alpha e^z. Smooth, negative saturation with nonzero gradient near 0, pushes mean activations toward zero.
  • GELU: f=zΦ(z)f=z\,\Phi(z) (Gaussian CDF); f=Φ(z)+zϕ(z)f'=\Phi(z)+z\phi(z). Smooth, differentiable everywhere, allows small gradients for slightly negative inputs. (mitigation sentences = 3)

(c) (8 marks) zi=jWijxjz_i=\sum_j W_{ij}x_j, independent zero-mean terms: Var(zi)=j=1ninVar(Wijxj)=ninσw2σx2\mathrm{Var}(z_i)=\sum_{j=1}^{n_\text{in}}\mathrm{Var}(W_{ij}x_j)=n_\text{in}\,\sigma_w^2\sigma_x^2 (using Var(WX)=E[W2]E[X2]=σw2σx2\mathrm{Var}(WX)=E[W^2]E[X^2]=\sigma_w^2\sigma_x^2 for zero-mean indep). (3) To preserve variance (Var(z)=σx2\mathrm{Var}(z)=\sigma_x^2): need ninσw2=1σw2=1/ninn_\text{in}\sigma_w^2=1\Rightarrow \sigma_w^2=1/n_\text{in} (Xavier, forward). Balancing forward+backward gives 2/(nin+nout)2/(n_\text{in}+n_\text{out}). (2) ReLU zeroes ~half the units, halving output variance: effective Var(a)12ninσw2σx2\mathrm{Var}(a)\approx\frac12 n_\text{in}\sigma_w^2\sigma_x^2. To keep it =σx2=\sigma_x^2 need 12ninσw2=1σw2=2/nin\frac12 n_\text{in}\sigma_w^2=1\Rightarrow \sigma_w^2=2/n_\text{in} (He). (3)


Question 3

(a) (7 marks) UAT: a feedforward net with a single hidden layer of finitely many neurons and a non-constant, bounded (or non-polynomial) activation can approximate any continuous function on a compact set to arbitrary accuracy in sup norm. (2) Construction of bump 1[axb]\mathbf1[a\le x\le b] with sigmoids (steep gain cc):

  • Hidden unit 1: h1=σ(c(xa))h_1=\sigma(c(x-a)) (rises ~0→1 at x=ax=a).
  • Hidden unit 2: h2=σ(c(xb))h_2=\sigma(c(x-b)) (rises ~0→1 at x=bx=b).
  • Output: o=h1h21[axb]o=h_1-h_2\to \mathbf1[a\le x\le b] as cc\to\infty. (3) Bias role: the bias ca-ca (resp. cb-cb) shifts the step's location to x=ax=a (resp. bb). Without bias the step is fixed at the origin and the bump cannot be positioned; bias sets the threshold/offset that translates the activation along the input axis. (2)

(b) (7 marks)

import numpy as np
 
def forward(X, W1, b1, W2, b2):
    # X: (N, d); W1: (h, d); b1: (h,); W2: (K, h); b2: (K,)
    Z1 = X @ W1.T + b1            # (N, h)
    A1 = np.maximum(0, Z1)        # ReLU
    Z2 = A1 @ W2.T + b2           # (N, K)
    Z2 = Z2 - Z2.max(axis=1, keepdims=True)   # numerical stability
    E  = np.exp(Z2)
    return E / E.sum(axis=1, keepdims=True)    # softmax probs (N, K)

Marks: correct linear+ReLU (2), correct softmax over class axis (2), stable-softmax subtraction of row max (2), correct shapes/vectorization (1). Stability: subtracting the max makes the largest exponent 00, avoiding exp overflow; softmax is shift-invariant so the result is unchanged.

[
  {"claim": "delta2 = yhat - y = [0.2, -0.7, 0.5]", "code": "yhat=Matrix([0.2,0.3,0.5]); y=Matrix([0,1,0]); d2=yhat-y; result = (d2==Matrix([0.2,-0.7,0.5]))"},
  {"claim": "W2^T delta2 = [-0.3, 0.2]", "code": "W2=Matrix([[1,2],[0,1],[-1,1]]); d2=Matrix([0.2,-0.7,0.5]); v=W2.T*d2; result = (simplify(v-Matrix([-0.3,0.2]))==zeros(2,1))"},
  {"claim": "delta1 = [-0.3, 0.072]", "code": "W2=Matrix([[1,2],[0,1],[-1,1]]); d2=Matrix([0.2,-0.7,0.5]); a1=Matrix([0,0.8]); v=W2.T*d2; deriv=Matrix([1-a1[0]**2,1-a1[1]**2]); d1=Matrix([v[0]*deriv[0], v[1]*deriv[1]]); result = (simplify(d1-Matrix([-0.3,0.072]))==zeros(2,1))"},
  {"claim": "max of sigma(1-sigma) is 1/4 at sigma=1/2", "code": "s=symbols('s'); f=s*(1-s); crit=solve(diff(f,s),s)[0]; result = (crit==Rational(1,2)) and (f.subs(s,crit)==Rational(1,4))"}
]