def __init__(self, name, split):
     self.name = name
     self.split = split
     self.path = os.path.join(settings.checkpoints, name + '-split_{}'.format(split))
     self.net = DualHypercolumnCatRefineNet(
         NoPoolDPN92Base(dpn92()),
         num_features=128,
         block_multiplier=1,
         num_features_base=[256 + 80, 512 + 192, 1024 + 528, 2048 + 640],
         classifier=lambda c: SmallDropoutRefineNetUpsampleClassifier(2*128, scale_factor=2),
     )
     self.tta = [
         tta.Pipeline([tta.Pad((13, 14, 13, 14))]),
         tta.Pipeline([tta.Pad((13, 14, 13, 14)), tta.Flip()])
     ]
Пример #2
0
    def __init__(self, name, split):
        self.name = name
        self.split = split
        self.path = os.path.join(settings.checkpoints, name + '-split_{}'.format(split))
        self.net = DualHypercolumnCatRefineNet(
            SCSENoPoolResNextBase(se_resnet152()),
            num_features=128,
            classifier=lambda c: RefineNetUpsampleClassifier(2*c, scale_factor=2),
            block=SCSERefineNetBlock
        )
        self.tta = [
            tta.Pipeline([tta.Pad((13, 14, 13, 14))]),
            tta.Pipeline([tta.Pad((13, 14, 13, 14)), tta.Flip()])
        ]

        self.test_predictions = utils.TestPredictions('ensemble-{}'.format(split)).load()
    def __init__(self, name, split):
        self.name = name
        self.split = split
        self.path = os.path.join(settings.checkpoints, name + '-split_{}'.format(split))
        self.net = DualHypercolumnCatRefineNet(
            NoPoolDPN107Base(dpn107()),
            num_features=128,
            block_multiplier=1,
            num_features_base=[376, 1152, 2432, 2048 + 640],
            classifier=lambda c: SmallDropoutRefineNetUpsampleClassifier(2 * 128, scale_factor=2),
        )
        self.tta = [
            tta.Pipeline([tta.Pad((13, 14, 13, 14))]),
            tta.Pipeline([tta.Pad((13, 14, 13, 14)), tta.Flip()])
        ]

        self.test_predictions = utils.TestPredictions('ensemble_top_6_postprocessed-split_{}'.format(split)).load()
