defcofi_cost_func(X, W, b, Y, R, lambda_): """ Returns the cost for the content-based filtering Args: X (ndarray (num_movies,num_features)): matrix of item features W (ndarray (num_users,num_features)) : matrix of user parameters b (ndarray (1, num_users) : vector of user parameters Y (ndarray (num_movies,num_users) : matrix of user ratings of movies R (ndarray (num_movies,num_users) : matrix, where R(i, j) = 1 if the i-th movies was rated by the j-th user lambda_ (float): regularization parameter Returns: J (float) : Cost """ nm, nu = Y.shape J = 0 ### START CODE HERE ### for j inrange(nu): w = W[j, :] b_j = b[0,j] for i inrange(nm): x = X[i, :] y = Y[i, j] r = R[i, j] J += np.square(r * (np.dot(w, x) - y + b_j)) # 正则化 J += lambda_ * (np.sum(np.square(W)) + np.sum(np.square(X))) J /= 2 ### END CODE HERE ###
return J
向量API实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
defcofi_cost_func_v(X, W, b, Y, R, lambda_): """ Returns the cost for the content-based filtering Vectorized for speed. Uses tensorflow operations to be compatible with custom training loop. Args: X (ndarray (num_movies,num_features)): matrix of item features W (ndarray (num_users,num_features)) : matrix of user parameters b (ndarray (1, num_users) : vector of user parameters Y (ndarray (num_movies,num_users) : matrix of user ratings of movies R (ndarray (num_movies,num_users) : matrix, where R(i, j) = 1 if the i-th movies was rated by the j-th user lambda_ (float): regularization parameter Returns: J (float) : Cost """ j = (tf.linalg.matmul(X, tf.transpose(W)) + b - Y)*R J = 0.5 * tf.reduce_sum(j**2) + (lambda_/2) * (tf.reduce_sum(X**2) + tf.reduce_sum(W**2)) return J
my_ratings = np.zeros(num_movies) # Initialize my ratings
# Check the file small_movie_list.csv for id of each movie in our dataset # For example, Toy Story 3 (2010) has ID 2700, so to rate it "5", you can set my_ratings[2700] = 5
#Or suppose you did not enjoy Persuasion (2007), you can set my_ratings[2609] = 2;
# We have selected a few movies we liked / did not like and the ratings we # gave are as follows: my_ratings[929] = 5# Lord of the Rings: The Return of the King, The my_ratings[246] = 5# Shrek (2001) my_ratings[2716] = 3# Inception my_ratings[1150] = 5# Incredibles, The (2004) my_ratings[382] = 2# Amelie (Fabuleux destin d'Amélie Poulain, Le) my_ratings[366] = 5# Harry Potter and the Sorcerer's Stone (a.k.a. Harry Potter and the Philosopher's Stone) (2001) my_ratings[622] = 5# Harry Potter and the Chamber of Secrets (2002) my_ratings[988] = 3# Eternal Sunshine of the Spotless Mind (2004) my_ratings[2925] = 1# Louis Theroux: Law & Disorder (2008) my_ratings[2937] = 1# Nothing to Declare (Rien à déclarer) my_ratings[793] = 5# Pirates of the Caribbean: The Curse of the Black Pearl (2003) my_rated = [i for i inrange(len(my_ratings)) if my_ratings[i] > 0]
print('\nNew user ratings:\n') for i inrange(len(my_ratings)): if my_ratings[i] > 0 : print(f'Rated {my_ratings[i]} for {movieList_df.loc[i,"title"]}');
将新用户加入数据集中并归一化:
1 2 3 4 5 6 7
# Reload ratings and add new ratings Y, R = load_ratings_small() Y = np.c_[my_ratings, Y] R = np.c_[(my_ratings != 0).astype(int), R]
# Normalize the Dataset Ynorm, Ymean = normalizeRatings(Y, R)
归一化函数:
1 2 3 4 5 6 7 8 9 10 11
defnormalizeRatings(Y, R): """ Preprocess data by subtracting mean rating for every movie (every row). Only include real ratings R(i,j)=1. [Ynorm, Ymean] = normalizeRatings(Y, R) normalized Y so that each movie has a rating of 0 on average. Unrated moves then have a mean rating (0) Returns the mean rating in Ymean. """ Ymean = (np.sum(Y*R,axis=1)/(np.sum(R, axis=1)+1e-12)).reshape(-1,1) Ynorm = Y - np.multiply(Ymean, R) return(Ynorm, Ymean)
# Set Initial Parameters (W, X), use tf.Variable to track these variables tf.random.set_seed(1234) # for consistent results W = tf.Variable(tf.random.normal((num_users, num_features),dtype=tf.float64), name='W') X = tf.Variable(tf.random.normal((num_movies, num_features),dtype=tf.float64), name='X') b = tf.Variable(tf.random.normal((1, num_users), dtype=tf.float64), name='b')
# Instantiate an optimizer. optimizer = keras.optimizers.Adam(learning_rate=1e-1)
iterations = 200 lambda_ = 1 foriterinrange(iterations): # Use TensorFlow’s GradientTape # to record the operations used to compute the cost with tf.GradientTape() as tape:
# Compute the cost (forward pass included in cost) cost_value = cofi_cost_func_v(X, W, b, Ynorm, R, lambda_)
# Use the gradient tape to automatically retrieve # the gradients of the trainable variables with respect to the loss grads = tape.gradient( cost_value, [X,W,b] )
# Run one step of gradient descent by updating # the value of the variables to minimize the loss. optimizer.apply_gradients( zip(grads, [X,W,b]) )
# Log periodically. ifiter % 20 == 0: print(f"Training loss at iteration {iter}: {cost_value:0.1f}")
# Make a prediction using trained weights and biases p = np.matmul(X.numpy(), np.transpose(W.numpy())) + b.numpy()
#restore the mean pm = p + Ymean
my_predictions = pm[:,0]
# sort predictions ix = tf.argsort(my_predictions, direction='DESCENDING')
for i inrange(17): j = ix[i] if j notin my_rated: print(f'Predicting rating {my_predictions[j]:0.2f} for movie {movieList[j]}')
print('\n\nOriginal vs Predicted ratings:\n') for i inrange(len(my_ratings)): if my_ratings[i] > 0: print(f'Original {my_ratings[i]}, Predicted {my_predictions[i]:0.2f} for {movieList[i]}')
表格查询:
1 2 3 4
filter=(movieList_df["number of ratings"] > 20) movieList_df["pred"] = my_predictions movieList_df = movieList_df.reindex(columns=["pred", "mean rating", "number of ratings", "title"]) movieList_df.loc[ix[:300]].loc[filter].sort_values("mean rating", ascending=False)
num_outputs = 32 tf.random.set_seed(1) user_NN = tf.keras.models.Sequential([ ### START CODE HERE ### tf.keras.layers.Dense(256, activation='relu'), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dense(num_outputs), ### END CODE HERE ### ])
item_NN = tf.keras.models.Sequential([ ### START CODE HERE ### tf.keras.layers.Dense(256, activation='relu'), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dense(num_outputs), ### END CODE HERE ### ])
# create the user input and point to the base network input_user = tf.keras.layers.Input(shape=(num_user_features)) vu = user_NN(input_user) vu = tf.linalg.l2_normalize(vu, axis=1)
# create the item input and point to the base network input_item = tf.keras.layers.Input(shape=(num_item_features)) vm = item_NN(input_item) vm = tf.linalg.l2_normalize(vm, axis=1)
# compute the dot product of the two vectors vu and vm output = tf.keras.layers.Dot(axes=1)([vu, vm])
# specify the inputs and output of the model model = Model([input_user, input_item], output)