import numpy as np
rng = np.random.default_rng(0)
x = rng.standard_normal(3); t = np.array([0.5])
W1 = rng.standard_normal((4, 3)); W2 = rng.standard_normal((1, 4))
def forward(W1, W2):
a1 = W1 @ x; z1 = np.tanh(a1); y = W2 @ z1
return 0.5*np.sum((y - t)**2), (z1, y)
E, (z1, y) = forward(W1, W2)
dy = y - t # δ at output
dW2 = np.outer(dy, z1) # ∂E/∂W2 = δ · zᵀ
da1 = (1 - z1**2) * (W2.T @ dy) # δ hidden = h'(a)·Wᵀδ , tanh'(a)=1−z²
dW1 = np.outer(da1, x) # ∂E/∂W1 = δ · xᵀ
def numgrad(W, sel): # finite-difference check
g = np.zeros_like(W)
for i in np.ndindex(W.shape):
Wp = W.copy(); Wp[i] += 1e-6
g[i] = (forward(*((Wp, W2) if sel == 1 else (W1, Wp)))[0] - E)/1e-6
return g
print("max |backprop − numerical|: W1 =", f"{abs(dW1-numgrad(W1,1)).max():.1e}",
" W2 =", f"{abs(dW2-numgrad(W2,2)).max():.1e}")