Esempio n. 1
0
def test_mini_batch():
    # Small input
    output = torch.FloatTensor([[0.1, 0.0], [0.1, 0.0]])
    target = torch.LongTensor([0, 0])
    assert accuracy(output, target)[0].cpu().numpy() == 100.0

    # A bit larger input
    output = torch.FloatTensor([[0.1, 0.2, 0.3, 0.4, 0.5, 0.6],
                                [0.1, 0.7, 0.3, 0.4, 0.5, 0.6],
                                [0.1, 0.2, 0.8, 0.4, 0.5, 0.6],
                                [0.1, 0.2, 0.3, 0.9, 0.5, 0.6],
                                [0.1, 0.2, 0.3, 0.4, 1.0, 0.6],
                                [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]])
    target = torch.LongTensor([5, 1, 2, 3, 4, 5])
    assert accuracy(output, target)[0].cpu().numpy() == 100.0

    # A bit larger input - with not 100%
    output = torch.FloatTensor([[0.1, 0.2, 0.3, 0.4, 0.5, 0.6],
                                [0.1, 0.7, 0.3, 0.4, 0.5, 0.6],
                                [0.1, 0.2, 0.8, 0.4, 0.5, 0.6],
                                [0.1, 0.2, 0.3, 0.9, 0.5, 0.6],
                                [0.1, 0.2, 0.3, 0.4, 1.0, 0.6],
                                [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]])
    target = torch.LongTensor([1, 1, 1, 1, 1, 1])
    np.testing.assert_almost_equal(
        accuracy(output, target)[0].cpu().numpy(), 100 / 6.0)
Esempio n. 2
0
def test_no_batch():
    # Sanity check
    output = torch.FloatTensor([0.0, 0.0]).unsqueeze(0)
    target = torch.LongTensor([0])
    assert accuracy(output, target)[0].cpu().numpy() == 0.0

    output = torch.FloatTensor([0.0, 1.0]).unsqueeze(0)
    target = torch.LongTensor([1])
    assert accuracy(output, target)[0].cpu().numpy() == 100.0

    output = torch.FloatTensor([0.2, 0.5, 0.7]).unsqueeze(0)
    target = torch.LongTensor([2])
    assert accuracy(output, target)[0].cpu().numpy() == 100.0
Esempio n. 3
0
def train_one_mini_batch(model, criterion, optimizer, input_var, target_var,
                         loss_meter, acc_meter, multi_crop, bs, ncrops):
    """
    This routing train the model passed as parameter for one mini-batch

    Parameters
    ----------
    model : torch.nn.module
        The network model being used.
    criterion : torch.nn.loss
        The loss function used to compute the loss of the model.
    optimizer : torch.optim
        The optimizer used to perform the weight update.
    input_var : torch.autograd.Variable
        The input data for the mini-batch
    target_var : torch.autograd.Variable
        The target data (labels) for the mini-batch
    loss_meter : AverageMeter
        Tracker for the overall loss
    acc_meter : AverageMeter
        Tracker for the overall accuracy
    multi_crop : bool
        Set to True if multi-crops are used.
    bs : int
        Batch size
    ncrops : int
        Number of crops.

    Returns
    -------
    acc : float
        Accuracy for this mini-batch
    loss : float
        Loss for this mini-batch
    """
    # Compute output
    output = model(input_var)

    if multi_crop:
        output = output.view(bs, ncrops, -1).mean(1)

    # Compute and record the loss
    loss = criterion(output, target_var)
    loss_meter.update(loss.data[0], len(input_var))

    # Compute and record the accuracy
    acc = accuracy(output.data, target_var.data, topk=(1, ))[0]
    acc_meter.update(acc[0], len(input_var))

    # Reset gradient
    optimizer.zero_grad()
    # Compute gradients
    loss.backward()
    # Perform a step by updating the weights
    optimizer.step()

    return acc, loss
