Loading

Scene Segmentation

Solution for submission 156892

A detailed solution for submission 156892 submitted for challenge Scene Segmentation

BanKhv
In [1]:
# Pytorch 
import torch
from torch import nn
import segmentation_models_pytorch as smp
from torch.utils.data import Dataset, DataLoader

# Reading Dataset, vis and miscellaneous
from PIL import Image
import matplotlib.pyplot as plt
import os
import numpy as np
import torch.nn as nn
from natsort import natsorted
from tqdm.notebook import tqdm
import cv2

from torch.utils.data import random_split
from torch.utils.data.sampler import SubsetRandomSampler

DEBUG = False
#size  = (256, 256)
Base model resolution EfficientNetB0 224 EfficientNetB1 240 EfficientNetB2 260 EfficientNetB3 300 EfficientNetB4 380 EfficientNetB5 456 EfficientNetB6 528 EfficientNetB7 600
In [2]:
class SemanticSegmentationDataset(Dataset):
    def __init__(self, img_directory = None, label_directory = None, train = True):        

        self.img_directory   = img_directory
        self.label_directory = label_directory            

        if img_directory != None:

          if train:
            self.img_list = natsorted(os.listdir(img_directory))
          else:
            self.img_list = natsorted(os.listdir(img_directory))

        if train:
          self.label_list = natsorted(os.listdir(label_directory))

        self.train = train

        self.labels = list(range(0, 25))

    def __len__(self):
        return len(self.img_list)

    def __getitem__(self, idx):

        # Reading the image
        img = Image.open(os.path.join(self.img_directory, self.img_list[idx]))
        #img = img.resize(size)
        img = img.convert("L")

        if self.train == True:
          
          # Readiding the mak image
          mask = Image.open(os.path.join(self.label_directory, self.label_list[idx]))
          #mask = mask.resize(size)

          # mask.show()
          img = np.array(img,   dtype = np.float32)
          mask = np.array(mask, dtype = np.float32)

          # Change image channel ordering
          img = img[np.newaxis, :, :]

          # Normalizing images
          img = torch.from_numpy(img)
          img = img.float() / 255

          binary_mask = np.array([(mask == v) for v in list(self.labels)])
          binary_mask = np.stack(binary_mask, axis = -1).astype('float')

          mask_preprocessed = binary_mask.transpose(2, 0, 1)
          mask_preprocessed = torch.from_numpy(mask_preprocessed)
        
          #img = img.unsqueeze(1)

          return img, mask_preprocessed
        
        # If reading test dataset, only return image 
        else:
          
          img = np.array(img, dtype=np.float32)
          img = img[np.newaxis, :, :]
          # img = np.moveaxis(img, -1, 0)

          # Normalizing images
          img = torch.from_numpy(img)
          img = img.float() / 255          

          return img
In [3]:
from sklearn.model_selection import StratifiedKFold, KFold, GroupKFold, cross_val_score, train_test_split
from shutil import copyfile
from models.efficientdet import EfficientDet

img_directory   = "./data/train/image"
img_ind = os.listdir(img_directory)
img_ind = np.array(img_ind)

seeds    = 1
n_splits = 5

if torch.cuda.is_available():
    device = 'cuda'
else:
    device = 'cpu'
    
# using DiceLoss
loss = smp.utils.losses.DiceLoss()

# using multiple metrics to train the model
metrics = [
    smp.utils.metrics.IoU(threshold       = 0.5),
    smp.utils.metrics.Fscore(threshold    = 0.5),
    smp.utils.metrics.Accuracy(threshold  = 0.5),
    smp.utils.metrics.Recall(threshold    = 0.5),
    smp.utils.metrics.Precision(threshold = 0.5),
]

# Using Adam optimizer
#optimizer = torch.optim.Adam(params = model.parameters(), lr = 0.006)

#encoder = 'resnet50'
#encoder_weights ='imagenet'

encoder         = 'timm-efficientnet-b0'
#encoder         = 'resnet50'
#encoder         = 'resnet34'

encoder_weights = 'imagenet'
ACTIVATION      = "softmax2d"

