Assignment 3 - Multi-class Classification and Neural Network
'''
:param num_in: the number of input units in the weight array
:param num_out: the number of output units in the weight array
'''
# Note that 'W' contains both weights and bias, you can consider W[0, :] as bias
W = np.zeros((1 + num_in, num_out))
###################################################################################
# Full Mark: 1 #
# TODO: #
# Implement Xavier/Glorot uniform initialization #
# #
# Hint: you can find the reference here: #
# https://www.tensorflow.org/api_docs/python/tf/keras/initializers/GlorotUniform #
###################################################################################
W =
###################################################################################
# END OF YOUR CODE #
###################################################################################
return W
def sigmoid(x):
'''
:param x: input
'''
###################################################################################
# Full Mark: 0.5 #
# TODO: #
# Implement sigmoid function: #
# sigmoid(x) = 1/(1+e^(-x)) #
###################################################################################
res =
###################################################################################
# END OF YOUR CODE #
###################################################################################
return res
def tanh(x):
'''
:param x: input
'''
###################################################################################
# Full Mark: 0.5 #
# TODO: #
# Implement tanh function: #
# tanh(x) = (e^x-e^(-x)) / (e^x+e^(-x)) #
###################################################################################
res =
###################################################################################
# END OF YOUR CODE #
###################################################################################
return res
def sigmoid_gradient(x):
'''
:param x: input
'''
###################################################################################
# Full Mark: 1 #
# TODO: #
# Computes the gradient of the sigmoid function evaluated at x. #
# #
###################################################################################
grad =
###################################################################################
# END OF YOUR CODE #
###################################################################################
return grad
def tanh_gradient(x):
'''
:param x: input
'''
###################################################################################
# Full Mark: 1 #
# TODO: #
# Computes the gradient of the tanh function evaluated at x. #
# #
###################################################################################
grad =
###################################################################################
# END OF YOUR CODE #
###################################################################################
return grad
def forward(W, X):
'''
:param W: weights (including biases) of the neural network. It is a list containing both W_hidden and W_output.
:param X: input. Already added one additional column of all "1"s.
'''
# Shape of W_hidden: [num_feature+1, num_hidden]
# Shape pf W_output: [num_hidden+1, num_output]
W_hidden, W_output = W
###################################################################################
# Full Mark: 1 #
# TODO: #
# Implement the forward pass. You need to compute four values: #
# z_hidden, a_hidden, z_output, a_output #
# #
# Note that our neural network consists of three layers: #
# Input -> Hidden -> Output #
# The activation function in hidden layer is 'tanh' #
# The activation function in output layer is 'sigmoid' #
###################################################################################
###################################################################################
# END OF YOUR CODE #
###################################################################################
# z_hidden is the raw output of hidden layer, a_hidden is the result after performing activation on z_hidden
# z_output is the raw output of output layer, a_output is the result after performing activation on z_output
return {'z_hidden': z_hidden, 'a_hidden': a_hidden,
'z_output': z_output, 'a_output': a_output}
def loss_funtion(W, X, y, num_feature, num_hidden, num_output, L2_lambda):
'''
:param W: a 1D array containing all weights and biases.
:param X: input
:param y: labels of X
:param num_feature: number of features in X
:param num_hidden: number of hidden units
:param num_output: number of output units
:param L2_lambda: the coefficient of regularization term
'''
m = y.size
# Reshape W back into the parameters W_hidden and W_output
W_hidden = np.reshape(W[:num_hidden * (num_feature + 1)],
((num_feature + 1), num_hidden))
W_output = np.reshape(W[(num_hidden * (num_feature + 1)):],
((num_hidden + 1), num_output))
# Initialize grads
W_hidden_grad = np.zeros(W_hidden.shape)
W_output_grad = np.zeros(W_output.shape)
# Add one column of "1"s to X
X_input = np.concatenate([np.ones((m, 1)), X], axis=1)
##########################################################################################
# Full Mark: 3 #
# TODO: #
# 1. Transform y to one-hot encoding. Implement binary cross-entropy loss function #
# (Hint: Use the forward function to get necessary outputs from the model) #
# #
# 2. Add L2 regularization to all weights in loss #
# (Note that we will not add regularization to bias) #
# #
# 3. Compute the gradient for W_hidden and W_output (including both weights and biases) #
# (Hint: use chain rule, and the sigmoid gradient, tanh gradient you have #
# implemented above. Don't forget to add the gradient of regularization term) #
##########################################################################################
L =
W_hidden_grad =
W_output_grad =
###################################################################################
# END OF YOUR CODE #
###################################################################################
grads = np.concatenate([W_hidden_grad.ravel(), W_output_grad.ravel()])
return L, grads
def optimize(initial_W, X, y, num_epoch, num_feature, num_hidden, num_output, L2_lambda):
'''
:param initial_W: initial weights as a 1D array.
:param X: input
:param y: labels of X
:param num_epoch: number of iterations
:param num_feature: number of features in X
:param num_hidden: number of hidden units
:param num_output: number of output units
:param L2_lambda: the coefficient of regularization term
'''
options = {'maxiter': num_epoch}
###########################################################################################
# Full Mark: 1 #
# TODO: #
# Optimize weights #
# (Hint: use scipy.optimize.minimize to automatically do the iteration.) #
# ref: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html) #
# For some optimizers, you need to set 'jac' as True. #
# You may need to use lambda to create a function with one parameter to wrap the #
# loss_funtion you have implemented above. #
# #
# Note that scipy.optimize.minimize only accepts a 1D weight array as initial weights, #
# and the output optimized weights will also be a 1D array. #
# That is why we unroll the initial weights into a single long vector. #
###########################################################################################
W_final =
###################################################################################
# END OF YOUR CODE #
###################################################################################
# Obtain W_hidden and W_output back from W_final
W_hidden = np.reshape(W_final[:num_hidden * (num_feature + 1)],
((num_feature + 1), num_hidden))
W_output = np.reshape(W_final[(num_hidden * (num_feature + 1)):],
((num_hidden + 1), num_output))
return [W_hidden, W_output]
def predict(X_test, y_test, W):
'''
:param X_test: input
:param y_test: labels of X_test
:param W: a list containing two weights W_hidden and W_output.
'''
test_input = np.concatenate([np.ones((y_test.size, 1)), X_test], axis=1)
###################################################################################
# Full Mark: 1 #
# TODO: #
# Predict on test set and compute the accuracy. #
# (Hint: use forward function to get predicted output) #
# #
###################################################################################
acc =
###################################################################################
# END OF YOUR CODE #
###################################################################################
return acc