{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":31090,"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-08-18T11:33:11.912890Z","iopub.execute_input":"2025-08-18T11:33:11.913423Z","iopub.status.idle":"2025-08-18T11:33:12.178720Z","shell.execute_reply.started":"2025-08-18T11:33:11.913398Z","shell.execute_reply":"2025-08-18T11:33:12.178084Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Imports","metadata":{}},{"cell_type":"code","source":"import warnings \nwarnings.filterwarnings('ignore')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:12.179691Z","iopub.execute_input":"2025-08-18T11:33:12.180076Z","iopub.status.idle":"2025-08-18T11:33:12.183398Z","shell.execute_reply.started":"2025-08-18T11:33:12.180057Z","shell.execute_reply":"2025-08-18T11:33:12.182686Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import datasets, transforms, models\nfrom torch.utils.data import DataLoader, Dataset\nfrom PIL import Image\nimport pandas as pd\nfrom tqdm import tqdm\nimport matplotlib.pyplot as plt\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:12.184031Z","iopub.execute_input":"2025-08-18T11:33:12.184204Z","iopub.status.idle":"2025-08-18T11:33:16.724657Z","shell.execute_reply.started":"2025-08-18T11:33:12.184188Z","shell.execute_reply":"2025-08-18T11:33:16.723897Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Device","metadata":{}},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:16.726334Z","iopub.execute_input":"2025-08-18T11:33:16.726670Z","iopub.status.idle":"2025-08-18T11:33:16.807182Z","shell.execute_reply.started":"2025-08-18T11:33:16.726652Z","shell.execute_reply":"2025-08-18T11:33:16.806380Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Loading Dataset","metadata":{}},{"cell_type":"code","source":"import zipfile\nimport os\n\nwith zipfile.ZipFile(\"/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip\", 'r') as zip_ref:\n    zip_ref.extractall(\"/kaggle/working/train\")\n\nwith zipfile.ZipFile(\"/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip\", 'r') as zip_ref:\n    zip_ref.extractall(\"/kaggle/working/test\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:16.808075Z","iopub.execute_input":"2025-08-18T11:33:16.808336Z","iopub.status.idle":"2025-08-18T11:33:34.239488Z","shell.execute_reply.started":"2025-08-18T11:33:16.808310Z","shell.execute_reply":"2025-08-18T11:33:34.238700Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dir = \"/kaggle/working/train/train\"\ntest_dir = \"/kaggle/working/test/test\"\nsubmission_path = \"/kaggle/input/dogs-vs-cats-redux-kernels-edition/sample_submission.csv\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:34.240706Z","iopub.execute_input":"2025-08-18T11:33:34.240975Z","iopub.status.idle":"2025-08-18T11:33:34.244508Z","shell.execute_reply.started":"2025-08-18T11:33:34.240950Z","shell.execute_reply":"2025-08-18T11:33:34.243891Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train folder\ntrain_files = os.listdir(train_dir)\ntrain_files = sorted(train_files)  # optional: to keep filenames in order\n\nprint(\"Train samples:\", train_files[:5])\n\n# Test folder\ntest_files = os.listdir(test_dir)\ntest_files = sorted(test_files)\n\nprint(\"Test samples:\", test_files[:5])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:34.245163Z","iopub.execute_input":"2025-08-18T11:33:34.245347Z","iopub.status.idle":"2025-08-18T11:33:34.282058Z","shell.execute_reply.started":"2025-08-18T11:33:34.245331Z","shell.execute_reply":"2025-08-18T11:33:34.281490Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Sample Data visualization","metadata":{}},{"cell_type":"code","source":"# Show 5 train images\nplt.figure(figsize=(15, 3))\nfor i in range(5):\n    img_path = os.path.join(train_dir, train_files[i])\n    img = Image.open(img_path)\n    plt.subplot(1, 5, i+1)\n    plt.imshow(img)\n    plt.title(train_files[i])\n    plt.axis(\"off\")\nplt.suptitle(\"Train Samples\")\nplt.show()\n\n# Show 5 test images\nplt.figure(figsize=(15, 3))\nfor i in range(5):\n    img_path = os.path.join(test_dir, test_files[i])\n    img = Image.open(img_path)\n    plt.subplot(1, 5, i+1)\n    plt.imshow(img)\n    plt.title(test_files[i])\n    plt.axis(\"off\")\nplt.suptitle(\"Test Samples\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:34.282681Z","iopub.execute_input":"2025-08-18T11:33:34.282866Z","iopub.status.idle":"2025-08-18T11:33:35.158239Z","shell.execute_reply.started":"2025-08-18T11:33:34.282850Z","shell.execute_reply":"2025-08-18T11:33:35.157612Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Hyperparameters","metadata":{}},{"cell_type":"code","source":"BATCH_SIZE = 32\nEPOCHS = 5\nLR = 0.001\nIMG_SIZE = 224","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:35.159107Z","iopub.execute_input":"2025-08-18T11:33:35.159377Z","iopub.status.idle":"2025-08-18T11:33:35.163099Z","shell.execute_reply.started":"2025-08-18T11:33:35.159339Z","shell.execute_reply":"2025-08-18T11:33:35.162266Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Custom Data","metadata":{}},{"cell_type":"code","source":"class CustomDataset(Dataset):\n    def __init__(self, image_dir, transform=None):\n        self.image_dir = image_dir\n        self.transform = transform\n        self.image_files = os.listdir(image_dir)\n\n    def __len__(self):\n        return len(self.image_files)\n\n    def __getitem__(self, idx):\n        image_name = self.image_files[idx]\n        image_path = os.path.join(self.image_dir, image_name)\n        image = Image.open(image_path).convert(\"RGB\")\n\n        label = 1 if 'dog' in image_name else 0  # dog=1, cat=0 (for training)\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, label\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:35.165793Z","iopub.execute_input":"2025-08-18T11:33:35.166045Z","iopub.status.idle":"2025-08-18T11:33:35.174857Z","shell.execute_reply.started":"2025-08-18T11:33:35.166022Z","shell.execute_reply":"2025-08-18T11:33:35.174140Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Transform ","metadata":{}},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.5]*3, std=[0.5]*3)\n])\n\ntrain_dataset = CustomDataset(train_dir, transform=transform)\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:35.175728Z","iopub.execute_input":"2025-08-18T11:33:35.176113Z","iopub.status.idle":"2025-08-18T11:33:35.196927Z","shell.execute_reply.started":"2025-08-18T11:33:35.176096Z","shell.execute_reply":"2025-08-18T11:33:35.196452Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"model = models.resnet18(pretrained=True)\nmodel.fc = nn.Linear(model.fc.in_features, 2)  # Binary classification (dog/cat)\nmodel = model.to(device)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=LR)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:35.197536Z","iopub.execute_input":"2025-08-18T11:33:35.197739Z","iopub.status.idle":"2025-08-18T11:33:35.991456Z","shell.execute_reply.started":"2025-08-18T11:33:35.197716Z","shell.execute_reply":"2025-08-18T11:33:35.990701Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model Training","metadata":{}},{"cell_type":"code","source":"for epoch in range(EPOCHS):\n    model.train()\n    running_loss = 0.0\n    correct = 0\n\n    for images, labels in tqdm(train_loader):\n        images, labels = images.to(device), labels.to(device)\n\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n        _, preds = outputs.max(1)\n        correct += (preds == labels).sum().item()\n\n    acc = 100.0 * correct / len(train_dataset)\n    print(f\"Epoch {epoch+1}, Loss: {running_loss:.4f}, Accuracy: {acc:.2f}%\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:33:35.992288Z","iopub.execute_input":"2025-08-18T11:33:35.992680Z","iopub.status.idle":"2025-08-18T11:45:57.709129Z","shell.execute_reply.started":"2025-08-18T11:33:35.992655Z","shell.execute_reply":"2025-08-18T11:45:57.708406Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Test dataset loader","metadata":{}},{"cell_type":"code","source":"class TestDataset(Dataset):\n    def __init__(self, image_dir, transform=None):\n        self.image_dir = image_dir\n        self.transform = transform\n        self.image_files = sorted(os.listdir(image_dir), key=lambda x: int(x.split('.')[0]))\n\n    def __len__(self):\n        return len(self.image_files)\n\n    def __getitem__(self, idx):\n        image_name = self.image_files[idx]\n        image_path = os.path.join(self.image_dir, image_name)\n        image = Image.open(image_path).convert(\"RGB\")\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, image_name\n\ntest_dataset = TestDataset(test_dir, transform=transform)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:45:57.709829Z","iopub.execute_input":"2025-08-18T11:45:57.710092Z","iopub.status.idle":"2025-08-18T11:45:57.727554Z","shell.execute_reply.started":"2025-08-18T11:45:57.710062Z","shell.execute_reply":"2025-08-18T11:45:57.727002Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model Evaluation on Test Data","metadata":{}},{"cell_type":"code","source":"model.eval()\npredictions = []\n\nwith torch.no_grad():\n    for images, image_names in tqdm(test_loader):\n        images = images.to(device)\n        outputs = model(images)\n        _, predicted = outputs.max(1)\n\n        for img_name, pred in zip(image_names, predicted):\n            id_ = int(img_name.split('.')[0])\n            predictions.append((id_, pred.item()))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:45:57.728178Z","iopub.execute_input":"2025-08-18T11:45:57.728441Z","iopub.status.idle":"2025-08-18T11:46:49.963995Z","shell.execute_reply.started":"2025-08-18T11:45:57.728417Z","shell.execute_reply":"2025-08-18T11:46:49.963053Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Saving the predicted output","metadata":{}},{"cell_type":"code","source":"submission_df = pd.DataFrame(predictions, columns=[\"id\", \"label\"])\nsubmission_df = submission_df.sort_values(by=\"id\")\nsubmission_df.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T11:45:57.728178Z","iopub.execute_input":"2025-08-18T11:45:57.728441Z","iopub.status.idle":"2025-08-18T11:46:49.963995Z","shell.execute_reply.started":"2025-08-18T11:45:57.728417Z","shell.execute_reply":"2025-08-18T11:46:49.963053Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Model evaluation on test data and saving the prediction in probability of label dog for each sample","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport torch.nn.functional as F\n\nmodel.eval()\nsubmission = []\n\nwith torch.no_grad():\n    for images, image_names in tqdm(test_loader):\n        images = images.to(device)\n\n        outputs = model(images)\n        probabilities = F.softmax(outputs, dim=1)  # get probabilities\n        dog_probs = probabilities[:, 1]  # probability that the image is a dog (class 1)\n\n        for img_name, prob in zip(image_names, dog_probs):\n            img_id = int(img_name.split('.')[0])\n            submission.append((img_id, prob.item()))\n\n# Sort by id to match the required order\nsubmission.sort(key=lambda x: x[0])\n\n# Create a dataframe\ndf_submission = pd.DataFrame(submission, columns=[\"id\", \"label\"])\n\n# Save to CSV\ndf_submission.to_csv(\"submission.csv\", index=False)\n\nprint(\"Submission file created: submission.csv\")\ndf_submission.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T12:03:27.234845Z","iopub.execute_input":"2025-08-18T12:03:27.235590Z","iopub.status.idle":"2025-08-18T12:04:19.783333Z","shell.execute_reply.started":"2025-08-18T12:03:27.235567Z","shell.execute_reply":"2025-08-18T12:04:19.782605Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(df_submission)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T12:08:07.993895Z","iopub.execute_input":"2025-08-18T12:08:07.994603Z","iopub.status.idle":"2025-08-18T12:08:07.999121Z","shell.execute_reply.started":"2025-08-18T12:08:07.994567Z","shell.execute_reply":"2025-08-18T12:08:07.998401Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### plot of model training","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Custom Model ","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nclass CustomNNModel(nn.Module):\n    def __init__(self):\n        super(CustomNNModel, self).__init__()\n        \n        self.conv_block1 = nn.Sequential(\n            nn.Conv2d(3, 32, kernel_size=3, padding=1),  # [B, 3, 224, 224] -> [B, 32, 224, 224]\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2)  # -> [B, 32, 112, 112]\n        )\n        \n        self.conv_block2 = nn.Sequential(\n            nn.Conv2d(32, 64, kernel_size=3, padding=1),  # -> [B, 64, 112, 112]\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2)  # -> [B, 64, 56, 56]\n        )\n\n        self.conv_block3 = nn.Sequential(\n            nn.Conv2d(64, 128, kernel_size=3, padding=1),  # -> [B, 128, 56, 56]\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2)  # -> [B, 128, 28, 28]\n        )\n\n        self.conv_block4 = nn.Sequential(\n            nn.Conv2d(128, 256, kernel_size=3, padding=1),  # -> [B, 256, 28, 28]\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2)  # -> [B, 256, 14, 14]\n        )\n\n        self.dropout = nn.Dropout(0.5)\n        self.fc1 = nn.Linear(256 * 14 * 14, 512)\n        self.fc2 = nn.Linear(512, 2)  # Output layer (2 classes: cat, dog)\n\n    def forward(self, x):\n        x = self.conv_block1(x)\n        x = self.conv_block2(x)\n        x = self.conv_block3(x)\n        x = self.conv_block4(x)\n        x = x.view(x.size(0), -1)  # Flatten\n        x = self.dropout(x)\n        x = F.relu(self.fc1(x))\n        x = self.fc2(x)\n        return x\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T12:27:27.489562Z","iopub.execute_input":"2025-08-18T12:27:27.489815Z","iopub.status.idle":"2025-08-18T12:27:27.498092Z","shell.execute_reply.started":"2025-08-18T12:27:27.489796Z","shell.execute_reply":"2025-08-18T12:27:27.497283Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = CustomNNModel().to(device)\n\n# Loss and optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T12:27:33.327386Z","iopub.execute_input":"2025-08-18T12:27:33.327657Z","iopub.status.idle":"2025-08-18T12:27:33.577283Z","shell.execute_reply.started":"2025-08-18T12:27:33.327636Z","shell.execute_reply":"2025-08-18T12:27:33.576746Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_losses = []\ntrain_accuracies = []\nEPOCHS = 3\nfor epoch in range(EPOCHS):\n    model.train()\n    running_loss = 0.0\n    correct = 0\n\n    for images, labels in tqdm(train_loader):\n        images, labels = images.to(device), labels.to(device)\n\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n        _, preds = outputs.max(1)\n        correct += (preds == labels).sum().item()\n\n    epoch_loss = running_loss / len(train_loader)\n    epoch_acc = 100.0 * correct / len(train_dataset)\n\n    train_losses.append(epoch_loss)\n    train_accuracies.append(epoch_acc)\n\n    print(f\"Epoch {epoch+1}, Loss: {epoch_loss:.4f}, Accuracy: {epoch_acc:.2f}%\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T12:27:43.340499Z","iopub.execute_input":"2025-08-18T12:27:43.340751Z","iopub.status.idle":"2025-08-18T12:34:00.737762Z","shell.execute_reply.started":"2025-08-18T12:27:43.340732Z","shell.execute_reply":"2025-08-18T12:34:00.737023Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Model training plot","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nepochs = range(1, EPOCHS + 1)\n\nplt.figure(figsize=(12, 5))\n\n# Plot Loss\nplt.subplot(1, 2, 1)\nplt.plot(epochs, train_losses, marker='o')\nplt.title(\"Training Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\n\n# Plot Accuracy\nplt.subplot(1, 2, 2)\nplt.plot(epochs, train_accuracies, marker='o', color='green')\nplt.title(\"Training Accuracy\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Accuracy (%)\")\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-18T12:36:29.355981Z","iopub.execute_input":"2025-08-18T12:36:29.356531Z","iopub.status.idle":"2025-08-18T12:36:29.707726Z","shell.execute_reply.started":"2025-08-18T12:36:29.356507Z","shell.execute_reply":"2025-08-18T12:36:29.707060Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = {'loss': [], 'acc': []}\n\nfor epoch in range(EPOCHS):\n    model.train()\n    running_loss = 0.0\n    correct = 0\n\n    for images, labels in tqdm(train_loader):\n        images, labels = images.to(device), labels.to(device)\n\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n        _, preds = outputs.max(1)\n        correct += (preds == labels).sum().item()\n\n    epoch_loss = running_loss / len(train_loader)\n    epoch_acc = 100.0 * correct / len(train_dataset)\n\n    history['loss'].append(epoch_loss)\n    history['acc'].append(epoch_acc)\n\n    print(f\"Epoch {epoch+1}, Loss: {epoch_loss:.4f}, Accuracy: {epoch_acc:.2f}%\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\n\n# Plotting training and validation accuracy/loss\ndef plot_training_history(history):\n    plt.figure(figsize=(12, 5))\n\n    # Accuracy\n    plt.subplot(1, 2, 1)\n    plt.plot(history.history['accuracy'], label='Train Accuracy')\n    plt.plot(history.history['val_accuracy'], label='Val Accuracy')\n    plt.title('Accuracy Over Epochs')\n    plt.xlabel('Epoch')\n    plt.ylabel('Accuracy')\n    plt.legend()\n\n    # Loss\n    plt.subplot(1, 2, 2)\n    plt.plot(history.history['loss'], label='Train Loss')\n    plt.plot(history.history['val_loss'], label='Val Loss')\n    plt.title('Loss Over Epochs')\n    plt.xlabel('Epoch')\n    plt.ylabel('Loss')\n    plt.legend()\n\n    plt.tight_layout()\n    plt.show()\n\n# Assuming `all_labels` are true labels and `all_preds` are predicted labels on validation data\ndef plot_confusion_matrix(all_labels, all_preds):\n    cm = confusion_matrix(all_labels, all_preds)\n    disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=[\"Cat\", \"Dog\"])\n    disp.plot(cmap=plt.cm.Blues)\n    plt.title(\"Confusion Matrix\")\n    plt.show()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}