{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":25563,"databundleVersionId":2094376,"sourceType":"competition"}],"dockerImageVersionId":30627,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as Fn\nfrom torch.utils.data import TensorDataset\nfrom sklearn.model_selection import train_test_split\nfrom scipy.io import savemat\nfrom time import time\nfrom sklearn.metrics import roc_auc_score\nimport torch.optim as optim\nimport os\nimport torchvision\nimport pandas as pd\n\nfrom PIL import Image\n\n\nimport warnings\n# Ignore all warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:37.982876Z","iopub.execute_input":"2024-03-28T22:43:37.983129Z","iopub.status.idle":"2024-03-28T22:43:43.530578Z","shell.execute_reply.started":"2024-03-28T22:43:37.983105Z","shell.execute_reply":"2024-03-28T22:43:43.529719Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"INTRODUCTION:\n\nThis notebook deals with Classification of the disease of plants using the 'Plant Pathology 2021 - FGVC8' Dataset. \n\nThe goal of this notebook is to train a neural network on the train-image dataset and used that trained network to correctly predict the disease of the test images.\n\n**********************************************************************************************","metadata":{}},{"cell_type":"code","source":"# Set device (CPU or GPU)\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\ndevice","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:43.532462Z","iopub.execute_input":"2024-03-28T22:43:43.533281Z","iopub.status.idle":"2024-03-28T22:43:43.596190Z","shell.execute_reply.started":"2024-03-28T22:43:43.533227Z","shell.execute_reply":"2024-03-28T22:43:43.595227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#!pip install cloud-tpu-client==0.10 https://storage.googleapis.com/tpu-pytorch/wheels/torch_xla-1.10-cp37-cp37m-linux_x86_64.whl\n","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:43.597696Z","iopub.execute_input":"2024-03-28T22:43:43.598478Z","iopub.status.idle":"2024-03-28T22:43:43.605918Z","shell.execute_reply.started":"2024-03-28T22:43:43.598441Z","shell.execute_reply":"2024-03-28T22:43:43.605035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#import torch\n\n# Set device to TPU\n#device = xm.xla_device()\n","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:43.607834Z","iopub.execute_input":"2024-03-28T22:43:43.608121Z","iopub.status.idle":"2024-03-28T22:43:43.617086Z","shell.execute_reply.started":"2024-03-28T22:43:43.608097Z","shell.execute_reply":"2024-03-28T22:43:43.616174Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"DATASETS PROVIDED:\n\n\nHere the image data is provided in two directories \n\n(1) train_images : contains 18632 .jpg images\n\n(2) test_images : contains 3  .jpg images\n\n(3) train.csv : a csv file containing two columns providing the train image filename and the disease labels\n\n************************************************************************************","metadata":{}},{"cell_type":"code","source":"train_path='/kaggle/input/plant-pathology-2021-fgvc8/train.csv'\n\ntrain_dir ='/kaggle/input/plant-pathology-2021-fgvc8/train_images'\ntest_dir='/kaggle/input/plant-pathology-2021-fgvc8/test_images'\n\ntrain=pd.read_csv(train_path)\n\n\nprint(f'Number of images = {len(train)}')\n\ntrain.head(4)","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:43.618931Z","iopub.execute_input":"2024-03-28T22:43:43.619515Z","iopub.status.idle":"2024-03-28T22:43:43.672163Z","shell.execute_reply.started":"2024-03-28T22:43:43.619481Z","shell.execute_reply":"2024-03-28T22:43:43.671376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plotting one image\n\ni=0\n\nname_img = train.iloc[i, 0]\nlabel_name_img=train.iloc[i,1]\n\nimg = Image.open(os.path.join(train_dir, name_img[:-4]+\".jpg\"))\nplt.imshow(img)\nplt.title(label_name_img)","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:43.673175Z","iopub.execute_input":"2024-03-28T22:43:43.673452Z","iopub.status.idle":"2024-03-28T22:43:46.259517Z","shell.execute_reply.started":"2024-03-28T22:43:43.673429Z","shell.execute_reply":"2024-03-28T22:43:46.258622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The images are seen to be really big in size so I transformed them into smaller 128 x 128 size to handle easily","metadata":{}},{"cell_type":"code","source":"img=np.array(img)\nimg.shape","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:46.260563Z","iopub.execute_input":"2024-03-28T22:43:46.260830Z","iopub.status.idle":"2024-03-28T22:43:46.331400Z","shell.execute_reply.started":"2024-03-28T22:43:46.260807Z","shell.execute_reply":"2024-03-28T22:43:46.330222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"CATEGORIES OF DISEASE:\n\nWe can observe there are 12 categories of disease.\n\nAlthough the count plot shows that there exists an imbalance between the categories, so usual cross-entropy loss would not be a good fit for the loss function, since it is biased towards the dominant classes.\n\n********************************************************************************************","metadata":{}},{"cell_type":"code","source":"# plot of label categories\n\n# Count the occurrences of each category\ncategory_counts = train['labels'].value_counts()\nprint(category_counts)\nprint(f\"number of categories={len(category_counts)}\")\n\ncategory_counts.index","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:46.333344Z","iopub.execute_input":"2024-03-28T22:43:46.333887Z","iopub.status.idle":"2024-03-28T22:43:46.352205Z","shell.execute_reply.started":"2024-03-28T22:43:46.333852Z","shell.execute_reply":"2024-03-28T22:43:46.351275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train['labels'].value_counts().plot(kind='bar')\nplt.suptitle('Count Plot of different disease category')","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:46.353428Z","iopub.execute_input":"2024-03-28T22:43:46.353770Z","iopub.status.idle":"2024-03-28T22:43:46.696444Z","shell.execute_reply.started":"2024-03-28T22:43:46.353737Z","shell.execute_reply":"2024-03-28T22:43:46.695479Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"IMAGES of leaves belonging to DIFFERENT CATEGORIES\n\n************************************************************","metadata":{}},{"cell_type":"code","source":"# Function to display images belonging to a class:\n\ndef show_image(class_name, examples):\n    image_list=train[train['labels']==class_name]['image'][0:examples].to_list()\n    \n    \n    plt.figure(figsize=(20, 10))\n    \n    for i in range(0,len(image_list)):\n        name_img = image_list[i]\n        img = Image.open(os.path.join(train_dir, name_img[:-4]+\".jpg\"))\n        img.resize ((128,128),resample=Image.BICUBIC)\n        \n    \n        plt.subplot(1 ,examples, i%examples +1)\n        plt.imshow(img)\n        plt.title(class_name)\n        plt.axis('off')\n    \n        \n#show_image('healthy',3)    \n    ","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:46.700099Z","iopub.execute_input":"2024-03-28T22:43:46.700419Z","iopub.status.idle":"2024-03-28T22:43:46.707753Z","shell.execute_reply.started":"2024-03-28T22:43:46.700393Z","shell.execute_reply":"2024-03-28T22:43:46.706735Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_list=['scab', 'healthy', 'frog_eye_leaf_spot', 'rust', 'complex',\n       'powdery_mildew', 'scab frog_eye_leaf_spot',\n       'scab frog_eye_leaf_spot complex', 'frog_eye_leaf_spot complex',\n       'rust frog_eye_leaf_spot', 'rust complex', 'powdery_mildew complex']\n\nfor k in range(0,len(class_list)):\n    class_name=class_list[k]\n    show_image(class_name,2)","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:43:46.708920Z","iopub.execute_input":"2024-03-28T22:43:46.709229Z","iopub.status.idle":"2024-03-28T22:44:46.979882Z","shell.execute_reply.started":"2024-03-28T22:43:46.709202Z","shell.execute_reply":"2024-03-28T22:44:46.978913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"MODELS CONSIDERED:\n****************************************************************","metadata":{}},{"cell_type":"markdown","source":"Data Transformation: \n\nSince the images are really big in size I used the following function to reduce them to 128 x 128 and also transform them into tensors\n","metadata":{}},{"cell_type":"code","source":"#transform all the training data into tensors \n\nfrom torch.utils.data import DataLoader\n\nimport os\nimport torch\nfrom torchvision import transforms,datasets\n\nfrom PIL import Image\nfrom torchvision.transforms import Compose, Resize, CenterCrop, RandomCrop,ToTensor, Normalize, Grayscale, RandomRotation,InterpolationMode\nfrom torchvision.transforms.v2 import  RandomResize\n\n# Define data transformations\ntransform = Compose([\n    Resize([128, 128],interpolation=InterpolationMode.BICUBIC),\n    ToTensor()\n    ])","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:44:46.981183Z","iopub.execute_input":"2024-03-28T22:44:46.981538Z","iopub.status.idle":"2024-03-28T22:44:47.023078Z","shell.execute_reply.started":"2024-03-28T22:44:46.981501Z","shell.execute_reply":"2024-03-28T22:44:47.022403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"MODEL 1: \n\nThe first model I considered is a CNN model with four layers described as below\n\n*********************************************************************************************","metadata":{}},{"cell_type":"markdown","source":"CNN model:\n\nlayer 1 :conv-relu-maxpool-dropout \n\nlayer 2 :conv-relu-maxpool-dropout \n\nlayer 3 :conv-relu-maxpool-dropout \n\nlayer 4 :conv-relu-maxpool-dropout \n\n*********************************************************************************\n","metadata":{}},{"cell_type":"markdown","source":"\nCUSTOM DATASET to preprocess the data for the model\n*********************************************************\n\ntrain.csv : contains the image names and labels\n\ntrain_dir : contains the images\n\nCustom Dataset returns the image_tensor and the corresponding text_labels","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nfrom torch.utils.data import Dataset\nfrom PIL import Image\nfrom torchvision import transforms\n\nclass CustomTextLabelDataset(Dataset):\n    def __init__(self, csv_path, image_dir, transform=None):\n        self.csv_path = csv_path\n        self.images_root = image_dir\n        self.transform = transform\n        self.data = self.load_data()\n\n    def load_data(self):\n        # Load data from the CSV file\n        df = pd.read_csv(self.csv_path)\n\n        # Combine filename and label information\n        data = [{'filename': row['image'], 'label': row['labels']} for _, row in df.iterrows()]\n\n        return data\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, index):\n        entry = self.data[index]\n        image_path = os.path.join(self.images_root, entry['filename'])\n        text_label = entry['label']\n\n        # Load image\n        image = Image.open(image_path)\n\n        # Apply transformations\n        if self.transform:\n            image = self.transform(image)\n\n        return image, text_label\n","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:44:47.024201Z","iopub.execute_input":"2024-03-28T22:44:47.024560Z","iopub.status.idle":"2024-03-28T22:44:47.033046Z","shell.execute_reply.started":"2024-03-28T22:44:47.024525Z","shell.execute_reply":"2024-03-28T22:44:47.032172Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Specify the path to CSV file and images directory:\ncsv_path = '/kaggle/input/plant-pathology-2021-fgvc8/train.csv'\nimages_root = '/kaggle/input/plant-pathology-2021-fgvc8/train_images'\n\n## dataset:\nfull_dataset = CustomTextLabelDataset(csv_path=csv_path, image_dir=images_root, transform=transform)\n\n","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:44:47.034228Z","iopub.execute_input":"2024-03-28T22:44:47.034560Z","iopub.status.idle":"2024-03-28T22:44:48.222023Z","shell.execute_reply.started":"2024-03-28T22:44:47.034535Z","shell.execute_reply":"2024-03-28T22:44:48.221222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#access label\nfull_dataset[0][1]","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:44:48.223100Z","iopub.execute_input":"2024-03-28T22:44:48.223367Z","iopub.status.idle":"2024-03-28T22:44:48.420303Z","shell.execute_reply.started":"2024-03-28T22:44:48.223344Z","shell.execute_reply":"2024-03-28T22:44:48.419325Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"LOSS FUNCTION: FOCAL LOSS\n*******************************************************\n\nSince we have a pretty significant imbalance in the category counts the classic cross entropy loss would show that less frequent classes will having a more significant loss.\n\n\nFocal Loss is a modification of the standard cross-entropy loss, designed to address the problem of class imbalance in binary and multi-class classification tasks. \nThe focal loss is a finetuned cross-entropy loss that puts emphasis on classes with a high loss and give less importance to classes with low loss. This regularisation term pushes the model to focus on learning rare classes and put less emphasis on dominant classes.\nIt was introduced in the paper titled \"Focal Loss for Dense Object Detection\" by Tsung-Yi Lin, Priya Goyal, Ross Girshick, Kaiming He, and Piotr Dollár.\n\nThe Focal Loss (FL) is defined as follows:\n\nhttps://doi.org/10.48550/arXiv.1708.02002","metadata":{}},{"cell_type":"markdown","source":"********************************\nThe CNN model with four layers explained earlier\n","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\n\nclass CNN_model(nn.Module):\n    def __init__(self, num_classes):\n        super(CNN_model, self).__init__()\n        \n        #### 1st Convolutional Layer\n        self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)\n        # ReLU activation\n        self.relu1 = nn.ReLU()\n        # Max-pooling layer\n        self.maxpool1 = nn.MaxPool2d(kernel_size=2, stride=2)\n\n        #### 2nd Convolutional Layer\n        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)\n        # ReLU activation\n        self.relu2 = nn.ReLU()\n        # Max-pooling layer\n        self.maxpool2 = nn.MaxPool2d(kernel_size=2, stride=2)\n\n        #### 3rd Convolutional Layer\n        self.conv3 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)\n        # ReLU activation\n        self.relu3 = nn.ReLU()\n        # Max-pooling layer\n        self.maxpool3 = nn.MaxPool2d(kernel_size=2, stride=2)\n\n        #### 4th Convolutional Layer\n        self.conv4 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)\n        # ReLU activation\n        self.relu4 = nn.ReLU()\n        # Max-pooling layer\n        self.maxpool4 = nn.MaxPool2d(kernel_size=2, stride=2)\n\n        ### Fully Connected Layer\n        self.fc = nn.Linear(128 * 8 * 8, num_classes)\n\n    def forward(self, x):\n        x = self.maxpool1(self.relu1(self.conv1(x)))\n        x = self.maxpool2(self.relu2(self.conv2(x)))\n        x = self.maxpool3(self.relu3(self.conv3(x)))\n        x = self.maxpool4(self.relu4(self.conv4(x)))\n        x = x.view(x.size(0), -1)\n        x = self.fc(x)\n        return x\n\n\nnum_classes = 12  # we have 12 classes here\nmodel = CNN_model(num_classes)\n\nmodel\n","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:44:48.421718Z","iopub.execute_input":"2024-03-28T22:44:48.422240Z","iopub.status.idle":"2024-03-28T22:44:48.446341Z","shell.execute_reply.started":"2024-03-28T22:44:48.422205Z","shell.execute_reply":"2024-03-28T22:44:48.445424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"An IMPLEMENTATION OF FOCAL LOSS function using Pytorch:\n******************************************\n\nhere, \n\nalpha = balancing factor to handle the class imbalance computed sample wise\n\ngamma =  a focusing parameter that allows the model to down-weight easy examples\n\nalpha and gamma are hyperparameters that can be adjusted based on specific problem and dataset. The reduction parameter specifies how the losses from individual samples should be aggregated.\n\nReturns average focul loss from all the samples","metadata":{}},{"cell_type":"code","source":"\nimport torch.nn.functional as F\n\nclass FocalLoss(nn.Module):\n    def __init__(self, alpha=None, gamma=2, reduction='mean'):\n        super(FocalLoss, self).__init__()\n        self.alpha = alpha\n        self.gamma = gamma\n        self.reduction = reduction\n\n    def forward(self, inputs, targets):\n        ce_loss = F.cross_entropy(inputs, targets, reduction='none')\n        \n        #focul loss \n        pt = torch.exp(-ce_loss)\n        focal_loss = self.alpha*(1 - pt) ** self.gamma * ce_loss\n        \n        #if self.alpha is not None:\n            #alpha_factor = self.alpha[targets]\n            #focal_loss = focal_loss * alpha_factor\n\n\n        # Apply reduction\n        if self.reduction == 'mean':\n            return focal_loss.mean()\n        elif self.reduction == 'sum':\n            return focal_loss.sum()\n        elif self.reduction == 'none':\n            return focal_loss\n        else:\n            raise ValueError(\"Invalid reduction option. Use 'mean', 'sum', or 'none'.\")\n","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:44:48.447616Z","iopub.execute_input":"2024-03-28T22:44:48.447884Z","iopub.status.idle":"2024-03-28T22:44:48.455431Z","shell.execute_reply.started":"2024-03-28T22:44:48.447860Z","shell.execute_reply":"2024-03-28T22:44:48.454486Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Since the labels are given in text format I made a mapping to turn text into numerics and vice-versa\n*********************","metadata":{}},{"cell_type":"code","source":"# Create a mapping between text labels and numerical indices\nunique_text_labels = class_list\nlabel_to_index = {label: index for index, label in enumerate(unique_text_labels)}\nindex_to_label = {index: label for label, index in label_to_index.items()}\n","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:44:48.456602Z","iopub.execute_input":"2024-03-28T22:44:48.456947Z","iopub.status.idle":"2024-03-28T22:44:48.470649Z","shell.execute_reply.started":"2024-03-28T22:44:48.456912Z","shell.execute_reply":"2024-03-28T22:44:48.469811Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"TRAINING ON train_images:\n*************************************************************************************************\nUsed Adam optimizer with learning rate 0.01.\n\n\nthe model is saved locally at 'cnn_model.pth'","metadata":{}},{"cell_type":"code","source":"from torch.utils.data import DataLoader, random_split\n#from torch.optim.lr_scheduler import StepLR\n\n# Define the focal loss function and optimizer:\ncriterion = FocalLoss(gamma=2, alpha=1)\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n#step_scheduler = StepLR(optimizer, step_size=30, gamma=0.1)\n\n# Wrap model and optimizer with XLA\n#model, optimizer = xm.initialize_model(model, optimizer, opt_level=\"O2\")\n\n\n# Split the dataset into training and validation sets: 80:20\ntrain_size = int(0.8 * len(full_dataset))\nval_size = len(full_dataset) - train_size\ntrain_dataset, val_dataset = random_split(full_dataset, [train_size, val_size])\nprint(len(train_dataset))\n\n# Create data loaders for training and validation\nbatch_size = 32\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\nprint(len(train_loader))\n\n\n# Use GPU for model\nmodel.to(device)\n\n\nepochs = 10\n\nfor epoch in range(epochs):\n    \n    ## Training loop:\n    \n    model.train()  # Set the model to training mode\n    \n    #run=0\n    for inputs, text_labels in train_loader:\n        inputs, text_labels = inputs.to(device), text_labels\n        \n        #print('input',inputs)\n        #print('text_labels',text_labels)\n        #print(inputs.shape)\n        \n        # Convert text labels to numerical indices using the mapping\n        numerical_labels = [label_to_index[label] for label in text_labels]\n        #print((numerical_labels))\n        \n        optimizer.zero_grad()  # Zero the gradients\n        outputs = model(inputs)  # Forward pass\n        #print(outputs.shape)\n        #print(torch.tensor(numerical_labels).shape)\n        \n        loss=criterion(outputs, torch.tensor(numerical_labels).to(device))  # Focal Loss\n        \n        \n        loss.backward()  # Backward pass\n        optimizer.step()  # Update the weights\n        \n        #print(f'{run}run done')\n        #run=run+1\n        \n    #print(f'train loss for {epoch+1} epoch = {loss:0.3f} ')\n    \n    ###Validation loop:\n    \n    model.eval()  # Set to evaluation mode\n    correct = 0\n    total = 0\n    \n    with torch.no_grad():\n        for inputs, text_labels in val_loader:\n            inputs, text_labels = inputs.to(device), text_labels\n            \n            \n            numerical_labels = [label_to_index[label] for label in text_labels]\n            numerical_labels=torch.tensor(numerical_labels).to(device)\n            \n            outputs = model(inputs)\n            _, predicted = torch.max(outputs.data, 1)\n            total += len(numerical_labels)\n            correct += (predicted == numerical_labels).sum().item()\n            \n            #step_scheduler.step()\n    \n    accuracy = correct / total\n    print(f'Epoch {epoch+1}/{epochs}, Train Set Loss: {loss.item():.4f}, Validation Set Accuracy: {accuracy:.4f}')\n\n\n","metadata":{"execution":{"iopub.status.busy":"2024-03-28T22:44:48.471730Z","iopub.execute_input":"2024-03-28T22:44:48.471980Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Save the trained model:\ntorch.save(model.state_dict(), 'cnn_model.pth')\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"PREDICTION ON TEST IMAGES:\n\n*****************************************************************************","metadata":{}},{"cell_type":"code","source":"### On test data:\n\n#Step 1:\n\n# Load the saved model state dict\nmodel.load_state_dict(torch.load('/kaggle/working/cnn_model.pth'))\n\n# Set the model to evaluation mode\nmodel.eval()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n# Step 2: Prepare Test Data\ntest_dir = '/kaggle/input/plant-pathology-2021-fgvc8/test_images'\n\nos.listdir(test_dir)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for filename in os.listdir(test_dir):\n    img_path=os.path.join(test_dir,filename)\n    img=Image.open(img_path)\n    plt.imshow(img)\n    plt.show()\n    img_tensor=transform(img).unsqueeze(0)\n    #print(img_tensor.shape)\n    \n    with torch.no_grad():\n        \n        pred=model(img_tensor.to(device))\n        #print(pred.shape)\n        \n        predicted_class = torch.argmax(pred).item()\n        predicted_text_class=index_to_label[predicted_class]\n        print(f\"Image: {filename}, Predicted Class: {predicted_text_class}\")\n    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Model 2:\n\nCNN:\n\n4 layers like Model 1 with a dropout at the end\n\n****************************************************************************************","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\n\nclass CNN_model_dropout(nn.Module):\n    def __init__(self, num_classes):\n        super(CNN_model_dropout, self).__init__()\n        \n        #### 1st Convolutional Layer\n        self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)\n        # ReLU activation\n        self.relu1 = nn.ReLU()\n        # Max-pooling layer\n        self.maxpool1 = nn.MaxPool2d(kernel_size=2, stride=2)\n        self.dropout1 = nn.Dropout(0.25)\n\n        #### 2nd Convolutional Layer\n        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)\n        # ReLU activation\n        self.relu2 = nn.ReLU()\n        # Max-pooling layer\n        self.maxpool2 = nn.MaxPool2d(kernel_size=2, stride=2)\n        self.dropout2 = nn.Dropout(0.25)\n        \n\n        #### 3rd Convolutional Layer\n        self.conv3 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)\n        # ReLU activation\n        self.relu3 = nn.ReLU()\n        # Max-pooling layer\n        self.maxpool3 = nn.MaxPool2d(kernel_size=2, stride=2)\n        self.dropout3 = nn.Dropout(0.25)\n\n        #### 4th Convolutional Layer\n        self.conv4 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)\n        # ReLU activation\n        self.relu4 = nn.ReLU()\n        # Max-pooling layer\n        self.maxpool4 = nn.MaxPool2d(kernel_size=2, stride=2)\n        self.dropout4 = nn.Dropout(0.25)\n\n        ### Fully Connected Layer\n        self.fc = nn.Linear(128 * 8 * 8, num_classes)\n\n    def forward(self, x):\n        x = self.maxpool1(self.relu1(self.conv1(x)))\n        x = self.maxpool2(self.relu2(self.conv2(x)))\n        x = self.maxpool3(self.relu3(self.conv3(x)))\n        x = self.maxpool4(self.relu4(self.conv4(x)))\n        x = x.view(x.size(0), -1)\n        x = self.fc(x)\n        return x\n\n\nnum_classes = 12  # we have 12 classes here\nmodel = CNN_model(num_classes)\n\nmodel","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import DataLoader, random_split\n#from torch.optim.lr_scheduler import StepLR\n\n# Define the focal loss function and optimizer:\ncriterion = FocalLoss(gamma=2, alpha=1)\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n#step_scheduler = StepLR(optimizer, step_size=30, gamma=0.1)\n\n# Wrap model and optimizer with XLA\n#model, optimizer = xm.initialize_model(model, optimizer, opt_level=\"O2\")\n\n\n# Split the dataset into training and validation sets: 80:20\ntrain_size = int(0.8 * len(full_dataset))\nval_size = len(full_dataset) - train_size\ntrain_dataset, val_dataset = random_split(full_dataset, [train_size, val_size])\nprint(len(train_dataset))\n\n# Create data loaders for training and validation\nbatch_size = 32\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\nprint(len(train_loader))\n\n\n# Use GPU for model\nmodel.to(device)\n\n\nepochs = 8\n\nfor epoch in range(epochs):\n    \n    ## Training loop:\n    \n    model.train()  # Set the model to training mode\n    \n    #run=0\n    for inputs, text_labels in train_loader:\n        inputs, text_labels = inputs.to(device), text_labels\n        \n        #print('input',inputs)\n        #print('text_labels',text_labels)\n        #print(inputs.shape)\n        \n        # Convert text labels to numerical indices using the mapping\n        numerical_labels = [label_to_index[label] for label in text_labels]\n        #print((numerical_labels))\n        \n        optimizer.zero_grad()  # Zero the gradients\n        outputs = model(inputs)  # Forward pass\n        #print(outputs.shape)\n        #print(torch.tensor(numerical_labels).shape)\n        \n        loss=criterion(outputs, torch.tensor(numerical_labels).to(device))  # Focal Loss\n        \n        \n        loss.backward()  # Backward pass\n        optimizer.step()  # Update the weights\n        \n        #print(f'{run}run done')\n        #run=run+1\n        \n    #print(f'train loss for {epoch+1} epoch = {loss:0.3f} ')\n    \n    ###Validation loop:\n    \n    model.eval()  # Set to evaluation mode\n    correct = 0\n    total = 0\n    \n    with torch.no_grad():\n        for inputs, text_labels in val_loader:\n            inputs, text_labels = inputs.to(device), text_labels\n            \n            \n            numerical_labels = [label_to_index[label] for label in text_labels]\n            numerical_labels=torch.tensor(numerical_labels).to(device)\n            \n            outputs = model(inputs)\n            _, predicted = torch.max(outputs.data, 1)\n            total += len(numerical_labels)\n            correct += (predicted == numerical_labels).sum().item()\n            \n            #step_scheduler.step()\n    \n    accuracy = correct / total\n    print(f'Epoch {epoch+1}/{epochs}, Train Set Loss: {loss.item():.4f}, Validation Set Accuracy: {accuracy:.4f}')\n\n\n    \n## Save the trained model:\ntorch.save(model.state_dict(), 'cnn_model_dropout.pth')\n   ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"### On test data:\n\n#Step 1:\n\n# Load the saved model state dict\nmodel.load_state_dict(torch.load('/kaggle/working/cnn_model_dropout.pth'))\n\n# Set the model to evaluation mode\nmodel.eval()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for filename in os.listdir(test_dir):\n    img_path=os.path.join(test_dir,filename)\n    img=Image.open(img_path)\n    plt.imshow(img)\n    plt.show()\n    img_tensor=transform(img).unsqueeze(0)\n    #print(img_tensor.shape)\n    \n    with torch.no_grad():\n        \n        pred=model(img_tensor.to(device))\n        #print(pred.shape)\n        \n        predicted_class = torch.argmax(pred).item()\n        predicted_text_class=index_to_label[predicted_class]\n        print(f\"Image: {filename}, Predicted Class: {predicted_text_class}\")\n    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}