{"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":6774553,"sourceType":"datasetVersion","datasetId":3898019},{"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":51789,"sourceType":"modelInstanceVersion","modelInstanceId":43554}],"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-23T09:46:05.444959Z","iopub.execute_input":"2024-05-23T09:46:05.445275Z","iopub.status.idle":"2024-05-23T09:47:32.878839Z","shell.execute_reply.started":"2024-05-23T09:46:05.445249Z","shell.execute_reply":"2024-05-23T09:47:32.877648Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport pyvips","metadata":{"execution":{"iopub.status.busy":"2024-05-23T09:47:32.881222Z","iopub.execute_input":"2024-05-23T09:47:32.881621Z","iopub.status.idle":"2024-05-23T09:47:33.369024Z","shell.execute_reply.started":"2024-05-23T09:47:32.881585Z","shell.execute_reply":"2024-05-23T09:47:33.367989Z"},"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-23T09:47:33.370389Z","iopub.execute_input":"2024-05-23T09:47:33.370764Z","iopub.status.idle":"2024-05-23T09:47:33.758931Z","shell.execute_reply.started":"2024-05-23T09:47:33.370733Z","shell.execute_reply":"2024-05-23T09:47:33.758003Z"},"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-23T09:47:33.761179Z","iopub.execute_input":"2024-05-23T09:47:33.761675Z","iopub.status.idle":"2024-05-23T09:47:35.622881Z","shell.execute_reply.started":"2024-05-23T09:47:33.761641Z","shell.execute_reply":"2024-05-23T09:47:35.622013Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df=pd.read_csv(\"/kaggle/input/UBC-OCEAN/test.csv\")\n\nprint('test dataset:')\nprint(test_df.shape)\nprint(test_df.head())","metadata":{"execution":{"iopub.status.busy":"2024-05-23T09:47:35.623986Z","iopub.execute_input":"2024-05-23T09:47:35.624406Z","iopub.status.idle":"2024-05-23T09:47:35.649253Z","shell.execute_reply.started":"2024-05-23T09:47:35.624379Z","shell.execute_reply":"2024-05-23T09:47:35.648345Z"},"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/test_images/\"\nTEST_TBNLS_DIR = \"/kaggle/input/UBC-OCEAN/test_thumbnails/\"\nTEST_TILES_DIR = \"/kaggle/working/test_tiles/\"","metadata":{"execution":{"iopub.status.busy":"2024-05-23T09:48:49.412206Z","iopub.execute_input":"2024-05-23T09:48:49.412621Z","iopub.status.idle":"2024-05-23T09:48:50.424094Z","shell.execute_reply.started":"2024-05-23T09:48:49.412588Z","shell.execute_reply":"2024-05-23T09:48:50.422742Z"},"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-23T09:48:52.379674Z","iopub.execute_input":"2024-05-23T09:48:52.380051Z","iopub.status.idle":"2024-05-23T09:48:52.387517Z","shell.execute_reply.started":"2024-05-23T09:48:52.380021Z","shell.execute_reply":"2024-05-23T09:48:52.386488Z"},"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-23T09:48:53.366457Z","iopub.execute_input":"2024-05-23T09:48:53.367344Z","iopub.status.idle":"2024-05-23T09:48:53.379274Z","shell.execute_reply.started":"2024-05-23T09:48:53.367312Z","shell.execute_reply":"2024-05-23T09:48:53.378353Z"},"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-23T09:48:55.078692Z","iopub.execute_input":"2024-05-23T09:48:55.079342Z","iopub.status.idle":"2024-05-23T09:48:56.553469Z","shell.execute_reply.started":"2024-05-23T09:48:55.07931Z","shell.execute_reply":"2024-05-23T09:48:56.552569Z"},"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-23T09:48:56.712867Z","iopub.execute_input":"2024-05-23T09:48:56.713338Z","iopub.status.idle":"2024-05-23T09:48:56.721797Z","shell.execute_reply.started":"2024-05-23T09:48:56.713311Z","shell.execute_reply":"2024-05-23T09:48:56.720738Z"},"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-23T09:49:01.571685Z","iopub.execute_input":"2024-05-23T09:49:01.572055Z","iopub.status.idle":"2024-05-23T09:49:01.599901Z","shell.execute_reply.started":"2024-05-23T09:49:01.572026Z","shell.execute_reply":"2024-05-23T09:49:01.598934Z"},"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-23T09:49:03.542674Z","iopub.execute_input":"2024-05-23T09:49:03.543419Z","iopub.status.idle":"2024-05-23T09:49:03.548066Z","shell.execute_reply.started":"2024-05-23T09:49:03.543386Z","shell.execute_reply":"2024-05-23T09:49:03.547046Z"},"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    for imgs in test_iter:\n        #print(f\"{imgs.shape}\")\n        with torch.no_grad():\n            imgs = imgs.to(device).half()\n            \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        preds1 += pred1.cpu().numpy().tolist()\n        preds2 += pred2.cpu().numpy().tolist()\n        preds3 += pred3.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    \n    lb1 = np.argmax(preds1)\n    lb1_prob = np.max(preds1)\n    lb2 = np.argmax(preds2)\n    lb2_prob = np.max(preds2)\n    lb3 = np.argmax(preds3)\n    lb3_prob = np.max(preds3)\n    \n    labels = [lb1, lb2, lb3]\n\n    \n    if np.max([lb1_prob, lb2_prob, lb3_prob])>= 0.1733:\n        lb = labels[np.argmax([lb1_prob, lb2_prob, lb3_prob])]\n        row['label'] = label_dict_reverse[lb]\n    else:\n        row['label'] = 'other'\n\n#     lb = labels[np.argmax([lb1_prob, lb2_prob, lb3_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-23T09:49:06.394997Z","iopub.execute_input":"2024-05-23T09:49:06.395852Z","iopub.status.idle":"2024-05-23T09:49:06.409727Z","shell.execute_reply.started":"2024-05-23T09:49:06.395818Z","shell.execute_reply":"2024-05-23T09:49:06.408826Z"},"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/efficientnetv2-152/pytorch/cx-152/1/tf_efficientnetv2_l.in21k_ft_in1k_ep13_bestRecall0.662_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' ))","metadata":{"execution":{"iopub.status.busy":"2024-05-23T09:49:17.091521Z","iopub.execute_input":"2024-05-23T09:49:17.09188Z","iopub.status.idle":"2024-05-23T09:49:32.032385Z","shell.execute_reply.started":"2024-05-23T09:49:17.091855Z","shell.execute_reply":"2024-05-23T09:49:32.031476Z"},"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()\nnets = [net, net2, net3]\n# nets = [net, net3]\nmax_samples = 27\nthreshold = 0  # for identifying outliers\nsubmission = []","metadata":{"execution":{"iopub.status.busy":"2024-05-23T09:49:32.033887Z","iopub.execute_input":"2024-05-23T09:49:32.034187Z","iopub.status.idle":"2024-05-23T09:49:32.603017Z","shell.execute_reply.started":"2024-05-23T09:49:32.034162Z","shell.execute_reply":"2024-05-23T09:49:32.602201Z"},"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\"]]\n","metadata":{"execution":{"iopub.status.busy":"2024-05-23T09:49:53.583311Z","iopub.execute_input":"2024-05-23T09:49:53.584126Z","iopub.status.idle":"2024-05-23T09:51:07.165977Z","shell.execute_reply.started":"2024-05-23T09:49:53.584083Z","shell.execute_reply":"2024-05-23T09:51:07.164706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output.to_csv(\"submission.csv\", index=False)\nprint(output)\nprint(\"Your submission was successfully saved!\")","metadata":{"execution":{"iopub.status.busy":"2024-05-23T09:55:38.355551Z","iopub.execute_input":"2024-05-23T09:55:38.356223Z","iopub.status.idle":"2024-05-23T09:55:38.366322Z","shell.execute_reply.started":"2024-05-23T09:55:38.356182Z","shell.execute_reply":"2024-05-23T09:55:38.365267Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}