Beispiel #1
0
    def test(self, k=20, batch_size=50):
        """ Model evaluation

        Args:
            k (int): the length of the recommendation list
            batch_size (int): testing batch_size

        Returns:
            avg_recall: mean of the Recall@K over the session-parallel mini-batches
            avg_mrr: mean of the MRR@K over the session-parallel mini-batches
        """
        # set the gru layer into inference mode
        self.gru.eval()

        recalls = []
        mrrs = []
        hidden = self.gru.init_hidden().data

        # Start the testing loop
        loader = SessionDataLoader(df=self.df_test,
                                   hidden=hidden,
                                   session_key=self.session_key,
                                   item_key=self.item_key,
                                   time_key=self.time_key,
                                   batch_size=batch_size,
                                   training=self.gru.training,
                                   time_sort=self.time_sort)

        for input, target, hidden in loader.generate_batch():
            if self.use_cuda:
                input = input.cuda()
                target = target.cuda()
            # forward propagation
            logit, hidden = self.gru(input, target, hidden)
            # update the hidden state for the dataloader
            loader.update_hidden(hidden.data)
            # Evaluate the results
            recall, mrr = E.evaluate(logit, target, k)
            recalls.append(recall)
            mrrs.append(mrr)

        avg_recall = np.mean(recalls)
        avg_mrr = np.mean(mrrs)

        # reset the gru to a training mode
        self.gru.train()

        return avg_recall, avg_mrr
    def test(self, k=20, batch_size=50):
        '''
        Args:
            k: the length of the recommendation list
            batch_size: size of the session-parallel mini-batch to use during the testing
        Returns:
            avg_recall: mean of the Recall@K over the session-parallel mini-batches
            avg_mrr: mean of the MRR@K over the session-parallel mini-batches
        '''
        # set the gru layer into inference mode
        if self.gru.training:
            self.gru.switch_mode()

        recalls = []
        mrrs = []
        hidden = self.gru.init_hidden().data

        for input, target, hidden in G.generate_batch(
                df=self.df_test,
                batch_size=batch_size,
                hidden=hidden,
                training=False,
                time_sort=self.time_sort):
            if self.use_cuda:
                input = input.cuda()
                target = target.cuda()
            # Embed the input
            embedded = self.gru.emb(input, volatile=True)
            # forward propagation
            logit, hidden = self.gru(embedded, target, hidden)
            # Evaluate the results
            recall, mrr = E.evaluate(logit, target, k)
            recalls.append(recall)
            mrrs.append(mrr)

        avg_recall = np.mean(recalls)
        avg_mrr = np.mean(mrrs)

        # reset the gru to a training mode
        self.gru.switch_mode()

        return avg_recall, avg_mrr
Beispiel #3
0
    def run_epoch(self, dataset, k=20, training=True):
        """ Run a single training epoch """
        start_time = time.time()
        # initialize
        losses = []
        recalls = []
        mrrs = []
        optimizer = self.optimizer
        hidden = self.gru.init_hidden()
        if not training:
            self.gru.eval()
        device = self.device
        
        def reset_hidden(hidden, mask):
            """Helper function that resets hidden state when some sessions terminate"""
            if len(mask) != 0:
                hidden[:, mask, :] = 0
            
            return hidden

        # Start the training loop
        loader = SessionDataLoader(dataset, batch_size=self.batch_size)
        for input, target, mask in loader:
            input = input.to(device)
            target = target.to(device)
            # device_desktop.to(device)
            # reset the hidden states if some sessions have just terminated
            hidden = reset_hidden(hidden, mask).detach()
            # Go through the GRU layer
            logit, hidden = self.gru(input, target, hidden)
            # Output sampling
            logit_sampled = logit[:, target.view(-1)]
            # Calculate the mini-batch loss
            loss = self.loss_fn(logit_sampled)
            with torch.no_grad():
                recall, mrr = E.evaluate(logit, target, k)
            losses.append(loss.item())         
            recalls.append(recall)
            mrrs.append(mrr)
            # Gradient Clipping(Optional)
            if self.clip_grad != -1:
                for p in self.gru.parameters():
                    p.grad.data.clamp_(max=self.clip_grad)
            # Mini-batch GD
            if training:
                # Backprop
                loss.backward()
                optimizer.step()
                optimizer.zero_grad() # flush the gradient after the optimization

        results = dict()
        results['loss'] = np.mean(losses)
        results['recall'] = np.mean(recalls)
        results['mrr'] = np.mean(mrrs)
        
        end_time = time.time()
        results['time'] = (end_time - start_time) / 60
        
        if not training:
            self.gru.train()

        return results
