holehouse.org Blog Machine learning notes

09: Neural Networks - Learning

Neural network cost function

Types of classification problems with NNs

y∈ℝK e.g.[1000],[0100],[0010],[0001] Left to right: pedestrian, car, motorcycle, truck.

Cost function for neural networks

J(θ)=−1m[∑i=1my(i)loghθ(x(i))+(1−y(i))log(1−hθ(x(i)))]+λ2m∑j=1nθj2
hΘ(x)∈ℝK(hΘ(x))i=ithoutput J(Θ)=−1m[∑i=1m∑k=1Kyk(i)log(hΘ(x(i)))k+(1−yk(i))log(1−(hΘ(x(i)))k)]+λ2m∑l=1L−1∑i=1sl∑j=1sl+1(Θji(l))2

Woah there - lets take a second to try and understand this!

First half

−1m[∑i=1m∑k=1Kyk(i)log(hΘ(x(i)))k+(1−yk(i))log(1−(hΘ(x(i)))k)]

Second half

λ2m∑l=1L−1∑i=1sl∑j=1sl+1(Θji(l))2

Summary of what's about to go down

The following section is, I think, the most complicated thing in the course, so I'm going to take a second to explain the general idea of what we're going to do;

Back propagation algorithm

J(Θ)=−1m[∑i=1m∑k=1Kyk(i)log(hΘ(x(i)))k+(1−yk(i))log(1−(hΘ(x(i)))k)]+λ2m∑l=1L−1∑i=1sl∑j=1sl+1(Θji(l))2
a(1)=x z(2)=Θ(1)a(1) a(2)=g(z(2)) z(3)=Θ(2)a(2) a(3)=g(z(3)) z(4)=Θ(3)a(3) a(4)=hΘ(x)=g(z(4)) The bias unit a0 is added to a(2) and a(3) after each activation.

What is back propagation?

Analyzing the mathematics

Why do we do this?

Putting it all together to get the partial derivatives!

Back propagation intuition

Forward propagation with pictures!

Back propagation

J(Θ)=−1m[∑i=1my(i)log(hΘ(x(i)))+(1−y(i))log(1−(hΘ(x(i))))]+λ2m∑l=1L−1∑i=1sl∑j=1sl+1(Θji(l))2
cost(i)=y(i)loghΘ(x(i))+(1−y(i))log(1−hΘ(x(i))) The original slide writes the second logarithm as log h(x(i)), dropping the 1 − ; it is corrected here to match the same expression elsewhere in this chapter.

Implementation notes - unrolling parameters (matrices)

def cost_function(theta):
    ...
    return jval, gradient

res = minimize(cost_function, initial_theta, jac=True)
opt_theta = res.x
Neural Network (L = 4): Θ(1),Θ(2),Θ(3)— matrices D(1),D(2),D(3)— matrices In the code these are Theta1, Theta2, Theta3 and D1, D2, D3.

Example

s1=10,s2=10,s3=1 Θ(1)∈ℝ10×11,Θ(2)∈ℝ10×11,Θ(3)∈ℝ1×11 D(1)∈ℝ10×11,D(2)∈ℝ10×11,D(3)∈ℝ1×11
Theta1 = np.ones((10, 11))
Theta2 = np.ones((10, 11))
Theta3 = np.ones((1, 11))

theta_vec = np.concatenate([Theta1.ravel(), Theta2.ravel(), Theta3.ravel()])
theta_vec.shape   # (231,) = 110 + 110 + 11, one long vector

np.array_equal(theta_vec[0:110].reshape(10, 11), Theta1)   # True - the round trip

Unroll and reshape for the example network above: three matrices flatten into one 231-element vector and come back out unchanged.

Gradient checking

∂∂θ1J(θ)≈J(θ1+ϵ,θ2,θ3,…)−J(θ1−ϵ,θ2,θ3,…)2ϵ ∂∂θ2J(θ)≈J(θ1,θ2+ϵ,θ3,…)−J(θ1,θ2−ϵ,θ3,…)2ϵ ⋮ ∂∂θnJ(θ)≈J(θ1,θ2,θ3,…,θn+ϵ)−J(θ1,θ2,θ3,…,θn−ϵ)2ϵ Each partial derivative is checked by nudging one parameter and leaving the rest alone.
def J(theta):                  # a simple stand-in cost: J = sum of squares
    return (theta ** 2).sum()

theta = np.array([1.0, -2.0, 3.0])
EPSILON = 1e-4

grad_approx = np.zeros(3)
for i in range(3):
    theta_plus  = theta.copy(); theta_plus[i]  += EPSILON
    theta_minus = theta.copy(); theta_minus[i] -= EPSILON
    grad_approx[i] = (J(theta_plus) - J(theta_minus)) / (2 * EPSILON)

grad_approx   # [2., -4., 6.]  - the analytic gradient of sum-of-squares is 2*theta

Gradient checking on a cost simple enough to differentiate by hand: the two-sided differences land on 2θ to ten decimal places.

for i in range(n):
    theta_plus = theta.copy()
    theta_plus[i] += EPSILON
    theta_minus = theta.copy()
    theta_minus[i] -= EPSILON
    grad_approx[i] = (J(theta_plus) - J(theta_minus)) \
                     / (2 * EPSILON)

Random initialization

Putting it all together

for i in range(m):
    forward propagation on (xi, yi)   # get activation (a) terms
    back propagation on (xi, yi)      # get delta (δ) terms
    compute Δl := Δl + δl+1(al)T

With this done compute the partial derivative terms