{"cells":[{"metadata":{},"cell_type":"markdown","source":"# DrHB","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 os\nimport cv2\nimport skimage.io\nfrom tqdm.notebook import tqdm\nimport zipfile\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport time\nfrom skimage import morphology\nfrom pdb import set_trace\nimport PIL\nimport torch\nfrom torch import tensor\nfrom torch.utils.data import DataLoader, Dataset\nimport pandas as pd\nfrom torch import nn\n\nimport fastai\nfrom fastai.vision import *\nfrom joblib import Parallel, delayed","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"SAMPLE = '../input/prostate-cancer-grade-assessment/sample_submission.csv'\nsub_df = pd.read_csv(SAMPLE)\nsub_df.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_drhb_best(debug=False):\n    N_FOLDS = 1\n    sz = 224\n    bs = 2\n    N = 81\n    nworkers = 2\n    imagenet_stats  = [[0.485, 0.456, 0.406], [0.229, 0.224, 0.225]]\n\n\n    DATA = '../input/prostate-cancer-grade-assessment/test_images'\n    TEST = '../input/prostate-cancer-grade-assessment/test.csv'\n    if debug:\n        DATA = '../input/prostate-cancer-grade-assessment/train_images'\n        TEST = '../input/prostate-cancer-grade-assessment/train.csv'\n        \n    SAMPLE = '../input/prostate-cancer-grade-assessment/sample_submission.csv'\n    MODELS = ['../input/exp-80/EXP_80_RESNET_34_TILES_81_SQ_FT_NBN_SE_DUAL_0_sq_features_41.pth']\n    IMG_OUT = 'imgs'\n\n\n\n    import scipy as sp\n    from sklearn import metrics\n\n\n    class OptimizedRounder():\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 = quadratic_weighted_kappa(y, X_p)\n            return -ll\n\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\n        def predict(self, X, coef):\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            return X_p\n\n        def coefficients(self):\n            return self.coef_['x']\n\n    def prepare_df(df):\n        uniq_id = list(df['image_id'].unique())\n        return df, uniq_id\n\n\n    def tile(img_name):\n        img = skimage.io.MultiImage(img_name)[-2]\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\n        img = img.reshape(img.shape[0]//sz,sz,img.shape[1]//sz,sz,3)\n\n\n        img = img.transpose(0,2,1,3,4).reshape(-1,sz,sz,3)\n        idxs = np.argsort(img.reshape(img.shape[0],-1).sum(-1))\n        img = img[idxs][:N]\n\n        if len(img)<N:\n            n = N-len(img)\n            img = np.concatenate([img, np.full((n,sz,sz,3),255,dtype=np.uint8)],0)\n\n        for i in range(len(img)):\n            result.append({'img':img[i],  'idx':i})\n        return result\n\n\n\n    def save_imgs(image_name, folder_path=DATA, image_folder_out=IMG_OUT):\n        image_nm = folder_path + '/' + image_name + '.tiff' \n        try:\n            tiles = tile(image_nm)\n            for t in tiles:\n                img,idx = t['img'], t['idx']\n                cv2.imwrite(f'{image_folder_out}/{image_name}_{idx}.png', cv2.cvtColor(img, cv2.COLOR_RGB2BGR))\n\n        except:\n            pass\n\n\n\n    class CustomEnd(nn.Module):\n        def __init__(self, scaler = SigmoidRange(-1, 6.0)):\n            super().__init__()\n            self.scaler_ = scaler\n\n        def forward(self, x):\n            classif = x[:, :-1]\n            regress = self.scaler_ (x[:, -1])\n            return classif, regress\n\n\n    import fastai\n\n    def make_divisible(v, divisor=8, min_value=None):\n       min_value = min_value or divisor\n       new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)\n       # Make sure that round down does not go down by more than 10%.\n       if new_v < 0.9 * v:\n          new_v += divisor\n       return new_v\n    def sigmoid(x, inplace: bool = False):\n       return x.sigmoid_() if inplace else x.sigmoid()\n    class SqueezeExcite(nn.Module):\n       def __init__(self, in_chs, se_ratio=0.25, reduced_base_chs=None,\n                 act_layer=nn.ReLU, gate_fn=sigmoid, divisor=1, **_):\n          super(SqueezeExcite, self).__init__()\n          self.gate_fn = gate_fn\n          reduced_chs = make_divisible((reduced_base_chs or in_chs) * se_ratio, divisor)\n          self.avg_pool = nn.AdaptiveAvgPool2d(1)\n          self.conv_reduce = nn.Conv2d(in_chs, reduced_chs, 1, bias=True)\n          self.act1 = act_layer(inplace=True)\n          self.conv_expand = nn.Conv2d(reduced_chs, in_chs, 1, bias=True)\n       def forward(self, x):\n          x_se = self.avg_pool(x)\n          x_se = self.conv_reduce(x_se)\n          x_se = self.act1(x_se)\n          x_se = self.conv_expand(x_se)\n          x = x * self.gate_fn(x_se)\n          return x\n\n    class CustomEnd(nn.Module):\n        def __init__(self, scaler = SigmoidRange(-1, 6.0)):\n            super().__init__()\n            self.scaler_ = scaler\n\n        def forward(self, x):\n            classif = x[:, :-1]\n            regress = self.scaler_ (x[:, -1])\n            return classif, regress\n\n\n    class ModelSeDul(nn.Module):\n        def __init__(self):\n            super().__init__()\n            m = fastai.vision.models.resnet34()\n            self.enc = nn.Sequential(*list(m.children())[:-2])       \n            nc = list(m.children())[-1].in_features\n            self.cb = SqueezeExcite(nc)\n            self.head = nn.Sequential(AdaptiveConcatPool2d(),\n                                      Flatten(),\n                                      nn.Linear(2*nc,512),\n                                      nn.ReLU(inplace=True),\n                                      nn.Dropout(0.4),\n                                      nn.Linear(512,7), \n                                      CustomEnd())\n\n\n\n\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, x.shape[1], x.shape[2], x.shape[3]).permute(0, 2, 1, 3, 4).contiguous().\\\n            view(-1, x.shape[1], x.shape[2] * n, x.shape[3])\n            x = x.view(x.shape[0], x.shape[1], x.shape[2]//int(np.sqrt(N)), -1)\n            x = self.cb(x)\n            x = self.head(x)\n            return x[1]\n\n\n\n    class PandasDSST2(Dataset):\n        def __init__(self, fnames,  stats=imagenet_stats, N=N, sz=sz, path = IMG_OUT):\n          self.items = fnames \n          self.stats = list(map(tensor, stats))\n          self.sz = sz\n          self.N =N\n          self.path = path\n\n        def __len__(self): \n          return len(self.items)\n\n        def __getitem__(self, idx):\n            imgs = []\n            fns = [f'{self.path}/{self.items[idx]}_{i}.png'   for i in range(self.N)]\n            for fn in fns:\n                img = PIL.Image.open(fn).convert('RGB')\n                img = tensor(np.array(img)).float()/255\n                img = self.normalize(img)\n                imgs.append(img)\n            return torch.cat(imgs).reshape(self.N, self.sz, self.sz, 3).permute(0, 3, 1, 2), self.items[idx]\n\n        def normalize(self, x):\n          return (x-self.stats[0])/self.stats[1]\n\n\n\n    models = []\n    for path in MODELS:\n        state_dict = torch.load(path,map_location=torch.device('cpu'))['model']\n        model = ModelSeDul()\n        model.load_state_dict(state_dict)\n        model.float()\n        model.eval()\n        model.cuda()\n        models.append(model)\n\n\n    optR = OptimizedRounder()\n    coefficients = [0.5, 1.5, 2.5,  3.5, 4.5]\n\n\n    def get_preds(N, nm, md_, TTA=False):\n        print('getting predictions:')\n        print (f\"{N}\")\n        ds = PandasDSST2(nm, N=N)\n        dl = DataLoader(ds, batch_size=bs, num_workers=nworkers, shuffle=False)\n        names,preds = [],[]\n        if TTA:\n            with torch.no_grad():\n                for x,y in tqdm(dl):\n                    x = x.cuda()\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,sz,sz)            \n                    p = [model(x) for model in md_]\n                    p = torch.stack(p,1)\n                    try:\n                        p = p.view(bs, 8*len(md_),-1).mean(1).cpu()\n                    except: \n                        bs_= p.shape[0]\n                        p = p.view(bs_, 8*len(md_),-1).mean(1).cpu()\n                    names.append(y)\n                    preds.append(p) \n\n        else:\n            with torch.no_grad():\n                for x,y in tqdm(dl):\n                    x = x.cuda()\n                    x = x.view(-1,N,3,sz,sz)\n                    p = [model(x) for model in md_]\n                    p = torch.stack(p,1)\n                    try:\n                        p = p.view(bs, len(md_),-1).mean(1).cpu()\n                    except:\n                        bs_= p.shape[0]\n                        p = p.view(bs_, len(md_),-1).mean(1).cpu()\n                    names.append(y)\n                    preds.append(p)\n\n        names = np.concatenate(names)\n        preds = torch.cat(preds).numpy().reshape(-1)\n        #pred_ = optR.predict(preds, coefficients).astype('int32')\n        sub_df = pd.DataFrame({'image_id': names, 'isup_grade': preds})\n        sub_df.to_csv('submission.csv', index=False)\n        return sub_df\n\n\n    sub_df = pd.read_csv(SAMPLE)\n    if os.path.exists(DATA):\n        nm = pd.read_csv(TEST).image_id.to_list()\n        if debug: \n            nm=nm[:100]\n        !mkdir imgs\n        Parallel(n_jobs=nworkers)(delayed(save_imgs)(i) for i in tqdm(nm));\n        sub_df = get_preds(81, nm, models, TTA=True)\n        sub_df.to_csv('submission.csv', index=False)\n        !rm -rf 'imgs'\n\n\n    sub_df.to_csv('submission.csv', index=False)\n    return sub_df\n\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA = '../input/prostate-cancer-grade-assessment/test_images'\nif os.path.exists(DATA):\n    res_drhb = get_drhb_best(False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.cuda.empty_cache()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Igor","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport skimage.io\nfrom skimage.util.shape import view_as_windows\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nimport cv2\nimport math\nimport collections\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader, Dataset\n\n\ndef get_igor_preds(debug=False):\n    weights = '/kaggle/input/rnx50ws7ep28/fold0_ep28pb2.pt'\n    \n    def fix_weights(weights):\n        state_dict = torch.load(weights)['model']\n        new_state_dict = collections.OrderedDict()\n        for k, v in state_dict.items():\n            name = k[7:]\n            new_state_dict[name] = v\n        return new_state_dict\n\n\n    def sigmoid_scale(x, low=-1.0, high=6.0):\n        return torch.sigmoid(x) * (high-low) + low\n\n\n    def make_divisible(v, divisor=8, min_value=None):\n        min_value = min_value or divisor\n        new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)\n        if new_v < 0.9 * v:\n            new_v += divisor\n        return new_v\n\n\n    def sigmoid(x, inplace: bool = False):\n        return x.sigmoid_() if inplace else x.sigmoid()\n    \n    class SqueezeExcite(nn.Module):\n        def __init__(self, in_chs, se_ratio=0.25, reduced_base_chs=None,\n                     act_layer=nn.ReLU, gate_fn=sigmoid, divisor=1, **_):\n            super(SqueezeExcite, self).__init__()\n            self.gate_fn = gate_fn\n            reduced_chs = make_divisible((reduced_base_chs or in_chs) * se_ratio, divisor)\n            self.avg_pool = nn.AdaptiveAvgPool2d(1)\n            self.conv_reduce = nn.Conv2d(in_chs, reduced_chs, 1, bias=True)\n            self.act1 = act_layer(inplace=True)\n            self.conv_expand = nn.Conv2d(reduced_chs, in_chs, 1, bias=True)\n\n        def forward(self, x):\n            x_se = self.avg_pool(x)\n            x_se = self.conv_reduce(x_se)\n            x_se = self.act1(x_se)\n            x_se = self.conv_expand(x_se)\n            x = x * self.gate_fn(x_se)\n            return x\n    \n\n    class AdaptiveConcatPool2d(nn.Module):\n        def __init__(self, sz=1):\n            super().__init__()\n            self.output_size = sz or 1\n            self.ap = nn.AdaptiveAvgPool2d(self.output_size)\n            self.mp = nn.AdaptiveMaxPool2d(self.output_size)\n\n        def forward(self, x):\n            return torch.cat([self.mp(x), self.ap(x)], 1)\n\n\n    class c_Conv2d(nn.Conv2d):\n\n        def __init__(self, in_channels, out_channels, kernel_size, stride=1,\n                     padding=0, dilation=1, groups=1, bias=True):\n            super(c_Conv2d, self).__init__(in_channels, out_channels, kernel_size, stride,\n                     padding, dilation, groups, bias)\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\n    def c_BatchNorm2d(num_features):\n        return nn.GroupNorm(num_channels=num_features, num_groups=32)\n\n\n    class Bottleneck(nn.Module):\n        expansion = 4\n\n        def __init__(self, inplanes, planes, baseWidth, cardinality, stride=1, downsample=None):\n\n            super(Bottleneck, self).__init__()\n\n            D = int(math.floor(planes * (baseWidth / 64)))\n            C = cardinality\n\n            self.conv1 = c_Conv2d(inplanes, D*C, kernel_size=1, stride=1, padding=0, bias=False)\n            self.bn1 = c_BatchNorm2d(D*C)\n            self.conv2 = c_Conv2d(D*C, D*C, kernel_size=3, stride=stride, padding=1, groups=C, bias=False)\n            self.bn2 = c_BatchNorm2d(D*C)\n            self.conv3 = c_Conv2d(D*C, planes * 4, kernel_size=1, stride=1, padding=0, bias=False)\n            self.bn3 = c_BatchNorm2d(planes * 4)\n            self.relu = nn.ReLU(inplace=True)\n\n            self.downsample = downsample\n\n        def forward(self, x):\n            residual = x\n\n            out = self.conv1(x)\n            out = self.bn1(out)\n            out = self.relu(out)\n\n            out = self.conv2(out)\n            out = self.bn2(out)\n            out = self.relu(out)\n\n            out = self.conv3(out)\n            out = self.bn3(out)\n\n            if self.downsample is not None:\n                residual = self.downsample(x)\n\n            out += residual\n            out = self.relu(out)\n\n            return out\n\n\n    class ResNeXt(nn.Module):\n\n        def __init__(self, baseWidth, cardinality, layers, num_classes):\n            super(ResNeXt, self).__init__()\n            block = Bottleneck\n\n            self.cardinality = cardinality\n            self.baseWidth = baseWidth\n            self.num_classes = num_classes\n            self.inplanes = 64\n            self.output_size = 64\n\n            self.conv1 = c_Conv2d(3, 64, 7, 2, 3, bias=False)\n            self.bn1 = c_BatchNorm2d(64)\n            self.relu = nn.ReLU(inplace=True)\n            self.maxpool1 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)\n            self.layer1 = self._make_layer(block, 64, layers[0])\n            self.layer2 = self._make_layer(block, 128, layers[1], 2)\n            self.layer3 = self._make_layer(block, 256, layers[2], 2)\n            self.layer4 = self._make_layer(block, 512, layers[3], 2)\n            self.avgpool = nn.AvgPool2d(7)\n            self.fc = nn.Linear(512 * block.expansion, num_classes)\n\n            for m in self.modules():\n                if isinstance(m, nn.Conv2d):\n                    n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels\n                    m.weight.data.normal_(0, math.sqrt(2. / n))\n                elif isinstance(m, nn.BatchNorm2d):\n                    m.weight.data.fill_(1)\n                    m.bias.data.zero_()\n\n        def _make_layer(self, block, planes, blocks, stride=1):\n\n            downsample = None\n            if stride != 1 or self.inplanes != planes * block.expansion:\n                downsample = nn.Sequential(\n                    c_Conv2d(self.inplanes, planes * block.expansion,\n                              kernel_size=1, stride=stride, bias=False),\n                    c_BatchNorm2d(planes * block.expansion),\n                )\n\n            layers = []\n            layers.append(block(self.inplanes, planes, self.baseWidth, self.cardinality, stride, downsample))\n            self.inplanes = planes * block.expansion\n            for i in range(1, blocks):\n                layers.append(block(self.inplanes, planes, self.baseWidth, self.cardinality))\n\n            return nn.Sequential(*layers)\n\n        def forward(self, x):\n            x = self.conv1(x)\n            x = self.bn1(x)\n            x = self.relu(x)\n            x = self.maxpool1(x)\n            x = self.layer1(x)\n            x = self.layer2(x)\n            x = self.layer3(x)\n            x = self.layer4(x)\n            x = self.avgpool(x)\n            x = x.view(x.size(0), -1)\n            x = self.fc(x)\n\n            return x\n\n\n    class Resnext50_ws(nn.Module):\n        def __init__(self, baseWidth=4, cardinality=32):\n            super(Resnext50_ws, self).__init__()\n            base_model = ResNeXt(baseWidth, cardinality, [3, 4, 6, 3], 1000)\n            self.base_model = nn.Sequential(*list(base_model.children())[:-2])\n            nc = list(base_model.children())[-1].in_features\n            self.conv_block = SqueezeExcite(nc)\n            self.head = nn.Sequential(AdaptiveConcatPool2d(),\n                                      nn.Flatten(),\n                                      nn.Linear(2 * nc, 512),\n                                      nn.ReLU(),\n                                      nn.Dropout(0.4),\n                                      nn.Linear(512, 1, bias=False))\n\n        def forward(self, x):\n            n = x.shape[1]\n            x = x.view(-1, x.shape[2], x.shape[3], x.shape[4])\n            x = self.base_model(x)\n            x = x.view(-1, n, x.shape[1], x.shape[2], x.shape[3]).permute(0, 2, 1, 3, 4).contiguous().view(-1, x.shape[1], x.shape[2] * n, x.shape[3])\n            x = x.view(x.shape[0], x.shape[1], x.shape[2]//7, -1)\n            x = self.conv_block(x)\n            x = self.head(x)\n            return sigmoid_scale(x)\n\n        \n    def crop(img, tol=254):\n        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n        mask = gray < tol\n        img1 = img[:, :, 0][np.ix_(mask.any(1), mask.any(0))]\n        img2 = img[:, :, 1][np.ix_(mask.any(1), mask.any(0))]\n        img3 = img[:, :, 2][np.ix_(mask.any(1), mask.any(0))]\n        img = np.stack([img1, img2, img3], axis=-1)\n        \n        _, img = cv2.threshold(img, 0, 255, cv2.THRESH_TOZERO)\n        return img\n\n\n    def pad_if_needed(img, tile):\n        if img.shape[0] % tile != 0 or img.shape[1] % tile != 0:\n            pad1 = int(np.ceil(img.shape[0] / tile))\n            pad1 = tile * pad1 - img.shape[0]\n            pad2 = int(np.ceil(img.shape[1] / tile))\n            pad2 = tile * pad2 - img.shape[1]\n            img_pad = np.pad(img, ((pad1, 0), (pad2, 0), (0, 0)), constant_values=255)\n            return img_pad\n        else:\n            return img\n    \n    def windows(img_fn, tiles=49, tile_size=224, overlap=1, threshold=254):\n        res = skimage.io.MultiImage(img_fn)[-2]\n        res = crop(res)\n        res = pad_if_needed(res, tile_size)\n    \n        windows = view_as_windows(res, (tile_size, tile_size, 1), (int(tile_size*overlap), int(tile_size*overlap), 1))[..., 0].transpose(0, 1, 3, 4, 2)\n        windows_orig = windows.reshape(windows.shape[0] * windows.shape[1], windows.shape[2], windows.shape[3], windows.shape[4])\n        mean = np.mean(windows_orig, axis=(1, 2, 3))\n        windows = np.delete(windows_orig, np.where(mean >= threshold), axis=0)\n    \n        if windows.shape[0] == 0:\n            windows = windows_orig\n        idxs = np.argsort(windows.reshape(windows.shape[0], -1).sum(-1))[:tiles]#[::-1]\n        if windows.shape[0] < tiles:\n            #windows_pad = np.repeat(np.expand_dims(windows[idxs[0]], 0), tiles - windows.shape[0], axis=0)\n            windows_pad = np.repeat(255*np.ones_like(np.expand_dims(windows[0], 0)), tiles - windows.shape[0], axis=0)\n            windows = np.concatenate((windows, windows_pad), axis=0)\n        else:\n            windows = windows[idxs]\n\n        return windows\n\n\n\n    def embed_output(output):\n        thrs = [0.5, 1.5, 2.5, 3.5, 4.5]\n        output[output < thrs[0]] = 0\n        output[(output >= thrs[0]) & (output < thrs[1])] = 1\n        output[(output >= thrs[1]) & (output < thrs[2])] = 2\n        output[(output >= thrs[2]) & (output < thrs[3])] = 3\n        output[(output >= thrs[3]) & (output < thrs[4])] = 4\n        output[output >= thrs[4]] = 5\n        return output\n\n\n    class TestDataset(Dataset):\n        def __init__(self, df, path):\n            self.df = df\n            self.path = path\n            \n        def __len__(self):\n            return len(self.df)\n\n        def __getitem__(self, idx):\n            row = self.df.iloc[idx]\n            img_path = '%s%s.tiff' % (self.path, row.image_id)\n            image = windows(img_path)\n            return torch.tensor(image.transpose(0, 3, 1, 2)).float()/255, row.image_id\n    \n\n\n    model = Resnext50_ws().cuda()\n    model.load_state_dict(fix_weights(weights))\n\n    preds = []\n    preds_raw = []\n    names = []\n    \n    path = '/kaggle/input/prostate-cancer-grade-assessment/test_images/'\n    submission = pd.read_csv('/kaggle/input/prostate-cancer-grade-assessment/test.csv')\n    \n    if debug:\n        path = '/kaggle/input/prostate-cancer-grade-assessment/train_images/'\n        submission = pd.read_csv('/kaggle/input/prostate-cancer-grade-assessment/train.csv')[:100]\n    #submission = pd.read_csv('/kaggle/input/prostate-cancer-grade-assessment/sample_submission.csv')\n\n    if os.path.exists(path):\n        test_dataset = TestDataset(submission, path)\n        test_loader = DataLoader(test_dataset, batch_size=1, shuffle=False)\n\n        for i, (images, name) in enumerate(test_loader):\n            images = images.cuda()\n\n            with torch.no_grad():\n                y_preds = model(images)\n        \n            preds.append(embed_output(y_preds.cpu().numpy()))\n            preds_raw.append(y_preds.cpu().numpy())\n            names.extend(name)\n        \n        preds_out = np.concatenate(preds)\n        preds_out_raw = np.concatenate(preds_raw).reshape(-1)\n\n        result = pd.DataFrame({\n            'image_id':names,\n            'isup_grade':preds_out_raw\n        })\n        return result","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA = '../input/prostate-cancer-grade-assessment/test_images'\nif os.path.exists(DATA):\n    res_igor = get_igor_preds(False)\n    \ntorch.cuda.empty_cache()\nimport gc\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Rui se 50","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import openslide\nfrom PIL import Image\nimport os\nimport tqdm\nimport torch\nimport torch.nn as nn\nfrom torch.nn.parameter import Parameter\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader\nimport numpy as np\nimport pandas as pd  \nfrom tqdm import tqdm_notebook as tqdm\nfrom collections import OrderedDict\nimport math\nimport time\nimport cv2\nimport skimage.io\nimport gc\nimport types\n\ndef get_prediction_medianse50(debug=False):\n    model_path=    [\"../input/pandamsesmoothse50/se_resnext50_32x4d_fold0_bestOptimQWK.pth\",\n                    \"../input/pandamsesmoothse50/se_resnext50_32x4d_fold1_bestOptimQWK.pth\",\n                    \"../input/pandamsesmoothse50/se_resnext50_32x4d_fold2_bestOptimQWK.pth\",\n                    \"../input/pandamsesmoothse50/se_resnext50_32x4d_fold3_bestOptimQWK.pth\",\n                    \"../input/pandamsesmoothse50/se_resnext50_32x4d_fold4_bestOptimQWK.pth\"]\n    if debug:\n        img_dir=\"../input/prostate-cancer-grade-assessment/train_images/\"\n        df=pd.read_csv(\"../input/prostate-cancer-grade-assessment/train.csv\")[:100]\n    else:\n        df=pd.read_csv(\"../input/prostate-cancer-grade-assessment/test.csv\")\n        img_dir=\"../input/prostate-cancer-grade-assessment/test_images/\"\n\n    def tile(img,sz=128,N=12):\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        idxs = np.argsort(img.reshape(img.shape[0],-1).sum(-1))[:N]\n        img = img[idxs]\n        return 1-img.astype(np.float32)/255\n\n    def crop_white(image: np.ndarray, value: int = 255) -> np.ndarray:\n        assert image.shape[2] == 3\n        assert image.dtype == np.uint8\n        ys, = (image.min((1, 2)) < value).nonzero()\n        xs, = (image.min(0).min(1) < value).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]\n\n    class DataSet_Test(object):\n        def __init__(self,\n                     df,\n                     img_dir,\n                     size,\n                     num_patch,\n                     grid_offset=(0,1/3,2/3),\n                     mean=(0.485, 0.456, 0.406),\n                     std=(0.229, 0.224, 0.225),\n                     ):\n            self.image_ids=df.image_id.tolist()\n            self.img_dir=img_dir\n            self.mean=mean\n            self.std=std\n            self.size=size\n            self.num_patch=num_patch\n            self.grid_offset=grid_offset\n\n        def __getitem__(self, idx):\n            img_id=self.image_ids[idx]\n            image=skimage.io.MultiImage(os.path.join(self.img_dir, \"{}.tiff\".format(img_id)))[1]\n            #image = openslide.OpenSlide(os.path.join(self.img_dir, \"{}.tiff\".format(img_id)))\n            #size = image.level_dimensions[1]\n            #image = np.array(image.read_region((0, 0), 1, size))[:, :, :3]\n            #image=cv2.imread(os.path.join(self.img_dir, \"{}.jpg\".format(img_id)))[:,:,::-1]\n            image=crop_white(image)\n            _, encoded_img = cv2.imencode(\".jpg\", image, (int(cv2.IMWRITE_JPEG_QUALITY), 100))\n            image = cv2.imdecode(encoded_img, cv2.IMREAD_UNCHANGED)\n\n            #shape = image.shape\n            #image = cv2.resize(image, dsize=(shape[1] // 2, shape[0] // 2))\n\n\n            shape = image.shape\n\n\n            pad0, pad1 = (self.size - shape[0] % self.size) % self.size, (self.size - shape[1] % self.size) % self.size\n\n            pad_up = pad0 // 2\n            pad_left = pad1 // 2\n\n            all_patches=[]\n            for offset in self.grid_offset:\n                pad_up_tmp=pad_up+int(offset*self.size)\n                pad_left_tmp=pad_left+int(offset*self.size)\n                tmp_img = np.pad(image, [[pad_up_tmp, self.size+pad0 - pad_up_tmp], [pad_left_tmp, self.size+pad1 - pad_left_tmp], [0, 0]],constant_values=255)\n                patch=tile(tmp_img,sz=self.size,N=self.num_patch)\n                all_patches.append(patch)\n\n\n\n            all_patches=np.stack(all_patches,axis=0) #[ntta,Npatch,sz,sz,3]\n            all_patches=(all_patches-self.mean)/self.std\n\n            return torch.tensor(all_patches,dtype=torch.float32).permute(0,1,4,2,3),img_id\n\n        def __len__(self):\n            return len(self.image_ids)\n        \n    class SEModule(nn.Module):\n\n        def __init__(self, channels, reduction):\n            super(SEModule, self).__init__()\n            self.avg_pool = nn.AdaptiveAvgPool2d(1)\n            self.fc1 = nn.Conv2d(channels, channels // reduction, kernel_size=1,\n                                 padding=0)\n            self.relu = nn.ReLU(inplace=True)\n            self.fc2 = nn.Conv2d(channels // reduction, channels, kernel_size=1,\n                                 padding=0)\n            self.sigmoid = nn.Sigmoid()\n\n        def forward(self, x):\n            module_input = x\n            x = self.avg_pool(x)\n            x = self.fc1(x)\n            x = self.relu(x)\n            x = self.fc2(x)\n            x = self.sigmoid(x)\n            return module_input * x\n\n\n    class Bottleneck(nn.Module):\n        \"\"\"\n        Base class for bottlenecks that implements `forward()` method.\n        \"\"\"\n        def forward(self, x):\n            residual = x\n\n            out = self.conv1(x)\n            out = self.bn1(out)\n            out = self.relu(out)\n\n            out = self.conv2(out)\n            out = self.bn2(out)\n            out = self.relu(out)\n\n            out = self.conv3(out)\n            out = self.bn3(out)\n\n            if self.downsample is not None:\n                residual = self.downsample(x)\n\n            out = self.se_module(out) + residual\n            out = self.relu(out)\n\n            return out\n\n\n    class SEBottleneck(Bottleneck):\n        \"\"\"\n        Bottleneck for SENet154.\n        \"\"\"\n        expansion = 4\n\n        def __init__(self, inplanes, planes, groups, reduction, stride=1,\n                     downsample=None):\n            super(SEBottleneck, self).__init__()\n            self.conv1 = nn.Conv2d(inplanes, planes * 2, kernel_size=1, bias=False)\n            self.bn1 = nn.BatchNorm2d(planes * 2)\n            self.conv2 = nn.Conv2d(planes * 2, planes * 4, kernel_size=3,\n                                   stride=stride, padding=1, groups=groups,\n                                   bias=False)\n            self.bn2 = nn.BatchNorm2d(planes * 4)\n            self.conv3 = nn.Conv2d(planes * 4, planes * 4, kernel_size=1,\n                                   bias=False)\n            self.bn3 = nn.BatchNorm2d(planes * 4)\n            self.relu = nn.ReLU(inplace=True)\n            self.se_module = SEModule(planes * 4, reduction=reduction)\n            self.downsample = downsample\n            self.stride = stride\n\n\n    class SEResNetBottleneck(Bottleneck):\n        \"\"\"\n        ResNet bottleneck with a Squeeze-and-Excitation module. It follows Caffe\n        implementation and uses `stride=stride` in `conv1` and not in `conv2`\n        (the latter is used in the torchvision implementation of ResNet).\n        \"\"\"\n        expansion = 4\n\n        def __init__(self, inplanes, planes, groups, reduction, stride=1,\n                     downsample=None):\n            super(SEResNetBottleneck, self).__init__()\n            self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False,\n                                   stride=stride)\n            self.bn1 = nn.BatchNorm2d(planes)\n            self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, padding=1,\n                                   groups=groups, bias=False)\n            self.bn2 = nn.BatchNorm2d(planes)\n            self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)\n            self.bn3 = nn.BatchNorm2d(planes * 4)\n            self.relu = nn.ReLU(inplace=True)\n            self.se_module = SEModule(planes * 4, reduction=reduction)\n            self.downsample = downsample\n            self.stride = stride\n\n\n    class SEResNeXtBottleneck(Bottleneck):\n        \"\"\"\n        ResNeXt bottleneck type C with a Squeeze-and-Excitation module.\n        \"\"\"\n        expansion = 4\n\n        def __init__(self, inplanes, planes, groups, reduction, stride=1,\n                     downsample=None, base_width=4):\n            super(SEResNeXtBottleneck, self).__init__()\n            width = math.floor(planes * (base_width / 64)) * groups\n            self.conv1 = nn.Conv2d(inplanes, width, kernel_size=1, bias=False,\n                                   stride=1)\n            self.bn1 = nn.BatchNorm2d(width)\n            self.conv2 = nn.Conv2d(width, width, kernel_size=3, stride=stride,\n                                   padding=1, groups=groups, bias=False)\n            self.bn2 = nn.BatchNorm2d(width)\n            self.conv3 = nn.Conv2d(width, planes * 4, kernel_size=1, bias=False)\n            self.bn3 = nn.BatchNorm2d(planes * 4)\n            self.relu = nn.ReLU(inplace=True)\n            self.se_module = SEModule(planes * 4, reduction=reduction)\n            self.downsample = downsample\n            self.stride = stride\n\n\n    class SENet(nn.Module):\n\n        def __init__(self, block, layers, groups, reduction, dropout_p=0.2,\n                     inplanes=128, input_3x3=True, downsample_kernel_size=3,\n                     downsample_padding=1, num_classes=1000):\n            \"\"\"\n            Parameters\n            ----------\n            block (nn.Module): Bottleneck class.\n                - For SENet154: SEBottleneck\n                - For SE-ResNet models: SEResNetBottleneck\n                - For SE-ResNeXt models:  SEResNeXtBottleneck\n            layers (list of ints): Number of residual blocks for 4 layers of the\n                network (layer1...layer4).\n            groups (int): Number of groups for the 3x3 convolution in each\n                bottleneck block.\n                - For SENet154: 64\n                - For SE-ResNet models: 1\n                - For SE-ResNeXt models:  32\n            reduction (int): Reduction ratio for Squeeze-and-Excitation modules.\n                - For all models: 16\n            dropout_p (float or None): Drop probability for the Dropout layer.\n                If `None` the Dropout layer is not used.\n                - For SENet154: 0.2\n                - For SE-ResNet models: None\n                - For SE-ResNeXt models: None\n            inplanes (int):  Number of input channels for layer1.\n                - For SENet154: 128\n                - For SE-ResNet models: 64\n                - For SE-ResNeXt models: 64\n            input_3x3 (bool): If `True`, use three 3x3 convolutions instead of\n                a single 7x7 convolution in layer0.\n                - For SENet154: True\n                - For SE-ResNet models: False\n                - For SE-ResNeXt models: False\n            downsample_kernel_size (int): Kernel size for downsampling convolutions\n                in layer2, layer3 and layer4.\n                - For SENet154: 3\n                - For SE-ResNet models: 1\n                - For SE-ResNeXt models: 1\n            downsample_padding (int): Padding for downsampling convolutions in\n                layer2, layer3 and layer4.\n                - For SENet154: 1\n                - For SE-ResNet models: 0\n                - For SE-ResNeXt models: 0\n            num_classes (int): Number of outputs in `last_linear` layer.\n                - For all models: 1000\n            \"\"\"\n            super(SENet, self).__init__()\n            self.inplanes = inplanes\n            if input_3x3:\n                layer0_modules = [\n                    ('conv1', nn.Conv2d(3, 64, 3, stride=2, padding=1,\n                                        bias=False)),\n                    ('bn1', nn.BatchNorm2d(64)),\n                    ('relu1', nn.ReLU(inplace=True)),\n                    ('conv2', nn.Conv2d(64, 64, 3, stride=1, padding=1,\n                                        bias=False)),\n                    ('bn2', nn.BatchNorm2d(64)),\n                    ('relu2', nn.ReLU(inplace=True)),\n                    ('conv3', nn.Conv2d(64, inplanes, 3, stride=1, padding=1,\n                                        bias=False)),\n                    ('bn3', nn.BatchNorm2d(inplanes)),\n                    ('relu3', nn.ReLU(inplace=True)),\n                ]\n            else:\n                layer0_modules = [\n                    ('conv1', nn.Conv2d(3, inplanes, kernel_size=7, stride=2,\n                                        padding=3, bias=False)),\n                    ('bn1', nn.BatchNorm2d(inplanes)),\n                    ('relu1', nn.ReLU(inplace=True)),\n                ]\n            # To preserve compatibility with Caffe weights `ceil_mode=True`\n            # is used instead of `padding=1`.\n            layer0_modules.append(('pool', nn.MaxPool2d(3, stride=2,\n                                                        ceil_mode=True)))\n            self.layer0 = nn.Sequential(OrderedDict(layer0_modules))\n            self.layer1 = self._make_layer(\n                block,\n                planes=64,\n                blocks=layers[0],\n                groups=groups,\n                reduction=reduction,\n                downsample_kernel_size=1,\n                downsample_padding=0\n            )\n            self.layer2 = self._make_layer(\n                block,\n                planes=128,\n                blocks=layers[1],\n                stride=2,\n                groups=groups,\n                reduction=reduction,\n                downsample_kernel_size=downsample_kernel_size,\n                downsample_padding=downsample_padding\n            )\n            self.layer3 = self._make_layer(\n                block,\n                planes=256,\n                blocks=layers[2],\n                stride=2,\n                groups=groups,\n                reduction=reduction,\n                downsample_kernel_size=downsample_kernel_size,\n                downsample_padding=downsample_padding\n            )\n            self.layer4 = self._make_layer(\n                block,\n                planes=512,\n                blocks=layers[3],\n                stride=2,\n                groups=groups,\n                reduction=reduction,\n                downsample_kernel_size=downsample_kernel_size,\n                downsample_padding=downsample_padding\n            )\n            self.avg_pool = nn.AvgPool2d(7, stride=1)\n            self.dropout = nn.Dropout(dropout_p) if dropout_p is not None else None\n            self.last_linear = nn.Linear(512 * block.expansion, num_classes)\n\n        def _make_layer(self, block, planes, blocks, groups, reduction, stride=1,\n                        downsample_kernel_size=1, downsample_padding=0):\n            downsample = None\n            if stride != 1 or self.inplanes != planes * block.expansion:\n                downsample = nn.Sequential(\n                    nn.Conv2d(self.inplanes, planes * block.expansion,\n                              kernel_size=downsample_kernel_size, stride=stride,\n                              padding=downsample_padding, bias=False),\n                    nn.BatchNorm2d(planes * block.expansion),\n                )\n\n            layers = []\n            layers.append(block(self.inplanes, planes, groups, reduction, stride,\n                                downsample))\n            self.inplanes = planes * block.expansion\n            for i in range(1, blocks):\n                layers.append(block(self.inplanes, planes, groups, reduction))\n\n            return nn.Sequential(*layers)\n\n        def features(self, x):\n            x = self.layer0(x)\n            x = self.layer1(x)\n            x = self.layer2(x)\n            x = self.layer3(x)\n            x = self.layer4(x)\n            return x\n\n        def features_ckpt(self,x):\n            x.requires_grad=True\n            x = checkpoint(self.layer0,x)\n            x = checkpoint_sequential(self.layer1,3,x)\n            x = checkpoint_sequential(self.layer2,4,x)\n            x = checkpoint_sequential(self.layer3,6,x)\n            x = checkpoint_sequential(self.layer4,3,x)\n            return x\n\n\n        def logits(self, x):\n            x = self.avg_pool(x)\n            if self.dropout is not None:\n                x = self.dropout(x)\n            x = x.view(x.size(0), -1)\n            x = self.last_linear(x)\n            return x\n\n        def forward(self, x):\n            x = self.features(x)\n            x = self.logits(x)\n            return x\n\n    def se_resnext50_32x4d(num_classes=1000, pretrained='imagenet'):\n        model = SENet(SEResNeXtBottleneck, [3, 4, 6, 3], groups=32, reduction=16,\n                      dropout_p=None, inplanes=64, input_3x3=False,\n                      downsample_kernel_size=1, downsample_padding=0,\n                      num_classes=num_classes)\n        return model\n    \n    class AttentionPool(nn.Module):\n        def __init__(self,in_ch,hidden=512,dropout=True):\n            super().__init__()\n            self.in_ch=in_ch\n\n            module=[nn.Linear(in_ch,hidden,bias=True),\n                    nn.Tanh()\n                    ]\n            if dropout:\n                module.append(nn.Dropout(0.25))\n            module.append(nn.Linear(hidden,1,bias=True))\n            self.attention=nn.Sequential(*module)\n\n        def forward(self,x):\n            num_patch=x.size(1)\n            x=x.view(-1,x.size(2))\n            A=self.attention(x)\n            A=A.view(-1,num_patch,1)\n            wt=F.softmax(A,dim=1)\n            return (x.view(-1,num_patch,self.in_ch)*wt).sum(dim=1),A\n\n    class AdaptiveConcatPool2d_Attention(nn.Module):\n        def __init__(self, in_ch,hidden=512,dropout=True):\n            super().__init__()\n            sz = (1,1)\n            self.ap = AttentionPool(in_ch,hidden=hidden,dropout=dropout)\n            self.mp = nn.AdaptiveMaxPool2d(sz)\n            self.in_ch=in_ch\n        def forward(self, x):\n            ap,A=self.ap(x)#[batch,num_patch,C]\n            mp=torch.max(x,dim=1)[0]\n            return torch.cat([ap, mp], dim=1),A\n\n    class PANDA_Model_Attention_Concat_MultiTask_Headv2(nn.Module):\n        def __init__(self,arch='se_resnext50_32x4d',dropout=0.25,num_classes=6,checkpoint=False,scale_op=True):\n            super().__init__()\n            if \"se\" in arch:\n                self.base_model=se_resnext50_32x4d(pretrained=None)\n                back_feature=self.base_model.last_linear.in_features\n            elif \"efficientnet\" in arch:\n                self.base_model = EfficientNet.from_pretrained(arch, num_classes=num_classes)\n                back_feature = self.base_model._fc.in_features\n            else:\n                self.base_model= resnet34(pretrained=None)\n                back_feature=self.base_model.last_linear.in_features\n            self.checkpoint=checkpoint\n            self.avg_pool=nn.AdaptiveAvgPool2d(1)\n            self.scale_op=scale_op\n\n            self.attention=AdaptiveConcatPool2d_Attention(in_ch=back_feature,hidden=512,dropout=dropout>0)\n\n            self.label_head=nn.Sequential(\n                nn.Dropout(p=dropout),\n                nn.Linear(back_feature,1,bias=True)\n            )\n\n            self.reg_head = nn.Sequential(\n                nn.Dropout(p=dropout),\n                nn.Linear(2*back_feature,1,bias=True),\n            )\n            self.cls_head = nn.Sequential(\n                nn.Dropout(p=dropout),\n                nn.Linear(2*back_feature,num_classes,bias=True),\n            )\n\n\n        def forward(self,x):\n            # x [bs,n,3,h,w]\n            B,N,C,H,W=x.shape\n            x=x.view(-1,C,H,W)\n            if self.checkpoint:\n                x=self.base_model.features_ckpt(x)\n            else:\n                x=self.base_model.features(x)\n            x=self.avg_pool(x).view(x.size(0),-1)\n\n            patch_pred=self.label_head(x)\n            x=x.view(B,N,-1)\n            x,A=self.attention(x)\n            reg_pred=self.reg_head(x).view(-1)\n            if self.scale_op:\n                reg_pred=7.*torch.sigmoid(reg_pred)-1.\n            cls_pred=self.cls_head(x)\n            return reg_pred,cls_pred,patch_pred,A\n\n    modellist=[]\n    for path in model_path:\n        model=PANDA_Model_Attention_Concat_MultiTask_Headv2(arch='se_resnext50_32x4d',dropout=0.4,num_classes=6,scale_op=True)\n        model.cuda()\n        print(\"Loading\",path)\n        ckpt=torch.load(path)\n        model.load_state_dict(ckpt['state_dict'])\n        model.eval()\n        modellist.append(model)\n    print(len(modellist),\"models Loaded\")\n    \n    grid_offset=[0,1/2]\n    num_offset=len(grid_offset)\n    num_patch=48\n    patch_size=192\n\n    dataset=DataSet_Test(df,img_dir,size=patch_size,num_patch=num_patch,grid_offset=grid_offset)\n    dataloader=DataLoader(dataset,batch_size=4,shuffle=False,num_workers=2)\n    \n    def get_expectation(cls_output,label):\n        prob=torch.softmax(cls_output.cpu(),dim=2)\n        prob=torch.mean(prob,dim=1)\n        return (label*prob).sum(dim=1)\n    label=torch.tensor([0,1,2,3,4,5],dtype=torch.float32).view(1,-1)\n    reg_weight=1\n    if os.path.exists(img_dir):\n        prediction=[]\n        name=[]\n        for images,img_ids in tqdm(dataloader):\n            images=images.cuda()\n            images=images.view(-1,num_patch,3,patch_size,patch_size)\n\n            reg_pred=0.\n            cls_pred=0.\n            with torch.no_grad():\n                for model in modellist:\n                    reg_output,cls_output,patch_pred,A=model(images)\n                    cls_output=cls_output.view(-1,num_offset,6)\n                    reg_output=reg_output.view(-1,num_offset)\n                    reg_pred+=reg_output.detach().cpu().numpy().mean(axis=1)\n                    cls_pred+=get_expectation(cls_output,label).numpy()\n            reg_pred/=len(modellist)\n            cls_pred/=len(modellist)\n\n            pred_batch=reg_weight*reg_pred+(1-reg_weight)*cls_pred\n\n            prediction.append(pred_batch)\n            name.extend(img_ids)\n        prediction=np.concatenate(prediction).reshape(-1)\n\n        result=pd.DataFrame({\n            'image_id':name,\n            'isup_grade':prediction\n        })\n        return result\n    else:\n        df=pd.read_csv(\"../input/prostate-cancer-grade-assessment/sample_submission.csv\")\n        return df\n    \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA = '../input/prostate-cancer-grade-assessment/test_images'\nif os.path.exists(DATA):\n    res_rs50 = get_prediction_medianse50(debug=False)\n    \ntorch.cuda.empty_cache()\ngc.collect()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Rui efnet","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from __future__ import print_function, division, absolute_import\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader\nimport numpy as np\nimport pandas as pd\n\nfrom tqdm import tqdm\nimport os\nimport cv2\n\nimport skimage.io\nimport openslide\n\ntorch.backends.cudnn.benchmark = False\n\nmodel_path_last_level=[]\nmodel_path_this_level=[]\nfor f in range(5):\n    model_path_last_level.append(\"../input/panda-sekfold/se_resnext50_32x4d_fold{}_bestOptimQWK.pth\".format(f,f))\nprint(\"Last level weight\")\nprint(model_path_last_level)\n#for f in range(5):\n#    model_path_this_level.append(\"../input/panda-highresolution-ef/efficientnet-b0_fold{}_bestOptimQWK.pth\".format(f,f))\nmodel_path_this_level.append(\"../input/panda-efb0-largebs/efficientnet-b0_fold0_bestOptimQWK.pth\")\nmodel_path_this_level.append(\"../input/panda-efb0-largebs/efficientnet-b0_fold1_bestOptimQWK.pth\")\nmodel_path_this_level.append(\"../input/panda-efb0-largebs/efficientnet-b0_fold2_bestOptimQWK.pth\")\nmodel_path_this_level.append(\"../input/panda-efb0-largebs/efficientnet-b0_fold4_bestOptimQWK.pth\")\nprint(\"This level weight\")\nprint(model_path_this_level)\n\n##for debuging\n##will run on first 100 samples\n#tiff_dir=\"../input/prostate-cancer-grade-assessment/train_images/\"\n#df=pd.read_csv(\"../input/prostate-cancer-grade-assessment/train.csv\")[:50]\n\ntiff_dir=\"../input/prostate-cancer-grade-assessment/test_images/\"\ndf=pd.read_csv(\"../input/prostate-cancer-grade-assessment/test.csv\")\n\nimport torchvision.models as models\nimport torch.utils.model_zoo as model_zoo\nimport types\nimport re\n\nfrom collections import OrderedDict\nimport math\n\nfrom torch.utils import model_zoo\nfrom torch.utils.checkpoint import checkpoint,checkpoint_sequential\nclass SEModule(nn.Module):\n\n    def __init__(self, channels, reduction):\n        super(SEModule, self).__init__()\n        self.avg_pool = nn.AdaptiveAvgPool2d(1)\n        self.fc1 = nn.Conv2d(channels, channels // reduction, kernel_size=1,\n                             padding=0)\n        self.relu = nn.ReLU(inplace=True)\n        self.fc2 = nn.Conv2d(channels // reduction, channels, kernel_size=1,\n                             padding=0)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        module_input = x\n        x = self.avg_pool(x)\n        x = self.fc1(x)\n        x = self.relu(x)\n        x = self.fc2(x)\n        x = self.sigmoid(x)\n        return module_input * x\n\n\nclass Bottleneck(nn.Module):\n    \"\"\"\n    Base class for bottlenecks that implements `forward()` method.\n    \"\"\"\n    def forward(self, x):\n        residual = x\n\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.relu(out)\n\n        out = self.conv2(out)\n        out = self.bn2(out)\n        out = self.relu(out)\n\n        out = self.conv3(out)\n        out = self.bn3(out)\n\n        if self.downsample is not None:\n            residual = self.downsample(x)\n\n        out = self.se_module(out) + residual\n        out = self.relu(out)\n\n        return out\n\n\nclass SEBottleneck(Bottleneck):\n    \"\"\"\n    Bottleneck for SENet154.\n    \"\"\"\n    expansion = 4\n\n    def __init__(self, inplanes, planes, groups, reduction, stride=1,\n                 downsample=None):\n        super(SEBottleneck, self).__init__()\n        self.conv1 = nn.Conv2d(inplanes, planes * 2, kernel_size=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(planes * 2)\n        self.conv2 = nn.Conv2d(planes * 2, planes * 4, kernel_size=3,\n                               stride=stride, padding=1, groups=groups,\n                               bias=False)\n        self.bn2 = nn.BatchNorm2d(planes * 4)\n        self.conv3 = nn.Conv2d(planes * 4, planes * 4, kernel_size=1,\n                               bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * 4)\n        self.relu = nn.ReLU(inplace=True)\n        self.se_module = SEModule(planes * 4, reduction=reduction)\n        self.downsample = downsample\n        self.stride = stride\n\n\nclass SEResNetBottleneck(Bottleneck):\n    \"\"\"\n    ResNet bottleneck with a Squeeze-and-Excitation module. It follows Caffe\n    implementation and uses `stride=stride` in `conv1` and not in `conv2`\n    (the latter is used in the torchvision implementation of ResNet).\n    \"\"\"\n    expansion = 4\n\n    def __init__(self, inplanes, planes, groups, reduction, stride=1,\n                 downsample=None):\n        super(SEResNetBottleneck, self).__init__()\n        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False,\n                               stride=stride)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, padding=1,\n                               groups=groups, bias=False)\n        self.bn2 = nn.BatchNorm2d(planes)\n        self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * 4)\n        self.relu = nn.ReLU(inplace=True)\n        self.se_module = SEModule(planes * 4, reduction=reduction)\n        self.downsample = downsample\n        self.stride = stride\n\n\nclass SEResNeXtBottleneck(Bottleneck):\n    \"\"\"\n    ResNeXt bottleneck type C with a Squeeze-and-Excitation module.\n    \"\"\"\n    expansion = 4\n\n    def __init__(self, inplanes, planes, groups, reduction, stride=1,\n                 downsample=None, base_width=4):\n        super(SEResNeXtBottleneck, self).__init__()\n        width = math.floor(planes * (base_width / 64)) * groups\n        self.conv1 = nn.Conv2d(inplanes, width, kernel_size=1, bias=False,\n                               stride=1)\n        self.bn1 = nn.BatchNorm2d(width)\n        self.conv2 = nn.Conv2d(width, width, kernel_size=3, stride=stride,\n                               padding=1, groups=groups, bias=False)\n        self.bn2 = nn.BatchNorm2d(width)\n        self.conv3 = nn.Conv2d(width, planes * 4, kernel_size=1, bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * 4)\n        self.relu = nn.ReLU(inplace=True)\n        self.se_module = SEModule(planes * 4, reduction=reduction)\n        self.downsample = downsample\n        self.stride = stride\n\n\nclass SENet(nn.Module):\n\n    def __init__(self, block, layers, groups, reduction, dropout_p=0.2,\n                 inplanes=128, input_3x3=True, downsample_kernel_size=3,\n                 downsample_padding=1, num_classes=1000):\n        \"\"\"\n        Parameters\n        ----------\n        block (nn.Module): Bottleneck class.\n            - For SENet154: SEBottleneck\n            - For SE-ResNet models: SEResNetBottleneck\n            - For SE-ResNeXt models:  SEResNeXtBottleneck\n        layers (list of ints): Number of residual blocks for 4 layers of the\n            network (layer1...layer4).\n        groups (int): Number of groups for the 3x3 convolution in each\n            bottleneck block.\n            - For SENet154: 64\n            - For SE-ResNet models: 1\n            - For SE-ResNeXt models:  32\n        reduction (int): Reduction ratio for Squeeze-and-Excitation modules.\n            - For all models: 16\n        dropout_p (float or None): Drop probability for the Dropout layer.\n            If `None` the Dropout layer is not used.\n            - For SENet154: 0.2\n            - For SE-ResNet models: None\n            - For SE-ResNeXt models: None\n        inplanes (int):  Number of input channels for layer1.\n            - For SENet154: 128\n            - For SE-ResNet models: 64\n            - For SE-ResNeXt models: 64\n        input_3x3 (bool): If `True`, use three 3x3 convolutions instead of\n            a single 7x7 convolution in layer0.\n            - For SENet154: True\n            - For SE-ResNet models: False\n            - For SE-ResNeXt models: False\n        downsample_kernel_size (int): Kernel size for downsampling convolutions\n            in layer2, layer3 and layer4.\n            - For SENet154: 3\n            - For SE-ResNet models: 1\n            - For SE-ResNeXt models: 1\n        downsample_padding (int): Padding for downsampling convolutions in\n            layer2, layer3 and layer4.\n            - For SENet154: 1\n            - For SE-ResNet models: 0\n            - For SE-ResNeXt models: 0\n        num_classes (int): Number of outputs in `last_linear` layer.\n            - For all models: 1000\n        \"\"\"\n        super(SENet, self).__init__()\n        self.inplanes = inplanes\n        if input_3x3:\n            layer0_modules = [\n                ('conv1', nn.Conv2d(3, 64, 3, stride=2, padding=1,\n                                    bias=False)),\n                ('bn1', nn.BatchNorm2d(64)),\n                ('relu1', nn.ReLU(inplace=True)),\n                ('conv2', nn.Conv2d(64, 64, 3, stride=1, padding=1,\n                                    bias=False)),\n                ('bn2', nn.BatchNorm2d(64)),\n                ('relu2', nn.ReLU(inplace=True)),\n                ('conv3', nn.Conv2d(64, inplanes, 3, stride=1, padding=1,\n                                    bias=False)),\n                ('bn3', nn.BatchNorm2d(inplanes)),\n                ('relu3', nn.ReLU(inplace=True)),\n            ]\n        else:\n            layer0_modules = [\n                ('conv1', nn.Conv2d(3, inplanes, kernel_size=7, stride=2,\n                                    padding=3, bias=False)),\n                ('bn1', nn.BatchNorm2d(inplanes)),\n                ('relu1', nn.ReLU(inplace=True)),\n            ]\n        # To preserve compatibility with Caffe weights `ceil_mode=True`\n        # is used instead of `padding=1`.\n        layer0_modules.append(('pool', nn.MaxPool2d(3, stride=2,\n                                                    ceil_mode=True)))\n        self.layer0 = nn.Sequential(OrderedDict(layer0_modules))\n        self.layer1 = self._make_layer(\n            block,\n            planes=64,\n            blocks=layers[0],\n            groups=groups,\n            reduction=reduction,\n            downsample_kernel_size=1,\n            downsample_padding=0\n        )\n        self.layer2 = self._make_layer(\n            block,\n            planes=128,\n            blocks=layers[1],\n            stride=2,\n            groups=groups,\n            reduction=reduction,\n            downsample_kernel_size=downsample_kernel_size,\n            downsample_padding=downsample_padding\n        )\n        self.layer3 = self._make_layer(\n            block,\n            planes=256,\n            blocks=layers[2],\n            stride=2,\n            groups=groups,\n            reduction=reduction,\n            downsample_kernel_size=downsample_kernel_size,\n            downsample_padding=downsample_padding\n        )\n        self.layer4 = self._make_layer(\n            block,\n            planes=512,\n            blocks=layers[3],\n            stride=2,\n            groups=groups,\n            reduction=reduction,\n            downsample_kernel_size=downsample_kernel_size,\n            downsample_padding=downsample_padding\n        )\n        self.avg_pool = nn.AvgPool2d(7, stride=1)\n        self.dropout = nn.Dropout(dropout_p) if dropout_p is not None else None\n        self.last_linear = nn.Linear(512 * block.expansion, num_classes)\n\n    def _make_layer(self, block, planes, blocks, groups, reduction, stride=1,\n                    downsample_kernel_size=1, downsample_padding=0):\n        downsample = None\n        if stride != 1 or self.inplanes != planes * block.expansion:\n            downsample = nn.Sequential(\n                nn.Conv2d(self.inplanes, planes * block.expansion,\n                          kernel_size=downsample_kernel_size, stride=stride,\n                          padding=downsample_padding, bias=False),\n                nn.BatchNorm2d(planes * block.expansion),\n            )\n\n        layers = []\n        layers.append(block(self.inplanes, planes, groups, reduction, stride,\n                            downsample))\n        self.inplanes = planes * block.expansion\n        for i in range(1, blocks):\n            layers.append(block(self.inplanes, planes, groups, reduction))\n\n        return nn.Sequential(*layers)\n\n    def features(self, x):\n        x = self.layer0(x)\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)\n        return x\n\n    def features_ckpt(self,x):\n        x.requires_grad=True\n        x = checkpoint(self.layer0,x,preserve_rng_state=False)\n        x = checkpoint_sequential(self.layer1,3,x,preserve_rng_state=False)\n        x = checkpoint_sequential(self.layer2,4,x,preserve_rng_state=False)\n        x = checkpoint_sequential(self.layer3,6,x,preserve_rng_state=False)\n        x = checkpoint_sequential(self.layer4,3,x,preserve_rng_state=False)\n        return x\n\n\n    def logits(self, x):\n        x = self.avg_pool(x)\n        if self.dropout is not None:\n            x = self.dropout(x)\n        x = x.view(x.size(0), -1)\n        x = self.last_linear(x)\n        return x\n\n    def forward(self, x):\n        x = self.features(x)\n        x = self.logits(x)\n        return x\n\ndef se_resnext50_32x4d(num_classes=1000, pretrained='imagenet'):\n    model = SENet(SEResNeXtBottleneck, [3, 4, 6, 3], groups=32, reduction=16,\n                  dropout_p=None, inplanes=64, input_3x3=False,\n                  downsample_kernel_size=1, downsample_padding=0,\n                  num_classes=num_classes)\n    if pretrained is not None:\n        settings = pretrained_settings['se_resnext50_32x4d'][pretrained]\n        initialize_pretrained_model(model, num_classes, settings)\n    return model\n\nclass ResNet(nn.Module):\n    def __init__(self, model):\n        super(ResNet, self).__init__()\n        self.conv1 = model.conv1\n        self.bn1 = model.bn1\n        self.relu = model.relu\n        self.maxpool = model.maxpool\n        self.layer1 = model.layer1\n        self.layer2 = model.layer2\n        self.layer3 = model.layer3\n        self.layer4 = model.layer4\n        self.avgpool = model.avgpool\n        self.last_linear = model.fc\n\n\n    def features(self, input):\n        x = self.conv1(input)\n        x = self.bn1(x)\n        x = self.relu(x)\n        x = self.maxpool(x)\n\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)\n        return x\n\n    def features_ckpt(self, input):\n        x = self.conv1(input)\n        x = self.bn1(x)\n        x = self.relu(x)\n        x = self.maxpool(x)\n\n        x = checkpoint_sequential(self.layer1,3,x)\n        x = checkpoint_sequential(self.layer2,4,x)\n        x = checkpoint_sequential(self.layer3,6,x)\n        x = checkpoint_sequential(self.layer4,3,x)\n        return x\n\n\n    def logits(self, features):\n        x = self.avgpool(features)\n        x = x.view(x.size(0), -1)\n        x = self.last_linear(x)\n        return x\n\n    def forward(self, input):\n        x = self.features(input)\n        x = self.logits(x)\n        return x\n\n\ndef resnet34(num_classes=1000, pretrained='imagenet'):\n    \"\"\"Constructs a ResNet-34 model.\n    \"\"\"\n    model = models.resnet34(pretrained=False, num_classes=num_classes)\n    if pretrained is not None:\n        settings = pretrained_settings['resnet34'][pretrained]\n        model = load_pretrained(model, num_classes, settings)\n    model = ResNet(model)\n    return model\n\n\"\"\"\nThis file contains helper functions for building the model and for loading model parameters.\nThese helper functions are built to mirror those in the official TensorFlow implementation.\n\"\"\"\n\nimport re\nimport math\nimport collections\nfrom functools import partial\nimport torch\nfrom torch import nn\nfrom torch.nn import functional as F\nfrom torch.utils import model_zoo\n\n########################################################################\n############### HELPERS FUNCTIONS FOR MODEL ARCHITECTURE ###############\n########################################################################\n\n\n# Parameters for the entire model (stem, all blocks, and head)\nGlobalParams = collections.namedtuple('GlobalParams', [\n    'batch_norm_momentum', 'batch_norm_epsilon', 'dropout_rate',\n    'num_classes', 'width_coefficient', 'depth_coefficient',\n    'depth_divisor', 'min_depth', 'drop_connect_rate', 'image_size'])\n\n# Parameters for an individual model block\nBlockArgs = collections.namedtuple('BlockArgs', [\n    'kernel_size', 'num_repeat', 'input_filters', 'output_filters',\n    'expand_ratio', 'id_skip', 'stride', 'se_ratio'])\n\n# Change namedtuple defaults\nGlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields)\nBlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields)\n\n\nclass SwishImplementation(torch.autograd.Function):\n    @staticmethod\n    def forward(ctx, i):\n        result = i * torch.sigmoid(i)\n        ctx.save_for_backward(i)\n        return result\n\n    @staticmethod\n    def backward(ctx, grad_output):\n        i = ctx.saved_variables[0]\n        sigmoid_i = torch.sigmoid(i)\n        return grad_output * (sigmoid_i * (1 + i * (1 - sigmoid_i)))\n\n\nclass MemoryEfficientSwish(nn.Module):\n    def forward(self, x):\n        return SwishImplementation.apply(x)\n\nclass Swish(nn.Module):\n    def forward(self, x):\n        return x * torch.sigmoid(x)\n\n\ndef round_filters(filters, global_params):\n    \"\"\" Calculate and round number of filters based on depth multiplier. \"\"\"\n    multiplier = global_params.width_coefficient\n    if not multiplier:\n        return filters\n    divisor = global_params.depth_divisor\n    min_depth = global_params.min_depth\n    filters *= multiplier\n    min_depth = min_depth or divisor\n    new_filters = max(min_depth, int(filters + divisor / 2) // divisor * divisor)\n    if new_filters < 0.9 * filters:  # prevent rounding by more than 10%\n        new_filters += divisor\n    return int(new_filters)\n\n\ndef round_repeats(repeats, global_params):\n    \"\"\" Round number of filters based on depth multiplier. \"\"\"\n    multiplier = global_params.depth_coefficient\n    if not multiplier:\n        return repeats\n    return int(math.ceil(multiplier * repeats))\n\n\ndef drop_connect(inputs, p, training):\n    \"\"\" Drop connect. \"\"\"\n    if not training: return inputs\n    batch_size = inputs.shape[0]\n    keep_prob = 1 - p\n    #random_tensor = keep_prob\n    random_tensor = torch.rand([batch_size, 1, 1, 1], dtype=inputs.dtype, device=inputs.device)+keep_prob\n    binary_tensor = torch.floor(random_tensor)\n    output = inputs / keep_prob * binary_tensor\n    return output\n\n\ndef get_same_padding_conv2d(image_size=None):\n    \"\"\" Chooses static padding if you have specified an image size, and dynamic padding otherwise.\n        Static padding is necessary for ONNX exporting of models. \"\"\"\n    if image_size is None:\n        return Conv2dDynamicSamePadding\n    else:\n        return partial(Conv2dStaticSamePadding, image_size=image_size)\n\n\nclass Conv2dDynamicSamePadding(nn.Conv2d):\n    \"\"\" 2D Convolutions like TensorFlow, for a dynamic image size \"\"\"\n\n    def __init__(self, in_channels, out_channels, kernel_size, stride=1, dilation=1, groups=1, bias=True):\n        super().__init__(in_channels, out_channels, kernel_size, stride, 0, dilation, groups, bias)\n        self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2\n\n    def forward(self, x):\n        ih, iw = x.size()[-2:]\n        kh, kw = self.weight.size()[-2:]\n        sh, sw = self.stride\n        oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)\n        pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)\n        pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)\n        if pad_h > 0 or pad_w > 0:\n            x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2])\n        return F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)\n\n\nclass Conv2dStaticSamePadding(nn.Conv2d):\n    \"\"\" 2D Convolutions like TensorFlow, for a fixed image size\"\"\"\n\n    def __init__(self, in_channels, out_channels, kernel_size, image_size=None, **kwargs):\n        super().__init__(in_channels, out_channels, kernel_size, **kwargs)\n        self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2\n\n        # Calculate padding based on image size and save it\n        assert image_size is not None\n        ih, iw = image_size if type(image_size) == list else [image_size, image_size]\n        kh, kw = self.weight.size()[-2:]\n        sh, sw = self.stride\n        oh, ow = math.ceil(ih / sh), math.ceil(iw / sw)\n        pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)\n        pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)\n        if pad_h > 0 or pad_w > 0:\n            self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2))\n        else:\n            self.static_padding = Identity()\n\n    def forward(self, x):\n        x = self.static_padding(x)\n        x = F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)\n        return x\n\n\nclass Identity(nn.Module):\n    def __init__(self, ):\n        super(Identity, self).__init__()\n\n    def forward(self, input):\n        return input\n\n\n########################################################################\n############## HELPERS FUNCTIONS FOR LOADING MODEL PARAMS ##############\n########################################################################\n\n\ndef efficientnet_params(model_name):\n    \"\"\" Map EfficientNet model name to parameter coefficients. \"\"\"\n    params_dict = {\n        # Coefficients:   width,depth,res,dropout\n        'efficientnet-b0': (1.0, 1.0, 224, 0.2),\n        'efficientnet-b1': (1.0, 1.1, 240, 0.2),\n        'efficientnet-b2': (1.1, 1.2, 260, 0.3),\n        'efficientnet-b3': (1.2, 1.4, 300, 0.3),\n        'efficientnet-b4': (1.4, 1.8, 380, 0.4),\n        'efficientnet-b5': (1.6, 2.2, 456, 0.4),\n        'efficientnet-b6': (1.8, 2.6, 528, 0.5),\n        'efficientnet-b7': (2.0, 3.1, 600, 0.5),\n        'efficientnet-b8': (2.2, 3.6, 672, 0.5),\n        'efficientnet-l2': (4.3, 5.3, 800, 0.5),\n    }\n    return params_dict[model_name]\n\n\nclass BlockDecoder(object):\n    \"\"\" Block Decoder for readability, straight from the official TensorFlow repository \"\"\"\n\n    @staticmethod\n    def _decode_block_string(block_string):\n        \"\"\" Gets a block through a string notation of arguments. \"\"\"\n        assert isinstance(block_string, str)\n\n        ops = block_string.split('_')\n        options = {}\n        for op in ops:\n            splits = re.split(r'(\\d.*)', op)\n            if len(splits) >= 2:\n                key, value = splits[:2]\n                options[key] = value\n\n        # Check stride\n        assert (('s' in options and len(options['s']) == 1) or\n                (len(options['s']) == 2 and options['s'][0] == options['s'][1]))\n\n        return BlockArgs(\n            kernel_size=int(options['k']),\n            num_repeat=int(options['r']),\n            input_filters=int(options['i']),\n            output_filters=int(options['o']),\n            expand_ratio=int(options['e']),\n            id_skip=('noskip' not in block_string),\n            se_ratio=float(options['se']) if 'se' in options else None,\n            stride=[int(options['s'][0])])\n\n    @staticmethod\n    def _encode_block_string(block):\n        \"\"\"Encodes a block to a string.\"\"\"\n        args = [\n            'r%d' % block.num_repeat,\n            'k%d' % block.kernel_size,\n            's%d%d' % (block.strides[0], block.strides[1]),\n            'e%s' % block.expand_ratio,\n            'i%d' % block.input_filters,\n            'o%d' % block.output_filters\n        ]\n        if 0 < block.se_ratio <= 1:\n            args.append('se%s' % block.se_ratio)\n        if block.id_skip is False:\n            args.append('noskip')\n        return '_'.join(args)\n\n    @staticmethod\n    def decode(string_list):\n        \"\"\"\n        Decodes a list of string notations to specify blocks inside the network.\n\n        :param string_list: a list of strings, each string is a notation of block\n        :return: a list of BlockArgs namedtuples of block args\n        \"\"\"\n        assert isinstance(string_list, list)\n        blocks_args = []\n        for block_string in string_list:\n            blocks_args.append(BlockDecoder._decode_block_string(block_string))\n        return blocks_args\n\n    @staticmethod\n    def encode(blocks_args):\n        \"\"\"\n        Encodes a list of BlockArgs to a list of strings.\n\n        :param blocks_args: a list of BlockArgs namedtuples of block args\n        :return: a list of strings, each string is a notation of block\n        \"\"\"\n        block_strings = []\n        for block in blocks_args:\n            block_strings.append(BlockDecoder._encode_block_string(block))\n        return block_strings\n\n\ndef efficientnet(width_coefficient=None, depth_coefficient=None, dropout_rate=0.2,\n                 drop_connect_rate=0.2, image_size=None, num_classes=1000):\n    \"\"\" Creates a efficientnet model. \"\"\"\n\n    blocks_args = [\n        'r1_k3_s11_e1_i32_o16_se0.25', 'r2_k3_s22_e6_i16_o24_se0.25',\n        'r2_k5_s22_e6_i24_o40_se0.25', 'r3_k3_s22_e6_i40_o80_se0.25',\n        'r3_k5_s11_e6_i80_o112_se0.25', 'r4_k5_s22_e6_i112_o192_se0.25',\n        'r1_k3_s11_e6_i192_o320_se0.25',\n    ]\n    blocks_args = BlockDecoder.decode(blocks_args)\n\n    global_params = GlobalParams(\n        batch_norm_momentum=0.99,\n        batch_norm_epsilon=1e-3,\n        dropout_rate=dropout_rate,\n        drop_connect_rate=drop_connect_rate,\n        # data_format='channels_last',  # removed, this is always true in PyTorch\n        num_classes=num_classes,\n        width_coefficient=width_coefficient,\n        depth_coefficient=depth_coefficient,\n        depth_divisor=8,\n        min_depth=None,\n        image_size=image_size,\n    )\n\n    return blocks_args, global_params\n\n\ndef get_model_params(model_name, override_params):\n    \"\"\" Get the block args and global params for a given model \"\"\"\n    if model_name.startswith('efficientnet'):\n        w, d, s, p = efficientnet_params(model_name)\n        # note: all models have drop connect rate = 0.2\n        blocks_args, global_params = efficientnet(\n            width_coefficient=w, depth_coefficient=d, dropout_rate=p, image_size=s)\n    else:\n        raise NotImplementedError('model name is not pre-defined: %s' % model_name)\n    if override_params:\n        # ValueError will be raised here if override_params has fields not included in global_params.\n        global_params = global_params._replace(**override_params)\n    return blocks_args, global_params\n\n\nurl_map = {\n    'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b0-355c32eb.pth',\n    'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b1-f1951068.pth',\n    'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b2-8bb594d6.pth',\n    'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b3-5fb5a3c3.pth',\n    'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b4-6ed6700e.pth',\n    'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b5-b6417697.pth',\n    'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b6-c76e70fd.pth',\n    'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b7-dcc49843.pth',\n}\n\n\nurl_map_advprop = {\n    'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b0-b64d5a18.pth',\n    'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b1-0f3ce85a.pth',\n    'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b2-6e9d97e5.pth',\n    'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b3-cdd7c0f4.pth',\n    'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b4-44fb3a87.pth',\n    'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b5-86493f6b.pth',\n    'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b6-ac80338e.pth',\n    'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b7-4652b6dd.pth',\n    'efficientnet-b8': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b8-22a8fe65.pth',\n}\n\n\ndef load_pretrained_weights(model, model_name, load_fc=True, advprop=False):\n    \"\"\" Loads pretrained weights, and downloads if loading for the first time. \"\"\"\n    # AutoAugment or Advprop (different preprocessing)\n    url_map_ = url_map_advprop if advprop else url_map\n    state_dict = model_zoo.load_url(url_map_[model_name])\n    if load_fc:\n        model.load_state_dict(state_dict)\n    else:\n        state_dict.pop('_fc.weight')\n        state_dict.pop('_fc.bias')\n        res = model.load_state_dict(state_dict, strict=False)\n        assert set(res.missing_keys) == set(['_fc.weight', '_fc.bias']), 'issue loading pretrained weights'\n    print('Loaded pretrained weights for {}'.format(model_name))\n    \n    \n\nclass AttentionPool(nn.Module):\n    def __init__(self,in_ch,hidden=512,dropout=True):\n        super().__init__()\n        self.in_ch=in_ch\n\n        module=[nn.Linear(in_ch,hidden,bias=True),\n                nn.Tanh()\n                ]\n        if dropout:\n            module.append(nn.Dropout(0.25))\n        module.append(nn.Linear(hidden,1,bias=True))\n        self.attention=nn.Sequential(*module)\n\n    def forward(self,x):\n        num_patch=x.size(1)\n        x=x.view(-1,x.size(2))\n        A=self.attention(x)\n        A=A.view(-1,num_patch,1)\n        wt=F.softmax(A,dim=1)\n        return (x.view(-1,num_patch,self.in_ch)*wt).sum(dim=1),A\n    \nclass AdaptiveConcatPool2d_Attention(nn.Module):\n    def __init__(self, in_ch,hidden=512,dropout=True):\n        super().__init__()\n        sz = (1,1)\n        self.ap = AttentionPool(in_ch,hidden=hidden,dropout=dropout)\n        self.mp = nn.AdaptiveMaxPool2d(sz)\n        self.in_ch=in_ch\n    def forward(self, x):\n        ap,A=self.ap(x)#[batch,num_patch,C]\n        mp=torch.max(x,dim=1)[0]\n        return torch.cat([ap, mp], dim=1),A\n    \n    \n    \n    \n    \nclass PANDA_Model_Attention_Concat_MultiTask_Headv2(nn.Module):\n    def __init__(self,arch='se_resnext50_32x4d',dropout=0.25,num_classes=6,checkpoint=False,scale_op=True):\n        super().__init__()\n        self.scale_op=scale_op\n        if \"se\" in arch:\n            self.base_model=se_resnext50_32x4d(pretrained=None)\n            back_feature=self.base_model.last_linear.in_features\n        elif \"efficientnet\" in arch:\n            self.base_model = EfficientNet.from_pretrained(arch, num_classes=num_classes)\n            back_feature = self.base_model._fc.in_features\n        else:\n            self.base_model= resnet34(pretrained=None)\n            back_feature=self.base_model.last_linear.in_features\n        self.checkpoint=checkpoint\n        self.avg_pool=nn.AdaptiveAvgPool2d(1)\n\n\n        self.attention=AdaptiveConcatPool2d_Attention(in_ch=back_feature,hidden=512,dropout=dropout>0)\n\n        self.label_head=nn.Sequential(\n            nn.Dropout(p=dropout),\n            nn.Linear(back_feature,1,bias=True)\n        )\n\n        self.reg_head = nn.Sequential(\n            nn.Dropout(p=dropout),\n            nn.Linear(2*back_feature,1,bias=True),\n        )\n        self.cls_head = nn.Sequential(\n            nn.Dropout(p=dropout),\n            nn.Linear(2*back_feature,num_classes,bias=True),\n        )\n\n\n    def forward(self,x):\n        # x [bs,n,3,h,w]\n        B,N,C,H,W=x.shape\n        x=x.view(-1,C,H,W)\n        if self.checkpoint:\n            x=self.base_model.features_ckpt(x)\n        else:\n            x=self.base_model.features(x)\n        x=self.avg_pool(x).view(x.size(0),-1)\n\n        patch_pred=self.label_head(x)\n        x=x.view(B,N,-1)\n        x,A=self.attention(x)\n\n        reg_pred=self.reg_head(x).view(-1)\n        if self.scale_op:\n            reg_pred=7.*torch.sigmoid(reg_pred)-1.\n        cls_pred=self.cls_head(x)\n        return reg_pred,cls_pred,patch_pred,A\n\n    \ndef crop_white(image, value=255):\n    assert image.shape[2] == 3\n    assert image.dtype == np.uint8\n    ys, = (image.min((1, 2)) < value).nonzero()\n    xs, = (image.min(0).min(1) < value).nonzero()\n    if len(xs) == 0 or len(ys) == 0:\n        return image,np.array([0,0], dtype=np.int)\n    return image[ys.min():ys.max() + 1, xs.min():xs.max() + 1],np.array([ys.min(), xs.min()], dtype=np.int)\n\ndef crop_patches(img,bg_threshold, sz=192):\n    W=img.shape[1]\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    sat = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)[:, :, 1]\n    background_ratio = (sat < 20).astype(np.float32).reshape(img.shape[0], -1).sum(1) / (sz * sz)\n\n    fg_idx = np.where(background_ratio < bg_threshold)[0]\n\n    img = img[fg_idx]\n\n    coord = np.stack([fg_idx // (W // sz), fg_idx % (W // sz)], axis=1)*sz\n    return img.reshape(-1, sz, sz, 3), coord, background_ratio[fg_idx]\n\ndef crop_upper_level(img_id, coords, sz, scale=0.5):\n    image = openslide.OpenSlide(os.path.join(tiff_dir,\"{}.tiff\".format(img_id)))\n    patches = []\n    for coord in coords:\n        x = coord[1] * 4\n        y = coord[0] * 4  # coordinate in upper level\n        x = max(0,x)\n        y = max(0,y)\n        region_sz = int(sz * 4)  # new size\n        patch = image.read_region((x, y), 0, (region_sz, region_sz))\n        patch = np.asarray(patch.convert(\"RGB\"))\n        if scale != 1:\n            patch = cv2.resize(patch, dsize=(int(scale * patch.shape[1]), int(scale * patch.shape[0])))\n        patches.append(patch)\n    return patches\n\ndef get_next_level_patches(img_id,attention,coords,sz=192,scale=0.5,max_patch=64):\n    idx=np.argsort(attention)[::-1]\n    N=min(max_patch,len(idx))\n    idx=idx[:N]\n    coords=coords[idx]\n    next_level_patches=crop_upper_level(img_id,coords,sz,scale)\n    return next_level_patches,attention[idx],idx\n\ndef prepare_next_level_input(next_level_patches,patch_num=32,crop_func=None,\n                             mean=(0.485, 0.456, 0.406),\n                             std=(0.229, 0.224, 0.225),):\n    next_level_patches=np.stack(next_level_patches,axis=0)\n\n    patches=[]\n    for patch in next_level_patches:\n        _, encoded_img = cv2.imencode(\".jpg\", patch, (int(cv2.IMWRITE_JPEG_QUALITY), 95))\n        patch = cv2.imdecode(encoded_img, cv2.IMREAD_UNCHANGED)\n        patches.append(patch)\n\n    if crop_func is not None:\n        patches=[crop_func(image=x)['image'] for x in patches]\n    patches=np.stack(patches,axis=0)\n    if len(patches)<patch_num:\n        patches=np.pad(patches,[[0,patch_num-len(patches)],[0,0],[0,0],[0,0]],constant_values=255)\n\n    patches = 1.0 - patches.astype(np.float32) / 255\n    patches = (patches - mean) /std\n    return torch.tensor(patches,dtype=torch.float32,device='cuda').permute(0,3,1,2).unsqueeze(0)\n\nclass MBConvBlock(nn.Module):\n    \"\"\"\n    Mobile Inverted Residual Bottleneck Block\n\n    Args:\n        block_args (namedtuple): BlockArgs, see above\n        global_params (namedtuple): GlobalParam, see above\n\n    Attributes:\n        has_se (bool): Whether the block contains a Squeeze and Excitation layer.\n    \"\"\"\n\n    def __init__(self, block_args, global_params):\n        super().__init__()\n        self._block_args = block_args\n        self._bn_mom = 1 - global_params.batch_norm_momentum\n        self._bn_eps = global_params.batch_norm_epsilon\n        self.has_se = (self._block_args.se_ratio is not None) and (0 < self._block_args.se_ratio <= 1)\n        self.id_skip = block_args.id_skip  # skip connection and drop connect\n\n        # Get static or dynamic convolution depending on image size\n        Conv2d = get_same_padding_conv2d(image_size=global_params.image_size)\n\n        # Expansion phase\n        inp = self._block_args.input_filters  # number of input channels\n        oup = self._block_args.input_filters * self._block_args.expand_ratio  # number of output channels\n        if self._block_args.expand_ratio != 1:\n            self._expand_conv = Conv2d(in_channels=inp, out_channels=oup, kernel_size=1, bias=False)\n            self._bn0 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps)\n\n        # Depthwise convolution phase\n        k = self._block_args.kernel_size\n        s = self._block_args.stride\n        self._depthwise_conv = Conv2d(\n            in_channels=oup, out_channels=oup, groups=oup,  # groups makes it depthwise\n            kernel_size=k, stride=s, bias=False)\n        self._bn1 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps)\n\n        # Squeeze and Excitation layer, if desired\n        if self.has_se:\n            num_squeezed_channels = max(1, int(self._block_args.input_filters * self._block_args.se_ratio))\n            self._se_reduce = Conv2d(in_channels=oup, out_channels=num_squeezed_channels, kernel_size=1)\n            self._se_expand = Conv2d(in_channels=num_squeezed_channels, out_channels=oup, kernel_size=1)\n\n        # Output phase\n        final_oup = self._block_args.output_filters\n        self._project_conv = Conv2d(in_channels=oup, out_channels=final_oup, kernel_size=1, bias=False)\n        self._bn2 = nn.BatchNorm2d(num_features=final_oup, momentum=self._bn_mom, eps=self._bn_eps)\n        self._swish = MemoryEfficientSwish()\n\n    def forward(self, inputs, drop_connect_rate=None):\n        \"\"\"\n        :param inputs: input tensor\n        :param drop_connect_rate: drop connect rate (float, between 0 and 1)\n        :return: output of block\n        \"\"\"\n\n        # Expansion and Depthwise Convolution\n        x = inputs\n        if self._block_args.expand_ratio != 1:\n            x = self._swish(self._bn0(self._expand_conv(inputs)))\n        x = self._swish(self._bn1(self._depthwise_conv(x)))\n\n        # Squeeze and Excitation\n        if self.has_se:\n            x_squeezed = F.adaptive_avg_pool2d(x, 1)\n            x_squeezed = self._se_expand(self._swish(self._se_reduce(x_squeezed)))\n            x = torch.sigmoid(x_squeezed) * x\n\n        x = self._bn2(self._project_conv(x))\n\n        # Skip connection and drop connect\n        input_filters, output_filters = self._block_args.input_filters, self._block_args.output_filters\n        if self.id_skip and self._block_args.stride == 1 and input_filters == output_filters:\n            if drop_connect_rate:\n                x = drop_connect(x, p=drop_connect_rate, training=self.training)\n            x = x + inputs  # skip connection\n        return x\n\n    def set_swish(self, memory_efficient=True):\n        \"\"\"Sets swish function as memory efficient (for training) or standard (for export)\"\"\"\n        self._swish = MemoryEfficientSwish() if memory_efficient else Swish()\n\n\nclass EfficientNet(nn.Module):\n    \"\"\"\n    An EfficientNet model. Most easily loaded with the .from_name or .from_pretrained methods\n\n    Args:\n        blocks_args (list): A list of BlockArgs to construct blocks\n        global_params (namedtuple): A set of GlobalParams shared between blocks\n\n    Example:\n        model = EfficientNet.from_pretrained('efficientnet-b0')\n\n    \"\"\"\n\n    def __init__(self, blocks_args=None, global_params=None):\n        super().__init__()\n        assert isinstance(blocks_args, list), 'blocks_args should be a list'\n        assert len(blocks_args) > 0, 'block args must be greater than 0'\n        self._global_params = global_params\n        self._blocks_args = blocks_args\n\n        # Get static or dynamic convolution depending on image size\n        Conv2d = get_same_padding_conv2d(image_size=global_params.image_size)\n\n        # Batch norm parameters\n        bn_mom = 1 - self._global_params.batch_norm_momentum\n        bn_eps = self._global_params.batch_norm_epsilon\n\n        # Stem\n        in_channels = 3  # rgb\n        out_channels = round_filters(32, self._global_params)  # number of output channels\n        self._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False)\n        self._bn0 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps)\n\n        # Build blocks\n        self._blocks = nn.ModuleList([])\n        for block_args in self._blocks_args:\n\n            # Update block input and output filters based on depth multiplier.\n            block_args = block_args._replace(\n                input_filters=round_filters(block_args.input_filters, self._global_params),\n                output_filters=round_filters(block_args.output_filters, self._global_params),\n                num_repeat=round_repeats(block_args.num_repeat, self._global_params)\n            )\n\n            # The first block needs to take care of stride and filter size increase.\n            self._blocks.append(MBConvBlock(block_args, self._global_params))\n            if block_args.num_repeat > 1:\n                block_args = block_args._replace(input_filters=block_args.output_filters, stride=1)\n            for _ in range(block_args.num_repeat - 1):\n                self._blocks.append(MBConvBlock(block_args, self._global_params))\n\n        # Head\n        in_channels = block_args.output_filters  # output of final block\n        out_channels = round_filters(1280, self._global_params)\n        self._conv_head = Conv2d(in_channels, out_channels, kernel_size=1, bias=False)\n        self._bn1 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps)\n\n        # Final linear layer\n        self._avg_pooling = nn.AdaptiveAvgPool2d(1)\n        self._dropout = nn.Dropout(self._global_params.dropout_rate)\n        self._fc = nn.Linear(out_channels, self._global_params.num_classes)\n        self._swish = MemoryEfficientSwish()\n\n    def set_swish(self, memory_efficient=True):\n        \"\"\"Sets swish function as memory efficient (for training) or standard (for export)\"\"\"\n        self._swish = MemoryEfficientSwish() if memory_efficient else Swish()\n        for block in self._blocks:\n            block.set_swish(memory_efficient)\n\n\n    def features(self, inputs):\n        \"\"\" Returns output of the final convolution layer \"\"\"\n\n        # Stem\n        x = self._swish(self._bn0(self._conv_stem(inputs)))\n\n        # Blocks\n        for idx, block in enumerate(self._blocks):\n            drop_connect_rate = self._global_params.drop_connect_rate\n            if drop_connect_rate:\n                drop_connect_rate *= float(idx) / len(self._blocks)\n            x = block(x, drop_connect_rate=drop_connect_rate)\n        # Head\n        x = self._swish(self._bn1(self._conv_head(x)))\n\n        return x\n\n    def features_ckpt(self, inputs):\n        \"\"\" Returns output of the final convolution layer \"\"\"\n\n        # Stem\n        x = self._swish(self._bn0(self._conv_stem(inputs)))\n\n        # Blocks\n        for idx, block in enumerate(self._blocks):\n            drop_connect_rate = self._global_params.drop_connect_rate\n            if drop_connect_rate:\n                drop_connect_rate *= float(idx) / len(self._blocks)\n            x=checkpoint(block,x,torch.tensor(drop_connect_rate).cuda(),preserve_rng_state=True)\n        # Head\n        x = self._swish(self._bn1(self._conv_head(x)))\n\n        return x\n\n    def forward(self, inputs):\n        \"\"\" Calls extract_features to extract features, applies final linear layer, and returns logits. \"\"\"\n        bs = inputs.size(0)\n        # Convolution layers\n        x = self.features(inputs)\n\n        # Pooling and final linear layer\n        x = self._avg_pooling(x)\n        x = x.view(bs, -1)\n        x = self._dropout(x)\n        x = self._fc(x)\n        return x\n\n    @classmethod\n    def from_name(cls, model_name, override_params=None):\n        cls._check_model_name_is_valid(model_name)\n        blocks_args, global_params = get_model_params(model_name, override_params)\n        return cls(blocks_args, global_params)\n\n    @classmethod\n    def from_pretrained(cls, model_name, advprop=False, num_classes=1000, in_channels=3):\n        model = cls.from_name(model_name, override_params={'num_classes': num_classes})\n        #load_pretrained_weights(model, model_name, load_fc=(num_classes == 1000), advprop=advprop)\n        if in_channels != 3:\n            Conv2d = get_same_padding_conv2d(image_size = model._global_params.image_size)\n            out_channels = round_filters(32, model._global_params)\n            model._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False)\n        return model\n    \n    @classmethod\n    def get_image_size(cls, model_name):\n        cls._check_model_name_is_valid(model_name)\n        _, _, res, _ = efficientnet_params(model_name)\n        return res\n\n    @classmethod\n    def _check_model_name_is_valid(cls, model_name):\n        \"\"\" Validates model name. \"\"\" \n        valid_models = ['efficientnet-b'+str(i) for i in range(9)]\n        if model_name not in valid_models:\n            raise ValueError('model_name should be one of: ' + ', '.join(valid_models))\n            \n            \nclass PANDAPatchExtraction_Test(object):\n    def __init__(self,\n                 df,\n                 tiff_dir,\n\n                 # Patch parameter\n                 patch_size=192,\n                 bg_threshold=0.8,\n                 trail_offset=[0,1/2],\n\n                 # Augmentation & Normalization\n                 mean=(0.485, 0.456, 0.406),\n                 std=(0.229, 0.224, 0.225),\n\n                 ):\n        self.image_ids = df['image_id'].tolist()\n\n        self.tiff_dir = tiff_dir\n        self.patch_size = patch_size\n        self.bg_threshold = bg_threshold\n        self.trail_offset=trail_offset\n\n        self.mean = np.array(mean, dtype=np.float32)\n        self.std = np.array(std, dtype=np.float)\n\n    def __getitem__(self, idx):\n        img_id = self.image_ids[idx]\n        image = skimage.io.MultiImage(os.path.join(self.tiff_dir, \"{}.tiff\".format(img_id)))[1]\n\n\n        image,offset = crop_white(image)\n        _, encoded_img = cv2.imencode(\".jpg\", image, (int(cv2.IMWRITE_JPEG_QUALITY), 100))\n        image = cv2.imdecode(encoded_img, cv2.IMREAD_UNCHANGED)\n\n        shape = image.shape\n\n        pad0 = (self.patch_size - shape[0] % self.patch_size) % self.patch_size\n        pad1 = (self.patch_size - shape[1] % self.patch_size) % self.patch_size\n\n        pad_up = pad0 // 2\n        pad_left = pad1 // 2\n\n        best_mean_bg_ratio=1000\n        best_patch=None\n        best_coord=None\n        best_pad_offset=None\n\n        for trail_offset in self.trail_offset:\n            trail_pad_up = pad_up + int(self.patch_size * trail_offset)\n            trail_pad_left = pad_left + int(self.patch_size * trail_offset)\n            image_tmp = np.pad(image, [[trail_pad_up, pad0+self.patch_size - trail_pad_up], [trail_pad_left, pad1+self.patch_size - trail_pad_left], [0, 0]], constant_values=255)\n\n            patches, coords,bg_ratio = crop_patches(image_tmp,self.bg_threshold, sz=self.patch_size)\n            if np.mean(bg_ratio)<best_mean_bg_ratio:\n                best_mean_bg_ratio=np.mean(bg_ratio)\n                best_patch=patches\n                best_coord=coords\n                best_pad_offset=(trail_pad_up,trail_pad_left)\n\n        #print(\"best\",best_mean_bg_ratio)\n        offset[0] -= best_pad_offset[0]\n        offset[1] -= best_pad_offset[1]\n\n        if len(best_patch)==0:\n            best_patch=255*np.ones((1,self.patch_size,self.patch_size,3))\n            best_coord=np.zeros((1,2))\n        \n        best_coord = best_coord + offset.reshape(1, 2)\n\n        best_patch = 1.0 - best_patch.astype(np.float32) / 255\n        best_patch = (best_patch - self.mean) / self.std\n        return torch.tensor(best_patch, dtype=torch.float32).permute(0, 3, 1, 2), best_coord, img_id\n\n    def __len__(self):\n        return len(self.image_ids)\n    \ndef safe_run(model,images,max_bs=128):\n    num_patch=images.shape[1]\n    split_dim=[max_bs]*(num_patch//max_bs)\n    if num_patch%max_bs>0:\n        split_dim+=[num_patch%max_bs]\n    attention=[]\n    for split_img in torch.split(images,split_dim,dim=1):\n        with torch.no_grad():\n            split_img=split_img.cuda()\n            output,_,_,A=model(split_img)\n            attention.append(A.cpu())\n    return torch.cat(attention,dim=1)\n\n\n\nmodel_last_level=[]\nmodel_this_level=[]\nfor p in model_path_last_level:\n    print(\"Loading last level\",p)\n    model=PANDA_Model_Attention_Concat_MultiTask_Headv2(arch='se_resnext50_32x4d',\n                                           dropout=0.25,\n                                           num_classes=6,\n                                           scale_op=False,\n                                           )\n    model.cuda()\n    ckpt=torch.load(p)\n    model.load_state_dict(ckpt['state_dict'])\n    model.eval()\n    model_last_level.append(model)\n\n\nfor p in model_path_this_level:\n    print(\"Loading this level\",p)\n    model=PANDA_Model_Attention_Concat_MultiTask_Headv2(arch='efficientnet-b0',\n                                           dropout=0.4,\n                                           num_classes=6,\n                                           scale_op=True,\n                                           )\n    model.cuda()\n    ckpt=torch.load(p)\n    model.load_state_dict(ckpt['state_dict'])\n    model.eval()\n    model_this_level.append(model)\nprint(len(model_last_level),\"Median resolution models\")\nprint(len(model_this_level),\"High resolution models\")\n\ndataset=PANDAPatchExtraction_Test(df,\n                                tiff_dir,\n                                patch_size=192,\n                                bg_threshold=0.95,\n                                trail_offset=[0,1/2],\n                                )\ndataloader=DataLoader(dataset,batch_size=1,shuffle=False,num_workers=2)\n\n\ncoef=[0.5,1.5,2.5,3.5,4.5]\ndef predict(X, coef):\n    return pd.cut(X, [-np.inf] + list(np.sort(coef)) + [np.inf], labels=[0, 1, 2, 3,4,5]) \n\n\nif os.path.exists(tiff_dir):\n    prediction=[]\n    name=[]\n    for images,coords,img_ids in tqdm(dataloader):\n        with torch.no_grad():\n            #run median level to collect image\n            A=[]\n            for model in model_last_level:\n                att=safe_run(model,images).view(-1).numpy()\n                A.append(att)\n            A=np.stack(A,axis=0).mean(axis=0)\n            \n            coords=coords.numpy().reshape(-1,2)\n\n            next_level_patches,attention,idx=get_next_level_patches(img_ids[0],A,coords,sz=192,scale=0.5,max_patch=36)\n\n            #run again level1 get prediction\n            #idx=np.sort(idx)\n            #this_level_input=images[:,idx].cuda()\n            #reg_output_last, cls_output_last, patch_label_last,A_last = model_this_level(next_level_patches)\n            \n            #collect next level and run\n            next_level_patches=prepare_next_level_input(next_level_patches,patch_num=36,crop_func=None)\n            \n            reg_pred = 0.\n            cls_pred = 0.\n            next_level_patches = torch.cat(\n                    [next_level_patches,next_level_patches.flip((3,4))],dim=0)\n            for model in model_this_level:\n                reg_output, cls_output, patch_pred, A = model(next_level_patches)\n                cls_output = cls_output.view(-1, 6).mean(dim=0)\n                reg_output = reg_output.view(-1).mean(dim=0)\n                reg_pred += reg_output.cpu().numpy()\n                cls_pred += cls_output.cpu().numpy()\n            reg_pred /= len(model_this_level)\n            cls_pred /= len(model_this_level)\n            prediction.append(reg_pred)\n            #prediction.append(reg_output.detach().cpu().numpy()+reg_output_last.detach().cpu().numpy())\n            name.extend(img_ids)\n\n    prediction=np.array(prediction).reshape(-1)\n    #prediction=predict(prediction,coef)\n    res_ruef=pd.DataFrame({\n        'image_id':name,\n        'isup_grade':prediction\n    })\n    print(res_ruef.head())\n    \n\nelse:\n    df=pd.read_csv(\"../input/prostate-cancer-grade-assessment/sample_submission.csv\")\n    df.to_csv(\"./submission.csv\",index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del dataloader\ndel dataset\ndel model_last_level\ndel model_this_level\ntorch.cuda.empty_cache()\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Xie","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport gc\nimport cv2\nimport PIL\nimport time\nimport math\nimport warnings\nimport skimage.io\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nimport albumentations as albu\nfrom tensorflow.keras.utils import get_custom_objects\nfrom tensorflow.keras.preprocessing.image import load_img\n\n\n\nprint('Tensorflow version : {}'.format(tf.__version__))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def predict(X, coef=[0.5,1.5,2.5,3.5,4.5]):\n    return pd.cut(X, [-np.inf] + list(np.sort(coef)) + [np.inf], labels=[0, 1, 2, 3,4,5]) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_xie29_raw_prediction(debug=False):\n    \n    class FixedDropout(tf.keras.layers.Dropout):\n        def _get_noise_shape(self, inputs):\n            if self.noise_shape is None:\n                return self.noise_shape\n\n            symbolic_shape = tf.keras.backend.shape(inputs)\n            noise_shape = [symbolic_shape[axis] if shape is None else shape\n                           for axis, shape in enumerate(self.noise_shape)]\n            return tuple(noise_shape)\n\n    class Generalized_mean_pooling2D(tf.keras.layers.Layer):\n        def __init__(self, p=3, epsilon=1e-6, name='', trainable=True, **kwargs):\n            super(Generalized_mean_pooling2D, self).__init__()\n            self.init_p = p\n            self.epsilon = epsilon\n\n        def build(self, input_shape):\n            if isinstance(input_shape, list) or len(input_shape) != 4:\n                raise ValueError('`GeM` pooling layer only allow 1 input with 4 dimensions(b, h, w, c)')\n            self.build_shape = input_shape\n            self.p = self.add_weight(\n                      name='p',\n                      shape=[1,],\n                      initializer=tf.keras.initializers.Constant(value=self.init_p),\n                      regularizer=None,\n                      trainable=True,\n                      dtype=tf.float32\n                      )\n            self.built=True\n\n        def call(self, inputs):\n            input_shape = inputs.get_shape()\n            if isinstance(inputs, list) or len(input_shape) != 4:\n                raise ValueError('`GeM` pooling layer only allow 1 input with 4 dimensions(b, h, w, c)')\n            return (tf.reduce_mean(tf.abs(inputs**self.p), axis=[1,2], keepdims=False) + self.epsilon)**(1.0/self.p)\n\n        def get_config(self):\n\n            config = super().get_config().copy()\n            config.update({\n                'p': self.init_p,\n                'epsilon': self.epsilon\n            })\n            return config\n    \n    class TestGenerator(tf.keras.utils.Sequence):    \n    \n        def __init__(self,\n                     image_shape,\n                     batch_size,\n                     load_dir,\n                     test_df\n                     ):\n\n            self.image_shape = image_shape\n            self.batch_size = batch_size\n            self.test_df = test_df\n            self.image_ids = test_df['image_id'].values\n            self.load_dir = load_dir\n            self.indices = range(test_df.shape[0])\n\n        def __len__(self):\n            return self.test_df.shape[0] // self.batch_size\n\n        def __getitem__(self, index):\n            batch_indices = self.indices[self.batch_size * index : self.batch_size * (index+1)]\n            image_ids = self.image_ids[batch_indices]\n            batch_images = [self.__getimages__(image_id) for image_id in image_ids]\n            return np.stack(batch_images)\n\n        def glue_tiles(self, images, y_tiles_num=3, x_tiles_num=4, sz=128):\n            glued_image = np.zeros((sz*y_tiles_num, sz*x_tiles_num, 3), np.uint8)\n            for i, image in enumerate(images):\n                y_start = int(i / x_tiles_num) * sz\n                y_end = y_start + sz\n                x_start = int(i % x_tiles_num) * sz\n                x_end = x_start + sz\n\n                glued_image[y_start:y_end, x_start:x_end, :] = image\n            return glued_image\n\n\n        def get_foreground(self, image):\n            grayscale = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)\n            _, thresh = cv2.threshold(grayscale, 200, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)\n            if np.sum(thresh) == 0:\n                return image\n            bbox = cv2.boundingRect(thresh)\n            x, y, w, h = bbox\n            foreground = image[y:y+h, x:x+w]\n            return foreground\n\n        def __getimages__(self, img_id):\n            read_in_path = os.path.join(self.load_dir, img_id + '.tiff')\n            img = skimage.io.MultiImage(read_in_path)[1]\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]],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            slim_images = []\n            for i in img:\n                i = self.get_foreground(i)\n                slim_images.append(cv2.resize(i, (resize_sz, resize_sz), cv2.INTER_AREA))\n            del img\n            glued_image = self.glue_tiles(slim_images, y_tiles_num, x_tiles_num, resize_sz)\n            '''\n            tfimage = tf.cast(tf.convert_to_tensor(glued_image), tf.uint8)\n            tfimage = tf.image.encode_jpeg(tfimage, optimize_size=True, chroma_downsampling=False)\n\n            glued_image = tf.image.decode_jpeg(tfimage, channels=3)\n            glued_image = tf.cast(glued_image, tf.float32) / 255.0\n            glued_image = glued_image.numpy()\n            '''\n            return glued_image/255.0\n    \n    def prediction_decode(y_preds):\n    \n        for i, pred in enumerate(y_preds):\n            if pred < 0.5:\n                y_preds[i] = 0\n            elif pred >= 0.5 and pred < 1.5:\n                y_preds[i] = 1\n            elif pred >= 1.5 and pred < 2.5:\n                y_preds[i] = 2\n            elif pred >= 2.5 and pred < 3.5:\n                y_preds[i] = 3\n            elif pred >= 3.5 and pred < 4.5:\n                y_preds[i] = 4\n            else:\n                y_preds[i] = 5\n\n        return y_preds.astype(np.int32)\n\n    @tf.function\n    def inference_step(images):\n        preds = model(images, training=False)\n        return preds\n    \n    \n    def inference(model, test_generator):\n    \n        prediction = []\n\n        for step in range(test_generator.__len__()):\n            print('=', end='', flush=True)\n            images = test_generator.__getitem__(step)\n            preds = model(images, training=False)\n            preds = preds[0].numpy()\n            for y_pred in preds:\n                prediction.append(y_pred)\n        print('')\n        return np.array(prediction, dtype=np.float32)\n    \n    \n    \n    get_custom_objects().update({'swish': tf.keras.layers.Activation(tf.nn.swish)})\n    get_custom_objects().update({'FixedDropout':FixedDropout})\n    get_custom_objects().update({'Generalized_mean_pooling2D':Generalized_mean_pooling2D})\n    \n    MAIN_DIR = '../input/prostate-cancer-grade-assessment'\n    sample_csv = pd.read_csv(os.path.join(MAIN_DIR, 'sample_submission.csv'))\n    \n    main_folder = 'test'\n    \n    if debug:\n        sample_csv = pd.read_csv(os.path.join(MAIN_DIR, 'train.csv'))[:100]\n        main_folder = 'train'\n\n    \n    #Hyper parameters\n    ########################################\n    x_tiles_num = 12\n    y_tiles_num = 12\n    sz = 128\n    resize_sz = 128\n    IMG_DIM = (int(resize_sz*y_tiles_num), int(resize_sz*x_tiles_num))\n    CLASSES_NUM = 1\n    BATCH_SIZE = 32\n    N= 144\n    PRETRAIN_PATH = ['../input/panda-best-weights/fold0_b3_144tiles_128tilesize_mse_huber_0905kcv_0853rcv_0706.h5',\n                     '../input/panda-best-weights/fold2_b3_144tiles_128tilesize_mse_huber_09174kcv_0841rcv_0719.h5']\n    \n    \n    raw_prediction = sample_csv['isup_grade'].values\n    print (f'folder using: {main_folder}')\n    test_generator = TestGenerator(image_shape=IMG_DIM,\n                                   batch_size=1,\n                                   load_dir=os.path.join(MAIN_DIR, f'{main_folder}_images'),\n                                   test_df=sample_csv)\n    \n    for idx in range(len(PRETRAIN_PATH)):\n        if PRETRAIN_PATH[idx]:\n            print('load xies model pretrain weights..')\n            model = tf.keras.models.load_model(PRETRAIN_PATH[idx],\n                                               custom_objects={\n                                                   'Generalized_mean_pooling2D' : Generalized_mean_pooling2D\n                                                })\n    \n    \n            \n            #if os.path.exists(f'../input/prostate-cancer-grade-assessment/train_images'):\n            if os.path.exists(f'../input/prostate-cancer-grade-assessment/{main_folder}_images'):\n                if idx == 0:\n                    raw_prediction = inference(model, test_generator)\n                else:\n                    raw_prediction += inference(model, test_generator)\n    \n            print('Clean usage memory of xie29 ... ')\n\n            del model\n            tf.keras.backend.clear_session()\n            gc.collect()\n    \n    #averaging raw prediction\n    raw_prediction = raw_prediction / len(PRETRAIN_PATH)\n    \n    #####################\n    #trial\n    #train_csv['isup_grade'] = raw_prediction\n    #return train_csv\n    #####################\n    \n    \n    sample_csv['isup_grade'] = raw_prediction\n    return sample_csv","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA = '../input/prostate-cancer-grade-assessment/test_images'\nif os.path.exists(DATA): \n        xie = get_xie29_raw_prediction(debug=False)\n        #renaming columns\n        res_drhb = res_drhb.rename(columns={'isup_grade': 'res_drhb'})\n        res_igor = res_igor.rename(columns={'isup_grade': 'res_igor'})\n        res_rs50 = res_rs50.rename(columns={'isup_grade': 'res_rs50'})\n        res_ruef = res_ruef.rename(columns={'isup_grade': 'res_ruef'})\n        xie      = xie     .rename(columns={'isup_grade': 'res_xief'})\n        \n        #merging\n        from functools import reduce\n        sub_df = reduce(lambda x,y: pd.merge(x,y, on='image_id'), [res_drhb, res_igor, res_rs50, res_ruef, xie])\n        \n        #averaging and converting to int\n        \n        sub_df['med_level'] =          (sub_df['res_drhb'] + \n                                        sub_df['res_igor'] + \n                                        sub_df['res_rs50'])/3\n        \n        sub_df['isup_grade'] = predict((sub_df['med_level'] +\n                                        sub_df['res_ruef' ] + \n                                        sub_df['res_xief' ])/3)\n        #saving\n        sub_df = sub_df[['image_id', 'isup_grade']].copy()\n        sub_df.to_csv(\"./submission.csv\",index=False)\n\n\n        print('Clean usage memory of xie29 ... ')","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}