{"cells":[{"metadata":{"_uuid":"8cf4b26fbe521de35807df1875cb8e7973027a0c"},"cell_type":"markdown","source":"# Airbus Ship Detection Challenge"},{"metadata":{"_uuid":"e896f8a545fe626066bd4f8535e147e164c5e200"},"cell_type":"markdown","source":"##### this code [resnet34-PANet](https://arxiv.org/abs/1805.10180) for ship detection  code  optimize by lovasz loss \n##### although I resize image to 256x256 and delete empty mask, but still have a large number images\n##### because my limit computer power , I have to abandon this challenge, I don't known the score it will acheive\n##### please cite [this](https://github.com/liuchuanloong/kaggle-TGS-salt-identification) if you apply this kernel"},{"metadata":{"_uuid":"4bddd6efc70be62774c3cc0158b87c915f3aaea6"},"cell_type":"markdown","source":"## prepare import library"},{"metadata":{"_uuid":"0e9d4ea969736204e291b8ef8d0d4c647bdd973f","collapsed":true,"trusted":false},"cell_type":"code","source":"import numpy as np\nimport cv2\nimport math\nimport pandas as pd\nimport os\nfrom sklearn.model_selection import train_test_split\nimport torch\nfrom torch.utils.data.dataset import Dataset\nfrom torch.utils.data import DataLoader\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e5a6982ad16d51531fd7d6713f2be291fb7de8ac"},"cell_type":"markdown","source":"## augmentation"},{"metadata":{"_uuid":"a9dfc1aee51b19de311309c52be7159d5109b013","collapsed":true,"trusted":false},"cell_type":"code","source":"def do_resize(image, H, W):\n    image = cv2.resize(image, dsize=(W, H))\n\n    return image\n\ndef do_resize2(image, mask, H, W):\n    image = cv2.resize(image, dsize=(W, H))\n    mask = cv2.resize(mask, dsize=(W, H))\n    mask = (mask > 0.5).astype(np.float32)\n\n    return image, mask\n\n\n#################################################################\n\ndef compute_center_pad(H, W, factor=32):\n    if H % factor == 0:\n        dy0, dy1 = 0, 0\n    else:\n        dy = factor - H % factor\n        dy0 = dy // 2\n        dy1 = dy - dy0\n\n    if W % factor == 0:\n        dx0, dx1 = 0, 0\n    else:\n        dx = factor - W % factor\n        dx0 = dx // 2\n        dx1 = dx - dx0\n\n    return dy0, dy1, dx0, dx1\n\n\ndef do_center_pad_to_factor(image, factor=32):\n    H, W = image.shape[:2]\n    dy0, dy1, dx0, dx1 = compute_center_pad(H, W, factor)\n\n    image = cv2.copyMakeBorder(image, dy0, dy1, dx0, dx1, cv2.BORDER_REFLECT_101)\n    # cv2.BORDER_CONSTANT, 0)\n    return image\n\n\ndef do_center_pad_to_factor2(image, mask, factor=32):\n    image = do_center_pad_to_factor(image, factor)\n    mask = do_center_pad_to_factor(mask, factor)\n    return image, mask\n\n\n# ---\n\ndef do_horizontal_flip(image):\n    # flip left-right\n    image = cv2.flip(image, 1)\n    return image\n\n\ndef do_horizontal_flip2(image, mask):\n    image = do_horizontal_flip(image)\n    mask = do_horizontal_flip(mask)\n    return image, mask\n\n\n# ---\n\ndef compute_random_pad(H, W, limit=(-4, 4), factor=32):\n    if H % factor == 0:\n        dy0, dy1 = 0, 0\n    else:\n        dy = factor - H % factor\n        dy0 = dy // 2 + np.random.randint(limit[0], limit[1])  # np.random.choice(dy)\n        dy1 = dy - dy0\n\n    if W % factor == 0:\n        dx0, dx1 = 0, 0\n    else:\n        dx = factor - W % factor\n        dx0 = dx // 2 + np.random.randint(limit[0], limit[1])  # np.random.choice(dx)\n        dx1 = dx - dx0\n\n    return dy0, dy1, dx0, dx1\n\n\ndef do_random_pad_to_factor2(image, mask, limit=(-4, 4), factor=32):\n    H, W = image.shape[:2]\n    dy0, dy1, dx0, dx1 = compute_random_pad(H, W, limit, factor)\n\n    image = cv2.copyMakeBorder(image, dy0, dy1, dx0, dx1, cv2.BORDER_REFLECT_101)\n    mask = cv2.copyMakeBorder(mask, dy0, dy1, dx0, dx1, cv2.BORDER_REFLECT_101)\n\n    return image, mask\n\n\n# ----\ndef do_invert_intensity(image):\n    # flip left-right\n    image = np.clip(1 - image, 0, 1)\n    return image\n\n\ndef do_brightness_shift(image, alpha=0.125):\n    image = image + alpha\n    image = np.clip(image, 0, 1)\n    return image\n\n\ndef do_brightness_multiply(image, alpha=1):\n    image = alpha * image\n    image = np.clip(image, 0, 1)\n    return image\n\n\n# https://www.pyimagesearch.com/2015/10/05/opencv-gamma-correction/\ndef do_gamma(image, gamma=1.0):\n    image = image ** (1.0 / gamma)\n    image = np.clip(image, 0, 1)\n    return image\n\n\ndef do_flip_transpose2(image, mask, type=0):\n    # choose one of the 8 cases\n\n    if type == 1:  # rotate90\n        image = image.transpose(1, 0)\n        image = cv2.flip(image, 1)\n\n        mask = mask.transpose(1, 0)\n        mask = cv2.flip(mask, 1)\n\n    if type == 2:  # rotate180\n        image = cv2.flip(image, -1)\n        mask = cv2.flip(mask, -1)\n\n    if type == 3:  # rotate270\n        image = image.transpose(1, 0)\n        image = cv2.flip(image, 0)\n\n        mask = mask.transpose(1, 0)\n        mask = cv2.flip(mask, 0)\n\n    if type == 4:  # flip left-right\n        image = cv2.flip(image, 1)\n        mask = cv2.flip(mask, 1)\n\n    if type == 5:  # flip up-down\n        image = cv2.flip(image, 0)\n        mask = cv2.flip(mask, 0)\n\n    if type == 6:\n        image = cv2.flip(image, 1)\n        image = image.transpose(1, 0)\n        image = cv2.flip(image, 1)\n\n        mask = cv2.flip(mask, 1)\n        mask = mask.transpose(1, 0)\n        mask = cv2.flip(mask, 1)\n\n    if type == 7:\n        image = cv2.flip(image, 0)\n        image = image.transpose(1, 0)\n        image = cv2.flip(image, 1)\n\n        mask = cv2.flip(mask, 0)\n        mask = mask.transpose(1, 0)\n        mask = cv2.flip(mask, 1)\n\n    return image, mask\n\n##================================\ndef do_shift_scale_crop(image, mask, x0=0, y0=0, x1=1, y1=1):\n    # cv2.BORDER_REFLECT_101\n    # cv2.BORDER_CONSTANT\n\n    height, width = image.shape[:2]\n    image = image[y0:y1, x0:x1]\n    mask = mask[y0:y1, x0:x1]\n\n    image = cv2.resize(image, dsize=(width, height))\n    mask = cv2.resize(mask, dsize=(width, height))\n    mask = (mask > 0.5).astype(np.float32)\n    return image, mask\n\n\ndef do_random_shift_scale_crop_pad2(image, mask, limit=0.10):\n    H, W = image.shape[:2]\n\n    dy = int(H * limit)\n    y0 = np.random.randint(0, dy)\n    y1 = H - np.random.randint(0, dy)\n\n    dx = int(W * limit)\n    x0 = np.random.randint(0, dx)\n    x1 = W - np.random.randint(0, dx)\n\n    # y0, y1, x0, x1\n    image, mask = do_shift_scale_crop(image, mask, x0, y0, x1, y1)\n    return image, mask\n\n\n# ===========================================================================\n\ndef do_shift_scale_rotate2(image, mask, dx=0, dy=0, scale=1, angle=0):\n    borderMode = cv2.BORDER_REFLECT_101\n    # cv2.BORDER_REFLECT_101  cv2.BORDER_CONSTANT\n\n    height, width = image.shape[:2]\n    sx = scale\n    sy = scale\n    cc = math.cos(angle / 180 * math.pi) * (sx)\n    ss = math.sin(angle / 180 * math.pi) * (sy)\n    rotate_matrix = np.array([[cc, -ss], [ss, cc]])\n\n    box0 = np.array([[0, 0], [width, 0], [width, height], [0, height], ], np.float32)\n    box1 = box0 - np.array([width / 2, height / 2])\n    box1 = np.dot(box1, rotate_matrix.T) + np.array([width / 2 + dx, height / 2 + dy])\n\n    box0 = box0.astype(np.float32)\n    box1 = box1.astype(np.float32)\n    mat = cv2.getPerspectiveTransform(box0, box1)\n\n    image = cv2.warpPerspective(image, mat, (width, height), flags=cv2.INTER_LINEAR,\n                                borderMode=borderMode, borderValue=(\n        0, 0, 0,))  # cv2.BORDER_CONSTANT, borderValue = (0, 0, 0))  #cv2.BORDER_REFLECT_101\n    mask = cv2.warpPerspective(mask, mat, (width, height), flags=cv2.INTER_NEAREST,  # cv2.INTER_LINEAR\n                               borderMode=borderMode, borderValue=(\n        0, 0, 0,))  # cv2.BORDER_CONSTANT, borderValue = (0, 0, 0))  #cv2.BORDER_REFLECT_101\n    mask = (mask > 0.5).astype(np.float32)\n    return image, mask\n\n\n# https://www.kaggle.com/ori226/data-augmentation-with-elastic-deformations\n# https://github.com/letmaik/lensfunpy/blob/master/lensfunpy/util.py\ndef do_elastic_transform2(image, mask, grid=32, distort=0.2):\n    borderMode = cv2.BORDER_REFLECT_101\n    height, width = image.shape[:2]\n\n    x_step = int(grid)\n    xx = np.zeros(width, np.float32)\n    prev = 0\n    for x in range(0, width, x_step):\n        start = x\n        end = x + x_step\n        if end > width:\n            end = width\n            cur = width\n        else:\n            cur = prev + x_step * (1 + np.random.uniform(-distort, distort))\n\n        xx[start:end] = np.linspace(prev, cur, end - start)\n        prev = cur\n\n    y_step = int(grid)\n    yy = np.zeros(height, np.float32)\n    prev = 0\n    for y in range(0, height, y_step):\n        start = y\n        end = y + y_step\n        if end > height:\n            end = height\n            cur = height\n        else:\n            cur = prev + y_step * (1 + np.random.uniform(-distort, distort))\n\n        yy[start:end] = np.linspace(prev, cur, end - start)\n        prev = cur\n\n    # grid\n    map_x, map_y = np.meshgrid(xx, yy)\n    map_x = map_x.astype(np.float32)\n    map_y = map_y.astype(np.float32)\n\n    # image = map_coordinates(image, coords, order=1, mode='reflect').reshape(shape)\n    image = cv2.remap(image, map_x, map_y, interpolation=cv2.INTER_LINEAR, borderMode=borderMode,\n                      borderValue=(0, 0, 0,))\n\n    mask = cv2.remap(mask, map_x, map_y, interpolation=cv2.INTER_NEAREST, borderMode=borderMode, borderValue=(0, 0, 0,))\n    mask = (mask > 0.5).astype(np.float32)\n    return image, mask\n\n\ndef do_horizontal_shear2(image, mask, dx=0):\n    borderMode = cv2.BORDER_REFLECT_101\n    # cv2.BORDER_REFLECT_101  cv2.BORDER_CONSTANT\n\n    height, width = image.shape[:2]\n    dx = int(dx * width)\n\n    box0 = np.array([[0, 0], [width, 0], [width, height], [0, height], ], np.float32)\n    box1 = np.array([[+dx, 0], [width + dx, 0], [width - dx, height], [-dx, height], ], np.float32)\n\n    box0 = box0.astype(np.float32)\n    box1 = box1.astype(np.float32)\n    mat = cv2.getPerspectiveTransform(box0, box1)\n\n    image = cv2.warpPerspective(image, mat, (width, height), flags=cv2.INTER_LINEAR,\n                                borderMode=borderMode, borderValue=(\n        0, 0, 0,))  # cv2.BORDER_CONSTANT, borderValue = (0, 0, 0))  #cv2.BORDER_REFLECT_101\n    mask = cv2.warpPerspective(mask, mat, (width, height), flags=cv2.INTER_NEAREST,  # cv2.INTER_LINEAR\n                               borderMode=borderMode, borderValue=(\n        0, 0, 0,))  # cv2.BORDER_CONSTANT, borderValue = (0, 0, 0))  #cv2.BORDER_REFLECT_101\n    mask = (mask > 0.5).astype(np.float32)\n    return image, mask\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"27a9e8ff0c1dc15838e4c1ee898a73bf274ddd27","collapsed":true,"trusted":false},"cell_type":"code","source":"def normalize(im):\n    max = np.max(im)\n    min = np.min(im)\n    if (max - min) > 0:\n        im = (im - min) / (max - min)\n    return im\n\ndef basic_augment(image, mask):\n    if np.random.rand() < 0.5:\n        image, mask = do_horizontal_flip2(image, mask)\n        pass\n\n    if np.random.rand() < 0.5:\n        c = np.random.choice(4)\n        if c == 0:\n            image, mask = do_random_shift_scale_crop_pad2(image, mask, 0.2)  # 0.125\n\n        if c == 1:\n            image, mask = do_horizontal_shear2(image, mask, dx=np.random.uniform(-0.07, 0.07))\n            pass\n\n        if c == 2:\n            image, mask = do_shift_scale_rotate2(image, mask, dx=0, dy=0, scale=1, angle=np.random.uniform(0, 15))  # 10\n\n        if c == 3:\n            image, mask = do_elastic_transform2(image, mask, grid=10, distort=np.random.uniform(0, 0.15))  # 0.10\n            pass\n\n    if np.random.rand() < 0.5:\n        c = np.random.choice(3)\n        if c == 0:\n            image = do_brightness_shift(image, np.random.uniform(-0.1, +0.1))\n        if c == 1:\n            image = do_brightness_multiply(image, np.random.uniform(1 - 0.08, 1 + 0.08))\n        if c == 2:\n            image = do_gamma(image, np.random.uniform(1 - 0.08, 1 + 0.08))\n        # if c==1:\n        #     image = do_invert_intensity(image)\n\n    return image, mask\n\nclass Airbus_Dataset():\n\n    def __init__(self, folder_path):\n        self.folder_path = folder_path\n        self.segmentation_df, self.train_imgs, self.test_imgs = self.create_dataset_df(self.folder_path)\n\n    @staticmethod\n    def create_dataset_df(folder_path):\n        '''Create a dataset for a specific dataset folder path'''\n\n        train_path = folder_path + '/train_v2/'\n        test_path = folder_path + '/test_v2/'\n        segmentation_csv = folder_path + '/train_ship_segmentations_v2.csv'\n\n        # 5% of data in the validation set is sufficient for model evaluation\n        segmentation_df = pd.read_csv(segmentation_csv).set_index('ImageId')\n\n        train_imgs = [os.path.join(train_path, id) for id in os.listdir(train_path)]\n        test_imgs = [os.path.join(test_path, id) for id in os.listdir(test_path)]\n\n        return segmentation_df, train_imgs, test_imgs\n    def cut_empty(self, names):\n        return [name for name in names\n            if (type(self.segmentation_df.loc[name.strip().split('/')[-1]]['EncodedPixels']) != float)]\n\n    def yield_dataloader(self, data='train', shuffle=True, seed=1234, num_workers=8, batch_size=32, size=672):\n\n        if data == 'train':\n\n            tr_n, val_n = train_test_split(self.train_imgs, test_size=0.05, random_state=seed)\n\n            tr_n = self.cut_empty(tr_n)\n            val_n = self.cut_empty(val_n)\n            \n#             tr_n = tr_n[:20]\n#             val_n = val_n[:20]\n#             print(len(tr_n), len(val_n))\n            \n            train_dataset = TorchDataset(img_ids=tr_n, df=self.segmentation_df, transform=basic_augment, size=size)\n            train_loader = DataLoader(train_dataset,\n                                      shuffle=shuffle,\n                                      num_workers=num_workers,\n                                      batch_size=batch_size,\n                                      pin_memory=True)\n\n            val_dataset = TorchDataset(img_ids=val_n, df=self.segmentation_df, size=size)\n            val_loader = DataLoader(val_dataset,\n                                    shuffle=shuffle,\n                                    num_workers=num_workers,\n                                    batch_size=batch_size,\n                                    pin_memory=True)\n            return train_loader, val_loader\n\n        elif data == 'test':\n            test_dataset = TorchDataset(img_ids=self.test_imgs, is_test=True, size=size)\n            test_loader = DataLoader(test_dataset,\n                                     shuffle=False,\n                                     num_workers=num_workers,\n                                     batch_size=batch_size,\n                                     pin_memory=True)\n            return test_loader\n\nclass TorchDataset(Dataset):\n\n    def __init__(self, img_ids, size=672, df = None, is_test=False, transform=None):\n        self.img_ids = img_ids\n        self.df = df\n        self.is_test = is_test\n        self.transform = transform\n        self.size = size\n\n    def __len__(self):\n        return len(self.img_ids)\n\n    def get_mask(self, img_id, df):\n        shape = (768, 768)\n        img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n        masks = df.loc[img_id]['EncodedPixels']\n        if (type(masks) == float): return img.reshape(shape)\n        if (type(masks) == str): masks = [masks]\n        for mask in masks:\n            s = mask.split()\n            for i in range(len(s) // 2):\n                start = int(s[2 * i]) - 1\n                length = int(s[2 * i + 1])\n                img[start:start + length] = 1\n        return img.reshape(shape).T\n\n    def load_images(self, img_id):\n        im = normalize(cv2.imread(img_id, cv2.IMREAD_COLOR).astype(np.float32))\n        if not self.is_test:\n            ImageId = img_id.strip().split('/')[-1]\n            mask = self.get_mask(ImageId, self.df)\n            return im, mask, ImageId\n        else:\n            ImageId = img_id.strip().split('/')[-1]\n            return im, ImageId\n\n    def __getitem__(self, index):\n\n        img_id = self.img_ids[index]\n\n        if not self.is_test:\n            im, mask, z= self.load_images(img_id)\n            if self.transform is not None:\n                im, mask = self.transform(im, mask)\n\n            im = cv2.resize(im, (self.size, self.size))\n            mask = np.array(cv2.resize(mask, (self.size ,self.size))>0.5).astype('float32')\n\n            mask = np.expand_dims(mask, 0)\n            mask = torch.from_numpy(mask).float()\n            im = im.transpose((2,0,1))\n            im = torch.from_numpy(im).float()\n\n            return im, mask, z\n        else:\n            im, z = self.load_images(img_id)\n\n            im = cv2.resize(im, (self.size, self.size))\n\n            im = im.transpose((2,0,1))\n            im = torch.from_numpy(im).float()\n            return im, z","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"23614fe3fcc8660753c20f5a43bd222c5df44ace"},"cell_type":"markdown","source":"## show image mask for debug"},{"metadata":{"_uuid":"42d96be714bafb0394bd4e13c1de87b4e8411a54","collapsed":true,"trusted":false},"cell_type":"code","source":"def show_image_mask(im, mask, n=2, label='Image', show=True, cmap='jet', format='channels_last'):\n    im = np.squeeze(im)\n    mask = np.squeeze(mask)\n    if format == 'channels_first':\n        im = im.transpose((0, 2, 3, 1))\n\n    n_batch = im.shape[0]\n    # idx = np.random.choice(np.arange(n_batch), n, replace=False)\n    idx = range(n_batch)\n    fig, axs = plt.subplots(2, n)\n    for i in range(n):\n        axs[0, i].imshow(im[idx[i], :, :, :], cmap=cmap)\n        axs[0, i].set_title('{}: {}'.format(label, i))\n        axs[1, i].imshow(mask[idx[i], :, :], cmap=cmap)\n        axs[1, i].set_title('mask: {}'.format(i))\n    if show:\n        plt.show()\n\ndef show_test_images(im, n=2, label='Image', show=True, cmap='jet', format='channels_first'):\n    im = np.squeeze(im)\n    if format == 'channels_first':\n        im = im.transpose((0, 2, 3, 1))\n    n_batch = im.shape[0]\n    # idx = np.random.choice(np.arange(n_batch), n, replace=False)\n    idx = range(n_batch)\n    fig, axs = plt.subplots(1, n)\n    for i in range(n):\n        axs[i].imshow(im[idx[i], :, :, :], cmap=cmap)\n        axs[i].set_title('{}: {}'.format(label, i))\n    if show:\n        plt.show()\n\nFOLDER_PATH = '../input'\n\ndataset = Airbus_Dataset(FOLDER_PATH)\ntrain_loader, val_loader = dataset.yield_dataloader(data='train', shuffle=True, seed=1234, num_workers=1, batch_size=2)\ntest_loader = dataset.yield_dataloader(data='test', shuffle=False, seed=42, num_workers=1, batch_size=2)\n\nfor i, (img, mask, z) in enumerate(train_loader):\n    img = img.numpy().transpose((0, 2, 3, 1))\n    mask = mask.numpy().transpose((0, 2, 3, 1))\n    reimg = np.array([cv2.resize(i, (224,224)) for i in img])\n    remask = np.array([cv2.resize(i, (224,224)) > 0.5 for i in mask]).astype('float32')\n    show_image_mask(img, mask)\n    show_image_mask(reimg, remask)\n    if i >4:\n        break\nfor i, (img, mask, z) in enumerate(val_loader):\n    img = img.numpy().transpose((0, 2, 3, 1))\n    mask = mask.numpy().transpose((0, 2, 3, 1))\n    reimg = np.array([cv2.resize(i, (224,224)) for i in img])\n    remask = np.array([cv2.resize(i, (224,224)) > 0.5 for i in mask]).astype('float32')\n    show_image_mask(img, mask)\n    show_image_mask(reimg, remask)\n    if i >4:\n        break\nfor i, (img, z) in enumerate(test_loader):\n    ti = img.numpy()\n    show_test_images(ti)\n    if i >4:\n        break","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a776027a6aba3ad859d6d603a815f99aba52f637"},"cell_type":"markdown","source":"## Analysis"},{"metadata":{"_uuid":"f00e77de1fe0138680828a9cf9e1dde6992ae6af","collapsed":true,"trusted":false},"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\n\ndef show_image_mask(im, mask, n=3, label='Image', show=True, cmap='jet', format='channels_first'):\n    im = np.squeeze(im)\n    mask = np.squeeze(mask)\n    if format == 'channels_first':\n        im = im.transpose((0, 2, 3, 1))\n\n    n_batch = im.shape[0]\n    idx = np.random.choice(np.arange(n_batch), n, replace=False)\n    fig, axs = plt.subplots(2, n)\n    for i in range(n):\n        axs[0, i].imshow(im[idx[i], :, :, :], cmap=cmap)\n        axs[0, i].set_title('{}: {}'.format(label, i))\n        axs[1, i].imshow(mask[idx[i], :, :], cmap=cmap)\n        axs[1, i].set_title('mask: {}'.format(i))\n    if show:\n        plt.show()\n\ndef show_image_mask_pred(im, mask, logit,  n=3, label='Image', show=True, cmap='gray', format='channels_first'):\n    mask = np.squeeze(mask)\n    logit = np.squeeze(logit)\n\n    if format == 'channels_first':\n        if im.shape[1] == 1:\n            im = np.squeeze(im)\n            im_cmap = 'gray'\n        else:\n            im = im.transpose((0, 2, 3, 1))\n            im_cmap = None\n\n    n_batch = im.shape[0]\n    idx = np.random.choice(np.arange(n_batch), n, replace=False)\n    fig, axs = plt.subplots(3, n)\n    for i in range(n):\n        axs[0, i].imshow(im[idx[i]], cmap=im_cmap)\n        axs[0, i].set_title('{}: {}'.format(label, i))\n        axs[1, i].imshow(mask[idx[i]], cmap=cmap)\n        axs[1, i].set_title('mask: {}'.format(i))\n        axs[2, i].imshow(logit[idx[i]], cmap=cmap)\n        axs[2, i].set_title('logit: {}'.format(i))\n    if show:\n        plt.show\n\ndef show_image_tta_pred(im, tta_im, logit, tta_logit,  n=3, label='Image', show=True, cmap='gray', format='channels_first'):\n    logit = np.squeeze(logit)\n    tta_logit = np.squeeze(tta_logit)\n\n    if format == 'channels_first':\n        if im.shape[1] == 1:\n            im = np.squeeze(im)\n            tta_im = np.squeeze(tta_im)\n            im_cmap = 'gray'\n        else:\n            im = im.transpose((0, 2, 3, 1))\n            tta_im = tta_im.transpose((0, 2, 3, 1))\n            im_cmap = None\n\n    n_batch = im.shape[0]\n    idx = np.random.choice(np.arange(n_batch), n, replace=False)\n    fig, axs = plt.subplots(n, 4)\n    for i in range(n):\n        axs[i, 0].imshow(im[idx[i]], cmap=im_cmap)\n        axs[i, 0].set_title('{}: {}'.format(label, i))\n        axs[i, 1].imshow(logit[idx[i]], cmap=cmap)\n        axs[i, 1].set_title('logit: {}'.format(i))\n        axs[i, 2].imshow(tta_im[idx[i]], cmap=im_cmap)\n        axs[i, 2].set_title('TTA {}: {}'.format(label, i))\n        axs[i, 3].imshow(tta_logit[idx[i]], cmap=cmap)\n        axs[i, 3].set_title('TTA logit: {}'.format(i))\n    if show:\n        plt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c7ad6ad95ed5487d911ae95a92631bee4075ceb1"},"cell_type":"markdown","source":"# define model"},{"metadata":{"_uuid":"3712ce34202531f53a605ebd7e5a676b533260a9"},"cell_type":"markdown","source":"## Decode v3"},{"metadata":{"_uuid":"c00200b169204dbf8dc7e5032e5ba41becfb565f","collapsed":true,"trusted":false},"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nclass ConvBn2d(nn.Module):\n    def __init__(self, in_channels, out_channels,\n                 kernel_size=(3, 3), stride=(1, 1),\n                 padding=(1, 1), groups=1, dilation=1):\n        super(ConvBn2d, self).__init__()\n        self.conv = nn.Conv2d(in_channels, out_channels,\n                              kernel_size=kernel_size,\n                              stride=stride,\n                              padding=padding,\n                              bias=False,\n                              groups=groups,\n                              dilation=dilation)\n        self.bn = nn.BatchNorm2d(out_channels)\n\n    def forward(self, x):\n        x = self.conv(x)\n        x = self.bn(x)\n        return x\n\nclass SpatialGate2d(nn.Module):\n\n    def __init__(self, in_channels):\n        super(SpatialGate2d, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels, 1, kernel_size=1, stride=1)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        cal = self.conv1(x)\n        cal = self.sigmoid(cal)\n        return cal * x\n\nclass ChannelGate2d(nn.Module):\n\n    def __init__(self, channels, reduction=2):\n        super(ChannelGate2d, self).__init__()\n        self.avg_pool = nn.AdaptiveAvgPool2d(1)\n        self.fc1 = nn.Conv2d(channels, channels // reduction, kernel_size=1,\n                             padding=0)\n        self.relu = nn.ReLU(inplace=True)\n        self.fc2 = nn.Conv2d(channels // reduction, channels, kernel_size=1,\n                             padding=0)\n\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        module_input = x\n        x = self.avg_pool(x)\n        x = self.fc1(x)\n        x = self.relu(x)\n        x = self.fc2(x)\n        x = self.sigmoid(x)\n\n        return module_input * x\n\nclass scSqueezeExcitationGate(nn.Module):\n    def __init__(self, channels, reduction=16):\n        super(scSqueezeExcitationGate, self).__init__()\n        self.spatial_gate = SpatialGate2d(channels)\n        self.channel_gate = ChannelGate2d(channels, reduction=reduction)\n\n    def  forward(self, x, z=None):\n        XsSE = self.spatial_gate(x)\n        XcSe = self.channel_gate(x)\n        return XsSE + XcSe\n    \nclass Decoder_v3(nn.Module):\n    def __init__(self, in_channels, convT_channels, out_channels, convT_ratio=2, SE=False):\n        super(Decoder_v3, self).__init__()\n        self.relu = nn.ReLU(inplace=True)\n        self.SE = SE\n        self.convT = nn.ConvTranspose2d(convT_channels, convT_channels // convT_ratio, kernel_size=2, stride=2)\n        self.conv1 = ConvBn2d(in_channels  + convT_channels // convT_ratio, out_channels)\n        self.conv2 = ConvBn2d(out_channels, out_channels)\n        if SE:\n            self.scSE = scSqueezeExcitationGate(out_channels)\n\n        self.conv_res = nn.Conv2d(convT_channels // convT_ratio, out_channels, kernel_size=1, padding=0)\n\n    def forward(self, x, skip):\n        x = self.convT(x)\n        residual = x\n        x = torch.cat([x, skip], 1)\n        x = self.conv1(x)\n        x = self.relu(x)\n        x = self.conv2(x)\n        if self.SE:\n            x = self.scSE(x)\n        x += self.conv_res(residual)\n        x = self.relu(x)\n        return x\nclass CenterBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, pool=True, SE=False):\n        super(CenterBlock, self).__init__()\n        self.SE = SE\n        self.pool = pool\n        self.relu = nn.ReLU(inplace=True)\n        self.conv1 = ConvBn2d(in_channels, out_channels, kernel_size=3, padding=1)\n        self.conv2 = ConvBn2d(out_channels, out_channels, kernel_size=3, padding=1)\n        self.conv_res = nn.Conv2d(in_channels, out_channels, kernel_size=1, padding=0)\n        if SE:\n            self.se = scSqueezeExcitationGate(out_channels)\n\n    def forward(self, x):\n        if self.pool:\n            x = F.max_pool2d(x, kernel_size=2, stride=2)\n        residual = self.conv_res(x)\n        x = self.conv1(x)\n        x = self.relu(x)\n        x = self.conv2(x)\n\n        if self.SE:\n            x = self.se(x)\n\n        x += residual\n        x = self.relu(x)\n        return x","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"acc160736afeef85a6cc6937d899553325cc94ec"},"cell_type":"markdown","source":"## FPAModule"},{"metadata":{"_uuid":"4250d9e4e0e54e4a089328bc8cd960790abfa5cf","collapsed":true,"trusted":false},"cell_type":"code","source":"class Conv2dBnRelu(nn.Module):\n\n    def __init__(self, in_ch, out_ch, kernel_size=3, stride=1, padding=0, dilation=1, bias=True):\n        super(Conv2dBnRelu, self).__init__()\n\n        self.conv = nn.Sequential(\n            nn.Conv2d(in_ch, out_ch, kernel_size, stride, padding, dilation=dilation, bias=bias),\n            nn.BatchNorm2d(out_ch),\n            nn.ReLU(inplace=True)\n        )\n\n    def forward(self, x):\n        return self.conv(x)\n\nclass Conv2dBn(nn.Module):\n\n    def __init__(self, in_ch, out_ch, kernel_size=3, stride=1, padding=0, dilation=1, bias=True):\n        super(Conv2dBn, self).__init__()\n\n        self.conv = nn.Sequential(\n            nn.Conv2d(in_ch, out_ch, kernel_size, stride, padding, dilation=dilation, bias=bias),\n            nn.BatchNorm2d(out_ch)\n        )\n\n    def forward(self, x):\n        return self.conv(x)\nclass FPAModule1(nn.Module):\n\n    def __init__(self, in_ch, out_ch):\n        super(FPAModule1, self).__init__()\n\n        # global pooling branch\n        self.branch1 = nn.Sequential(\n            nn.AdaptiveAvgPool2d(1),\n            Conv2dBnRelu(in_ch, out_ch, kernel_size=1, stride=1, padding=0)\n        )\n\n        # midddle branch\n        self.mid = nn.Sequential(\n            Conv2dBnRelu(in_ch, out_ch, kernel_size=1, stride=1, padding=0)\n        )\n\n        self.down1 = nn.Sequential(\n            nn.MaxPool2d(kernel_size=2, stride=2),\n            Conv2dBnRelu(in_ch, out_ch, kernel_size=7, stride=1, padding=3)\n        )\n\n        self.down2 = nn.Sequential(\n            nn.MaxPool2d(kernel_size=2, stride=2),\n            Conv2dBnRelu(out_ch, out_ch, kernel_size=5, stride=1, padding=2)\n        )\n\n        self.down3 = nn.Sequential(\n            nn.MaxPool2d(kernel_size=2, stride=2),\n            Conv2dBnRelu(out_ch, out_ch, kernel_size=3, stride=1, padding=1),\n            Conv2dBnRelu(out_ch, out_ch, kernel_size=3, stride=1, padding=1),\n        )\n\n        self.conv2 = Conv2dBnRelu(out_ch, out_ch, kernel_size=5, stride=1, padding=2)\n        self.conv1 = Conv2dBnRelu(out_ch, out_ch, kernel_size=7, stride=1, padding=3)\n\n    def forward(self, x):\n        h, w = x.size(2), x.size(3)\n        b1 = self.branch1(x)\n        b1 = nn.Upsample(size=(h, w), mode='bilinear', align_corners=True)(b1)\n\n        mid = self.mid(x)\n\n        x1 = self.down1(x)\n        x2 = self.down2(x1)\n        x3 = self.down3(x2)\n        x3 = nn.Upsample(size=(h // 4, w // 4), mode='bilinear', align_corners=True)(x3)\n\n        x2 = self.conv2(x2)\n        x = x2 + x3\n        x = nn.Upsample(size=(h // 2, w // 2), mode='bilinear', align_corners=True)(x)\n\n        x1 = self.conv1(x1)\n        x = x + x1\n        x = nn.Upsample(size=(h, w), mode='bilinear', align_corners=True)(x)\n\n        x = torch.mul(x, mid)\n        x = x + b1\n        return x","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"43f5514754961c05b4e5666b0dd626c4ce67d99e"},"cell_type":"markdown","source":"## Segmentation Network"},{"metadata":{"_uuid":"655c20453f5b53dd5d656d78cb9195d94bb63a1f","collapsed":true,"trusted":false},"cell_type":"code","source":"import torch.optim as optim\nimport torch.nn as nn\nimport torch\n\nfrom contextlib import contextmanager\nimport datetime\nimport  time\nimport os\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\n@contextmanager\ndef timer(title):\n    t0 = time.time()\n    yield\n    print(\"{} - done in {:.3f}s\".format(title, time.time() - t0))\n\n\nclass SegmentationNetwork(nn.Module):\n\n    def __init__(self, lr=0.005, fold=None, debug=False, val_mode='max', comment=''):\n        super(SegmentationNetwork, self).__init__()\n        self.lr = lr\n        self.fold = fold\n        self.debug = debug\n        self.scheduler = None\n        self.best_model_path = None\n        self.epoch = 0\n        self.val_mode = val_mode\n        self.comment = comment\n\n        if self.val_mode == 'max':\n            self.best_metric = -np.inf\n        elif self.val_mode == 'min':\n            self.best_metric = np.inf\n\n        self.train_log = dict(loss=[], iou=[], mAP=[])\n        self.val_log = dict(loss=[], iou=[], mAP=[])\n        self.create_save_folder()\n\n    def create_optmizer(self, optimizer='SGD', use_scheduler=None, gamma=0.25, patience=4,\n                        milestones=None, T_max=10, T_mul=2, lr_min=0):\n        self.cuda()\n        if optimizer == 'SGD':\n            self.optimizer = optim.SGD(filter(lambda p: p.requires_grad, self.parameters()),\n                                  lr=self.lr, momentum=0.9, weight_decay=0.0001)\n        elif optimizer == 'Adam':\n            self.optimizer = optim.Adam(filter(lambda p: p.requires_grad,\n                       self.parameters()), lr=self.lr)\n\n        if use_scheduler == 'ReduceOnPlateau':\n            self.scheduler = optim.lr_scheduler.ReduceLROnPlateau(self.optimizer,\n                                                                  mode='max',\n                                                                  factor=gamma,\n                                                                  patience=patience,\n                                                                  verbose=True,\n                                                                  threshold=0.01,\n                                                                  min_lr=1e-05,\n                                                                  eps=1e-08)\n\n        elif use_scheduler == 'Milestones':\n            self.scheduler = optim.lr_scheduler.MultiStepLR(self.optimizer,\n                                                            milestones=milestones,\n                                                            gamma=gamma,\n                                                            last_epoch=-1)\n\n        elif use_scheduler == 'CosineAnneling':\n            self.scheduler = CosineAnnealingLR(self.optimizer,\n                                                         T_max=T_max,\n                                                         T_mul=T_mul,\n                                                         lr_min=lr_min,\n                                                         val_mode=self.val_mode,\n                                                         last_epoch=-1,\n                                                         save_snapshots=True)\n\n\n    def train_network(self, train_loader, val_loader, n_epoch=10):\n        print('Model created, total of {} parameters'.format(\n            sum(p.numel() for p in self.parameters())))\n        while self.epoch < n_epoch:\n            self.epoch += 1\n            lr = np.mean([param_group['lr'] for param_group in self.optimizer.param_groups])\n            with timer('Train Epoch {:}/{:} - LR: {:.3E}'.format(self.epoch, n_epoch, lr)):\n                # Training step\n                train_loss, train_iou, train_mAP = self.training_step(train_loader)\n                #  Validation\n                val_loss, val_iou, val_mAP = self.perform_validation(val_loader)\n                # Learning Rate Scheduler\n                if self.scheduler is not None:\n                    if type(self.scheduler).__name__ == 'ReduceLROnPlateau':\n                        self.scheduler.step(np.mean(val_mAP))\n                    elif type(self.scheduler).__name__ == 'CosineAnnealingLR':\n                        self.scheduler.step(self.epoch,\n                                            save_dict=dict(metric=np.mean(val_loss),\n                                                           save_dir=self.save_dir,\n                                                           fold=self.fold,\n                                                           state_dict=self.state_dict()))\n                    else:\n                        self.scheduler.step(self.epoch)\n                # Save best model\n                if type(self.scheduler).__name__ != 'CosineAnnealingLR':\n                    self.save_best_model(np.mean(val_mAP))\n\n            # Print statistics\n            print(('train loss: {:.3f}  val_loss: {:.3f}  '\n                   'train iou:  {:.3f}  val_iou:  {:.3f}  '\n                   'train mAP:  {:.3f}  val_mAP:  {:.3f}').format(\n                np.mean(train_loss),\n                np.mean(val_loss),\n                np.mean(train_iou),\n                np.mean(val_iou),\n                np.mean(train_mAP),\n                np.mean(val_mAP)))\n\n        self.save_training_log()\n\n    def training_step(self, train_loader):\n        self.set_mode('train')\n        train_loss = []\n        train_iou = []\n        train_mAP = []\n        for i, (im, mask, z) in enumerate(train_loader):\n            self.optimizer.zero_grad()\n            im = im.cuda()\n            mask = mask.cuda()\n            logit = self.forward(im)\n            pred = torch.sigmoid(logit)\n\n            loss = self.criterion(logit, mask)\n            iou  = dice_accuracy(pred, mask, is_average=False)\n            mAP = do_mAP(pred.data.cpu().numpy(), mask.cpu().numpy())\n\n            train_loss.append(loss.item())\n            train_iou.extend(iou)\n            train_mAP.extend(mAP)\n\n            loss.backward()\n            self.optimizer.step()\n\n            if self.debug and not self.epoch % 5 and not i % 30:\n                show_image_mask_pred(\n                    im.cpu().data.numpy(), mask.cpu().data.numpy(), logit.cpu().data.numpy())\n        # Append epoch data to metrics dict\n        for metric in ['loss', 'iou', 'mAP']:\n            self.train_log[metric].append(np.mean(eval('train_{}'.format(metric))))\n        return train_loss, train_iou, train_mAP\n\n\n    def perform_validation(self, val_loader):\n        self.set_mode('valid')\n        val_loss = []\n        val_iou = []\n        val_mAP = []\n        for im, mask, z in val_loader:\n            im = im.cuda()\n            mask = mask.cuda()\n\n            with torch.no_grad():\n                logit = self.forward(im)\n                pred = torch.sigmoid(logit)\n                loss = self.criterion(logit, mask)\n                iou  = dice_accuracy(pred, mask, is_average=False)\n                mAP = do_mAP(pred.cpu().numpy(), mask.cpu().numpy())\n\n            val_loss.append(loss.item())\n            val_iou.extend(iou)\n            val_mAP.extend(mAP)\n        # Append epoch data to metrics dict\n        for metric in ['loss', 'iou', 'mAP']:\n            self.val_log[metric].append(np.mean(eval('val_{}'.format(metric))))\n\n        return val_loss, val_iou, val_mAP\n\n\n    def predict(self, test_loader, return_rle=False, tta_transform=None, threshold=0.45):\n        self.set_mode('test')\n        self.cuda()\n        for i, (im, z) in enumerate(test_loader):\n            with torch.no_grad():\n                # Apply TTA and predict\n                batch_pred = []\n                # TTA\n                if tta_transform is not None:\n                    tta_list = torch.FloatTensor(tta_transform(im.cpu().numpy(), mode='in'))\n                    tta_pred = []\n                    for t_im in tta_list:\n                        t_im = t_im.cuda()\n                        t_logit = self.forward(t_im)\n                        pred = torch.sigmoid(t_logit)\n                        pred = unpad_im(pred.cpu().numpy())\n                        tta_pred.append(pred)\n                    batch_pred.extend(tta_transform(tta_pred, mode='out'))\n\n                # Predict original batch\n                im = im.cuda()\n                logit = self.forward(im)\n                pred = torch.sigmoid(logit)\n                pred = unpad_im(pred.cpu().numpy())\n                batch_pred.append(pred)\n\n                # Average TTA results\n                batch_pred = np.mean(batch_pred, 0)\n                # Threshold result\n                if threshold > 0:\n                    batch_pred = batch_pred > threshold\n\n                if return_rle:\n                    batch_pred = batch_encode(batch_pred)\n\n                if not i:\n                    out = batch_pred\n                    ids = z\n                else:\n                    out = np.concatenate([out, batch_pred], axis=0)\n                    ids = np.concatenate([ids, z], axis=0)\n\n                if self.debug:\n                    show_image_tta_pred(\n                        im.cpu().data.numpy(), t_im.cpu().data.numpy(),\n                        logit.cpu().data.numpy(), t_logit.cpu().data.numpy())\n\n        if return_rle:\n            out = dict(id=ids, rle_mask=out)\n            out = pd.DataFrame(out)\n        else:\n            out = dict(id=ids, pred=out)\n        return out\n\n\n    def define_criterion(self, name):\n        if name.lower() == 'bce+dice':\n            self.criterion = BCE_Dice()\n        elif name.lower() == 'dice':\n            self.criterion = DiceLoss()\n        elif name.lower() == 'bce':\n            self.criterion = nn.BCEWithLogitsLoss()\n        elif name.lower() == 'robustfocal':\n            self.criterion = RobustFocalLoss2d()\n        elif name.lower() == 'lovasz-hinge' or name.lower() == 'lovasz':\n            self.criterion = Lovasz_Hinge(per_image=True)\n        elif name.lower() == 'bce+lovasz':\n            self.criterion = BCE_Lovasz(per_image=True)\n        else:\n            raise NotImplementedError('Loss {} is not implemented'.format(name))\n\n\n    def set_mode(self, mode):\n        self.mode = mode\n        if mode in ['eval', 'valid', 'test']:\n            self.eval()\n        elif mode in ['train']:\n            self.train()\n        else:\n            raise NotImplementedError\n\n\n    def save_best_model(self, metric):\n        if (self.val_mode == 'max' and metric > self.best_metric) or (self.val_mode == 'min' and metric < self.best_metric):\n            # Update best metric\n            self.best_metric = metric\n            # Remove old file\n            if self.best_model_path is not None:\n                os.remove(self.best_model_path)\n            # Save new best model weights\n            date = ':'.join(str(datetime.datetime.now()).split(':')[:2])\n#             if self.fold is not None:\n#                 self.best_model_path = os.path.join(\n#                     self.save_dir,\n#                     '{:}_Fold{:}_Epoach{}_val{:.3f}'.format(date, self.fold, self.epoch, metric))\n#             else:\n#                 self.best_model_path = os.path.join(\n#                     self.save_dir,\n#                     '{:}_Epoach{}_val{:.3f}'.format(date, self.epoch, metric))\n            if self.fold is not None:\n                self.best_model_path = os.path.join(\n                    self.save_dir,\n                    'Fold{:}_Epoach{}_val{:.3f}'.format(self.fold, self.epoch, metric))\n            else:\n                self.best_model_path = os.path.join(\n                    self.save_dir,\n                    'Epoach{}_val{:.3f}'.format(self.epoch, metric))\n\n            torch.save(self.state_dict(), self.best_model_path)\n\n\n    def save_training_log(self):\n        d = dict()\n        for tk, vk in zip(self.train_log.keys(), self.val_log.keys()):\n            d['train_{}'.format(tk)] = self.train_log[tk]\n            d['val_{}'.format(vk)] = self.val_log[vk]\n\n        df = pd.DataFrame(d)\n        df.index += 1\n        df.index.name = 'Epoach'\n\n        date = ':'.join(str(datetime.datetime.now()).split(':')[:2])\n#         if self.fold is not None:\n#             p = os.path.join(\n#                 self.save_dir,\n#                 '{:}_Fold{:}_TrainLog.csv'.format(date, self.fold))\n#         else:\n#             p = os.path.join(\n#                 self.save_dir,\n#                 '{:}_TrainLog.csv'.format(date))\n        if self.fold is not None:\n            p = os.path.join(\n                self.save_dir,\n                'Fold{:}_TrainLog.csv'.format(self.fold))\n        else:\n            p = os.path.join(\n                self.save_dir,\n                'TrainLog.csv')\n\n        df.to_csv(p, sep=\";\")\n\n        with open(p, 'a') as fd:\n            fd.write(self.comment)\n\n\n    def load_model(self, path=None, best_model=False):\n        if best_model:\n            self.load_state_dict(torch.load(self.best_model_path))\n        else:\n            self.load_state_dict(torch.load(path))\n\n    def create_save_folder(self):\n        name = type(self).__name__\n        #self.save_dir = os.path.join('./Saves', name)\n        self.save_dir = './'\n        #if not os.path.exists(self.save_dir):\n        #    os.makedirs(self.save_dir)\n\n    def plot_training_curve(self, show=True):\n        fig, axs = plt.subplots(3, 1)\n        for i, metric in enumerate(['loss', 'iou', 'mAP']):\n            axs[i].plot(self.train_log[metric], 'y', label='Train')\n            axs[i].plot(self.val_log[metric], 'b', label='Validation')\n            if metric == 'loss':\n                min = np.argmin(self.val_log[metric])\n                axs[i].plot(min, self.val_log[metric][min], \"xr\", label='best_loss')\n            else:\n                max = np.argmax(self.val_log[metric])\n                axs[i].plot(max, self.val_log[metric][max], \"xr\", label='best_{}'.format(metric))\n            axs[i].legend()\n            axs[i].set_title(metric)\n            axs[i].set_xlabel('Epochs')\n            axs[i].set_ylabel(metric)\n        if show:\n            plt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c7635eb7d8656a45c9ac54f47fa05429ab6dbb26"},"cell_type":"markdown","source":"## UNetResNet34_SE_Hyper_PFA"},{"metadata":{"_uuid":"f91307ebff7ea983837ebe9e0b2bf205d45fc0ed","collapsed":true,"trusted":false},"cell_type":"code","source":"import torch.nn as nn\nimport math\nimport torch.utils.model_zoo as model_zoo\nimport torch.nn.functional as F\nimport torch\n\n__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',\n           'resnet152']\n\nmodel_urls = {\n    'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',\n    'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',\n    'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',\n    'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',\n    'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',\n}\n\n\ndef conv3x3(in_planes, out_planes, stride=1):\n    \"\"\"3x3 convolution with padding\"\"\"\n    return nn.Conv2d(in_planes, out_planes,\n                     kernel_size=3, stride=stride,\n                     padding=1, bias=False)\n\n\nclass ChannelGate2d(nn.Module):\n\n    def __init__(self, channels, reduction=2):\n        super(ChannelGate2d, self).__init__()\n        self.avg_pool = nn.AdaptiveAvgPool2d(1)\n        self.fc1 = nn.Conv2d(channels, channels // reduction, kernel_size=1,\n                             padding=0)\n        self.relu = nn.ReLU(inplace=True)\n        self.fc2 = nn.Conv2d(channels // reduction, channels, kernel_size=1,\n                             padding=0)\n\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        module_input = x\n        x = self.avg_pool(x)\n        x = self.fc1(x)\n        x = self.relu(x)\n        x = self.fc2(x)\n        x = self.sigmoid(x)\n\n        return module_input * x\n\n\nclass BasicBlock(nn.Module):\n    expansion = 1\n\n    def __init__(self, inplanes, planes, stride=1, downsample=None, activation=None, SE=False):\n        super(BasicBlock, self).__init__()\n        self.SE = SE\n        if activation is None:\n            self.activation = nn.ReLU(inplace=True)\n        else:\n            self.activation = activation\n\n        self.conv1 = conv3x3(inplanes, planes, stride)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.conv2 = conv3x3(planes, planes)\n        self.bn2 = nn.BatchNorm2d(planes)\n        self.downsample = downsample\n        self.stride = stride\n        if SE:\n            self.cSE = ChannelGate2d(planes, reduction=16)\n\n    def forward(self, x):\n        residual = x\n\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.activation(out)\n\n        out = self.conv2(out)\n        out = self.bn2(out)\n\n        if self.downsample is not None:\n            residual = self.downsample(x)\n\n        if self.SE:\n            out = self.cSE(out)\n\n        out += residual\n        out = self.activation(out)\n\n        return out\n\n\nclass Bottleneck(nn.Module):\n    expansion = 4\n\n    def __init__(self, inplanes, planes, stride=1, downsample=None, activation=None, SE=False):\n        super(Bottleneck, self).__init__()\n        self.SE = SE\n        if activation is None:\n            self.activation = nn.ReLU(inplace=True)\n        else:\n            self.activation = activation\n\n        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,\n                               padding=1, bias=False)\n        self.bn2 = nn.BatchNorm2d(planes)\n        self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * 4)\n        self.downsample = downsample\n        self.stride = stride\n        if SE:\n            self.cSE = ChannelGate2d(planes, reduction=16)\n\n    def forward(self, x):\n        residual = x\n\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.activation(out)\n\n        out = self.conv2(out)\n        out = self.bn2(out)\n        out = self.activation(out)\n\n        out = self.conv3(out)\n        out = self.bn3(out)\n\n        if self.downsample is not None:\n            residual = self.downsample(x)\n\n        if self.SE:\n            out = self.cSE(out)\n\n        out += residual\n        out = self.activation(out)\n\n        return out\n\n\nclass ResNet(nn.Module):\n\n    def __init__(self, block, layers, activation=None, num_classes=1000, SE=False):\n        super(ResNet, self).__init__()\n\n        self.SE = SE\n        self.inplanes = 64\n        if activation is None:\n            self.activation = nn.ReLU(inplace=True)\n        else:\n            self.activation = activation\n\n        self.conv1 = nn.Conv2d(3, 64, kernel_size=7,\n                               stride=1, padding=3, bias=False)\n        self.bn1 = nn.BatchNorm2d(64)\n        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)\n        self.layer1 = self._make_layer(block, 64, layers[0])\n        self.layer2 = self._make_layer(block, 128, layers[1], stride=2)\n        self.layer3 = self._make_layer(block, 256, layers[2], stride=2)\n        self.layer4 = self._make_layer(block, 512, layers[3], stride=2)\n        self.avgpool = nn.AvgPool2d(7, stride=1)\n        self.fc = nn.Linear(512 * block.expansion, num_classes)\n\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels\n                m.weight.data.normal_(0, math.sqrt(2. / n))\n            elif isinstance(m, nn.BatchNorm2d):\n                m.weight.data.fill_(1)\n                m.bias.data.zero_()\n\n    def _make_layer(self, block, planes, blocks, stride=1):\n        downsample = None\n        if stride != 1 or self.inplanes != planes * block.expansion:\n            downsample = nn.Sequential(\n                nn.Conv2d(self.inplanes, planes * block.expansion,\n                          kernel_size=1, stride=stride, bias=False),\n                nn.BatchNorm2d(planes * block.expansion),\n            )\n\n        layers = []\n        layers.append(block(self.inplanes, planes, stride, downsample, activation=self.activation, SE=self.SE))\n        self.inplanes = planes * block.expansion\n        for i in range(1, blocks):\n            layers.append(block(self.inplanes, planes, activation=self.activation, SE=self.SE))\n\n        return nn.Sequential(*layers)\n\n    def forward(self, x):\n        x = self.conv1(x)\n        x = self.bn1(x)\n        x = self.activation(x)\n        x = self.maxpool(x)\n\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)\n\n        x = self.avgpool(x)\n        x = x.view(x.size(0), -1)\n        x = self.fc(x)\n\n        return x\n\n\ndef resnet18(pretrained=False, **kwargs):\n    \"\"\"Constructs a ResNet-18 model.\n\n    Args:\n        pretrained (bool): If True, returns a model pre-trained on ImageNet\n    \"\"\"\n    model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs)\n    if pretrained:\n        model.load_state_dict(model_zoo.load_url(model_urls['resnet18']))\n    return model\n\n\ndef resnet34(pretrained=False, **kwargs):\n    \"\"\"Constructs a ResNet-34 model.\n\n    Args:\n        pretrained (bool): If True, returns a model pre-trained on ImageNet\n    \"\"\"\n    model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs)\n    if pretrained:\n        model.load_state_dict(model_zoo.load_url(model_urls['resnet34']), strict=False)\n    return model\n\n\ndef resnet50(pretrained=False, **kwargs):\n    \"\"\"Constructs a ResNet-50 model.\n\n    Args:\n        pretrained (bool): If True, returns a model pre-trained on ImageNet\n    \"\"\"\n    model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs)\n    if pretrained:\n        model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))\n    return model\n\n\ndef resnet101(pretrained=False, **kwargs):\n    \"\"\"Constructs a ResNet-101 model.\n\n    Args:\n        pretrained (bool): If True, returns a model pre-trained on ImageNet\n    \"\"\"\n    model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs)\n    if pretrained:\n        model.load_state_dict(model_zoo.load_url(model_urls['resnet101']))\n    return model\n\n\ndef resnet152(pretrained=False, **kwargs):\n    \"\"\"Constructs a ResNet-152 model.\n\n    Args:\n        pretrained (bool): If True, returns a model pre-trained on ImageNet\n    \"\"\"\n    model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs)\n    if pretrained:\n        model.load_state_dict(model_zoo.load_url(model_urls['resnet152']))\n    return model\n\n\ndef load_pretrain_file(net, pretrain_file, skip=['cSE']):\n    pretrain_state_dict = torch.load(pretrain_file)\n    state_dict = net.state_dict()\n    keys = list(state_dict.keys())\n    for key in keys:\n        if any(s in key for s in skip):\n            continue\n        else:\n            state_dict[key] = pretrain_state_dict[key]","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fb74de2b45824c72c5571e5263ed87f5b5598e77","collapsed":true,"trusted":false},"cell_type":"code","source":"class UNetResNet34_SE_Hyper_FPA(SegmentationNetwork):\n    # PyTorch U-Net model using ResNet(34, 50 , 101 or 152) encoder.\n\n    def __init__(self, pretrained=True, activation='relu', **kwargs):\n        super(UNetResNet34_SE_Hyper_FPA, self).__init__(**kwargs)\n        if activation == 'relu':\n            self.activation = nn.ReLU(inplace=True)\n        elif activation == 'elu':\n            self.activation = ELU_1(inplace=True)\n\n        self.resnet = resnet34(pretrained=pretrained, activation=self.activation, SE=True)\n\n        self.conv1 = nn.Sequential(\n            self.resnet.conv1,\n            self.resnet.bn1,\n            self.resnet.activation,\n        )  # 64\n\n        self.encoder1 = self.resnet.layer1  # 64\n        self.encoder2 = self.resnet.layer2  # 128\n        self.encoder3 = self.resnet.layer3  # 256\n        self.encoder4 = self.resnet.layer4  # 512\n\n        self.center = CenterBlock(512, 64, pool=False, SE=True)\n\n        self.decoder4 = Decoder_v3(256, 64, 64, convT_ratio=1, SE=True)\n        self.decoder3 = Decoder_v3(128, 64, 64, convT_ratio=1, SE=True)\n        self.decoder2 = Decoder_v3(64, 64, 64, convT_ratio=1, SE=True)\n        self.decoder1 = Decoder_v3(64, 64, 64, convT_ratio=1, SE=True)\n\n        self.reducer = ConvBn2d(256, 64, kernel_size=1, padding=0)\n\n        self.fpa = FPAModule1(in_ch=512, out_ch=256)\n\n        self.logit = nn.Sequential(\n            ConvBn2d(64 * 5, 128, kernel_size=3, padding=1),\n            nn.Dropout2d(),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(128, 1, kernel_size=1, padding=0),\n        )\n\n    def forward(self, x):\n\n        x = self.conv1(x)  # 128\n        p = F.max_pool2d(x, kernel_size=2, stride=2)  # 64\n\n        e1 = self.encoder1(p)  # 64\n        e2 = self.encoder2(e1)  # 32\n        e3 = self.encoder3(e2)  # 16\n        e4 = self.encoder4(e3)  # 8\n\n        f1 = self.fpa(e4)\n        f2 = self.reducer(f1)\n\n        d4 = self.decoder4(f2, e3)  # 16\n        d3 = self.decoder3(d4, e2)  # 32\n        d2 = self.decoder2(d3, e1)  # 64\n        d1 = self.decoder1(d2, x)  # 128\n\n        f = torch.cat([\n            d1,\n            F.upsample(d2, scale_factor=2, mode='bilinear', align_corners=False),\n            F.upsample(d3, scale_factor=4, mode='bilinear', align_corners=False),\n            F.upsample(d4, scale_factor=8, mode='bilinear', align_corners=False),\n            F.upsample(f2, scale_factor=16, mode='bilinear', align_corners=False)\n        ], 1)\n        logit = self.logit(f)\n        return logit","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c8a1e765918b7a9621eaac06b8c268129c36ddf7"},"cell_type":"markdown","source":"## Scheduler"},{"metadata":{"_uuid":"70933cee2a5e4de9bd96119f39a5fbed226533e2","collapsed":true,"trusted":false},"cell_type":"code","source":"import datetime\nimport math\nimport os\nimport torch\nimport numpy as np\nfrom torch.optim.lr_scheduler import _LRScheduler\n\n\nclass CosineAnnealingLR(_LRScheduler):\n    r\"\"\"Set the learning rate of each parameter group using a cosine annealing\n    schedule, where :math:`\\eta_{max}` is set to the initial lr and\n    :math:`T_{cur}` is the number of epochs since the last restart in SGDR:\n\n    .. math::\n\n        \\eta_t = \\eta_{min} + \\frac{1}{2}(\\eta_{max} - \\eta_{min})(1 +\n        \\cos(\\frac{T_{cur}}{T_{max}}\\pi))\n\n    When last_epoch=-1, sets initial lr as lr.\n\n    It has been proposed in\n    `SGDR: Stochastic Gradient Descent with Warm Restarts`_. This implementation\n    contains restarts and T_mul.\n\n    Args:\n        optimizer (Optimizer): Wrapped optimizer.\n        T_max (int): Maximum number of iterations.\n        eta_min (float): Minimum learning rate. Default: 0.\n        last_epoch (int): The index of last epoch. Default: -1.\n\n    .. _SGDR\\: Stochastic Gradient Descent with Warm Restarts:\n        https://arxiv.org/abs/1608.03983\n    \"\"\"\n\n    def __init__(self, optimizer, T_max, T_mul, lr_min=0, last_epoch=-1, val_mode='max', save_snapshots=False):\n        self.T_max = T_max\n        self.T_mul = T_mul\n        self.T_curr = 0\n        self.lr_min = lr_min\n        self.save_snapshots = save_snapshots\n        self.val_mode = val_mode\n        self.best_model_path = None\n        self.reset = 0\n\n        if self.val_mode == 'max':\n            self.best_metric = -np.inf\n        elif self.val_mode == 'min':\n            self.best_metric = np.inf\n\n        super(CosineAnnealingLR, self).__init__(optimizer, last_epoch)\n\n    def get_lr(self):\n        r = self.T_curr % self.T_max\n\n        if not r and self.last_epoch > 0:\n            self.T_max *= self.T_mul\n            self.T_curr = 1\n            self.update_saving_vars()\n        else:\n            self.T_curr += 1\n\n        return [self.lr_min + (base_lr - self.lr_min) *\n                (1 + math.cos(math.pi * r / self.T_max)) / 2\n                for base_lr in self.base_lrs]\n\n    def step(self, epoch=None, save_dict=None):\n        if epoch is None:\n            epoch = self.last_epoch + 1\n        self.last_epoch = epoch\n\n        if self.save_snapshots and save_dict is not None:\n            self.save_best_model(save_dict)\n\n        for param_group, lr in zip(self.optimizer.param_groups, self.get_lr()):\n            param_group['lr'] = lr\n\n    def update_saving_vars(self):\n        self.reset += 1\n        self.best_model_path = None\n\n        if self.val_mode == 'max':\n            self.best_metric = -np.inf\n        elif self.val_mode == 'min':\n            self.best_metric = np.inf\n\n\n    def save_best_model(self, save_dict):\n        metric = save_dict['metric']\n        fold = save_dict['fold']\n        save_dir = save_dict['save_dir']\n        state_dict = save_dict['state_dict']\n\n        if (self.val_mode == 'max' and metric > self.best_metric) or (\n                self.val_mode == 'min' and metric < self.best_metric):\n            # Update best metric\n            self.best_metric = metric\n            # Remove old file\n            if self.best_model_path is not None:\n                os.remove(self.best_model_path)\n            # Save new best model weights\n            date = ':'.join(str(datetime.datetime.now()).split(':')[:2])\n#             if fold is not None:\n#                 self.best_model_path = os.path.join(\n#                     save_dir,\n#                     '{:}_Fold{:}_Epoach{}_reset{:}_val{:.3f}'.format(date, fold, self.last_epoch, self.reset, metric))\n#             else:\n#                 self.best_model_path = os.path.join(\n#                     save_dir,\n#                     '{:}_Epoach{}_reset{:}_val{:.3f}'.format(date, self.last_epoch, self.reset, metric))\n            if fold is not None:\n                self.best_model_path = os.path.join(\n                    save_dir,\n                    'Fold{:}_Epoach{}_reset{:}_val{:.3f}'.format(fold, self.last_epoch, self.reset, metric))\n            else:\n                self.best_model_path = os.path.join(\n                    save_dir,\n                    'Epoach{}_reset{:}_val{:.3f}'.format(self.last_epoch, self.reset, metric))\n\n            torch.save(state_dict, self.best_model_path)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a2359bd8afcd98a259856e4425414de52b00bff1"},"cell_type":"markdown","source":"## Evaluation"},{"metadata":{"_uuid":"81e81793821f014417b990d31a1f23d32eccb95f","collapsed":true,"trusted":false},"cell_type":"code","source":"from skimage.transform import resize\nfrom scipy import ndimage\n\ndef batch_encode(batch):\n    rle = []\n    for i in range(len(batch)):\n        rle.append(do_length_encode(batch[i]))\n    return rle\n\ndef unpad_im(im):\n    return np.array([np.expand_dims(resize(np.squeeze(i), (768, 768), mode='constant', preserve_range=True), axis=0) for i in im])\n\ndef dice_accuracy(prob, truth, threshold=0.5, is_average=True, smooth=1e-12):\n    # prob = unpad_im(prob)\n    # truth = unpad_im(truth)\n\n    batch_size = prob.size(0)\n    p = prob.detach().contiguous().view(batch_size, -1)\n    t = truth.detach().contiguous().view(batch_size, -1)\n\n    p = p > threshold\n    t = t > 0.5\n    intersection = p & t\n    union = p | t\n    dice = (intersection.float().sum(1) + smooth) / (union.float().sum(1) + smooth)\n\n    if is_average:\n        dice = dice.sum() / batch_size\n\n    return dice\n\ndef do_mAP(pred, truth, is_average=False, threshold=0.5):\n    pred = pred > threshold\n    batch_size = truth.shape[0]\n    metric = []\n    for batch in range(batch_size):\n        p, t = pred[batch] > 0, truth[batch] > 0\n        intersection = np.logical_and(t, p)\n        union = np.logical_or(t, p)\n        iou = (np.sum(intersection > 0) + 1e-10) / (np.sum(union > 0) + 1e-10)\n        thresholds = np.arange(0.5, 1, 0.05)\n        s = []\n        for thresh in thresholds:\n            s.append(iou > thresh)\n        metric.append(np.mean(s))\n\n    if is_average:\n        return np.mean(metric)\n    else:\n        return metric","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c8ab8445cd15faddbe8cd9ba1acb7b5b496a620c"},"cell_type":"markdown","source":"## Define Loss"},{"metadata":{"_uuid":"72363c375182951a6b1f0965a4fbcbd18442c292","collapsed":true,"trusted":false},"cell_type":"code","source":"################### DICE ########################\ndef IoU(logit, truth, smooth=1):\n    prob = torch.sigmoid(logit)\n    intersection = torch.sum(prob * truth)\n    union = torch.sum(prob + truth)\n    iou = (2 * intersection + smooth) / (union + smooth)\n    return iou\n\nclass DiceLoss(nn.Module):\n    def __init__(self, smooth=1):\n        super(DiceLoss, self).__init__()\n        self.smooth = smooth\n\n    def forward(self, logit, truth):\n        iou = IoU(logit, truth, self.smooth)\n        loss = 1 - iou\n        return loss\n\n################ FOCAL LOSS ####################\nclass RobustFocalLoss2d(nn.Module):\n    # assume top 10% is outliers\n\n    def __init__(self, gamma=2, size_average=True):\n        super(RobustFocalLoss2d, self).__init__()\n        self.gamma = gamma\n        self.size_average = size_average\n\n    def forward(self, logit, target, class_weight=None, type='softmax'):\n        target = target.view(-1, 1).long()\n\n        if type == 'sigmoid':\n            if class_weight is None:\n                class_weight = [1] * 2  # [0.5, 0.5]\n\n            prob = torch.sigmoid(logit)\n            prob = prob.view(-1, 1)\n            prob = torch.cat((1 - prob, prob), 1)\n            select = torch.FloatTensor(len(prob), 2).zero_().cuda()\n            select.scatter_(1, target, 1.)\n\n        elif type == 'softmax':\n            B, C, H, W = logit.size()\n            if class_weight is None:\n                class_weight = [1] * C  # [1/C]*C\n\n            logit = logit.permute(0, 2, 3, 1).contiguous().view(-1, C)\n            prob = F.softmax(logit, 1)\n            select = torch.FloatTensor(len(prob), C).zero_().cuda()\n            select.scatter_(1, target, 1.)\n\n        class_weight = torch.FloatTensor(class_weight).cuda().view(-1, 1)\n        class_weight = torch.gather(class_weight, 0, target)\n\n        prob = (prob * select).sum(1).view(-1, 1)\n        prob = torch.clamp(prob, 1e-8, 1 - 1e-8)\n\n        focus = torch.pow((1 - prob), self.gamma)\n        # focus = torch.where(focus < 2.0, focus, torch.zeros(prob.size()).cuda())\n        focus = torch.clamp(focus, 0, 2)\n\n        batch_loss = - class_weight * focus * prob.log()\n\n        if self.size_average:\n            loss = batch_loss.mean()\n        else:\n            loss = batch_loss\n\n        return loss\n\n################# BCE + DICE ########################\nclass BCE_Dice(nn.Module):\n    def __init__(self, smooth=1):\n        super(BCE_Dice, self).__init__()\n        self.smooth = smooth\n        self.dice = DiceLoss(smooth=smooth)\n        self.bce = nn.BCEWithLogitsLoss()\n\n    def forward(self, logit, truth):\n        dice = self.dice(logit, truth)\n        bce = self.bce(logit, truth)\n        return dice + bce\n\n############### LOVÁSZ-HINGE ########################\nclass Lovasz_Hinge(nn.Module):\n    def __init__(self, per_image=True):\n        super(Lovasz_Hinge, self).__init__()\n        self.per_image = per_image\n\n    def forward(self, logit, truth):\n        return lovasz_hinge(logit, truth,\n                            per_image=self.per_image)\n\n\n############## BCE + LOVÁSZ #########################\nclass BCE_Lovasz(nn.Module):\n    def __init__(self, per_image=True):\n        super(BCE_Lovasz, self).__init__()\n        self.per_image = per_image\n\n    def forward(self, logit, truth):\n        bce = binary_xloss(logit, truth)\n        lovasz = lovasz_hinge(logit, truth, per_image=self.per_image)\n        return bce + lovasz","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4a36658c1f1cb255564cb56ad0f13cf5644a1baa"},"cell_type":"markdown","source":"## Lovasz Loss"},{"metadata":{"_uuid":"f9e1ecffd6870c8a9371a8a9870d08e53e6bd649","collapsed":true,"trusted":false},"cell_type":"code","source":"\"\"\"\nLovasz-Softmax and Jaccard hinge loss in PyTorch\nMaxim Berman 2018 ESAT-PSI KU Leuven (MIT License)\n\"\"\"\n\nfrom __future__ import print_function, division\n\nimport torch\nfrom torch.autograd import Variable\nimport torch.nn.functional as F\nimport numpy as np\ntry:\n    from itertools import  ifilterfalse\nexcept ImportError: # py3k\n    from itertools import  filterfalse\n\n\ndef lovasz_grad(gt_sorted):\n    \"\"\"\n    Computes gradient of the Lovasz extension w.r.t sorted errors\n    See Alg. 1 in paper\n    \"\"\"\n    p = len(gt_sorted)\n    gts = gt_sorted.sum()\n    intersection = gts - gt_sorted.float().cumsum(0)\n    union = gts + (1 - gt_sorted).float().cumsum(0)\n    jaccard = 1. - intersection / union\n    if p > 1: # cover 1-pixel case\n        jaccard[1:p] = jaccard[1:p] - jaccard[0:-1]\n    return jaccard\n\n\ndef iou_binary(preds, labels, EMPTY=1., ignore=None, per_image=True):\n    \"\"\"\n    IoU for foreground class\n    binary: 1 foreground, 0 background\n    \"\"\"\n    if not per_image:\n        preds, labels = (preds,), (labels,)\n    ious = []\n    for pred, label in zip(preds, labels):\n        intersection = ((label == 1) & (pred == 1)).sum()\n        union = ((label == 1) | ((pred == 1) & (label != ignore))).sum()\n        if not union:\n            iou = EMPTY\n        else:\n            iou = float(intersection) / union\n        ious.append(iou)\n    iou = mean(ious)    # mean accross images if per_image\n    return 100 * iou\n\n\ndef iou(preds, labels, C, EMPTY=1., ignore=None, per_image=False):\n    \"\"\"\n    Array of IoU for each (non ignored) class\n    \"\"\"\n    if not per_image:\n        preds, labels = (preds,), (labels,)\n    ious = []\n    for pred, label in zip(preds, labels):\n        iou = []\n        for i in range(C):\n            if i != ignore: # The ignored label is sometimes among predicted classes (ENet - CityScapes)\n                intersection = ((label == i) & (pred == i)).sum()\n                union = ((label == i) | ((pred == i) & (label != ignore))).sum()\n                if not union:\n                    iou.append(EMPTY)\n                else:\n                    iou.append(float(intersection) / union)\n        ious.append(iou)\n    ious = map(mean, zip(*ious)) # mean accross images if per_image\n    return 100 * np.array(ious)\n\n\n# --------------------------- BINARY LOSSES ---------------------------\n\n\ndef lovasz_hinge(logits, labels, per_image=True, ignore=None):\n    \"\"\"\n    Binary Lovasz hinge loss\n      logits: [B, H, W] Variable, logits at each pixel (between -\\infty and +\\infty)\n      labels: [B, H, W] Tensor, binary ground truth masks (0 or 1)\n      per_image: compute the loss per image instead of per batch\n      ignore: void class id\n    \"\"\"\n    if per_image:\n        loss = mean(lovasz_hinge_flat(*flatten_binary_scores(log.unsqueeze(0), lab.unsqueeze(0), ignore))\n                          for log, lab in zip(logits, labels))\n    else:\n        loss = lovasz_hinge_flat(*flatten_binary_scores(logits, labels, ignore))\n    return loss\n\n\ndef lovasz_hinge_flat(logits, labels):\n    \"\"\"\n    Binary Lovasz hinge loss\n      logits: [P] Variable, logits at each prediction (between -\\infty and +\\infty)\n      labels: [P] Tensor, binary ground truth labels (0 or 1)\n      ignore: label to ignore\n    \"\"\"\n    if len(labels) == 0:\n        # only void pixels, the gradients should be 0\n        return logits.sum() * 0.\n    signs = 2. * labels.float() - 1.\n    errors = (1. - logits * Variable(signs))\n    errors_sorted, perm = torch.sort(errors, dim=0, descending=True)\n    perm = perm.data\n    gt_sorted = labels[perm]\n    grad = lovasz_grad(gt_sorted)\n    loss = torch.dot(F.relu(errors_sorted), Variable(grad))\n    return loss\n\n\ndef flatten_binary_scores(scores, labels, ignore=None):\n    \"\"\"\n    Flattens predictions in the batch (binary case)\n    Remove labels equal to 'ignore'\n    \"\"\"\n    scores = scores.view(-1)\n    labels = labels.view(-1)\n    if ignore is None:\n        return scores, labels\n    valid = (labels != ignore)\n    vscores = scores[valid]\n    vlabels = labels[valid]\n    return vscores, vlabels\n\n\nclass StableBCELoss(torch.nn.modules.Module):\n    def __init__(self):\n         super(StableBCELoss, self).__init__()\n\n    def forward(self, input, target):\n         neg_abs = - input.abs()\n         loss = input.clamp(min=0) - input * target + (1 + neg_abs.exp()).log()\n         return loss.mean()\n\n\ndef binary_xloss(logits, labels, ignore=None):\n    \"\"\"\n    Binary Cross entropy loss\n      logits: [B, H, W] Variable, logits at each pixel (between -\\infty and +\\infty)\n      labels: [B, H, W] Tensor, binary ground truth masks (0 or 1)\n      ignore: void class id\n    \"\"\"\n    logits, labels = flatten_binary_scores(logits, labels, ignore)\n    loss = StableBCELoss()(logits, Variable(labels.float()))\n    return loss\n\n\n# --------------------------- MULTICLASS LOSSES ---------------------------\n\n\ndef lovasz_softmax(probas, labels, only_present=False, per_image=False, ignore=None):\n    \"\"\"\n    Multi-class Lovasz-Softmax loss\n      probas: [B, C, H, W] Variable, class probabilities at each prediction (between 0 and 1)\n      labels: [B, H, W] Tensor, ground truth labels (between 0 and C - 1)\n      only_present: average only on classes present in ground truth\n      per_image: compute the loss per image instead of per batch\n      ignore: void class labels\n    \"\"\"\n    if per_image:\n        loss = mean(lovasz_softmax_flat(*flatten_probas(prob.unsqueeze(0), lab.unsqueeze(0), ignore), only_present=only_present)\n                          for prob, lab in zip(probas, labels))\n    else:\n        loss = lovasz_softmax_flat(*flatten_probas(probas, labels, ignore), only_present=only_present)\n    return loss\n\n\ndef lovasz_softmax_flat(probas, labels, only_present=False):\n    \"\"\"\n    Multi-class Lovasz-Softmax loss\n      probas: [P, C] Variable, class probabilities at each prediction (between 0 and 1)\n      labels: [P] Tensor, ground truth labels (between 0 and C - 1)\n      only_present: average only on classes present in ground truth\n    \"\"\"\n    C = probas.size(1)\n    losses = []\n    for c in range(C):\n        fg = (labels == c).float() # foreground for class c\n        if only_present and fg.sum() == 0:\n            continue\n        errors = (Variable(fg) - probas[:, c]).abs()\n        errors_sorted, perm = torch.sort(errors, 0, descending=True)\n        perm = perm.data\n        fg_sorted = fg[perm]\n        losses.append(torch.dot(errors_sorted, Variable(lovasz_grad(fg_sorted))))\n    return mean(losses)\n\n\ndef flatten_probas(probas, labels, ignore=None):\n    \"\"\"\n    Flattens predictions in the batch\n    \"\"\"\n    B, C, H, W = probas.size()\n    probas = probas.permute(0, 2, 3, 1).contiguous().view(-1, C)  # B * H * W, C = P, C\n    labels = labels.view(-1)\n    if ignore is None:\n        return probas, labels\n    valid = (labels != ignore)\n    vprobas = probas[valid.nonzero().squeeze()]\n    vlabels = labels[valid]\n    return vprobas, vlabels\n\ndef xloss(logits, labels, ignore=None):\n    \"\"\"\n    Cross entropy loss\n    \"\"\"\n    return F.cross_entropy(logits, Variable(labels), ignore_index=255)\n\n\n# --------------------------- HELPER FUNCTIONS ---------------------------\n\ndef mean(l, ignore_nan=False, empty=0):\n    \"\"\"\n    nanmean compatible with generators.\n    \"\"\"\n    l = iter(l)\n    if ignore_nan:\n        l = ifilterfalse(np.isnan, l)\n    try:\n        n = 1\n        acc = next(l)\n    except StopIteration:\n        if empty == 'raise':\n            raise ValueError('Empty mean')\n        return empty\n    for n, v in enumerate(l, 2):\n        acc += v\n    if n == 1:\n        return acc\n    return acc / n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7a903596c131dd1eed5c640bf7f04588c801fb0c"},"cell_type":"markdown","source":"## Train"},{"metadata":{"_uuid":"830f6cb907e4226cf1e36e27721ef8d037475a60","collapsed":true,"trusted":false},"cell_type":"code","source":"from contextlib import contextmanager\nimport time\n@contextmanager\ndef timer(title):\n    t0 = time.time()\n    yield\n    print(\"{} - done in {:.0f}s\".format(title, time.time() - t0))\n\n##############################\nTRAIN_PATH = '../input'\nLOAD_PATHS = None\n\nDEBUG = False\n##############################\nLOSS = 'lovasz'\nOPTIMIZER = 'SGD'\nVAL_MODE = 'max'\nPRETRAINED = True\nN_EPOCH = 1\nBATCH_SIZE = 8\nSIZE = 224\nNET = UNetResNet34_SE_Hyper_FPA\nACTIVATION = 'relu'\n###########OPTIMIZER###########\nLR = 1e-2\nUSE_SCHEDULER = 'CosineAnneling'\nMILESTONES = [20, 40, 75]\nGAMMA = 0.5\nPATIENCE = 10\nT_MAX = 50\nT_MUL = 1\nLR_MIN = 0\n##############################\nCOMMENT = 'SGDR (Tmax40, Tmul1), Lovasz, relu, pretrained'\n\ntrain_dataset = Airbus_Dataset(TRAIN_PATH)\ntrain_loader, val_loader = train_dataset.yield_dataloader(num_workers=1, batch_size=BATCH_SIZE, size=SIZE\n                                              # auxiliary_df=TGS_Dataset.create_dataset_df(AUX_PATH)\n                                              )\n\n\nnet = NET(lr=LR, debug=DEBUG, pretrained=PRETRAINED, fold=None, activation=ACTIVATION, val_mode=VAL_MODE, comment=COMMENT)\nnet.define_criterion(LOSS)\nnet.create_optmizer(optimizer=OPTIMIZER, use_scheduler=USE_SCHEDULER, milestones=MILESTONES,\n                    gamma=GAMMA, patience=PATIENCE, T_max=T_MAX, T_mul=T_MUL, lr_min=LR_MIN)\n\n\nnet.train_network(train_loader, val_loader, n_epoch=N_EPOCH)\nnet.plot_training_curve(show=True)\n\n\n\n","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}