Esempio n. 4
0
def train_one_mini_batch(model, criterion, optimizer, input_var, target_var,
                         loss_meter, acc_meter):
    """
    This routing train the model passed as parameter for one mini-batch

    Parameters
    ----------
    model : torch.nn.module
        The network model being used.
    criterion : torch.nn.loss
        The loss function used to compute the loss of the model.
    optimizer : torch.optim
        The optimizer used to perform the weight update.
    input_var : torch.autograd.Variable
        The input data for the mini-batch
    target_var : torch.autograd.Variable
        The target data (labels) for the mini-batch
    loss_meter : AverageMeter
        Tracker for the overall loss
    acc_meter : AverageMeter
        Tracker for the overall accuracy

    Returns
    -------
    acc : float
        Accuracy for this mini-batch
    loss : float
        Loss for this mini-batch
    """
    # Compute output
    output = model(input_var)

    # Compute and record the loss
    # for inception combine the two losses
    if isinstance(output, tuple):
        loss1 = criterion(output[0], target_var)
        loss2 = criterion(output[1], target_var)
        loss = loss1 + 0.4 * loss2
        output = output[0]
    else:
        loss = criterion(output, target_var)
    loss_meter.update(loss.data[0], len(input_var))
    loss_meter.update(loss.data[0], len(input_var))

    # Compute and record the accuracy
    acc = accuracy(output.data, target_var.data, topk=(1, ))[0]
    acc_meter.update(acc[0], len(input_var))

    # Reset gradient
    optimizer.zero_grad()
    # Compute gradients
    loss.backward()
    # Perform a step by updating the weights
    optimizer.step()

    return acc, loss
Esempio n. 5
0
def evaluate_one_mini_batch(model, criterion, input_var, target_var,
                            loss_meter, acc_meter):
    # Compute output
    output = model(input_var)

    # Compute and record the loss
    loss = criterion(output, target_var)
    loss_meter.update(loss.data[0], len(input_var))

    # Compute and record the accuracy
    acc1 = accuracy(output.data, target_var.data, topk=(1, ))[0]
    acc_meter.update(acc1[0], len(input_var))

    return acc1, loss
def train_one_mini_batch(model, criterion, optimizer, input_var, target_var, loss_meter, acc_meter):
    # Compute output
    output = model(input_var)

    # Compute and record the loss
    loss = criterion(output, target_var)
    loss_meter.update(loss.data[0], len(input_var))

    # Compute and record the accuracy
    acc1 = accuracy(output.data, target_var.data, topk=(1,))[0]
    acc_meter.update(acc1[0], len(input_var))

    # Reset gradient
    optimizer.zero_grad()
    # Compute gradients
    loss.backward()
    # Perform a step by updating the weights
    optimizer.step()

    return acc1, loss