class Model:
    def __init__(self, name, split):
        self.name = name
        self.split = split
        self.path = os.path.join(settings.checkpoints,
                                 name + '-split_{}'.format(split))
        self.net = DualHypercolumnCatRefineNet(
            SCSENoPoolResNextBase(se_resnext101_32x4d()),
            num_features=128,
            classifier=lambda c: RefineNetUpsampleClassifier(2 * c,
                                                             scale_factor=2),
            block=SCSERefineNetBlock)
        self.tta = [
            tta.Pipeline([tta.Pad((13, 14, 13, 14))]),
            tta.Pipeline([tta.Pad((13, 14, 13, 14)),
                          tta.Flip()])
        ]

        self.test_predictions = utils.TestPredictions(
            'ensemble-{}'.format(split)).load()

    def save(self):
        pathlib.Path(self.path).mkdir(parents=True, exist_ok=True)
        torch.save(self.net.state_dict(), os.path.join(self.path, 'model'))

    def load(self):
        state_dict = torch.load(os.path.join(self.path, 'model'))
        self.net.load_state_dict(state_dict)

    def update_pbar(self, masks_predictions, masks_targets, pbar,
                    average_meter, pbar_description):
        average_meter.add('iou',
                          iou(masks_predictions > 0.5, masks_targets.byte()))
        average_meter.add('mAP',
                          mAP(masks_predictions > 0.5, masks_targets.byte()))

        pbar.set_description(pbar_description + ''.join([
            ' {}:{:6.4f}'.format(k, v)
            for k, v in average_meter.get_all().items()
        ]))

        pbar.update()

    def predict_raw(self, net, images):
        tta_masks = []
        for tta in self.tta:
            masks_predictions = net(tta.transform_forward(images))
            masks_predictions = tta.transform_backward(masks_predictions)
            tta_masks.append(masks_predictions)

        tta_masks = torch.stack(tta_masks, dim=1)

        return tta_masks

    def predict(self, net, images):
        tta_masks = []
        for tta in self.tta:
            masks_predictions = net(tta.transform_forward(images))
            masks_predictions = torch.sigmoid(
                tta.transform_backward(masks_predictions))
            tta_masks.append(masks_predictions)

        tta_masks = torch.stack(tta_masks, dim=0)
        masks_predictions = torch.mean(tta_masks, dim=0)

        return masks_predictions

    def fit(self, samples_train, samples_val):
        net = DataParallel(self.net)

        optimizer = NDAdam(net.parameters(), lr=1e-4, weight_decay=1e-4)
        lr_scheduler = utils.CyclicLR(optimizer, 5, {
            0: (1e-4, 1e-6),
            100: (0.5e-4, 1e-6),
            160: (1e-5, 1e-6),
        })

        epochs = 200

        best_val_mAP = 0
        best_stats = None

        # Logs stats for each epoch and saves them as .csv at the end
        epoch_logger = utils.EpochLogger(self.name +
                                         '-split_{}'.format(self.split))

        # Training
        for e in range(epochs):
            lr_scheduler.step(e)

            stats_train = self.train(net, samples_train, optimizer, e)
            stats_val = self.validate(net, samples_val, e)

            stats = {**stats_train, **stats_val}

            epoch_logger.add_epoch(stats)
            current_mAP = stats_val['val_mAP']
            if current_mAP > best_val_mAP:
                best_val_mAP = current_mAP
                best_stats = stats
                self.save()

        # Post training
        epoch_logger.save()

        return best_stats

    def train(self, net, samples, optimizer, e):
        alpha = 2 * max(0, ((50 - e) / 50))
        criterion = losses.ELULovaszFocalWithLogitsLoss(alpha, 2 - alpha)

        transforms = generator.TransformationsGenerator([
            random.RandomFlipLr(),
            random.RandomAffine(image_size=101,
                                translation=lambda rs:
                                (rs.randint(-20, 20), rs.randint(-20, 20)),
                                scale=lambda rs: (rs.uniform(0.85, 1.15), 1),
                                **utils.transformations_options)
        ])

        samples_aux = list(
            set(samples).intersection(set(utils.get_aux_samples())))
        dataset_aux = datasets.ImageDataset(samples_aux, settings.train,
                                            transforms)

        dataset_pseudo = datasets.SemiSupervisedImageDataset(
            samples_test,
            settings.test,
            transforms,
            size=len(samples_test),
            test_predictions=self.test_predictions,
            momentum=0.0)

        dataset = datasets.ImageDataset(samples, settings.train, transforms)
        weight_train = len(dataset_pseudo) / len(dataset) * 2
        weight_aux = weight_train / 2
        weights = [weight_train] * len(dataset) + [weight_aux] * len(
            dataset_aux) + [1] * len(dataset_pseudo)
        dataloader = DataLoader(
            ConcatDataset([dataset, dataset_aux, dataset_pseudo]),
            num_workers=10,
            batch_size=16,
            sampler=WeightedRandomSampler(weights=weights, num_samples=3200))

        average_meter_train = meters.AverageMeter()

        with tqdm(total=len(dataloader), leave=False,
                  ascii=True) as pbar, torch.enable_grad():
            net.train()

            padding = tta.Pad((13, 14, 13, 14))

            for images, masks_targets in dataloader:
                masks_targets = masks_targets.to(gpu)
                masks_predictions = padding.transform_backward(
                    net(padding.transform_forward(images))).contiguous()

                loss = criterion(masks_predictions, masks_targets)
                loss.backward()
                optimizer.step()
                optimizer.zero_grad()

                average_meter_train.add('loss', loss.item())
                self.update_pbar(torch.sigmoid(masks_predictions),
                                 masks_targets, pbar, average_meter_train,
                                 'Training epoch {}'.format(e))

        train_stats = {
            'train_' + k: v
            for k, v in average_meter_train.get_all().items()
        }
        return train_stats

    def validate(self, net, samples, e):
        transforms = generator.TransformationsGenerator([])
        dataset = datasets.ImageDataset(samples, settings.train, transforms)
        dataloader = DataLoader(dataset, num_workers=10, batch_size=32)

        average_meter_val = meters.AverageMeter()

        with tqdm(total=len(dataloader), leave=True,
                  ascii=True) as pbar, torch.no_grad():
            net.eval()

            for images, masks_targets in dataloader:
                masks_targets = masks_targets.to(gpu)
                masks_predictions = self.predict(net, images)

                self.update_pbar(masks_predictions, masks_targets, pbar,
                                 average_meter_val,
                                 'Validation epoch {}'.format(e))

        val_stats = {
            'val_' + k: v
            for k, v in average_meter_val.get_all().items()
        }
        return val_stats

    def test(self, samples_test, dir_test=settings.test, predict=None):
        if predict is None:
            predict = self.predict

        net = DataParallel(self.net).cuda()

        transforms = generator.TransformationsGenerator([])

        test_dataset = datasets.ImageDataset(samples_test,
                                             dir_test,
                                             transforms,
                                             test=True)
        test_dataloader = DataLoader(test_dataset,
                                     num_workers=10,
                                     batch_size=32)

        with tqdm(total=len(test_dataloader), leave=True,
                  ascii=True) as pbar, torch.no_grad():
            net.eval()

            for images, ids in test_dataloader:
                masks_predictions = predict(net, images)

                pbar.set_description('Creating test predictions...')
                pbar.update()

                masks_predictions = masks_predictions.cpu().squeeze().numpy()

                for p, id in zip(masks_predictions, ids):
                    yield p, id
