{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install segmentation_models_pytorch","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"prefix = '/kaggle/input/covid-segmentation/'\n\nimages_radiopedia = np.load(os.path.join(prefix, 'images_radiopedia.npy')).astype(np.float32)\nmasks_radiopedia = np.load(os.path.join(prefix, 'masks_radiopedia.npy')).astype(np.int8)\nimages_medseg = np.load(os.path.join(prefix, 'images_medseg.npy')).astype(np.float32)\nmasks_medseg = np.load(os.path.join(prefix, 'masks_medseg.npy')).astype(np.int8)\n\ntest_images_medseg = np.load(os.path.join(prefix, 'test_images_medseg.npy')).astype(np.float32)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def visualize(image_batch, mask_batch=None, pred_batch=None, num_samples=8, hot_encode=True):\n    num_classes = mask_batch.shape[-1] if mask_batch is not None else 0\n    fix, ax = plt.subplots(num_classes + 1, num_samples, figsize=(num_samples * 2, (num_classes + 1) * 2))\n\n    for i in range(num_samples):\n        ax_image = ax[0, i] if num_classes > 0 else ax[i]\n        if hot_encode: \n            ax_image.imshow(image_batch[i,:,:,0], cmap='Greys')\n        else: \n            ax_image.imshow(image_batch[i,:,:])\n        ax_image.set_xticks([]) \n        ax_image.set_yticks([])\n        \n        if mask_batch is not None:\n            for j in range(num_classes):\n                if pred_batch is None:\n                    mask_to_show = mask_batch[i,:,:,j]\n                else:\n                    mask_to_show = np.zeros(shape=(*mask_batch.shape[1:-1], 3)) \n                    mask_to_show[..., 0] = pred_batch[i,:,:,j] > 0.5\n                    mask_to_show[..., 1] = mask_batch[i,:,:,j]\n                ax[j + 1, i].imshow(mask_to_show, vmin=0, vmax=1)\n                ax[j + 1, i].set_xticks([]) \n                ax[j + 1, i].set_yticks([]) \n\n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Images from radiopedia are full CT volumes:\nClass 0 is \"ground glass\"<br>\nClass 1 is \"consolidations\"<br>\nClass 2 is \"lungs other\" – it doesn't mean that it is healthy lungs (you don't need to predict this class)<br>\nClass 3 is \"background\" – not lungs (you don't need to predict this class)<br>","metadata":{}},{"cell_type":"code","source":"visualize(images_radiopedia[30:], masks_radiopedia[30:])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def onehot_to_mask(mask, palette):\n    \"\"\"\n    Converts a mask (H, W, K) to (H, W, C)\n    \"\"\"\n    x = np.argmax(mask, axis=-1)\n    colour_codes = np.array(palette)\n    x = np.uint8(colour_codes[x.astype(np.uint8)])\n    return x\n\npalette = [[0], [1], [2],[3]]\nmasks_radiopedia_recover = onehot_to_mask(masks_radiopedia, palette).squeeze()  # shape = (H, W)\n\nmasks_medseg_recover = onehot_to_mask(masks_medseg, palette).squeeze()  # shape = (H, W)\n\nprint('Hot encoded mask size: ',masks_radiopedia.shape)\nprint('Paletted mask size:',masks_medseg_recover.shape)\n\nvisualize(masks_medseg_recover[30:],hot_encode=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Preprocess images:","metadata":{}},{"cell_type":"code","source":"def preprocess_images(images_arr, mean_std=None):\n    images_arr[images_arr > 500] = 500\n    images_arr[images_arr < -1500] = -1500\n    min_perc, max_perc = np.percentile(images_arr, 5), np.percentile(images_arr, 95)\n    images_arr_valid = images_arr[(images_arr > min_perc) & (images_arr < max_perc)]\n    mean, std = (images_arr_valid.mean(), images_arr_valid.std()) if mean_std is None else mean_std\n    images_arr = (images_arr - mean) / std\n    print(f'mean {mean}, std {std}')\n    return images_arr, (mean, std)\n\nimages_radiopedia, mean_std = preprocess_images(images_radiopedia)\nimages_medseg, _ = preprocess_images(images_medseg, mean_std)\ntest_images_medseg, _ = preprocess_images(test_images_medseg, mean_std)","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_hists(images1, images2=None):\n    plt.hist(images1.ravel(), bins=100, density=True, color='b', alpha=1 if images2 is None else 0.5)\n    if images2 is not None:\n        plt.hist(images2.ravel(), bins=100, density=True, alpha=0.5, color='orange')\n    plt.show();\n    \nplot_hists(test_images_medseg, images_radiopedia)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Split train / val:","metadata":{}},{"cell_type":"code","source":"masks_radiopedia_recover = onehot_to_mask(masks_radiopedia, palette).squeeze()  # shape = (H, W)\nmasks_medseg_recover = onehot_to_mask(masks_medseg, palette).squeeze()  # shape = (H, W)\n\n\nval_indexes, train_indexes = list(range(24)), list(range(24, 100))\n\ntrain_images = np.concatenate((images_medseg[train_indexes], images_radiopedia))\ntrain_masks = np.concatenate((masks_medseg_recover[train_indexes], masks_radiopedia_recover))\nval_images = images_medseg[val_indexes]\nval_masks = masks_medseg_recover[val_indexes]\n\nbatch_size = len(val_masks)\n\ndel masks_medseg_recover\ndel masks_radiopedia_recover\ndel images_radiopedia\ndel masks_radiopedia\ndel images_medseg\ndel masks_medseg","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data generator and augmentations:","metadata":{}},{"cell_type":"code","source":"import tensorflow\n\nimport albumentations\n\nimport cv2\n\nSOURCE_SIZE = 512\nTARGET_SIZE = 256\n\n\ntrain_augs = albumentations.Compose([\n    albumentations.Rotate(limit=360, p=0.9, border_mode=cv2.BORDER_REPLICATE),\n    albumentations.RandomSizedCrop((int(SOURCE_SIZE * 0.75), SOURCE_SIZE), \n                                   TARGET_SIZE, \n                                   TARGET_SIZE, \n                                   interpolation=cv2.INTER_NEAREST),\n    albumentations.HorizontalFlip(p=0.5),\n\n])\n\nval_augs = albumentations.Compose([\n    albumentations.Resize(TARGET_SIZE, TARGET_SIZE, interpolation=cv2.INTER_NEAREST)\n])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\nimport segmentation_models_pytorch as smp\nimport torch.nn.functional as F\nimport torch.nn as nn\nfrom tqdm.notebook import tqdm\nimport time\n\nfrom torchvision import transforms as T\nfrom torch.utils.data import Dataset, DataLoader  \nimport torch\n\ndevice = torch.cuda.set_device(0)\n\nclass Dataset:   \n    def __init__(\n            self, \n            images, \n            masks,\n            augmentations=None\n    ):\n        self.images = images\n        self.masks = masks\n        self.augmentations = augmentations\n        self.mean = [0.485]\n        self.std = [0.229]\n    \n    def __getitem__(self, i):\n        image = self.images[i]\n        mask = self.masks[i]\n        \n        \n        if self.augmentations is not None:\n            sample = self.augmentations(image=image, mask=mask)\n            \n            image, mask = Image.fromarray(np.squeeze(sample['image'], axis=2)), sample['mask']\n        \n        if self.augmentations is None:\n            image = Image.fromarray(image)\n        \n        t = T.Compose([T.ToTensor(), T.Normalize(self.mean, self.std)])\n        image = t(image)\n        mask = torch.from_numpy(mask).long()\n    \n        return image, mask\n    \n    def __len__(self):\n        return len(self.images)\n    \n    def tiles(self, image, mask):\n\n        img_patches = image.unfold(1, 512, 512).unfold(2, 768, 768) \n        img_patches  = img_patches.contiguous().view(3,-1, 512, 768) \n        img_patches = img_patches.permute(1,0,2,3)\n        \n        mask_patches = mask.unfold(0, 512, 512).unfold(1, 768, 768)\n        mask_patches = mask_patches.contiguous().view(-1, 512, 768)\n        \n        return img_patches, mask_patches\n    \n                \ntrain_dataset = Dataset(train_images, train_masks, train_augs)\nval_dataset = Dataset(val_images, val_masks, val_augs)       \n\ntrain_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_dataloader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def mask_to_onehot(mask, palette):\n    \"\"\"\n    Converts a segmentation mask (H, W, C) to (H, W, K) where the last dim is a one\n    hot encoding vector, C is usually 1 or 3, and K is the number of class.\n    \"\"\"\n    semantic_map = []\n    for colour in palette:\n        #print('colour',colour)\n        equality = np.equal(mask, colour)\n        #print('equality',equality)\n        class_map = np.all(equality, axis=-1)\n        semantic_map.append(class_map)\n    semantic_map = np.stack(semantic_map, axis=-1).astype(np.float32)\n    return torch.from_numpy(semantic_map)\n\ni,train_data = next(enumerate(train_dataloader))\n\nmask_hot_encoded = mask_to_onehot(torch.unsqueeze(train_data[1],-1).numpy(),palette)\n#visualize(torch.unsqueeze(torch.squeeze(train_data[0],1),-1),mask_hot_encoded)\nvisualize(train_data[0].permute(0, 2, 3,1),mask_hot_encoded)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def pixel_accuracy(output, mask):\n    with torch.no_grad():\n        output = torch.argmax(F.softmax(output, dim=1), dim=1)\n        correct = torch.eq(output, mask).int()\n        accuracy = float(correct.sum()) / float(correct.numel())\n    return accuracy","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def mIoU(pred_mask, mask, smooth=1e-10, n_classes=4):\n    with torch.no_grad():\n        pred_mask = F.softmax(pred_mask, dim=1)\n        pred_mask = torch.argmax(pred_mask, dim=1)\n        pred_mask = pred_mask.contiguous().view(-1)\n        mask = mask.contiguous().view(-1)\n\n        iou_per_class = []\n        for clas in range(0, n_classes): #loop per pixel class\n            true_class = pred_mask == clas\n            true_label = mask == clas\n\n            if true_label.long().sum().item() == 0: #no exist label in this loop\n                iou_per_class.append(np.nan)\n            else:\n                intersect = torch.logical_and(true_class, true_label).sum().float().item()\n                union = torch.logical_or(true_class, true_label).sum().float().item()\n\n                iou = (intersect + smooth) / (union +smooth)\n                iou_per_class.append(iou)\n        return np.nanmean(iou_per_class)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def iou(pred, gt):\n    pred = pred.squeeze().cpu().data.numpy()\n    pred = ToLabel(pred)\n    gt = gt.squeeze().cpu().data.numpy()\n    agg = pred + gt\n    i = float(np.sum(agg == 2))\n    u = float(np.sum(agg > 0))\n    if u == 0:\n        result = 1\n    else:\n        result = i/u\n    return result","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = smp.Unet('efficientnet-b2',in_channels=1, encoder_weights='imagenet',classes=4, activation=None, encoder_depth=5, decoder_channels=[256, 128, 64, 32, 16])\n#decoder_attention_type ='scse'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_lr(optimizer):\n    for param_group in optimizer.param_groups:\n        return param_group['lr']\n\ndef fit(epochs, model, train_loader, val_loader, criterion, optimizer, scheduler, patch=False):\n    #torch.cuda.empty_cache()\n    train_losses = []\n    test_losses = []\n    val_iou = []; val_acc = []\n    train_iou = []; train_acc = []\n    lrs = []\n    min_loss = np.inf\n    decrease = 1 ; not_improve=0\n\n    model.to(device)\n    fit_time = time.time()\n    for e in range(epochs):\n        since = time.time()\n        running_loss = 0\n        iou_score = 0\n        accuracy = 0\n        #training loop\n        model.train()\n        for i, data in enumerate(tqdm(train_loader)):\n            #training phase\n            image_tiles, mask_tiles = data\n            \n            image = image_tiles.to(device); mask =mask_tiles.to(device);\n            #forward\n            output = model(image)\n            \n            loss = criterion(output, mask)\n            #evaluation metrics\n            iou_score += mIoU(output, mask)\n            accuracy += pixel_accuracy(output, mask)\n            #backward\n            loss.backward()\n            optimizer.step() #update weight          \n            optimizer.zero_grad() #reset gradient\n            \n            #step the learning rate\n            lrs.append(get_lr(optimizer))\n            scheduler.step() \n            \n            running_loss += loss.item()\n            \n\n        else:\n            model.eval()\n            test_loss = 0\n            test_accuracy = 0\n            val_iou_score = 0\n            #validation loop\n            with torch.no_grad():\n                for i, data in enumerate(tqdm(val_loader)):\n                    image_tiles, mask_tiles = data\n\n                    image = image_tiles.to(device); mask =mask_tiles.to(device);\n                    output = model(image)\n                    #evaluation metrics\n                    val_iou_score +=  mIoU(output, mask)\n                    test_accuracy += pixel_accuracy(output, mask)\n                    #loss\n                    loss = criterion(output, mask)                                  \n                    test_loss += loss.item()\n            \n            #calculatio mean for each batch\n            train_losses.append(running_loss/len(train_loader))\n            test_losses.append(test_loss/len(val_loader))\n\n\n            if min_loss > (test_loss/len(val_loader)):\n                print('Loss Decreasing.. {:.3f} >> {:.3f} '.format(min_loss, (test_loss/len(val_loader))))\n                min_loss = (test_loss/len(val_loader))\n                decrease += 1\n                if decrease % 5 == 0:\n                    print('saving model...')\n                    torch.save(model, 'Unet_efficientnet_b2_mIoU-{:.3f}.pt'.format(val_iou_score/len(val_loader)))\n                    \n\n            if (test_loss/len(val_loader)) > min_loss:\n                not_improve += 1\n                min_loss = (test_loss/len(val_loader))\n                print(f'Loss Not Decrease for {not_improve} time')\n                if not_improve == 7:\n                    print('Loss not decrease for 7 times, Stop Training')\n                    break\n            \n            #iou\n            val_iou.append(val_iou_score/len(val_loader))\n            train_iou.append(iou_score/len(train_loader))\n            train_acc.append(accuracy/len(train_loader))\n            val_acc.append(test_accuracy/ len(val_loader))\n            print(\"Epoch:{}/{}..\".format(e+1, epochs),\n                  \"Train Loss: {:.3f}..\".format(running_loss/len(train_loader)),\n                  \"Val Loss: {:.3f}..\".format(test_loss/len(val_loader)),\n                  \"Train mIoU:{:.3f}..\".format(iou_score/len(train_loader)),\n                  \"Val mIoU: {:.3f}..\".format(val_iou_score/len(val_loader)),\n                  \"Train Acc:{:.3f}..\".format(accuracy/len(train_loader)),\n                  \"Val Acc:{:.3f}..\".format(test_accuracy/len(val_loader)),\n                  \"Time: {:.2f}m\".format((time.time()-since)/60))\n        \n    history = {'train_loss' : train_losses, 'val_loss': test_losses,\n               'train_miou' :train_iou, 'val_miou':val_iou,\n               'train_acc' :train_acc, 'val_acc':val_acc,\n               'lrs': lrs}\n    print('Total time: {:.2f} m' .format((time.time()- fit_time)/60))\n    return history","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"max_lr = 1e-3\nepoch = 10\nweight_decay = 1e-4\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.AdamW(model.parameters(), lr=max_lr, weight_decay=weight_decay)\nsched = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr, epochs=epoch,\n                                            steps_per_epoch=len(train_dataloader))\n\nhistory = fit(epoch, model, train_dataloader, val_dataloader, criterion, optimizer, sched)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.save(model, 'Unet-efficientnet.pt')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_loss(history):\n    plt.plot(history['val_loss'], label='val', marker='o')\n    plt.plot( history['train_loss'], label='train', marker='o')\n    plt.title('Loss per epoch'); plt.ylabel('loss');\n    plt.xlabel('epoch')\n    plt.legend(), plt.grid()\n    plt.show()\n    \ndef plot_score(history):\n    plt.plot(history['train_miou'], label='train_mIoU', marker='*')\n    plt.plot(history['val_miou'], label='val_mIoU',  marker='*')\n    plt.title('Score per epoch'); plt.ylabel('mean IoU')\n    plt.xlabel('epoch')\n    plt.legend(), plt.grid()\n    plt.show()\n    \ndef plot_acc(history):\n    plt.plot(history['train_acc'], label='train_accuracy', marker='*')\n    plt.plot(history['val_acc'], label='val_accuracy',  marker='*')\n    plt.title('Accuracy per epoch'); plt.ylabel('Accuracy')\n    plt.xlabel('epoch')\n    plt.legend(), plt.grid()\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_loss(history)\nplot_score(history)\nplot_acc(history)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Evaluation\n## Result","metadata":{}},{"cell_type":"code","source":"def predict_image_mask_miou(model, image, mask, mean=[0.485], std=[0.229]):\n    model.eval()\n    #t = T.Compose([T.ToTensor(), T.Normalize(mean, std)])\n    #image = t(image)\n    model.to(device); image=image.to(device)\n    mask = mask.to(device)\n    \n    \n    with torch.no_grad():\n        \n        #image = image.unsqueeze(0)\n        #mask = mask.unsqueeze(0)\n        \n        output = model(image)\n        a,b,c,d = output.shape\n        score = mIoU(output, mask)\n        masked = torch.argmax(output, dim=1)\n        masked = masked.cpu().squeeze(0)\n    return masked, score, output.permute(0, 2, 3,1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict_image_mask_pixel(model, image, mask, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]):\n    model.eval()\n    model.to(device); image=image.to(device)\n    mask = mask.to(device)\n    with torch.no_grad():\n        \n        output = model(image)\n        acc = pixel_accuracy(output, mask)\n        masked = torch.argmax(output, dim=1)\n        masked = masked.cpu().squeeze(0)\n    return masked, acc","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def mask_to_onehot(mask, palette):\n    \"\"\"\n    Converts a segmentation mask (H, W, C) to (H, W, K) where the last dim is a one\n    hot encoding vector, C is usually 1 or 3, and K is the number of class.\n    \"\"\"\n    semantic_map = []\n    for colour in palette:\n        equality = np.equal(mask, colour)\n        class_map = np.all(equality, axis=-1)\n        semantic_map.append(class_map)\n    semantic_map = np.stack(semantic_map, axis=-1).astype(np.float32)\n    return torch.from_numpy(semantic_map)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image, mask = next(iter(val_dataloader))\npred_mask, score,output = predict_image_mask_miou(model, image, mask)\nsemantic_map = mask_to_onehot(torch.unsqueeze(mask,-1).numpy(),palette)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"visualize(image, semantic_map, pred_batch=output)\n\n# yellow is TP, red is FP, green is FN","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def miou_score(model, test_set):\n    score_iou = []\n    for i, data in enumerate(tqdm(test_set)):\n        img, mask = data\n        pred_mask, score,output = predict_image_mask_miou(model, img, mask)\n        score_iou.append(score)\n    return score_iou","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mob_miou = miou_score(model, val_dataloader)\nmob_miou","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del train_images\ndel train_masks","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Test preds:","metadata":{}},{"cell_type":"code","source":"def test_predict(model, image, mean=[0.485], std=[0.229]):\n    t = T.Compose([T.ToTensor(), T.Normalize(mean, std)])\n    image = t(image)\n    model.eval()\n    \n    model.to(device); image=image.to(device)\n    \n    with torch.no_grad():\n        output = model(torch.unsqueeze(image,1))\n        output = nn.Softmax(dim=1)(output)\n    return output.permute(0, 2, 3,1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_batch = np.stack([val_augs(image=img)['image'] for img in test_images_medseg], axis=0)\nprint(torch.from_numpy(image_batch).shape)\nprint(image_batch[i].shape)\n#output = test_predict(model, torch.from_numpy(image_batch).permute(0, 3, 1,2))\noutput = np.zeros((10,256,256,4))\nfor i in range(10):   \n    output[i] = test_predict(model, image_batch[i])\nprint(output.shape)\ntest_masks_prediction = output > 0.5\nvisualize(image_batch, test_masks_prediction, num_samples=len(test_images_medseg))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Resize prediction to original size:","metadata":{}},{"cell_type":"code","source":"import scipy\ntest_masks_prediction_original_size = scipy.ndimage.zoom(test_masks_prediction[..., :-2], (1, 2, 2, 1), order=0)\ntest_masks_prediction_original_size.shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\n\npd.DataFrame(\n             data=np.stack((np.arange(len(test_masks_prediction_original_size.ravel())), \n                            test_masks_prediction_original_size.ravel().astype(int)),\n                            axis=-1), \n             columns=['Id', 'Predicted'])\\\n.set_index('Id').to_csv('sub.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}