Example #1
0
    def perform_training(self, num_epochs=None, message=None):
        starttime = datetime.now().replace(microsecond=0)
        if num_epochs is None: num_epochs = self.ps.num_epochs

        self.logger(
            'Started Training at %s for %d epochs' % (datetime.strftime(starttime, '%Y-%m-%d_%H:%M:%S'), num_epochs))
        if message is not None: self.logger(expr_message)

        prev_lr = np.inf

        scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(self.optimizer, 'min', patience=7)
        early_stopping = EarlyStopping(patience=20)

        for epoch_num in range(1, num_epochs + 1):
            train_loss_dict = self.train()
            eval_loss_dict = self.evaluate()

            scheduler.step(eval_loss_dict['loss_total'])

            cur_lr = self.optimizer.param_groups[0]['lr']
            if cur_lr != prev_lr:
                self.logger('--- Optimizer learning rate changed from %.2e to %.2e ---' % (prev_lr, cur_lr))
                prev_lr = cur_lr
            self.epochs_completed += 1

            with torch.no_grad():
                eval_msg = CCPCM_Trainer.creat_loss_message(eval_loss_dict, expr_code=self.ps.expr_code,
                                                              epoch_num=self.epochs_completed, it=len(self.ds_val),
                                                              try_num=self.try_num, mode='evald')
                if eval_loss_dict['loss_total'] < self.best_loss_total:
                    self.ps.best_model_fname = makepath(
                        os.path.join(self.ps.work_dir, 'snapshots', 'TR%02d_E%03d.pt' % (
                            self.try_num, self.epochs_completed)), isfile=True)
                    self.logger(eval_msg + ' ** ')
                    self.best_loss_total = eval_loss_dict['loss_total']
                    torch.save(self.ccpcm_model.module.state_dict() if isinstance(self.ccpcm_model,
                                                                                     torch.nn.DataParallel) else self.ccpcm_model.state_dict(),
                               self.ps.best_model_fname)

                else:
                    self.logger(eval_msg)

                self.swriter.add_scalars('total_loss/scalars', {'train_loss_total': train_loss_dict['loss_total'],
                                                                'evald_loss_total': eval_loss_dict['loss_total'], },
                                         self.epochs_completed)

            if early_stopping(eval_loss_dict['loss_total']):
                self.logger("Early stopping")
                break

        endtime = datetime.now().replace(microsecond=0)
        self.logger(expr_message)
        self.logger('Finished Training at %s\n' % (datetime.strftime(endtime, '%Y-%m-%d_%H:%M:%S')))
        self.logger(
            'Training done in %s! Best val total loss achieved: %.2e\n' % (endtime - starttime, self.best_loss_total))
        self.logger('Best model path: %s\n' % self.ps.best_model_fname)
Example #2
0
def evaluate_error(dataset_dir,
                   ccpcm_model,
                   ccpcm_ps,
                   splitname,
                   batch_size=1):
    ccpcm_model.eval()

    n_class = 40

    ds_name = dataset_dir.split('/')[-2]

    comp_device = torch.device(
        "cuda:0" if torch.cuda.is_available() else "cpu")

    ccpcm_model = ccpcm_model.to(comp_device)

    BCELoss = torch.nn.BCELoss()

    ds = CCPCM_DS(dataset_dir=os.path.join(dataset_dir, splitname))
    print('%s dataset size: %s' % (splitname, len(ds)))
    ds = DataLoader(
        ds, batch_size=batch_size, shuffle=False,
        drop_last=False)  #batchsize for bm is fixed so drop the last one

    all_auc = {}

    loss_mean = []
    with torch.no_grad():
        for dorig in ds:
            dorig = {k: dorig[k].to(comp_device) for k in dorig.keys()}

            drec = ccpcm_model(Ditp1=dorig['Ditp1'],
                               Bit=dorig['Bit'],
                               Binf=dorig['Binf'])
            loss_mean.append(BCELoss(drec['Bit_p1'], dorig['Bit_p1']))

            y_test = c2c(dorig['Bit_p1'])
            y_score = c2c(drec['Bit_p1'])
            if splitname == 'test':
                y_test = np.int32(y_test > 0.5)
            # Compute ROC curve and ROC area for each class
            for j in range(n_class):
                fpr, tpr, _ = roc_curve(y_test[:, j], y_score[:, j])
                auc = compute_auc(fpr, tpr)
                c = all_auc.get(j, [])
                c.append(auc.mean())
                all_auc[j] = c.copy()

    valid_ids = {k: ~np.isnan(v) for k, v in all_auc.items()}
    final_results = {
        'BCE': float(c2c(torch.stack(loss_mean).mean())),
        'auc':
        {k: np.mean(np.stack(v)[valid_ids[k]])
         for k, v in all_auc.items()},
    }

    outpath = makepath(os.path.join(
        ccpcm_ps.work_dir, 'evaluations', 'ds_%s' % ds_name,
        os.path.basename(ccpcm_ps.best_model_fname).replace(
            '.pt', '_%s.json' % splitname)),
                       isfile=True)
    with open(outpath, 'w') as f:
        json.dump(final_results, f)

    return final_results
Example #3
0
# Implementation: Nima Ghorbani: nghorbani.github.io
#
# If you use this code please consider citing:
# Cross-Category Product Choice: A Scalable Deep-Learning Model (Sebastian Gabel and Artem Timoshenko)
#
#
# 2019.09.01
import pandas
import numpy as np
from ccpcm.tools.model_loader import load_ccpcm
from ccpcm.tools.omni_tools import makepath
from ccpcm.tools.omni_tools import copy2cpu as c2c
import os
import torch