class Model:
    def __init__(self, name, split):
        self.name = name
        self.split = split
        self.path = os.path.join(settings.checkpoints, name + '-split_{}'.format(split))
        self.net = DualHypercolumnCatRefineNet(
            NoPoolDPN92Base(dpn92()),
            num_features=128,
            block_multiplier=1,
            num_features_base=[256 + 80, 512 + 192, 1024 + 528, 2048 + 640],
            classifier=lambda c: SmallDropoutRefineNetUpsampleClassifier(2*128, scale_factor=2),
        )
        self.tta = [
            tta.Pipeline([tta.Pad((13, 14, 13, 14))]),
            tta.Pipeline([tta.Pad((13, 14, 13, 14)), tta.Flip()])
        ]

    def save(self):
        pathlib.Path(self.path).mkdir(parents=True, exist_ok=True)
        torch.save(self.net.state_dict(), os.path.join(self.path, 'model'))

    def load(self):
        state_dict = torch.load(os.path.join(self.path, 'model'))
        self.net.load_state_dict(state_dict)

    def update_pbar(self, masks_predictions, masks_targets, pbar, average_meter, pbar_description):
        average_meter.add('iou', iou(masks_predictions > 0.5, masks_targets.byte()))
        average_meter.add('mAP', mAP(masks_predictions > 0.5, masks_targets.byte()))

        pbar.set_description(
            pbar_description + ''.join(
                [' {}:{:6.4f}'.format(k, v) for k, v in average_meter.get_all().items()]
            )
        )

        pbar.update()

    def predict_raw(self, net, images):
        tta_masks = []
        for tta in self.tta:
            masks_predictions = net(tta.transform_forward(images))
            masks_predictions = tta.transform_backward(masks_predictions)
            tta_masks.append(masks_predictions)

        tta_masks = torch.stack(tta_masks, dim=1)

        return tta_masks

    def predict(self, net, images):
        tta_masks = []
        for tta in self.tta:
            masks_predictions = net(tta.transform_forward(images))
            masks_predictions = torch.sigmoid(tta.transform_backward(masks_predictions))
            tta_masks.append(masks_predictions)

        tta_masks = torch.stack(tta_masks, dim=0)
        masks_predictions = torch.mean(tta_masks, dim=0)

        return masks_predictions

    def fit(self, samples_train, samples_val):
        net = DataParallel(self.net)

        epochs = 200
        optimizer = SGD(net.parameters(), lr=1e-2, weight_decay=1e-4, momentum=0.9, nesterov=True)
        lr_scheduler = utils.PolyLR(optimizer, 40, 0.9, steps={
            0: 1e-2,
            50: 0.5 * 1e-2,
            100: 0.5 * 0.5 * 1e-2,
            150: 0.5 * 0.5 * 0.5 * 1e-2,
        })

        best_val_mAP = 0
        best_stats = None

        # Logs stats for each epoch and saves them as .csv at the end
        epoch_logger = utils.EpochLogger(self.name + '-split_{}'.format(self.split))

        # Training
        for e in range(epochs):
            lr_scheduler.step(e)

            stats_train = self.train(net, samples_train, optimizer, e)
            stats_val = self.validate(net, samples_val, e)

            stats = {**stats_train, **stats_val}

            epoch_logger.add_epoch(stats)
            current_mAP = stats_val['val_mAP']
            if current_mAP > best_val_mAP:
                best_val_mAP = current_mAP
                best_stats = stats
                self.save()

        # Post training
        epoch_logger.save()

        return best_stats

    def train(self, net, samples, optimizer, e):
        alpha = 2 * max(0, ((50 - e) / 50))
        criterion = losses.ELULovaszFocalWithLogitsLoss(alpha, 2 - alpha)

        transforms = generator.TransformationsGenerator([
            random.RandomFlipLr(),
            random.RandomAffine(
                image_size=101,
                translation=lambda rs: (rs.randint(-20, 20), rs.randint(-20, 20)),
                scale=lambda rs: (rs.uniform(0.85, 1.15), 1),
                **utils.transformations_options
            )
        ])

        dataset = datasets.ImageDataset(samples, settings.train, transforms)
        dataloader = DataLoader(
            dataset,
            num_workers=10,
            batch_size=16,
            shuffle=True
        )

        average_meter_train = meters.AverageMeter()

        with tqdm(total=len(dataloader), leave=False, ascii=True) as pbar, torch.enable_grad():
            net.train()

            padding = tta.Pad((13, 14, 13, 14))

            for images, masks_targets in dataloader:
                masks_targets = masks_targets.to(gpu)
                masks_predictions = padding.transform_backward(net(padding.transform_forward(images))).contiguous()

                loss = criterion(masks_predictions, masks_targets)
                loss.backward()
                optimizer.step()
                optimizer.zero_grad()

                average_meter_train.add('loss', loss.item())
                self.update_pbar(
                    torch.sigmoid(masks_predictions),
                    masks_targets,
                    pbar,
                    average_meter_train,
                    'Training epoch {}'.format(e)
                )

        train_stats = {'train_' + k: v for k, v in average_meter_train.get_all().items()}
        return train_stats

    def validate(self, net, samples, e):
        transforms = generator.TransformationsGenerator([])
        dataset = datasets.ImageDataset(samples, settings.train, transforms)
        dataloader = DataLoader(
            dataset,
            num_workers=10,
            batch_size=16
        )

        average_meter_val = meters.AverageMeter()

        with tqdm(total=len(dataloader), leave=True, ascii=True) as pbar, torch.no_grad():
            net.eval()

            for images, masks_targets in dataloader:
                masks_targets = masks_targets.to(gpu)
                masks_predictions = self.predict(net, images)

                self.update_pbar(
                    masks_predictions,
                    masks_targets,
                    pbar,
                    average_meter_val,
                    'Validation epoch {}'.format(e)
                )

        val_stats = {'val_' + k: v for k, v in average_meter_val.get_all().items()}
        return val_stats

    def test(self, samples_test, dir_test=settings.test, predict=None):
        if predict is None:
            predict = self.predict

        net = DataParallel(self.net).cuda()

        transforms = generator.TransformationsGenerator([])

        test_dataset = datasets.ImageDataset(samples_test, dir_test, transforms, test=True)
        test_dataloader = DataLoader(
            test_dataset,
            num_workers=10,
            batch_size=32
        )

        with tqdm(total=len(test_dataloader), leave=True, ascii=True) as pbar, torch.no_grad():
            net.eval()

            for images, ids in test_dataloader:
                masks_predictions = predict(net, images)

                pbar.set_description('Creating test predictions...')
                pbar.update()

                masks_predictions = masks_predictions.cpu().squeeze().numpy()

                for p, id in zip(masks_predictions, ids):
                    yield p, id