{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Import","metadata":{"_kg_hide-output":true}},{"cell_type":"code","source":"import sys\nsys.path.append('../input/efficientnet-pytorch/EfficientNet-PyTorch/EfficientNet-PyTorch-master')\nsys.path.append('../input/pytorch-image-models/pytorch-image-models-master')\nsys.path.append('../input/pytorch-images-seresnet')","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n%matplotlib inline\n\nfrom tqdm.notebook import tqdm\nimport os, gc\nimport random\nimport math\nfrom PIL import Image\nimport tifffile as tiff\nimport cv2\nimport zipfile\n\nimport timm\nfrom efficientnet_pytorch import EfficientNet\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader, Dataset\nimport torch.optim as optim\n\nimport torchvision\nfrom torchvision import transforms\nimport albumentations as A\nfrom torch.optim.lr_scheduler import CosineAnnealingWarmRestarts\nfrom torch.optim.lr_scheduler import CosineAnnealingLR\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"seed = 2020\nseed_everything(seed)\nprint(device)\n\nTEST_ROOT = '../input/hpa-single-cell-image-classification/test/'\n\nsz = 256\nbs = 64\nTH = 1e-15\n\n#ImageNet\nmean = np.array([[[0.485, 0.456, 0.406]]])\nstd = np.array([[[0.229, 0.224, 0.225]]])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#commit: public\n#submit: public + private\ntest_df = pd.read_csv('../input/hpa-single-cell-image-classification/sample_submission.csv')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#commit&submit: public\npublic = pd.read_csv('../input/hpasubmission009/sample_submission.csv')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#commit: public + public\n#submit: public + private + public\ntest_df_ = pd.concat([test_df, public]).reset_index(drop=True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#commit→publicの最後20個のid\nif len(test_df) == 559:\n    public = test_df_[-20:]\n\n#submit→private_id\nelse:\n    public = test_df_.drop_duplicates(keep=False).reset_index(drop=True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Functions","metadata":{}},{"cell_type":"code","source":"def collate_fn(batch):\n    return tuple(zip(*batch))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_RGB_image(image_id_path):\n    red = cv2.imread(image_id_path+\"_red.png\", cv2.IMREAD_GRAYSCALE) #HW\n    green = cv2.imread(image_id_path+\"_green.png\", cv2.IMREAD_GRAYSCALE)\n    blue = cv2.imread(image_id_path+\"_blue.png\", cv2.IMREAD_GRAYSCALE)\n    \n    #CHW\n    stacked_image = np.array([red, green, blue])\n    return stacked_image","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_GGG_image(image_id_path):\n    green = cv2.imread(image_id_path+\"_green.png\", cv2.IMREAD_GRAYSCALE)\n    \n    #CHW\n    stacked_image = np.array([green, green, green])\n    return stacked_image","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset","metadata":{"_kg_hide-output":true}},{"cell_type":"code","source":"class HPADataset(Dataset):\n    def __init__(self, path, df, nuc_masks_batch, cell_masks_batch, transform=None):\n        self.path = path\n        self.df = df\n        self.nuc_masks_batch = nuc_masks_batch\n        self.cell_masks_batch = cell_masks_batch\n        self.transform = transform\n    \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):  #1バッチ内でのidx\n        img_path = os.path.join(self.path, self.df.iloc[idx, 0])\n        image = load_RGB_image(img_path).astype(np.float32)  #3*H*W\n        green = load_GGG_image(img_path).astype(np.float32)  #3*H*W\n        img_512 = cv2.resize(np.transpose(green, (1, 2, 0)), (512, 512))  #512*512*3\n        img_512 = (img_512/255.0 - mean) / std  #Normalization\n        img_512 = np.transpose(img_512, (2, 0, 1))  #3*512*512\n        img_512 = torch.from_numpy(img_512)\n        \n        nuc_mask = nuc_masks_batch[idx]  #H*W\n        cell_mask = cell_masks_batch[idx]  #H*W\n        img_tiles = []\n        img_centers = []\n        \n        for i in range(1, np.max(cell_mask)+1):\n            try: #細胞マスクができる時\n                cx1 = np.min(np.where(cell_mask==i)[1])\n                cx2 = np.max(np.where(cell_mask==i)[1])\n                cy1 = np.min(np.where(cell_mask==i)[0])\n                cy2 = np.max(np.where(cell_mask==i)[0])\n            \n            except: #細胞マスクができない時はラベル予測をしても意味がない\n                continue\n            \n            try: #核マスクができる時\n                nx1 = np.min(np.where(nuc_mask==i)[1])\n                nx2 = np.max(np.where(nuc_mask==i)[1])\n                ny1 = np.min(np.where(nuc_mask==i)[0])\n                ny2 = np.max(np.where(nuc_mask==i)[0])\n#                 xc = (nx1 + nx2) // 2\n#                 yc = (ny1 + ny2) // 2\n#                 img_centers.append([xc, yc])  #核BBoxの中心座標\n                \n            except: #核マスクができない時\n                continue\n#                 blue = image[2]\n#                 cell_mask_ = np.where(cell_mask==i, 0, -255)  #該当細胞マスク領域は0、それ以外は-255の配列\n#                 rblue = np.clip(blue+cell_mask_, 0, 255).astype(np.uint8)\n#                 nuc_coo = np.argwhere((rblue>=1)&(rblue<=255))  #細胞マスク内でblueが1以上の値を取る座標(核+α?)\n#                 nuc_center = np.median(nuc_coo, axis=0).astype(np.int32)  #上記座標の中央値(外れ値に強くするため)\n#                 xc = nuc_center[1]\n#                 yc = nuc_center[0]\n#                 img_centers.append([xc, yc])\n#                 del blue, cell_mask_, rblue, nuc_coo\n#                 gc.collect()\n                \n            \n            #核BBoxの中心座標\n            xc = (nx1 + nx2) // 2\n            yc = (ny1 + ny2) // 2\n            img_centers.append([xc, yc])           \n    \n            #切り出すタイルの1辺の長さaは細胞BBoxの短辺とする\n            w = cx2 - cx1\n            h = cy2 - cy1\n            if w <= h: a = w\n            else: a = h\n            \n            #padding追加\n            pad0 = a\n            pad1 = a\n            image_ = np.pad(image, [(0, 0), (pad0//2, pad0-pad0//2), (pad1//2, pad1-pad1//2)], constant_values=0)\n            \n            #切り出す細胞タイルの左上と右下の座標を求める(+padding補正)\n            rx1 = xc - a//2 + a//2\n            rx2 = xc + a//2 + a//2\n            ry1 = yc - a//2 + a//2\n            ry2 = yc + a//2 + a//2\n            \n            #タイル切り出し\n            tile = image_[:, ry1:ry2, rx1:rx2]  #3*a*a\n            tile = np.transpose(tile, (1, 2, 0))  #a*a*3\n            rtile = cv2.resize(tile, (sz, sz))  #sz*sz*3\n            rtile = (rtile/255.0 - mean) / std  #Normalization\n            rtile = np.transpose(rtile, (2, 0, 1))  #3*sz*sz\n\n            rtile = torch.from_numpy(rtile)\n            img_tiles.append(rtile)\n            \n            del image_, tile, rtile\n            gc.collect()\n            \n        img_centers = np.array(img_centers)\n        \n        del image, nuc_mask, cell_mask, green\n        gc.collect()\n        \n        return img_tiles, img_centers, img_512","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Tile Model","metadata":{}},{"cell_type":"code","source":"#EfficientNet B5\ntile_model1 = EfficientNet.from_name('efficientnet-b5')\ntile_model1._fc = nn.Linear(in_features=2048, out_features=19)\ntile_model1.load_state_dict(torch.load('../input/hpa-vol4tox-upsampling-6enspl-efb5-weight/efficientnetb5_seed_2020_single_fold.pth'))\ntile_model1.to(device)","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#EfficientNet B6\ntile_model2 = EfficientNet.from_name('efficientnet-b6')\ntile_model2._fc = nn.Linear(in_features=2304, out_features=19)\ntile_model2.load_state_dict(torch.load('../input/hpa-vol4tox-upsampling-6enspl-efb6-weight/efficientnetb6_seed_2020_single_fold.pth'))\ntile_model2.to(device)","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#EfficientNet B7\ntile_model3 = EfficientNet.from_name('efficientnet-b7')\ntile_model3._fc = nn.Linear(in_features=2560, out_features=19)\ntile_model3.load_state_dict(torch.load('../input/hpa-vol4tox-upsampling-6enspl-efb7-weight/efficientnetb7_seed_2020_single_fold.pth'))\ntile_model3.to(device)","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#SEResNeXt50\nclass SRNX50(nn.Module):\n    def __init__(self, model_name='seresnext50_32x4d', pretrained=True):\n        super().__init__()\n        self.model = timm.create_model(model_name, pretrained=pretrained)\n        n_features = self.model.fc.in_features\n        self.model.fc = nn.Linear(n_features, 19)\n\n    def forward(self, x):\n        x = self.model(x)\n        return x\n    \ntile_model4 = SRNX50(pretrained=False)\ntile_model4.load_state_dict(torch.load('../input/hpa-vol4tox-upsampling-6enspl-srnx50-weight/seresnext50_seed_2020_single_fold.pth'))\ntile_model4.to(device)","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#CSPResNeXt50\nclass CSPNetModel(nn.Module):\n    \n    def __init__(self, num_classes=19, model_name='cspresnext50', pretrained=True):\n        super(CSPNetModel, self).__init__()\n        self.model = timm.create_model(model_name, pretrained=pretrained)\n        self.model.head.fc = nn.Linear(self.model.head.fc.in_features, 19)\n        \n    def forward(self, x):\n        x = self.model(x)\n        return x\n    \ntile_model5 = CSPNetModel(pretrained=False)\ntile_model5.load_state_dict(torch.load('../input/hpa-vol4tox-upsampling-6enspl-csprnx50-weight/cspresnext50_seed_2020_single_fold.pth'))\ntile_model5.to(device)","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#NFNet F1\nclass NFNet(nn.Module):\n    def __init__(self, output_features=19, model_name='nfnet_f1', pretrained=True):\n        super(NFNet, self).__init__()\n        self.model = timm.create_model(model_name, pretrained=pretrained)\n        self.model.head.fc = nn.Sequential(nn.Linear(self.model.head.fc.in_features, 512),\n                                 nn.ReLU(),\n                                 nn.Linear(512, output_features))\n        \n    def forward(self, x):\n        x = self.model(x)\n        return x\n\ntile_model6 = NFNet(pretrained=False)\ntile_model6.load_state_dict(torch.load('../input/hpa-vol4tox-upsampling-6enspl-nfnetf1-weight/nfnetf1_seed_2020_single_fold.pth'))\ntile_model6.to(device)","metadata":{"_kg_hide-output":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Image Model","metadata":{}},{"cell_type":"code","source":"#EfficientNet B7\nimg_model = EfficientNet.from_name('efficientnet-b7')\nimg_model._fc = nn.Linear(in_features=2560, out_features=19)\nimg_model.load_state_dict(torch.load('../input/hpa-ill-ggg-efb7-weight/efficientnetb7_seed_2020_single_fold.pth'))\nimg_model.to(device)","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference function","metadata":{}},{"cell_type":"code","source":"def inference_per_batch(data_loader, \n                        tile_model1, \n                        tile_model2, \n                        tile_model3, \n                        tile_model4, \n                        tile_model5, \n                        tile_model6, \n                        img_model, \n                        device):\n    \n    tile_model1.eval()  #EFB5\n    tile_model2.eval()  #EFB6\n    tile_model3.eval()  #EFB7\n    tile_model4.eval()  #SRNX50\n    tile_model5.eval()  #CSPRNX50\n    tile_model6.eval()  #NFNetF1\n    img_model.eval()  #EFB7\n    \n    for i, (img_tiles, img_centers, img) in enumerate(data_loader):  #1バッチ\"だけ\"取り出す\n        preds = []\n        \n        for j in range(len(img_tiles)):  #1バッチ内のj番目の画像に対して\n            tiles = img_tiles[j]\n            preds_per_image = []\n            img_j = img[j].to(device, dtype=torch.float)\n            img_j = img_j.unsqueeze(0)\n            img_pred = img_model(img_j)\n            img_pred = nn.Sigmoid()(img_pred)  #1*19\n            img_pred[0][11] = 0.0\n            img_pred[0][18] = 0.0\n            \n            for k in range(len(tiles)):  #1バッチ内のj番目の画像のk番目にtileに対して\n                tile = tiles[k]\n                tile = torch.unsqueeze(tile, 0)  #(batch)の次元を増やす\n                tile = tile.to(device, dtype=torch.float)\n        \n                with torch.no_grad():\n                    tile_pred1 = tile_model1(tile)\n                    tile_pred2 = tile_model2(tile)\n                    tile_pred3 = tile_model3(tile)\n                    tile_pred4 = tile_model4(tile)\n                    tile_pred5 = tile_model5(tile)\n                    tile_pred6 = tile_model6(tile)\n                    tile_pred1 = nn.Sigmoid()(tile_pred1)  #1*19\n                    tile_pred2 = nn.Sigmoid()(tile_pred2)  #1*19\n                    tile_pred3 = nn.Sigmoid()(tile_pred3)  #1*19\n                    tile_pred4 = nn.Sigmoid()(tile_pred4)  #1*19\n                    tile_pred5 = nn.Sigmoid()(tile_pred5)  #1*19\n                    tile_pred6 = nn.Sigmoid()(tile_pred6)  #1*19\n                    tile_pred = (tile_pred1 + tile_pred2 + tile_pred3 + tile_pred4 + tile_pred5 + tile_pred6) / 6\n\n                    pred = tile_pred * 0.75 + img_pred * 0.25\n                    \n                preds_per_image.append(pred.detach().cpu().numpy())\n        \n                del tile, pred, tile_pred1, tile_pred2, tile_pred3, tile_pred4, tile_pred5, tile_pred6, tile_pred\n                gc.collect()\n            \n            preds_per_image = np.stack(preds_per_image)  #j番目の画像に関してk個のタイル予測結果を結合\n            preds.append(preds_per_image)    \n\n            del img_j, img_pred\n            gc.collect()\n            \n    return preds, img_centers","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# HPA-cellsegmentator","metadata":{}},{"cell_type":"code","source":"!pip install \"../input/pycocotools/pycocotools-2.0-cp37-cp37m-linux_x86_64.whl\"\n!pip install \"../input/hpapytorchzoozip/pytorch_zoo-master\"\n!pip install \"../input/hpacellsegmentatorraman/HPA-Cell-Segmentation/\"","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import warnings\nwith warnings.catch_warnings():\n    warnings.simplefilter(\"ignore\")\n    import numpy as np\n    import pandas as pd\n    import os\n    import gc\n    import os.path\n    import urllib\n    import zipfile\n    from hpacellseg.cellsegmentator import *\n    from hpacellseg import cellsegmentator, utils\n    import cv2\n    import scipy.ndimage as ndi\n    from skimage import filters, measure, segmentation, transform, util\n    from skimage.morphology import (binary_erosion, closing, disk, remove_small_holes, remove_small_objects)\n    from PIL import Image\n    import matplotlib.pyplot as plt","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"NUC_MODEL = \"../input/hpacellsegmentatormodelweights/dpn_unet_nuclei_v1.pth\"\nCELL_MODEL = \"../input/hpacellsegmentatormodelweights/dpn_unet_cell_3ch_v1.pth\"\nsegmentator_even_faster = cellsegmentator.CellSegmentator(\n    NUC_MODEL,\n    CELL_MODEL,\n    device=\"cuda\",\n    multi_channel_model=True,\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_images(df, size, root='../input/hpa-single-cell-image-classification/test/'):\n    blue_scaled = []\n    rgb_scaled = []\n    for id in list(df.ID):\n        r = cv2.imread(os.path.join(root, f'{id}_red.png'), cv2.IMREAD_GRAYSCALE)\n        y = cv2.imread(os.path.join(root, f'{id}_yellow.png'), cv2.IMREAD_GRAYSCALE)\n        b = cv2.imread(os.path.join(root, f'{id}_blue.png'), cv2.IMREAD_GRAYSCALE)\n        blue_image = cv2.resize(b, (int(size*0.25), int(size*0.25)))\n        rgb_image = cv2.resize(np.stack((r, y, b), axis=2), (int(size*0.25), int(size*0.25)))\n        blue_scaled.append(blue_image/255.)\n        rgb_scaled.append(rgb_image/255.)\n        del r, y, b, blue_image, rgb_image\n        gc.collect()\n    return blue_scaled, rgb_scaled","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import base64\nimport numpy as np\nfrom pycocotools import _mask as coco_mask\nimport typing as t\nimport zlib\n\n\ndef encode_binary_mask(mask: np.ndarray) -> t.Text:\n  \"\"\"Converts a binary mask into OID challenge encoding ascii text.\"\"\"\n\n  # check input mask --\n  if mask.dtype != np.bool:\n    raise ValueError(\n        \"encode_binary_mask expects a binary mask, received dtype == %s\" %\n        mask.dtype)\n\n  mask = np.squeeze(mask)\n  if len(mask.shape) != 2:\n    raise ValueError(\n        \"encode_binary_mask expects a 2d mask, received shape == %s\" %\n        mask.shape)\n\n  # convert input mask to expected COCO API input --\n  mask_to_encode = mask.reshape(mask.shape[0], mask.shape[1], 1)\n  mask_to_encode = mask_to_encode.astype(np.uint8)\n  mask_to_encode = np.asfortranarray(mask_to_encode)\n\n  # RLE encode mask --\n  encoded_mask = coco_mask.encode(mask_to_encode)[0][\"counts\"]\n\n  # compress and base64 encoding --\n  binary_str = zlib.compress(encoded_mask, zlib.Z_BEST_COMPRESSION)\n  base64_str = base64.b64encode(binary_str)\n  return base64_str.decode('ascii')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"#Image sizeごとにtest_dfを分割\n#それぞれindexを初期化(0スタート)してからsub_dfsに格入\nsub_dfs = []\nfor dim in public.ImageWidth.unique():\n    df = public[public['ImageWidth']==dim].copy().reset_index(drop=True)\n    sub_dfs.append(df)\n\nfor sub in sub_dfs:\n    print(f'<<<<<<<<<<Inference for image size: {sub.ImageWidth.loc[0]}>>>>>>>>>>')\n    \n    for start in tqdm(range(0, len(sub), bs)):\n        #1バッチごとにcell segmentation→label inference→mask and label matchingを行う\n        #start: 0, bs, 2*bs, 3*bs...\n        #img_num: 1バッチに含まれる画像数(id数)\n        if len(sub) < bs:\n            img_num = len(sub)\n        elif len(sub) - start < bs:\n            img_num = len(sub) - start\n        else:\n            img_num = bs        \n        \n        ############################################################################ \n        \n        #fast cell segmentation\n        print(f'Image {sub.ImageWidth.loc[0]} Batch {int(start/bs)+1}: Cell Segmentation')\n        data_df = sub[start:start+img_num]  #subの1バッチ分のdf\n        blue_scaled, rgb_scaled = load_images(df=data_df, size=sub.ImageWidth.loc[0])\n        nuc_masks_batch = []\n        cell_masks_batch = []\n        batch_size = 24\n        with warnings.catch_warnings():\n            warnings.simplefilter(\"ignore\")\n            for i in range(0, len(data_df), batch_size):\n                s = i\n                e = min(len(data_df), s+batch_size)\n                blue_batch = blue_scaled[s:e]\n                rgb_batch = rgb_scaled[s:e]\n                nuc_segmentations = segmentator_even_faster.pred_nuclei(blue_batch)\n                cell_segmentations = segmentator_even_faster.pred_cells(rgb_batch, precombined=True)\n                for data_id, nuc_seg, cell_seg in zip(data_df.ID.to_list(), nuc_segmentations, cell_segmentations):\n                    nuc_mask, cell_mask = utils.label_cell(nuc_seg, cell_seg)\n                    #マスクに関してはinterpolation大切\n                    r_nuc_mask = cv2.resize(nuc_mask.astype(np.uint8), (sub.ImageWidth.loc[0], sub.ImageWidth.loc[0]), interpolation=cv2.INTER_NEAREST)\n                    r_cell_mask = cv2.resize(cell_mask.astype(np.uint8), (sub.ImageWidth.loc[0], sub.ImageWidth.loc[0]), interpolation=cv2.INTER_NEAREST)                        \n                    nuc_masks_batch.append(r_nuc_mask)\n                    cell_masks_batch.append(r_cell_mask)\n                    del nuc_mask, cell_mask, r_nuc_mask, r_cell_mask\n                    gc.collect()\n                del blue_batch, rgb_batch, nuc_segmentations, cell_segmentations\n                gc.collect()\n        del blue_scaled, rgb_scaled, data_df\n        gc.collect()\n        \n        ############################################################################\n        \n        #label inference\n        print(f'Image {sub.ImageWidth.loc[0]} Batch {int(start/bs)+1}: Label inference')\n        test_ds = HPADataset(path=TEST_ROOT,\n                             df=sub.iloc[start:start+img_num],\n                             nuc_masks_batch=nuc_masks_batch,\n                             cell_masks_batch=cell_masks_batch,\n                             transform=None)\n        test_dl = DataLoader(dataset=test_ds,\n                             batch_size=img_num,\n                             shuffle=False,\n                             collate_fn=collate_fn,\n                             num_workers=0)\n        preds, centers = inference_per_batch(test_dl, \n                                             tile_model1, \n                                             tile_model2, \n                                             tile_model3, \n                                             tile_model4, \n                                             tile_model5, \n                                             tile_model6,\n                                             img_model, \n                                             device)\n        del test_ds, test_dl, nuc_masks_batch\n        gc.collect()\n        \n        ############################################################################\n\n        #mask and label matching\n        print(f'Image {sub.ImageWidth.loc[0]} Batch {int(start/bs)+1}: Mask and Label matching')\n        predstrings = []    \n        for i in range(img_num):  #1バッチ内のi番目の画像に対して          \n            preds_ = preds[i]\n            centers_ = centers[i]\n            cell_masks_ = cell_masks_batch[i]\n            predstring = ''\n            all_masks = np.arange(1, np.max(cell_masks_)+1)\n            pocs = []\n        \n            for t in range(len(preds_)):\n                poc = cell_masks_[centers_[t][1], centers_[t][0]]  #poc: 細胞マスクの核座標におけるピクセル値\n                if poc == 0: continue  #偶発的に0の場合\n                pocs.append(poc)\n                lpred = preds_[t]  #lpred: タイルのラベル予測(1*19)\n                lpred_arr = np.where(lpred.flatten()>TH)[0]  #lpred_arr: THより大きいラベル一覧を取得\n                bmask = (cell_masks_==poc)\n                enc = encode_binary_mask(bmask)\n                \n                if len(lpred_arr) == 0:  #生予測値の全てがTH以下で予測ラベルが存在しない時→ひとまず'18'にする\n                    predstring += '18' + f' {lpred[0][18]} ' + enc + ' '\n                else:  #1タイルに対してちゃんと1つ以上のラベルが存在する時\n                    for l in lpred_arr:\n                        predstring += f'{l}' + f' {lpred[0][l]} ' + enc + ' '        \n                del bmask, enc\n                gc.collect()\n        \n            #細胞マスキングはできたが核マスキングはできなかった場合\n            lack = list(set(all_masks) - set(pocs))\n            labels = np.arange(19)\n            for ll in lack:\n                bmask = (cell_masks_==ll)\n                enc = encode_binary_mask(bmask)\n                for l in labels:\n                    predstring += 'l' + f' {TH} ' + enc + ' '\n                del bmask, enc\n                gc.collect()\n            predstrings.append(predstring)\n            del preds_, centers_, cell_masks_, predstring\n            gc.collect()\n        \n        sub['PredictionString'].iloc[start:start+img_num] = predstrings\n        del predstrings, cell_masks_batch, preds, centers\n        gc.collect()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_subs = pd.concat(sub_dfs, ignore_index=True, sort=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_subs.head(20)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_subs.iloc[0, 3]","metadata":{"_kg_hide-output":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"private_dict = dict(zip(all_subs['ID'], all_subs['PredictionString']))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['PredictionString'] = test_df['ID'].map(private_dict).fillna(test_df['PredictionString'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}