{"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":"markdown","source":"# Imports","metadata":{"id":"qceXT4tPTiSg"}},{"cell_type":"code","source":"!pip install segmentation_models_pytorch --quiet\n!pip -q install cairosvg==2.5.2 --quiet \n!pip -q install reportlab==3.5.65 --quiet\n!pip -q install cssutils==2.2.0 --quiet","metadata":{"id":"OyE_nN59Zc1V","outputId":"fd031966-006a-40ff-89bd-3780ca3d8880","execution":{"iopub.status.busy":"2023-05-27T07:56:06.607293Z","iopub.execute_input":"2023-05-27T07:56:06.607802Z","iopub.status.idle":"2023-05-27T07:57:36.665353Z","shell.execute_reply.started":"2023-05-27T07:56:06.607760Z","shell.execute_reply":"2023-05-27T07:57:36.664081Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport albumentations as A\nimport segmentation_models_pytorch as smp\nimport warnings\nimport glob\nimport segmentation_models_pytorch.utils.metrics\nimport segmentation_models_pytorch.utils.train\nimport builtins\nimport pickle\n\nfrom tqdm import tqdm\n\nfrom torch.autograd import Variable\nfrom torch.utils.data import Dataset, DataLoader, SubsetRandomSampler\nfrom torchvision import transforms, utils\nfrom torch.optim import Adam\nfrom torch.optim.lr_scheduler import OneCycleLR\n\nfrom albumentations.pytorch import ToTensorV2\nfrom segmentation_models_pytorch.encoders import get_preprocessing_fn\n\nfrom PIL import Image\n\nwarnings.filterwarnings(\"ignore\")","metadata":{"id":"6RcXzjG3TMuO","execution":{"iopub.status.busy":"2023-05-27T07:57:36.667666Z","iopub.execute_input":"2023-05-27T07:57:36.668032Z","iopub.status.idle":"2023-05-27T07:57:42.903763Z","shell.execute_reply.started":"2023-05-27T07:57:36.667996Z","shell.execute_reply":"2023-05-27T07:57:42.902817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Config","metadata":{"id":"UPBoTA_MT0l1"}},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")","metadata":{"id":"kvSB81UWTyzz","execution":{"iopub.status.busy":"2023-05-27T07:57:42.906629Z","iopub.execute_input":"2023-05-27T07:57:42.906970Z","iopub.status.idle":"2023-05-27T07:57:42.933651Z","shell.execute_reply.started":"2023-05-27T07:57:42.906936Z","shell.execute_reply":"2023-05-27T07:57:42.931311Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CFG:\n    # ============== set paths =============\n    root_dir = '/kaggle/input/airbus-ship-detection'\n    csv_file = '/kaggle/input/airbus-ship-detection/sample_submission_v2.csv'\n    saved_model_path = '/kaggle/input/airbus-ship-detection-unet-weights/Unet_Weights.pth'\n\n    # ============== model cfg =============\n    model_name = 'Unet'\n    backbone = 'efficientnet-b0'\n    \n    # ============== training cfg =============\n    size = 224\n    batch_size = 32 # 64\n    epochs = 5 # 30\n    lr = 1e-3\n    weight_decay = 1e-5\n    seed = 42\n\n    # ============== loss cfg =============\n    mode = 'binary'\n    gamma = 5.0\n\n    # ============== fixed cfg =============\n    num_workers = 2\n\n    # ============== augmentation =============\n    torch_aug = [\n        A.Resize(width=224, height=224),\n        A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n        ToTensorV2()\n    ]\n    \n    train_aug = [\n        A.Resize(width=224, height=224),\n        A.HorizontalFlip(p=0.5),\n        A.Rotate(limit=45, p=0.5),\n        A.RandomBrightnessContrast(p=0.5),\n        A.RandomResizedCrop(height=256, width=256, scale=(0.8, 1.0), ratio=(0.9, 1.1), p=0.5),\n        A.Affine(scale=1.0, rotate=0, translate_percent=0, shear=0, p=0.5),\n        A.GaussNoise(var_limit=(10.0, 50.0), p=0.5),\n        A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n        ToTensorV2()\n    ]\n    \n    test_aug = [\n        A.Resize(width=224, height=224),\n        A.HorizontalFlip(p=0.5),\n        A.VerticalFlip(p=0.5),\n        A.Rotate(limit=45, p=0.5),\n        A.RandomBrightnessContrast(p=0.5),\n        A.RandomResizedCrop(height=224, width=224, scale=(0.8, 1.0), ratio=(0.9, 1.1), p=0.5),\n        A.GaussNoise(var_limit=(10.0, 50.0), p=0.5),\n        A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n        ToTensorV2()\n    ]\n\n    exclude_list = {\n        '6384c3e78.jpg','13703f040.jpg', '14715c06d.jpg',  '33e0ff2d5.jpg',\n        '4d4e09f2a.jpg', '877691df8.jpg', '8b909bb20.jpg', 'a8d99130e.jpg', \n        'ad55c3143.jpg', 'c8260c541.jpg', 'd6c7f17c7.jpg', 'dc3e7c901.jpg',\n        'e44dffe88.jpg', 'ef87bad36.jpg', 'f083256d8.jpg'\n    }","metadata":{"id":"m8Rfj9QNT16v","execution":{"iopub.status.busy":"2023-05-27T07:57:42.936397Z","iopub.execute_input":"2023-05-27T07:57:42.937059Z","iopub.status.idle":"2023-05-27T07:57:42.950265Z","shell.execute_reply.started":"2023-05-27T07:57:42.937022Z","shell.execute_reply":"2023-05-27T07:57:42.949531Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def set_seed(seed):\n    torch.manual_seed(seed)\n    np.random.seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n\nset_seed(CFG.seed)","metadata":{"id":"hOFRzj74Ef66","execution":{"iopub.status.busy":"2023-05-27T07:57:42.952683Z","iopub.execute_input":"2023-05-27T07:57:42.953937Z","iopub.status.idle":"2023-05-27T07:57:42.964895Z","shell.execute_reply.started":"2023-05-27T07:57:42.953909Z","shell.execute_reply":"2023-05-27T07:57:42.964180Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Helper Functions","metadata":{"id":"dIAjE97bTrfJ"}},{"cell_type":"code","source":"# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode\ndef rle_encode(mask):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    pixels = mask.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)\n\ndef rle_decode(mask_rle, shape=(768, 768)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (height,width) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T  # Needed to align to RLE direction","metadata":{"id":"s9b-ezVvTnVf","execution":{"iopub.status.busy":"2023-05-27T08:20:21.118932Z","iopub.execute_input":"2023-05-27T08:20:21.119289Z","iopub.status.idle":"2023-05-27T08:20:21.130089Z","shell.execute_reply.started":"2023-05-27T08:20:21.119258Z","shell.execute_reply":"2023-05-27T08:20:21.128955Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def imshow(img):\n    npimg = img.numpy()\n    plt.imshow(np.transpose(np.clip(npimg, 0, 1), (1, 2, 0)))\n\n\ndef plot_images_masks(images, masks):\n    num_images = images.shape[0]\n\n    fig, axs = plt.subplots(num_images, 2, figsize=(5, num_images*2))\n    \n    for i in range(num_images):\n        img = images[i].permute(1, 2, 0).numpy()  # move channels to last dimension\n        mask = masks[i].squeeze(0).numpy()  # remove channels dimension\n        img = np.clip(img, 0, 1)\n        mask = np.clip(mask, 0, 1)\n        \n        if num_images == 1:\n            axs[0].imshow(img, cmap='gray')\n            axs[0].axis('off')\n            axs[0].set_title('Image')\n\n            axs[1].imshow(mask, cmap='gray')\n            axs[1].axis('off')\n            axs[1].set_title('Mask')\n        else:\n            axs[i, 0].imshow(img, cmap='gray')\n            axs[i, 0].axis('off')\n            axs[i, 0].set_title('Image')\n\n            axs[i, 1].imshow(mask, cmap='gray')\n            axs[i, 1].axis('off')\n            axs[i, 1].set_title('Mask')\n    \n    plt.tight_layout()\n    plt.show()\n\n\ndef plot_images_masks_and_preds(images, masks, preds):\n    num_images = images.shape[0]\n\n    fig, axs = plt.subplots(num_images, 3, figsize=(5, num_images*2))\n    \n    for i in range(num_images):\n        img = images[i].permute(1, 2, 0).numpy()  # move channels to last dimension\n        mask = masks[i].squeeze(0).numpy()  # remove channels dimension\n        pred = preds[i].permute(1, 2, 0).numpy()  # move channels to last dimension\n        img = np.clip(img, 0, 1)\n        mask = np.clip(mask, 0, 1)\n        pred = np.clip(pred, 0, 1)\n        \n        if num_images == 1:\n            axs[0].imshow(img)\n            axs[0].axis('off')\n            axs[0].set_title('Image')\n\n            axs[1].imshow(mask)\n            axs[1].axis('off')\n            axs[1].set_title('Mask')\n\n            axs[2].imshow(preds)\n            axs[2].axis('off')\n            axs[2].set_title('pred mask')\n        else:\n            axs[i, 0].imshow(img)\n            axs[i, 0].axis('off')\n            axs[i, 0].set_title('Image')\n\n            axs[i, 1].imshow(mask)\n            axs[i, 1].axis('off')\n            axs[i, 1].set_title('Mask')\n\n            axs[i, 2].imshow(pred)\n            axs[i, 2].axis('off')\n            axs[i, 2].set_title('pred mask')\n    \n    plt.tight_layout()\n    plt.show()\n\n\ndef plot_learning_curve(train_loss_history, val_loss_history):\n    plt.figure()\n    plt.plot(train_loss_history, label='train')\n    plt.plot(val_loss_history, label='val')\n    plt.title('Training and validation loss')\n    plt.xlabel('Epochs')\n    plt.ylabel('Loss')\n    plt.legend()\n    plt.show()\n\n\ndef masks_as_image(in_mask_list):\n    # Take the individual ship masks and create a single mask array for all ships\n    all_masks = np.zeros((768, 768), dtype = np.int16)\n    #if isinstance(in_mask_list, list):\n    for mask in in_mask_list:\n        if isinstance(mask, str):\n            all_masks += rle_decode(mask)\n    return np.expand_dims(all_masks, -1)","metadata":{"id":"ELuQRMJ2Ttck","execution":{"iopub.status.busy":"2023-05-27T07:57:42.977553Z","iopub.execute_input":"2023-05-27T07:57:42.977902Z","iopub.status.idle":"2023-05-27T07:57:42.999044Z","shell.execute_reply.started":"2023-05-27T07:57:42.977866Z","shell.execute_reply":"2023-05-27T07:57:42.998090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data","metadata":{"id":"c_IhTISBT8iC"}},{"cell_type":"code","source":"TEST_NAMES = os.listdir(TEST_DIR)\nSAMPLE_SUBMISSION_DF =  pd.read_csv('/kaggle/input/airbus-ship-detection/sample_submission_v2.csv')\n\n\n\nCORRUPTED_IMAGES = {'6384c3e78.jpg','13703f040.jpg', '14715c06d.jpg',  '33e0ff2d5.jpg',\n            '4d4e09f2a.jpg', '877691df8.jpg', '8b909bb20.jpg', 'a8d99130e.jpg', \n            'ad55c3143.jpg', 'c8260c541.jpg', 'd6c7f17c7.jpg', 'dc3e7c901.jpg',\n            'e44dffe88.jpg', 'ef87bad36.jpg', 'f083256d8.jpg'}\n\n\nfor names_set in TEST_NAMES:\n    for name in names_set:\n        if name in CORRUPTED_IMAGES:\n            names_set.remove(name)\n            \nprint(f\"TEST_NAMES length = {len(TEST_NAMES)}\")","metadata":{"execution":{"iopub.status.busy":"2023-05-27T08:36:41.775127Z","iopub.execute_input":"2023-05-27T08:36:41.775554Z","iopub.status.idle":"2023-05-27T08:36:41.825080Z","shell.execute_reply.started":"2023-05-27T08:36:41.775521Z","shell.execute_reply":"2023-05-27T08:36:41.823838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Airbus(Dataset):\n    \"\"\" Airbus Ship dataset \"\"\"\n    \n    def __init__(self, csv_file, root_dir, transform=None):\n        \"\"\"\n        Arguments:\n            csv_file (string): Path to the csv file with annotations.\n            root_dir (string): Directory with all the images.\n            transform (callable, optional): Optional transform to be applied\n                on a sample.\n            train (bool): Indicate whether train or test set.\n        \"\"\"\n        self.images_frame = pd.read_csv(os.path.join(root_dir, csv_file)).fillna(-1)\n        self.root_dir = root_dir\n        self.transform = transform\n        self.data_path = 'test_v2'\n        \n    \n    def __len__(self):\n        return len(self.images_frame)\n    \n    \n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n        \n        image_name = self.images_frame.iloc[idx, 0]\n        image = np.array(Image.open(os.path.join(self.root_dir, self.data_path, image_name)))\n        mask = np.zeros_like(image)\n        \n        sample = {'image': image}\n            \n        if self.transform:\n            sample = self.transform(image=image, mask=mask)\n        \n        return sample['image']","metadata":{"id":"bf05d3gVT4ot","execution":{"iopub.status.busy":"2023-05-27T08:38:06.549604Z","iopub.execute_input":"2023-05-27T08:38:06.549977Z","iopub.status.idle":"2023-05-27T08:38:06.558914Z","shell.execute_reply.started":"2023-05-27T08:38:06.549944Z","shell.execute_reply":"2023-05-27T08:38:06.557831Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_transform = A.Compose(CFG.test_aug)","metadata":{"execution":{"iopub.status.busy":"2023-05-27T08:38:07.291557Z","iopub.execute_input":"2023-05-27T08:38:07.291925Z","iopub.status.idle":"2023-05-27T08:38:07.299193Z","shell.execute_reply.started":"2023-05-27T08:38:07.291895Z","shell.execute_reply":"2023-05-27T08:38:07.298380Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_set = Airbus(CFG.csv_file, CFG.root_dir, test_transform)","metadata":{"id":"kxDyz5g0UAcO","execution":{"iopub.status.busy":"2023-05-27T08:38:10.333133Z","iopub.execute_input":"2023-05-27T08:38:10.333752Z","iopub.status.idle":"2023-05-27T08:38:10.369286Z","shell.execute_reply.started":"2023-05-27T08:38:10.333707Z","shell.execute_reply":"2023-05-27T08:38:10.368396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_loader = DataLoader(test_set, batch_size=CFG.batch_size, shuffle=True)","metadata":{"id":"JqW931ugbOVa","execution":{"iopub.status.busy":"2023-05-27T08:38:10.716792Z","iopub.execute_input":"2023-05-27T08:38:10.717149Z","iopub.status.idle":"2023-05-27T08:38:10.721797Z","shell.execute_reply.started":"2023-05-27T08:38:10.717119Z","shell.execute_reply":"2023-05-27T08:38:10.720749Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{"id":"WnBrTPZ_UF1L"}},{"cell_type":"code","source":"model = smp.Unet(\n    encoder_name = CFG.backbone, \n    encoder_weights = 'imagenet',\n    in_channels = 3,\n    classes = 1,\n    activation = 'sigmoid'\n).to(device)","metadata":{"id":"PdCIAHCEUFX7","execution":{"iopub.status.busy":"2023-05-27T08:38:12.160846Z","iopub.execute_input":"2023-05-27T08:38:12.161968Z","iopub.status.idle":"2023-05-27T08:38:12.322133Z","shell.execute_reply.started":"2023-05-27T08:38:12.161919Z","shell.execute_reply":"2023-05-27T08:38:12.321166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if os.path.exists(CFG.saved_model_path):\n    print(model.load_state_dict(torch.load(CFG.saved_model_path, map_location=device)))","metadata":{"id":"FRhmMwE1BuJs","outputId":"e99f07e7-235a-4c26-a511-0337d992056d","execution":{"iopub.status.busy":"2023-05-27T08:38:13.108544Z","iopub.execute_input":"2023-05-27T08:38:13.109532Z","iopub.status.idle":"2023-05-27T08:38:13.205885Z","shell.execute_reply.started":"2023-05-27T08:38:13.109485Z","shell.execute_reply":"2023-05-27T08:38:13.204888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Metric","metadata":{}},{"cell_type":"code","source":"metrics = [segmentation_models_pytorch.utils.metrics.IoU(threshold=0.5)]","metadata":{"execution":{"iopub.status.busy":"2023-05-27T08:38:13.432636Z","iopub.execute_input":"2023-05-27T08:38:13.433004Z","iopub.status.idle":"2023-05-27T08:38:13.439371Z","shell.execute_reply.started":"2023-05-27T08:38:13.432971Z","shell.execute_reply":"2023-05-27T08:38:13.438321Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{"id":"iuV-B5WNHlnn"}},{"cell_type":"code","source":"test_df = pd.read_csv('/kaggle/input/airbus-ship-detection/sample_submission_v2.csv').copy()\ntest_df = test_df.set_index('ImageId')\ntest_df","metadata":{"execution":{"iopub.status.busy":"2023-05-27T08:40:07.903804Z","iopub.execute_input":"2023-05-27T08:40:07.904189Z","iopub.status.idle":"2023-05-27T08:40:07.928188Z","shell.execute_reply.started":"2023-05-27T08:40:07.904156Z","shell.execute_reply":"2023-05-27T08:40:07.927111Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def encode_minibatch(outputs):\n    encoded_list = []\n    for i in range(len(outputs)):\n        predicted_mask = cv2.resize(outputs[i], (768, 768))\n        encoded_list.append(rle_encode(predicted_mask))\n        \n    return encoded_list","metadata":{"execution":{"iopub.status.busy":"2023-05-27T07:58:17.889678Z","iopub.execute_input":"2023-05-27T07:58:17.890416Z","iopub.status.idle":"2023-05-27T07:58:17.896460Z","shell.execute_reply.started":"2023-05-27T07:58:17.890377Z","shell.execute_reply":"2023-05-27T07:58:17.895373Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with torch.no_grad():\n    size = test_loader.batch_size\n    start = 0\n    end = size\n    preds = []\n    for images in tqdm(test_loader):\n        size = images.size(0)\n        images = images.to(device)\n        outputs = model(images)\n        outputs = outputs.cpu().detach().numpy().squeeze().astype(np.uint8)\n\n        if end > len(test_df):\n            test_df['EncodedPixels'][start:] = encode_minibatch(outputs)\n        else:\n            test_df['EncodedPixels'][start:end] = encode_minibatch(outputs)\n\n        start = end\n        end += size\n        \ntest_df.to_csv('submission.csv', index=True)","metadata":{"execution":{"iopub.status.busy":"2023-05-27T08:41:12.508582Z","iopub.execute_input":"2023-05-27T08:41:12.508994Z"},"trusted":true},"execution_count":null,"outputs":[]}]}