{"cells":[{"metadata":{},"cell_type":"markdown","source":"This is a kernel made by kaggle_gaggle team which had 25th prize in Prostate-cancer-grade-assessement competition/\n\nThanks to Quishen Ha  \n\nWe tested lots of public kerenels in the competition but at the last, the kernel provided by Quishen Ha showed stable and high LB score consistently.\n\nTrain EfficientNet-B0 w/ 36 tiles_256 [LB0.87]  \nTraining : https://www.kaggle.com/haqishen/train-efficientnet-b0-w-36-tiles-256-lb0-87\n\nInference : https://www.kaggle.com/haqishen/panda-inference-w-36-tiles-256\n\nOur train code:\nTraining : https://github.com/ddw02141/PANDA_Challenge\n\nWe added Test time augmentation (TTA) on original inference code with same augmentation configuration at train code.\n\nEnsemble from efficientnet b0 and b1 including specific folds whcih showed consistent result between CV and LB.\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"DEBUG = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport sys\nsys.path = [\n    '../input/efficientnet-pytorch/EfficientNet-PyTorch/EfficientNet-PyTorch-master',\n] + sys.path","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sys.path","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import skimage.io\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader, Dataset\nfrom efficientnet_pytorch import model as enet\nimport albumentations\nfrom albumentations.pytorch import ToTensor\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm_notebook as tqdm\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_dir = '../input/prostate-cancer-grade-assessment'\ndf_train = pd.read_csv(os.path.join(data_dir, 'train.csv'))\ndf_test = pd.read_csv(os.path.join(data_dir, 'test.csv'))\ndf_sub = pd.read_csv(os.path.join(data_dir, 'sample_submission.csv'))\n\nmodel_dir = '../input/effnet-model-assemble'\nimage_folder = os.path.join(data_dir, 'test_images')\nis_test = os.path.exists(image_folder)  # IF test_images is not exists, we will use some train images.\nimage_folder = image_folder if is_test else os.path.join(data_dir, 'train_images')\n\ndf = df_test if is_test else df_train.loc[:100]\n\ntile_size = 256\nimage_size = 256\nn_tiles = 36\nbatch_size = 8\nnum_workers = 4\n\ndevice = torch.device('cuda')\n\nprint(image_folder)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class enetv2(nn.Module):\n    def __init__(self, backbone, out_dim):\n        super(enetv2, self).__init__()\n        self.enet = enet.EfficientNet.from_name(backbone)\n        self.myfc = nn.Linear(self.enet._fc.in_features, out_dim)\n        self.enet._fc = nn.Identity()\n\n    def extract(self, x):\n        return self.enet(x)\n\n    def forward(self, x):\n        x = self.extract(x)\n        x = self.myfc(x)\n        return x\n    \n    \ndef load_models(model_files):\n    models = []\n    for model_f in model_files:\n        model_f = os.path.join(model_dir, model_f)\n        backbone = 'efficientnet-b0'\n        model = enetv2(backbone, out_dim=5)\n        model.load_state_dict(torch.load(model_f, map_location=lambda storage, loc: storage), strict=True)\n        model.eval()\n        model.to(device)\n        models.append(model)\n        print(f'{model_f} loaded!')\n    return models\n\n\nmodel_files = [\n    'cls_effnet_b0_Rand36r36tiles256_big_bce_lr0.3_augx2_30epo_model_fold0.pth'\n]\n\nmodels = load_models(model_files)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_dir_1 = '../input/effnet-model-assemble/'\nbackbone_1 = 'efficientnet-b1'\n\nclass enetv2_1(nn.Module):\n    def __init__(self, backbone_1, out_dim):\n        super(enetv2_1, self).__init__()\n        self.enet = enet.EfficientNet.from_name(backbone_1)\n        self.myfc = nn.Linear(self.enet._fc.in_features, out_dim)\n        self.enet._fc = nn.Identity()\n\n    def extract(self, x):\n        return self.enet(x)\n\n    def forward(self, x):\n        x = self.extract(x)\n        x = self.myfc(x)\n        return x\n\nclass WrappedModel(nn.Module):\n    def __init__(self):\n        super(WrappedModel, self).__init__()\n        self.module = enetv2_1(backbone_1, out_dim=5)\n    def forward(self, x):\n        return self.module(x)\n    \ndef load_models_1(model_files):\n    models = []\n    for model_f in model_files:\n        model_f = os.path.join(model_dir, model_f)\n        \n        model = WrappedModel()\n        model.load_state_dict(torch.load(model_f, map_location=lambda storage, loc: storage.cuda(0)), strict=True)\n        model.eval()\n        model.to(device)\n        models.append(model)\n        print(f'{model_f} loaded!')\n    return models\n\n\nmodel_files = [\n    'efficientnet_b1_36x256x256_final_best_fold0.pth',\n    'efficientnet_b1_36x256x256_final_best_fold1.pth'\n]\n\nmodels_1 = load_models_1(model_files)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# TTA","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"test_transform = albumentations.Compose([\n    albumentations.Transpose(p=0.5),\n    albumentations.VerticalFlip(p=0.5),\n    albumentations.HorizontalFlip(p=0.5),\n    \n])\ntransforms_val = albumentations.Compose([])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Dataset","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_tiles(img, mode=0):\n        result = []\n        h, w, c = img.shape\n        pad_h = (tile_size - h % tile_size) % tile_size + ((tile_size * mode) // 2)\n        pad_w = (tile_size - w % tile_size) % tile_size + ((tile_size * mode) // 2)\n\n        img2 = np.pad(img,[[pad_h // 2, pad_h - pad_h // 2], [pad_w // 2,pad_w - pad_w//2], [0,0]], constant_values=255)\n        img3 = img2.reshape(\n            img2.shape[0] // tile_size,\n            tile_size,\n            img2.shape[1] // tile_size,\n            tile_size,\n            3\n        )\n\n        img3 = img3.transpose(0,2,1,3,4).reshape(-1, tile_size, tile_size,3)\n        n_tiles_with_info = (img3.reshape(img3.shape[0],-1).sum(1) < tile_size ** 2 * 3 * 255).sum()\n        if len(img) < n_tiles:\n            img3 = np.pad(img3,[[0,N-len(img3)],[0,0],[0,0],[0,0]], constant_values=255)\n        idxs = np.argsort(img3.reshape(img3.shape[0],-1).sum(-1))[:n_tiles]\n        img3 = img3[idxs]\n        for i in range(len(img3)):\n            result.append({'img':img3[i], 'idx':i})\n        return result, n_tiles_with_info >= n_tiles\n\n\nclass PANDADataset(Dataset):\n    def __init__(self,\n                 df,\n                 image_size,\n                 n_tiles=n_tiles,\n                 tile_mode=0,\n                 rand=False,\n                 sub_imgs=False,\n                 transform=None\n                 ):\n\n        self.df = df.reset_index(drop=True)\n        self.image_size = image_size\n        self.n_tiles = n_tiles\n        self.tile_mode = tile_mode\n        self.rand = rand\n        self.sub_imgs = sub_imgs\n        self.transform = transform\n        \n    def __len__(self):\n        return self.df.shape[0]\n\n    def __getitem__(self, index):\n        row = self.df.iloc[index]\n        img_id = row.image_id\n        \n        tiff_file = os.path.join(image_folder, f'{img_id}.tiff')\n        image = skimage.io.MultiImage(tiff_file)[1]\n        tiles, OK = get_tiles(image, self.tile_mode)\n        \n    \n        \n        if self.rand:\n            idxes = np.random.choice(list(range(self.n_tiles)), self.n_tiles, replace=False)\n        else:\n            idxes = list(range(self.n_tiles))\n        idxes = np.asarray(idxes) + self.n_tiles if self.sub_imgs else idxes\n\n        n_row_tiles = int(np.sqrt(self.n_tiles))\n        images = np.zeros((image_size * n_row_tiles, image_size * n_row_tiles, 3))\n        for h in range(n_row_tiles):\n            for w in range(n_row_tiles):\n                i = h * n_row_tiles + w\n    \n                if len(tiles) > idxes[i]:\n                    this_img = tiles[idxes[i]]['img']\n                else:\n                    this_img = np.ones((self.image_size, self.image_size, 3)).astype(np.uint8) * 255\n                this_img = 255 - this_img\n                h1 = h * image_size\n                w1 = w * image_size\n                images[h1:h1+image_size, w1:w1+image_size] = this_img\n\n#         images = 255 - images\n        if self.transform is not None:\n           images = self.transform(image=images)['image']\n        images = images.astype(np.float32)\n        images /= 255\n        images = images.transpose(2, 0, 1)\n\n        return torch.tensor(images)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prediction","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"TTA_num = 16\nLOGITS_bags_0= []\nLOGITS_bags_1= []\nLOGITS_bags_b0=[]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(2*TTA_num):\n    LOGITS_bags_0.append([])\n    LOGITS_bags_1.append([])\n    LOGITS_bags_b0.append([])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"LOGITS_total=[]\nLOGITS_total_b0=[]\nwith torch.no_grad():\n    for i in range(2*TTA_num):\n        if i%2 == 0:\n            dataset=(PANDADataset(df, image_size, n_tiles, 0, transform=test_transform))\n            loader=(DataLoader(dataset, batch_size=batch_size, num_workers=num_workers, shuffle=False))\n        else:\n            dataset=(PANDADataset(df, image_size, n_tiles, 2, transform=test_transform))\n            loader=(DataLoader(dataset, batch_size=batch_size, num_workers=num_workers, shuffle=False))\n            \n        for data in tqdm(loader):\n            data = data.to(device)\n            logits_0 = models_1[0](data)\n            logits_1 = models_1[1](data)\n            logits_b0 = models[0](data)\n            LOGITS_bags_0[i].append(logits_0)\n            LOGITS_bags_1[i].append(logits_1)\n            LOGITS_bags_b0[i].append(logits_b0)\n            \n        LOGITS_total.append(torch.cat(LOGITS_bags_0[i]).sigmoid().cpu())\n        LOGITS_total.append(torch.cat(LOGITS_bags_1[i]).sigmoid().cpu())\n        LOGITS_total_b0.append(torch.cat(LOGITS_bags_b0[i]).sigmoid().cpu())\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"LOGITS=sum(LOGITS_total)/(2*TTA_num*2)\nLOGITS_b0=sum(LOGITS_total_b0)/(2*TTA_num)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"LOGITS_final = (LOGITS + LOGITS_b0)/2\nPREDS = LOGITS_final.sum(1).round().numpy()\n\ndf['isup_grade'] = PREDS.astype(int)\ndf[['image_id', 'isup_grade']].to_csv('submission.csv', index=False)\nprint(df.head())\nprint()\nprint(df.isup_grade.value_counts())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}