B_path = makepath('../data/dataset/train/B.npz', isfile=True)
Bit = np.load(B_path)['data']
Binf = Bit.mean(1)  # product purchasing frequencies
window_size = 10
n_prod = 40

expr_code = '10'
expr_dir = os.path.join('../experiments/', expr_code)
ccpcm_model, ccpcm_ps = load_ccpcm(expr_dir)

# Test will be applied on week 50th
# Note: testset specifies discount on product 24 however, it has never been discounted before in the trainset
prediction_example = pandas.read_csv(
    "../data/dataset/prediction_example.csv")  # .sort_values(['i','j'])
promotion_schedule = pandas.read_csv(
    "../data/dataset/promotion_schedule.csv")  # .sort_values(['j'])
Example #4
0
    def __init__(self, work_dir, ps):

        from tensorboardX import SummaryWriter

        torch.manual_seed(ps.seed)

        starttime = datetime.now().replace(microsecond=0)
        ps.work_dir = makepath(work_dir, isfile=False)

        logger = log2file(makepath(os.path.join(work_dir, '%s.log' % (expr_code)), isfile=True))

        summary_logdir = os.path.join(work_dir, 'summaries')
        self.swriter = SummaryWriter(log_dir=summary_logdir)
        logger('[%s] - Started training ccpcm experiment code %s' % (expr_code, starttime))
        logger('tensorboard --logdir=%s' % summary_logdir)
        logger('Torch Version: %s\n' % torch.__version__)

        logger('Base dataset_dir is %s' % ps.dataset_dir)

        shutil.copy2(os.path.basename(sys.argv[0]), work_dir)

        use_cuda = torch.cuda.is_available()
        if use_cuda: torch.cuda.empty_cache()
        self.comp_device = torch.device("cuda:%d" % ps.cuda_id if torch.cuda.is_available() else "cpu")

        gpu_count = torch.cuda.device_count()
        logger('%d CUDAs available!' % gpu_count)

        gpu_brand = torch.cuda.get_device_name(ps.cuda_id) if use_cuda else None
        logger('Training with %s [%s]' % (self.comp_device, gpu_brand) if use_cuda else 'Training on CPU!!!')
        logger('Base dataset_dir is %s' % ps.dataset_dir)

        kwargs = {'num_workers': ps.n_workers}
        # kwargs = {'num_workers': ps.n_workers, 'pin_memory': True} if use_cuda else {'num_workers': ps.n_workers}
        ds_train = CCPCM_DS(dataset_dir=os.path.join(ps.dataset_dir, 'train'))
        self.ds_train = DataLoader(ds_train, batch_size=ps.batch_size, shuffle=True, drop_last=True, **kwargs)
        ds_val = CCPCM_DS(dataset_dir=os.path.join(ps.dataset_dir, 'vald'))
        self.ds_val = DataLoader(ds_val, batch_size=ps.batch_size, shuffle=True, drop_last=True, **kwargs)
        ds_test = CCPCM_DS(dataset_dir=os.path.join(ps.dataset_dir, 'test'))
        self.ds_test = DataLoader(ds_test, batch_size=ps.batch_size, shuffle=True, drop_last=False)

        logger('Dataset Train, Vald, Test size respectively: %.2f M, %.2f K, %.2f' %
               (len(self.ds_train.dataset) * 1e-6, len(self.ds_val.dataset) * 1e-3, len(self.ds_test.dataset)))

        self.ccpcm_model = CCPCM(window_size=ps.window_size, n_class=ps.n_class).to(self.comp_device)

        if ps.use_multigpu:
            self.ccpcm_model = nn.DataParallel(self.ccpcm_model)
            logger("Training on Multiple GPU's")

        varlist = [var[1] for var in self.ccpcm_model.named_parameters()]

        params_count = sum(p.numel() for p in varlist if p.requires_grad)
        logger('Total Trainable Parameters Count is %2.2f M.' % ((params_count) * 1e-6))

        self.optimizer = optim.Adam(varlist, lr=ps.base_lr, weight_decay=ps.reg_coef)

        self.logger = logger
        self.best_loss_total = np.inf
        self.try_num = ps.try_num
        self.epochs_completed = 0
        self.ps = ps

        if ps.best_model_fname is not None:
            self._get_model().load_state_dict(torch.load(ps.best_model_fname, map_location=self.comp_device), strict=False)
            logger('Restored model from %s' % ps.best_model_fname)

        self.BCELoss = nn.BCELoss()
Example #5
0
import os
import torch

data = pandas.read_csv(f"dataset/train.csv").sort_values(['i', 't'])

customers = data['i'].to_numpy(dtype=np.int32)
times = data['t'].to_numpy(dtype=np.int32)
prods = data['j'].to_numpy(dtype=np.int32)
prices = data['price'].to_numpy(dtype=np.float32)
advertised = data['advertised'].to_numpy(dtype=np.bool)

n_cust = data.i.max() + 1
n_prod = data.j.max() + 1
T = data.t.max() + 1

B_path = makepath('dataset/train/B.npz', isfile=True)
if not os.path.exists(B_path):
    Bit = np.zeros(
        [n_cust, T, n_prod], dtype=np.bool
    )  # customer purchasing history: customer i purchased product j at time t

    for i in tqdm(range(n_cust)):
        for t in range(T):
            for j in range(n_prod):
                Bit[i, t, j] = np.sum(prods[(customers == i)
                                            & (times == t)] == j) > 0

    np.savez(B_path, data=Bit)
else:
    Bit = np.load(B_path)['data']