{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":45867,"databundleVersionId":6924515,"sourceType":"competition"},{"sourceId":1760030,"sourceType":"datasetVersion","datasetId":1046169},{"sourceId":6774553,"sourceType":"datasetVersion","datasetId":3898019},{"sourceId":7486642,"sourceType":"datasetVersion","datasetId":4358578},{"sourceId":7486941,"sourceType":"datasetVersion","datasetId":4358790},{"sourceId":8454643,"sourceType":"datasetVersion","datasetId":5024610},{"sourceId":39801,"sourceType":"modelInstanceVersion","modelInstanceId":33532},{"sourceId":41533,"sourceType":"modelInstanceVersion","modelInstanceId":34920},{"sourceId":41534,"sourceType":"modelInstanceVersion","modelInstanceId":34921},{"sourceId":43373,"sourceType":"modelInstanceVersion","modelInstanceId":36423}],"dockerImageVersionId":30636,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!ls /kaggle/input/pyvips-python-and-deb-package-gpu\n# intall the deb packages\n!yes | dpkg -i --force-depends /kaggle/input/pyvips-python-and-deb-package-gpu/linux_packages/archives/*.deb\n# install the python wrapper\n!pip install pyvips -f /kaggle/input/pyvips-python-and-deb-package-gpu/python_packages/ --no-index\n!pip list | grep pyvips\n# !pip install /kaggle/input/einops-030/einops-0.3.0-py2.py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:04:25.820712Z","iopub.execute_input":"2024-05-17T03:04:25.82141Z","iopub.status.idle":"2024-05-17T03:06:23.351702Z","shell.execute_reply.started":"2024-05-17T03:04:25.821369Z","shell.execute_reply":"2024-05-17T03:06:23.349714Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport pyvips","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:06:55.975317Z","iopub.execute_input":"2024-05-17T03:06:55.976024Z","iopub.status.idle":"2024-05-17T03:06:56.45606Z","shell.execute_reply.started":"2024-05-17T03:06:55.975987Z","shell.execute_reply":"2024-05-17T03:06:56.45512Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport pandas as pd\nimport numpy as np\nfrom PIL import Image\nimport os\nimport gc\nimport time\nfrom IPython import display\nimport glob\nimport random\nfrom joblib import Parallel, delayed","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:07:03.494809Z","iopub.execute_input":"2024-05-17T03:07:03.495888Z","iopub.status.idle":"2024-05-17T03:07:03.91663Z","shell.execute_reply.started":"2024-05-17T03:07:03.495842Z","shell.execute_reply":"2024-05-17T03:07:03.915703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import models, transforms, datasets","metadata":{"execution":{"iopub.status.busy":"2024-05-17T06:10:47.825639Z","iopub.execute_input":"2024-05-17T06:10:47.826398Z","iopub.status.idle":"2024-05-17T06:10:47.831002Z","shell.execute_reply.started":"2024-05-17T06:10:47.826365Z","shell.execute_reply":"2024-05-17T06:10:47.829937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df=pd.read_csv(\"/kaggle/input/dev-100/dev_100_3.csv\")\n\nprint('test dataset:')\nprint(test_df.shape)\nprint(test_df.head())","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:08:50.707194Z","iopub.execute_input":"2024-05-17T03:08:50.708109Z","iopub.status.idle":"2024-05-17T03:08:50.72053Z","shell.execute_reply.started":"2024-05-17T03:08:50.708072Z","shell.execute_reply":"2024-05-17T03:08:50.719645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# test_df=pd.read_csv(\"/kaggle/input/UBC-OCEAN/test.csv\")\n\n# print('test dataset:')\n# print(test_df.shape)\n# print(test_df.head())","metadata":{"execution":{"iopub.status.busy":"2024-04-30T12:04:02.959551Z","iopub.execute_input":"2024-04-30T12:04:02.960345Z","iopub.status.idle":"2024-04-30T12:04:02.994636Z","shell.execute_reply.started":"2024-04-30T12:04:02.960299Z","shell.execute_reply":"2024-04-30T12:04:02.993717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir test_tiles\nTEST_IMG_DIR = \"/kaggle/input/UBC-OCEAN/train_images/\"\nTEST_TBNLS_DIR = \"/kaggle/input/UBC-OCEAN/train_thumbnails/\"\nTEST_TILES_DIR = \"/kaggle/working/test_tiles/\"","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:09:50.350049Z","iopub.execute_input":"2024-05-17T03:09:50.350798Z","iopub.status.idle":"2024-05-17T03:09:51.358017Z","shell.execute_reply.started":"2024-05-17T03:09:50.350764Z","shell.execute_reply":"2024-05-17T03:09:51.356614Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.environ['VIPS_CONCURRENCY'] = '4'\nos.environ['VIPS_DISC_THRESHOLD'] = '15gb' \n#use disk caching instead of memory when the image exceeds 15GB","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:09:56.547558Z","iopub.execute_input":"2024-05-17T03:09:56.54807Z","iopub.status.idle":"2024-05-17T03:09:56.553293Z","shell.execute_reply.started":"2024-05-17T03:09:56.548034Z","shell.execute_reply":"2024-05-17T03:09:56.552273Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def extract_test_tiles(img_path, size=1792, scale=0.125, drop_thr=0.6, white_thr=240, max_samples=20):\n    \n    # print(f\"processing: {img_path}\")\n    im = pyvips.Image.new_from_file(img_path) #load image\n    \n    w=h=size\n    new_size = int(size * scale), int(size * scale)\n    \n    # https://stackoverflow.com/a/47581978/4521646\n    idxs = [(y, y + h, x, x + w) for y in range(0, im.height, h) for x in range(0, im.width, w)]\n    \n    # random subsample\n    max_samples = max_samples if isinstance(max_samples, int) else int(len(idxs) * max_samples)\n    random.shuffle(idxs)\n    \n    images = []\n    for y, y_, x, x_ in idxs:\n\n        tile = im.crop(x, y, min(w, im.width - x), min(h, im.height - y)).numpy()[..., :3] \n\n        # increase tile size to (h,w) for edge tiles\n        if tile.shape[:2] != new_size:\n            tile_ = tile\n            tile_size = (h, w) if tile.ndim == 2 else (h, w, tile.shape[2])\n            tile = np.zeros(tile_size, dtype=tile.dtype)\n            tile[:tile_.shape[0], :tile_.shape[1], ...] = tile_\n        \n        # reduce size\n        tile = np.array(Image.fromarray(tile).resize(new_size, Image.LANCZOS))\n        \n        # emptry ratio detection\n        black_bg = np.sum(tile, axis=2) == 0\n        tile[black_bg, :] = 255\n        mask_bg = np.mean(tile, axis=2) > white_thr\n        if np.sum(mask_bg) >= (np.prod(mask_bg.shape) * drop_thr):\n            #print(f\"skip almost empty tile: {k:06}_{int(x_ / w)}-{int(y_ / h)}\")\n            continue\n        # print(tile.shape, tile.dtype, tile.min(), tile.max())\n        \n        images.append(tile)\n        if len(images) >= max_samples:\n            break\n    return images","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:10:02.065624Z","iopub.execute_input":"2024-05-17T03:10:02.066335Z","iopub.status.idle":"2024-05-17T03:10:02.079459Z","shell.execute_reply.started":"2024-05-17T03:10:02.066299Z","shell.execute_reply":"2024-05-17T03:10:02.078334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"net_input=1024\n\nimport albumentations as A\nfrom albumentations import Compose, CenterCrop, Normalize\nfrom albumentations.pytorch import ToTensorV2\n\n# use albumentations for augmentation\nval_transform = A.Compose([\n        CenterCrop(height=net_input, width=net_input),\n        A.Normalize(\n                mean=[0.485, 0.456, 0.406], \n                std=[0.229, 0.224, 0.225], \n                max_pixel_value=255.0, \n                p=1.0\n            ),\n        ToTensorV2()])","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:10:03.722017Z","iopub.execute_input":"2024-05-17T03:10:03.723024Z","iopub.status.idle":"2024-05-17T03:10:05.179351Z","shell.execute_reply.started":"2024-05-17T03:10:03.722974Z","shell.execute_reply":"2024-05-17T03:10:05.178295Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ImageTilesDataset(Dataset):\n\n    def __init__(self, img_path:str, size=2048, scale=0.5, drop_thr=0.6, max_samples=20, transform=None):\n        assert os.path.isfile(img_path)\n        self.transform = transform\n        self.tiles=extract_test_tiles(img_path, size=size, scale=scale, drop_thr=drop_thr, max_samples=max_samples)\n    \n    def __len__(self) -> int:\n        return len(self.tiles)\n    \n    def __getitem__(self, idx: int):\n        tile = self.tiles[idx]\n        if np.max(tile) < 1.5:\n            tile = np.clip(tile * 255, 0, 255).astype(np.uint8)\n        # augmentation\n        if self.transform:\n            augmented = self.transform(image=tile)  # 注意，这里输入的img是一个numpy数组\n            tile = augmented['image']\n        return tile","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:10:05.72099Z","iopub.execute_input":"2024-05-17T03:10:05.721911Z","iopub.status.idle":"2024-05-17T03:10:05.730869Z","shell.execute_reply.started":"2024-05-17T03:10:05.721875Z","shell.execute_reply":"2024-05-17T03:10:05.729739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def try_gpu(i=0):\n    if torch.cuda.device_count()>=i+1:\n        return torch.device(f'cuda:{i}')\n    return torch.device('cpu')\n\ndef try_all_gpus():\n    devices=[torch.device(f'cuda:{i}') for i in range(torch.cuda.device_count())]\n    return devices if devices else [torch.device('cpu')]\n\nprint(try_all_gpus())","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:10:07.688128Z","iopub.execute_input":"2024-05-17T03:10:07.688969Z","iopub.status.idle":"2024-05-17T03:10:07.725109Z","shell.execute_reply.started":"2024-05-17T03:10:07.68893Z","shell.execute_reply":"2024-05-17T03:10:07.724036Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nfrom torch.utils.data import DataLoader\nimport torch.nn.functional as F\nfrom joblib.externals.loky.backend.context import get_context","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:10:18.194037Z","iopub.execute_input":"2024-05-17T03:10:18.194437Z","iopub.status.idle":"2024-05-17T03:10:18.200057Z","shell.execute_reply.started":"2024-05-17T03:10:18.194405Z","shell.execute_reply":"2024-05-17T03:10:18.199012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"label_dict_reverse = {0: 'CC', 1: 'EC', 2: 'HGSC', 3: 'LGSC', 4: 'MC'}\n\ndef infer_single_image(idx_row, nets, device=try_gpu(), max_samples=20, threshold=10) -> dict:\n    row = dict(idx_row[1])\n    \n    # prepare data - cut and load tiles\n    img_path = os.path.join(TEST_IMG_DIR, f\"{str(row['image_id'])}.png\")\n    test_dataset = ImageTilesDataset(img_path, size=3072, scale=0.5, max_samples=max_samples, transform=val_transform)\n    if not len(test_dataset):\n        print (f\"seem no tiles were cut for `{row['image_id']}`\")\n        return row\n    test_iter = torch.utils.data.DataLoader(\n        test_dataset, batch_size=8, num_workers=2, shuffle=False,\n        # https://github.com/pytorch/pytorch/issues/44687#issuecomment-790842173\n        multiprocessing_context=get_context('loky'))\n\n    # iterate over images and collect predictions\n    preds1 = []\n    preds2 = []\n    preds3 = []\n    preds4 = []\n    \n    for imgs in test_iter:\n        #print(f\"{imgs.shape}\")\n        with torch.no_grad():\n            imgs = imgs.to(device).half()\n            pred = nets[0](imgs)\n            pred1 = F.softmax(pred, dim=1)\n            \n            pred = nets[1](imgs)\n            pred2 = F.softmax(pred, dim=1)\n            \n            pred = nets[2](imgs)\n            pred3 = F.softmax(pred, dim=1)\n            \n            pred = nets[3](imgs)\n            pred4 = F.softmax(pred, dim=1)\n            \n        preds1 += pred1.cpu().numpy().tolist()\n        preds2 += pred2.cpu().numpy().tolist()\n        preds3 += pred3.cpu().numpy().tolist()\n        preds4 += pred4.cpu().numpy().tolist()\n    # print(f\"Sum contrinution from all tiles: {np.sum(preds, axis=0)}\")\n    # print(f\"Max contribution over all tiles: {np.max(preds, axis=0)}\")\n    \n    # decide label\n    preds1 = np.sum(preds1, axis=0)\n    preds2 = np.sum(preds2, axis=0)\n    preds3 = np.sum(preds3, axis=0)\n    preds4 = np.sum(preds4, axis=0)\n    \n    lb1 = np.argmax(preds1)\n    lb1_prob = np.max(preds1)\n    \n    lb2 = np.argmax(preds2)\n    lb2_prob = np.max(preds2)\n    \n    lb3 = np.argmax(preds3)\n    lb3_prob = np.max(preds3)\n    \n    lb4 = np.argmax(preds4)\n    lb4_prob = np.max(preds4)\n    \n    labels = [lb1, lb2, lb3, lb4]\n\n    lb = labels[np.argmax([lb1_prob, lb2_prob, lb3_prob, lb4_prob])]\n        \n    row['label'] = label_dict_reverse[lb]\n    \n    del test_iter, test_dataset\n    gc.collect()\n    \n    # print(row)\n    return row","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:10:21.885384Z","iopub.execute_input":"2024-05-17T03:10:21.885766Z","iopub.status.idle":"2024-05-17T03:10:21.900388Z","shell.execute_reply.started":"2024-05-17T03:10:21.885734Z","shell.execute_reply":"2024-05-17T03:10:21.899393Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import timm\nnet = timm.create_model('resnest200e', pretrained=0, num_classes=5)\nnet.load_state_dict(torch.load( '/kaggle/input/v2efficientnet/pytorch/resnet200e/1/resnest200e.in1k_bestAcc0.950_imgsize_1024_onlyRedMaskTileImg_stainmix.pt' ))\n\n# net2 = timm.create_model('tf_efficientnetv2_m', pretrained=True, num_classes=5)\n# net2.load_state_dict(torch.load( '/kaggle/input/v2efficientnet/pytorch/tf2/1/tf_efficientnet_b5.ns_jft_in1k_bestRecall0.719_imgsize_1024_onlyMaskTileImg_stainmix.pt')['state_dict'])\nnet2 = timm.create_model('tf_efficientnetv2_l.in21k_ft_in1k', pretrained=0, num_classes=5)\nnet2.load_state_dict(torch.load('/kaggle/input/v2efficientnet/pytorch/v232/1/tf_efficientnetv2_l.in21k_ft_in1k_ep32_Recall0.639_imgsize_1024_fold1.pt'))\n\nnet3 = timm.create_model('resnest200e', pretrained=0, num_classes=5)\nnet3.load_state_dict(torch.load( '/kaggle/input/v2efficientnet/pytorch/bestreacll078resnet/1/resnest200e.in1k_bestRecall0.780_imgsize_1024_onlyRedMaskTileImg_stainmix_v2.pt' ))\n\nnet4 = timm.create_model('seresnextaa101d_32x8d', pretrained=0, num_classes=5)\nnet4.load_state_dict(torch.load( '/kaggle/input/v2efficientnet/pytorch/seresnetx/1/seresnextaa101d_32x8d.sw_in12k_ft_in1k_ep16_bestRecall0.735_imgsize_1024_onlyRedMaskTileImg_stainmix.pt' ))","metadata":{"execution":{"iopub.status.busy":"2024-05-17T06:11:01.020614Z","iopub.execute_input":"2024-05-17T06:11:01.020977Z","iopub.status.idle":"2024-05-17T06:11:22.698181Z","shell.execute_reply.started":"2024-05-17T06:11:01.020947Z","shell.execute_reply":"2024-05-17T06:11:22.697111Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm.auto import tqdm\nfrom joblib import Parallel, delayed\n\nnet = net.to(try_gpu()).half()\nnet.eval()\nnet2 = net2.to(try_gpu()).half()\nnet2.eval()\nnet3 = net3.to(try_gpu()).half()\nnet3.eval()\nnet4 = net4.to(try_gpu()).half()\nnet4.eval()\nnets = [net, net2, net3, net4]\n# nets = [net, net3]\nmax_samples = 24\nthreshold = 0  # for identifying outliers\nsubmission = []","metadata":{"execution":{"iopub.status.busy":"2024-05-17T03:10:57.80591Z","iopub.execute_input":"2024-05-17T03:10:57.806795Z","iopub.status.idle":"2024-05-17T03:10:58.402777Z","shell.execute_reply.started":"2024-05-17T03:10:57.80676Z","shell.execute_reply":"2024-05-17T03:10:58.401727Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = Parallel(n_jobs=-2, backend='loky')(\n     delayed(infer_single_image)\n     (idx_row, nets=nets, device=try_gpu(), max_samples=max_samples, threshold=threshold)\n     for idx_row in tqdm(test_df.iterrows(), total=len(test_df))\n )\n# submission\n\noutput = pd.DataFrame(submission)[[\"image_id\", \"label\"]]\noutput.to_csv(\"submission_esemble4.csv\", index=False)\nprint(output)\nprint(\"Your submission was successfully saved!\")","metadata":{},"execution_count":null,"outputs":[]}]}