Example #1
0
    def train_iterations(self):
        """Train model for the 'self.epochs' number of batches."""

        self.model.train()
        pbar = ProgressBar(target=self.epochs, width=8)
        iterator = InfiniteDataLoader(self.train_loader)
        correct = 0
        processed = 0
        for iteration in range(self.epochs):
            # Train a batch
            data, target = iterator.get_batch()
            loss = self.train_batch(data, target)

            # Update Progress Bar
            accuracy = 100 * self.train_correct / self.train_processed
            pbar.update(iteration,
                        values=[('loss', round(loss, 2)),
                                ('accuracy', round(accuracy, 2))])

            # Update training history
            self.update_training_history(loss, accuracy)

        pbar.add(1,
                 values=[('loss', round(loss, 2)),
                         ('accuracy', round(accuracy, 2))])
Example #2
0
    def train_iterations(self):
        """Train model for the 'self.epochs' number of batches."""

        self.model.train()
        pbar = ProgressBar(target=self.epochs, width=8)
        iterator = InfiniteDataLoader(self.train_loader)
        for iteration in range(self.epochs):
            # Train a batch
            loss = self.train_batch(iterator.get_batch())

            # Update Progress Bar
            pbar_values = self._get_pbar_values(loss)
            pbar.update(iteration, values=pbar_values)

            # Update training history
            self.update_training_history(loss)

        pbar.add(1, values=pbar_values)
Example #3
0
    def range_test(
        self,
        train_loader,
        iterations,
        mode='iteration',
        learner=None,
        val_loader=None,
        start_lr=None,
        end_lr=10,
        step_mode='exp',
        smooth_f=0.0,
        diverge_th=5,
    ):
        """Performs the learning rate range test.

        Args:
            train_loader (torch.utils.data.DataLoader): The training set data loader.
            iterations (int): The number of iterations/epochs over which the test occurs.
                If 'mode' is set to 'iteration' then it will correspond to the
                number of iterations else if mode is set to 'epoch' then it will correspond
                to the number of epochs.
            mode (str, optional): After which mode to update the learning rate. Can be
                either 'iteration' or 'epoch'. (default: 'iteration') 
            learner (Learner, optional): Learner object for the model. (default: None) 
            val_loader (torch.utils.data.DataLoader, optional): If None, the range test
                will only use the training metric. When given a data loader, the model is
                evaluated after each iteration on that dataset and the evaluation metric
                is used. Note that in this mode the test takes significantly longer but
                generally produces more precise results. (default: None)
            start_lr (float, optional): The starting learning rate for the range test.
                If None, uses the learning rate from the optimizer. (default: None)
            end_lr (float, optional): The maximum learning rate to test. (default: 10)
            step_mode (str, optional): One of the available learning rate policies,
                linear or exponential ('linear', 'exp'). (default: 'exp')
            smooth_f (float, optional): The metric smoothing factor within the [0, 1]
                interval. Disabled if set to 0, otherwise the metric is smoothed using
                exponential smoothing. (default: 0.0)
            diverge_th (int, optional): The test is stopped when the metric surpasses the
                threshold: diverge_th * best_metric. To disable, set it to 0. (default: 5)
        """

        # Check if correct 'mode' mode has been given
        if not mode in ['iteration', 'epoch']:
            raise ValueError(
                f'For "mode" expected one of (iteration, epoch), got {mode}')

        # Reset test results
        self.history = {'lr': [], 'metric': []}
        self.best_metric = None
        self.best_lr = None

        # Check if the optimizer is already attached to a scheduler
        self._check_for_scheduler()

        # Set the starting learning rate
        if start_lr:
            self._set_learning_rate(start_lr)

        # Initialize the proper learning rate policy
        if step_mode.lower() == 'exp':
            lr_schedule = ExponentialLR(self.optimizer, end_lr, iterations)
        elif step_mode.lower() == 'linear':
            lr_schedule = LinearLR(self.optimizer, end_lr, iterations)
        else:
            raise ValueError(f'Expected one of (exp, linear), got {step_mode}')

        if smooth_f < 0 or smooth_f >= 1:
            raise ValueError('smooth_f is outside the range [0, 1]')

        # Set accuracy metric if needed
        metrics = None
        if self.metric == 'accuracy':
            metrics = ['accuracy']

        # Get the learner object
        if not learner is None:
            self.learner = learner(train_loader,
                                   self.optimizer,
                                   self.criterion,
                                   device=self.device,
                                   val_loader=val_loader,
                                   metrics=metrics)
        else:
            self.learner = Learner(train_loader,
                                   self.optimizer,
                                   self.criterion,
                                   device=self.device,
                                   val_loader=val_loader,
                                   metrics=metrics)
        self.learner.set_model(self.model)

        train_iterator = InfiniteDataLoader(train_loader)
        pbar = ProgressBar(target=iterations, width=8)
        if mode == 'iteration':
            print(mode.title() + 's')
        for iteration in range(iterations):
            # Train model
            if mode == 'epoch':
                print(f'{mode.title()} {iteration + 1}:')
            self._train_model(mode, train_iterator)
            if val_loader:
                self.learner.validate(verbose=False)

            # Get metric value
            metric_value = self._get_metric(val_loader)

            # Update the learning rate
            lr_schedule.step()
            self.history['lr'].append(lr_schedule.get_lr()[0])

            # Track the best metric and smooth it if smooth_f is specified
            if iteration == 0:
                self.best_metric = metric_value
                self.best_lr = self.history['lr'][-1]
            else:
                if smooth_f > 0:
                    metric_value = smooth_f * metric_value + (
                        1 - smooth_f) * self.history['metric'][-1]
                if ((self.metric == 'loss' and metric_value < self.best_metric)
                        or (self.metric == 'accuracy'
                            and metric_value > self.best_metric)):
                    self.best_metric = metric_value
                    self.best_lr = self.history['lr'][-1]

            # Check if the metric has diverged; if it has, stop the test
            self.history['metric'].append(metric_value)
            metric_value = self._display_metric_value(metric_value)
            if (diverge_th > 0
                    and ((self.metric == 'loss'
                          and metric_value > self.best_metric * diverge_th) or
                         (self.metric == 'accuracy'
                          and metric_value < self.best_metric / diverge_th))):
                if mode == 'iteration':
                    pbar.update(iterations - 1,
                                values=[('lr', self.history['lr'][-1]),
                                        (self.metric.title(), metric_value)])
                print('\nStopping early, the loss has diverged.')
                break
            else:
                if mode == 'epoch':
                    lr = self.history['lr'][-1]
                    print(
                        f'Learning Rate: {lr:.4f}, {self.metric.title()}: {metric_value:.2f}\n'
                    )
                elif mode == 'iteration':
                    pbar.update(iteration,
                                values=[('lr', self.history['lr'][-1]),
                                        (self.metric.title(), metric_value)])

        metric = self._display_metric_value(self.best_metric)
        if mode == 'epoch':
            print(
                f'Learning Rate: {self.best_lr:.4f}, {self.metric.title()}: {metric:.2f}\n'
            )
        elif mode == 'iteration':
            pbar.add(1,
                     values=[('lr', self.best_lr),
                             (self.metric.title(), metric)])
        print('Learning rate search finished.')