{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":14774,"databundleVersionId":875431,"sourceType":"competition"}],"dockerImageVersionId":31193,"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},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as T\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix\nimport timm\n\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(\"Using device:\", device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:10:53.432716Z","iopub.execute_input":"2025-12-13T09:10:53.433088Z","iopub.status.idle":"2025-12-13T09:10:53.521075Z","shell.execute_reply.started":"2025-12-13T09:10:53.433058Z","shell.execute_reply":"2025-12-13T09:10:53.520436Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATASET_DIR = \"/kaggle/input/aptos2019-blindness-detection\"\n\nCSV_PATH = DATASET_DIR + \"/train.csv\"\nIMG_DIR  = DATASET_DIR + \"/train_images\"\n\ndf = pd.read_csv(CSV_PATH)\ndf[\"id_code\"] = df[\"id_code\"].astype(str)\n\n# full path for each image\ndf[\"filepath\"] = df[\"id_code\"].apply(lambda x: f\"{IMG_DIR}/{x}.png\")\n\nprint(\"Total training images:\", len(df))\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:12:28.294938Z","iopub.execute_input":"2025-12-13T09:12:28.295438Z","iopub.status.idle":"2025-12-13T09:12:28.335628Z","shell.execute_reply.started":"2025-12-13T09:12:28.295416Z","shell.execute_reply":"2025-12-13T09:12:28.334794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def cvd_class(x):\n    x = int(x)\n    if x <= 1:  return 0  # low\n    elif x == 2: return 1  # medium\n    else: return 2  # high (3,4)\n\ndf[\"cvd_risk\"] = df[\"diagnosis\"].apply(cvd_class)\ndf[\"cvd_risk\"].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:13:13.914457Z","iopub.execute_input":"2025-12-13T09:13:13.914738Z","iopub.status.idle":"2025-12-13T09:13:13.928801Z","shell.execute_reply.started":"2025-12-13T09:13:13.914718Z","shell.execute_reply":"2025-12-13T09:13:13.928254Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df, val_df = train_test_split(\n    df,\n    test_size=0.2,\n    stratify=df[\"cvd_risk\"],\n    random_state=42\n)\n\nprint(\"Train size:\", len(train_df))\nprint(\"Val size:\", len(val_df))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:13:53.290044Z","iopub.execute_input":"2025-12-13T09:13:53.290463Z","iopub.status.idle":"2025-12-13T09:13:53.305621Z","shell.execute_reply.started":"2025-12-13T09:13:53.290440Z","shell.execute_reply":"2025-12-13T09:13:53.304750Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class APTOSDataset(Dataset):\n    def __init__(self, df, transform=None):\n        self.df = df\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        img = Image.open(row[\"filepath\"]).convert(\"RGB\")\n\n        if self.transform:\n            img = self.transform(img)\n\n        label = torch.tensor(int(row[\"cvd_risk\"]))\n        return img, label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:15:03.226942Z","iopub.execute_input":"2025-12-13T09:15:03.227309Z","iopub.status.idle":"2025-12-13T09:15:03.233433Z","shell.execute_reply.started":"2025-12-13T09:15:03.227287Z","shell.execute_reply":"2025-12-13T09:15:03.232590Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_size = 380   # EfficientNet-B4/B5 recommended (better accuracy)\n\ntrain_transform = T.Compose([\n    T.Resize((img_size, img_size)),\n    T.RandomResizedCrop(img_size, scale=(0.85, 1.0)),\n    T.RandomHorizontalFlip(),\n    T.RandomRotation(10),\n    T.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3),\n    T.ToTensor(),\n    T.Normalize(mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225]),\n])\n\nval_transform = T.Compose([\n    T.Resize((img_size, img_size)),\n    T.ToTensor(),\n    T.Normalize(mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225]),\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:16:18.994008Z","iopub.execute_input":"2025-12-13T09:16:18.994303Z","iopub.status.idle":"2025-12-13T09:16:18.999964Z","shell.execute_reply.started":"2025-12-13T09:16:18.994280Z","shell.execute_reply":"2025-12-13T09:16:18.999180Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_ds = APTOSDataset(train_df, transform=train_transform)\nval_ds   = APTOSDataset(val_df, transform=val_transform)\n\ntrain_loader = DataLoader(train_ds, batch_size=16, shuffle=True)\nval_loader = DataLoader(val_ds, batch_size=16)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:16:57.121515Z","iopub.execute_input":"2025-12-13T09:16:57.122316Z","iopub.status.idle":"2025-12-13T09:16:57.126103Z","shell.execute_reply.started":"2025-12-13T09:16:57.122287Z","shell.execute_reply":"2025-12-13T09:16:57.125459Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = timm.create_model(\"efficientnet_b3\", pretrained=True, num_classes=3)\nmodel.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:17:27.701132Z","iopub.execute_input":"2025-12-13T09:17:27.701748Z","iopub.status.idle":"2025-12-13T09:17:29.327318Z","shell.execute_reply.started":"2025-12-13T09:17:27.701724Z","shell.execute_reply":"2025-12-13T09:17:29.326690Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.utils.class_weight import compute_class_weight\n\nweights = compute_class_weight(\n    class_weight=\"balanced\",\n    classes=np.array([0,1,2]),\n    y=df[\"cvd_risk\"]\n)\n\nweights = torch.tensor(weights, dtype=torch.float).to(device)\n\ncriterion = nn.CrossEntropyLoss(weight=weights)\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:18:19.830905Z","iopub.execute_input":"2025-12-13T09:18:19.831165Z","iopub.status.idle":"2025-12-13T09:18:19.839537Z","shell.execute_reply.started":"2025-12-13T09:18:19.831149Z","shell.execute_reply":"2025-12-13T09:18:19.838954Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"epochs = 5\n\nfor epoch in range(epochs):\n    model.train()\n    total_loss = 0\n\n    for imgs, labels in train_loader:\n        imgs, labels = imgs.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n        preds = model(imgs)\n        loss = criterion(preds, labels)\n\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n\n    print(f\"Epoch {epoch+1}/{epochs} - Loss: {total_loss/len(train_loader):.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:31:45.288002Z","iopub.execute_input":"2025-12-13T09:31:45.288723Z","iopub.status.idle":"2025-12-13T10:08:57.026917Z","shell.execute_reply.started":"2025-12-13T09:31:45.288701Z","shell.execute_reply":"2025-12-13T10:08:57.026043Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(model.state_dict(), \"/kaggle/working/efficientnet_b3_aptos_cvd.pth\")\nprint(\"MODEL SAVED!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T10:09:17.301807Z","iopub.execute_input":"2025-12-13T10:09:17.302074Z","iopub.status.idle":"2025-12-13T10:09:17.397954Z","shell.execute_reply.started":"2025-12-13T10:09:17.302045Z","shell.execute_reply":"2025-12-13T10:09:17.397358Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.eval()\nall_preds, all_labels = [], []\n\nwith torch.no_grad():\n    for imgs, labels in val_loader:\n        imgs = imgs.to(device)\n        labels = labels.to(device)\n\n        preds = model(imgs)\n        preds = torch.argmax(preds, dim=1)\n\n        all_preds.extend(preds.cpu().numpy())\n        all_labels.extend(labels.cpu().numpy())\n\nall_preds = np.array(all_preds)\nall_labels = np.array(all_labels)\n\nacc = accuracy_score(all_labels, all_preds)\nprec = precision_score(all_labels, all_preds, average=\"weighted\")\nrec  = recall_score(all_labels, all_preds, average=\"weighted\")\nf1   = f1_score(all_labels, all_preds, average=\"weighted\")\ncm   = confusion_matrix(all_labels, all_preds)\n\nprint(\"Accuracy :\", acc)\nprint(\"Precision:\", prec)\nprint(\"Recall   :\", rec)\nprint(\"F1 Score :\", f1)\nprint(\"\\nConfusion Matrix:\\n\", cm)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T10:09:34.329286Z","iopub.execute_input":"2025-12-13T10:09:34.329520Z","iopub.status.idle":"2025-12-13T10:11:06.546865Z","shell.execute_reply.started":"2025-12-13T10:09:34.329504Z","shell.execute_reply":"2025-12-13T10:11:06.546085Z"}},"outputs":[],"execution_count":null}]}