{"metadata":{"accelerator":"GPU","colab":{"provenance":[]},"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"},"widgets":{"application/vnd.jupyter.widget-state+json":{"da020a361865457d98cd8b46e3142004":{"model_module":"@jupyter-widgets/controls","model_name":"HBoxModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_a58945caa20649eaacbebbaa8ff8e666","IPY_MODEL_a92f7565e5ff4fde859d41a46ae62ef2","IPY_MODEL_51638b6781d942b981130fa27131fad6"],"layout":"IPY_MODEL_3845612ee74f4340bed3d9af35c1b992"}},"a58945caa20649eaacbebbaa8ff8e666":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_8d24a7f66f0446bcaf1f1716b360e754","placeholder":"​","style":"IPY_MODEL_75490dcd55764ac7b5e9a83e08b17156","value":"100%"}},"a92f7565e5ff4fde859d41a46ae62ef2":{"model_module":"@jupyter-widgets/controls","model_name":"FloatProgressModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_ea82c8b01ee94b678cde386d73157080","max":111898327,"min":0,"orientation":"horizontal","style":"IPY_MODEL_a712ddf5abec4e4c86fd919a97b6ed67","value":111898327}},"51638b6781d942b981130fa27131fad6":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_49785ccfe3ee43fd8496513997712a47","placeholder":"​","style":"IPY_MODEL_a944fd8c7e4f488bbad149caf6113cc0","value":" 107M/107M [00:00&lt;00:00, 309MB/s]"}},"3845612ee74f4340bed3d9af35c1b992":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"8d24a7f66f0446bcaf1f1716b360e754":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"75490dcd55764ac7b5e9a83e08b17156":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"ea82c8b01ee94b678cde386d73157080":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"a712ddf5abec4e4c86fd919a97b6ed67":{"model_module":"@jupyter-widgets/controls","model_name":"ProgressStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"49785ccfe3ee43fd8496513997712a47":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"a944fd8c7e4f488bbad149caf6113cc0":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}}}},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":63103,"databundleVersionId":6877691,"sourceType":"competition"}],"dockerImageVersionId":30588,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# CS-405 Deep Learning BS-CS/SE Fall-2023\n\n### Submitted by Hareem Bilal Malik - 344043, Hafsa Hassan -","metadata":{"id":"cF-pnQy2YMQT"}},{"cell_type":"code","source":"pip install facenet-pytorch","metadata":{"id":"uM94vHPEXkP7","outputId":"bb82af92-549f-4721-f0a0-bf19962ce9f7","execution":{"iopub.status.busy":"2023-11-19T13:31:49.915245Z","iopub.execute_input":"2023-11-19T13:31:49.916031Z","iopub.status.idle":"2023-11-19T13:32:01.430614Z","shell.execute_reply.started":"2023-11-19T13:31:49.915997Z","shell.execute_reply":"2023-11-19T13:32:01.429482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\n# Check if GPU is available\nuse_cuda = torch.cuda.is_available()\ndevice = torch.device(\"cuda\" if use_cuda else \"cpu\")\nprint ('<== CUDA availability : ==>', use_cuda)\n\ntorch.manual_seed(42)","metadata":{"id":"8nAeM33MbA-d","outputId":"b878198d-47e6-44c4-c94a-68e39ea2a353","execution":{"iopub.status.busy":"2023-11-19T13:32:05.298061Z","iopub.execute_input":"2023-11-19T13:32:05.298412Z","iopub.status.idle":"2023-11-19T13:32:06.793545Z","shell.execute_reply.started":"2023-11-19T13:32:05.298384Z","shell.execute_reply":"2023-11-19T13:32:06.792600Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nfrom PIL import Image\nimport torch\nfrom torch.utils.data import Dataset\nfrom torchvision import transforms\nfrom facenet_pytorch import MTCNN\n\nroot_directory = r'/kaggle/input/face-classification-deep-learning-cs-405/dataset/train'\n\n# Define data transformations\ntransform = transforms.Compose([\n    transforms.Resize((160, 160)),  # Resize the images to a consistent size\n    transforms.ToTensor(),  # Convert images to tensors\n\n])\n\nclass CustomDataset(Dataset):\n    def __init__(self, root_directory):\n        self.root_directory = root_directory\n        self.identity_directories = os.listdir(root_directory)\n        self.transform = transform\n        self.mtcnn = MTCNN()\n\n        self.identity_mapping = {identity: label for label, identity in enumerate(self.identity_directories)}\n\n        self.data = []\n        for identity_label, identity in enumerate(self.identity_directories):\n            images = os.listdir(os.path.join(root_directory, identity))\n            for image in images:\n                image_path = os.path.join(root_directory, identity, image)\n                self.data.append((image_path, identity_label))\n\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, index):\n        image_path, identity_label = self.data[index]\n        img = Image.open(image_path)\n\n        # Use MTCNN for face detection and alignment\n        boxes, probs = self.mtcnn.detect(img)\n\n        # If faces are detected, crop and align them\n        if boxes is not None:\n            face = img.crop((boxes[0][0], boxes[0][1], boxes[0][2], boxes[0][3]))  # Cropping the face\n\n            # Apply transform to the cropped face\n            face_transformed = self.transform(face)\n            return face_transformed, torch.tensor(identity_label)\n\n        else:\n            return None\n\n\n# Create a dataset instance with the specified transformations and MTCNN\ndataset = CustomDataset(root_directory)","metadata":{"id":"mhIMgnKIXDim","execution":{"iopub.status.busy":"2023-11-19T13:32:09.194482Z","iopub.execute_input":"2023-11-19T13:32:09.195325Z","iopub.status.idle":"2023-11-19T13:33:51.759293Z","shell.execute_reply.started":"2023-11-19T13:32:09.195290Z","shell.execute_reply":"2023-11-19T13:33:51.758442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import DataLoader\n\n# Split the dataset into training, validation, and test sets\ntrain_size = int(0.7 * len(dataset))\nvalidation_size = int(0.15 * len(dataset))\ntest_size = len(dataset) - train_size - validation_size\n\ntrain_data, validation_data, test_data = torch.utils.data.random_split(\n    dataset, [train_size, validation_size, test_size]\n)\n\n# Define batch sizes for data loaders\nbatch_size = 128\n\n# Create data loaders for training, validation, and test sets with the custom collate function\ntrain_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, collate_fn=lambda x: [sample for sample in x if sample is not None], num_workers=2)\nvalidation_loader = DataLoader(validation_data, batch_size=batch_size, shuffle=False, collate_fn=lambda x: [sample for sample in x if sample is not None])\ntest_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False, collate_fn=lambda x: [sample for sample in x if sample is not None])\ntrain_loader","metadata":{"id":"WY2_EtdNxPoM","outputId":"688e2c6e-95f8-47f2-f637-8efc21065ccb","execution":{"iopub.status.busy":"2023-11-19T13:34:45.281506Z","iopub.execute_input":"2023-11-19T13:34:45.282253Z","iopub.status.idle":"2023-11-19T13:34:45.313055Z","shell.execute_reply.started":"2023-11-19T13:34:45.282219Z","shell.execute_reply":"2023-11-19T13:34:45.311585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\n\ndef display_images(loader):\n    # Get a batch of data\n    data_iter = iter(loader)\n    batch = next(data_iter)\n\n    inputs, labels = zip(*batch)\n\n    # Convert the batch to NumPy arrays\n    inputs = np.array([item.numpy() for item in inputs])\n\n    # Define a function to display images and labels\n    def show_images(images, labels):\n        num_images = len(images)\n        num_cols = 5  # Number of columns for image display\n        num_rows = (num_images + num_cols - 1) // num_cols\n\n        plt.figure(figsize=(15, 3 * num_rows))\n        for i in range(num_images):\n            plt.subplot(num_rows, num_cols, i + 1)\n            plt.imshow(np.transpose(images[i], (1, 2, 0)))\n            if labels is not None:\n                plt.title(f\"Label: {labels[i]}\")  # Show label as title\n            plt.axis(\"off\")\n\n    show_images(inputs, labels)\n    plt.show()\n\ndisplay_images(train_loader)","metadata":{"id":"zQzXww_6M5Wk","outputId":"146bd7d2-e496-4606-9763-7069d4a52010","execution":{"iopub.status.busy":"2023-11-19T13:34:49.512725Z","iopub.execute_input":"2023-11-19T13:34:49.513571Z","iopub.status.idle":"2023-11-19T13:35:18.437414Z","shell.execute_reply.started":"2023-11-19T13:34:49.513538Z","shell.execute_reply":"2023-11-19T13:35:18.436200Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from facenet_pytorch import InceptionResnetV1\n\n# Set num_classes to 7000\nnum_classes = 7000\n\n# Initialize the InceptionResnetV1 model\nmodel = InceptionResnetV1(pretrained='vggface2', device=device, classify=True, num_classes=num_classes)\n\nlayers_to_unfreeze = 15  # Number of layers to keep unfrozen\nfor param in model.parameters():\n    param.requires_grad = False\n\n# Unfreeze the last layers\nfor param in list(model.parameters())[-layers_to_unfreeze:]:\n    param.requires_grad = True\nprint(model)","metadata":{"id":"wNkLXJu9H2mS","outputId":"7d82786e-4dbd-45cf-d31d-9f302aabb05a","execution":{"iopub.status.busy":"2023-11-19T13:35:24.904715Z","iopub.execute_input":"2023-11-19T13:35:24.905103Z","iopub.status.idle":"2023-11-19T13:35:28.922682Z","shell.execute_reply.started":"2023-11-19T13:35:24.905071Z","shell.execute_reply":"2023-11-19T13:35:28.921630Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.nn as nn\nfrom torch import optim\n\n# Assuming you want to use cross-entropy loss for classification\ncriterion = nn.CrossEntropyLoss()\n\n# Assuming you want to use Adam optimizer\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n\ncheckpoint_path = '/kaggle/working/checkpoint.pth'\nbest_val_checkpoint_path = '/kaggle/working/best_val_checkpoint.pth'\n\ntorch.save(model.state_dict(), checkpoint_path)\ntorch.save(model.state_dict(), best_val_checkpoint_path)","metadata":{"id":"LZFpoTpCY8h7","execution":{"iopub.status.busy":"2023-11-19T13:35:45.241528Z","iopub.execute_input":"2023-11-19T13:35:45.241926Z","iopub.status.idle":"2023-11-19T13:35:45.669028Z","shell.execute_reply.started":"2023-11-19T13:35:45.241877Z","shell.execute_reply":"2023-11-19T13:35:45.668183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm import tqdm\n\nnum_epochs = 5\n\ndef train_model(model):\n    model.to(device)\n    model.train()\n\n    train_losses = []\n    train_accuracies = []\n    val_losses = []\n    val_accuracies = []\n\n    best_val_accuracy = 0.0\n\n    for epoch in range(num_epochs):\n        running_loss = 0.0\n        correct_predictions = 0\n        total_samples = 0\n\n        # Wrap the training loader with tqdm for a progress bar\n        for batch in tqdm(train_loader):\n            if batch is not None:\n                inputs, labels = zip(*batch)\n                inputs = torch.stack(inputs).to(device)\n                labels = torch.stack(labels).to(device)\n\n                optimizer.zero_grad()\n\n                outputs = model(inputs)\n                loss = criterion(outputs, labels)\n                loss.backward()\n                optimizer.step()\n\n                running_loss += loss.item()\n\n                _, predicted = torch.max(outputs, 1)\n                total_samples += labels.size(0)\n                correct_predictions += (predicted == labels).sum().item()\n\n        epoch_loss = running_loss / len(train_loader)\n        epoch_accuracy = correct_predictions / total_samples\n\n        train_losses.append(epoch_loss)\n        train_accuracies.append(epoch_accuracy)\n\n        print(f'Epoch {epoch + 1}/{num_epochs}, Training Loss: {epoch_loss:.4f}, Training Accuracy: {epoch_accuracy * 100:.2f}%')\n\n        # Save a checkpoint every epoch\n        torch.save({\n            'epoch': epoch,\n            'model_state_dict': model.state_dict(),\n            'optimizer_state_dict': optimizer.state_dict(),\n            'loss': epoch_loss,\n            'accuracy': epoch_accuracy\n        }, checkpoint_path)\n\n        # Check validation accuracy and save the best model\n        val_loss, val_accuracy = evaluate_model(model, validation_loader)\n\n        print(f'Epoch {epoch + 1}/{num_epochs}, Validation Loss: {val_loss:.4f}, Validation Accuracy: {val_accuracy * 100:.2f}%')\n\n\n        val_losses.append(val_loss)\n        val_accuracies.append(val_accuracy)\n\n        if val_accuracy > best_val_accuracy:\n            best_val_accuracy = val_accuracy\n            torch.save({\n                'epoch': epoch,\n                'model_state_dict': model.state_dict(),\n                'optimizer_state_dict': optimizer.state_dict(),\n                'loss': epoch_loss,\n                'accuracy': epoch_accuracy\n            }, best_val_checkpoint_path)\n\n    print('Training complete.')\n\n    # Plotting training loss and accuracy\n    plt.figure(figsize=(12, 4))\n    plt.subplot(1, 2, 1)\n    plt.plot(train_losses, label='Training Loss')\n    plt.title('Training Loss')\n    plt.xlabel('Epoch')\n    plt.ylabel('Loss')\n    plt.legend()\n\n    plt.subplot(1, 2, 2)\n    plt.plot(train_accuracies, label='Training Accuracy')\n    plt.title('Training Accuracy')\n    plt.xlabel('Epoch')\n    plt.ylabel('Accuracy')\n    plt.legend()\n\n    plt.show()\n\n    # Plotting validation loss and accuracy\n    plt.figure(figsize=(12, 4))\n    plt.subplot(1, 2, 1)\n    plt.plot(val_losses, label='Validation Loss')\n    plt.title('Validation Loss')\n    plt.xlabel('Epoch')\n    plt.ylabel('Loss')\n    plt.legend()\n\n    plt.subplot(1, 2, 2)\n    plt.plot(val_accuracies, label='Validation Accuracy')\n    plt.title('Validation Accuracy')\n    plt.xlabel('Epoch')\n    plt.ylabel('Accuracy')\n    plt.legend()\n\n    plt.show()\n\ndef evaluate_model(model, dataloader):\n    model.eval()\n    correct_predictions = 0\n    total_samples = 0\n\n    valLoss = 0\n\n    with torch.no_grad():\n        for batch in dataloader:\n            inputs, labels = zip(*batch)\n            inputs = torch.stack(inputs).to(device)\n            labels = torch.stack(labels).to(device)\n\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n\n            valLoss += loss.item()\n\n            _, predicted = torch.max(outputs, 1)\n\n            total_samples += labels.size(0)\n            correct_predictions += (predicted == labels).sum().item()\n\n    valLoss = valLoss / len(validation_loader)\n    accuracy = correct_predictions / total_samples\n    return valLoss, accuracy\n\n# Usage example\ntrain_model(model)","metadata":{"id":"1cQU5Zf0oR6f","outputId":"ddd13935-2c12-4445-ca35-32d3708d4cdc","execution":{"iopub.status.busy":"2023-11-19T13:35:48.896118Z","iopub.execute_input":"2023-11-19T13:35:48.896812Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def validate_model(model):\n    # Load model from the checkpoint\n    checkpoint = torch.load(best_val_checkpoint_path)\n    model.load_state_dict(checkpoint['model_state_dict'])\n    model.to(device)\n\n    model.eval()\n    running_loss = 0.0\n    correct_predictions = 0\n    total_samples = 0\n\n    with torch.no_grad():\n        for batch in tqdm(validation_loader):\n            if batch is not None:\n                val_inputs, val_labels = zip(*batch)\n                val_inputs = torch.stack(val_inputs).to(device)\n                val_labels = torch.stack(val_labels).to(device)\n\n                val_outputs = model(val_inputs)\n                val_loss = criterion(val_outputs, val_labels)\n\n                running_loss += val_loss.item()\n\n                _, val_predicted = torch.max(val_outputs, 1)\n                total_samples += val_labels.size(0)\n                correct_predictions += (val_predicted == val_labels).sum().item()\n\n    val_loss = running_loss / len(validation_loader)\n    val_accuracy = correct_predictions / total_samples\n\n    print(f'Validation Loss: {val_loss:.4f}, Validation Accuracy: {val_accuracy * 100:.2f}%')\n\n# Usage example\nvalidate_model(model)","metadata":{"execution":{"iopub.status.busy":"2023-11-18T20:42:50.053567Z","iopub.execute_input":"2023-11-18T20:42:50.054597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def test_model(model):\n    # Load model from the best validation checkpoint\n    checkpoint = torch.load(best_val_checkpoint_path)\n    model.load_state_dict(checkpoint['model_state_dict'])\n    model.to(device)\n\n    model.eval()\n    running_loss = 0.0\n    correct_predictions = 0\n    total_samples = 0\n\n    with torch.no_grad():\n        for batch in tqdm(test_loader):\n            if batch is not None:\n                test_inputs, test_labels = zip(*batch)\n                test_inputs = torch.stack(test_inputs).to(device)\n                test_labels = torch.stack(test_labels).to(device)\n\n                test_outputs = model(test_inputs)\n                test_loss = criterion(test_outputs, test_labels)\n\n                running_loss += test_loss.item()\n\n                _, test_predicted = torch.max(test_outputs, 1)\n                total_samples += test_labels.size(0)\n                correct_predictions += (test_predicted == test_labels).sum().item()\n\n    # Calculate the mean loss and accuracy over all batches\n    test_loss = running_loss / len(test_loader)\n    test_accuracy = correct_predictions / total_samples\n\n    print(f'Test Loss: {test_loss:.4f}, Test Accuracy: {test_accuracy * 100:.2f}%')\n\n# Usage example\ntest_model(model)","metadata":{},"execution_count":null,"outputs":[]}]}