{"cells":[{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport math\n\nimport cv2 as cv\nfrom PIL import Image\n\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nfrom sklearn.model_selection import train_test_split\n\nimport torch.nn as nn\nfrom torchvision import models\nimport torch.nn.functional as F\n\nfrom torch.optim.optimizer import Optimizer, required\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau\nfrom tqdm.auto import tqdm as tq\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"path = \"../input/understanding_cloud_organization/\"\nshape = (1400, 2100)\nresized = (350, 525)\nresized_inv = (525, 350)\ntrain_on_gpu = torch.cuda.is_available()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Format original dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"def prepare_dataset(df) :\n    # Extract masks\n    fish = df[df['Image_Label'].str.contains('Fish')].EncodedPixels.to_numpy()\n    flower = df[df['Image_Label'].str.contains('Flower')].EncodedPixels.to_numpy()\n    gravel = df[df['Image_Label'].str.contains('Gravel')].EncodedPixels.to_numpy()\n    sugar = df[df['Image_Label'].str.contains('Sugar')].EncodedPixels.to_numpy()\n    \n    # Extract files name\n    df.Image_Label = df.Image_Label.str.replace('_Fish', '')\n    df.Image_Label = df.Image_Label.str.replace('_Flower', '')\n    df.Image_Label = df.Image_Label.str.replace('_Gravel', '')\n    df.Image_Label = df.Image_Label.str.replace('_Sugar', '')\n    images = df.Image_Label.unique()\n    \n    \n    fish = np.reshape(fish, (fish.shape[0],1))\n    flower = np.reshape(flower, (flower.shape[0],1))\n    gravel = np.reshape(gravel, (gravel.shape[0],1))\n    sugar = np.reshape(sugar, (sugar.shape[0],1))\n    images = np.reshape(images, (images.shape[0],1))\n    \n    # Create a new dataset where each row represents an image and all its masks\n    new_df = np.concatenate((images, fish, flower, gravel, sugar), axis=1)\n    new_df = pd.DataFrame(data=new_df, columns=['Image', 'Fish', 'Flower', 'Gravel', 'Sugar'])\n    \n    return new_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset = prepare_dataset(pd.read_csv(path+'train.csv'))\ndataset.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Helper functions"},{"metadata":{"trusted":true},"cell_type":"code","source":"### Transform inputs data (1D) into 2D masks\ndef rle_decode(mask, shape=(1400,2100)) :\n    m = str(mask)\n    if m == 'nan' :\n        m = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    else :\n        m = m.split()\n        starts = np.asarray(m[0:][::2], dtype=int) - 1\n        lengths = np.asarray(m[1:][::2], dtype=int)\n        ends = starts + lengths\n        \n        m = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n        for lo, hi in zip(starts, ends):\n            m[lo:hi] = 1\n        \n    m = m.reshape(shape, order='F')\n    m = cv.resize(m, resized_inv)\n    return m\n\n\ndef display_img_with_masks(img, masks) :\n    plt.figure()\n    plt.imshow(to_img(img))\n    for mask in masks :\n        if np.sum(mask) > 0 :\n            plt.imshow(mask, alpha=0.2, cmap='gray')\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"class Dataset(Dataset) :\n    # Constructor\n    def __init__(self, df=None, transform=None, train=True) :\n        self.directory = \"/kaggle/input/understanding_cloud_organization/\"\n        if train == True :\n            self.directory = self.directory + \"train_images/\"\n        else :\n            self.directory = self.directory + \"test_images/\"\n        self.all_files = [self.directory + img for img in df.Image]\n        self.masks = df.drop(columns=['Image']).to_numpy()\n        self.transform = transform\n        self.len = len(self.all_files)\n        \n    # Getter\n    def __getitem__(self, idx):\n        image = Image.open(self.all_files[idx])\n        y = self.masks[idx]\n        Y = np.zeros((4,350,525))\n        for i in range(4) :\n            Y[i,:,:] = rle_decode(y[i])\n        if self.transform:\n            image = self.transform(image)\n        return image, Y\n    \n    def __len__(self):\n        return self.len","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"transform = transforms.Compose([transforms.Resize(resized), transforms.ToTensor()])\nto_img = transforms.ToPILImage()\n\ntrain, validation = train_test_split(dataset, test_size=0.2, random_state=4)\ntrain_set = Dataset(train, transform)\nvalidation_set = Dataset(validation, transform)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Example"},{"metadata":{"trusted":true},"cell_type":"code","source":"img, masks = train_set[0]\ndisplay_img_with_masks(img, masks)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"class Conv(nn.Module) :\n    def __init__(self, in_ch, out_ch) :\n        super(Conv, self).__init__()\n        self.conv = nn.Sequential(\n                nn.Conv2d(in_ch, out_ch, 3, padding=1),\n                nn.BatchNorm2d(out_ch),\n                nn.ReLU(inplace=True),\n                nn.Conv2d(out_ch, out_ch, 3, padding=1),\n                nn.BatchNorm2d(out_ch),\n                nn.ReLU(inplace=True))\n        \n    def forward(self, x) :\n        x = self.conv(x)\n        return x\n\n\nclass Down(nn.Module) :\n    def __init__(self, in_ch, out_ch) :\n        super(Down, self).__init__()\n        self.layer = nn.Sequential(nn.MaxPool2d(2), Conv(in_ch, out_ch))\n        \n    def forward(self, x) :\n        x = self.layer(x)\n        return x\n\n\nclass Up(nn.Module) :\n    def __init__(self, in_ch, out_ch) :\n        super(Up, self).__init__()\n        self.up = nn.ConvTranspose2d(in_ch//2, in_ch//2, 2, 2)\n        self.conv = Conv(in_ch, out_ch)\n        \n    def forward(self, x, x_prev) :\n        x = self.up(x)\n        \n        diffY = x_prev.size()[2] - x.size()[2]\n        diffX = x_prev.size()[3] - x.size()[3]\n        x = F.pad(x, (diffX // 2, diffX - diffX // 2, diffY // 2, diffY - diffY // 2))\n        x = torch.cat([x_prev, x], dim=1)\n        \n        return self.conv(x)\n\n\nclass UNet(nn.Module) :\n    def __init__(self, n_chan, n_classes) :\n        super(UNet, self).__init__()\n        self.init = Conv(n_chan,64)\n        self.down1 = Down(64,128)\n        self.down2 = Down(128,256)\n        self.down3 = Down(256,512)\n        self.down4 = Down(512,512)\n        self.up1 = Up(1024,256)\n        self.up2 = Up(512,128)\n        self.up3 = Up(256,64)\n        self.up4 = Up(128,64)\n        self.out = nn.Conv2d(64, n_classes, 1)\n        \n    def forward(self, x):\n        x1 = self.init(x)\n        x2 = self.down1(x1)\n        x3 = self.down2(x2)\n        x4 = self.down3(x3)\n        x5 = self.down4(x4)\n        x = self.up1(x5, x4)\n        x = self.up2(x, x3)\n        x = self.up3(x, x2)\n        x = self.up4(x, x1)\n        x = self.out(x)\n        return torch.sigmoid(x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = UNet(3, 4).float()\nif train_on_gpu:\n    model.cuda()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Loss function"},{"metadata":{"trusted":true},"cell_type":"code","source":"class DiceLoss(nn.Module) :\n    __name__ = 'dice_loss'\n    def __init__(self, eps=1e-7, activation='sigmoid') :\n        super().__init__()\n        self.activation = activation\n        self.eps = eps\n    \n    def forward(self, pred, truth) :\n        tp = torch.sum(pred*truth)\n        fp = torch.sum(pred) - tp\n        fn = torch.sum(truth) - tp\n        score = (2*tp + self.eps) / (2*tp + fn + fp + self.eps)\n        return 1-score\n        \n        \nclass BCEDiceLoss(DiceLoss):\n    __name__ = 'bce_dice_loss'\n    def __init__(self, eps=1e-7, activation='sigmoid'):\n        super().__init__(eps, activation)\n        self.bce = nn.BCELoss(reduction='mean')\n\n    def forward(self, pred, truth):\n        dice = super().forward(pred, truth)\n        bce = self.bce(pred, truth)\n        return dice + bce\n\n    \ndef calc_dice_score(outputs, targets, threshold=None, min_size=None, eps=1e-7) :\n    if threshold is not None :\n        outputs = (outputs > threshold).float()\n    \n    if min_size is not None :\n        if torch.sum(outputs) < min_size :\n            outputs = torch.zeros(outputs.shape[0], outputs.shape[1])\n    \n    intersection = torch.sum(targets * outputs)\n    union = torch.sum(targets) + torch.sum(outputs)\n    dice = (2*intersection + eps) / (union + eps)\n\n    return dice","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Optimizer"},{"metadata":{"trusted":true},"cell_type":"code","source":"class RAdam(Optimizer):\n\n    def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, weight_decay=0):\n        if not 0.0 <= lr:\n            raise ValueError(\"Invalid learning rate: {}\".format(lr))\n        if not 0.0 <= eps:\n            raise ValueError(\"Invalid epsilon value: {}\".format(eps))\n        if not 0.0 <= betas[0] < 1.0:\n            raise ValueError(\"Invalid beta parameter at index 0: {}\".format(betas[0]))\n        if not 0.0 <= betas[1] < 1.0:\n            raise ValueError(\"Invalid beta parameter at index 1: {}\".format(betas[1]))\n            \n        defaults = dict(lr=lr, betas=betas, eps=eps, weight_decay=weight_decay)\n        self.buffer = [[None, None, None] for ind in range(10)]\n        super(RAdam, self).__init__(params, defaults)\n\n    def __setstate__(self, state):\n        super(RAdam, self).__setstate__(state)\n\n    def step(self, closure=None):\n        loss = None\n        if closure is not None:\n            loss = closure()\n\n        for group in self.param_groups:\n            for p in group['params']:\n                if p.grad is None:\n                    continue\n                grad = p.grad.data.float()\n                if grad.is_sparse:\n                    raise RuntimeError('RAdam does not support sparse gradients')\n\n                p_data_fp32 = p.data.float()\n                state = self.state[p]\n                if len(state) == 0:\n                    state['step'] = 0\n                    state['exp_avg'] = torch.zeros_like(p_data_fp32)\n                    state['exp_avg_sq'] = torch.zeros_like(p_data_fp32)\n                else:\n                    state['exp_avg'] = state['exp_avg'].type_as(p_data_fp32)\n                    state['exp_avg_sq'] = state['exp_avg_sq'].type_as(p_data_fp32)\n\n                exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq']\n                beta1, beta2 = group['betas']\n\n                exp_avg_sq.mul_(beta2).addcmul_(1 - beta2, grad, grad)\n                exp_avg.mul_(beta1).add_(1 - beta1, grad)\n\n                state['step'] += 1\n                buffered = self.buffer[int(state['step'] % 10)]\n                if state['step'] == buffered[0]:\n                    N_sma, step_size = buffered[1], buffered[2]\n                else:\n                    buffered[0] = state['step']\n                    beta2_t = beta2 ** state['step']\n                    N_sma_max = 2 / (1 - beta2) - 1\n                    N_sma = N_sma_max - 2 * state['step'] * beta2_t / (1 - beta2_t)\n                    buffered[1] = N_sma\n\n                    # more conservative since it's an approximated value\n                    if N_sma >= 5:\n                        step_size = math.sqrt((1 - beta2_t) * (N_sma - 4) / (N_sma_max - 4) * (N_sma - 2) / N_sma * N_sma_max / (N_sma_max - 2)) / (1 - beta1 ** state['step'])\n                    else:\n                        step_size = 1.0 / (1 - beta1 ** state['step'])\n                    buffered[2] = step_size\n\n                if group['weight_decay'] != 0:\n                    p_data_fp32.add_(-group['weight_decay'] * group['lr'], p_data_fp32)\n\n                # more conservative since it's an approximated value\n                if N_sma >= 5:            \n                    denom = exp_avg_sq.sqrt().add_(group['eps'])\n                    p_data_fp32.addcdiv_(-step_size * group['lr'], exp_avg, denom)\n                else:\n                    p_data_fp32.add_(-step_size * group['lr'], exp_avg)\n\n                p.data.copy_(p_data_fp32)\n\n        return loss","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"criterion = BCEDiceLoss(eps=1.0, activation=None)\noptimizer = RAdam(model.parameters(), lr = 0.005)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training the model\nSkip this step if you don't want to train model (it takes several hours)."},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_model(model, n_epochs,\n                train_set, validation_set, batch_size,\n                criterion, optimizer) :\n    \n    train_loss_list = []\n    valid_loss_list = []\n    dice_score_list = []\n    lr_rate_list = []\n    valid_loss_min = np.Inf # track change in validation loss\n    \n    current_lr = [param_group['lr'] for param_group in optimizer.param_groups][0]\n    scheduler = ReduceLROnPlateau(optimizer, factor=0.2, patience=2, cooldown=2)\n    train_loader = DataLoader(train_set, batch_size = batch_size)\n    validation_loader = DataLoader(validation_set, batch_size = batch_size)\n\n    for epoch in range(1, n_epochs+1):\n        # keep track of training and validation loss\n        train_loss = 0.0\n        valid_loss = 0.0\n        dice_score = 0.0\n\n        ###################\n        # train the model #\n        ###################\n        model.train()\n        bar = tq(train_loader, postfix={\"train_loss\":0.0})\n        for data, target in bar:\n            if train_on_gpu:\n                data, target = data.cuda(), target.cuda()\n            optimizer.zero_grad()\n            output = model(data).double()\n            loss = criterion(output, target)\n            loss.backward()\n            optimizer.step()\n            train_loss += loss.item()*data.size(0)\n            bar.set_postfix(ordered_dict={\"train_loss\":loss.item()})\n\n        ######################    \n        # validate the model #\n        ######################\n        model.eval()\n        del data, target\n        with torch.no_grad():\n            bar = tq(validation_loader, postfix={\"valid_loss\":0.0, \"dice_score\":0.0})\n            for data, target in bar:\n                if train_on_gpu:\n                    data, target = data.cuda(), target.cuda()\n                output = model(data).double()\n                loss = criterion(output, target)\n                valid_loss += loss.item()*data.size(0)\n                dice_cof = calc_dice_score(output.cpu(), target.cpu()).item()\n                dice_score +=  dice_cof * data.size(0)\n                bar.set_postfix(ordered_dict={\"valid_loss\":loss.item(), \"dice_score\":dice_cof})\n\n        # calculate average losses\n        train_loss = train_loss/len(train_loader.dataset)\n        valid_loss = valid_loss/len(validation_loader.dataset)\n        dice_score = dice_score/len(validation_loader.dataset)\n        train_loss_list.append(train_loss)\n        valid_loss_list.append(valid_loss)\n        dice_score_list.append(dice_score)\n        lr_rate_list.append([param_group['lr'] for param_group in optimizer.param_groups])\n\n        # print training/validation statistics \n        print('Epoch: {}  Training Loss: {:.6f}  Validation Loss: {:.6f} Dice Score: {:.6f}'.format(\n            epoch, train_loss, valid_loss, dice_score))\n\n        # save model if validation loss has decreased\n        if valid_loss <= valid_loss_min:\n            print('Validation loss decreased ({:.6f} --> {:.6f}).  Saving model ...'.format(\n            valid_loss_min,\n            valid_loss))\n            torch.save(model.state_dict(), 'clouds_segmentation_unet.pt')\n            valid_loss_min = valid_loss\n\n        scheduler.step(valid_loss)\n    \n    return model, [train_loss_list, valid_loss_list, dice_score_list, lr_rate_list]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"n_epochs = 20\nbatch_size = 4\n#model, history = train_model(model, n_epochs, train_set, validation_set, batch_size, criterion, optimizer)\n#train_loss_list, valid_loss_list, dice_score_list, lr_rate_list = history","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\nplt.figure(figsize=(10,10))\nplt.plot([i[0] for i in lr_rate_list])\nplt.ylabel('learing rate during training', fontsize=22)\nplt.show()\n\nplt.figure(figsize=(10,10))\nplt.plot(train_loss_list,  marker='o', label=\"Training Loss\")\nplt.plot(valid_loss_list,  marker='o', label=\"Validation Loss\")\nplt.ylabel('loss', fontsize=22)\nplt.legend()\nplt.show()\n\nplt.figure(figsize=(10,10))\nplt.plot(dice_score_list)\nplt.ylabel('Dice score')\nplt.show()\n'''","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Load the model\nSkip this step if you just trained the model."},{"metadata":{"trusted":true},"cell_type":"code","source":"checkpoint = torch.load(\"../input/clouds-output/clouds_segmentation_unet.pt\")\nmodel.load_state_dict(checkpoint)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Post-processing\nWe will process masks with a threshold and a minimal size. All pixels value will be turned to 1 if their predicted value is above the threshold, 0 otherwise. Moreover, if a processed mask has too few pixel evaluated to 1, they will be considered null."},{"metadata":{"trusted":true},"cell_type":"code","source":"def calc_score(outputs, targets, threshold=None, min_size=None, eps=1e-7) :\n    if threshold is not None :\n        outputs = (outputs > threshold).float()\n    \n    if min_size is not None :\n        if torch.sum(outputs) < min_size :\n            outputs = torch.zeros(outputs.shape[0], outputs.shape[1])\n    \n    inter = torch.sum(targets * outputs)\n    pred = torch.sum(outputs)\n    truth = torch.sum(targets)\n    \n    dice = (2*inter + eps) / (pred + truth + eps)\n    recall = (inter + eps) / (truth + eps)\n    precision = (inter + eps) / (pred + eps) \n    \n    return dice, precision, recall\n\n\ndef post_processing(model, validation_set) :\n    threshold_list = [i/100 for i in range(10,100,5)]\n    size_list = [500, 1000, 2500, 5000, 7500, 10000]\n    \n    dice_table = np.zeros((len(threshold_list), len(size_list)))\n    precision_table = np.zeros((len(threshold_list), len(size_list)))\n    recall_table = np.zeros((len(threshold_list), len(size_list)))\n    \n    model.eval()\n    with torch.no_grad():\n        bar = tq(DataLoader(validation_set, batch_size=1))\n        for data, target in bar:\n            if train_on_gpu:\n                data, target = data.cuda(), target.cuda()\n            output = model(data).cpu()\n            target  = target.cpu()\n            i = 0\n            for t in threshold_list :\n                j = 0\n                for s in size_list :\n                    for mask, tar in zip(output[0], target[0]) :\n                        score = calc_score(mask, tar, t, s)\n                        dice_table[i,j] += score[0]\n                        precision_table[i,j] += score[1]\n                        recall_table[i,j] += score[2]\n                    j += 1\n                i += 1\n\n    dice_table /= (len(validation_set)*4)\n    precision_table /= (len(validation_set)*4)\n    recall_table /= (len(validation_set)*4)\n    \n    # Merge the tables into a dataframe\n    dice_df = []\n    i = 0\n    for t in threshold_list :\n        j = 0\n        for s in size_list :\n            dice_df.append((t, s, dice_table[i,j], precision_table[i,j], recall_table[i,j]))\n            j += 1\n        i += 1\n\n    dice_df = pd.DataFrame(dice_df, columns=['threshold', 'size', 'dice', 'precision', 'recall'])\n    dice_df.to_csv('dice_scores.csv', index=False)\n    \n    return dice_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The following cell calculate the average dice score for the validation set for different values of the threshold and the min size (it should take around 10 minutes).  \nSkip this cell if you don't want to calculate the dice scores from all the combinations of treshold and min_size."},{"metadata":{"trusted":true},"cell_type":"code","source":"#dice_df = post_processing(model, validation_set)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Running this cell will load the dice values computed during a previous execution with the model loaded above."},{"metadata":{"trusted":true},"cell_type":"code","source":"dice_df = pd.read_csv('../input/clouds-output/dice_scores.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(dice_df.groupby(['threshold'])['dice'].max(),'\\n')\nprint(dice_df.groupby(['size'])['dice'].max(),'\\n')\nprint(dice_df.sort_values('dice', ascending=False))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(dice_df.groupby(['threshold'])['precision'].max(),'\\n')\nprint(dice_df.groupby(['threshold'])['recall'].max(),'\\n')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.lineplot(x='threshold', y='dice', hue='size', data=dice_df);\nplt.title('Threshold and min size vs dice');","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Find the best parameters."},{"metadata":{"trusted":true},"cell_type":"code","source":"params = dice_df.sort_values('dice', ascending=False)[0:1].to_numpy()\nparams = list(params[0][:2])\nprint('Best parameters')\nprint('threshold =', params[0], '   size =', params[1])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Display results"},{"metadata":{"trusted":true},"cell_type":"code","source":"def process_mask(outputs, threshold, min_size) :\n    outputs = (outputs > threshold).float()\n    \n    if torch.sum(outputs) < min_size :\n        outputs = torch.zeros(outputs.shape[0], outputs.shape[1])\n    return outputs\n\n\ndef show_results(orig_img, output, target, params) :\n    threshold, min_size = params\n    fontsize = 14\n    class_list = ['Fish', 'Flower', 'Sugar', 'Gravel']\n    \n    f, ax = plt.subplots(3, 5, figsize=(24, 12))\n    ax[0,0].imshow(orig_img)\n    ax[0,0].set_title(\"Original image\", fontsize=fontsize)\n\n    for i in range(4):\n        ax[0,i+1].imshow(target[i])\n        ax[0,i+1].set_title(f\"Original mask {class_list[i]}\", fontsize=fontsize)\n\n    ax[1,0].imshow(orig_img)\n    ax[1,0].set_title(\"Original image\", fontsize=fontsize)\n\n    for i in range(4):\n        dice_score = calc_dice_score(output[i], target[i]).item()\n        ax[1,i+1].imshow(output[i])\n        ax[1,i+1].set_title(f\"Raw predicted mask {class_list[i]}\\nDice score = {round(dice_score,2)}\", fontsize=fontsize)\n\n    ax[2,0].imshow(orig_img)\n    ax[2,0].set_title(\"Transformed image\", fontsize=fontsize)\n\n    for i in range(4):\n        dice_score = calc_dice_score(output[i], target[i], threshold, min_size).item()\n        ax[2,i+1].imshow(process_mask(output[i], threshold, min_size))\n        ax[2,i+1].set_title( f\"Predicted mask with processing {class_list[i]}\\nDice score = {round(dice_score,2)}\", fontsize=fontsize)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Choose few images to display with their original, predicted and processed masks\nn = 50\nnum_of_img_to_display = 4\ndisplay_set = Dataset(validation[n:n+num_of_img_to_display], transform)\n\nmodel.eval()\nwith torch.no_grad():\n    for data, target in DataLoader(display_set, batch_size=1):\n        if train_on_gpu:\n            data, target = data.cuda(), target.cuda()\n        output = model(data).cpu()[0]\n        img = to_img(data.cpu()[0])\n        show_results(img, output, target.cpu()[0], params)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prepare submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_dataset = prepare_dataset(pd.read_csv(path + 'sample_submission.csv'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_set = Dataset(test_dataset, transform, train=False)\ntest_loader = DataLoader(test_set, batch_size=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def mask2rle(img):\n    \"\"\"\n    Convert mask to rle.\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    \"\"\"\n    pixels = img.T.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return \" \".join(str(x) for x in runs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def prepare_sub(model, test_loader) :\n    encoded_pixels = []\n    model.eval()\n    with torch.no_grad():\n        bar = tq(test_loader)\n        for data, target in bar:\n            if train_on_gpu:\n                data = data.cuda()\n            output = model(data).cpu()[0]\n            for mask in output :\n                mask = process_mask(mask, params[0], params[1])\n                mask = mask2rle(mask.detach().numpy())\n                encoded_pixels.append(mask)\n    return encoded_pixels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#submission = pd.read_csv(path + 'sample_submission.csv')\n#submission['EncodedPixels'] = prepare_sub(model, test_loader)\nsubmission = pd.read_csv('../input/clouds-output/submission.csv')\nsubmission.to_csv('submission.csv', columns=['Image_Label', 'EncodedPixels'], index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}