{"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":14774,"databundleVersionId":875431,"sourceType":"competition"}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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 transforms\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\nfrom sklearn.utils.class_weight import compute_class_weight\nimport timm\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(\"Using device:\", device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:28:36.171314Z","iopub.execute_input":"2025-12-13T12:28:36.171658Z","iopub.status.idle":"2025-12-13T12:28:36.178979Z","shell.execute_reply.started":"2025-12-13T12:28:36.171634Z","shell.execute_reply":"2025-12-13T12:28:36.177834Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATASET_DIR = \"/kaggle/input/aptos2019-blindness-detection\"\nCSV_PATH = os.path.join(DATASET_DIR, \"train.csv\")\nIMG_DIR  = os.path.join(DATASET_DIR, \"train_images\")\n\ndf = pd.read_csv(CSV_PATH)\ndf[\"id_code\"] = df[\"id_code\"].astype(str)\ndf[\"filepath\"] = df[\"id_code\"].apply(lambda x: f\"{IMG_DIR}/{x}.png\")\n\nprint(\"Total images:\", len(df))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:29:23.349399Z","iopub.execute_input":"2025-12-13T12:29:23.349719Z","iopub.status.idle":"2025-12-13T12:29:23.393570Z","shell.execute_reply.started":"2025-12-13T12:29:23.349693Z","shell.execute_reply":"2025-12-13T12:29:23.392389Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def cvd_class(x):\n    if x <= 1:\n        return 0   # Low\n    elif x == 2:\n        return 1   # Medium\n    else:\n        return 2   # High\n\ndf[\"cvd_risk\"] = df[\"diagnosis\"].apply(cvd_class)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:29:53.428913Z","iopub.execute_input":"2025-12-13T12:29:53.429254Z","iopub.status.idle":"2025-12-13T12:29:53.437575Z","shell.execute_reply.started":"2025-12-13T12:29:53.429228Z","shell.execute_reply":"2025-12-13T12:29:53.436382Z"}},"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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:30:26.457317Z","iopub.execute_input":"2025-12-13T12:30:26.457640Z","iopub.status.idle":"2025-12-13T12:30:26.467300Z","shell.execute_reply.started":"2025-12-13T12:30:26.457614Z","shell.execute_reply":"2025-12-13T12:30:26.466425Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class APTOSDataset(Dataset):\n    def __init__(self, dataframe, transform=None):\n        self.df = dataframe.reset_index(drop=True)\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        img = Image.open(self.df.loc[idx, \"filepath\"]).convert(\"RGB\")\n        label = int(self.df.loc[idx, \"cvd_risk\"])\n\n        if self.transform:\n            img = self.transform(img)\n\n        return img, torch.tensor(label, dtype=torch.long)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:30:55.854517Z","iopub.execute_input":"2025-12-13T12:30:55.854890Z","iopub.status.idle":"2025-12-13T12:30:55.861260Z","shell.execute_reply.started":"2025-12-13T12:30:55.854860Z","shell.execute_reply":"2025-12-13T12:30:55.860429Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_size = 240   # EfficientNet-B1\n\ntrain_transform = transforms.Compose([\n    transforms.Resize((img_size, img_size)),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(10),\n    transforms.ColorJitter(0.3, 0.3, 0.3),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485,0.456,0.406],\n                         [0.229,0.224,0.225])\n])\n\nval_transform = transforms.Compose([\n    transforms.Resize((img_size, img_size)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485,0.456,0.406],\n                         [0.229,0.224,0.225])\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:31:35.963067Z","iopub.execute_input":"2025-12-13T12:31:35.963428Z","iopub.status.idle":"2025-12-13T12:31:35.969458Z","shell.execute_reply.started":"2025-12-13T12:31:35.963400Z","shell.execute_reply":"2025-12-13T12:31:35.968490Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dataset = APTOSDataset(train_df, train_transform)\nval_dataset   = APTOSDataset(val_df, val_transform)\n\ntrain_loader = DataLoader(train_dataset, batch_size=16, shuffle=True, num_workers=2)\nval_loader   = DataLoader(val_dataset, batch_size=16, shuffle=False, num_workers=2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:32:03.261586Z","iopub.execute_input":"2025-12-13T12:32:03.261922Z","iopub.status.idle":"2025-12-13T12:32:03.269551Z","shell.execute_reply.started":"2025-12-13T12:32:03.261896Z","shell.execute_reply":"2025-12-13T12:32:03.268741Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = timm.create_model(\n    \"efficientnet_b1\",\n    pretrained=True,\n    num_classes=3\n)\nmodel.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:32:30.737923Z","iopub.execute_input":"2025-12-13T12:32:30.738270Z","iopub.status.idle":"2025-12-13T12:32:32.954982Z","shell.execute_reply.started":"2025-12-13T12:32:30.738243Z","shell.execute_reply":"2025-12-13T12:32:32.953608Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class_weights = compute_class_weight(\n    class_weight=\"balanced\",\n    classes=np.array([0,1,2]),\n    y=df[\"cvd_risk\"]\n)\n\nclass_weights = torch.tensor(class_weights, dtype=torch.float).to(device)\n\ncriterion = nn.CrossEntropyLoss(weight=class_weights)\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:33:20.642228Z","iopub.execute_input":"2025-12-13T12:33:20.642525Z","iopub.status.idle":"2025-12-13T12:33:20.652250Z","shell.execute_reply.started":"2025-12-13T12:33:20.642503Z","shell.execute_reply":"2025-12-13T12:33:20.651031Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"epochs = 5\n\nfor epoch in range(epochs):\n    model.train()\n    running_loss = 0\n\n    for images, labels in train_loader:\n        images, labels = images.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n\n    print(f\"Epoch {epoch+1}/{epochs} | Loss: {running_loss/len(train_loader):.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T12:33:52.821121Z","iopub.execute_input":"2025-12-13T12:33:52.821457Z","iopub.status.idle":"2025-12-13T13:30:01.457067Z","shell.execute_reply.started":"2025-12-13T12:33:52.821427Z","shell.execute_reply":"2025-12-13T13:30:01.454261Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(model.state_dict(), \"/kaggle/working/efficientnet_b1_cvd.pth\")\nprint(\" Model saved!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T13:30:21.317947Z","iopub.execute_input":"2025-12-13T13:30:21.318558Z","iopub.status.idle":"2025-12-13T13:30:21.457240Z","shell.execute_reply.started":"2025-12-13T13:30:21.318496Z","shell.execute_reply":"2025-12-13T13:30:21.456056Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.eval()\ny_true, y_pred = [], []\n\nwith torch.no_grad():\n    for images, labels in val_loader:\n        images, labels = images.to(device), labels.to(device)\n        outputs = model(images)\n        preds = torch.argmax(outputs, dim=1)\n\n        y_true.extend(labels.cpu().numpy())\n        y_pred.extend(preds.cpu().numpy())\n\nprint(\"Accuracy :\", accuracy_score(y_true, y_pred))\nprint(\"Precision:\", precision_score(y_true, y_pred, average=\"weighted\"))\nprint(\"Recall   :\", recall_score(y_true, y_pred, average=\"weighted\"))\nprint(\"F1 Score :\", f1_score(y_true, y_pred, average=\"weighted\"))\nprint(\"Confusion Matrix:\\n\", confusion_matrix(y_true, y_pred))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T13:30:38.715513Z","iopub.execute_input":"2025-12-13T13:30:38.716523Z","iopub.status.idle":"2025-12-13T13:31:45.339145Z","shell.execute_reply.started":"2025-12-13T13:30:38.716492Z","shell.execute_reply":"2025-12-13T13:31:45.337939Z"}},"outputs":[],"execution_count":null}]}