Esempio n. 7
0
def _evaluate(data_loader,
              model,
              criterion,
              writer,
              epoch,
              logging_label,
              no_cuda=False,
              log_interval=10,
              **kwargs):
    """
    The evaluation routine

    Parameters
    ----------
    data_loader : torch.utils.data.DataLoader
        The dataloader of the evaluation set
    model : torch.nn.module
        The network model being used
    criterion: torch.nn.loss
        The loss function used to compute the loss of the model
    writer : tensorboardX.writer.SummaryWriter
        The tensorboard writer object. Used to log values on file for the tensorboard visualization.
    epoch : int
        Number of the epoch (for logging purposes)
    logging_label : string
        Label for logging purposes. Typically 'test' or 'valid'. Its prepended to the logging output path and messages.
    no_cuda : boolean
        Specifies whether the GPU should be used or not. A value of 'True' means the CPU will be used.
    log_interval : int
        Interval limiting the logging of mini-batches. Default value of 10.

    Returns
    -------
    top1.avg : float
        Accuracy of the model of the evaluated split
    """
    multi_run = kwargs['run'] if 'run' in kwargs else None

    # Instantiate the counters
    batch_time = AverageMeter()
    losses = AverageMeter()
    top1 = AverageMeter()
    data_time = AverageMeter()

    # Switch to evaluate mode (turn off dropout & such )
    model.eval()

    # Iterate over whole evaluation set
    end = time.time()

    # Empty lists to store the predictions and target values
    preds = []
    targets = []
    multi_run = False

    pbar = tqdm(enumerate(data_loader),
                total=len(data_loader),
                unit='batch',
                ncols=150,
                leave=False)
    for batch_idx, (input, target) in pbar:
        # todo: how to you implement sliding window accross batches

        if len(input.size()) == 5:
            multi_run = True
            # input [64, 5, 3, 299, 299]
            bs, ncrops, c, h, w = input.size()
            # input.view leaves the 3rd 4th and 5th dimension as is, but multiplies the 1st and 2nd together
            # result [320, 3, 299, 299]
            # result = input.view(-1, c, h, w) # fuse batch size and ncrops
            # result_avg = input.view(bs, -1, c, h, w).mean(1)
            input = input.view(-1, c, h, w)

            # If you are using tensor.max(1) then you get a tupel with two tensors, choose the first one
            # which is a floattensor and what you need.
            # input = result_avg[0]
        # Measure data loading time
        data_time.update(time.time() - end)

        # Moving data to GPU
        if not no_cuda:
            input = input.cuda(async=True)
            target = target.cuda(async=True)

        # Convert the input and its labels to Torch Variables
        # todo: check them out in debugger
        input_var = torch.autograd.Variable(input, volatile=True)
        target_var = torch.autograd.Variable(target, volatile=True)

        # Compute output
        output = model(input_var)

        if multi_run:
            output = output.view(bs, ncrops, -1).mean(1)

        # Compute and record the loss
        loss = criterion(output, target_var)
        losses.update(loss.data[0], input.size(0))

        # Compute and record the accuracy
        acc1 = accuracy(output.data, target, topk=(1, ))[0]
        top1.update(acc1[0], input.size(0))

        # Get the predictions
        _ = [
            preds.append(item) for item in
            [np.argmax(item) for item in output.data.cpu().numpy()]
        ]
        _ = [targets.append(item) for item in target.cpu().numpy()]

        # Add loss and accuracy to Tensorboard
        if multi_run is None:
            writer.add_scalar(logging_label + '/mb_loss', loss.data[0],
                              epoch * len(data_loader) + batch_idx)
            writer.add_scalar(logging_label + '/mb_accuracy',
                              acc1.cpu().numpy(),
                              epoch * len(data_loader) + batch_idx)
        else:
            writer.add_scalar(logging_label + '/mb_loss_{}'.format(multi_run),
                              loss.data[0],
                              epoch * len(data_loader) + batch_idx)
            writer.add_scalar(
                logging_label + '/mb_accuracy_{}'.format(multi_run),
                acc1.cpu().numpy(),
                epoch * len(data_loader) + batch_idx)

        # Measure elapsed time
        batch_time.update(time.time() - end)
        end = time.time()

        if batch_idx % log_interval == 0:
            pbar.set_description(logging_label +
                                 ' epoch [{0}][{1}/{2}]\t'.format(
                                     epoch, batch_idx, len(data_loader)))

            pbar.set_postfix(
                Time='{batch_time.avg:.3f}\t'.format(batch_time=batch_time),
                Loss='{loss.avg:.4f}\t'.format(loss=losses),
                Acc1='{top1.avg:.3f}\t'.format(top1=top1),
                Data='{data_time.avg:.3f}\t'.format(data_time=data_time))

    # Make a confusion matrix
    try:
        cm = confusion_matrix(y_true=targets, y_pred=preds)
        confusion_matrix_heatmap = make_heatmap(cm,
                                                data_loader.dataset.classes)
    except ValueError:
        logging.warning('Confusion Matrix did not work as expected')

        confusion_matrix_heatmap = np.zeros((10, 10, 3))

    # Logging the epoch-wise accuracy and confusion matrix
    if multi_run is None:
        writer.add_scalar(logging_label + '/accuracy', top1.avg, epoch)
        # ERROR: save_image_and_log_tensorboard() got an unexpected keyword argument 'image_tensore'
        # changed 'image_tensor=confusion_matrix_heattmap' to 'image=confusion_mastrix_heatmap'
        save_image_and_log_to_tensorboard(writer,
                                          tag=logging_label +
                                          '/confusion_matrix',
                                          image=confusion_matrix_heatmap,
                                          global_step=epoch)
    else:
        writer.add_scalar(logging_label + '/accuracy_{}'.format(multi_run),
                          top1.avg, epoch)
        save_image_and_log_to_tensorboard(
            writer,
            tag=logging_label + '/confusion_matrix_{}'.format(multi_run),
            image=confusion_matrix_heatmap,
            global_step=epoch)

    logging.info(
        _prettyprint_logging_label(logging_label) + ' epoch[{}]: '
        'Acc@1={top1.avg:.3f}\t'
        'Loss={loss.avg:.4f}\t'
        'Batch time={batch_time.avg:.3f} ({data_time.avg:.3f} to load data)'.
        format(epoch,
               batch_time=batch_time,
               data_time=data_time,
               loss=losses,
               top1=top1))

    # Generate a classification report for each epoch
    _log_classification_report(data_loader, epoch, preds, targets, writer)

    return top1.avg
