{"cells":[{"metadata":{},"cell_type":"markdown","source":"In this kernel, I finetune seresnext50 pretrained model on PANDA dataset. I used the tiles approach from [this kernel](http://https://www.kaggle.com/iafoss/panda-concat-tile-pooling-starter-0-79-lb) and learnt how to use TPU from [this kernel ](http://https://www.kaggle.com/tarunpaparaju/panda-challenge-resnet-multitask-8-fold-on-tpu). If you like the kernel please upvote this kernel and the above kernels as well.  ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install ../input/pretrainedmodels/pretrainedmodels-0.7.4/pretrainedmodels-0.7.4/ > /dev/null","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Import Libraries","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import sys\nimport os\nimport numpy as np\nimport pandas as pd \nimport glob\nimport random\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.optim.lr_scheduler as lr_scheduler\nfrom torch.nn import GroupNorm\nfrom torch.utils.data import Dataset, DataLoader, RandomSampler, SequentialSampler\nimport torch.nn.functional as F\nfrom sklearn.model_selection import StratifiedKFold\nimport torchvision.models as models\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\nfrom PIL import Image\nfrom tqdm.notebook import tqdm\nfrom sklearn.metrics import cohen_kappa_score, confusion_matrix\nimport pretrainedmodels\nimport cv2\nimport skimage.io\n\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"IMG_DIR = '/kaggle/input/prostate-cancer-grade-assessment/test_images/'\nDATA_DIR='/kaggle/input/prostate-cancer-grade-assessment/'\nWEIGHTS_DIR = '/kaggle/input/tpu-weights-to-cpu/'\n\nnum_classes=6\nN=12\nsz=128\nfiles=['SE_RNXT50_loss_1.pth','SE_RNXT50_loss_2.pth','SE_RNXT50_loss_3.pth','SE_RNXT50_loss_4.pth']\nnum_models=len(files)\ndevice='cuda' if torch.cuda.is_available() else 'cpu'\nseed=42\n\narch = pretrainedmodels.__dict__['se_resnext50_32x4d']\ntest = pd.read_csv(DATA_DIR+'test.csv')\nsub=pd.read_csv(DATA_DIR+'sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def seed_everything(seed=42):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n\nseed_everything(seed)\n","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"from torch.nn.parameter import Parameter\n\ndef gem(x, p=3, eps=1e-6):\n    return F.avg_pool2d(x.clamp(min=eps).pow(p), (x.size(-2), x.size(-1))).pow(1./p)\n\nclass GeM(nn.Module):\n    def __init__(self, p=3, eps=1e-6):\n        super(GeM,self).__init__()\n        self.p = Parameter(torch.ones(1)*p)\n        self.eps = eps\n    def forward(self, x):\n        return gem(x, p=self.p, eps=self.eps)       \n    def __repr__(self):\n        return self.__class__.__name__ + '(' + 'p=' + '{:.4f}'.format(self.p.data.tolist()[0]) + ', ' + 'eps=' + str(self.eps) + ')'\n    \n    \nclass Conv2d_ws(nn.Conv2d):\n\n    def __init__(self, in_channels, out_channels, kernel_size, stride=1,padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros'):\n        super(nn.Conv2d, self).__init__(in_channels, out_channels, kernel_size, stride,padding, dilation, bias=True ,padding_mode='zeros',\n                                       groups=1, output_padding='zeros', transposed=False)\n\n\n\n    def forward(self, x):\n        weight = self.weight\n        weight_mean = weight.mean(dim=1, keepdim=True).mean(dim=2,\n                                  keepdim=True).mean(dim=3, keepdim=True)\n        weight = weight - weight_mean\n        std = weight.view(weight.size(0), -1).std(dim=1).view(-1, 1, 1, 1) + 1e-5\n        weight = weight / std.expand_as(weight)\n        return F.conv2d(x, weight, self.bias, self.stride,\n                        self.padding, self.dilation, self.groups)\n    \n    \nimport math\ndef spatial_pyramid_pool(previous_conv, num_sample, previous_conv_size, out_pool_size):\n    '''\n    previous_conv: a tensor vector of previous convolution layer\n    num_sample: an int number of image in the batch\n    previous_conv_size: an int vector [height, width] of the matrix features size of previous convolution layer\n    out_pool_size: a int vector of expected output size of max pooling layer\n    \n    returns: a tensor vector with shape [1 x n] is the concentration of multi-level pooling\n    '''    \n    # print(previous_conv.size())\n    for i in range(len(out_pool_size)):\n        # print(previous_conv_size)\n        h_wid = int(math.ceil(previous_conv_size[0] / out_pool_size[i]))\n        w_wid = int(math.ceil(previous_conv_size[1] / out_pool_size[i]))\n        h_str = int(math.floor(previous_conv_size[0] / out_pool_size[i]))\n        w_str = int(math.floor(previous_conv_size[1] / out_pool_size[i]))        \n        h_pad = int((h_wid*out_pool_size[i] - previous_conv_size[0]+1)/2)\n        w_pad = int((w_wid*out_pool_size[i] - previous_conv_size[1]+1)/2)\n        maxpool = nn.MaxPool2d((h_wid, w_wid), stride=(h_str, w_str), padding=(h_pad, w_pad))\n        x = maxpool(previous_conv)\n        if(i == 0):\n            spp = x.view(num_sample,-1)\n            # print(\"spp size:\",spp.size())\n        else:\n            # print(\"size:\",spp.size())\n            spp = torch.cat((spp,x.view(num_sample,-1)), 1)\n    return spp\n\nclass SPP(nn.Module):\n    def __init__(self, n, shape, out):\n        super(SPP,self).__init__()\n        \n        self.batch = n\n        self.shape = shape\n        self.out = out\n        \n    def forward(self, x):\n        return spatial_pyramid_pool(x, self.batch, self.shape, self.out)\n    \n    \n    \ndef convert_to_gem(model):\n    for child_name, child in model.named_children():\n        if isinstance(child, nn.AdaptiveAvgPool2d):\n            setattr(model, child_name, GeM())\n        else:\n            convert_to_gem(child)\n            \ndef convert_to_conv2d(model):\n    for child_name, child in model.named_children():\n        if child_name not in ['fc1','fc2']:\n            if isinstance(child, nn.Conv2d):\n                in_feat = child.in_channels\n                out_feat = child.out_channels\n                ker_size = child.kernel_size\n                stride = child.stride\n                padding = child.padding\n                dilation = child.dilation\n                groups = child.groups\n                setattr(model, child_name, Conv2d_ws(in_channels=in_feat, out_channels=out_feat, kernel_size=ker_size, stride=stride,padding = padding, dilation=dilation, groups=groups))\n            else:\n                convert_to_conv2d(child)\n                \ndef convert_to_groupnorm(model):\n    for child_name, child in model.named_children():\n            if isinstance(child, nn.BatchNorm2d):\n                num_features = child.num_features\n                setattr(model, child_name, GroupNorm(num_groups=32, num_channels=num_features))\n            else:\n                convert_to_groupnorm(child)\n                \ndef convert_to_evonorm(model):\n    for child_name, child in model.named_children():\n            if isinstance(child, nn.BatchNorm2d):\n                num_features = child.num_features\n                setattr(model, child_name, EvoNorm2D(num_features))\n            else:\n                convert_to_evonorm(child)\n                \n                \ndef convert_to_identity(model):\n    for child_name, child in model.named_children():\n            if isinstance(child, nn.ReLU):\n                setattr(model, child_name, nn.Identity())\n            else:\n                convert_to_identity(child)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class PANDA_MODEL(nn.Module):\n    def __init__(self, pretrained=False, classes=num_classes, conv_ws=False):\n        super(PANDA_MODEL, self).__init__()\n        \n        m = arch(pretrained='imagenet') if pretrained else arch(pretrained=None)\n        in_feat = m.last_linear.in_features\n        self.base = nn.Sequential(*list(m.children())[:-2]) \n        self.gem = GeM()\n        self.linear1 = nn.Linear(in_features=in_feat, out_features= 512)\n        self.relu1=nn.ReLU()\n        self.bn = nn.BatchNorm1d(512)\n        self.dropout = nn.Dropout(0.5)\n        self.linear2 = nn.Linear(512,classes)\n        \n        if conv_ws:\n            convert_to_conv2d(self.base)       \n            convert_to_groupnorm(self.base)\n            \n    def forward(self, x):\n        n=len(x)\n        x=self.base(x)\n        x=self.gem(x)  \n        x=x.view(n,-1) \n        x=self.linear1(x)\n        x=self.bn(x)\n        x=self.relu1(x)\n        x=self.dropout(x)\n                \n        out=self.linear2(x)\n        \n        return out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def tile(img):\n    result = []\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    for i in range(len(img)):\n        result.append({'img':img[i], 'idx':i})\n    return result","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class PANDA(Dataset):\n    def __init__(self,df, transform, mode='train'):\n        self.df = df['image_id'].values\n        self.transform=transform\n        self.mode=mode\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):\n        img_id = self.df[idx]\n        tiles = tile(skimage.io.MultiImage(IMG_DIR+img_id+'.tiff')[-1])\n        \n        img=cv2.hconcat([cv2.vconcat([tiles[0]['img'], tiles[1]['img'], tiles[2]['img'], tiles[3]['img']]),\n                        cv2.vconcat([tiles[4]['img'], tiles[5]['img'], tiles[6]['img'], tiles[7]['img']]),\n                        cv2.vconcat([tiles[8]['img'], tiles[9]['img'], tiles[10]['img'], tiles[11]['img']])])\n        \n#         img=cv2.addWeighted( img,4, cv2.GaussianBlur( img , (0,0), sigmaX) ,-4 ,128)\n        \n        img = 255-img   # Very important. Background was 255. Now, background is zero. \n\n        if self.transform:\n            img = self.transform(image=img)['image']\n            \n        \n        if self.mode!='test':    \n            label = self.df['isup_grade'][idx]\n            \n        img = img.transpose(2,0,1)\n    \n        if self.mode!='test':\n            return {'image': torch.tensor(img, dtype=torch.float),\n                'provider': provider,\n               'label': torch.tensor(label, dtype=torch.long)}\n        \n        else:\n            return {'image': torch.tensor(img, dtype=torch.float),\n                    'img_id': img_id}            ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_models(weight):\n    model=PANDA_MODEL()\n    model.load_state_dict(torch.load(WEIGHTS_DIR+weight))\n    model.to(device)\n    model.eval()\n    return model\n\nall_models=[load_models(files[i]) for i in range(num_models)]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_tfm = A.Compose([A.Normalize(mean=[1-0.90949707,1-0.8188697,1-0.87795304],\n                                   std=[0.36357649,0.49984502,0.40477625])])\n\ntest_dataset = PANDA(test, test_tfm, mode='test')\ntest_loader = DataLoader(test_dataset, batch_size=2, sampler=SequentialSampler(test_dataset))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"if os.path.exists(IMG_DIR):\n    all_preds=[]\n    img_ids = []\n    with torch.no_grad():\n        for i, batch in tqdm(enumerate(test_loader), total=len(test_loader)):\n            img=batch['image'].to(device)\n            img_id = batch['img_id']\n            img_ids.append(img_id)\n            pred_array=np.zeros((len(img),6))\n    \n            for model in all_models:\n                prob=model(img)\n                pred_array+=prob.detach().cpu().numpy()/num_models\n        \n            pred = np.argmax(pred_array,1)\n            all_preds.append(pred)\n            \n    all_preds=np.concatenate(all_preds)\n    img_ids = np.concatenate(img_ids)\n    sub = pd.DataFrame()\n    sub['image_id']=img_ids\n    sub['isup_grade']=all_preds\n    sub.to_csv('submission.csv', index=False)\nelse:\n    sub.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub.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}