{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceType":"competition","sourceId":18647,"databundleVersionId":1126921}],"dockerImageVersionId":31259,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"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)\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\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:51:49.93569Z","iopub.execute_input":"2026-04-14T11:51:49.936372Z","iopub.status.idle":"2026-04-14T11:52:34.521775Z","shell.execute_reply.started":"2026-04-14T11:51:49.936338Z","shell.execute_reply":"2026-04-14T11:52:34.520759Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install einops timm openslide-python\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:53:10.847241Z","iopub.execute_input":"2026-04-14T11:53:10.847672Z","iopub.status.idle":"2026-04-14T11:53:15.403269Z","shell.execute_reply.started":"2026-04-14T11:53:10.847646Z","shell.execute_reply":"2026-04-14T11:53:15.40253Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!git clone https://github.com/mahmoodlab/HIPT.git\n%cd HIPT\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:53:19.614887Z","iopub.execute_input":"2026-04-14T11:53:19.615344Z","iopub.status.idle":"2026-04-14T11:53:56.780638Z","shell.execute_reply.started":"2026-04-14T11:53:19.61531Z","shell.execute_reply":"2026-04-14T11:53:56.779874Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%cd HIPT\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:55:57.189577Z","iopub.execute_input":"2026-04-14T11:55:57.189907Z","iopub.status.idle":"2026-04-14T11:55:57.195498Z","shell.execute_reply.started":"2026-04-14T11:55:57.189878Z","shell.execute_reply":"2026-04-14T11:55:57.194718Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ls","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:56:02.665567Z","iopub.execute_input":"2026-04-14T11:56:02.666116Z","iopub.status.idle":"2026-04-14T11:56:02.787977Z","shell.execute_reply.started":"2026-04-14T11:56:02.666086Z","shell.execute_reply":"2026-04-14T11:56:02.786972Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mkdir checkpoints\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:56:09.225945Z","iopub.execute_input":"2026-04-14T11:56:09.226715Z","iopub.status.idle":"2026-04-14T11:56:09.344431Z","shell.execute_reply.started":"2026-04-14T11:56:09.226681Z","shell.execute_reply":"2026-04-14T11:56:09.343662Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install timm einops\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:56:11.780246Z","iopub.execute_input":"2026-04-14T11:56:11.781064Z","iopub.status.idle":"2026-04-14T11:56:15.139059Z","shell.execute_reply.started":"2026-04-14T11:56:11.781031Z","shell.execute_reply":"2026-04-14T11:56:15.137989Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls -lh checkpoints\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:56:19.721716Z","iopub.execute_input":"2026-04-14T11:56:19.722526Z","iopub.status.idle":"2026-04-14T11:56:19.841874Z","shell.execute_reply.started":"2026-04-14T11:56:19.722491Z","shell.execute_reply":"2026-04-14T11:56:19.841214Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%cd /kaggle/working/HIPT\n!mkdir -p checkpoints\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:56:22.667139Z","iopub.execute_input":"2026-04-14T11:56:22.667412Z","iopub.status.idle":"2026-04-14T11:56:22.787362Z","shell.execute_reply.started":"2026-04-14T11:56:22.667385Z","shell.execute_reply":"2026-04-14T11:56:22.786622Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import requests, re\nurl = \"https://api.github.com/repos/mahmoodlab/HIPT/releases\"\ndata = requests.get(url).json()\nprint(\"Total releases:\", len(data))\nfor r in data[:3]:\n    print(\"\\nRelease:\", r.get(\"tag_name\"))\n    for a in r.get(\"assets\", []):\n        print(\"  -\", a.get(\"name\"))\n        ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:56:25.840617Z","iopub.execute_input":"2026-04-14T11:56:25.841625Z","iopub.status.idle":"2026-04-14T11:56:26.120896Z","shell.execute_reply.started":"2026-04-14T11:56:25.841578Z","shell.execute_reply":"2026-04-14T11:56:26.120242Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch, timm\nfrom einops import rearrange\n\ndevice = \"cpu\"\n\nvit256 = timm.create_model(\"vit_small_patch16_224\", pretrained=True, num_classes=0).to(device).eval()\nprint(\"Loaded patch encoder\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:56:28.689597Z","iopub.execute_input":"2026-04-14T11:56:28.690138Z","iopub.status.idle":"2026-04-14T11:56:42.598444Z","shell.execute_reply.started":"2026-04-14T11:56:28.690107Z","shell.execute_reply":"2026-04-14T11:56:42.597563Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Load the patch encoder","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:35:14.061055Z","iopub.execute_input":"2026-01-31T22:35:14.061362Z","iopub.status.idle":"2026-01-31T22:35:14.064676Z","shell.execute_reply.started":"2026-01-31T22:35:14.061337Z","shell.execute_reply":"2026-01-31T22:35:14.064145Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch, timm\nfrom einops import rearrange\n\ndevice = \"cuda\"\n\nvit256 = timm.create_model(\n    \"vit_small_patch16_224\",\n    pretrained=True,\n    num_classes=0\n).to(device).eval()\n\nprint(\"Patch encoder ready on GPU\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:57:12.996343Z","iopub.execute_input":"2026-04-14T11:57:12.997087Z","iopub.status.idle":"2026-04-14T11:57:13.444267Z","shell.execute_reply.started":"2026-04-14T11:57:12.997058Z","shell.execute_reply":"2026-04-14T11:57:13.443325Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# from PIL import Image\n# import matplotlib.pyplot as plt\n\n# img_path = \"/kaggle/input/breast-histopathology-image/10253_idx5_x601_y651_class1.png\"\n\n# img = Image.open(img_path).convert(\"RGB\")\n# plt.imshow(img)\n# plt.axis(\"off\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:35:19.90324Z","iopub.execute_input":"2026-01-31T22:35:19.903535Z","iopub.status.idle":"2026-01-31T22:35:20.014077Z","shell.execute_reply.started":"2026-01-31T22:35:19.903512Z","shell.execute_reply":"2026-01-31T22:35:20.013502Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Preprocess for HIPT-style pipeline","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-27T13:19:01.426331Z","iopub.execute_input":"2026-01-27T13:19:01.426931Z","iopub.status.idle":"2026-01-27T13:19:01.430252Z","shell.execute_reply.started":"2026-01-27T13:19:01.426902Z","shell.execute_reply":"2026-01-27T13:19:01.429454Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import torchvision.transforms as T\n# import torch\n\n# device = \"cuda\"\n\n# # transform = T.Compose([\n#     T.Resize((512, 512)),\n#     T.ToTensor()\n# ])\n\n# x = transform(img).unsqueeze(0).to(device)  # [1, 3, 512, 512]\n# print(x.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:35:23.561457Z","iopub.execute_input":"2026-01-31T22:35:23.562219Z","iopub.status.idle":"2026-01-31T22:35:28.050969Z","shell.execute_reply.started":"2026-01-31T22:35:23.56219Z","shell.execute_reply":"2026-01-31T22:35:28.050349Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Extracting 256×256 patches (HIPT stage-1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-27T13:20:06.010311Z","iopub.execute_input":"2026-01-27T13:20:06.010586Z","iopub.status.idle":"2026-01-27T13:20:06.01408Z","shell.execute_reply.started":"2026-01-27T13:20:06.010564Z","shell.execute_reply":"2026-01-27T13:20:06.01318Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# from einops import rearrange\n\n# patches = x.unfold(2, 256, 256).unfold(3, 256, 256)\n# patches = rearrange(patches, 'b c p1 p2 w h -> (b p1 p2) c w h')\n\n# print(\"Total patches:\", patches.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:35:31.638631Z","iopub.execute_input":"2026-01-31T22:35:31.639327Z","iopub.status.idle":"2026-01-31T22:35:31.717493Z","shell.execute_reply.started":"2026-01-31T22:35:31.639298Z","shell.execute_reply":"2026-01-31T22:35:31.716867Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Loading ViT patch encoder (GPU)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-27T13:20:30.54558Z","iopub.execute_input":"2026-01-27T13:20:30.545866Z","iopub.status.idle":"2026-01-27T13:20:30.549075Z","shell.execute_reply.started":"2026-01-27T13:20:30.545843Z","shell.execute_reply":"2026-01-27T13:20:30.54835Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import timm\n\n# vit256 = timm.create_model(\n#     \"vit_small_patch16_224\",\n#     pretrained=True,\n#     num_classes=0\n# ).to(device).eval()\n\n# print(\"ViT patch encoder loaded on GPU\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:35:35.262121Z","iopub.execute_input":"2026-01-31T22:35:35.262693Z","iopub.status.idle":"2026-01-31T22:35:42.690601Z","shell.execute_reply.started":"2026-01-31T22:35:35.262667Z","shell.execute_reply":"2026-01-31T22:35:42.689952Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Patch embeddings (core HIPT idea)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# patches_224 = torch.nn.functional.interpolate(patches, size=(224,224))\n\n# with torch.no_grad():\n#     patch_embeddings = vit256(patches_224)\n\n# print(\"Patch embeddings:\", patch_embeddings.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:43:38.773604Z","iopub.execute_input":"2026-01-31T22:43:38.773892Z","iopub.status.idle":"2026-01-31T22:43:38.78558Z","shell.execute_reply.started":"2026-01-31T22:43:38.773868Z","shell.execute_reply":"2026-01-31T22:43:38.785046Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# def group_patches_into_regions(patch_embeddings, patches_per_region=8):\n#     N, D = patch_embeddings.shape\n#     R = N // patches_per_region\n\n#     patch_embeddings = patch_embeddings[:R * patches_per_region]\n#     region_patches = patch_embeddings.view(R, patches_per_region, D)\n\n#     return region_patches\n    \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:43:44.366475Z","iopub.execute_input":"2026-01-31T22:43:44.367054Z","iopub.status.idle":"2026-01-31T22:43:44.371136Z","shell.execute_reply.started":"2026-01-31T22:43:44.36702Z","shell.execute_reply":"2026-01-31T22:43:44.370431Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# def region_aggregation(region_patches):\n#     return region_patches.mean(dim=1)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:36:02.977322Z","iopub.execute_input":"2026-01-31T22:36:02.978171Z","iopub.status.idle":"2026-01-31T22:36:02.98177Z","shell.execute_reply.started":"2026-01-31T22:36:02.978135Z","shell.execute_reply":"2026-01-31T22:36:02.981266Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# def slide_aggregation(region_embeddings):\n#     return region_embeddings.mean(dim=0, keepdim=True)\n    \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:36:06.356271Z","iopub.execute_input":"2026-01-31T22:36:06.356851Z","iopub.status.idle":"2026-01-31T22:36:06.360188Z","shell.execute_reply.started":"2026-01-31T22:36:06.356824Z","shell.execute_reply":"2026-01-31T22:36:06.359599Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# classifier = nn.Linear(384, 2).to(device)\n# logits = classifier(slide_embedding)\n# pred = torch.argmax(logits, dim=1)\n\n# print(\"Predicted class:\", pred.item())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:38:44.181455Z","iopub.execute_input":"2026-01-31T22:38:44.181758Z","iopub.status.idle":"2026-01-31T22:38:44.253395Z","shell.execute_reply.started":"2026-01-31T22:38:44.181732Z","shell.execute_reply":"2026-01-31T22:38:44.252781Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import torch.nn as nn\n\n# survival_head = nn.Linear(384, 1).to(device)\n# risk_score = survival_head(slide_embedding)\n\n# print(\"Predicted risk score:\", risk_score.item())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T22:38:21.296146Z","iopub.execute_input":"2026-01-31T22:38:21.296793Z","iopub.status.idle":"2026-01-31T22:38:21.321951Z","shell.execute_reply.started":"2026-01-31T22:38:21.296768Z","shell.execute_reply":"2026-01-31T22:38:21.32141Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Higher risk score indicates higher hazard and lower expected survival.","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Implemented these:-\n#Real histopathology image\n#Patch extraction (256×256)\n#Transformer-based patch embeddings\n#Region level representation \n#Slide-level representation\n#GPU acceleration (Tesla P100)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-27T13:23:35.331605Z","iopub.execute_input":"2026-01-27T13:23:35.331921Z","iopub.status.idle":"2026-01-27T13:23:35.335241Z","shell.execute_reply.started":"2026-01-27T13:23:35.331897Z","shell.execute_reply":"2026-01-27T13:23:35.334698Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Prostate cancer classification and survival rate prediction ","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_path = \"/kaggle/input/competitions/prostate-cancer-grade-assessment\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:58:29.493435Z","iopub.execute_input":"2026-04-14T11:58:29.494187Z","iopub.status.idle":"2026-04-14T11:58:29.498008Z","shell.execute_reply.started":"2026-04-14T11:58:29.494153Z","shell.execute_reply":"2026-04-14T11:58:29.497169Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nprint(os.listdir(\"/kaggle/input/competitions\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:58:32.620008Z","iopub.execute_input":"2026-04-14T11:58:32.62067Z","iopub.status.idle":"2026-04-14T11:58:32.624979Z","shell.execute_reply.started":"2026-04-14T11:58:32.620639Z","shell.execute_reply":"2026-04-14T11:58:32.624287Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_path = \"/kaggle/input/competitions/prostate-cancer-grade-assessment\"\nprint(os.listdir(base_path))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:58:34.810694Z","iopub.execute_input":"2026-04-14T11:58:34.811305Z","iopub.status.idle":"2026-04-14T11:58:34.817654Z","shell.execute_reply.started":"2026-04-14T11:58:34.811273Z","shell.execute_reply":"2026-04-14T11:58:34.816869Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ndf = pd.read_csv(base_path + \"/train.csv\")\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:58:37.14521Z","iopub.execute_input":"2026-04-14T11:58:37.145887Z","iopub.status.idle":"2026-04-14T11:58:37.217442Z","shell.execute_reply.started":"2026-04-14T11:58:37.145845Z","shell.execute_reply":"2026-04-14T11:58:37.216818Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_id = df.iloc[2][\"image_id\"]\nlabel = df.iloc[2][\"isup_grade\"]\n\nimg_path = base_path + \"/train_images/\" + image_id + \".tiff\"\n\nprint(\"Image ID:\", image_id)\nprint(\"True ISUP Grade:\", label)\nprint(\"Path:\", img_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:58:39.636232Z","iopub.execute_input":"2026-04-14T11:58:39.636794Z","iopub.status.idle":"2026-04-14T11:58:39.642335Z","shell.execute_reply.started":"2026-04-14T11:58:39.636766Z","shell.execute_reply":"2026-04-14T11:58:39.641382Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from PIL import Image\n\nimg = Image.open(img_path)\nimg = img.reduce(8)  # if memory issue, use 16\n\nimg","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:58:45.90013Z","iopub.execute_input":"2026-04-14T11:58:45.900949Z","iopub.status.idle":"2026-04-14T11:58:47.924948Z","shell.execute_reply.started":"2026-04-14T11:58:45.900904Z","shell.execute_reply":"2026-04-14T11:58:47.923785Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision import transforms\nimport torch\n\nimg_tensor = transforms.ToTensor()(img)\nC, H, W = img_tensor.shape\n\nprint(H, W)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:58:55.092564Z","iopub.execute_input":"2026-04-14T11:58:55.09313Z","iopub.status.idle":"2026-04-14T11:58:55.140532Z","shell.execute_reply.started":"2026-04-14T11:58:55.093098Z","shell.execute_reply":"2026-04-14T11:58:55.139756Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\ngray = img_tensor.mean(dim=0)\ntissue_mask = gray < 0.9  # white areas are near 1\n\nprint(\"Tissue pixels:\", tissue_mask.sum().item())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:58:56.996327Z","iopub.execute_input":"2026-04-14T11:58:56.996607Z","iopub.status.idle":"2026-04-14T11:58:57.02291Z","shell.execute_reply.started":"2026-04-14T11:58:56.996583Z","shell.execute_reply":"2026-04-14T11:58:57.022184Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\ndef simple_stain_normalization(img):\n    img_np = np.array(img)\n    \n    # normalize per channel\n    for i in range(3):\n        channel = img_np[:,:,i]\n        img_np[:,:,i] = (channel - channel.mean()) / (channel.std() + 1e-8)\n        img_np[:,:,i] = (img_np[:,:,i] - img_np[:,:,i].min()) / \\\n                        (img_np[:,:,i].max() - img_np[:,:,i].min())\n        img_np[:,:,i] *= 255\n    \n    return Image.fromarray(img_np.astype(np.uint8))\n\nnormalized_img = simple_stain_normalization(img)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:00.515767Z","iopub.execute_input":"2026-04-14T11:59:00.516906Z","iopub.status.idle":"2026-04-14T11:59:00.635358Z","shell.execute_reply.started":"2026-04-14T11:59:00.516865Z","shell.execute_reply":"2026-04-14T11:59:00.634661Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import random\n\ndef extract_tissue_patches(img_tensor, tissue_mask, patch_size=256, num_patches=16):\n    patches = []\n    C, H, W = img_tensor.shape\n    \n    attempts = 0\n    \n    while len(patches) < num_patches and attempts < 500:\n        top = random.randint(0, H - patch_size)\n        left = random.randint(0, W - patch_size)\n        \n        patch_mask = tissue_mask[top:top+patch_size, left:left+patch_size]\n        \n        if patch_mask.float().mean() > 0.5:  # at least 50% tissue\n            patch = img_tensor[:, top:top+patch_size, left:left+patch_size]\n            patches.append(patch)\n        \n        attempts += 1\n    \n    return torch.stack(patches)\n\npatches = extract_tissue_patches(img_tensor, tissue_mask)\n\nprint(patches.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:03.223134Z","iopub.execute_input":"2026-04-14T11:59:03.223399Z","iopub.status.idle":"2026-04-14T11:59:03.247403Z","shell.execute_reply.started":"2026-04-14T11:59:03.223378Z","shell.execute_reply":"2026-04-14T11:59:03.246785Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import timm\nimport torch.nn as nn\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nvit_model = timm.create_model(\n    \"vit_small_patch16_224\",\n    pretrained=True,\n    num_classes=0   # remove classifier head\n).to(device)\n\nvit_model.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:25.930112Z","iopub.execute_input":"2026-04-14T11:59:25.930884Z","iopub.status.idle":"2026-04-14T11:59:26.341788Z","shell.execute_reply.started":"2026-04-14T11:59:25.930853Z","shell.execute_reply":"2026-04-14T11:59:26.341151Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn.functional as F\n\npatches_resized = F.interpolate(patches, size=(224,224))\npatches_resized = patches_resized.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:32.154473Z","iopub.execute_input":"2026-04-14T11:59:32.155488Z","iopub.status.idle":"2026-04-14T11:59:32.172935Z","shell.execute_reply.started":"2026-04-14T11:59:32.155456Z","shell.execute_reply":"2026-04-14T11:59:32.171998Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with torch.no_grad():\n    patch_embeddings = vit_model(patches_resized)\n\nprint(patch_embeddings.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:34.417102Z","iopub.execute_input":"2026-04-14T11:59:34.417385Z","iopub.status.idle":"2026-04-14T11:59:35.126256Z","shell.execute_reply.started":"2026-04-14T11:59:34.417361Z","shell.execute_reply":"2026-04-14T11:59:35.125518Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with torch.no_grad():\n    patch_embeddings = vit_model(patches_resized)\n\nprint(patch_embeddings.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:37.116178Z","iopub.execute_input":"2026-04-14T11:59:37.116442Z","iopub.status.idle":"2026-04-14T11:59:37.128643Z","shell.execute_reply.started":"2026-04-14T11:59:37.11642Z","shell.execute_reply":"2026-04-14T11:59:37.127855Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"patch_embeddings = patch_embeddings.view(4, 4, 384)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:39.938622Z","iopub.execute_input":"2026-04-14T11:59:39.939234Z","iopub.status.idle":"2026-04-14T11:59:39.943186Z","shell.execute_reply.started":"2026-04-14T11:59:39.939205Z","shell.execute_reply":"2026-04-14T11:59:39.942342Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"region_embeddings = patch_embeddings.mean(dim=1)\n\nprint(region_embeddings.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:42.660122Z","iopub.execute_input":"2026-04-14T11:59:42.660709Z","iopub.status.idle":"2026-04-14T11:59:42.686851Z","shell.execute_reply.started":"2026-04-14T11:59:42.660681Z","shell.execute_reply":"2026-04-14T11:59:42.686271Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(patch_embeddings.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:44.844259Z","iopub.execute_input":"2026-04-14T11:59:44.844874Z","iopub.status.idle":"2026-04-14T11:59:44.849513Z","shell.execute_reply.started":"2026-04-14T11:59:44.844845Z","shell.execute_reply":"2026-04-14T11:59:44.848626Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"patch_embeddings = patch_embeddings.view(4, 4, 384)\nregion_embeddings = patch_embeddings.mean(dim=1)\n\nprint(region_embeddings.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:46.724274Z","iopub.execute_input":"2026-04-14T11:59:46.724614Z","iopub.status.idle":"2026-04-14T11:59:46.729598Z","shell.execute_reply.started":"2026-04-14T11:59:46.724587Z","shell.execute_reply":"2026-04-14T11:59:46.7289Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AttentionMIL(nn.Module):\n    def __init__(self, dim):\n        super().__init__()\n        self.attention = nn.Sequential(\n            nn.Linear(dim, 128),\n            nn.Tanh(),\n            nn.Linear(128, 1)\n        )\n\n    def forward(self, x):\n        # x shape: [num_regions, dim]\n        A = self.attention(x)          # [num_regions, 1]\n        A = torch.softmax(A, dim=0)    # attention weights\n        M = torch.sum(A * x, dim=0)    # weighted sum → [dim]\n        return M","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:50.995781Z","iopub.execute_input":"2026-04-14T11:59:50.996527Z","iopub.status.idle":"2026-04-14T11:59:51.001612Z","shell.execute_reply.started":"2026-04-14T11:59:50.996495Z","shell.execute_reply":"2026-04-14T11:59:51.000566Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mil_model = AttentionMIL(384).to(device)\n\nregion_embeddings = region_embeddings.to(device)\n\nprint(\"Before MIL:\", region_embeddings.shape)\n\nslide_embedding_mil = mil_model(region_embeddings)\n\nprint(\"After MIL:\", slide_embedding_mil.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:54.469365Z","iopub.execute_input":"2026-04-14T11:59:54.470026Z","iopub.status.idle":"2026-04-14T11:59:54.603771Z","shell.execute_reply.started":"2026-04-14T11:59:54.469984Z","shell.execute_reply":"2026-04-14T11:59:54.603125Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"slide_embedding_mean = region_embeddings.mean(dim=0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T11:59:57.33102Z","iopub.execute_input":"2026-04-14T11:59:57.331299Z","iopub.status.idle":"2026-04-14T11:59:57.335494Z","shell.execute_reply.started":"2026-04-14T11:59:57.331275Z","shell.execute_reply":"2026-04-14T11:59:57.334566Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"slide_embedding_mil = mil_model(region_embeddings)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:00:00.427409Z","iopub.execute_input":"2026-04-14T12:00:00.428094Z","iopub.status.idle":"2026-04-14T12:00:00.434702Z","shell.execute_reply.started":"2026-04-14T12:00:00.428062Z","shell.execute_reply":"2026-04-14T12:00:00.433904Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"classifier = nn.Linear(384, 6).to(device)\n\nlogits_mean = classifier(slide_embedding_mean.unsqueeze(0))\npred_mean = torch.argmax(logits_mean, dim=1)\n\nlogits_mil = classifier(slide_embedding_mil.unsqueeze(0))\npred_mil = torch.argmax(logits_mil, dim=1)\n\nprint(\"Mean pooling ISUP:\", pred_mean.item())\nprint(\"MIL ISUP:\", pred_mil.item())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:00:04.244741Z","iopub.execute_input":"2026-04-14T12:00:04.24553Z","iopub.status.idle":"2026-04-14T12:00:04.274287Z","shell.execute_reply.started":"2026-04-14T12:00:04.245495Z","shell.execute_reply":"2026-04-14T12:00:04.273669Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}