Source code for elliot.recommender.latent_factor_models.BPRSlim.bprslim_model

"""
Module description:

"""

__version__ = '0.3.1'
__author__ = 'Felice Antonio Merra, Vito Walter Anelli, Claudio Pomo'
__email__ = 'felice.merra@poliba.it, vitowalter.anelli@poliba.it, claudio.pomo@poliba.it'

import pickle

import numpy as np


[docs]class BPRSlimModel(object): def __init__(self, data, num_users, num_items, lr, lj_reg, li_reg, sampler, random_seed=42): self._data = data self._num_users = num_users self._num_items = num_items self._sp_i_train_ratings = self._data.sp_i_train_ratings self._lr = lr self._lj_reg = lj_reg self._li_reg = li_reg self._sampler = sampler self._random_seed = random_seed self._random_state = np.random.RandomState(self._random_seed) self._mask_indices = np.array(self._sp_i_train_ratings.indices, dtype=np.int32) self._mask_indptr = np.array(self._sp_i_train_ratings.indptr, dtype=np.int32) self._s_dense = np.empty((self._num_items, self._num_items), np.double)
[docs] def train_step(self, batch): u, i, j = batch x_uij = 0.0 # The difference is computed on the user_seen items index = 0 seen_items_start_pos = self._mask_indptr[u] seen_items_end_pos = self._mask_indptr[u + 1] while index < seen_items_end_pos - seen_items_start_pos: seenItem = self._mask_indices[seen_items_start_pos + index] index += 1 x_uij += self._s_dense[i, seenItem] - self._s_dense[j, seenItem] gradient = 1 / (1 + np.exp(x_uij)) loss = np.sum(x_uij) ** 2 index = 0 while index < seen_items_end_pos - seen_items_start_pos: seenItem = self._mask_indices[seen_items_start_pos + index] index += 1 if seenItem != i: self._s_dense[i, seenItem] += self._lr * (gradient - self._li_reg * self._s_dense[i, seenItem]) if seenItem != j: self._s_dense[j, seenItem] -= self._lr * (gradient - self._lj_reg * self._s_dense[j, seenItem]) return loss
[docs] def predict(self, u, i): x_ui = 0.0 # The difference is computed on the user_seen items index = 0 seen_items_start_pos = self._mask_indptr[u] seen_items_end_pos = self._mask_indptr[u + 1] while index < seen_items_end_pos - seen_items_start_pos: seenItem = self._mask_indices[seen_items_start_pos + index] index += 1 x_ui += self._s_dense[i, seenItem] return x_ui
[docs] def get_user_recs(self, user, mask, k=100): user_mask = mask[self._data.public_users[user]] predictions = {i: self.predict(user, i) for i in self._data.items if user_mask[self._data.public_items[i]]} indices, values = zip(*predictions.items()) indices = np.array(indices) values = np.array(values) local_k = min(k, len(values)) partially_ordered_preds_indices = np.argpartition(values, -local_k)[-local_k:] real_values = values[partially_ordered_preds_indices] real_indices = indices[partially_ordered_preds_indices] local_top_k = real_values.argsort()[::-1] return [(real_indices[item], real_values[item]) for item in local_top_k]
[docs] def get_model_state(self): saving_dict = {} saving_dict['_s_dense'] = self._s_dense return saving_dict
[docs] def set_model_state(self, saving_dict): self._s_dense = saving_dict['_s_dense']
[docs] def load_weights(self, path): with open(path, "rb") as f: self.set_model_state(pickle.load(f))
[docs] def save_weights(self, path): with open(path, "wb") as f: pickle.dump(self.get_model_state(), f)