예제 #1
0
    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()
예제 #2
0
    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))
예제 #3
0
    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()
예제 #4
0
    def _initialize(self, interactions, max_seq_len=-1):
        self._interactions = interactions
        self._max_user_seq_len = interactions._max_len_user_seq if max_seq_len == -1 else max_seq_len
        # self._max_item_seq_len = interactions._max_len_item_seq if max_seq_len == -1 else max_seq_len

        (self._n_users, self._n_items) = (interactions.num_users, interactions.num_items)
        print 'total users: %d, total items: %d'%(self._n_users, self._n_items)
        if self._model == 'sdm':
            self._net = SDM(n_users=self._n_users, n_items=self._n_items, embedding_size=self._embedding_size,
                                  item_seq_size=self._max_user_seq_len, n_hops=self._n_hops,
                                  nonlinear_func=self._activation_func_sdm, dropout_prob=self._dropout,
                                  gate_tying=self._gate_tying
                                  )
        elif self._model == 'sdp':
            self._net = SDP(n_users=self._n_users, n_items=self._n_items, embedding_size=self._embedding_size,
                             nonlinear_func=self._activation_func_sdp,
                             num_layers=self._n_layers_sdp,
                             dropout_prob=self._dropout)
        else:
            self._net = SDMR(n_users=self._n_users, n_items=self._n_items, embedding_size=self._embedding_size,
                             item_seq_size=self._max_user_seq_len, n_hops=self._n_hops,
                             nonlinear_func_sdm=self._args.act_func_sdm,
                             nonlinear_func_sdp=self._args.act_func_sdp,
                             nonlinear_func_sdmr=self._args.act_func_sdmr,
                             dropout_prob=self._dropout,
                             gate_tying=self._gate_tying,
                             beta=self._beta
                             )

        self._net = my_utils.gpu(self._net, self._use_cuda)
        reg = 1e-6
        if self._args.model == 'sdp': reg = self._args.reg_sdp
        elif self._args.model == 'sdm': reg = self._args.reg_sdm
        else: reg = 1e-6

        print 'setting reg to :', reg

        if self._optimizer_func is None:
            self._optimizer = optim.Adam(
                self._net.parameters(),
                weight_decay=reg,
                lr=self._lr
            )
            decay_step = self._decay_step
            decay_percent = self._decay_weight
            self._lr_schedule = StepLR(self._optimizer, step_size=decay_step, gamma=decay_percent)

        else:
            self._optimizer = self._optimizer_func(self._net.parameters())

        self._loss_func = my_losses.bpr_loss


        self._sampler.init_user_item_seqs(interactions._user_all_items, interactions.num_users, interactions.num_items)
예제 #5
0
    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