lr = 0.0001

I = 0
#for seed in range(seeds):

#random_state   = 10
#number_epoches = 3
#0.932

#random_state   = 10
#number_epoches = 4
#0.903

#random_state = 0
#number_epoches = 5
#



#for model_name in  ["FPN", "Unet"]:
for model_name in  ["FPN"]:
    
    kf = KFold(n_splits = n_splits, shuffle = True, random_state = 5)
    #for train_index, test_index in kf.split(img_ind):
    
    if DEBUG:
        train_index, test_index = list(kf.split(img_ind))[0][1], list(kf.split(img_ind))[0][0]
        number_epoches = 20
        test_index = test_index[:200]
        print(len(train_index), len(test_index))
    else:    
        train_index, test_index = list(kf.split(img_ind))[0][0], list(kf.split(img_ind))[0][1]
        number_epoches = 25
        print(len(train_index), len(test_index))
    
    if True:
        
        !rm -rf train
        !mkdir  train
        
        !rm -rf train/image
        !mkdir  train/image
        
        !rm -rf train/segmentation
        !mkdir  train/segmentation
        
        !rm -rf valid
        !mkdir  valid

        !rm -rf valid/image
        !mkdir  valid/image
        
        !rm -rf valid/segmentation
        !mkdir  valid/segmentation
        
        X_trg, X_val = img_ind[train_index], img_ind[test_index]
        
        for i in X_trg:
            copyfile("./data/train/image/" + i,        './train/image/' + i)
            i = i.replace('jpg', 'png')
            copyfile("./data/train/segmentation/" + i, './train/segmentation/' + i)
            
        for i in X_val:
            copyfile("./data/train/image/" + i,        './valid/image/' + i)
            i = i.replace('jpg', 'png')
            copyfile("./data/train/segmentation/" + i, './valid/segmentation/' + i)
            
        # Creating the training dataset
        train_dataset = SemanticSegmentationDataset(
            img_directory   = "./train/image", 
            label_directory = "./train/segmentation"
        )
        train_loader = DataLoader(
            train_dataset, 
            batch_size  = 4, 
            num_workers = 0, 
            shuffle     = False, 
            drop_last   = True
        )
        
        # Creating the validation dataset
        valid_dataset = SemanticSegmentationDataset(
            img_directory   = "./valid/image", 
            label_directory = "./valid/segmentation"
        )
        valid_loader = DataLoader(
            valid_dataset, 
            batch_size  = 8, 
            num_workers = 0, 
            shuffle     = False, 
            drop_last   = True
        )
        
        aux_params = dict(
            pooling='avg',             # one of 'avg', 'max'
            dropout = 0.1,               # dropout ratio, default is None
            activation = 'softmax',      # activation function, default is None softmax sigmoid
            classes    = len(train_dataset.labels), # define number of output labels
        )
        
        if model_name == 'Unet':
            model = smp.Unet(
                encoder_name    = encoder, 
                encoder_weights = encoder_weights, 
                classes         = len(train_dataset.labels),
                in_channels     = 1,
                activation      = ACTIVATION,
                #aux_params      = aux_params,
            )
            model = torch.load("Unet_best_model.pth")
            
            """model = EfficientDet(
                num_classes = len(train_dataset.labels),
                network = 'efficientdet-d0',
                #batch_size = 32
            )"""
        
        elif model_name == 'FPN':
            model = smp.FPN(
                encoder_name    = encoder, 
                encoder_weights = encoder_weights, 
                classes         = len(train_dataset.labels),
                in_channels     = 1,
                activation      = ACTIVATION,
                #aux_params      = aux_params
            )
            model = torch.load("FPN-0.981.pth")
            
        optimizer = torch.optim.Adam(params = model.parameters(), lr = 0.006)
        train_epoch = smp.utils.train.TrainEpoch(
            model, 
            loss      = loss, 
            metrics   = metrics, 
            optimizer = optimizer,
            device    = device,
            verbose   = True,
        )

        valid_epoch = smp.utils.train.ValidEpoch(
            model, 
            loss      = loss, 
            metrics   = metrics, 
            #optimizer = optimizer,
            device    = device,
            verbose   = True,
        )
        
        full_name = model_name + '-' + str(I)
        print("\nStart train model : ", model_name)
        #I += 1
        
        est = 0
        max_score = 0
        for i in range(0, number_epoches):
            print('\nEpoch: {}'.format(i))
            train_logs = train_epoch.run(train_loader)
            valid_logs = valid_epoch.run(valid_loader)

            # do something (save model, change lr, etc.)
            if max_score < valid_logs['fscore']:
                max_score = valid_logs['fscore']
                torch.save(model, full_name + '.pth')
                print('Model saved!')
            else:
                est += 1

            if i == 25:
                optimizer.param_groups[0]['lr'] = 1e-5
                print('Decrease decoder learning rate to 1e-5!')
