{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":45867,"databundleVersionId":6924515,"sourceType":"competition"},{"sourceId":847338,"sourceType":"datasetVersion","datasetId":255488},{"sourceId":6844262,"sourceType":"datasetVersion","datasetId":3934666},{"sourceId":6979608,"sourceType":"datasetVersion","datasetId":4009169},{"sourceId":7120688,"sourceType":"datasetVersion","datasetId":4107067},{"sourceId":7269372,"sourceType":"datasetVersion","datasetId":3931100,"isSourceIdPinned":true},{"sourceId":7269376,"sourceType":"datasetVersion","datasetId":3939049,"isSourceIdPinned":true}],"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Lunit + Attention MIL Inference for Ovarian Cancer","metadata":{}},{"cell_type":"code","source":"import os\nif os.path.isdir('/kaggle/input'):\n    !cp /kaggle/input/library-fastkaggle/fastkaggle-0.0.8-py3-none-any.whl /kaggle/working \n    !pip install  /kaggle/working/fastkaggle-0.0.8-py3-none-any.whl -q\nfrom fastkaggle import setup_comp, iskaggle\n","metadata":{"tags":[],"execution":{"iopub.status.busy":"2024-02-28T11:29:05.622063Z","iopub.execute_input":"2024-02-28T11:29:05.622904Z","iopub.status.idle":"2024-02-28T11:29:19.089672Z","shell.execute_reply.started":"2024-02-28T11:29:05.622868Z","shell.execute_reply":"2024-02-28T11:29:19.088775Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if iskaggle:\n    # !yes | sudo dpkg -i /kaggle/input/libvips-pyvips-installation-and-getting-started/libvips/*.deb\n    # !pip install /kaggle/input/libvips-pyvips-installation-and-getting-started/pyvips/pyvips-2.2.1-py2.py3-none-any.whl --no-index --find-links /kaggle/input/libvips-pyvips-installation-and-getting-started/pyvips\n    # !pip install /kaggle/input/library-large-image/large_image-1.26.0-py3-none-any.whl --no-index --find-links /kaggle/input/library-large-image/large_image\n    # !pip install /kaggle/input/library-large-image-source-vips/large_image_source_vips-1.26.0-py3-none-any.whl --no-index --find-links /kaggle/input/library-large-image-source-vips\n    !pip install /kaggle/input/library-histomicstk/wheelhouse/histomicstk-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl --no-index --find-links /kaggle/input/library-histomicstk/wheelhouse -q","metadata":{"tags":[],"execution":{"iopub.status.busy":"2024-02-28T11:29:19.091643Z","iopub.execute_input":"2024-02-28T11:29:19.092111Z","iopub.status.idle":"2024-02-28T11:29:33.08555Z","shell.execute_reply.started":"2024-02-28T11:29:19.092083Z","shell.execute_reply":"2024-02-28T11:29:33.084289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# make source_vips accept PNGs\n# !sed -i \"/source_vips_ignored_names/{N;s/png|//}\" /opt/conda/lib/python3.10/site-packages/large_image_source_vips/__init__.py\n# !cat /opt/conda/lib/python3.10/site-packages/large_image_source_vips/__init__.py","metadata":{"execution":{"iopub.status.busy":"2024-02-28T11:29:33.087136Z","iopub.execute_input":"2024-02-28T11:29:33.087468Z","iopub.status.idle":"2024-02-28T11:29:33.091905Z","shell.execute_reply.started":"2024-02-28T11:29:33.087439Z","shell.execute_reply":"2024-02-28T11:29:33.090985Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"comp_slug = 'UBC-OCEAN'\ncomp_path = setup_comp(comp_slug)\ncomp_path","metadata":{"tags":[],"execution":{"iopub.status.busy":"2024-02-28T11:29:33.092959Z","iopub.execute_input":"2024-02-28T11:29:33.09319Z","iopub.status.idle":"2024-02-28T11:29:33.112062Z","shell.execute_reply.started":"2024-02-28T11:29:33.09317Z","shell.execute_reply":"2024-02-28T11:29:33.111131Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport sys\nimport re\nfrom pathlib import Path\nimport time\n# import psutil\nimport gc\nimport ctypes\nimport pandas as pd\nimport numpy as np\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\n\nimport torch\nimport torch.nn.functional as F","metadata":{"tags":[],"execution":{"iopub.status.busy":"2024-02-28T11:29:33.115267Z","iopub.execute_input":"2024-02-28T11:29:33.115663Z","iopub.status.idle":"2024-02-28T11:29:35.178484Z","shell.execute_reply.started":"2024-02-28T11:29:33.115639Z","shell.execute_reply":"2024-02-28T11:29:35.177688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.environ['VIPS_CONCURRENCY'] = '4'\nos.environ['VIPS_DISC_THRESHOLD'] = '15gb'","metadata":{"execution":{"iopub.status.busy":"2024-02-28T11:29:35.179459Z","iopub.execute_input":"2024-02-28T11:29:35.179829Z","iopub.status.idle":"2024-02-28T11:29:35.184284Z","shell.execute_reply.started":"2024-02-28T11:29:35.179804Z","shell.execute_reply":"2024-02-28T11:29:35.183319Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Make Juptyter allow multi-processing in the data loader\n# also seems to save memory\nfrom multiprocessing import set_start_method\ntry:\n    set_start_method('spawn')\nexcept RuntimeError as ex:\n    print(ex)","metadata":{"execution":{"iopub.status.busy":"2024-02-28T11:29:35.185444Z","iopub.execute_input":"2024-02-28T11:29:35.185811Z","iopub.status.idle":"2024-02-28T11:29:35.197429Z","shell.execute_reply.started":"2024-02-28T11:29:35.185745Z","shell.execute_reply":"2024-02-28T11:29:35.196567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.set_num_threads(4)\n\nif iskaggle:\n    clam_path = '/kaggle/input/clam-for-ovarian-cancer'    \nelse:\n    clam_path = '../clam'\nsys.path.append(clam_path)\n\nfrom CLAM.extract_png_features import extract_png_features\nfrom CLAM.utils.eval_utils import initiate_model","metadata":{"tags":[],"execution":{"iopub.status.busy":"2024-02-28T11:29:35.198438Z","iopub.execute_input":"2024-02-28T11:29:35.198687Z","iopub.status.idle":"2024-02-28T11:29:38.929375Z","shell.execute_reply.started":"2024-02-28T11:29:35.198665Z","shell.execute_reply":"2024-02-28T11:29:38.928568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if iskaggle:\n    # Kaggle Submission\n    if len(os.listdir(comp_path/'test_images')) != 1:\n        is_submission = True\n        test_meta = pd.read_csv(comp_path/'test.csv')\n        train_test = 'test'\n        test_folder = comp_path/f'test_images'\n    # Kaggle Test Run\n    else:\n        is_submission = False\n        train_test = 'train'\n        test_meta = pd.read_csv(comp_path/f'{train_test}.csv')\n        # test_meta = test_meta[test_meta['image_id'].isin([39728, 39872, 39880, 29084, 44232, 34247, 42125, 5264])]\n        #test_meta = test_meta[test_meta['image_id'].isin([45630, 36678, 8713, 14424])] # four largest images\n        test_meta = test_meta.sample(5)\n        test_folder = comp_path/f'{train_test}_images'\n    project_root = Path('/tmp')\n    ckpt_folder = Path('/kaggle/input/trained-clam-for-ovarian-cancer')\n    # model_path = '/kaggle/input/pytorch-pretrained-models/resnet50-19c8e357.pth'\n    model_path = '/kaggle/input/lunit-dino-weights/dino_vit_small_patch16_ep200.torch'\nelse:\n    # Local Run\n    project_root = Path('test_working')\n    working_dir = Path('test_working')\n    ckpt_folder = Path('resnet50/results')\n    model_path = 'resnet50-19c8e357.pth'\n    test_folder = comp_path/'test_images'\n\n    tma_test = pd.read_csv(comp_path/'train.csv')\n    tma_test = tma_test[tma_test['image_id'].isin([13568, 17637, 21020, 29084, 31594, 4134, 51346, 8280, 91, 9200])]\n    test_meta = pd.concat([\n        tma_test[['image_id', 'image_width', 'image_height']]\n    ])\n\n\nfile_sizes = []\nformatted_sizes = []\nfor image_id in test_meta['image_id']:\n    size = os.path.getsize(test_folder/f'{image_id}.png')\n    file_sizes.append(size)\n    formatted_sizes.append(f\"{size / 1024**3:.2f} GB\")\ntest_meta['file_gb'] = np.array(file_sizes) / 1024 **3\ntest_meta['formatted_file_size'] = formatted_sizes\ntest_meta['n_mega_pixels'] = (test_meta['image_width'] * test_meta['image_height'] // 1e6).astype(int)\ntma_megapixel_threshold = 50\nn_classes = 6","metadata":{"tags":[],"execution":{"iopub.status.busy":"2024-02-28T11:34:06.472824Z","iopub.execute_input":"2024-02-28T11:34:06.473193Z","iopub.status.idle":"2024-02-28T11:34:06.511669Z","shell.execute_reply.started":"2024-02-28T11:34:06.473166Z","shell.execute_reply":"2024-02-28T11:34:06.510709Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_meta","metadata":{"tags":[],"execution":{"iopub.status.busy":"2024-02-28T11:34:11.133663Z","iopub.execute_input":"2024-02-28T11:34:11.134518Z","iopub.status.idle":"2024-02-28T11:34:11.146657Z","shell.execute_reply.started":"2024-02-28T11:34:11.134486Z","shell.execute_reply":"2024-02-28T11:34:11.145688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# def print_memory():\n#     ram_info = psutil.virtual_memory()\n#     print(f\"Available: {ram_info.available / 1024 / 1024 / 1024:.2f} GB\")","metadata":{"execution":{"iopub.status.busy":"2024-02-28T11:34:12.696125Z","iopub.execute_input":"2024-02-28T11:34:12.696902Z","iopub.status.idle":"2024-02-28T11:34:12.700969Z","shell.execute_reply.started":"2024-02-28T11:34:12.696868Z","shell.execute_reply":"2024-02-28T11:34:12.699918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = 'lunit_dino_16'\nif model == 'resnet50':\n    tile_size = 256\n    batch_size = 1024\nelif model == 'kimia':\n    tile_size = 1000\n    batch_size = 128\nelif model == 'swin_v2_base':\n    tile_size = 384\n    batch_size = 64\nelif model in ['lunit_dino_16']:\n    tile_size = 224\n    batch_size = 2048\n    \nstart = time.time()\nextract_png_features(test_meta,\n                     comp_path,\n                     project_root,\n                     train_or_test=train_test,\n                     tma_megapixel_threshold=tma_megapixel_threshold,\n                     model=model,\n                     model_path=model_path,\n                     use_fp16=True,\n                     num_workers=4,\n                     prefetch_factor=1,\n                     tile_size=tile_size,\n                     batch_size=batch_size,\n                     print_every_batches=10,\n                     tissue_threshold=0.05,\n                     tumor_threshold=0.05,\n                     gc_after_batch=True,\n                     print_memory=True)\nprint(f'Finished in {(time.time()-start) // 60:.0f} min {(time.time()-start) % 60:.1f} s')","metadata":{"execution":{"iopub.status.busy":"2024-02-28T11:34:13.036987Z","iopub.execute_input":"2024-02-28T11:34:13.037664Z","iopub.status.idle":"2024-02-28T11:37:16.454707Z","shell.execute_reply.started":"2024-02-28T11:34:13.037633Z","shell.execute_reply":"2024-02-28T11:37:16.45374Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load Model Checkpoints","metadata":{"tags":[]}},{"cell_type":"code","source":"labels = pd.read_csv(ckpt_folder/'label_mapping.csv', header=None)\nlabels.columns=['label', 'idx']\nlabels","metadata":{"execution":{"iopub.status.busy":"2024-02-28T11:37:16.456415Z","iopub.execute_input":"2024-02-28T11:37:16.456716Z","iopub.status.idle":"2024-02-28T11:37:16.470232Z","shell.execute_reply.started":"2024-02-28T11:37:16.456691Z","shell.execute_reply":"2024-02-28T11:37:16.469266Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_size='big'\ndrop_out=0.65\nuse_inst_predictions=False\n\nre_checkpoint = re.compile(r's_\\d+_checkpoint.pt')\nckpt_files = [path for path in os.listdir(ckpt_folder) if re_checkpoint.match(path)]\nlabel_dict = {row['label']: row['idx'] for i, row in labels.iterrows()}\nmodels = [initiate_model(label_dict, \n                         'clam_sb', \n                         os.path.join(ckpt_folder, ckpt_file),\n                         model_size=model_size,\n                         drop_out=drop_out,\n                         feature_dim=384,\n                         use_inst_predictions=use_inst_predictions) for ckpt_file in ckpt_files]","metadata":{"tags":[],"execution":{"iopub.status.busy":"2024-02-28T11:37:16.471514Z","iopub.execute_input":"2024-02-28T11:37:16.471873Z","iopub.status.idle":"2024-02-28T11:37:17.006183Z","shell.execute_reply.started":"2024-02-28T11:37:16.471842Z","shell.execute_reply":"2024-02-28T11:37:17.005168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"bag_weight = 0.7\nuse_inst_predictions = False\n\ndefault_prediction = 'HGSC'\npredictions = {}\n\nnot_found_count = 0\nfor i, row in test_meta.iterrows():\n    image_id = row['image_id']\n    is_tma = (row['n_mega_pixels'] <= 50)\n    feature_path = project_root/'features'/f'{image_id}.pt'\n    try:\n        features = torch.load(feature_path, map_location='cuda')\n    except FileNotFoundError:\n        not_found_count += 1\n        continue\n\n    probs = []\n    for model in models:\n        model.eval()\n        with torch.no_grad():\n            result = model(features, bag_weight, is_tma)[0]\n        probs.append(F.softmax(result, dim=1).cpu().numpy())\n    model_avg = np.array(probs).mean(axis=0)\n\n    predictions[image_id] = labels['label'].iloc[model_avg.argmax()]","metadata":{"tags":[],"execution":{"iopub.status.busy":"2024-02-28T11:39:04.341031Z","iopub.execute_input":"2024-02-28T11:39:04.341396Z","iopub.status.idle":"2024-02-28T11:39:05.188129Z","shell.execute_reply.started":"2024-02-28T11:39:04.341365Z","shell.execute_reply":"2024-02-28T11:39:05.187087Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions = pd.DataFrame(predictions.items(), columns=['image_id', 'label'])\nif not_found_count > 0:\n    print(f'Could not find {not_found_count} feature files.')","metadata":{"execution":{"iopub.status.busy":"2024-02-28T11:39:05.809704Z","iopub.execute_input":"2024-02-28T11:39:05.810685Z","iopub.status.idle":"2024-02-28T11:39:05.816087Z","shell.execute_reply.started":"2024-02-28T11:39:05.810651Z","shell.execute_reply":"2024-02-28T11:39:05.814919Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Replacing {predictions['label'].isnull().sum()} null labels\")\npredictions['label'].fillna(default_prediction, inplace=True)\nprint(f\"Replacing {(~(predictions['label'].isin(labels['label']))).sum()} invalid labels\")\npredictions[~predictions['label'].isin(labels['label'])] = default_prediction\nprint(f\"Fill default prediction for {(~test_meta['image_id'].isin(predictions['image_id'])).sum()} misisng image_ids.\")\nmissing_ids = test_meta[~test_meta['image_id'].isin(predictions['image_id'])][['image_id']]\nmissing_ids['label'] = default_prediction\npredictions = pd.concat([predictions, missing_ids])\npredictions.sort_values('image_id').to_csv('/kaggle/working/submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2024-02-28T11:39:05.974068Z","iopub.execute_input":"2024-02-28T11:39:05.974367Z","iopub.status.idle":"2024-02-28T11:39:05.990013Z","shell.execute_reply.started":"2024-02-28T11:39:05.974343Z","shell.execute_reply":"2024-02-28T11:39:05.988803Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cat submission.csv","metadata":{"execution":{"iopub.status.busy":"2024-02-28T11:39:07.572753Z","iopub.execute_input":"2024-02-28T11:39:07.573138Z","iopub.status.idle":"2024-02-28T11:39:08.570877Z","shell.execute_reply.started":"2024-02-28T11:39:07.57311Z","shell.execute_reply":"2024-02-28T11:39:08.56964Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}