{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"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":"none","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":30626,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Kaggle link: https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition\nMy Kaggle Link: https://www.kaggle.com/code/revathimuthukrishnan/dog-vs-cat/\nMy WandDb Link: https://wandb.ai/revathimuthukrishnan/DogVsCat","metadata":{}},{"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 # OS module in python provides functions for interacting with the operating system\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":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.status.busy":"2024-01-16T05:27:51.869225Z","iopub.execute_input":"2024-01-16T05:27:51.869598Z","iopub.status.idle":"2024-01-16T05:27:52.522132Z","shell.execute_reply.started":"2024-01-16T05:27:51.869570Z","shell.execute_reply":"2024-01-16T05:27:52.521214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Import everything needed","metadata":{}},{"cell_type":"code","source":"import zipfile\nimport glob\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport time\nfrom sklearn.model_selection import train_test_split\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader, Dataset\nfrom torchvision import datasets, transforms\nnp.random.seed(0)\ntorch.manual_seed(0)\ntorch.cuda.manual_seed(0)\nimport wandb\nwandb.init(project='DogVsCat', save_code=True)","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:27:52.523746Z","iopub.execute_input":"2024-01-16T05:27:52.524076Z","iopub.status.idle":"2024-01-16T05:28:33.166272Z","shell.execute_reply.started":"2024-01-16T05:27:52.524027Z","shell.execute_reply":"2024-01-16T05:28:33.165221Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Unzip datasets","metadata":{}},{"cell_type":"code","source":"train_dir = 'train'\ntest_dir = 'test'\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip') as train_zip:\n    train_zip.extractall('')\n    \nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip') as test_zip:\n    test_zip.extractall('')\ntrain_list = glob.glob(os.path.join(train_dir,'*.jpg'))\ntest_list = glob.glob(os.path.join(test_dir, '*.jpg'))\nprint(f\"Train Data: {len(train_list)}\")\nprint(f\"Test Data: {len(test_list)}\")","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:33.167611Z","iopub.execute_input":"2024-01-16T05:28:33.168420Z","iopub.status.idle":"2024-01-16T05:28:44.761336Z","shell.execute_reply.started":"2024-01-16T05:28:33.168383Z","shell.execute_reply":"2024-01-16T05:28:44.760240Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = [path.split('/')[-1].split('.')[0] for path in train_list]","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:44.763912Z","iopub.execute_input":"2024-01-16T05:28:44.764252Z","iopub.status.idle":"2024-01-16T05:28:44.784390Z","shell.execute_reply.started":"2024-01-16T05:28:44.764226Z","shell.execute_reply":"2024-01-16T05:28:44.783352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Plot random image with their label","metadata":{}},{"cell_type":"code","source":"random_idx = np.random.randint(1, len(train_list), size=9)\nfig, axes = plt.subplots(3, 3, figsize=(16, 12))\n\nfor idx, ax in enumerate(axes.ravel()):\n    img = Image.open(train_list[idx])\n    ax.set_title(labels[idx])\n    ax.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:44.785555Z","iopub.execute_input":"2024-01-16T05:28:44.785828Z","iopub.status.idle":"2024-01-16T05:28:47.539478Z","shell.execute_reply.started":"2024-01-16T05:28:44.785803Z","shell.execute_reply":"2024-01-16T05:28:47.538129Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Use Sklearn to split the training data","metadata":{}},{"cell_type":"code","source":"train_list, valid_list = train_test_split(train_list, \n                                          test_size=0.2,\n                                          stratify=labels,\n                                          random_state=0)","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:47.541410Z","iopub.execute_input":"2024-01-16T05:28:47.541708Z","iopub.status.idle":"2024-01-16T05:28:47.574047Z","shell.execute_reply.started":"2024-01-16T05:28:47.541680Z","shell.execute_reply":"2024-01-16T05:28:47.573090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Train Data: {len(train_list)}\")\nprint(f\"Validation Data: {len(valid_list)}\")\nprint(f\"Test Data: {len(test_list)}\")","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:47.575447Z","iopub.execute_input":"2024-01-16T05:28:47.575744Z","iopub.status.idle":"2024-01-16T05:28:47.582943Z","shell.execute_reply.started":"2024-01-16T05:28:47.575718Z","shell.execute_reply":"2024-01-16T05:28:47.581858Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We will discuss this in more detail in a near future...","metadata":{}},{"cell_type":"code","source":"train_transforms = transforms.Compose([\n    # TODO: define traininig augmentations \n    transforms.Resize(256),  # Resize the image to a fixed size\n    transforms.CenterCrop(224),  # Crop the center of the image\n    transforms.RandomHorizontalFlip(),  # Randomly flip the image horizontally\n    #transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2),  # Adjust color jitter\n    transforms.RandomRotation(degrees=20),  # Randomly rotate the image    \n    #transforms.ToPILImage(),\n    #transforms.Grayscale(num_output_channels=1),\n    transforms.ToTensor(), \n    #MobileNet Mean: [0.485, 0.456, 0.406] Standard Deviation (std): [0.229, 0.224, 0.225]\n    transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225))\n])\n\ntest_transforms = transforms.Compose([\n    # TODO: define test augmentations\n    transforms.Resize(256),  # Resize the image to a fixed size\n    transforms.CenterCrop(224),  # Crop the center of the image\n    #transforms.ToPILImage(),\n    #transforms.Grayscale(num_output_channels=1),\n    transforms.ToTensor(), \n    transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225))\n])","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:47.584672Z","iopub.execute_input":"2024-01-16T05:28:47.585251Z","iopub.status.idle":"2024-01-16T05:28:47.593103Z","shell.execute_reply.started":"2024-01-16T05:28:47.585217Z","shell.execute_reply":"2024-01-16T05:28:47.592089Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using device: {device}\")","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:47.594489Z","iopub.execute_input":"2024-01-16T05:28:47.594779Z","iopub.status.idle":"2024-01-16T05:28:47.604989Z","shell.execute_reply.started":"2024-01-16T05:28:47.594748Z","shell.execute_reply":"2024-01-16T05:28:47.604111Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Define the dataset using PIL to read image","metadata":{}},{"cell_type":"code","source":"class CatsDogsDataset(Dataset):\n    def __init__(self, file_list, transform=None):\n        self.file_list = file_list\n        self.transform = transform\n        self.filelength = len(file_list)\n\n    def __len__(self):\n        return self.filelength\n\n    def __getitem__(self, idx):\n        img_path = self.file_list[idx]\n        img = Image.open(img_path)\n        img_transformed = self.transform(img).to(device)\n        label = img_path.split(\"/\")[-1].split(\".\")[0]\n        label = 1 if label == \"dog\" else 0\n        return img_transformed, label","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:47.609133Z","iopub.execute_input":"2024-01-16T05:28:47.609390Z","iopub.status.idle":"2024-01-16T05:28:47.616488Z","shell.execute_reply.started":"2024-01-16T05:28:47.609366Z","shell.execute_reply":"2024-01-16T05:28:47.615578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data = CatsDogsDataset(train_list, transform=train_transforms)\nvalid_data = CatsDogsDataset(valid_list, transform=test_transforms)\ntest_data = CatsDogsDataset(test_list, transform=test_transforms)","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:47.617642Z","iopub.execute_input":"2024-01-16T05:28:47.617915Z","iopub.status.idle":"2024-01-16T05:28:47.624962Z","shell.execute_reply.started":"2024-01-16T05:28:47.617890Z","shell.execute_reply":"2024-01-16T05:28:47.623995Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Create dataloader, you can modify the batch size if needed","metadata":{}},{"cell_type":"code","source":"batch_size = 32\ntest_batch_size = 32\ntrain_loader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)\nvalid_loader = DataLoader(dataset=valid_data, batch_size=batch_size, shuffle=False)\ntest_loader = DataLoader(dataset=test_data, batch_size=test_batch_size, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:47.626416Z","iopub.execute_input":"2024-01-16T05:28:47.626687Z","iopub.status.idle":"2024-01-16T05:28:47.634563Z","shell.execute_reply.started":"2024-01-16T05:28:47.626663Z","shell.execute_reply":"2024-01-16T05:28:47.633600Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create a new dataset with only the transform applied\ntransformed_dataset = CatsDogsDataset(train_list, transform=train_transforms)\n\n# Create a data loader for the transformed dataset\ntransformed_loader = DataLoader(dataset=transformed_dataset, batch_size=9, shuffle=True)\n\n# Fetch a batch of transformed images\ntransformed_batch, transformed_labels = next(iter(transformed_loader))\n\n# Move the batch to CPU if it's on GPU\ntransformed_batch_cpu = transformed_batch.cpu()\n\n# Convert the batch to NumPy array\ntransformed_np = transformed_batch_cpu.numpy()\n\n# Plot the transformed images\nfig, axes = plt.subplots(3, 3, figsize=(16, 12))\n\n# Define the denormalization parameters\ndenorm_mean = np.array([0.485, 0.456, 0.406])\ndenorm_std = np.array([0.229, 0.224, 0.225])\n\nfor i in range(9):\n    ax = axes.ravel()[i]\n    img = transformed_np[i].transpose(1, 2, 0)  # Transpose to (H, W, C) for displaying with matplotlib\n    \n    # Denormalize the image using new mean and std values\n    img = img * denorm_std + denorm_mean\n    \n    ax.set_title(transformed_labels[i].item())\n    ax.imshow(img)\n    \nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:47.635947Z","iopub.execute_input":"2024-01-16T05:28:47.636257Z","iopub.status.idle":"2024-01-16T05:28:49.894424Z","shell.execute_reply.started":"2024-01-16T05:28:47.636232Z","shell.execute_reply":"2024-01-16T05:28:49.892139Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# TODO: define a convolutional neural network, train it and output the log \nclass SimpleCNN(nn.Module):\n    def __init__(self):\n        super(SimpleCNN, self).__init__()\n        # Convolutional layers\n        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1)\n        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)\n        self.conv3 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)\n        # Max pooling layer\n        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)\n        # Fully connected layers\n        self.fc1 = nn.Linear(128 * 28 * 28, 512)\n        self.dropout = nn.Dropout(0.5)\n        self.fc2 = nn.Linear(512, 2)  # Output size is 2 for binary classification (cat vs. dog)\n\n    def forward(self, x):\n        # Convolutional layers with ReLU activation and max pooling\n        x = self.pool(F.relu(self.conv1(x)))\n        x = self.pool(F.relu(self.conv2(x)))\n        x = self.pool(F.relu(self.conv3(x)))\n        # Flatten the output for the fully connected layers\n        x = x.view(-1, 128 * 28 * 28)\n        # Fully connected layers with ReLU activation\n        x = F.relu(self.fc1(x))\n        # Output layer (no activation function here, as it's handled later during training)\n        #x = self.fc2(x)\n        x = self.dropout(x)\n        x = F.softmax(self.fc2(x), dim=1)\n        return x\n","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:49.895857Z","iopub.execute_input":"2024-01-16T05:28:49.896626Z","iopub.status.idle":"2024-01-16T05:28:49.909454Z","shell.execute_reply.started":"2024-01-16T05:28:49.896591Z","shell.execute_reply":"2024-01-16T05:28:49.908332Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Instantiate the model\nmodel = SimpleCNN()\nmodel.to(device)\n\n# Define loss function and optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.0001)\n\n# Training parameters\nnum_epochs = 40\ntrain_losses = []\ntrain_accuracies = []\nval_losses = []\nval_accuracies = []\n\n# Training loop\nfor epoch in range(num_epochs):\n    model.train()\n    running_loss = 0.0\n    correct_train = 0\n    total_train = 0\n    start_time = time.time() \n    print(f'Epoch [{epoch + 1}/{num_epochs}]')\n    for inputs, labels in train_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        running_loss += loss.item()\n        \n        # Calculate accuracy\n        _, predicted = torch.max(outputs.data, 1)\n        total_train += labels.size(0)\n        correct_train += (predicted == labels).sum().item()\n\n    # Print training loss at the end of each epoch\n    end_time = time.time()  # Record the end time for the epoch\n    epoch_time = end_time - start_time  # Calculate the time taken for the epoch\n    average_loss = running_loss / len(train_loader)\n    train_accuracy = correct_train / total_train  \n    # Append training metrics to lists\n    train_losses.append(average_loss)\n    train_accuracies.append(train_accuracy)\n    # Log training accuracy and loss to WandB\n    wandb.log({\"train_loss\": average_loss, \"train_accuracy\": train_accuracy})\n    print(f'Training Loss: {average_loss}, Training Accuracy: {train_accuracy}, Time: {epoch_time} seconds')\n    \n    # Evaluate the model on the validation set\n    model.eval()\n    correct_val = 0\n    total_val = 0\n    val_running_loss = 0.0    \n    start_val_time = time.time()\n    with torch.no_grad():\n        for inputs, labels in valid_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            outputs = model(inputs)\n            val_loss = criterion(outputs, labels)\n            val_running_loss += val_loss.item()\n            \n            _, predicted = torch.max(outputs.data, 1)\n            total_val += labels.size(0)\n            correct_val += (predicted == labels).sum().item()\n\n    # Print validation loss and accuracy\n    validation_loss = val_running_loss / len(valid_loader)\n    validation_accuracy = correct_val / total_val\n    end_val_time = time.time()  # Record the end time for validation\n    val_epoch_time = end_val_time - start_val_time\n    # Append validation metrics to lists\n    val_losses.append(validation_loss)\n    val_accuracies.append(validation_accuracy)\n    # Log Validation accuracy and loss to WandB\n    wandb.log({\"validation_loss\": validation_loss, \"validation_accuracy\": validation_accuracy})\n    print(f'Validation Loss: {validation_loss}, Validation Accuracy: {validation_accuracy}, Validation Time: {val_epoch_time} seconds')","metadata":{"execution":{"iopub.status.busy":"2024-01-16T05:28:49.911266Z","iopub.execute_input":"2024-01-16T05:28:49.911895Z","iopub.status.idle":"2024-01-16T06:55:34.493319Z","shell.execute_reply.started":"2024-01-16T05:28:49.911860Z","shell.execute_reply":"2024-01-16T06:55:34.492307Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plotting\nplt.figure(figsize=(12, 4))\n\n# Plot training and validation loss\nplt.subplot(1, 2, 1)\nplt.plot(train_losses, label='Training Loss')\nplt.plot(val_losses, label='Validation Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\n\n# Plot training and validation accuracy\nplt.subplot(1, 2, 2)\nplt.plot(train_accuracies, label='Training Accuracy')\nplt.plot(val_accuracies, label='Validation Accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.legend()\n\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-01-16T06:55:34.494734Z","iopub.execute_input":"2024-01-16T06:55:34.495128Z","iopub.status.idle":"2024-01-16T06:55:34.949001Z","shell.execute_reply.started":"2024-01-16T06:55:34.495091Z","shell.execute_reply":"2024-01-16T06:55:34.948109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"out_data = []\nwith torch.no_grad():\n    model.eval()\n    for i, (data,label) in enumerate(test_loader):\n        data = data.to(device)\n        output = model(data)\n        predicted = F.softmax(output.data, dim=1).cpu()[0][1]\n        out_data.append([i + 1, predicted.item()])\n        \nout_df = pd.DataFrame(out_data, columns=['id', 'label'])\nout_df.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2024-01-16T06:55:34.950299Z","iopub.execute_input":"2024-01-16T06:55:34.950659Z","iopub.status.idle":"2024-01-16T06:56:26.642644Z","shell.execute_reply.started":"2024-01-16T06:55:34.950623Z","shell.execute_reply":"2024-01-16T06:56:26.641527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import random\n\nid_list = []\nclass_ = {0: 'cat', 1: 'dog'}\n\nfig, axes = plt.subplots(2, 5, figsize=(20, 12), facecolor='w')\n\nfor ax in axes.ravel():\n    \n    i = random.choice(out_df['id'].values)\n    \n    label = out_df.loc[out_df['id'] == i, 'label'].values[0]\n    if label > 0.5:\n        label = 1\n    else:\n        label = 0\n        \n    img_path = os.path.join(test_dir, '{}.jpg'.format(i))\n    img = Image.open(img_path)\n    \n    ax.set_title(class_[label])\n    ax.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2024-01-16T06:56:26.644254Z","iopub.execute_input":"2024-01-16T06:56:26.644583Z","iopub.status.idle":"2024-01-16T06:56:29.492534Z","shell.execute_reply.started":"2024-01-16T06:56:26.644555Z","shell.execute_reply":"2024-01-16T06:56:29.491524Z"},"trusted":true},"execution_count":null,"outputs":[]}]}