3200 800

Start train model :  FPN

Epoch: 0
train: 100%|██████████| 800/800 [10:00<00:00,  1.33it/s, dice_loss - 0.01957, iou_score - 0.9617, fscore - 0.9805, accuracy - 0.9984, recall - 0.9805, precision - 0.9805]
valid: 100%|██████████| 100/100 [01:53<00:00,  1.14s/it, dice_loss - 0.01788, iou_score - 0.9649, fscore - 0.9821, accuracy - 0.9986, recall - 0.9821, precision - 0.9821]
Model saved!

Epoch: 1
train: 100%|██████████| 800/800 [10:00<00:00,  1.33it/s, dice_loss - 0.01949, iou_score - 0.9618, fscore - 0.9805, accuracy - 0.9984, recall - 0.9805, precision - 0.9805]
valid: 100%|██████████| 100/100 [01:52<00:00,  1.13s/it, dice_loss - 0.01796, iou_score - 0.9648, fscore - 0.9821, accuracy - 0.9986, recall - 0.9821, precision - 0.9821]

Epoch: 2
train: 100%|██████████| 800/800 [10:10<00:00,  1.31it/s, dice_loss - 0.01938, iou_score - 0.962, fscore - 0.9806, accuracy - 0.9985, recall - 0.9806, precision - 0.9806] 
valid: 100%|██████████| 100/100 [01:58<00:00,  1.18s/it, dice_loss - 0.01789, iou_score - 0.9649, fscore - 0.9821, accuracy - 0.9986, recall - 0.9821, precision - 0.9821]

Epoch: 3
train: 100%|██████████| 800/800 [24:10:18<00:00, 108.77s/it, dice_loss - 0.01928, iou_score - 0.9622, fscore - 0.9807, accuracy - 0.9985, recall - 0.9807, precision - 0.9807]       
valid: 100%|██████████| 100/100 [01:55<00:00,  1.15s/it, dice_loss - 0.01784, iou_score - 0.965, fscore - 0.9822, accuracy - 0.9986, recall - 0.9822, precision - 0.9822]
Model saved!

Epoch: 4
train: 100%|██████████| 800/800 [10:09<00:00,  1.31it/s, dice_loss - 0.01954, iou_score - 0.9617, fscore - 0.9805, accuracy - 0.9984, recall - 0.9805, precision - 0.9805]
valid: 100%|██████████| 100/100 [01:53<00:00,  1.13s/it, dice_loss - 0.01909, iou_score - 0.9626, fscore - 0.9809, accuracy - 0.9985, recall - 0.9809, precision - 0.9809]

Epoch: 5
train: 100%|██████████| 800/800 [10:02<00:00,  1.33it/s, dice_loss - 0.01966, iou_score - 0.9615, fscore - 0.9804, accuracy - 0.9984, recall - 0.9804, precision - 0.9804]
valid: 100%|██████████| 100/100 [01:54<00:00,  1.14s/it, dice_loss - 0.0178, iou_score - 0.9651, fscore - 0.9822, accuracy - 0.9986, recall - 0.9822, precision - 0.9822]
Model saved!

