{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":99552,"databundleVersionId":13851420,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":265188702,"sourceType":"kernelVersion"}],"dockerImageVersionId":31089,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport pandas as pd\nimport numpy as np\nimport cv2, nibabel as nib\nfrom torchvision.models import resnet18\n\n# match training architecture\ndef get_model():\n    model = resnet18(weights=None)   # don't download pretrained\n    model.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)\n    model.fc = nn.Linear(model.fc.in_features, 2)\n    return model\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = get_model().to(device)\n\n# load your trained weights\nmodel.load_state_dict(torch.load(\"/kaggle/input/notebook23cee6a84c/model.pth\", map_location=device))\nmodel.eval()\nprint(\"✅ Model loaded for inference\")\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-10-02T05:51:22.990456Z","iopub.execute_input":"2025-10-02T05:51:22.990702Z","iopub.status.idle":"2025-10-02T05:51:35.845428Z","shell.execute_reply.started":"2025-10-02T05:51:22.990679Z","shell.execute_reply":"2025-10-02T05:51:35.844312Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_scan_as_mip(uid, scan_dir=\"/kaggle/input/rsna-intracranial-aneurysm-detection/test\"):\n    scan_path = f\"{scan_dir}/{uid}.nii\"\n    scan = nib.load(scan_path).get_fdata()\n    scan = np.clip(scan, -1000, 2000)\n    scan = (scan - scan.min()) / (scan.max() - scan.min())\n    mip = np.max(scan, axis=2)\n    mip_resized = cv2.resize(mip, (224,224))\n    return mip_resized.astype(np.float32)\n\ndef predict_scan(uid, model, device):\n    img = load_scan_as_mip(uid)\n    tensor = torch.tensor(img[None,None,:,:], dtype=torch.float32).to(device)\n    with torch.no_grad():\n        output = torch.softmax(model(tensor), dim=1).cpu().numpy()[0]\n    return output[1]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-02T05:51:51.226059Z","iopub.execute_input":"2025-10-02T05:51:51.226484Z","iopub.status.idle":"2025-10-02T05:51:51.23707Z","shell.execute_reply.started":"2025-10-02T05:51:51.226451Z","shell.execute_reply":"2025-10-02T05:51:51.23578Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import kaggle_evaluation.rsna_inference_server\nimport shutil, os\nimport polars as pl\n\nID_COL = \"SeriesInstanceUID\"\nLABEL_COLS = [\n    \"Left Infraclinoid Internal Carotid Artery\",\n    \"Right Infraclinoid Internal Carotid Artery\",\n    \"Left Supraclinoid Internal Carotid Artery\",\n    \"Right Supraclinoid Internal Carotid Artery\",\n    \"Left Middle Cerebral Artery\",\n    \"Right Middle Cerebral Artery\",\n    \"Anterior Communicating Artery\",\n    \"Left Anterior Cerebral Artery\",\n    \"Right Anterior Cerebral Artery\",\n    \"Left Posterior Communicating Artery\",\n    \"Right Posterior Communicating Artery\",\n    \"Basilar Tip\",\n    \"Other Posterior Circulation\",\n    \"Aneurysm Present\",\n]\n\n# This is what Kaggle will call\ndef predict(series_path: str) -> pl.DataFrame:\n    \"\"\"Given a DICOM series folder, return predictions for all 15 labels.\"\"\"\n    series_id = os.path.basename(series_path)\n\n    # --- load scan, make mip ---\n    try:\n        img = load_scan_as_mip(series_id, scan_dir=series_path)   # adjust your load function to use dicoms\n        tensor = torch.tensor(img[None,None,:,:], dtype=torch.float32).to(device)\n        with torch.no_grad():\n            output = torch.softmax(model(tensor), dim=1).cpu().numpy()[0]\n        aneurysm_prob = float(output[1])\n    except Exception as e:\n        print(f\"Error with {series_id}: {e}\")\n        aneurysm_prob = 0.5\n\n    # replicate across all required columns\n    preds = [aneurysm_prob] * len(LABEL_COLS)\n\n    df = pl.DataFrame([[series_id] + preds], schema=[ID_COL, *LABEL_COLS])\n\n    # required cleanup step\n    shutil.rmtree(\"/kaggle/shared\", ignore_errors=True)\n\n    return df.drop(ID_COL)\n\n# launch inference server\ninference_server = kaggle_evaluation.rsna_inference_server.RSNAInferenceServer(predict)\n\nif os.getenv(\"KAGGLE_IS_COMPETITION_RERUN\"):\n    inference_server.serve()   # production (Kaggle test set)\nelse:\n    inference_server.run_local_gateway()   # local debug\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-02T05:52:24.266641Z","iopub.execute_input":"2025-10-02T05:52:24.267007Z","iopub.status.idle":"2025-10-02T05:52:24.310273Z","shell.execute_reply.started":"2025-10-02T05:52:24.26698Z","shell.execute_reply":"2025-10-02T05:52:24.308766Z"}},"outputs":[],"execution_count":null}]}