{"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-12T03:44:17.240260Z","iopub.execute_input":"2025-12-12T03:44:17.240453Z","iopub.status.idle":"2025-12-12T03:44:35.198008Z","shell.execute_reply.started":"2025-12-12T03:44:17.240436Z","shell.execute_reply":"2025-12-12T03:44:35.196956Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision\nfrom torchvision import transforms\nfrom torch.utils.data import DataLoader\nfrom torch.utils.data import Dataset\nfrom torchinfo import summary\n\nfrom torchvision.models import resnet152, ResNet152_Weights\n\nimport albumentations \nfrom albumentations.pytorch.transforms import ToTensorV2\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom sklearn.model_selection import train_test_split, StratifiedKFold\n\nimport os\nimport copy\nimport glob\nimport json\nimport random\nimport pathlib\nfrom PIL import Image\nimport pickle \n\n\nBASE_PATH = '/kaggle/input/cassava-leaf-disease-classification/'\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(f'Device: {DEVICE}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:35.200044Z","iopub.execute_input":"2025-12-12T03:44:35.200459Z","iopub.status.idle":"2025-12-12T03:44:44.413563Z","shell.execute_reply.started":"2025-12-12T03:44:35.200434Z","shell.execute_reply":"2025-12-12T03:44:44.412823Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(BASE_PATH + 'train.csv')\ndf.head(10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:44.414272Z","iopub.execute_input":"2025-12-12T03:44:44.414686Z","iopub.status.idle":"2025-12-12T03:44:44.461469Z","shell.execute_reply.started":"2025-12-12T03:44:44.414665Z","shell.execute_reply":"2025-12-12T03:44:44.460846Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels = json.load(open(BASE_PATH + \"label_num_to_disease_map.json\"))\nlabels = {int(key):value for key, value in labels.items()}\nlabels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:44.462440Z","iopub.execute_input":"2025-12-12T03:44:44.462728Z","iopub.status.idle":"2025-12-12T03:44:44.472637Z","shell.execute_reply.started":"2025-12-12T03:44:44.462707Z","shell.execute_reply":"2025-12-12T03:44:44.472024Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:44.473451Z","iopub.execute_input":"2025-12-12T03:44:44.473797Z","iopub.status.idle":"2025-12-12T03:44:44.495420Z","shell.execute_reply.started":"2025-12-12T03:44:44.473772Z","shell.execute_reply":"2025-12-12T03:44:44.494699Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['label'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:44.496343Z","iopub.execute_input":"2025-12-12T03:44:44.496706Z","iopub.status.idle":"2025-12-12T03:44:44.506341Z","shell.execute_reply.started":"2025-12-12T03:44:44.496675Z","shell.execute_reply":"2025-12-12T03:44:44.505491Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def display_images(label, rows, cols):\n    \n    number = rows * cols\n    \n    new_df = df[df['label'] == label]\n    \n    img_list = random.sample(new_df['image_id'].tolist(), number)\n    \n    plt.figure(figsize=(12, 9))\n    for index, img_id in enumerate(img_list):\n        plt.subplot(rows, cols, index+1)\n        image = Image.open(BASE_PATH + \"/train_images/\" + img_id)\n        plt.imshow(image, aspect='auto')\n        plt.axis('off')\n        \n    plt.suptitle(f'\\n\\n Class {label}: ' + labels[label], fontsize=20)\n    plt.tight_layout()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:44.508751Z","iopub.execute_input":"2025-12-12T03:44:44.509392Z","iopub.status.idle":"2025-12-12T03:44:44.524321Z","shell.execute_reply.started":"2025-12-12T03:44:44.509370Z","shell.execute_reply":"2025-12-12T03:44:44.523418Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"random.seed(42)\nfor i in range(5):\n    display_images(label=i, rows=3, cols=4)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:44.525218Z","iopub.execute_input":"2025-12-12T03:44:44.525508Z","iopub.status.idle":"2025-12-12T03:44:53.379194Z","shell.execute_reply.started":"2025-12-12T03:44:44.525478Z","shell.execute_reply":"2025-12-12T03:44:53.377524Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"example_id = df['image_id'][19]\nexample_image = Image.open(BASE_PATH + \"/train_images/\" + example_id)\nplt.figure()\nplt.imshow(example_image)\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:53.380154Z","iopub.execute_input":"2025-12-12T03:44:53.380386Z","iopub.status.idle":"2025-12-12T03:44:53.596356Z","shell.execute_reply.started":"2025-12-12T03:44:53.380367Z","shell.execute_reply":"2025-12-12T03:44:53.595530Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"vertical_transform = albumentations.VerticalFlip(p=1)\naugmented_image = vertical_transform(image=np.array(example_image))['image']\nplt.figure()\nplt.imshow(augmented_image)\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:53.597062Z","iopub.execute_input":"2025-12-12T03:44:53.597290Z","iopub.status.idle":"2025-12-12T03:44:53.799890Z","shell.execute_reply.started":"2025-12-12T03:44:53.597273Z","shell.execute_reply":"2025-12-12T03:44:53.798948Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"horizontal_transform = albumentations.HorizontalFlip(p=1)\naugmented_image = horizontal_transform(image=np.array(example_image))['image']\nplt.figure()\nplt.imshow(augmented_image)\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:53.800766Z","iopub.execute_input":"2025-12-12T03:44:53.801340Z","iopub.status.idle":"2025-12-12T03:44:53.995942Z","shell.execute_reply.started":"2025-12-12T03:44:53.801315Z","shell.execute_reply":"2025-12-12T03:44:53.995152Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"random_crop_transform = albumentations.RandomResizedCrop(size=(512, 512))\naugmented_image = random_crop_transform(image=np.array(example_image))['image']\nplt.figure()\nplt.imshow(augmented_image)\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:53.996652Z","iopub.execute_input":"2025-12-12T03:44:53.996938Z","iopub.status.idle":"2025-12-12T03:44:54.150596Z","shell.execute_reply.started":"2025-12-12T03:44:53.996914Z","shell.execute_reply":"2025-12-12T03:44:54.149894Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transpose_transform = albumentations.Transpose(p=1)\naugmented_image = transpose_transform(image=np.array(example_image))['image']\nplt.figure()\nplt.imshow(augmented_image)\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:54.151464Z","iopub.execute_input":"2025-12-12T03:44:54.151707Z","iopub.status.idle":"2025-12-12T03:44:54.291778Z","shell.execute_reply.started":"2025-12-12T03:44:54.151690Z","shell.execute_reply":"2025-12-12T03:44:54.291071Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"shift_scale_rotate_transform = albumentations.ShiftScaleRotate(p=1)\naugmented_image = shift_scale_rotate_transform(image=np.array(example_image))['image']\nplt.figure()\nplt.imshow(augmented_image)\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:54.292510Z","iopub.execute_input":"2025-12-12T03:44:54.292707Z","iopub.status.idle":"2025-12-12T03:44:54.470574Z","shell.execute_reply.started":"2025-12-12T03:44:54.292690Z","shell.execute_reply":"2025-12-12T03:44:54.469721Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"hue_saturation_value_transform = albumentations.HueSaturationValue(\n    hue_shift_limit=20,\n    sat_shift_limit=50,\n    val_shift_limit=20,\n    p=1)\naugmented_image = hue_saturation_value_transform(image=np.array(example_image))['image']\nplt.figure()\nplt.imshow(augmented_image)\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:54.471556Z","iopub.execute_input":"2025-12-12T03:44:54.472100Z","iopub.status.idle":"2025-12-12T03:44:54.713304Z","shell.execute_reply.started":"2025-12-12T03:44:54.472073Z","shell.execute_reply":"2025-12-12T03:44:54.712427Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"random_brightness_contrast_transform = albumentations.RandomBrightnessContrast(\n    brightness_limit=(-0.1, 0.1), \n    contrast_limit=(-0.1, 0.1), \n    p=1)\naugmented_image = hue_saturation_value_transform(image=np.array(example_image))['image']\nplt.figure()\nplt.imshow(augmented_image)\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:54.714091Z","iopub.execute_input":"2025-12-12T03:44:54.714391Z","iopub.status.idle":"2025-12-12T03:44:54.915363Z","shell.execute_reply.started":"2025-12-12T03:44:54.714373Z","shell.execute_reply":"2025-12-12T03:44:54.914441Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.manual_seed(1)\n\nnum_classes = 5\nnum_folds = 5    # for stratified K-fold cross-validation\n\nwidth = 512     # for image augmentation, we will resize image width and height\nheight = 512","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:54.916344Z","iopub.execute_input":"2025-12-12T03:44:54.916694Z","iopub.status.idle":"2025-12-12T03:44:54.925785Z","shell.execute_reply.started":"2025-12-12T03:44:54.916670Z","shell.execute_reply":"2025-12-12T03:44:54.925210Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"skf = StratifiedKFold(n_splits=num_folds, shuffle=True, random_state=1)\n\ndf_train_folds = []\ndf_valid_folds = []\n\nfor i, (train_index, valid_index) in enumerate(skf.split(X=df['image_id'], y=df['label'])):\n    \n    df_train_folds.append(df.loc[list(train_index)])\n    df_valid_folds.append(df.loc[list(valid_index)])\n    \nfold_number = 0\n\ndf_train = df_train_folds[fold_number]\ndf_valid = df_valid_folds[fold_number]\n\ndf_train = df_train.reset_index(drop=True)\ndf_valid = df_valid.reset_index(drop=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:54.926627Z","iopub.execute_input":"2025-12-12T03:44:54.926932Z","iopub.status.idle":"2025-12-12T03:44:54.961973Z","shell.execute_reply.started":"2025-12-12T03:44:54.926907Z","shell.execute_reply":"2025-12-12T03:44:54.961329Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_transforms = albumentations.Compose([\n    \n    albumentations.RandomResizedCrop(size=(height, width)),\n    albumentations.HorizontalFlip(p=0.5),\n    albumentations.Transpose(p=0.5),\n    albumentations.VerticalFlip(p=0.5),\n    albumentations.ShiftScaleRotate(p=0.5),\n    albumentations.HueSaturationValue(\n                hue_shift_limit=0.2, \n                sat_shift_limit=0.2, \n                val_shift_limit=0.2, \n                p=0.5\n            ),\n    albumentations.RandomBrightnessContrast(\n                brightness_limit=(-0.1, 0.1), \n                contrast_limit=(-0.1, 0.1), \n                p=0.5),\n    albumentations.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),\n    ToTensorV2()\n    \n])\n\nvalid_transforms = albumentations.Compose([\n    albumentations.CenterCrop(width, height, p=1.0),\n    albumentations.Resize(width, height),\n    albumentations.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),\n    ToTensorV2(),\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:54.962718Z","iopub.execute_input":"2025-12-12T03:44:54.962990Z","iopub.status.idle":"2025-12-12T03:44:54.975034Z","shell.execute_reply.started":"2025-12-12T03:44:54.962962Z","shell.execute_reply":"2025-12-12T03:44:54.974228Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CassavaDataset(Dataset):\n    \n    def __init__(self, image_ids, labels, target_directory, transform=None):\n        \n        self.transform = transform\n        self.image_ids = image_ids\n        self.labels = labels\n        self.target_directory = target_directory\n        \n    def __len__(self):\n        return len(self.image_ids)\n    \n    def __getitem__(self, index):\n        \n        img = Image.open(os.path.join(BASE_PATH, self.target_directory, self.image_ids[index]))\n        img = np.array(img)\n        label = torch.tensor(self.labels[index], dtype=torch.long)\n        \n        if self.transform:\n            return self.transform(image=img)['image'], label \n        else:\n            return img, label ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:54.975922Z","iopub.execute_input":"2025-12-12T03:44:54.976257Z","iopub.status.idle":"2025-12-12T03:44:54.988918Z","shell.execute_reply.started":"2025-12-12T03:44:54.976237Z","shell.execute_reply":"2025-12-12T03:44:54.988090Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_directory = pathlib.Path(\"train_images\")\nbatch_size = 16\n\ntrain_dataset = CassavaDataset(image_ids=df_train.image_id, labels=df_train.label, target_directory=train_directory, transform=train_transforms)\nvalid_dataset = CassavaDataset(image_ids=df_valid.image_id, labels=df_valid.label, target_directory=train_directory, transform=valid_transforms)\n\ntrain_dl = DataLoader(train_dataset, batch_size, shuffle=True)\nvalid_dl = DataLoader(valid_dataset, batch_size, shuffle=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:54.989751Z","iopub.execute_input":"2025-12-12T03:44:54.990026Z","iopub.status.idle":"2025-12-12T03:44:55.003589Z","shell.execute_reply.started":"2025-12-12T03:44:54.989996Z","shell.execute_reply":"2025-12-12T03:44:55.002700Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_resnet_model():\n    \n    model = resnet152(weights=ResNet152_Weights.DEFAULT)\n    \n    for params in model.parameters():\n        params.requires_grad = False\n        \n    in_feat = model.fc.in_features\n        \n    model.fc = nn.Sequential(\n          nn.Linear(in_feat, 256),\n          nn.ReLU(),\n          nn.Dropout(p=0.3),\n          nn.Linear(256, num_classes))\n    \n    model = model.to(DEVICE)\n    \n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:55.007136Z","iopub.execute_input":"2025-12-12T03:44:55.007373Z","iopub.status.idle":"2025-12-12T03:44:55.019965Z","shell.execute_reply.started":"2025-12-12T03:44:55.007353Z","shell.execute_reply":"2025-12-12T03:44:55.019063Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = get_resnet_model()\n\nsummary(model, input_size=(batch_size, 3, width, height))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:55.020743Z","iopub.execute_input":"2025-12-12T03:44:55.020992Z","iopub.status.idle":"2025-12-12T03:44:58.732738Z","shell.execute_reply.started":"2025-12-12T03:44:55.020970Z","shell.execute_reply":"2025-12-12T03:44:58.732036Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train(model, num_epochs, train_dl, valid_dl):\n    \n    loss_hist_train = [0] * num_epochs\n    accuracy_hist_train = [0] * num_epochs\n    loss_hist_valid = [0] * num_epochs\n    accuracy_hist_valid = [0] * num_epochs\n    \n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n    min_valid_loss = np.inf\n    \n    for epoch in range(num_epochs):\n        \n        model.train()\n        \n        batch_num = 0\n        \n        for x_batch, y_batch in train_dl:\n            \n            x_batch = x_batch.to(DEVICE)\n            y_batch = y_batch.to(DEVICE)\n            \n            batch_num += 1\n            if (batch_num % 100 == 0):\n                print(f'Batch number: {batch_num}')\n            \n            pred = model(x_batch)\n            loss = loss_fn(pred, y_batch)\n            loss.backward()\n            optimizer.step()\n            optimizer.zero_grad()\n            \n            loss_hist_train[epoch] += loss.item() * y_batch.size(0)\n            is_correct = (torch.argmax(pred, dim=1) == y_batch).float()\n            accuracy_hist_train[epoch] += is_correct.sum().item()\n        \n        \n        loss_hist_train[epoch] /= len(train_dl.dataset)\n        accuracy_hist_train[epoch] /= len(train_dl.dataset)\n        \n        scheduler.step()\n        \n        model.eval()\n        \n        with torch.no_grad():\n            \n            for x_batch, y_batch in valid_dl:\n                \n                x_batch = x_batch.to(DEVICE)\n                y_batch = y_batch.to(DEVICE)\n                \n                pred = model(x_batch)\n                loss = loss_fn(pred, y_batch)\n                loss_hist_valid[epoch] += loss.item() * y_batch.size(0)\n                is_correct = (torch.argmax(pred, dim=1) == y_batch).float()\n                accuracy_hist_valid[epoch] += is_correct.sum().item()\n                \n        loss_hist_valid[epoch] /= len(valid_dl.dataset)\n        accuracy_hist_valid[epoch] /= len(valid_dl.dataset)\n        \n        if accuracy_hist_valid[epoch] > best_acc:\n            best_acc = accuracy_hist_valid[epoch]\n            best_model_wts = copy.deepcopy(model.state_dict())\n        \n        print(f'Epoch {epoch+1}:   Train accuracy: {accuracy_hist_train[epoch]:.4f}    Validation accuracy: {accuracy_hist_valid[epoch]:.4f} ')\n    \n    \n        if loss_hist_valid[epoch] < min_valid_loss:\n            counter = 0\n        else:\n            counter += 1\n    \n        if counter >= patience:\n            break\n    \n    \n    model.load_state_dict(best_model_wts)\n    \n    history = {}\n    history['loss_hist_train'] = loss_hist_train\n    history['loss_hist_valid'] = loss_hist_valid\n    history['accuracy_hist_train'] = accuracy_hist_train\n    history['accuracy_hist_valid'] = accuracy_hist_valid\n    \n    return model, history","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:58.733519Z","iopub.execute_input":"2025-12-12T03:44:58.733695Z","iopub.status.idle":"2025-12-12T03:44:58.742871Z","shell.execute_reply.started":"2025-12-12T03:44:58.733680Z","shell.execute_reply":"2025-12-12T03:44:58.742229Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"num_epochs = 10\npatience = 3\nloss_fn = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)\nscheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=10, T_mult=1, eta_min=1e-6, last_epoch=-1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:58.743714Z","iopub.execute_input":"2025-12-12T03:44:58.743994Z","iopub.status.idle":"2025-12-12T03:44:58.763650Z","shell.execute_reply.started":"2025-12-12T03:44:58.743972Z","shell.execute_reply":"2025-12-12T03:44:58.762914Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"best_model, hist = train(model, num_epochs, train_dl, valid_dl)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T03:44:58.764348Z","iopub.execute_input":"2025-12-12T03:44:58.764563Z","iopub.status.idle":"2025-12-12T05:38:08.235013Z","shell.execute_reply.started":"2025-12-12T03:44:58.764540Z","shell.execute_reply":"2025-12-12T05:38:08.234354Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Saving loss and accuracy history during initial training phase\n\nwith open('hist_fold_' + str(fold_number) + '.pkl', 'wb') as f:\n    pickle.dump(hist, f)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T05:38:08.235755Z","iopub.execute_input":"2025-12-12T05:38:08.235946Z","iopub.status.idle":"2025-12-12T05:38:08.240354Z","shell.execute_reply.started":"2025-12-12T05:38:08.235931Z","shell.execute_reply":"2025-12-12T05:38:08.239570Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for i, block in enumerate(model.children()):\n    print('\\n\\n')\n    print(f'Block {i}: \\n\\n')\n    print(block)\n    print('\\n\\n')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T05:38:08.241104Z","iopub.execute_input":"2025-12-12T05:38:08.241328Z","iopub.status.idle":"2025-12-12T05:38:08.257606Z","shell.execute_reply.started":"2025-12-12T05:38:08.241310Z","shell.execute_reply":"2025-12-12T05:38:08.256752Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for params in model.parameters():\n    params.requires_grad = False\n    \nunfreeze_layers = [7]\ni = 0\nfor layer in model.children():\n    if i in unfreeze_layers:\n        for param in layer.parameters():\n            param.requires_grad = True\n    i += 1    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T05:38:08.258484Z","iopub.execute_input":"2025-12-12T05:38:08.258777Z","iopub.status.idle":"2025-12-12T05:38:08.272169Z","shell.execute_reply.started":"2025-12-12T05:38:08.258756Z","shell.execute_reply":"2025-12-12T05:38:08.271345Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Print model summary again\n\nsummary(model, input_size=(batch_size, 3, width, height))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T05:38:08.272992Z","iopub.execute_input":"2025-12-12T05:38:08.273284Z","iopub.status.idle":"2025-12-12T05:38:08.486274Z","shell.execute_reply.started":"2025-12-12T05:38:08.273260Z","shell.execute_reply":"2025-12-12T05:38:08.485547Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"best_model_tuned, hist_tuned = train(best_model, num_epochs, train_dl, valid_dl)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T05:38:08.487032Z","iopub.execute_input":"2025-12-12T05:38:08.487201Z","iopub.status.idle":"2025-12-12T07:35:35.429659Z","shell.execute_reply.started":"2025-12-12T05:38:08.487187Z","shell.execute_reply":"2025-12-12T07:35:35.428805Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Saving loss and accuracy history during finetuning phase\n\nwith open('hist_tuned_fold_' + str(fold_number) + '.pkl', 'wb') as f:\n    pickle.dump(hist_tuned, f)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T07:35:35.430709Z","iopub.execute_input":"2025-12-12T07:35:35.430994Z","iopub.status.idle":"2025-12-12T07:35:35.435420Z","shell.execute_reply.started":"2025-12-12T07:35:35.430965Z","shell.execute_reply":"2025-12-12T07:35:35.434616Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(best_model_tuned, '/kaggle/working/best_model_tuned_resnet152_10_epochs_fold_' + str(fold_number) + '.pt')\ntorch.save(best_model_tuned.state_dict(), '/kaggle/working/best_model_tuned_weights_resnet152_10_epochs_fold_' + str(fold_number) + '.pt')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T07:35:35.436122Z","iopub.execute_input":"2025-12-12T07:35:35.436433Z","iopub.status.idle":"2025-12-12T07:35:36.151395Z","shell.execute_reply.started":"2025-12-12T07:35:35.436415Z","shell.execute_reply":"2025-12-12T07:35:36.150762Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, axs = plt.subplots(ncols=2, figsize=(6.5, 3))\n\naxs[0].plot(range(1, (2*num_epochs)+1), hist['accuracy_hist_valid']+hist_tuned['accuracy_hist_valid'], '-o', color='tab:blue', label='Validation set')\naxs[0].plot(range(1, (2*num_epochs)+1), hist['accuracy_hist_train']+hist_tuned['accuracy_hist_train'], '-o', color='tab:orange', label='Training set')\naxs[1].plot(range(1, (2*num_epochs)+1), hist['loss_hist_valid']+hist_tuned['loss_hist_valid'], '-o', color='tab:red', label='Validation set')\naxs[1].plot(range(1, (2*num_epochs)+1), hist['loss_hist_train']+hist_tuned['loss_hist_train'], '-o', color='tab:green', label='Training set')\n\naxs[0].set_ylabel('Accuracy')\naxs[0].set_xlabel('Epoch')\naxs[0].set_xticks([1, 5, 10, 15, 20])\naxs[0].grid(alpha=0.1)\naxs[0].legend(frameon=True, edgecolor='black', fontsize=8)\naxs[0].axvline(x=10, color='black', linestyle='dashed', linewidth=1)\naxs[0].text(x=1.6, y=0.875, s='Start Finetuning ⟶', fontsize=7)\n\naxs[1].set_ylabel('Loss')\naxs[1].set_xlabel('Epoch')\naxs[1].set_xticks([1, 5, 10, 15, 20])\naxs[1].grid(alpha=0.1)\naxs[1].legend(frameon=True, edgecolor='black', fontsize=8)\naxs[1].axvline(x=10, color='black', linestyle='dashed', linewidth=1)\n\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T07:35:36.152290Z","iopub.execute_input":"2025-12-12T07:35:36.152549Z","iopub.status.idle":"2025-12-12T07:35:36.459974Z","shell.execute_reply.started":"2025-12-12T07:35:36.152518Z","shell.execute_reply":"2025-12-12T07:35:36.459353Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Get lists of true labels and our predictions (from our model trained in this Notebook only) for images \n# in the validation set:\n\neval_dl = DataLoader(valid_dataset, batch_size=1, shuffle=False)\n\nlabel_list = []\nprediction_list = []\n\nwith torch.no_grad():\n    for image, label in eval_dl:\n        \n        image = image.to(DEVICE)\n        logits = best_model_tuned(image)\n        probs = torch.nn.functional.softmax(logits, dim=1).detach().cpu().numpy()\n        prediction = np.argmax(probs)\n        label_list.append(label.numpy())\n        prediction_list.append(prediction)\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T07:35:36.460747Z","iopub.execute_input":"2025-12-12T07:35:36.461319Z","iopub.status.idle":"2025-12-12T07:38:12.872541Z","shell.execute_reply.started":"2025-12-12T07:35:36.461294Z","shell.execute_reply":"2025-12-12T07:38:12.871669Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import classification_report, confusion_matrix, ConfusionMatrixDisplay\n\nprint(classification_report(label_list, prediction_list))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T07:38:12.873527Z","iopub.execute_input":"2025-12-12T07:38:12.873754Z","iopub.status.idle":"2025-12-12T07:38:12.900369Z","shell.execute_reply.started":"2025-12-12T07:38:12.873735Z","shell.execute_reply":"2025-12-12T07:38:12.899455Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cm = confusion_matrix(label_list, prediction_list)\nplt.figure(figsize=(5, 5))\nsns.heatmap(cm, annot=True, fmt='d', cmap='Greens', cbar=False, linewidth=1, linecolor='white')\nplt.xlabel('Predicted labels')\nplt.ylabel('True labels')\nplt.title('Confusion Matrix')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-12T07:38:12.901384Z","iopub.execute_input":"2025-12-12T07:38:12.901695Z","iopub.status.idle":"2025-12-12T07:38:13.078206Z","shell.execute_reply.started":"2025-12-12T07:38:12.901668Z","shell.execute_reply":"2025-12-12T07:38:13.077504Z"}},"outputs":[],"execution_count":null}]}