Skip to content

Commit

Permalink
version 1.0 on DeepModel
Browse files Browse the repository at this point in the history
  • Loading branch information
orbxball committed May 30, 2017
1 parent e8c5427 commit 4b270b0
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 0 deletions.
47 changes: 47 additions & 0 deletions hw6/CFModel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# CFModel.py
#
# A simple implementation of matrix factorization for collaborative filtering
# expressed as a Keras Sequential model. This code is based on the approach
# outlined in [Alkahest](http:https://www.fenris.org/)'s blog post
# [Collaborative Filtering in Keras](http:https://www.fenris.org/2016/03/07/collaborative-filtering-in-keras).
#
# License: MIT. See the LICENSE file for the copyright notice.
#

import numpy as np
from keras.layers import Embedding, Reshape, Merge, Dropout, Dense
from keras.models import Sequential

class CFModel(Sequential):

def __init__(self, n_users, m_items, k_factors, **kwargs):
P = Sequential()
P.add(Embedding(n_users, k_factors, input_length=1))
P.add(Reshape((k_factors,)))
Q = Sequential()
Q.add(Embedding(m_items, k_factors, input_length=1))
Q.add(Reshape((k_factors,)))
super(CFModel, self).__init__(**kwargs)
self.add(Merge([P, Q], mode='dot', dot_axes=1))

def rate(self, user_id, item_id):
return self.predict([np.array([user_id]), np.array([item_id])])[0][0]

class DeepModel(Sequential):

def __init__(self, n_users, m_items, k_factors, p_dropout=0.1, **kwargs):
P = Sequential()
P.add(Embedding(n_users, k_factors, input_length=1))
P.add(Reshape((k_factors,)))
Q = Sequential()
Q.add(Embedding(m_items, k_factors, input_length=1))
Q.add(Reshape((k_factors,)))
super(DeepModel, self).__init__(**kwargs)
self.add(Merge([P, Q], mode='concat'))
self.add(Dropout(p_dropout))
self.add(Dense(k_factors, activation='relu'))
self.add(Dropout(p_dropout))
self.add(Dense(1, activation='linear'))

def rate(self, user_id, item_id):
return self.predict([np.array([user_id]), np.array([item_id])])[0][0]
67 changes: 67 additions & 0 deletions hw6/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import os
import sys
import argparse
import numpy as np
import pandas as pd
from CFModel import CFModel, DeepModel

def parse_args():
parser = argparse.ArgumentParser(description='HW6: Matrix Factorization')
parser.add_argument('train', type=str)
parser.add_argument('output', type=str)
return parser.parse_args()


def predict_rating(trained_model, userid, movieid):
return trained_model.rate(userid - 1, movieid - 1)


def ensure_dir(file_path):
directory = os.path.dirname(file_path)
if len(directory) == 0: return
if not os.path.exists(directory):
os.makedirs(directory)


def main(args):
ratings = pd.read_csv(args.train, usecols=['UserID', 'MovieID', 'Rating'])
max_userid = ratings['UserID'].drop_duplicates().max()
max_movieid = ratings['MovieID'].drop_duplicates().max()
print('{} ratings loaded.'.format(ratings.shape[0]))

users = pd.read_csv(USERS_CSV, sep='::', engine='python',
usecols=['UserID', 'Gender', 'Age', 'Occupation', 'Zip-code'])
print('{} description of {} users loaded'.format(len(users), max_userid))

movies = pd.read_csv(MOVIES_CSV, sep='::', engine='python',
usecols=['movieID', 'Title', 'Genres'])
print('{} descriptions of {} movies loaded'.format(len(movies), max_movieid))

test_data = pd.read_csv(TEST_CSV, usecols=['UserID', 'MovieID'])
print('{} testing data loaded.'.format(test_data.shape[0]))

trained_model = DeepModel(max_userid, max_movieid, DIM)
print('Loading model weights...')
trained_model.load_weights(MODEL_WEIGHTS_FILE)
print('Loading model done!!!')

recommendations = pd.read_csv(TEST_CSV, usecols=['TestDataID'])
recommendations['Rating'] = test_data.apply(lambda x: predict_rating(trained_model, x['UserID'], x['MovieID']), axis=1)
# print(recommendations)

ensure_dir(args.output)
recommendations.to_csv(args.output, index=False, columns=['TestDataID', 'Rating'])


if __name__ == '__main__':
args = parse_args()

TEST_CSV = 'data/test.csv'
USERS_CSV = 'data/users.csv'
MOVIES_CSV = 'data/movies.csv'
MODEL_WEIGHTS_FILE = 'weights.h5'

DIM = 120
TEST_USER = 3000

main(args)
47 changes: 47 additions & 0 deletions hw6/train.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import os
import sys
import argparse
import numpy as np
import pandas as pd
from keras.callbacks import Callback, EarlyStopping, ModelCheckpoint
from CFModel import CFModel, DeepModel

def parse_args():
parser = argparse.ArgumentParser(description='HW6: Matrix Factorization')
parser.add_argument('train', type=str)
parser.add_argument('test', type=str)
return parser.parse_args()


def main(args):
ratings = pd.read_csv(args.train,
usecols=['UserID', 'MovieID', 'Rating'])
max_userid = ratings['UserID'].drop_duplicates().max()
max_movieid = ratings['MovieID'].drop_duplicates().max()
ratings['User_emb_id'] = ratings['UserID'] - 1
ratings['Movie_emb_id'] = ratings['MovieID'] - 1
print('{} ratings loaded.'.format(ratings.shape[0]))

ratings = ratings.sample(frac=1)
Users = ratings['User_emb_id'].values
print('Users: {}, shape = {}'.format(Users, Users.shape))
Movies = ratings['Movie_emb_id'].values
print('Movies: {}, shape = {}'.format(Movies, Movies.shape))
Ratings = ratings['Rating'].values
print('Ratings: {}, shape = {}'.format(Ratings, Ratings.shape))

model = DeepModel(max_userid, max_movieid, DIM)
model.compile(loss='mse', optimizer='adamax')

callbacks = [EarlyStopping('val_loss', patience=2),
ModelCheckpoint(MODEL_WEIGHTS_FILE, save_best_only=True)]
history = model.fit([Users, Movies], Ratings, epochs=100, validation_split=.1, verbose=1, callbacks=callbacks)


if __name__ == '__main__':
args = parse_args()

DIM = 120
MODEL_WEIGHTS_FILE = 'weights.h5'

main(args)

0 comments on commit 4b270b0

Please sign in to comment.