Recommendation (Pytorch) Inference

from surprise import Dataset
import numpy as np
import torch
from torch import nn
import pandas as pd

class MF(nn.Module):
    itr = 0
    
    def __init__(self, n_user, n_item, k=18, c_vector=1.0, c_bias=1.0):
        super(MF, self).__init__()
        self.k = k
        self.n_user = n_user
        self.n_item = n_item
        self.c_bias = c_bias
        self.c_vector = c_vector
        
        self.user = nn.Embedding(n_user, k)
        self.item = nn.Embedding(n_item, k)
        
        # We've added new terms here:
        self.bias_user = nn.Embedding(n_user, 1)
        self.bias_item = nn.Embedding(n_item, 1)
        self.bias = nn.Parameter(torch.ones(1))
    
    def __call__(self, train_x):
        user_id = train_x[:, 0]
        item_id = train_x[:, 1]
        vector_user = self.user(user_id)
        vector_item = self.item(item_id)
        
        # Pull out biases
        bias_user = self.bias_user(user_id).squeeze()
        bias_item = self.bias_item(item_id).squeeze()
        biases = (self.bias + bias_user + bias_item)
        
        ui_interaction = torch.sum(vector_user * vector_item, dim=1)
        
        # Add bias prediction to the interaction prediction
        prediction = ui_interaction + biases
        return prediction
    
    def loss(self, prediction, target):
        loss_mse = F.mse_loss(prediction, target.squeeze())
        
        # Add new regularization to the biases
        prior_bias_user =  l2_regularize(self.bias_user.weight) * self.c_bias
        prior_bias_item = l2_regularize(self.bias_item.weight) * self.c_bias
        
        prior_user =  l2_regularize(self.user.weight) * self.c_vector
        prior_item = l2_regularize(self.item.weight) * self.c_vector
        total = loss_mse + prior_user + prior_item + prior_bias_user + prior_bias_item
        return total

def get_top_n(model,testset,trainset,uid_input,n=10):
    
    preds = []
    try:
        uid_input = int(trainset.to_inner_uid(uid_input))
    except KeyError:
        return preds        

    # First map the predictions to each user.
    for uid, iid, _ in testset: #inefficient
        try:
            uid_internal = int(trainset.to_inner_uid(uid))
        except KeyError:
            continue
        if uid_internal==uid_input:
            try:
                iid_internal = int(trainset.to_inner_iid(iid))
                movie_name = df.loc[int(iid),'name']
                preds.append((iid,movie_name,float(model(torch.tensor([[uid_input,iid_internal]])))))
            except KeyError:
                pass
    # Then sort the predictions for each user and retrieve the k highest ones
    if preds is not None:
        preds.sort(key=lambda x: x[1], reverse=True)
        if len(preds) > n:
            preds = preds[:n]
    return preds
#Data
df = pd.read_csv('./movies.dat',sep="::",header=None,engine='python')
df.columns = ['iid','name','genre']
df.set_index('iid',inplace=True)
print(df.head())
data = Dataset.load_builtin('ml-100k')
trainset = data.build_full_trainset()
testset = trainset.build_anti_testset()
                                   name                         genre
iid                                                                  
1                      Toy Story (1995)   Animation|Children's|Comedy
2                        Jumanji (1995)  Adventure|Children's|Fantasy
3               Grumpier Old Men (1995)                Comedy|Romance
4              Waiting to Exhale (1995)                  Comedy|Drama
5    Father of the Bride Part II (1995)                        Comedy
#Parameters
lr = 1e-2
k = 10 #latent dimension
c_bias = 1e-6
c_vector = 1e-6

model = MF(trainset.n_users, trainset.n_items, k=k, c_bias=c_bias, c_vector=c_vector)
model.load_state_dict(torch.load('./pytorch_model'))
model.eval()
MF(
  (user): Embedding(943, 10)
  (item): Embedding(1682, 10)
  (bias_user): Embedding(943, 1)
  (bias_item): Embedding(1682, 1)
)
# Print the recommended items for each user
limit = 0
for uid,_,_ in testset:
    print('\nUser:',uid)
    seen = [df.loc[int(iid),'name'] for (iid, _) in trainset.ur[int(uid)]]
    if len(seen) > 10: seen = seen[:10]
    print('\tSeen:',seen)
    print('\tRecommendations:',get_top_n(model,testset,trainset,uid,n=10))
    limit+=1
    if limit>3:
        break
User: 196
    Seen: ['Naked Gun 33 1/3: The Final Insult (1994)', 'Free Willy (1993)', 'Rob Roy (1995)', 'Die Hard: With a Vengeance (1995)', 'Hate (Haine, La) (1995)', 'Up Close and Personal (1996)', 'Brady Bunch Movie, The (1995)', 'Miami Rhapsody (1995)', 'Baton Rouge (1988)', 'Innocents, The (1961)']
    Recommendations: ['Glory (1989)', 'Losing Chase (1996)', 'Larger Than Life (1996)', 'Shadowlands (1993)', "Pharaoh's Army (1995)", 'Salut cousin! (1996)', 'Babyfever (1994)', 'High School High (1996)', 'Bread and Chocolate (Pane e cioccolata) (1973)', 'Rock, The (1996)']

User: 196
    Seen: ['Naked Gun 33 1/3: The Final Insult (1994)', 'Free Willy (1993)', 'Rob Roy (1995)', 'Die Hard: With a Vengeance (1995)', 'Hate (Haine, La) (1995)', 'Up Close and Personal (1996)', 'Brady Bunch Movie, The (1995)', 'Miami Rhapsody (1995)', 'Baton Rouge (1988)', 'Innocents, The (1961)']
    Recommendations: ['Glory (1989)', 'Losing Chase (1996)', 'Larger Than Life (1996)', 'Shadowlands (1993)', "Pharaoh's Army (1995)", 'Salut cousin! (1996)', 'Babyfever (1994)', 'High School High (1996)', 'Bread and Chocolate (Pane e cioccolata) (1973)', 'Rock, The (1996)']

User: 196
    Seen: ['Naked Gun 33 1/3: The Final Insult (1994)', 'Free Willy (1993)', 'Rob Roy (1995)', 'Die Hard: With a Vengeance (1995)', 'Hate (Haine, La) (1995)', 'Up Close and Personal (1996)', 'Brady Bunch Movie, The (1995)', 'Miami Rhapsody (1995)', 'Baton Rouge (1988)', 'Innocents, The (1961)']
    Recommendations: ['Glory (1989)', 'Losing Chase (1996)', 'Larger Than Life (1996)', 'Shadowlands (1993)', "Pharaoh's Army (1995)", 'Salut cousin! (1996)', 'Babyfever (1994)', 'High School High (1996)', 'Bread and Chocolate (Pane e cioccolata) (1973)', 'Rock, The (1996)']

User: 196
    Seen: ['Naked Gun 33 1/3: The Final Insult (1994)', 'Free Willy (1993)', 'Rob Roy (1995)', 'Die Hard: With a Vengeance (1995)', 'Hate (Haine, La) (1995)', 'Up Close and Personal (1996)', 'Brady Bunch Movie, The (1995)', 'Miami Rhapsody (1995)', 'Baton Rouge (1988)', 'Innocents, The (1961)']
    Recommendations: ['Glory (1989)', 'Losing Chase (1996)', 'Larger Than Life (1996)', 'Shadowlands (1993)', "Pharaoh's Army (1995)", 'Salut cousin! (1996)', 'Babyfever (1994)', 'High School High (1996)', 'Bread and Chocolate (Pane e cioccolata) (1973)', 'Rock, The (1996)']