Esempio n. 8
0
def train(train_loader,
          model,
          criterion,
          optimizer,
          writer,
          epoch,
          no_cuda=False,
          log_interval=25,
          **kwargs):
    """
    Training routine

    Parameters
    ----------
    :param train_loader : torch.utils.data.DataLoader
        The dataloader of the train set.

    :param model : torch.nn.module
        The network model being used.

    :param criterion : torch.nn.loss
        The loss function used to compute the loss of the model.

    :param optimizer : torch.optim
        The optimizer used to perform the weight update.

    :param writer : tensorboardX.writer.SummaryWriter
        The tensorboard writer object. Used to log values on file for the tensorboard visualization.

    :param epoch : int
        Number of the epoch (for logging purposes).

    :param no_cuda : boolean
        Specifies whether the GPU should be used or not. A value of 'True' means the CPU will be used.

    :param log_interval : int
        Interval limiting the logging of mini-batches. Default value of 10.

    :return:
        None
    """
    multi_run = kwargs['run'] if 'run' in kwargs else None

    # Instantiate the counters
    batch_time = AverageMeter()
    losses = AverageMeter()
    top1 = AverageMeter()
    data_time = AverageMeter()

    # Switch to train mode (turn on dropout & stuff)
    model.train()

    # Iterate over whole training set
    end = time.time()
    pbar = tqdm(enumerate(train_loader),
                total=len(train_loader),
                unit='batch',
                ncols=150,
                leave=False)
    for batch_idx, data in pbar:
        # pmu
        is_sequence = True if len(data) == 3 else False
        if is_sequence:
            in_data, length, target = sort_sequences_desc_order(data)
        else:
            in_data, target = data
        # Measure data loading time
        data_time.update(time.time() - end)

        # Moving data to GPU
        if not no_cuda:
            in_data = in_data.cuda(async=True)
            target = target.cuda(async=True)
            # pmu
            length = length.cuda(async=True) if is_sequence else None

        # pmu del
        # Convert the input and its labels to Torch Variables
        input_var = in_data  # torch.autograd.Variable(input)
        target_var = target  # torch.autograd.Variable(target)

        # Compute output
        # pmu
        if is_sequence:
            model.zero_grad()
            output = model((input_var, length))
            # output = output.view(output.size(0), 2)
            # target_var = target_var.view(output.size(0))
        else:
            output = model(input_var)

        # Compute and record the loss
        loss = criterion(output, target_var)
        losses.update(loss.item(), input_var.size(0))

        # Compute and record the accuracy
        # acc1, acc5 = accuracy(output.data, target, topk=(1, 5))
        acc1 = accuracy(output.data, target_var, topk=(1, ))[0]

        top1.update(acc1[0], input_var.size(0))
        # top5.update(acc5[0], input.size(0))

        # Add loss and accuracy to Tensorboard
        if multi_run == None:
            writer.add_scalar('train/mb_loss', loss.item(),
                              epoch * len(train_loader) + batch_idx)
            writer.add_scalar('train/mb_accuracy',
                              acc1.cpu().numpy(),
                              epoch * len(train_loader) + batch_idx)
        else:
            writer.add_scalar('train/mb_loss_{}'.format(multi_run),
                              loss.item(),
                              epoch * len(train_loader) + batch_idx)
            writer.add_scalar('train/mb_accuracy_{}'.format(multi_run),
                              acc1.cpu().numpy(),
                              epoch * len(train_loader) + batch_idx)

        # Reset gradient
        optimizer.zero_grad()
        # Compute gradients
        loss.backward()
        # Perform a step by updating the weights
        optimizer.step()

        # Measure elapsed time
        batch_time.update(time.time() - end)
        end = time.time()

        # Log to console
        if batch_idx % log_interval == 0:
            pbar.set_description('train epoch [{0}][{1}/{2}]\t'.format(
                epoch, batch_idx, len(train_loader)))

            pbar.set_postfix(
                Time='{batch_time.avg:.3f}\t'.format(batch_time=batch_time),
                Loss='{loss.avg:.4f}\t'.format(loss=losses),
                Acc1='{top1.avg:.3f}\t'.format(top1=top1),
                Data='{data_time.avg:.3f}\t'.format(data_time=data_time))
