{"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":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":14774,"databundleVersionId":875431}],"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-03-22T13:50:39.01248Z","iopub.execute_input":"2026-03-22T13:50:39.013277Z","iopub.status.idle":"2026-03-22T13:50:42.640835Z","shell.execute_reply.started":"2026-03-22T13:50:39.013242Z","shell.execute_reply":"2026-03-22T13:50:42.640013Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install timm albumentations seaborn scikit-learn\n\nimport os\nimport cv2\nimport torch\nimport timm\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, classification_report, f1_score\nimport albumentations as A","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:50:42.642287Z","iopub.execute_input":"2026-03-22T13:50:42.642704Z","iopub.status.idle":"2026-03-22T13:51:00.462384Z","shell.execute_reply.started":"2026-03-22T13:50:42.642679Z","shell.execute_reply":"2026-03-22T13:51:00.461771Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BASE_PATH = \"/kaggle/input/competitions/aptos2019-blindness-detection\"\n\nCSV_PATH = BASE_PATH + \"/train.csv\"\nIMG_PATH = BASE_PATH + \"/train_images\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:51:00.463339Z","iopub.execute_input":"2026-03-22T13:51:00.463853Z","iopub.status.idle":"2026-03-22T13:51:00.467418Z","shell.execute_reply.started":"2026-03-22T13:51:00.463824Z","shell.execute_reply":"2026-03-22T13:51:00.466773Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(CSV_PATH)\ntrain_df, val_df = train_test_split(df, test_size=0.2, random_state=42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:51:00.469278Z","iopub.execute_input":"2026-03-22T13:51:00.469594Z","iopub.status.idle":"2026-03-22T13:51:00.500367Z","shell.execute_reply.started":"2026-03-22T13:51:00.469572Z","shell.execute_reply":"2026-03-22T13:51:00.499832Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = A.Compose([\n    A.Resize(224, 224),\n    A.HorizontalFlip(p=0.5),\n    A.RandomBrightnessContrast(p=0.5),\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:51:00.501163Z","iopub.execute_input":"2026-03-22T13:51:00.501694Z","iopub.status.idle":"2026-03-22T13:51:00.507707Z","shell.execute_reply.started":"2026-03-22T13:51:00.501671Z","shell.execute_reply":"2026-03-22T13:51:00.506858Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class DRDataset(Dataset):\n    def __init__(self, df, img_dir, transform=None):\n        self.df = df\n        self.img_dir = img_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        img_name = self.df.iloc[idx]['id_code']\n        label = self.df.iloc[idx]['diagnosis']\n\n        path = os.path.join(self.img_dir, img_name + \".png\")\n\n        img = cv2.imread(path)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        if self.transform:\n            img = self.transform(image=img)['image']\n\n        img = torch.tensor(img).permute(2,0,1).float() / 255.0\n        return img, torch.tensor(label).long()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:51:00.5087Z","iopub.execute_input":"2026-03-22T13:51:00.508975Z","iopub.status.idle":"2026-03-22T13:51:00.523015Z","shell.execute_reply.started":"2026-03-22T13:51:00.508942Z","shell.execute_reply":"2026-03-22T13:51:00.522164Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_loader = DataLoader(DRDataset(train_df, IMG_PATH, transform), batch_size=8, shuffle=True)\nval_loader = DataLoader(DRDataset(val_df, IMG_PATH, transform), batch_size=8, shuffle=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:51:00.523917Z","iopub.execute_input":"2026-03-22T13:51:00.524331Z","iopub.status.idle":"2026-03-22T13:51:00.534333Z","shell.execute_reply.started":"2026-03-22T13:51:00.52427Z","shell.execute_reply":"2026-03-22T13:51:00.533576Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torchvision.models as models\n\nclass Model(nn.Module):\n    def __init__(self, model_name=\"efficientnet\"):\n        super().__init__()\n\n        if model_name == \"efficientnet\":\n            self.model = timm.create_model('efficientnet_b3', pretrained=True, num_classes=5)\n\n        elif model_name == \"densenet\":\n            self.model = models.densenet169(pretrained=True)\n            self.model.classifier = nn.Linear(self.model.classifier.in_features, 5)\n\n        elif model_name == \"resnet\":\n            self.model = models.resnet50(pretrained=True)\n            self.model.fc = nn.Linear(self.model.fc.in_features, 5)\n\n        elif model_name == \"mobilenet\":\n            self.model = models.mobilenet_v2(pretrained=True)\n            self.model.classifier[1] = nn.Linear(1280, 5)\n\n    def forward(self, x):\n        return self.model(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:51:00.535258Z","iopub.execute_input":"2026-03-22T13:51:00.535661Z","iopub.status.idle":"2026-03-22T13:51:00.549161Z","shell.execute_reply.started":"2026-03-22T13:51:00.535627Z","shell.execute_reply":"2026-03-22T13:51:00.548471Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nMODEL_NAME = \"resnet\"   # change here\n\nmodel = Model(MODEL_NAME).to(device)\n\nweights = torch.tensor([1.0,2.0,2.0,3.0,4.0]).to(device)\ncriterion = nn.CrossEntropyLoss(weight=weights)\n\noptimizer = torch.optim.Adam(model.parameters(), lr=3e-4)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:51:00.549871Z","iopub.execute_input":"2026-03-22T13:51:00.550261Z","iopub.status.idle":"2026-03-22T13:51:02.189975Z","shell.execute_reply.started":"2026-03-22T13:51:00.550238Z","shell.execute_reply":"2026-03-22T13:51:02.18938Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def accuracy(outputs, labels):\n    _, preds = torch.max(outputs, 1)\n    return (preds == labels).float().mean()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:51:02.192028Z","iopub.execute_input":"2026-03-22T13:51:02.192363Z","iopub.status.idle":"2026-03-22T13:51:02.196022Z","shell.execute_reply.started":"2026-03-22T13:51:02.192339Z","shell.execute_reply":"2026-03-22T13:51:02.195274Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_epoch(loader):\n    model.train()\n    total_loss, total_acc = 0, 0\n\n    for imgs, labels in loader:\n        imgs, labels = imgs.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n        outputs = model(imgs)\n\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n        total_acc += accuracy(outputs, labels).item()\n\n    return total_loss/len(loader), total_acc/len(loader)\n\n\ndef validate(loader):\n    model.eval()\n    total_acc = 0\n\n    with torch.no_grad():\n        for imgs, labels in loader:\n            imgs, labels = imgs.to(device), labels.to(device)\n            outputs = model(imgs)\n            total_acc += accuracy(outputs, labels).item()\n\n    return total_acc/len(loader)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:51:02.197026Z","iopub.execute_input":"2026-03-22T13:51:02.197368Z","iopub.status.idle":"2026-03-22T13:51:02.210723Z","shell.execute_reply.started":"2026-03-22T13:51:02.197345Z","shell.execute_reply":"2026-03-22T13:51:02.210131Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"EPOCHS = 10\nbest_acc = 0\n\nfor epoch in range(EPOCHS):\n    train_loss, train_acc = train_epoch(train_loader)\n    val_acc = validate(val_loader)\n\n    print(f\"\\nEpoch {epoch+1}\")\n    print(f\"Train Acc: {train_acc:.4f}\")\n    print(f\"Val Acc: {val_acc:.4f}\")\n\n    if val_acc > best_acc:\n        best_acc = val_acc\n        torch.save(model.state_dict(), f\"/kaggle/working/{MODEL_NAME}.pth\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T13:51:02.21154Z","iopub.execute_input":"2026-03-22T13:51:02.211945Z","iopub.status.idle":"2026-03-22T14:52:08.225898Z","shell.execute_reply.started":"2026-03-22T13:51:02.211912Z","shell.execute_reply":"2026-03-22T14:52:08.2252Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y_true, y_pred = [], []\n\nmodel.eval()\n\nwith torch.no_grad():\n    for imgs, labels in val_loader:\n        imgs = imgs.to(device)\n        outputs = model(imgs)\n        _, preds = torch.max(outputs, 1)\n\n        y_true.extend(labels.numpy())\n        y_pred.extend(preds.cpu().numpy())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-24T16:28:52.540847Z","iopub.execute_input":"2026-03-24T16:28:52.54142Z","iopub.status.idle":"2026-03-24T16:28:52.54795Z","shell.execute_reply.started":"2026-03-24T16:28:52.541388Z","shell.execute_reply":"2026-03-24T16:28:52.547048Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels = [\"No DR\", \"Mild\", \"Moderate\", \"Severe\", \"Proliferative\"]\n\ncm = confusion_matrix(y_true, y_pred)\n\nplt.figure(figsize=(6,5))\nsns.heatmap(cm, annot=True, fmt='d', xticklabels=labels, yticklabels=labels)\nplt.show()\n\nprint(classification_report(y_true, y_pred, target_names=labels))\n\nprint(\"F1 Score:\", f1_score(y_true, y_pred, average='weighted'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T14:53:18.8924Z","iopub.execute_input":"2026-03-22T14:53:18.892609Z","iopub.status.idle":"2026-03-22T14:53:19.126068Z","shell.execute_reply.started":"2026-03-22T14:53:18.892587Z","shell.execute_reply":"2026-03-22T14:53:19.125289Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(model.state_dict(), f\"/kaggle/working/final_{MODEL_NAME}.pth\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-22T14:53:19.126946Z","iopub.execute_input":"2026-03-22T14:53:19.127255Z","iopub.status.idle":"2026-03-22T14:53:19.25122Z","shell.execute_reply.started":"2026-03-22T14:53:19.127231Z","shell.execute_reply":"2026-03-22T14:53:19.25057Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import cohen_kappa_score","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-24T16:28:30.816119Z","iopub.execute_input":"2026-03-24T16:28:30.817258Z","iopub.status.idle":"2026-03-24T16:28:31.940022Z","shell.execute_reply.started":"2026-03-24T16:28:30.817223Z","shell.execute_reply":"2026-03-24T16:28:31.939183Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"kappa = cohen_kappa_score(y_true, y_pred)\nprint(\"Kappa Score:\", kappa)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-24T16:28:44.662168Z","iopub.execute_input":"2026-03-24T16:28:44.662721Z","iopub.status.idle":"2026-03-24T16:28:44.672475Z","shell.execute_reply.started":"2026-03-24T16:28:44.66269Z","shell.execute_reply":"2026-03-24T16:28:44.671564Z"}},"outputs":[],"execution_count":null}]}