{"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":"gpu","dataSources":[{"sourceId":13836,"databundleVersionId":1718836,"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,"execution":{"iopub.status.busy":"2025-12-06T01:13:53.849173Z","iopub.execute_input":"2025-12-06T01:13:53.849718Z","iopub.status.idle":"2025-12-06T01:14:28.142825Z","shell.execute_reply.started":"2025-12-06T01:13:53.849692Z","shell.execute_reply":"2025-12-06T01:14:28.141805Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision\nfrom torchvision import transforms, models\nfrom PIL import Image\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:18:56.483997Z","iopub.execute_input":"2025-12-06T01:18:56.484757Z","iopub.status.idle":"2025-12-06T01:18:56.489370Z","shell.execute_reply.started":"2025-12-06T01:18:56.484724Z","shell.execute_reply":"2025-12-06T01:18:56.488645Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:18:59.145998Z","iopub.execute_input":"2025-12-06T01:18:59.146621Z","iopub.status.idle":"2025-12-06T01:18:59.150654Z","shell.execute_reply.started":"2025-12-06T01:18:59.146596Z","shell.execute_reply":"2025-12-06T01:18:59.149864Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_path = \"/kaggle/input/cassava-leaf-disease-classification/\"\nimages_path = os.path.join(data_path, \"train_images\")\ncsv_path = os.path.join(data_path, \"train.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:19:00.913953Z","iopub.execute_input":"2025-12-06T01:19:00.914589Z","iopub.status.idle":"2025-12-06T01:19:00.918297Z","shell.execute_reply.started":"2025-12-06T01:19:00.914563Z","shell.execute_reply":"2025-12-06T01:19:00.917458Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(csv_path)\n\ndf.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:19:02.214220Z","iopub.execute_input":"2025-12-06T01:19:02.214498Z","iopub.status.idle":"2025-12-06T01:19:02.239872Z","shell.execute_reply.started":"2025-12-06T01:19:02.214477Z","shell.execute_reply":"2025-12-06T01:19:02.239197Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df, temp_df = train_test_split(df, test_size=0.3, stratify=df['label'], random_state=42)\n\nval_df, test_df = train_test_split(temp_df, test_size=1/3, stratify=temp_df['label'], random_state=42)\n\nprint(\"Train:\", len(train_df))\nprint(\"Validation:\", len(val_df))\nprint(\"Test:\", len(test_df))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:19:03.842089Z","iopub.execute_input":"2025-12-06T01:19:03.842353Z","iopub.status.idle":"2025-12-06T01:19:03.862287Z","shell.execute_reply.started":"2025-12-06T01:19:03.842335Z","shell.execute_reply":"2025-12-06T01:19:03.861458Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n\ntrain_transforms = transforms.Compose([\n    transforms.Resize((300, 300)),           \n    transforms.RandomHorizontalFlip(),      \n    transforms.RandomRotation(20),          \n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\nval_transforms = transforms.Compose([\n    transforms.Resize((300, 300)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n])\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:42:16.971628Z","iopub.execute_input":"2025-12-06T01:42:16.972113Z","iopub.status.idle":"2025-12-06T01:42:16.976844Z","shell.execute_reply.started":"2025-12-06T01:42:16.972090Z","shell.execute_reply":"2025-12-06T01:42:16.976184Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CassavaDataset(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]['image_id']\n        label = self.df.iloc[idx]['label']\n        \n        img_path = os.path.join(self.img_dir, img_name)\n        image = Image.open(img_path).convert(\"RGB\")\n        \n        if self.transform:\n            image = self.transform(image)\n        \n        return image, label\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:42:20.771791Z","iopub.execute_input":"2025-12-06T01:42:20.772496Z","iopub.status.idle":"2025-12-06T01:42:20.777450Z","shell.execute_reply.started":"2025-12-06T01:42:20.772469Z","shell.execute_reply":"2025-12-06T01:42:20.776738Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Datasets\ntrain_dataset = CassavaDataset(train_df, images_path, transform=train_transforms)\nval_dataset = CassavaDataset(val_df, images_path, transform=val_transforms)\ntest_dataset = CassavaDataset(test_df, images_path, transform=val_transforms)\n\n# DataLoaders\nbatch_size = 32\n\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=2)\nval_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False, num_workers=2)\ntest_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=2)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:42:23.118183Z","iopub.execute_input":"2025-12-06T01:42:23.118437Z","iopub.status.idle":"2025-12-06T01:42:23.123955Z","shell.execute_reply.started":"2025-12-06T01:42:23.118420Z","shell.execute_reply":"2025-12-06T01:42:23.123252Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:42:25.180668Z","iopub.execute_input":"2025-12-06T01:42:25.180911Z","iopub.status.idle":"2025-12-06T01:42:25.184658Z","shell.execute_reply.started":"2025-12-06T01:42:25.180894Z","shell.execute_reply":"2025-12-06T01:42:25.183844Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install efficientnet-pytorch\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:18:38.226284Z","iopub.execute_input":"2025-12-06T01:18:38.226596Z","iopub.status.idle":"2025-12-06T01:18:41.401748Z","shell.execute_reply.started":"2025-12-06T01:18:38.226574Z","shell.execute_reply":"2025-12-06T01:18:41.401028Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from efficientnet_pytorch import EfficientNet\nimport torch.nn as nn\nimport torch\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:42:30.129660Z","iopub.execute_input":"2025-12-06T01:42:30.130382Z","iopub.status.idle":"2025-12-06T01:42:30.133540Z","shell.execute_reply.started":"2025-12-06T01:42:30.130356Z","shell.execute_reply":"2025-12-06T01:42:30.132939Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ndevice\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:42:32.107747Z","iopub.execute_input":"2025-12-06T01:42:32.108494Z","iopub.status.idle":"2025-12-06T01:42:32.114365Z","shell.execute_reply.started":"2025-12-06T01:42:32.108462Z","shell.execute_reply":"2025-12-06T01:42:32.113621Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = EfficientNet.from_pretrained('efficientnet-b3')\n\nmodel._fc = nn.Linear(model._fc.in_features, 5)\n\nmodel = model.to(device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:42:34.281818Z","iopub.execute_input":"2025-12-06T01:42:34.282369Z","iopub.status.idle":"2025-12-06T01:42:34.512443Z","shell.execute_reply.started":"2025-12-06T01:42:34.282348Z","shell.execute_reply":"2025-12-06T01:42:34.511682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:42:36.368945Z","iopub.execute_input":"2025-12-06T01:42:36.369634Z","iopub.status.idle":"2025-12-06T01:42:36.379697Z","shell.execute_reply.started":"2025-12-06T01:42:36.369611Z","shell.execute_reply":"2025-12-06T01:42:36.378947Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_one_epoch(model, loader, optimizer, criterion):\n    model.train()\n    running_loss = 0\n    running_correct = 0\n\n    for images, labels in 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\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item() * images.size(0)\n        _, preds = torch.max(outputs, 1)\n        running_correct += torch.sum(preds == labels)\n\n    epoch_loss = running_loss / len(loader.dataset)\n    epoch_acc = running_correct.double() / len(loader.dataset)\n    return epoch_loss, epoch_acc\nloss, acc = train_one_epoch(model, train_loader, optimizer, criterion)\n\nprint(\"Training Loss:\", loss)\nprint(\"Training Accuracy:\", acc)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:42:38.699062Z","iopub.execute_input":"2025-12-06T01:42:38.699890Z","iopub.status.idle":"2025-12-06T01:46:25.591411Z","shell.execute_reply.started":"2025-12-06T01:42:38.699865Z","shell.execute_reply":"2025-12-06T01:46:25.590406Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def validate(model, loader, criterion):\n    model.eval()\n    running_loss = 0\n    running_correct = 0\n\n    with torch.no_grad():\n        for images, labels in loader:\n            images, labels = images.to(device), labels.to(device)\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n\n            running_loss += loss.item() * images.size(0)\n            _, preds = torch.max(outputs, 1)\n            running_correct += torch.sum(preds == labels)\n\n    epoch_loss = running_loss / len(loader.dataset)\n    epoch_acc = running_correct.double() / len(loader.dataset)\n    return epoch_loss, epoch_acc\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-06T01:46:58.360335Z","iopub.execute_input":"2025-12-06T01:46:58.360899Z","iopub.status.idle":"2025-12-06T01:46:58.365925Z","shell.execute_reply.started":"2025-12-06T01:46:58.360877Z","shell.execute_reply":"2025-12-06T01:46:58.365082Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"epochs = 15\npatience = 3\nbest_acc = 0\ntrigger_times = 0\n\nfor epoch in range(epochs):\n    train_loss, train_acc = train_one_epoch(model, train_loader, optimizer, criterion)\n    val_loss, val_acc = validate(model, val_loader, criterion)\n\n    print(f\"Epoch [{epoch+1}/{epochs}]\")\n    print(f\"Train Acc: {train_acc:.4f} | Val Acc: {val_acc:.4f}\")\n\n    if val_acc > best_acc:\n        best_acc = val_acc\n        torch.save(model.state_dict(), \"best_model.pth\")\n        trigger_times = 0\n        print(\">>> Saved Best Model\")\n    else:\n        trigger_times += 1\n        if trigger_times >= patience:\n            print(\"Early stopping activated!\")\n            break\n","metadata":{"trusted":true,"execution":{"execution_failed":"2025-12-06T13:48:44.820Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}