def predict(self, user_ids, item_ids): max_seq_len = self._max_user_seq_len self._net.train(False) item_seqs = self._interactions.get_batch_seqs(user_ids, item_ids, max_seq_len=max_seq_len) item_seqs = Variable(my_utils.gpu(my_utils.numpy2tensor(item_seqs).type(torch.LongTensor), self._use_cuda), requires_grad=False) out = self._net(item_seqs, Variable(my_utils.gpu(my_utils.numpy2tensor(user_ids), self._use_cuda)), Variable(my_utils.gpu(my_utils.numpy2tensor(item_ids), self._use_cuda))) return my_utils.cpu(out).detach().data.numpy().flatten()
def _reset_transform_identity(self): self._W1.weight.data.copy_(my_utils.numpy2tensor( np.concatenate( (np.identity(self._embedding_size), -np.identity(self._embedding_size)) , axis=0).T ) ) self._W2.weight.data.copy_(my_utils.numpy2tensor( np.concatenate( (np.identity(self._embedding_size), np.identity(self._embedding_size)) , axis=0).T) )
def _make_mask(self, x): mask = np.asarray(my_utils.tensor2numpy(x.data.cpu().clone()), dtype=np.float64) # mask = my_utils.tensor2numpy(x != 0) mask[mask != gc.PADDING_IDX] = 1.0 # mask[mask <= 0] = float('inf') mask[mask <= 0] = 65535 return my_utils.gpu(Variable(my_utils.numpy2tensor(mask)).type(torch.FloatTensor), use_cuda=my_utils.is_cuda(x))
def predict(self, user_ids, item_ids, playlist_ids): max_seq_len = self._max_user_seq_len self._net.train(False) #last item id is the target item item_seqs = self._interactions.get_batch_seqs(user_ids, item_ids, playlist_ids, max_seq_len=max_seq_len, type='all') item_seqs = Variable(my_utils.gpu( my_utils.numpy2tensor(item_seqs).type(torch.LongTensor), self._use_cuda), requires_grad=False) if self._args.data_type == 'upt': out = self._net( item_seqs, Variable( my_utils.gpu(my_utils.numpy2tensor(user_ids), self._use_cuda)), Variable( my_utils.gpu(my_utils.numpy2tensor(item_ids), self._use_cuda)), Variable( my_utils.gpu(my_utils.numpy2tensor(playlist_ids), self._use_cuda)), ) elif self._args.data_type == 'ut': out = self._net( item_seqs, Variable( my_utils.gpu(my_utils.numpy2tensor(user_ids), self._use_cuda)), Variable( my_utils.gpu(my_utils.numpy2tensor(item_ids), self._use_cuda)), None) elif self._args.data_type == 'pt': out = self._net( item_seqs, Variable( my_utils.gpu(my_utils.numpy2tensor(playlist_ids), self._use_cuda)), Variable( my_utils.gpu(my_utils.numpy2tensor(item_ids), self._use_cuda)), None) else: import sys print 'not supporting data type:', self._args.data_type sys.exit(1) return my_utils.cpu(out).detach().data.numpy().flatten()
def _reset_transform_identity(self): self._W1.weight.data.copy_(my_utils.numpy2tensor ( np.concatenate( (-np.identity(self._embedding_size), np.identity(self._embedding_size) ) , axis=0 ).T # initialy, it is subtractions of target user u and target item j, u-j ) ) if self._n_playlists: self._W2.weight.data.copy_(my_utils.numpy2tensor ( np.concatenate( (-np.identity(self._embedding_size), np.identity(self._embedding_size) ) , axis=0 ).T # initialy, it is subtractions of target user u and target item j, u-j ) )
def _reset_weights(self): self._user_embeddings.weight.data.normal_(0, 1.0 / self._embedding_size) self._user_embeddings.weight.data[gc.PADDING_IDX].fill_(0) self._item_embeddings.weight.data.normal_(0, 1.0 / self._embedding_size) self._item_embeddings.weight.data[gc.PADDING_IDX].fill_(0) if self._sum_func: initializer.lecun_uniform_initialization(self._sum_func.weight) for i , fc in enumerate(self._fcs): if i == 0: fc.weight.data.copy_(my_utils.numpy2tensor( np.concatenate( (np.identity(self._embedding_size), -np.identity(self._embedding_size)) , axis=0).T # initialy, it is subtractions of target user u and target item j, u-j )) else: fc.weight.data.normal_(0, 1.0 / self._embedding_size)
def init_parameters(self): ''' init the parameters in here :return: ''' position_enc = np.array([[ pos / np.power(10000, 2 * (j // 2) / self._embedding_dim) for j in range(self._embedding_dim) ] if pos != gc.PADDING_IDX else np.zeros(self._embedding_dim) for pos in range(self._num_embeddings)]) position_enc[1:, 0::2] = np.sin(position_enc[1:, 0::2]) # dim 2i position_enc[1:, 1::2] = np.cos(position_enc[1:, 1::2]) # dim 2i+1 # return my_utils.numpy2tensor(position_enc).type(torch.FloatTensor) self.weight.data = my_utils.numpy2tensor(position_enc).type( torch.FloatTensor)
def _get_neg_pred(self, item_seqs_var, batch_user_var, batch_playlist_var, batch_negative_items, adv=False): ''' user_ids are numpy data :param user_ids: :param user_seqs: :return: ''' negative_prediction = None for i in range(batch_negative_items.shape[1]): negative_items = batch_negative_items[:, i] batch_neg_item_var = Variable( my_utils.gpu(my_utils.numpy2tensor(negative_items).type( torch.LongTensor), use_cuda=self._use_cuda)) if self._args.data_type == 'upt': tmp_negative_prediction = self._net(item_seqs_var, batch_user_var, batch_neg_item_var, batch_playlist_var, adv=adv) elif self._args.data_type == 'pt': tmp_negative_prediction = self._net(item_seqs_var, batch_playlist_var, batch_neg_item_var, adv=adv) else: #ut tmp_negative_prediction = self._net(item_seqs_var, batch_user_var, batch_neg_item_var, adv=adv) if negative_prediction is None: negative_prediction = tmp_negative_prediction else: negative_prediction = torch.max(negative_prediction, tmp_negative_prediction) return negative_prediction
def load_checkpoint(self, args): lst_models = ['sdm', 'sdp'] if args.eval: lst_models = ['sdm', 'sdp', 'dmmr'] if args.model in lst_models: best_hits = 0.0 best_ndcg = 0.0 best_saved_file = '' saved_file_pattern = '%s_%s_%s*' % (args.dataset, args.model, self._make_model_desc(args)) for filepath in glob.glob( os.path.join(args.saved_path, saved_file_pattern)): # filepath = os.path.join(args.saved_path, fname) if os.path.isfile(filepath): print("=> loading checkpoint '{}'".format(filepath)) checkpoint = torch.load(filepath) hits = float(checkpoint['best_hits']) ndcg = float(checkpoint['best_ndcg']) if hits > best_hits or (hits == best_hits and ndcg > best_ndcg): # if ndcg > best_ndcg or (ndcg == best_ndcg and hits > best_hits): best_saved_file = filepath best_hits = hits best_ndcg = ndcg if best_saved_file != '': checkpoint = torch.load(best_saved_file) self._net.load_state_dict(checkpoint['model']) self._optimizer.load_state_dict(checkpoint['optimizer']) print("=> loaded checkpoint '{}' (epoch {})".format( best_saved_file, checkpoint['epoch'])) return (best_hits, best_ndcg) else: #sdmr : Deep Metric memory Recommender #load best sdp checkpoint best_sdp_file = '' best_sdp_hits, best_sdp_ndcgs = 0, 0 sdp_files_pattern = '%s_sdp_%s*' % ( args.dataset, self._make_model_desc(args, 'sdp')) # print sdp_files_pattern for filepath in glob.glob( os.path.join(args.saved_path, sdp_files_pattern)): print filepath if os.path.isfile(filepath): print("=> loading checkpoint '{}'".format(filepath)) if args.cuda: checkpoint = torch.load(filepath) else: checkpoint = torch.load( filepath, map_location=lambda storage, loc: storage) hits = float(checkpoint['best_hits']) ndcg = float(checkpoint['best_ndcg']) if hits > best_sdp_hits or (hits == best_sdp_hits and ndcg > best_sdp_ndcgs): best_sdp_file = filepath best_sdp_hits = hits best_sdp_ndcgs = ndcg #load best sdm checkpoint best_sdm_file = '' best_sdm_hits, best_sdm_ndcgs = 0, 0 sdm_files_pattern = '%s_sdm_%s*' % ( args.dataset, self._make_model_desc(args, 'sdm')) for filepath in glob.glob( os.path.join(args.saved_path, sdm_files_pattern)): if os.path.isfile(filepath): print("=> loading checkpoint '{}'".format(filepath)) if args.cuda: checkpoint = torch.load(filepath) else: checkpoint = torch.load( filepath, map_location=lambda storage, loc: storage) hits = float(checkpoint['best_hits']) ndcg = float(checkpoint['best_ndcg']) if hits > best_sdm_hits or (hits == best_sdm_hits and ndcg > best_sdm_ndcgs): # if ndcg > best_sdm_ndcgs or (ndcg == best_sdm_ndcgs and hits > best_sdm_hits): best_sdm_file = filepath best_sdm_hits = hits best_sdm_ndcgs = ndcg #now loading best checkpoints from sdp and sdm for sdmr: if best_sdp_file != '': #load checkpoint into cpu if not using cuda if args.cuda: checkpoint = torch.load(best_sdp_file) else: checkpoint = torch.load( best_sdp_file, map_location=lambda storage, loc: storage) self._net._sdp.load_state_dict(checkpoint['model']) print("=> loaded checkpoint '{}' (epoch {})".format( best_sdp_file, checkpoint['epoch'])) # no train or re-train the sdm and sdp weights? for params in self._net._sdp.parameters(): params.requires_grad = bool(args.sdmr_retrain) if best_sdm_file != '': #load checkpoint into gpu or in cpu if not using cuda if args.cuda: checkpoint = torch.load(best_sdm_file) else: checkpoint = torch.load( best_sdm_file, map_location=lambda storage, loc: storage) self._net._sdm.load_state_dict(checkpoint['model']) print("=> loaded checkpoint '{}' (epoch {})".format( best_sdm_file, checkpoint['epoch'])) #no train the sdm and sdp? for params in self._net._sdm.parameters(): params.requires_grad = bool(args.sdmr_retrain) sum_weights = np.concatenate( ((1 - args.beta) * my_utils.tensor2numpy(self._net._sdp._sum_func.weight.data), args.beta * my_utils.tensor2numpy(self._net._sdm._sum_func.weight.data)), axis=1) sum_bias = (1-args.beta) * my_utils.tensor2numpy(self._net._sdp._sum_func.bias.data) + \ args.beta * my_utils.tensor2numpy(self._net._sdm._sum_func.bias.data) self._net._sum_func.weight.data.copy_( my_utils.numpy2tensor(sum_weights)) self._net._sum_func.bias.data.copy_( my_utils.numpy2tensor(sum_bias)) return 0, 0
def fit(self, interactions, verbose=False, topN=10, vadRatings=None, vadNegatives=None, testRatings=None, testNegatives=None, max_seq_len=100, args=None): if not self._is_initialized(): self._initialize(interactions, max_seq_len=max_seq_len) user_ids = interactions._user_ids.astype(np.int64) item_ids = interactions._item_ids.astype(np.int64) playlist_ids = interactions._playlists.astype(np.int64) # self._check_input(sequences) if verbose: best_hit = 0.0 best_ndcg = 0.0 best_epoch = 0 test_hit, test_ndcg = 0.0, 0.0 if args.load_best_chkpoint > 0: # print self._net.parameters best_hit, best_ndcg = self.load_checkpoint(args) print 'Results from best checkpoints ...' # print self._net.parameters if verbose: t1 = time.time() hits, ndcg = my_evaluator.evaluate(self, vadRatings, vadNegatives, topN) for topN in range(10, 11, 1): hits_test, ndcg_test = my_evaluator.evaluate( self, testRatings, testNegatives, topN) t2 = time.time() eval_time = t2 - t1 print( '| Eval time: %d ' '| Vad hits@%d = %.3f | Vad ndcg@%d = %.3f ' '| Test hits@%d = %.3f | Test ndcg@%d = %.3f |' % (eval_time, topN, hits, topN, ndcg, topN, hits_test, topN, ndcg_test)) if topN == 10: test_hit = hits_test test_ndcg = ndcg_test best_hit, best_ndcg = hits, ndcg topN = 10 print 'End!' if args.eval: print 'Evaluation using the saved checkpoint done!' return if self._has_params(): for epoch in range(self._n_iters): self._lr_schedule.step(epoch) self._net.train() # set training environment t1 = time.time() users, items, playlists = my_utils.shuffle( user_ids, item_ids, playlist_ids, random_state=self._random_state) users = np.asarray(users) items = np.asarray(items) playlists = np.asarray(playlists) #neg_items = self._sampler.random_neg_items(users, num_neg=args.num_neg) neg_items = self._sampler.random_neg_items( playlists, num_neg=args.num_neg) epoch_loss = 0.0 epoch_noise_loss = 0.0 t1 = time.time() total_interactions = 0 for (minibatch_idx, (batch_user, batch_item, batch_playlists, batch_neg_items)) in enumerate( my_utils.minibatch(users, items, playlists, neg_items, batch_size=self._batch_size)): total_interactions += len(batch_user) # or batch_size if args.model == 'mass' or args.model == 'masr': item_seqs = interactions.get_batch_seqs( batch_user, batch_item, batch_playlists, max_seq_len=self._max_user_seq_len, type='all') item_seqs_var = Variable(my_utils.gpu( my_utils.numpy2tensor(item_seqs).type( torch.LongTensor), self._use_cuda), requires_grad=False) else: item_seqs, item_seqs_var = None, None batch_user_var = Variable( my_utils.gpu(my_utils.numpy2tensor(batch_user).type( torch.LongTensor), use_cuda=self._use_cuda)) batch_item_var = Variable( my_utils.gpu(my_utils.numpy2tensor(batch_item).type( torch.LongTensor), use_cuda=self._use_cuda)) if args.adv: ########################### construct adversarial pertubations:################################# if args.model == 'mdr' or args.model == 'mass': if args.data_type == 'upt' or args.data_type == 'pt': batch_playlist_var = Variable( my_utils.gpu(my_utils.numpy2tensor( batch_playlists).type( torch.LongTensor), use_cuda=self._use_cuda)) else: batch_playlist_var = None if args.data_type == 'upt': positive_prediction_adv = self._net( item_seqs_var, batch_user_var, batch_item_var, batch_playlist_var, adv=True) negative_prediction_adv = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items, adv=True) elif args.data_type == 'pt': positive_prediction_adv = self._net( item_seqs_var, batch_playlist_var, batch_item_var, None, adv=True) negative_prediction_adv = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items, adv=True) elif args.data_type == 'ut': positive_prediction_adv = self._net( item_seqs_var, batch_user_var, batch_item_var, None, adv=True) negative_prediction_adv = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items, adv=True) else: import sys print 'error, donot support data_type', args.data_type, ' please select: upt, pt, or ut' sys.exit(1) loss_adv = self._loss_func(positive_prediction_adv, negative_prediction_adv) self._optimizer.zero_grad() loss_adv.backward(retain_graph=True) #update adversarial noise self._net._update_noise_params() epoch_noise_loss += my_utils.cpu(loss_adv).data.numpy() ###########################update model's params:################################# if args.model == 'mdr' or args.model == 'mass': if args.data_type == 'upt' or args.data_type == 'pt': batch_playlist_var = Variable( my_utils.gpu(my_utils.numpy2tensor( batch_playlists).type( torch.LongTensor), use_cuda=self._use_cuda)) else: batch_playlist_var = None if args.data_type == 'upt': positive_prediction_adv = self._net( item_seqs_var, batch_user_var, batch_item_var, batch_playlist_var, adv=True) negative_prediction_adv = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items, adv=True) elif args.data_type == 'pt': positive_prediction_adv = self._net( item_seqs_var, batch_playlist_var, batch_item_var, None, adv=True) negative_prediction_adv = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items, adv=True) elif args.data_type == 'ut': positive_prediction_adv = self._net( item_seqs_var, batch_user_var, batch_item_var, None, adv=True) negative_prediction_adv = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items, adv=True) else: import sys print 'error, donot support data_type', args.data_type, ' please select: upt, pt, or ut' sys.exit(1) loss_adv = self._loss_func(positive_prediction_adv, negative_prediction_adv) #normal loss if args.model == 'mdr' or args.model == 'mass': if args.data_type == 'upt' or args.data_type == 'pt': batch_playlist_var = Variable( my_utils.gpu(my_utils.numpy2tensor( batch_playlists).type( torch.LongTensor), use_cuda=self._use_cuda)) else: batch_playlist_var = None if args.data_type == 'upt': positive_prediction = self._net( item_seqs_var, batch_user_var, batch_item_var, batch_playlist_var, adv=False) negative_prediction = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items, adv=False) elif args.data_type == 'pt': positive_prediction = self._net( item_seqs_var, batch_playlist_var, batch_item_var, None, adv=False) negative_prediction = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items, adv=False) elif args.data_type == 'ut': positive_prediction = self._net(item_seqs_var, batch_user_var, batch_item_var, None, adv=False) negative_prediction = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items, adv=False) else: import sys print 'error, donot support data_type', args.data_type, ' please select: upt, pt, or ut' sys.exit(1) loss = self._loss_func(positive_prediction, negative_prediction) loss_total = loss + args.reg_noise * loss_adv epoch_loss += my_utils.cpu(loss_total).data.numpy() self._optimizer.zero_grad() # clear previous grad loss_total.backward() # clear all the grads for noises now since we are not updating the noise. self._net._clear_grad(adv=True) self._optimizer.step() pass else: #sample negative items #batch_neg_items = self.sample_neg_items(batch_user, num_negs=args.num_neg) if args.model == 'mdr' or args.model == 'mass': if args.data_type == 'upt' or args.data_type == 'pt': batch_playlist_var = Variable( my_utils.gpu(my_utils.numpy2tensor( batch_playlists).type( torch.LongTensor), use_cuda=self._use_cuda)) else: batch_playlist_var = None if args.data_type == 'upt': positive_prediction = self._net( item_seqs_var, batch_user_var, batch_item_var, batch_playlist_var) negative_prediction = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items) elif args.data_type == 'pt': positive_prediction = self._net( item_seqs_var, batch_playlist_var, batch_item_var, None) negative_prediction = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items) elif args.data_type == 'ut': positive_prediction = self._net( item_seqs_var, batch_user_var, batch_item_var, None) negative_prediction = self._get_neg_pred( item_seqs_var, batch_user_var, batch_playlist_var, batch_neg_items) else: import sys print 'error, donot support data_type', args.data_type, ' please select: upt, pt, or ut' sys.exit(1) self._optimizer.zero_grad() loss = self._loss_func(positive_prediction, negative_prediction) #regularizer = self._net._get_l2_loss() #if self._model == 'mass': loss += self._reg_mass * regularizer #elif self._model == 'mdr': loss += self._reg_mdr * regularizer #else: loss += self._reg_mdr * regularizer[0] + self._reg_mass * regularizer[1] epoch_loss += my_utils.cpu(loss).data.numpy() loss.backward() self._optimizer.step() if gc.DEBUG: # print 'W1 :', self._net._W1.weight.data # print 'W2 :', self._net._W2.weight.data # # print 'W1 grad:', self._net._W1.weight.grad.data # print 'W2 grad:', self._net._W2.weight.grad.data # print 'Loss is :', loss print 'Positive prediction:', positive_prediction print 'negative prediction:', negative_prediction if minibatch_idx >= 1: break # debug epoch_loss = epoch_loss / total_interactions epoch_noise_loss = epoch_noise_loss / total_interactions t2 = time.time() epoch_train_time = t2 - t1 if verbose: t1 = time.time() hits, ndcg = my_evaluator.evaluate(self, vadRatings, vadNegatives, topN) hits_test, ndcg_test = my_evaluator.evaluate( self, testRatings, testNegatives, topN) t2 = time.time() eval_time = t2 - t1 print( '|Epoch %d | Train time: %d | Train loss: %.3f | Train Noise loss: %.3f | Eval time: %d ' '| Vad hits@%d = %.3f | Vad ndcg@%d = %.3f ' '| Test hits@%d = %.3f | Test ndcg@%d = %.3f |' % (epoch, epoch_train_time, epoch_loss, epoch_noise_loss, eval_time, topN, hits, topN, ndcg, topN, hits_test, topN, ndcg_test)) if hits > best_hit or (hits == best_hit and ndcg > best_ndcg): # if (hits + ndcg) > (best_hit + best_ndcg): # if (ndcg > best_ndcg) or (ndcg == best_ndcg and hits > best_hit): best_hit, best_ndcg, best_epoch = hits, ndcg, epoch test_hit, test_ndcg = hits_test, ndcg_test #self.save_checkpoint(args, best_hit, best_ndcg, epoch) if args.out: self.save_checkpoint(args, hits, ndcg, epoch) # save best params else: print('|Epoch %d | Train time: %d | loss: %.3f' % (epoch, epoch_train_time, epoch_loss)) if np.isnan(epoch_loss) or epoch_loss == 0.0: raise ValueError( 'Degenerate epoch loss: {}'.format(epoch_loss)) print( 'Best result: ' '| vad hits@%d = %.3f | vad ndcg@%d = %.3f ' '| test hits@%d = %.3f | test ndcg@%d = %.3f | epoch = %d' % (topN, best_hit, topN, best_ndcg, topN, test_hit, topN, test_ndcg, best_epoch))
def fit(self, interactions, topN=10, testRatings=None, testNegatives=None, max_seq_len=5, args=None): if not self._is_initialized(): self._initialize(interactions, max_seq_len=max_seq_len) user_ids = interactions._user_ids.astype(np.int64) item_ids = interactions._item_ids.astype(np.int64) best_hit = 0.0 best_ndcg = 0.0 best_epoch = 0 test_hit, test_ndcg = 0.0, 0.0 if args.load_best_chkpoint > 0: best_hit, best_ndcg = self.load_checkpoint(args) print 'Results from best checkpoints ...' t1 = time.time() hits, ndcgs = my_evaluator.evaluate(self, testRatings, testNegatives, topN) t2 = time.time() eval_time = t2-t1 best_hit, best_ndcg = hits, ndcgs print('| Eval time: %d ' '| Test hits@%d = %.3f | Test ndcg@%d = %.3f |' % (eval_time, topN, hits, topN, ndcgs)) topN = 10 print 'End!' if args.eval: print 'Evaluation using the saved checkpoint done!' return if self._has_params(): for epoch in range(self._n_iters): self._lr_schedule.step(epoch) self._net.train() # set training environment users, items = my_utils.shuffle(user_ids, item_ids, random_state=self._random_state) users = np.asarray(users) items = np.asarray(items) neg_items = self._sampler.random_neg_items(users, num_neg=args.num_neg) # copy to GPU: user_vars = Variable(my_utils.gpu(my_utils.numpy2tensor(users).type(torch.LongTensor), use_cuda=self._use_cuda)) item_vars = Variable(my_utils.gpu(my_utils.numpy2tensor(items).type(torch.LongTensor), use_cuda=self._use_cuda)) neg_item_vars = Variable(my_utils.gpu(my_utils.numpy2tensor(neg_items).type(torch.LongTensor), use_cuda=self._use_cuda)) context_vars = None #if args.model != 'sdp': contexts = interactions.get_batch_seqs(users, items, max_seq_len=self._max_user_seq_len) context_vars = Variable(my_utils.gpu(my_utils.numpy2tensor(contexts).type(torch.LongTensor), self._use_cuda), requires_grad=False) epoch_loss = 0.0 t1 = time.time() total_interactions = 0 for (minibatch_idx, (batch_users, batch_items, batch_neg_items, batch_contexts )) in enumerate( my_utils.minibatch( user_vars, item_vars, neg_item_vars, context_vars, batch_size=self._batch_size)): total_interactions += len(batch_users) # or batch_size if args.model == 'sdp': batch_contexts = None positive_prediction = self._net(batch_contexts, batch_users, batch_items) negative_prediction = self._get_neg_pred(batch_contexts, batch_users, batch_neg_items) self._optimizer.zero_grad() loss = self._loss_func(positive_prediction, negative_prediction ) epoch_loss += my_utils.cpu(loss).data.numpy() loss.backward() self._optimizer.step() epoch_loss = epoch_loss / total_interactions t2 = time.time() epoch_train_time = t2 - t1 t1 = time.time() hits, ndcgs = my_evaluator.evaluate(self, testRatings, testNegatives, topN) t2 = time.time() eval_time = t2 - t1 print('|Epoch %d | Train time: %d | Train loss: %.3f | Eval time: %d ' '| Test hits@%d = %.3f | Test ndcg@%d = %.3f |' % (epoch, epoch_train_time, epoch_loss, eval_time, topN, hits, topN, ndcgs)) if hits > best_hit or (hits == best_hit and ndcgs >= best_ndcg): best_hit, best_ndcg, best_epoch = hits, ndcgs, epoch if args.out: self.save_checkpoint(args, hits, ndcgs, epoch) # save best params if np.isnan(epoch_loss) or epoch_loss == 0.0: raise ValueError('Degenerate epoch loss: {}' .format(epoch_loss)) print ('Best result: ' '| test hits@%d = %.3f | test ndcg@%d = %.3f | epoch = %d' % (topN, best_hit, topN, best_ndcg, best_epoch))