{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Description\nThis kernel performs inference for [PANDA concat tile pooling starter](https://www.kaggle.com/iafoss/panda-concat-fast-ai-starter) kernel with use of multiple models and 8 fold TTA. Check it for more training details. The image preprocessing pipline is provided [here](https://www.kaggle.com/iafoss/panda-16x128x128-tiles).","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\nimport numpy as np\nimport pandas as pd\nsys.path.insert(0, '../input/semisupervised-imagenet-models/semi-supervised-ImageNet1K-models-master/')\nfrom hubconf import *","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"os.listdir('../input/mypandago/')","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/mypandago/RNXT50_200_reg_nozoomin_0.pth']\n\nsz = 128*4\nimg_size = 200\nbs = 2\nN = 12\nnworkers = 2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv('../input/mypanda/train_5folds.csv')\ndf = df[df.fold == 0]\ndf","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def _resnext(url, block, layers, pretrained, progress, **kwargs):\n    model = ResNet(block, layers, **kwargs)\n    #state_dict = load_state_dict_from_url(url, progress=progress)\n    #model.load_state_dict(state_dict)\n    return model\n\n# 101 [3, 4, 23, 3], 50 [3, 4, 6, 3]\nclass Model(nn.Module):\n    def __init__(self, arch='resnext50_32x4d', n=1, pre=True):\n        super().__init__()\n        #m = torch.hub.load('facebookresearch/semi-supervised-ImageNet1K-models', arch)\n        m = _resnext(semi_supervised_model_urls[arch], Bottleneck, [3, 4, 6, 3], False, \n                progress=False,groups=32,width_per_group=4)\n        self.enc = nn.Sequential(*list(m.children())[:-2])       \n        nc = list(m.children())[-1].in_features\n        self.head = nn.Sequential(AdaptiveConcatPool2d(),Flatten(),nn.Linear(2*nc,512),\n                Mish(),nn.BatchNorm1d(512),nn.Dropout(0.5),nn.Linear(512,n))\n        \n    def forward(self, x):\n        shape = x.shape\n        n = shape[1]\n        x = x.view(-1,shape[2],shape[3],shape[4])\n        x = self.enc(x)\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        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'))\n    model = Model()\n    \n    from collections import OrderedDict\n    new_state_dict = OrderedDict()\n    for k, v in state_dict.items():\n        name = k[7:] # remove `module.`\n#         name = k\n        new_state_dict[name] = v\n        \n    model.load_state_dict(new_state_dict)\n    model.float()\n    model.eval()\n    model.cuda()\n    models.append(model)\n\ndel state_dict","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# models = []\n# for path in MODELS:\n#     state_dict = torch.load(path,map_location=torch.device('cpu'))\n#     model = Model()\n#     model.load_state_dict(state_dict)\n#     model.float()\n#     model.eval()\n#     model.cuda()\n#     models.append(model)\n\n# del state_dict","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def imshow(\n    img,\n    title=None,\n    show_shape=True,\n    figsize=(5, 5)\n):\n    fig, ax = plt.subplots(figsize=figsize)\n    ax.imshow(img)\n    ax.grid(\"off\")\n    ax.set_xticks([])\n    ax.set_yticks([])\n\n    if show_shape:\n        ax.set_xlabel(f\"Shape: {img.shape}\", fontsize=16)\n        \n    if title:\n        ax.set_title(title, fontsize=16)\n\n    return ax","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def crop_white(image: np.ndarray) -> np.ndarray:\n    assert image.shape[2] == 3\n    assert image.dtype == np.uint8\n    ys, = (image.min((1, 2)) != 255).nonzero()\n    xs, = (image.min(0).min(1) != 255).nonzero()\n    if len(xs) == 0 or len(ys) == 0:\n        return image\n    return image[ys.min():ys.max() + 1, xs.min():xs.max() + 1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from PIL import Image\n\ndef tile(img):\n    shape = img.shape\n    pad0,pad1 = (sz - shape[0]%sz)%sz, (sz - shape[1]%sz)%sz\n    img = np.pad(img,[[pad0//2,pad0-pad0//2],[pad1//2,pad1-pad1//2],[0,0]],\n                 constant_values=255)\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    if len(img) < N:\n        img = np.pad(img,[[0,N-len(img)],[0,0],[0,0],[0,0]],constant_values=255)\n    idxs = np.argsort(img.reshape(img.shape[0],-1).sum(-1))[:N]\n    img = img[idxs]\n    \n#     img_ = np.ndarray([len(img),img_size,img_size,3])\n    img_ = []\n    for i in range(len(img)):\n        img_tmp = img[i]\n#         img_tmp = Image.fromarray(img_tmp)\n#         img_tmp = img_tmp.resize((img_size,img_size))\n#         img_tmp = cv2.cvtColor(img_tmp, cv2.COLOR_RGB2BGR)\n        img_tmp = cv2.resize(img_tmp,(256,256))\n        img_tmp = cv2.resize(img_tmp,(img_size,img_size))\n        img_.append(img_tmp)\n    img_ = np.stack(img_)\n    return img_\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\nclass PandaDataset(Dataset):\n    def __init__(self, path, test, is_train=True):\n        self.path = path\n        if is_train:\n            self.names = list(pd.read_csv(test).image_id)\n        else:\n            self.names = list(df.image_id)\n\n    def __len__(self):\n        return len(self.names)\n\n    def __getitem__(self, idx):\n        name = self.names[idx]\n        img = skimage.io.MultiImage(os.path.join(DATA,name+'.tiff'))[-2]\n#         img = crop_white(img)\n        imgs = tile(img)\n#         n = len(imgs)\n#         imgs = np.resize(imgs, (n,img_size,img_size,3))\n#         print(imgs.shape)\n        tiles = torch.Tensor(1.0 - imgs/255.0)\n        tiles = (tiles - mean)/std\n        return tiles.permute(0,3,1,2), name","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img = skimage.io.MultiImage(os.path.join(DATA,'0005f7aaab2800f6170c399693a96917'+'.tiff'))[-2]\nimgs = tile(img)\n# img_tmp = cv2.cvtColor(imgs[0], cv2.COLOR_RGB2BGR)\n# img_tmp = cv2.resize(imgs[0],(img_size,img_size))\n# img_tmp = np.resize(imgs[0], (img_size,img_size,3))\nimshow(imgs[0])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Valid","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"TRAINDATA = '../input/prostate-cancer-grade-assessment/train_images'\nTRAIN = '../input/prostate-cancer-grade-assessment/train.csv'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# if os.path.exists(TRAINDATA):\n#     ds = PandaDataset(TRAINDATA,TRAIN,False)\n#     dl = DataLoader(ds, batch_size=bs, num_workers=nworkers, shuffle=False)\n#     valid_names,valid_preds = [],[]\n\n#     with torch.no_grad():\n#         for x,y in tqdm(dl):\n#             x = x.cuda()\n#             #dihedral TTA\n#             x = torch.stack([x,x.flip(-1),x.flip(-2),x.flip(-1,-2),\n#               x.transpose(-1,-2),x.transpose(-1,-2).flip(-1),\n#               x.transpose(-1,-2).flip(-2),x.transpose(-1,-2).flip(-1,-2)],1)\n#             x = x.view(-1,N,3,img_size,img_size)\n#             p = [model(x) for model in models]\n#             p = torch.stack(p,1)\n#             p = p.view(bs,8*len(models),-1).mean(1).cpu()\n#             valid_names.append(y)\n#             valid_preds.append(p)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# valid_names = np.concatenate(valid_names)\n# valid_preds = torch.cat(valid_preds).numpy()\n# valid_labels = df.isup_grade.values","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport scipy as sp\nfrom functools import partial\nfrom sklearn import metrics\nfrom collections import Counter\nimport json","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class OptimizedRounder(object):\n    def __init__(self):\n        self.coef_ = 0\n\n    def _kappa_loss(self, coef, X, y):\n        X_p = np.copy(X)\n        for i, pred in enumerate(X_p):\n            if pred < coef[0]:\n                X_p[i] = 0\n            elif pred >= coef[0] and pred < coef[1]:\n                X_p[i] = 1\n            elif pred >= coef[1] and pred < coef[2]:\n                X_p[i] = 2\n            elif pred >= coef[2] and pred < coef[3]:\n                X_p[i] = 3\n            elif pred >= coef[3] and pred < coef[4]:\n                X_p[i] = 4\n            else:\n                X_p[i] = 5\n\n        ll = metrics.cohen_kappa_score(y, X_p, weights='quadratic')\n        return -ll\n    def fit(self, X, y):\n        loss_partial = partial(self._kappa_loss, X=X, y=y)\n        initial_coef = [0.5, 1.5, 2.5, 3.5, 4.5]\n        self.coef_ = sp.optimize.minimize(loss_partial, initial_coef, method='nelder-mead')\n        print(-loss_partial(self.coef_['x']))\n\n    def predict(self, X, coef):\n        X_p = np.copy(X)\n#         coef = [0.5, 1.5, 2.5, 3.5, 4.5]\n        for i, pred in enumerate(X_p):\n            if pred < coef[0]:\n                X_p[i] = 0\n            elif pred >= coef[0] and pred < coef[1]:\n                X_p[i] = 1\n            elif pred >= coef[1] and pred < coef[2]:\n                X_p[i] = 2\n            elif pred >= coef[2] and pred < coef[3]:\n                X_p[i] = 3\n            elif pred >= coef[3] and pred < coef[4]:\n                X_p[i] = 4\n            else:\n                X_p[i] = 5\n        return X_p\n    \n    def coefficients(self):\n        return self.coef_['x']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"optR = OptimizedRounder()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# optR.fit(valid_preds,valid_labels[:])\n# coefficients = optR.coefficients()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# coefficients","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prediction","execution_count":null},{"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            #dihedral TTA\n            x = torch.stack([x,x.flip(-1),x.flip(-2),x.flip(-1,-2),\n              x.transpose(-1,-2),x.transpose(-1,-2).flip(-1),\n              x.transpose(-1,-2).flip(-2),x.transpose(-1,-2).flip(-1,-2)],1)\n            x = x.view(-1,N,3,img_size,img_size)\n            p = [model(x) for model in models]\n            p = torch.stack(p,1)\n            p = p.view(bs,8*len(models),-1).mean(1).cpu()\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":"coefficients = [0.538597, 1.585673, 2.633171, 3.240498, 4.070715]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"coefficients","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_predictions = optR.predict(preds, coefficients)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_predictions = test_predictions.reshape(1,-1).tolist()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"names = names.reshape(1,-1).tolist()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_df = pd.DataFrame({'image_id': names[0], 'isup_grade': test_predictions[0]})\nsub_df[\"isup_grade\"] = sub_df[\"isup_grade\"].astype(int)","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":{"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}