Epoch: 6
train: 100%|██████████| 800/800 [10:04<00:00,  1.32it/s, dice_loss - 0.01908, iou_score - 0.9626, fscore - 0.9809, accuracy - 0.9985, recall - 0.9809, precision - 0.9809]
valid: 100%|██████████| 100/100 [01:52<00:00,  1.13s/it, dice_loss - 0.01772, iou_score - 0.9652, fscore - 0.9823, accuracy - 0.9986, recall - 0.9823, precision - 0.9823]
Model saved!

Epoch: 7
train: 100%|██████████| 800/800 [09:59<00:00,  1.34it/s, dice_loss - 0.0191, iou_score - 0.9626, fscore - 0.9809, accuracy - 0.9985, recall - 0.9809, precision - 0.9809] 
valid: 100%|██████████| 100/100 [01:52<00:00,  1.13s/it, dice_loss - 0.01773, iou_score - 0.9652, fscore - 0.9823, accuracy - 0.9986, recall - 0.9823, precision - 0.9823]

Epoch: 8
train: 100%|██████████| 800/800 [10:10<00:00,  1.31it/s, dice_loss - 0.01905, iou_score - 0.9627, fscore - 0.981, accuracy - 0.9985, recall - 0.981, precision - 0.981]   
valid: 100%|██████████| 100/100 [01:55<00:00,  1.15s/it, dice_loss - 0.01837, iou_score - 0.964, fscore - 0.9816, accuracy - 0.9985, recall - 0.9816, precision - 0.9816]

Epoch: 9
train: 100%|██████████| 800/800 [09:28<00:00,  1.41it/s, dice_loss - 0.01903, iou_score - 0.9627, fscore - 0.981, accuracy - 0.9985, recall - 0.981, precision - 0.981]   
valid: 100%|██████████| 100/100 [01:00<00:00,  1.65it/s, dice_loss - 0.01792, iou_score - 0.9648, fscore - 0.9821, accuracy - 0.9986, recall - 0.9821, precision - 0.9821]

Epoch: 10
train: 100%|██████████| 800/800 [06:07<00:00,  2.18it/s, dice_loss - 0.01958, iou_score - 0.9617, fscore - 0.9804, accuracy - 0.9984, recall - 0.9804, precision - 0.9804]
valid: 100%|██████████| 100/100 [01:00<00:00,  1.65it/s, dice_loss - 0.01823, iou_score - 0.9643, fscore - 0.9818, accuracy - 0.9985, recall - 0.9818, precision - 0.9818]

Epoch: 11
train: 100%|██████████| 800/800 [08:00<00:00,  1.66it/s, dice_loss - 0.01913, iou_score - 0.9625, fscore - 0.9809, accuracy - 0.9985, recall - 0.9809, precision - 0.9809]
valid: 100%|██████████| 100/100 [01:56<00:00,  1.17s/it, dice_loss - 0.01774, iou_score - 0.9652, fscore - 0.9823, accuracy - 0.9986, recall - 0.9823, precision - 0.9823]

Epoch: 12
train: 100%|██████████| 800/800 [10:09<00:00,  1.31it/s, dice_loss - 0.01884, iou_score - 0.9631, fscore - 0.9812, accuracy - 0.9985, recall - 0.9812, precision - 0.9812]
valid: 100%|██████████| 100/100 [01:55<00:00,  1.16s/it, dice_loss - 0.01755, iou_score - 0.9656, fscore - 0.9825, accuracy - 0.9986, recall - 0.9825, precision - 0.9825]
Model saved!

Epoch: 13
train: 100%|██████████| 800/800 [10:05<00:00,  1.32it/s, dice_loss - 0.01883, iou_score - 0.9631, fscore - 0.9812, accuracy - 0.9985, recall - 0.9812, precision - 0.9812]
valid: 100%|██████████| 100/100 [01:16<00:00,  1.31it/s, dice_loss - 0.01761, iou_score - 0.9654, fscore - 0.9824, accuracy - 0.9986, recall - 0.9824, precision - 0.9824]