Esempio n. 9
0
def _evaluate(data_loader,
              model,
              criterion,
              observer,
              observer_criterion,
              writer,
              epoch,
              logging_label,
              no_cuda=False,
              log_interval=10,
              **kwargs):
    """
    The evaluation routine

    Parameters
    ----------
    :param data_loader : torch.utils.data.DataLoader
        The dataloader of the evaluation set

    :param model : torch.nn.module
        The network model being used

    :param criterion: torch.nn.loss
        The loss function used to compute the loss of the model

    :param writer : tensorboardX.writer.SummaryWriter
        The tensorboard writer object. Used to log values on file for the tensorboard visualization.

    :param epoch : int
        Number of the epoch (for logging purposes)

    :param logging_label : string
        Label for logging purposes. Typically 'test' or 'valid'. Its prepended to the logging output path and messages.

    :param no_cuda : boolean
        Specifies whether the GPU should be used or not. A value of 'True' means the CPU will be used.

    :param log_interval : int
        Interval limiting the logging of mini-batches. Default value of 10.

    :return:
        None
    """
    multi_run = kwargs['run'] if 'run' in kwargs else None

    # Instantiate the counters
    batch_time = AverageMeter()
    losses = AverageMeter()
    observer_loss_meter = AverageMeter()
    top1 = AverageMeter()
    observer_acc_meter = AverageMeter()
    data_time = AverageMeter()

    # Switch to evaluate mode (turn off dropout & such )
    model.eval()

    # Iterate over whole evaluation set
    end = time.time()

    # Empty lists to store the predictions and target values
    preds = []
    targets = []

    pbar = tqdm(enumerate(data_loader),
                total=len(data_loader),
                unit='batch',
                ncols=150,
                leave=False)
    for batch_idx, (input, target) in pbar:

        # Measure data loading time
        data_time.update(time.time() - end)

        # Moving data to GPU
        if not no_cuda:
            input = input.cuda(async=True)
            target = target.cuda(async=True)

        # Convert the input and its labels to Torch Variables
        input_var = torch.autograd.Variable(input, volatile=True)
        target_var = torch.autograd.Variable(target, volatile=True)

        # Compute output
        output = model(input_var)

        # Get the features from second last layer
        input_features_var = torch.autograd.Variable(
            model.module.features.data)

        # Use observer on the features
        observer_acc, observer_loss = evaluate_one_mini_batch(
            observer, observer_criterion, input_features_var, target_var,
            observer_loss_meter, observer_acc_meter)

        # Compute and record the loss
        loss = criterion(output, target_var)
        losses.update(loss.data[0], input.size(0))

        # Compute and record the accuracy
        acc1 = accuracy(output.data, target, topk=(1, ))[0]
        top1.update(acc1[0], input.size(0))

        # Get the predictions
        _ = [
            preds.append(item) for item in
            [np.argmax(item) for item in output.data.cpu().numpy()]
        ]
        _ = [targets.append(item) for item in target.cpu().numpy()]

        # Add loss and accuracy to Tensorboard
        if multi_run is None:
            writer.add_scalar(logging_label + '/mb_loss', loss.data[0],
                              epoch * len(data_loader) + batch_idx)
            writer.add_scalar(logging_label + '/mb_accuracy',
                              acc1.cpu().numpy(),
                              epoch * len(data_loader) + batch_idx)
            writer.add_scalar(logging_label + '/obs_mb_loss',
                              observer_loss.data[0],
                              epoch * len(data_loader) + batch_idx)
            writer.add_scalar(logging_label + '/obs_mb_accuracy',
                              observer_acc.cpu().numpy(),
                              epoch * len(data_loader) + batch_idx)
        else:
            writer.add_scalar(logging_label + '/mb_loss_{}'.format(multi_run),
                              loss.data[0],
                              epoch * len(data_loader) + batch_idx)
            writer.add_scalar(
                logging_label + '/mb_accuracy_{}'.format(multi_run),
                acc1.cpu().numpy(),
                epoch * len(data_loader) + batch_idx)
            writer.add_scalar(
                logging_label + '/obs_mb_loss_{}'.format(multi_run),
                observer_loss.data[0],
                epoch * len(data_loader) + batch_idx)
            writer.add_scalar(
                logging_label + '/obs_mb_accuracy_{}'.format(multi_run),
                observer_acc.cpu().numpy(),
                epoch * len(data_loader) + batch_idx)

        # Measure elapsed time
        batch_time.update(time.time() - end)
        end = time.time()

        if batch_idx % log_interval == 0:
            pbar.set_description(logging_label +
                                 ' epoch [{0}][{1}/{2}]\t'.format(
                                     epoch, batch_idx, len(data_loader)))

            pbar.set_postfix(
                Time='{batch_time.avg:.3f}\t'.format(batch_time=batch_time),
                Loss='{loss.avg:.4f}\t'.format(loss=losses),
                Acc1='{top1.avg:.3f}\t'.format(top1=top1),
                Data='{data_time.avg:.3f}\t'.format(data_time=data_time))

    # Make a confusion matrix
    try:
        cm = confusion_matrix(y_true=targets, y_pred=preds)
        confusion_matrix_heatmap = make_heatmap(cm,
                                                data_loader.dataset.classes)
    except ValueError:
        logging.warning('Confusion Matrix did not work as expected')

        confusion_matrix_heatmap = np.zeros((10, 10, 3))

    # Logging the epoch-wise accuracy and confusion matrix
    if multi_run is None:
        writer.add_scalar(logging_label + '/accuracy', top1.avg, epoch)
        writer.add_scalar(logging_label + '/obs_accuracy',
                          observer_acc_meter.avg, epoch)
        save_image_and_log_to_tensorboard(
            writer,
            tag=logging_label + '/confusion_matrix',
            image_tensor=confusion_matrix_heatmap,
            global_step=epoch)
    else:
        writer.add_scalar(logging_label + '/accuracy_{}'.format(multi_run),
                          top1.avg, epoch)
        writer.add_scalar(logging_label + '/obs_accuracy_{}'.format(multi_run),
                          observer_acc_meter.avg, epoch)
        save_image_and_log_to_tensorboard(
            writer,
            tag=logging_label + '/confusion_matrix_{}'.format(multi_run),
            image_tensor=confusion_matrix_heatmap,
            global_step=epoch)

    logging.info(
        _prettyprint_logging_label(logging_label) + ' epoch[{}]: '
        'Acc@1={top1.avg:.3f}\t'
        'Loss={loss.avg:.4f}\t'
        'Batch time={batch_time.avg:.3f} ({data_time.avg:.3f} to load data)'.
        format(epoch,
               batch_time=batch_time,
               data_time=data_time,
               loss=losses,
               top1=top1))

    # Generate a classification report for each epoch
    _log_classification_report(data_loader, epoch, preds, targets, writer)

    return top1.avg
