{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Description\nThis kernel performs inference for [PANDA training for EffNetB0 Regression](https://www.kaggle.com/fanconic/panda-training-for-effnetb0-regression).\n\nIt is originially based on @iafoss training and inference Kernel. Thank you very much for the original submission!","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"import cv2\nfrom tqdm import tqdm_notebook as tqdm\nimport fastai\nfrom fastai.vision import *\nimport os\nfrom mish_activation import *\nimport warnings\nwarnings.filterwarnings(\"ignore\")\nimport skimage.io\nfrom skimage.transform import resize\nimport numpy as np\nimport pandas as pd\nimport cv2\n\nimport sys\npackage_path = '../input/efficientnet-pytorch/EfficientNet-PyTorch/EfficientNet-PyTorch-master'\nsys.path.append(package_path)\nfrom efficientnet_pytorch import EfficientNet","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"os.listdir('../input/panda-training-for-effnetb0-regression')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA = '../input/prostate-cancer-grade-assessment/test_images'\nTEST = '../input/prostate-cancer-grade-assessment/test.csv'\nSAMPLE = '../input/prostate-cancer-grade-assessment/sample_submission.csv'\nMODELS = [f'../input/panda-training-for-effnetb0-regression/models/model.pth']\n\ntile_sz = 128\nimg_sz = 224\nbs = 2\nN = 12\nnworkers = 2","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class Model(nn.Module):\n    def __init__(self, n=6, pre=True):\n        super().__init__()\n        \n        # Load model backbone\n        model = EfficientNet.from_name('efficientnet-b0')\n        \n        # Encoder, runs through the pretrained efficientnet\n        self.enc = model\n        \n        # Neural network head. After running through the neural network, this is the transfer\n        nc = list(model.children())[-1].in_features\n        self.head = nn.Sequential(AdaptiveConcatPool2d(),\n                                  Flatten(),\n                                  nn.Linear(2*nc,512), \n                                  Mish(),\n                                  nn.BatchNorm1d(512), \n                                  nn.Dropout(0.5),\n                                  nn.Linear(512,1))\n        \n        \n    def forward(self, x):\n        \"\"\" Forward run through the neural network\n        Params:\n        x: torch tensor - input\n        \n        returns: output after feed forward.\n        \"\"\"\n        # Reshape array\n        shape = x.shape\n        n = shape[1]\n        x = x.view(-1,shape[2],shape[3],shape[4])\n        \n        #x: bs*N x 3 x 224 x 224\n        # Go through convolutional layers\n        x = self.enc.extract_features(x)\n        \n        shape = x.shape\n        x = x.view(-1,n,shape[1],shape[2],shape[3]).permute(0,2,1,3,4).contiguous()\\\n          .view(-1,shape[1],shape[2]*n,shape[3])\n        \n        # Go through classifier\n        x = self.head(x)\n        return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"models = []\nfor path in MODELS:\n    state_dict = torch.load(path,map_location=torch.device('cpu'))['model']\n    model = Model()\n    model.load_state_dict(state_dict)\n    model.float()\n    model.eval()\n    model.cuda()\n    models.append(model)\n\ndel state_dict","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def tile(img, sz):\n    shape = img.shape\n    \n    pad0,pad1 = (sz - shape[0]%sz)%sz, (sz - shape[1]%sz)%sz\n    \n    img = np.pad(img,[[pad0//2,pad0-pad0//2],[pad1//2,pad1-pad1//2],[0,0]],constant_values=255)\n    \n    img = img.reshape(img.shape[0]//sz,sz,img.shape[1]//sz,sz,3)\n    img = img.transpose(0,2,1,3,4).reshape(-1,sz,sz,3)\n    \n    if len(img) < N:\n        img = np.pad(img,[[0,N-len(img)],[0,0],[0,0],[0,0]],constant_values=255)\n        \n    idxs = np.argsort(img.reshape(img.shape[0],-1).sum(-1))[:N]\n    img = img[idxs]\n    \n    return img\n\n\nmean = torch.tensor([1.0-0.90949707, 1.0-0.8188697, 1.0-0.87795304])\nstd = torch.tensor([0.36357649, 0.49984502, 0.40477625])\n\n\nclass PandaDataset(Dataset):\n    def __init__(self, path, test):\n        self.path = path\n        self.names = list(pd.read_csv(test).image_id)\n\n        \n    def __len__(self):\n        return len(self.names)\n\n    \n    def __getitem__(self, idx):\n        name = self.names[idx]\n        img = skimage.io.MultiImage(os.path.join(DATA,name+'.tiff'))[-1]\n        tiles = tile(img, tile_sz)\n        tiles = torch.Tensor(tiles)\n        tiles = tiles.permute(0,3,1,2)\n        tiles = nn.functional.interpolate(tiles, size = img_sz, mode = 'bilinear')\n        tiles = 1- tiles/255.0\n        tiles = (tiles - mean[...,None,None])/std[...,None,None]\n        return tiles, name","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"# Only for testing with train folder\nds = PandaDataset(DATA,TEST)\ndl = DataLoader(ds, batch_size=bs, num_workers=nworkers, shuffle=False)\n\nfor x,y in dl:\n    fig, axs = plt.subplots(2,12, figsize=(25, 6), facecolor='w', edgecolor='k')\n    axs = axs.ravel()\n    for j,batch in enumerate(x):\n        for i,t in enumerate(batch):\n            axs[j*12+i].imshow(t.permute(1,2,0).numpy())\n        if j == 1:\n            break\n    break\"\"\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"\n# Prediction","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class KappaOptimizer(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.coef = [0.5, 1.5, 2.5, 3.5]\n        # define score function:\n        self.func = self.quad_kappa\n    \n    \n    def predict(self, preds):\n        return self._predict(self.coef, preds)\n\n    \n    @classmethod\n    def _predict(cls, coef, preds):\n        if type(preds).__name__ == 'Tensor':\n            y_hat = preds.clone().view(-1)\n        else:\n            y_hat = torch.FloatTensor(preds).view(-1)\n\n        for i,pred in enumerate(y_hat):\n            if   pred < coef[0]: y_hat[i] = 0\n            elif pred < coef[1]: y_hat[i] = 1\n            elif pred < coef[2]: y_hat[i] = 2\n            elif pred < coef[3]: y_hat[i] = 3\n            else:                y_hat[i] = 4\n        return y_hat.int()\n    \n    \n    def quad_kappa(self, preds, y):\n        return self._quad_kappa(self.coef, preds, y)\n\n    \n    @classmethod\n    def _quad_kappa(cls, coef, preds, y):\n        y_hat = cls._predict(coef, preds)\n        \n        try:\n            return cohen_kappa_score(y, y_hat, weights='quadratic')\n        except:\n            return cohen_kappa_score(y.cpu(), y_hat.cpu(), weights='quadratic')\n\n    \n    def fit(self, preds, y):\n        ''' maximize quad_kappa '''\n        neg_kappa = lambda coef: -self._quad_kappa(coef, preds, y)\n        opt_res = sp.optimize.minimize(neg_kappa, x0=self.coef, method='nelder-mead',\n                                       options={'maxiter':100, 'fatol':1e-20, 'xatol':1e-20})\n        self.coef = opt_res.x\n\n        \n    def forward(self, preds, y):\n        ''' the pytorch loss function '''\n        return torch.tensor(self.quad_kappa(preds, y))\n\n\nkappa_opt = KappaOptimizer()\n\n# Optimized Thresholds from previous training\nkappa_opt.coef = [0.55589, 1.635796, 2.427105, 3.058962]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_df = pd.read_csv(SAMPLE)\nif os.path.exists(DATA):\n    ds = PandaDataset(DATA,TEST)\n    dl = DataLoader(ds, batch_size=bs, num_workers=nworkers, shuffle=False)\n    names,preds = [],[]\n    \n    with torch.no_grad():\n        for x,y in tqdm(dl):\n            x = x.cuda()\n            #trafos = [x]\n            \n            #dihedral TTA\n            trafos = [x,\n                      x.flip(-1),\n                      x.flip(-2),\n                      x.flip(-1,-2),\n                      x.transpose(-1,-2),\n                      x.transpose(-1,-2).flip(-1),\n                      x.transpose(-1,-2).flip(-2),\n                      x.transpose(-1,-2).flip(-1,-2)]\n            \n            \n            # Reshape input\n            x = torch.stack(trafos,1)\n            x = x.view(-1,N,3,img_sz, img_sz)\n            \n            # Make predictions\n            p = [model(x) for model in models]\n            p = torch.stack(p,1)\n            \n            # Take mean/median of predictions\n            p = p.view(bs,len(trafos)*len(models),-1).median(1).values\n            p = kappa_opt.predict(p).cpu()\n            #p = p.view(bs,len(trafos)*len(models),-1).mean(1).argmax(-1).cpu()\n            \n            names.append(y)\n            preds.append(p)\n    \n    names = np.concatenate(names)\n    preds = torch.cat(preds).numpy()\n    sub_df = pd.DataFrame({'image_id': names, 'isup_grade': preds})\n    sub_df.to_csv('submission.csv', index=False)\n    sub_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"# Only for testing with train folder\nfrom sklearn.metrics import cohen_kappa_score, confusion_matrix\n\nsub_df = pd.DataFrame({'image_id': names, 'isup_grade': preds})\ndf = pd.read_csv(TEST)\ndf.drop([\"isup_grade\"], axis =1)\ndf = df.merge(sub_df, left_on=\"image_id\", right_on=\"image_id\")\ndf = df.dropna()\n\nt = df.isup_grade_x\np = df.isup_grade_y\nprint(cohen_kappa_score(t,p,weights='quadratic'))\nprint(confusion_matrix(t,p))\"\"\"","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"sub_df.to_csv(\"submission.csv\", index=False)\nsub_df.head()","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}