Beispiel #4
0
    def run_epoch(self, dataset, k=20, training=True):
        """ Run a single training epoch """
        start_time = time.time()

        # initialize
        losses = []
        recalls = []
        mrrs = []
        ##增加###
        zippers = []
        ##增加###
        optimizer = self.optimizer
        hidden = self.gru.init_hidden()
        if not training:
            self.gru.eval()
        device = self.device

        def reset_hidden(hidden, mask):
            """Helper function that resets hidden state when some sessions terminate"""
            if len(mask) != 0:
                hidden[:, mask, :] = 0

            return hidden

        # Start the training loop
        loader = SessionDataLoader(dataset, batch_size=self.batch_size)
        # 一个bach一个bach的迭代,每次迭代是一个input:tensor([ 31,  26,  27,  29,  24]);一个output:tensor([ 31,  26,  28,  17,  24])
        #
        if training == True:
            n_items = len(dataset.items)
            # sampling 增加额外负样本采样
            if self.n_sample > 0:
                pop = dataset.df.groupby(
                    'ItemId').size()  # item的流行度supp,数据如下格式
                # ItemId
                # 214507331  1
                # 214507365  1
                # 将sample_alpha设置为1会导致基于流行度的采样,将其设置为0会导致均匀采样
                pop = pop[
                    dataset.itemmap[dataset.item_key].
                    values].values**self.sample_alpha  # item选择作为样本的概率为supp ^ sample_alpha
                pop = pop.cumsum() / pop.sum()
                pop[-1] = 1
                if self.sample_store:
                    generate_length = self.sample_store // self.n_sample
                    if generate_length <= 1:
                        sample_store = 0
                        print('No example store was used')
                    else:
                        neg_samples = self.generate_neg_samples(
                            n_items, pop, generate_length)
                        sample_pointer = 0
                else:
                    print('No example store was used')

        for input, target, mask in loader:
            input = input.to(device)
            target = target.to(device)
            # print(input)
            # print(target)
            #额外的 SAMPLING THE OUTPUT
            if self.n_sample > 0 and training:
                if self.sample_store:
                    if sample_pointer == generate_length:
                        neg_samples = self.generate_neg_samples(
                            n_items, pop, generate_length)
                        sample_pointer = 0
                    sample = neg_samples[sample_pointer]
                    sample_pointer += 1
                else:
                    sample = self.generate_neg_samples(pop, 1)
                y = torch.LongTensor(np.hstack([target, sample]))
            else:
                y = target  #不增加额外采样
            # reset the hidden states if some sessions have just terminated
            hidden = reset_hidden(hidden, mask).detach()
            # Go through the GRU layer
            logit, hidden = self.gru(input, target, hidden)
            # Output sampling   #理解,很重要!!!!!!!
            y = y.to(device)
            logit_sampled = logit[:, y]
            # Calculate the mini-batch loss
            loss = self.loss_fn(logit_sampled)
            with torch.no_grad():
                recall, mrr = E.evaluate(logit, target, k)
            losses.append(loss.item())
            recalls.append(recall)
            mrrs.append(mrr)
            # Gradient Clipping(Optional)
            if self.clip_grad != -1:
                for p in self.gru.parameters():
                    p.grad.data.clamp_(max=self.clip_grad)
            # Mini-batch GD
            if training:
                # Backprop
                loss.backward()
                optimizer.step()
                optimizer.zero_grad(
                )  # flush the gradient after the optimization

        results = dict()
        results['loss'] = np.mean(losses)
        results['recall'] = np.mean(recalls)
        results['mrr'] = np.mean(mrrs)

        end_time = time.time()
        results['time'] = (end_time - start_time) / 60

        if not training:
            self.gru.train()

        return results
Beispiel #5
0
import argparse

from modules.train import train
from modules.evaluate import evaluate

parser = argparse.ArgumentParser()
parser.add_argument("--train",
                    help="trains model on provided environment",
                    action='store_true')
parser.add_argument("--evaluate",
                    help="runs model on provided environment",
                    type=int)
args = parser.parse_args()

if __name__ == "__main__":
    if args.train:
        train()
    if args.evaluate and args.evaluate > 1:
        evaluate(args.evaluate)