Epoch: 14
train: 100%|██████████| 800/800 [06:07<00:00,  2.18it/s, dice_loss - 0.0188, iou_score - 0.9632, fscore - 0.9812, accuracy - 0.9985, recall - 0.9812, precision - 0.9812] 
valid: 100%|██████████| 100/100 [01:00<00:00,  1.66it/s, dice_loss - 0.01781, iou_score - 0.9651, fscore - 0.9822, accuracy - 0.9986, recall - 0.9822, precision - 0.9822]

Epoch: 15
train: 100%|██████████| 800/800 [06:08<00:00,  2.17it/s, dice_loss - 0.01884, iou_score - 0.9631, fscore - 0.9812, accuracy - 0.9985, recall - 0.9812, precision - 0.9812]
valid: 100%|██████████| 100/100 [01:00<00:00,  1.65it/s, dice_loss - 0.01767, iou_score - 0.9653, fscore - 0.9824, accuracy - 0.9986, recall - 0.9823, precision - 0.9824]

Epoch: 16
train: 100%|██████████| 800/800 [06:08<00:00,  2.17it/s, dice_loss - 0.0188, iou_score - 0.9631, fscore - 0.9812, accuracy - 0.9985, recall - 0.9812, precision - 0.9812] 
valid: 100%|██████████| 100/100 [01:00<00:00,  1.66it/s, dice_loss - 0.01761, iou_score - 0.9654, fscore - 0.9824, accuracy - 0.9986, recall - 0.9824, precision - 0.9824]

Epoch: 17
train: 100%|██████████| 800/800 [06:07<00:00,  2.18it/s, dice_loss - 0.01869, iou_score - 0.9634, fscore - 0.9813, accuracy - 0.9985, recall - 0.9813, precision - 0.9813]
valid: 100%|██████████| 100/100 [01:00<00:00,  1.65it/s, dice_loss - 0.01786, iou_score - 0.965, fscore - 0.9822, accuracy - 0.9986, recall - 0.9822, precision - 0.9822]

Epoch: 18
train: 100%|██████████| 800/800 [06:07<00:00,  2.18it/s, dice_loss - 0.01871, iou_score - 0.9633, fscore - 0.9813, accuracy - 0.9985, recall - 0.9813, precision - 0.9813]
valid: 100%|██████████| 100/100 [01:00<00:00,  1.66it/s, dice_loss - 0.01759, iou_score - 0.9655, fscore - 0.9824, accuracy - 0.9986, recall - 0.9824, precision - 0.9824]

Epoch: 19
train: 100%|██████████| 800/800 [06:07<00:00,  2.18it/s, dice_loss - 0.01869, iou_score - 0.9634, fscore - 0.9813, accuracy - 0.9985, recall - 0.9813, precision - 0.9813]
valid: 100%|██████████| 100/100 [01:00<00:00,  1.65it/s, dice_loss - 0.0176, iou_score - 0.9655, fscore - 0.9824, accuracy - 0.9986, recall - 0.9824, precision - 0.9824]

Epoch: 20
train: 100%|██████████| 800/800 [06:08<00:00,  2.17it/s, dice_loss - 0.01869, iou_score - 0.9634, fscore - 0.9813, accuracy - 0.9985, recall - 0.9813, precision - 0.9813]
valid: 100%|██████████| 100/100 [01:00<00:00,  1.66it/s, dice_loss - 0.01777, iou_score - 0.9651, fscore - 0.9822, accuracy - 0.9986, recall - 0.9822, precision - 0.9822]

Epoch: 21
train: 100%|██████████| 800/800 [06:07<00:00,  2.18it/s, dice_loss - 0.01859, iou_score - 0.9635, fscore - 0.9814, accuracy - 0.9985, recall - 0.9814, precision - 0.9814]
valid: 100%|██████████| 100/100 [01:00<00:00,  1.66it/s, dice_loss - 0.01761, iou_score - 0.9654, fscore - 0.9824, accuracy - 0.9986, recall - 0.9824, precision - 0.9824]

Epoch: 22
train: 100%|██████████| 800/800 [06:08<00:00,  2.17it/s, dice_loss - 0.01858, iou_score - 0.9636, fscore - 0.9814, accuracy - 0.9985, recall - 0.9814, precision - 0.9814]
valid: 100%|██████████| 100/100 [01:00<00:00,  1.65it/s, dice_loss - 0.01765, iou_score - 0.9654, fscore - 0.9824, accuracy - 0.9986, recall - 0.9824, precision - 0.9824]