예제 #6
0
    def _initialize(self, interactions, max_seq_len=-1):
        self._interactions = interactions
        self._max_user_seq_len = interactions._max_len_user_seq if max_seq_len == -1 else max_seq_len
        # self._max_item_seq_len = interactions._max_len_item_seq if max_seq_len == -1 else max_seq_len

        (self._n_users, self._n_items,
         self._n_playlists) = (interactions.num_users, interactions.num_items,
                               interactions.num_playlists)
        print 'total users: %d, total playlists: %d, total items: %d, total training interactions: %d' % (
            self._n_users, self._n_playlists, self._n_items,
            len(interactions._user_ids))

        if self._model == 'mass':
            if self._args.data_type == 'upt':
                self._net = MASS(n_users=self._n_users,
                                 n_items=self._n_items,
                                 n_playlists=self._n_playlists,
                                 embedding_size=self._embedding_size,
                                 item_seq_size=self._max_user_seq_len,
                                 distance_type=self._distance_metric,
                                 nonlinear_func=self._activation_func,
                                 dropout_prob=self._dropout,
                                 adv=self._args.adv,
                                 eps=self._args.eps)
            elif self._args.data_type == 'pt':
                self._net = MASS(n_users=self._n_playlists,
                                 n_items=self._n_items,
                                 n_playlists=None,
                                 embedding_size=self._embedding_size,
                                 item_seq_size=self._max_user_seq_len,
                                 distance_type=self._distance_metric,
                                 nonlinear_func=self._activation_func,
                                 dropout_prob=self._dropout,
                                 adv=self._args.adv,
                                 eps=self._args.eps)
            else:
                self._net = MASS(n_users=self._n_users,
                                 n_items=self._n_items,
                                 n_playlists=None,
                                 embedding_size=self._embedding_size,
                                 item_seq_size=self._max_user_seq_len,
                                 distance_type=self._distance_metric,
                                 nonlinear_func=self._activation_func,
                                 dropout_prob=self._dropout,
                                 adv=self._args.adv,
                                 eps=self._args.eps)

        elif self._model == 'mdr':
            if self._args.data_type == 'upt':
                self._net = MDR(n_users=self._n_users,
                                n_items=self._n_items,
                                n_playlists=self._n_playlists,
                                embedding_size=self._embedding_size,
                                nonlinear_func=self._activation_func_mdr,
                                num_layers=self._n_layers_mdr,
                                dropout_prob=self._dropout,
                                adv=self._args.adv,
                                eps=self._args.eps)
            elif self._args.data_type == 'pt':
                self._net = MDR(n_users=self._n_playlists,
                                n_items=self._n_items,
                                n_playlists=None,
                                embedding_size=self._embedding_size,
                                nonlinear_func=self._activation_func_mdr,
                                num_layers=self._n_layers_mdr,
                                dropout_prob=self._dropout,
                                adv=self._args.adv,
                                eps=self._args.eps)
            else:
                self._net = MDR(n_users=self._n_users,
                                n_items=self._n_items,
                                n_playlists=None,
                                embedding_size=self._embedding_size,
                                nonlinear_func=self._activation_func_mdr,
                                num_layers=self._n_layers_mdr,
                                dropout_prob=self._dropout,
                                adv=self._args.adv,
                                eps=self._args.eps)

        else:
            mdr_model = None
            mass_model = None
            if self._args.data_type_mdr == 'upt':
                mdr_model = MDR(n_users=self._n_users,
                                n_items=self._n_items,
                                n_playlists=self._n_playlists,
                                embedding_size=self._embedding_size,
                                nonlinear_func=self._activation_func_mdr,
                                num_layers=self._n_layers_mdr,
                                dropout_prob=self._dropout,
                                adv=self._args.adv,
                                eps=self._args.eps)
            elif self._args.data_type_mdr == 'pt':
                mdr_model = MDR(n_users=self._n_playlists,
                                n_items=self._n_items,
                                n_playlists=None,
                                embedding_size=self._embedding_size,
                                nonlinear_func=self._activation_func_mdr,
                                num_layers=self._n_layers_mdr,
                                dropout_prob=self._dropout,
                                adv=self._args.adv,
                                eps=self._args.eps)
            else:
                mdr_model = MDR(n_users=self._n_users,
                                n_items=self._n_items,
                                n_playlists=None,
                                embedding_size=self._embedding_size,
                                nonlinear_func=self._activation_func_mdr,
                                num_layers=self._n_layers_mdr,
                                dropout_prob=self._dropout,
                                adv=self._args.adv,
                                eps=self._args.eps)

            if self._args.data_type_mass == 'upt':
                mass_model = MASS(n_users=self._n_users,
                                  n_items=self._n_items,
                                  n_playlists=self._n_playlists,
                                  embedding_size=self._embedding_size,
                                  item_seq_size=self._max_user_seq_len,
                                  distance_type=self._distance_metric,
                                  nonlinear_func=self._activation_func,
                                  dropout_prob=self._dropout,
                                  adv=self._args.adv,
                                  eps=self._args.eps)
            elif self._args.data_type_mass == 'pt':
                mass_model = MASS(n_users=self._n_playlists,
                                  n_items=self._n_items,
                                  n_playlists=None,
                                  embedding_size=self._embedding_size,
                                  item_seq_size=self._max_user_seq_len,
                                  distance_type=self._distance_metric,
                                  nonlinear_func=self._activation_func,
                                  dropout_prob=self._dropout,
                                  adv=self._args.adv,
                                  eps=self._args.eps)
            else:
                mass_model = MASS(n_users=self._n_users,
                                  n_items=self._n_items,
                                  n_playlists=None,
                                  embedding_size=self._embedding_size,
                                  item_seq_size=self._max_user_seq_len,
                                  distance_type=self._distance_metric,
                                  nonlinear_func=self._activation_func,
                                  dropout_prob=self._dropout,
                                  adv=self._args.adv,
                                  eps=self._args.eps)

            self._net = MASR(mdr_model=mdr_model,
                             mass_model=mass_model,
                             beta=self._args.beta)

        self._net = my_utils.gpu(self._net, self._use_cuda)

        reg = 1e-6
        if self._args.model == 'mdr': reg = self._args.reg_mdr
        elif self._args.model == 'mass': reg = self._args.reg_mass
        else: reg = 1e-6
        print 'setting reg to :', reg
        if self._optimizer_func is None:
            self._optimizer = optim.Adam(self._net.parameters(),
                                         weight_decay=reg,
                                         lr=self._lr)
            decay_step = self._decay_step
            decay_percent = self._decay_weight
            self._lr_schedule = StepLR(self._optimizer,
                                       step_size=decay_step,
                                       gamma=decay_percent)

        else:
            self._optimizer = self._optimizer_func(self._net.parameters())
        if self._loss == 'pointwise':
            self._loss_func = my_losses.pointwise_loss
        elif self._loss == 'bpr':
            self._loss_func = my_losses.bpr_loss
        elif self._loss == 'hinge':
            self._loss_func = my_losses.hinge_loss
        elif self._loss == 'bce':  #binary cross entropy
            self._loss_func = my_losses.pointwise_bceloss
        else:
            self._loss_func = my_losses.adaptive_hinge_loss

        #self._sampler.init_user_item_seqs(interactions._user_all_items, interactions.num_users, interactions.num_items)
        self._sampler.init_user_item_seqs(interactions._playlist_all_items,
                                          interactions.num_playlists,
                                          interactions.num_items)
예제 #7
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))
예제 #8
0
    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))