{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":52254,"databundleVersionId":9674523,"sourceType":"competition"}],"dockerImageVersionId":31012,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Full RSNA Abdominal Trauma Detection Notebook\nIncludes training, validation, real metrics, test image inference, and a knowledge graph.","metadata":{}},{"cell_type":"code","source":"# Environment Setup\nimport os, random, warnings\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn.model_selection import GroupKFold\nfrom sklearn.metrics import accuracy_score, f1_score, cohen_kappa_score, recall_score, precision_score, roc_auc_score\nfrom pathlib import Path\nimport pydicom\nwarnings.filterwarnings('ignore')\nDEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T03:43:51.020157Z","iopub.execute_input":"2025-05-04T03:43:51.020408Z","iopub.status.idle":"2025-05-04T03:44:00.209066Z","shell.execute_reply.started":"2025-05-04T03:43:51.020387Z","shell.execute_reply":"2025-05-04T03:44:00.20702Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Data Preparation\nDATA_ROOT = Path('/kaggle/input/rsna-2023-abdominal-trauma-detection')\nIMG_ROOT = DATA_ROOT / 'train_images'\nlabels_df = pd.read_csv(DATA_ROOT / 'train_2024.csv')\nrows = []\nfor p in IMG_ROOT.iterdir():\n    pid = int(p.name)\n    for s in p.iterdir():\n        rows.append({'patient_id': pid, 'series_id': int(s.name)})\ndf_series = pd.DataFrame(rows)\ntrain_df = labels_df.merge(df_series, on='patient_id', how='inner')\ntrain_df = train_df[train_df.apply(lambda r: (IMG_ROOT / str(r.patient_id) / str(r.series_id)).is_dir(), axis=1)].reset_index(drop=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T03:44:00.210729Z","iopub.execute_input":"2025-05-04T03:44:00.212128Z","iopub.status.idle":"2025-05-04T03:44:12.172572Z","shell.execute_reply.started":"2025-05-04T03:44:00.212073Z","shell.execute_reply":"2025-05-04T03:44:12.171562Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Dataset\nclass RSNASlices(Dataset):\n    def __init__(self, df, root, k=3):\n        self.df = df\n        self.root = root\n        self.k = k\n    def __len__(self): return len(self.df)\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        pid, sid = row.patient_id, row.series_id\n        path = self.root / str(pid) / str(sid)\n        files = sorted(path.glob('*.dcm'))\n        mid = len(files) // 2\n        imgs = [pydicom.dcmread(str(f)).pixel_array.astype(np.float32) for f in files[mid:mid+self.k]]\n        vol = np.stack(imgs, axis=0)\n        vol = (vol - vol.mean()) / (vol.std() + 1e-5)\n        vol = vol[:, :512, :512]  # Crop to match expected shape\n        padded = np.zeros((3, 512, 512), dtype=np.float32)\n        padded[:vol.shape[0], :vol.shape[1], :vol.shape[2]] = vol\n        label = row.iloc[2:12].values.astype(np.float32)\n        return torch.tensor(padded), torch.tensor(label), pid","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T03:44:12.174578Z","iopub.execute_input":"2025-05-04T03:44:12.175632Z","iopub.status.idle":"2025-05-04T03:44:12.183294Z","shell.execute_reply.started":"2025-05-04T03:44:12.175592Z","shell.execute_reply":"2025-05-04T03:44:12.182369Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Model\nclass TraumaCNN(nn.Module):\n    def __init__(self, in_channels=3, num_classes=10):\n        super().__init__()\n        self.conv = nn.Sequential(\n            nn.Conv2d(in_channels, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),\n            nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2)\n        )\n        self.fc = nn.Sequential(\n            nn.Flatten(),\n            nn.Linear(64 * 128 * 128, 128), nn.ReLU(),\n            nn.Linear(128, num_classes)\n        )\n    def forward(self, x): return self.fc(self.conv(x))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T03:44:12.184069Z","iopub.execute_input":"2025-05-04T03:44:12.184671Z","iopub.status.idle":"2025-05-04T03:44:12.216266Z","shell.execute_reply.started":"2025-05-04T03:44:12.184637Z","shell.execute_reply":"2025-05-04T03:44:12.215127Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training + Metrics\ngkf = GroupKFold(n_splits=3)\ntrain_accs, val_accs = [], []\nmodel = TraumaCNN().to(DEVICE)\nfor fold, (tr_idx, va_idx) in enumerate(gkf.split(train_df, groups=train_df.patient_id)):\n    tr_dl = DataLoader(RSNASlices(train_df.iloc[tr_idx], IMG_ROOT), batch_size=4)\n    va_dl = DataLoader(RSNASlices(train_df.iloc[va_idx], IMG_ROOT), batch_size=4)\n    optim = torch.optim.Adam(model.parameters(), lr=1e-4)\n    model.train()\n    for x, y, _ in tr_dl:\n        x, y = x.to(DEVICE), y.to(DEVICE)\n        out = model(x)\n        loss = F.binary_cross_entropy_with_logits(out, y)\n        optim.zero_grad(); loss.backward(); optim.step()\n    model.eval(); all_preds, all_labels = [], []\n    with torch.no_grad():\n        for x, y, _ in va_dl:\n            x, y = x.to(DEVICE), y.to(DEVICE)\n            out = torch.sigmoid(model(x)).cpu(); all_preds.append(out); all_labels.append(y.cpu())\n    pred = torch.cat(all_preds); true = torch.cat(all_labels)\n    acc = accuracy_score(true > 0.5, pred > 0.5)\n    val_accs.append(acc); print(f'Fold {fold} Val Accuracy: {acc:.4f}')\nval_accuracy_mean = np.mean(val_accs); val_accuracy_std = np.std(val_accs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T03:44:12.217331Z","iopub.execute_input":"2025-05-04T03:44:12.21821Z","iopub.status.idle":"2025-05-04T06:23:05.716208Z","shell.execute_reply.started":"2025-05-04T03:44:12.218176Z","shell.execute_reply":"2025-05-04T06:23:05.715092Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Inference on test image\ndef predict_dicom(model, dicom_path):\n    ds = pydicom.dcmread(dicom_path)\n    img = ds.pixel_array.astype(np.float32)\n    img = (img - img.mean()) / (img.std() + 1e-5)\n    img = np.stack([img]*3, axis=0)\n    padded = np.zeros((3,512,512)); padded[:,:img.shape[1],:img.shape[2]] = img[:,:512,:512]\n    input_tensor = torch.tensor(padded).unsqueeze(0).float()\n    model.eval()\n    with torch.no_grad():\n        return torch.sigmoid(model(input_tensor.to(DEVICE))).cpu().numpy()\npred = predict_dicom(model, '/kaggle/input/rsna-2023-abdominal-trauma-detection/test_images/48843/62825/30.dcm')\nprint('Prediction:', pred)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T06:23:05.717869Z","iopub.execute_input":"2025-05-04T06:23:05.718583Z","iopub.status.idle":"2025-05-04T06:23:05.873887Z","shell.execute_reply.started":"2025-05-04T06:23:05.718553Z","shell.execute_reply":"2025-05-04T06:23:05.872896Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Knowledge Graph\nimport networkx as nx\nG = nx.DiGraph(); G.add_node('Model')\nmetrics = {'val_accuracy_mean': val_accuracy_mean, 'val_accuracy_std': val_accuracy_std}\nfor k, v in metrics.items(): G.add_node(k); G.add_edge('Model', k)\npos = nx.spring_layout(G, seed=42)\nplt.figure(figsize=(10,7))\nnx.draw_networkx_nodes(G, pos, node_color='lightblue', node_size=2000)\nnx.draw_networkx_edges(G, pos, arrows=True)\nnx.draw_networkx_labels(G, pos, labels={k: f'{k}\n{v:.3f}' if k in metrics else k for k in G.nodes})\nplt.title('Model Metrics Knowledge Graph'); plt.axis('off'); plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T12:53:54.348212Z","iopub.execute_input":"2025-05-04T12:53:54.348579Z","iopub.status.idle":"2025-05-04T12:53:54.356125Z","shell.execute_reply.started":"2025-05-04T12:53:54.348555Z","shell.execute_reply":"2025-05-04T12:53:54.354883Z"}},"outputs":[],"execution_count":null}]}