Epoch: 23
train: 100%|██████████| 800/800 [06:08<00:00,  2.17it/s, dice_loss - 0.01858, iou_score - 0.9636, fscore - 0.9814, accuracy - 0.9985, recall - 0.9814, precision - 0.9814]
valid: 100%|██████████| 100/100 [01:00<00:00,  1.65it/s, dice_loss - 0.01752, iou_score - 0.9656, fscore - 0.9825, accuracy - 0.9986, recall - 0.9825, precision - 0.9825]
Model saved!

Epoch: 24
train: 100%|██████████| 800/800 [06:08<00:00,  2.17it/s, dice_loss - 0.0186, iou_score - 0.9635, fscore - 0.9814, accuracy - 0.9985, recall - 0.9814, precision - 0.9814] 
valid: 100%|██████████| 100/100 [01:00<00:00,  1.65it/s, dice_loss - 0.01761, iou_score - 0.9654, fscore - 0.9824, accuracy - 0.9986, recall - 0.9824, precision - 0.9824]
0.962 FPN_best_model1.pthstop
In [3]:
"""
FPN0 = torch.load("FPN-0.pth")
FPN1 = torch.load("FPN-1.pth")
FPN2 = torch.load("FPN-2.pth")
FPN3 = torch.load("FPN-3.pth")
FPN4 = torch.load("FPN-4.pth")
"""

FPN0 = torch.load("FPN-0.981.pth")
FPN1 = torch.load("FPN-0.981-2.pth")
In [4]:
# Creating the testing dataset

test_dataset = SemanticSegmentationDataset(
    img_directory = "data/test/image", 
    train = False
)

test_loader  = DataLoader(
    test_dataset, 
    batch_size = 1, 
    num_workers = 2, 
    shuffle = False, 
    drop_last = False
)
In [5]:
if torch.cuda.is_available():
    device = 'cuda'
else:
    device = 'cpu'


# Generating Model Predictions
!rm -rf segmentation
!mkdir segmentation

for n, batch in enumerate(tqdm(test_loader)):

    # Getting the predictions
    predictions0 = FPN0.predict(batch.to(device)).cpu()
    predictions1 = FPN1.predict(batch.to(device)).cpu()
  
    # Converting the predictions to right format
    prediction_mask0 = (predictions0.squeeze().cpu().numpy())   
    prediction_mask0 = np.transpose(prediction_mask0, (1, 2, 0))
    
    prediction_mask1 = (predictions1.squeeze().cpu().numpy())   
    prediction_mask1 = np.transpose(prediction_mask1, (1, 2, 0))
    
    prediction_mask = (prediction_mask0 + prediction_mask1) / 2
    
    #prediction_mask = prediction_mask1

    # Getting individual channel and combining them into single image
    prediction_mask_gray = np.zeros((prediction_mask.shape[0], prediction_mask.shape[1]))
    for ii in range(prediction_mask.shape[2]):
        prediction_mask_gray = prediction_mask_gray + ii*prediction_mask[:,:,ii].round()


    # Saving the image
    prediction_mask_gray = Image.fromarray(prediction_mask_gray.astype(np.uint8))
    prediction_mask_gray.save(os.path.join("segmentation", f"{n}.png"))
In [ ]:

In [ ]:

In [7]:
%load_ext aicrowd.magic
%aicrowd login
The aicrowd.magic extension is already loaded. To reload it, use:
  %reload_ext aicrowd.magic
Please login here: https://api.aicrowd.com/auth/w50kiGmIDxtf_3hogyts3aX42K8qgIM-sgyzRsNDBa0
API Key valid
Saved API Key successfully!
WARNING: Got more than 1 jupyter server, selecting the latest session
Invalid Jupyter Response Error: Got invalid response from Jupyter: {"message": "Forbidden", "reason": null}
In [ ]:


Comments

You must login before you can post a comment.

Execute