First commit
This commit is contained in:
269
Exercise8/utils.py
Executable file
269
Exercise8/utils.py
Executable file
@@ -0,0 +1,269 @@
|
||||
import numpy as np
|
||||
import sys
|
||||
from os.path import join
|
||||
from matplotlib import pyplot
|
||||
|
||||
sys.path.append('..')
|
||||
from submission import SubmissionBase
|
||||
|
||||
|
||||
def normalizeRatings(Y, R):
|
||||
"""
|
||||
Preprocess data by subtracting mean rating for every movie (every row).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
Y : array_like
|
||||
The user ratings for all movies. A matrix of shape (num_movies x num_users).
|
||||
|
||||
R : array_like
|
||||
Indicator matrix for movies rated by users. A matrix of shape (num_movies x num_users).
|
||||
|
||||
Returns
|
||||
-------
|
||||
Ynorm : array_like
|
||||
A matrix of same shape as Y, after mean normalization.
|
||||
|
||||
Ymean : array_like
|
||||
A vector of shape (num_movies, ) containing the mean rating for each movie.
|
||||
"""
|
||||
m, n = Y.shape
|
||||
Ymean = np.zeros(m)
|
||||
Ynorm = np.zeros(Y.shape)
|
||||
|
||||
for i in range(m):
|
||||
idx = R[i, :] == 1
|
||||
Ymean[i] = np.mean(Y[i, idx])
|
||||
Ynorm[i, idx] = Y[i, idx] - Ymean[i]
|
||||
|
||||
return Ynorm, Ymean
|
||||
|
||||
|
||||
def loadMovieList():
|
||||
"""
|
||||
Reads the fixed movie list in movie_ids.txt and returns a list of movie names.
|
||||
|
||||
Returns
|
||||
-------
|
||||
movieNames : list
|
||||
A list of strings, representing all movie names.
|
||||
"""
|
||||
# Read the fixed movieulary list
|
||||
with open(join('Data', 'movie_ids.txt'), encoding='ISO-8859-1') as fid:
|
||||
movies = fid.readlines()
|
||||
|
||||
movieNames = []
|
||||
for movie in movies:
|
||||
parts = movie.split()
|
||||
movieNames.append(' '.join(parts[1:]).strip())
|
||||
return movieNames
|
||||
|
||||
|
||||
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.
|
||||
|
||||
Returns
|
||||
-------
|
||||
numgrad : array_like
|
||||
The numerical gradient with respect to theta. Has same shape as theta.
|
||||
|
||||
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 checkCostFunction(cofiCostFunc, lambda_=0.):
|
||||
"""
|
||||
Creates a collaborative filtering problem to check your cost function and gradients.
|
||||
It will output the analytical gradients produced by your code and the numerical gradients
|
||||
(computed using computeNumericalGradient). These two gradient computations should result
|
||||
in very similar values.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
cofiCostFunc: func
|
||||
Implementation of the cost function.
|
||||
|
||||
lambda_ : float, optional
|
||||
The regularization parameter.
|
||||
"""
|
||||
# Create small problem
|
||||
X_t = np.random.rand(4, 3)
|
||||
Theta_t = np.random.rand(5, 3)
|
||||
|
||||
# Zap out most entries
|
||||
Y = np.dot(X_t, Theta_t.T)
|
||||
Y[np.random.rand(*Y.shape) > 0.5] = 0
|
||||
R = np.zeros(Y.shape)
|
||||
R[Y != 0] = 1
|
||||
|
||||
# Run Gradient Checking
|
||||
X = np.random.randn(*X_t.shape)
|
||||
Theta = np.random.randn(*Theta_t.shape)
|
||||
num_movies, num_users = Y.shape
|
||||
num_features = Theta_t.shape[1]
|
||||
|
||||
params = np.concatenate([X.ravel(), Theta.ravel()])
|
||||
numgrad = computeNumericalGradient(
|
||||
lambda x: cofiCostFunc(x, Y, R, num_users, num_movies, num_features, lambda_), params)
|
||||
|
||||
cost, grad = cofiCostFunc(params, Y, R, num_users,num_movies, num_features, lambda_)
|
||||
|
||||
print(np.stack([numgrad, grad], axis=1))
|
||||
print('\nThe above two columns you get should be very similar.'
|
||||
'(Left-Your Numerical Gradient, Right-Analytical Gradient)')
|
||||
|
||||
diff = np.linalg.norm(numgrad-grad)/np.linalg.norm(numgrad+grad)
|
||||
print('If your cost function implementation is correct, then '
|
||||
'the relative difference will be small (less than 1e-9).')
|
||||
print('\nRelative Difference: %g' % diff)
|
||||
|
||||
|
||||
def multivariateGaussian(X, mu, Sigma2):
|
||||
"""
|
||||
Computes the probability density function of the multivariate gaussian distribution.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : array_like
|
||||
The dataset of shape (m x n). Where there are m examples of n-dimensions.
|
||||
|
||||
mu : array_like
|
||||
A vector of shape (n,) contains the means for each dimension (feature).
|
||||
|
||||
Sigma2 : array_like
|
||||
Either a vector of shape (n,) containing the variances of independent features
|
||||
(i.e. it is the diagonal of the correlation matrix), or the full
|
||||
correlation matrix of shape (n x n) which can represent dependent features.
|
||||
|
||||
Returns
|
||||
------
|
||||
p : array_like
|
||||
A vector of shape (m,) which contains the computed probabilities at each of the
|
||||
provided examples.
|
||||
"""
|
||||
k = mu.size
|
||||
|
||||
# if sigma is given as a diagonal, compute the matrix
|
||||
if Sigma2.ndim == 1:
|
||||
Sigma2 = np.diag(Sigma2)
|
||||
|
||||
X = X - mu
|
||||
p = (2 * np.pi) ** (- k / 2) * np.linalg.det(Sigma2) ** (-0.5)\
|
||||
* np.exp(-0.5 * np.sum(np.dot(X, np.linalg.pinv(Sigma2)) * X, axis=1))
|
||||
return p
|
||||
|
||||
|
||||
def visualizeFit(X, mu, sigma2):
|
||||
"""
|
||||
Visualize the dataset and its estimated distribution.
|
||||
This visualization shows you the probability density function of the Gaussian distribution.
|
||||
Each example has a location (x1, x2) that depends on its feature values.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : array_like
|
||||
The dataset of shape (m x 2). Where there are m examples of 2-dimensions. We need at most
|
||||
2-D features to be able to visualize the distribution.
|
||||
|
||||
mu : array_like
|
||||
A vector of shape (n,) contains the means for each dimension (feature).
|
||||
|
||||
sigma2 : array_like
|
||||
Either a vector of shape (n,) containing the variances of independent features
|
||||
(i.e. it is the diagonal of the correlation matrix), or the full
|
||||
correlation matrix of shape (n x n) which can represent dependent features.
|
||||
"""
|
||||
|
||||
X1, X2 = np.meshgrid(np.arange(0, 35.5, 0.5), np.arange(0, 35.5, 0.5))
|
||||
Z = multivariateGaussian(np.stack([X1.ravel(), X2.ravel()], axis=1), mu, sigma2)
|
||||
Z = Z.reshape(X1.shape)
|
||||
|
||||
pyplot.plot(X[:, 0], X[:, 1], 'bx', mec='b', mew=2, ms=8)
|
||||
|
||||
if np.all(abs(Z) != np.inf):
|
||||
pyplot.contour(X1, X2, Z, levels=10**(np.arange(-20., 1, 3)), zorder=100)
|
||||
|
||||
|
||||
class Grader(SubmissionBase):
|
||||
# Random Test Cases
|
||||
n_u = 3
|
||||
n_m = 4
|
||||
n = 5
|
||||
X = np.sin(np.arange(1, 1 + n_m * n)).reshape(n_m, n, order='F')
|
||||
Theta = np.cos(np.arange(1, 1 + n_u * n)).reshape(n_u, n, order='F')
|
||||
Y = np.sin(np.arange(1, 1 + 2 * n_m * n_u, 2)).reshape(n_m, n_u, order='F')
|
||||
R = Y > 0.5
|
||||
pval = np.concatenate([abs(Y.ravel('F')), [0.001], [1]])
|
||||
Y = Y * R # set 'Y' values to 0 for movies not reviewed
|
||||
|
||||
yval = np.concatenate([R.ravel('F'), [1], [0]])
|
||||
#
|
||||
params = np.concatenate([X.ravel(), Theta.ravel()])
|
||||
|
||||
def __init__(self):
|
||||
part_names = ['Estimate Gaussian Parameters',
|
||||
'Select Threshold',
|
||||
'Collaborative Filtering Cost',
|
||||
'Collaborative Filtering Gradient',
|
||||
'Regularized Cost',
|
||||
'Regularized Gradient']
|
||||
super().__init__('anomaly-detection-and-recommender-systems', part_names)
|
||||
|
||||
def __iter__(self):
|
||||
for part_id in range(1, 7):
|
||||
try:
|
||||
func = self.functions[part_id]
|
||||
|
||||
# Each part has different expected arguments/different function
|
||||
if part_id == 1:
|
||||
res = np.hstack(func(self.X)).tolist()
|
||||
elif part_id == 2:
|
||||
res = np.hstack(func(self.yval, self.pval)).tolist()
|
||||
elif part_id == 3:
|
||||
J, grad = func(self.params, self.Y, self.R, self.n_u, self.n_m, self.n)
|
||||
res = J
|
||||
elif part_id == 4:
|
||||
J, grad = func(self.params, self.Y, self.R, self.n_u, self.n_m, self.n, 0)
|
||||
xgrad = grad[:self.n_m*self.n].reshape(self.n_m, self.n)
|
||||
thetagrad = grad[self.n_m*self.n:].reshape(self.n_u, self.n)
|
||||
res = np.hstack([xgrad.ravel('F'), thetagrad.ravel('F')]).tolist()
|
||||
elif part_id == 5:
|
||||
res, _ = func(self.params, self.Y, self.R, self.n_u, self.n_m, self.n, 1.5)
|
||||
elif part_id == 6:
|
||||
J, grad = func(self.params, self.Y, self.R, self.n_u, self.n_m, self.n, 1.5)
|
||||
xgrad = grad[:self.n_m*self.n].reshape(self.n_m, self.n)
|
||||
thetagrad = grad[self.n_m*self.n:].reshape(self.n_u, self.n)
|
||||
res = np.hstack([xgrad.ravel('F'), thetagrad.ravel('F')]).tolist()
|
||||
else:
|
||||
raise KeyError
|
||||
yield part_id, res
|
||||
except KeyError:
|
||||
yield part_id, 0
|
||||
Reference in New Issue
Block a user