227 lines
8.0 KiB
Python
Executable File
227 lines
8.0 KiB
Python
Executable File
import sys
|
|
import numpy as np
|
|
from matplotlib import pyplot
|
|
|
|
sys.path.append('..')
|
|
from submission import SubmissionBase
|
|
|
|
|
|
def displayData(X, example_width=None, figsize=(10, 10)):
|
|
"""
|
|
Displays 2D data stored in X in a nice grid.
|
|
"""
|
|
# Compute rows, cols
|
|
if X.ndim == 2:
|
|
m, n = X.shape
|
|
elif X.ndim == 1:
|
|
n = X.size
|
|
m = 1
|
|
X = X[None] # Promote to a 2 dimensional array
|
|
else:
|
|
raise IndexError('Input X should be 1 or 2 dimensional.')
|
|
|
|
example_width = example_width or int(np.round(np.sqrt(n)))
|
|
example_height = n / example_width
|
|
|
|
# Compute number of items to display
|
|
display_rows = int(np.floor(np.sqrt(m)))
|
|
display_cols = int(np.ceil(m / display_rows))
|
|
|
|
fig, ax_array = pyplot.subplots(display_rows, display_cols, figsize=figsize)
|
|
fig.subplots_adjust(wspace=0.025, hspace=0.025)
|
|
|
|
ax_array = [ax_array] if m == 1 else ax_array.ravel()
|
|
|
|
for i, ax in enumerate(ax_array):
|
|
# Display Image
|
|
h = ax.imshow(X[i].reshape(example_width, example_width, order='F'),
|
|
cmap='Greys', extent=[0, 1, 0, 1])
|
|
ax.axis('off')
|
|
|
|
|
|
def predict(Theta1, Theta2, X):
|
|
"""
|
|
Predict the label of an input given a trained neural network
|
|
Outputs the predicted label of X given the trained weights of a neural
|
|
network(Theta1, Theta2)
|
|
"""
|
|
# Useful values
|
|
m = X.shape[0]
|
|
num_labels = Theta2.shape[0]
|
|
|
|
# You need to return the following variables correctly
|
|
p = np.zeros(m)
|
|
h1 = sigmoid(np.dot(np.concatenate([np.ones((m, 1)), X], axis=1), Theta1.T))
|
|
h2 = sigmoid(np.dot(np.concatenate([np.ones((m, 1)), h1], axis=1), Theta2.T))
|
|
p = np.argmax(h2, axis=1)
|
|
return p
|
|
|
|
|
|
def debugInitializeWeights(fan_out, fan_in):
|
|
"""
|
|
Initialize the weights of a layer with fan_in incoming connections and fan_out outgoings
|
|
connections using a fixed strategy. This will help you later in debugging.
|
|
|
|
Note that W should be set a matrix of size (1+fan_in, fan_out) as the first row of W handles
|
|
the "bias" terms.
|
|
|
|
Parameters
|
|
----------
|
|
fan_out : int
|
|
The number of outgoing connections.
|
|
|
|
fan_in : int
|
|
The number of incoming connections.
|
|
|
|
Returns
|
|
-------
|
|
W : array_like (1+fan_in, fan_out)
|
|
The initialized weights array given the dimensions.
|
|
"""
|
|
# Initialize W using "sin". This ensures that W is always of the same values and will be
|
|
# useful for debugging
|
|
W = np.sin(np.arange(1, 1 + (1+fan_in)*fan_out))/10.0
|
|
W = W.reshape(fan_out, 1+fan_in, order='F')
|
|
return W
|
|
|
|
|
|
def computeNumericalGradient(J, theta, e=1e-4):
|
|
"""
|
|
Computes the gradient using "finite differences" and gives us a numerical estimate of the
|
|
gradient.
|
|
|
|
Parameters
|
|
----------
|
|
J : func
|
|
The cost function which will be used to estimate its numerical gradient.
|
|
|
|
theta : array_like
|
|
The one dimensional unrolled network parameters. The numerical gradient is computed at
|
|
those given parameters.
|
|
|
|
e : float (optional)
|
|
The value to use for epsilon for computing the finite difference.
|
|
|
|
Notes
|
|
-----
|
|
The following code implements numerical gradient checking, and
|
|
returns the numerical gradient. It sets `numgrad[i]` to (a numerical
|
|
approximation of) the partial derivative of J with respect to the
|
|
i-th input argument, evaluated at theta. (i.e., `numgrad[i]` should
|
|
be the (approximately) the partial derivative of J with respect
|
|
to theta[i].)
|
|
"""
|
|
numgrad = np.zeros(theta.shape)
|
|
perturb = np.diag(e * np.ones(theta.shape))
|
|
for i in range(theta.size):
|
|
loss1, _ = J(theta - perturb[:, i])
|
|
loss2, _ = J(theta + perturb[:, i])
|
|
numgrad[i] = (loss2 - loss1)/(2*e)
|
|
return numgrad
|
|
|
|
|
|
def checkNNGradients(nnCostFunction, lambda_=0):
|
|
"""
|
|
Creates a small neural network to check the backpropagation gradients. It will output the
|
|
analytical gradients produced by your backprop code and the numerical gradients
|
|
(computed using computeNumericalGradient). These two gradient computations should result in
|
|
very similar values.
|
|
|
|
Parameters
|
|
----------
|
|
nnCostFunction : func
|
|
A reference to the cost function implemented by the student.
|
|
|
|
lambda_ : float (optional)
|
|
The regularization parameter value.
|
|
"""
|
|
input_layer_size = 3
|
|
hidden_layer_size = 5
|
|
num_labels = 3
|
|
m = 5
|
|
|
|
# We generate some 'random' test data
|
|
Theta1 = debugInitializeWeights(hidden_layer_size, input_layer_size)
|
|
Theta2 = debugInitializeWeights(num_labels, hidden_layer_size)
|
|
|
|
# Reusing debugInitializeWeights to generate X
|
|
X = debugInitializeWeights(m, input_layer_size - 1)
|
|
y = np.arange(1, 1+m) % num_labels
|
|
# print(y)
|
|
# Unroll parameters
|
|
nn_params = np.concatenate([Theta1.ravel(), Theta2.ravel()])
|
|
|
|
# short hand for cost function
|
|
costFunc = lambda p: nnCostFunction(p, input_layer_size, hidden_layer_size,
|
|
num_labels, X, y, lambda_)
|
|
cost, grad = costFunc(nn_params)
|
|
numgrad = computeNumericalGradient(costFunc, nn_params)
|
|
|
|
# Visually examine the two gradient computations.The two columns you get should be very similar.
|
|
print(np.stack([numgrad, grad], axis=1))
|
|
print('The above two columns you get should be very similar.')
|
|
print('(Left-Your Numerical Gradient, Right-Analytical Gradient)\n')
|
|
|
|
# Evaluate the norm of the difference between two the solutions. If you have a correct
|
|
# implementation, and assuming you used e = 0.0001 in computeNumericalGradient, then diff
|
|
# should be less than 1e-9.
|
|
diff = np.linalg.norm(numgrad - grad)/np.linalg.norm(numgrad + grad)
|
|
|
|
print('If your backpropagation implementation is correct, then \n'
|
|
'the relative difference will be small (less than 1e-9). \n'
|
|
'Relative Difference: %g' % diff)
|
|
|
|
|
|
def sigmoid(z):
|
|
"""
|
|
Computes the sigmoid of z.
|
|
"""
|
|
return 1.0 / (1.0 + np.exp(-z))
|
|
|
|
|
|
class Grader(SubmissionBase):
|
|
X = np.reshape(3 * np.sin(np.arange(1, 31)), (3, 10), order='F')
|
|
Xm = np.reshape(np.sin(np.arange(1, 33)), (16, 2), order='F') / 5
|
|
ym = np.arange(1, 17) % 4
|
|
t1 = np.sin(np.reshape(np.arange(1, 25, 2), (4, 3), order='F'))
|
|
t2 = np.cos(np.reshape(np.arange(1, 41, 2), (4, 5), order='F'))
|
|
t = np.concatenate([t1.ravel(), t2.ravel()], axis=0)
|
|
|
|
def __init__(self):
|
|
part_names = ['Feedforward and Cost Function',
|
|
'Regularized Cost Function',
|
|
'Sigmoid Gradient',
|
|
'Neural Network Gradient (Backpropagation)',
|
|
'Regularized Gradient']
|
|
super().__init__('neural-network-learning', part_names)
|
|
|
|
def __iter__(self):
|
|
for part_id in range(1, 6):
|
|
try:
|
|
func = self.functions[part_id]
|
|
|
|
# Each part has different expected arguments/different function
|
|
if part_id == 1:
|
|
res = func(self.t, 2, 4, 4, self.Xm, self.ym, 0)[0]
|
|
elif part_id == 2:
|
|
res = func(self.t, 2, 4, 4, self.Xm, self.ym, 1.5)
|
|
elif part_id == 3:
|
|
res = func(self.X, )
|
|
elif part_id == 4:
|
|
J, grad = func(self.t, 2, 4, 4, self.Xm, self.ym, 0)
|
|
grad1 = np.reshape(grad[:12], (4, 3))
|
|
grad2 = np.reshape(grad[12:], (4, 5))
|
|
grad = np.concatenate([grad1.ravel('F'), grad2.ravel('F')])
|
|
res = np.hstack([J, grad]).tolist()
|
|
elif part_id == 5:
|
|
J, grad = func(self.t, 2, 4, 4, self.Xm, self.ym, 1.5)
|
|
grad1 = np.reshape(grad[:12], (4, 3))
|
|
grad2 = np.reshape(grad[12:], (4, 5))
|
|
grad = np.concatenate([grad1.ravel('F'), grad2.ravel('F')])
|
|
res = np.hstack([J, grad]).tolist()
|
|
else:
|
|
raise KeyError
|
|
yield part_id, res
|
|
except KeyError:
|
|
yield part_id, 0
|