{"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":13836,"databundleVersionId":1718836,"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,"execution":{"iopub.status.busy":"2025-11-30T04:28:58.920614Z","iopub.execute_input":"2025-11-30T04:28:58.921145Z","iopub.status.idle":"2025-11-30T04:29:11.625526Z","shell.execute_reply.started":"2025-11-30T04:28:58.921119Z","shell.execute_reply":"2025-11-30T04:29:11.624352Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport timm\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nfrom sklearn.model_selection import StratifiedKFold\n\nimport torch\nimport torch.nn as nn\nfrom torch.cuda import amp\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\n\n\n# ======================\n# CONFIG\n# ======================\nclass CFG:\n    seed = 42\n    model_name = \"swin_large_patch4_window12_384\"\n    img_size = 384\n    batch_size = 4             # works on T4 (16GB)\n    grad_accum = 2             # effective batch 8\n    epochs = 8\n    lr = 2e-5\n    num_classes = 5\n    num_workers = 2\n    train_csv = \"/kaggle/input/cassava-leaf-disease-classification/train.csv\"\n    images = \"/kaggle/input/cassava-leaf-disease-classification/train_images/\"\n\n\n# ======================\n# SEED\n# ======================\ndef seed_everything(seed=42):\n    import random\n    random.seed(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n\nseed_everything()\n\n\n# ======================\n# DATASET\n# ======================\nclass CassavaDS(Dataset):\n    def __init__(self, df, tfm=None):\n        self.df = df\n        self.tfm = tfm\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        img = cv2.imread(CFG.images + row.image_id)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        \n        if self.tfm:\n            img = self.tfm(img)\n        \n        return img, row.label\n\n\n# ======================\n# AUGMENTATIONS\n# ======================\ntrain_tfms = transforms.Compose([\n    transforms.ToPILImage(),\n    transforms.Resize((CFG.img_size, CFG.img_size)),\n    transforms.RandAugment(2, 8),\n    transforms.ToTensor(),\n    transforms.Normalize([0.5]*3, [0.5]*3),\n])\n\nvalid_tfms = transforms.Compose([\n    transforms.ToPILImage(),\n    transforms.Resize((CFG.img_size, CFG.img_size)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.5]*3, [0.5]*3),\n])\n\n\n# ======================\n# MODEL\n# ======================\ndef build_model():\n    model = timm.create_model(\n        CFG.model_name,\n        pretrained=True,\n        num_classes=CFG.num_classes\n    )\n    return model\n\n\n# ======================\n# TRAIN LOOP\n# ======================\ndevice = \"cuda\"\n\n\ndef train_one_epoch(model, loader, optimizer, criterion, scaler):\n    model.train()\n    correct, total = 0, 0\n    loss_sum = 0\n    \n    optimizer.zero_grad()\n    \n    for step, (x, y) in enumerate(tqdm(loader)):\n        x, y = x.to(device), y.to(device)\n\n        with amp.autocast():\n            out = model(x)\n            loss = criterion(out, y) / CFG.grad_accum\n\n        scaler.scale(loss).backward()\n\n        if (step + 1) % CFG.grad_accum == 0:\n            scaler.step(optimizer)\n            scaler.update()\n            optimizer.zero_grad()\n\n        loss_sum += loss.item() * CFG.grad_accum * x.size(0)\n        correct += (out.argmax(1) == y).sum().item()\n        total += x.size(0)\n\n    return loss_sum / total, correct / total\n\n\ndef valid_one_epoch(model, loader, criterion):\n    model.eval()\n    correct, total = 0, 0\n    loss_sum = 0\n    \n    with torch.no_grad():\n        for x, y in loader:\n            x, y = x.to(device), y.to(device)\n            out = model(x)\n            loss = criterion(out, y)\n\n            loss_sum += loss.item() * x.size(0)\n            correct += (out.argmax(1) == y).sum().item()\n            total += x.size(0)\n\n    return loss_sum / total, correct / total\n\n\n# ======================\n# TRAINING SETUP\n# ======================\ndf = pd.read_csv(CFG.train_csv)\n\nskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\ntrain_idx, val_idx = next(skf.split(df, df.label))\n\ntrain_ds = CassavaDS(df.iloc[train_idx], train_tfms)\nvalid_ds = CassavaDS(df.iloc[val_idx], valid_tfms)\n\ntrain_loader = DataLoader(train_ds, batch_size=CFG.batch_size, shuffle=True, num_workers=CFG.num_workers)\nvalid_loader = DataLoader(valid_ds, batch_size=CFG.batch_size, shuffle=False, num_workers=CFG.num_workers)\n\nmodel = build_model().to(device)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.AdamW(model.parameters(), lr=CFG.lr)\nscaler = amp.GradScaler()\n\nbest_acc = 0\n\n\n# ======================\n# TRAINING LOOP\n# ======================\nfor epoch in range(1, CFG.epochs + 1):\n    tr_loss, tr_acc = train_one_epoch(model, train_loader, optimizer, criterion, scaler)\n    val_loss, val_acc = valid_one_epoch(model, valid_loader, criterion)\n    \n    print(f\"\\nEPOCH {epoch}\")\n    print(f\"Train     Loss: {tr_loss:.4f} | Acc: {tr_acc*100:.2f}%\")\n    print(f\"Valid     Loss: {val_loss:.4f} | Acc: {val_acc*100:.2f}%\")\n    \n    if val_acc > best_acc:\n        best_acc = val_acc\n        torch.save(model.state_dict(), \"best_swin_large.pth\")\n        print(\"✔ Saved New Best Model (Swin-L)\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-30T04:29:11.627326Z","iopub.execute_input":"2025-11-30T04:29:11.627701Z","iopub.status.idle":"2025-11-30T09:34:29.292711Z","shell.execute_reply.started":"2025-11-30T04:29:11.627681Z","shell.execute_reply":"2025-11-30T09:34:29.291570Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ntrain_loss = [0.4238, 0.3109, 0.2575, 0.2022, 0.1534, 0.1191, 0.0930, 0.0741]\nvalid_loss = [0.3343, 0.3363, 0.3333, 0.3647, 0.4191, 0.4333, 0.4907, 0.5985]\n\ntrain_acc = [85.52, 89.39, 91.00, 92.93, 94.81, 96.02, 96.80, 97.42]\nvalid_acc = [88.90, 88.86, 89.04, 88.01, 88.29, 88.60, 88.79, 87.76]\n\nepochs = list(range(1, 9))\n\nplt.figure(figsize=(10,5))\nplt.plot(epochs, train_loss, label=\"Train Loss\")\nplt.plot(epochs, valid_loss, label=\"Valid Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.title(\"Training vs Validation Loss\")\nplt.legend()\nplt.grid()\nplt.show()\n\nplt.figure(figsize=(10,5))\nplt.plot(epochs, train_acc, label=\"Train Accuracy\")\nplt.plot(epochs, valid_acc, label=\"Validation Accuracy\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Accuracy (%)\")\nplt.title(\"Training vs Validation Accuracy\")\nplt.legend()\nplt.grid()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T04:05:19.559206Z","iopub.execute_input":"2025-12-01T04:05:19.559492Z","iopub.status.idle":"2025-12-01T04:05:20.171542Z","shell.execute_reply.started":"2025-12-01T04:05:19.559446Z","shell.execute_reply":"2025-12-01T04:05:20.170395Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}