{"cells":[{"metadata":{},"cell_type":"markdown","source":"# PANDA EfficientNet-B0 Baseline with 36 x tiles_256\n\nHi everyone,\n\nI'm here to show you how to train a single efficientnet-b0 model to get LB 0.87\n\nThis is inference kernel and the Training kernel is avalilable here: https://www.kaggle.com/haqishen/train-efficientnet-b0-w-36-tiles-256-lb0-87\n\n\n\n# TTA\n    \nTile extraction start from different point (by adding more white padding)","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":{"_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\n\nimport matplotlib.pyplot as plt\nfrom tqdm.notebook import tqdm\n\nfrom scipy import stats","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 = ''\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=False)\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    '../input/panda-public-models/cls_effnet_b0_Rand36r36tiles256_big_bce_lr0.3_augx2_30epo_model_fold0.pth',\n    '../input/efficientnet-pytorch/efficientnet-b7-dcc49843.pth'\n]\n\nmodels = load_models(model_files)","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                ):\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\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        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        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":{"trusted":true},"cell_type":"code","source":"if not is_test:\n    dataset_show = PANDADataset(df, image_size, n_tiles, 0)\n    from pylab import rcParams\n    rcParams['figure.figsize'] = 20,10\n    for i in range(2):\n        f, axarr = plt.subplots(1,5)\n        for p in range(5):\n            idx = np.random.randint(0, len(dataset_show))\n            img = dataset_show[idx]\n            axarr[p].imshow(1. - img.transpose(0, 1).transpose(1,2).squeeze())\n            axarr[p].set_title(str(idx))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prediction","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset = PANDADataset(df, image_size, n_tiles, 0)  # mode == 0\nloader = DataLoader(dataset, batch_size=batch_size, num_workers=num_workers, shuffle=False)\n\ndataset2 = PANDADataset(df, image_size, n_tiles, 2)  # mode == 2\nloader2 = DataLoader(dataset2, batch_size=batch_size, num_workers=num_workers, shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"LOGITS = []\nLOGITS2 = []\nwith torch.no_grad():\n    for data in tqdm(loader):\n        data = data.to(device)\n        logits = models[1](data)\n        LOGITS.append(logits)\n\n    for data in tqdm(loader2):\n        data = data.to(device)\n        logits = models[1](data)\n        LOGITS2.append(logits)\n\nLOGITS = (torch.cat(LOGITS).sigmoid().cpu() + torch.cat(LOGITS2).sigmoid().cpu()) / 2\nPREDS = LOGITS.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":"# MAIN_PREDS = []\n# for i in range(len(models)):\n#     LOGITS = []\n#     LOGITS2 = []\n#     with torch.no_grad():\n#         for data in tqdm(loader):\n#             data = data.to(device)\n#             logits = models[i](data)\n#             LOGITS.append(logits)\n\n#         for data in tqdm(loader2):\n#             data = data.to(device)\n#             logits = models[i](data)\n#             LOGITS2.append(logits)\n\n#     LOGITS = (torch.cat(LOGITS).sigmoid().cpu() + torch.cat(LOGITS2).sigmoid().cpu()) / 2\n#     PREDS = LOGITS.sum(1).round().numpy()\n#     MAIN_PREDS.append(PREDS)\n    \n# PREDS = stats.mode(MAIN_PREDS)[0]\n\n# df['isup_grade'] = PREDS.astype(int)\n# df[['image_id', 'isup_grade']].to_csv('submission.csv', index=False)\n# print(df.head())\n# print()\n# print(df.isup_grade.value_counts())","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}