Beispiel #6
0
    def test(self, df_train, df_test, session_key, time_key, item_key,
             k=20, batch_size=50):
        """ Model evaluation

        Args:
            df_train (pd.DataFrame): training set required to retrieve the training item indices.
            df_test (pd.DataFrame): test set
            session_key (str): session ID
            time_key (str): time ID
            item_key (str): item ID
            k (int): the length of the recommendation list
            batch_size (int): testing batch_size

        Returns:
            avg_recall: mean of the Recall@K over the session-parallel mini-batches
            avg_mrr: mean of the MRR@K over the session-parallel mini-batches
        """
        # set the gru layer into inference mode
        if self.gru.training:
            self.gru.switch_mode()

        recalls = []
        mrrs = []

        # initializations
        # Build item2idx from train data.
        iids = df_train[item_key].unique() # unique item ids
        item2idx = pd.Series(data=np.arange(len(iids)), index=iids)
        df_test = pd.merge(df_test,
                           pd.DataFrame({item_key: iids,
                                         'item_idx': item2idx[iids].values}),
                           on=item_key,
                           how='inner')
        # Sort the df by time, and then by session ID.
        df_test.sort_values([session_key, time_key], inplace=True)
        # Return the offsets of the beginning clicks of each session IDs
        click_offsets = GRU4REC.get_click_offsets(df_test, session_key)
        session_idx_arr = GRU4REC.order_session_idx(df_test, session_key, time_key, time_sort=self.time_sort)

        iters = np.arange(batch_size)
        maxiter = iters.max()
        start = click_offsets[session_idx_arr[iters]]
        end = click_offsets[session_idx_arr[iters]+1]
        hidden = self.gru.init_hidden().data

        # Start the training loop
        finished = False
        while not finished:
            minlen = (end-start).min()
            # Item indices(for embedding) for clicks where the first sessions start
            idx_target = df_test.item_idx.values[start]
            for i in range(minlen - 1):
                # Build inputs, targets, and hidden states
                idx_input = idx_target
                idx_target = df_test.item_idx.values[start + i + 1]
                input = torch.LongTensor(idx_input) #(B) At first, input is a Tensor
                target = Variable(torch.LongTensor(idx_target), volatile=True)  # (B)
                if self.use_cuda:
                    input = input.cuda()
                    target = target.cuda()

                logit, hidden = self.predict(input, target, hidden)
                recall, mrr = evaluate(logit, target, k)
                recalls.append(recall)
                mrrs.append(mrr)

                # Detach the hidden state for later reuse
                hidden = hidden.data

            # click indices where a particular session meets second-to-last element
            start = start + (minlen - 1)
            # see if how many sessions should terminate
            mask = np.arange(len(iters))[(end-start)<=1]
            for idx in mask:
                maxiter += 1
                if maxiter >= len(click_offsets)-1:
                    finished = True
                    break
                # update the next starting/ending point
                iters[idx] = maxiter
                start[idx] = click_offsets[session_idx_arr[maxiter]]
                end[idx] = click_offsets[session_idx_arr[maxiter]+1]

            # reset the rnn hidden state to zero after transition
            if len(mask)!= 0:
                hidden[:,mask,:] = 0

        avg_recall = np.mean(recalls)
        avg_mrr = np.mean(mrrs)

        # reset the gru to a training mode
        self.gru.switch_mode()

        return avg_recall, avg_mrr
Beispiel #7
0
    def run_epoch(self,
                  dataset,
                  k=20,
                  training=True,
                  compression_scheduler=None,
                  epoch=0):
        """ Run a single training epoch """
        start_time = time.time()

        # initialize
        losses = []
        recalls = []
        mrrs = []
        optimizer = self.optimizer
        hidden = self.gru.init_hidden()
        if not training:
            self.gru.eval()
        device = self.device

        def reset_hidden(hidden, mask):
            """Helper function that resets hidden state when some sessions terminate"""
            if len(mask) != 0:
                hidden[:, mask, :] = 0

            return hidden

        # Start the training loop
        loader = SessionDataLoader(dataset, batch_size=self.batch_size)
        batch_id = 0
        steps_per_epoch = math.ceil(len(dataset.items) / self.batch_size)

        for input, target, mask in loader:
            batch_id = batch_id + 1
            input = input.to(device)
            target = target.to(device)
            # reset the hidden states if some sessions have just terminated
            hidden = reset_hidden(hidden, mask).detach()
            if compression_scheduler:
                compression_scheduler.on_minibatch_begin(
                    epoch,
                    minibatch_id=batch_id,
                    minibatches_per_epoch=steps_per_epoch)
            # Go through the GRU layer
            logit, hidden = self.gru(input, target, hidden)
            # Output sampling
            logit_sampled = logit[:, target.view(-1)]
            # Calculate the mini-batch loss
            loss = self.loss_fn(logit_sampled)
            with torch.no_grad():
                recall, mrr = E.evaluate(logit, target, k)
            losses.append(loss.item())
            recalls.append(recall)
            mrrs.append(mrr)
            # Gradient Clipping(Optional)
            if self.clip_grad != -1:
                for p in self.gru.parameters():
                    p.grad.data.clamp_(max=self.clip_grad)
            # Mini-batch GD
            if training:
                if compression_scheduler:
                    # Before running the backward phase, we allow the scheduler to modify the loss
                    # (e.g. add regularization loss)
                    loss = compression_scheduler.before_backward_pass(
                        epoch,
                        minibatch_id=batch_id,
                        minibatches_per_epoch=steps_per_epoch,
                        loss=loss,
                        return_loss_components=False)
                # Backprop
                loss.backward()
                optimizer.step()
                optimizer.zero_grad(
                )  # flush the gradient after the optimization
            if compression_scheduler:
                compression_scheduler.on_minibatch_end(
                    epoch,
                    minibatch_id=batch_id,
                    minibatches_per_epoch=steps_per_epoch)

        results = dict()
        #ipdb.set_trace()
        results['loss'] = np.mean(losses)
        results['recall'] = np.mean(recalls)
        results['mrr'] = np.mean(mrrs)

        end_time = time.time()
        results['time'] = (end_time - start_time) / 60

        if not training:
            self.gru.train()

        return results