Esempio n. 10
0
def _evaluate(data_loader,
              model,
              criterion,
              writer,
              epoch,
              logging_label,
              no_cuda=False,
              log_interval=10,
              **kwargs):
    """
    The evaluation routine

    Parameters
    ----------
    :param data_loader : torch.utils.data.DataLoader
        The dataloader of the evaluation set

    :param model : torch.nn.module
        The network model being used

    :param criterion: torch.nn.loss
        The loss function used to compute the loss of the model

    :param writer : tensorboardX.writer.SummaryWriter
        The tensorboard writer object. Used to log values on file for the tensorboard visualization.

    :param epoch : int
        Number of the epoch (for logging purposes)

    :param logging_label : string
        Label for logging purposes. Typically 'test' or 'valid'. Its prepended to the logging output path and messages.

    :param no_cuda : boolean
        Specifies whether the GPU should be used or not. A value of 'True' means the CPU will be used.

    :param log_interval : int
        Interval limiting the logging of mini-batches. Default value of 10.

    :return:
        None
    """
    multi_run = kwargs['run'] if 'run' in kwargs else None

    # Instantiate the counters
    batch_time = AverageMeter()
    losses = AverageMeter()
    top1 = AverageMeter()
    data_time = AverageMeter()

    # Switch to evaluate mode (turn off dropout & such )
    model.eval()

    # Iterate over whole evaluation set
    end = time.time()

    # Empty lists to store the predictions and target values
    preds = []
    targets = []

    pbar = tqdm(enumerate(data_loader),
                total=len(data_loader),
                unit='batch',
                ncols=150,
                leave=False)
    for batch_idx, data in pbar:
        # pmu
        is_sequence = True if len(data) == 3 else False
        if is_sequence:
            in_data, length, target = sort_sequences_desc_order(data)
        else:
            in_data, target = data

        # Measure data loading time
        data_time.update(time.time() - end)
        # Moving data to GPU
        if not no_cuda:
            in_data = in_data.cuda(async=True)
            target = target.cuda(async=True)
            # pmu
            length = length.cuda(async=True) if is_sequence else None

        # pmu
        # Convert the input and its labels to Torch Variables
        input_var = in_data  # torch.autograd.Variable(input, volatile=True)
        target_var = target  # torch.autograd.Variable(target, volatile=True)

        # Compute output
        # pmu
        if is_sequence:
            model.zero_grad()
            output = model((input_var, length))
            output = output.view(output.size(0), 2)
            target_var = target_var.view(output.size(0))
        else:
            output = model(input_var)

        # Compute and record the loss
        loss = criterion(output, target_var)
        losses.update(loss.item(), input_var.size(0))

        # Compute and record the accuracy
        acc1 = accuracy(output, target_var, topk=(1, ))[0]
        top1.update(acc1[0], target_var.size(0))

        # Get the predictions
        _ = [
            preds.append(item) for item in
            [np.argmax(item) for item in output.data.cpu().numpy()]
        ]
        _ = [targets.append(item) for item in target_var.cpu().numpy()]

        # Add loss and accuracy to Tensorboard
        if multi_run is None:
            writer.add_scalar(logging_label + '/mb_loss', loss.item(),
                              epoch * len(data_loader) + batch_idx)
            writer.add_scalar(logging_label + '/mb_accuracy',
                              acc1.cpu().numpy(),
                              epoch * len(data_loader) + batch_idx)
        else:
            writer.add_scalar(logging_label + '/mb_loss_{}'.format(multi_run),
                              loss.item(),
                              epoch * len(data_loader) + batch_idx)
            writer.add_scalar(
                logging_label + '/mb_accuracy_{}'.format(multi_run),
                acc1.cpu().numpy(),
                epoch * len(data_loader) + batch_idx)

        # Measure elapsed time
        batch_time.update(time.time() - end)
        end = time.time()

        if batch_idx % log_interval == 0:
            pbar.set_description(logging_label +
                                 ' epoch [{0}][{1}/{2}]\t'.format(
                                     epoch, batch_idx, len(data_loader)))

            pbar.set_postfix(
                Time='{batch_time.avg:.3f}\t'.format(batch_time=batch_time),
                Loss='{loss.avg:.4f}\t'.format(loss=losses),
                Acc1='{top1.avg:.3f}\t'.format(top1=top1),
                Data='{data_time.avg:.3f}\t'.format(data_time=data_time))