{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":3649,"databundleVersionId":46718,"sourceType":"competition"}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Install required package\n!pip install py7zr\n\n# -----------------------------\n# Required Imports\n# -----------------------------\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nfrom torchvision import datasets, transforms\nfrom torch.utils.data import DataLoader, Dataset\nfrom PIL import Image\nimport os\nimport pandas as pd\nfrom tqdm import tqdm\nimport py7zr\nimport math\n\n# -----------------------------\n# Device Configuration\n# -----------------------------\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using device: {device}\")\n\n# -----------------------------\n# Model Definition: ResNet152\n# -----------------------------\n\nclass Bottleneck(nn.Module):\n    expansion = 4\n\n    def __init__(self, in_planes, planes, stride=1):\n        super(Bottleneck, self).__init__()\n        self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm2d(planes)\n        self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * self.expansion)\n\n        self.shortcut = nn.Sequential()\n        if stride != 1 or in_planes != planes * self.expansion:\n            self.shortcut = nn.Sequential(\n                nn.Conv2d(in_planes, planes * self.expansion, kernel_size=1, stride=stride, bias=False),\n                nn.BatchNorm2d(planes * self.expansion)\n            )\n\n    def forward(self, x):\n        out = F.relu(self.bn1(self.conv1(x)))\n        out = F.relu(self.bn2(self.conv2(out)))\n        out = self.bn3(self.conv3(out))\n        out += self.shortcut(x)\n        out = F.relu(out)\n        return out\n\nclass ResNet(nn.Module):\n    def __init__(self, block, num_blocks, num_classes=10):\n        super(ResNet, self).__init__()\n        self.in_planes = 64\n\n        # Stem layer\n        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(64)\n\n        # ResNet layers\n        self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)\n        self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)\n        self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)\n        self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)\n\n        # Final classifier layer\n        self.linear = nn.Linear(512 * block.expansion, num_classes)\n\n        # Initialize weights\n        self._initialize_weights()\n\n    def _make_layer(self, block, planes, num_blocks, stride):\n        strides = [stride] + [1] * (num_blocks - 1)\n        layers = []\n        for stride in strides:\n            layers.append(block(self.in_planes, planes, stride))\n            self.in_planes = planes * block.expansion\n        return nn.Sequential(*layers)\n\n    def _initialize_weights(self):\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')\n                if m.bias is not None:\n                    nn.init.zeros_(m.bias)\n            elif isinstance(m, nn.BatchNorm2d):\n                nn.init.ones_(m.weight)\n                nn.init.zeros_(m.bias)\n            elif isinstance(m, nn.Linear):\n                nn.init.normal_(m.weight, 0, 0.01)\n                nn.init.zeros_(m.bias)\n\n    def forward(self, x):\n        out = F.relu(self.bn1(self.conv1(x)))\n        out = self.layer1(out)\n        out = self.layer2(out)\n        out = self.layer3(out)\n        out = self.layer4(out)\n        out = F.avg_pool2d(out, 4)\n        out = out.view(out.size(0), -1)\n        out = self.linear(out)\n        return out\n\ndef ResNet152():\n    return ResNet(Bottleneck, [3, 8, 36, 3])\n\n# -----------------------------\n# Instantiate the Model\n# -----------------------------\n\nmodel = ResNet152().to(device)\nprint(\"Model instantiated successfully.\")\n\n# -----------------------------\n# Data Augmentation: CutOut\n# -----------------------------\n\nclass Cutout(object):\n    def __init__(self, length):\n        self.length = length\n\n    def __call__(self, img):\n        h, w = img.size(1), img.size(2)\n        mask = torch.ones(h, w, dtype=img.dtype, device=img.device)\n\n        y = torch.randint(h, (1,)).item()\n        x = torch.randint(w, (1,)).item()\n\n        y1 = max(0, y - self.length // 2)\n        y2 = min(h, y + self.length // 2)\n        x1 = max(0, x - self.length // 2)\n        x2 = min(w, x + self.length // 2)\n\n        mask[y1:y2, x1:x2] = 0\n        img = img * mask.unsqueeze(0)  # Apply mask to all channels\n        return img\n\n# -----------------------------\n# Data Loading and Preprocessing\n# -----------------------------\n\n# CIFAR-10 mean and std for normalization\nCIFAR10_MEAN = (0.4914, 0.4822, 0.4465)\nCIFAR10_STD = (0.2023, 0.1994, 0.2010)\n\n# Training transformations with CutOut\ntransform_train = transforms.Compose([\n    transforms.RandomCrop(32, padding=4),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize(CIFAR10_MEAN, CIFAR10_STD),\n    Cutout(length=16),\n])\n\n# Validation/Test transformations\ntransform_test = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize(CIFAR10_MEAN, CIFAR10_STD),\n])\n\n# Load CIFAR-10 dataset\ntrainset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train)\ntrainloader = DataLoader(trainset, batch_size=128, shuffle=True, num_workers=4)\n\ntestset = datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)\ntestloader = DataLoader(testset, batch_size=100, shuffle=False, num_workers=4)\n\n# -----------------------------\n# Define Loss Function and Optimizer\n# -----------------------------\n\ncriterion = nn.CrossEntropyLoss()\n\n# AdamW optimizer with weight decay\noptimizer = optim.AdamW(model.parameters(), lr=0.001, weight_decay=5e-4)\n\n# -----------------------------\n# Cosine Annealing Scheduler with Warmup\n# -----------------------------\n\nclass CosineAnnealingWarmupRestarts(optim.lr_scheduler._LRScheduler):\n    def __init__(self, optimizer, T_0, T_mult=1, eta_max=0.001, T_up=5, gamma=0.5, last_epoch=-1):\n        self.T_0 = T_0\n        self.T_mult = T_mult\n        self.base_eta_max = eta_max\n        self.eta_max = eta_max\n        self.T_up = T_up\n        self.gamma = gamma\n        self.cycle = 0\n        self.T_i = T_0\n        super(CosineAnnealingWarmupRestarts, self).__init__(optimizer, last_epoch)\n\n    def get_lr(self):\n        if self.last_epoch < self.T_up:\n            # Warmup phase\n            return [(self.base_lrs[i] + (self.eta_max - self.base_lrs[i]) * self.last_epoch / self.T_up) \n                    for i in range(len(self.base_lrs))]\n        else:\n            # Cosine annealing phase\n            cos_inner = (self.last_epoch - self.T_up) / (self.T_i - self.T_up)\n            return [self.base_lrs[i] + 0.5 * (self.eta_max - self.base_lrs[i]) * \n                    (1 + math.cos(math.pi * cos_inner)) \n                    for i in range(len(self.base_lrs))]\n\n    def step_ReduceLROnPlateau(self, metrics, epoch=None):\n        pass  # Not implemented\n\nscheduler = CosineAnnealingWarmupRestarts(optimizer, T_0=60, T_mult=1, eta_max=0.001, T_up=10, gamma=0.5)\n\n# -----------------------------\n# Training and Validation Functions\n# -----------------------------\n\ndef train(epoch):\n    model.train()\n    running_loss = 0.0\n    for batch_idx, (inputs, targets) in enumerate(tqdm(trainloader, desc=f\"Training Epoch {epoch+1}\")):\n        inputs, targets = inputs.to(device), targets.to(device)\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, targets)\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n        if batch_idx % 100 == 99:    # Print every 100 mini-batches\n            print(f'[Epoch {epoch + 1}, Batch {batch_idx + 1}] loss: {running_loss / 100:.3f}')\n            running_loss = 0.0\n\ndef validate(epoch):\n    model.eval()\n    correct = 0\n    total = 0\n    with torch.no_grad():\n        for inputs, targets in tqdm(testloader, desc=f\"Validation Epoch {epoch+1}\"):\n            inputs, targets = inputs.to(device), targets.to(device)\n            outputs = model(inputs)\n            _, predicted = torch.max(outputs, 1)\n            total += targets.size(0)\n            correct += predicted.eq(targets).sum().item()\n    accuracy = 100. * correct / total\n    print(f'Validation Accuracy after Epoch {epoch + 1}: {accuracy:.2f}%')\n    return accuracy\n\n# -----------------------------\n# Training Loop with Checkpointing\n# -----------------------------\n\nbest_acc = 0.0\nnum_epochs = 70  # Total number of epochs\n\nfor epoch in range(num_epochs):\n    train(epoch)\n    acc = validate(epoch)\n    scheduler.step()\n\n    # Save the model checkpoint if it's the best so far\n    if acc > best_acc:\n        best_acc = acc\n        torch.save(model.state_dict(), 'resnet152_cifar10_weights_best.pt')\n        print(f\"Best model saved with accuracy: {best_acc:.2f}%\")\n\nprint(\"Initial Training completed.\")\n\n# -----------------------------\n# Fine-Tuning Phase\n# -----------------------------\n\n# Load the best model from initial training\nmodel.load_state_dict(torch.load('resnet152_cifar10_weights_best.pt'))\nmodel.eval()\n\n# Fine-Tuning Transformations (additional normalization if needed)\ntransform_finetune = transforms.Compose([\n    transforms.RandomCrop(32, padding=4),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize(CIFAR10_MEAN, CIFAR10_STD),\n    Cutout(length=16),\n])\n\n# Update the training dataset with fine-tuning transformations\nfinetune_trainset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_finetune)\nfinetune_trainloader = DataLoader(finetune_trainset, batch_size=128, shuffle=True, num_workers=4)\n\n# Re-define optimizer for fine-tuning with lower learning rate\nfinetune_optimizer = optim.AdamW(model.parameters(), lr=0.0001, weight_decay=5e-4)\n\n# Re-define scheduler for fine-tuning\nfinetune_scheduler = CosineAnnealingWarmupRestarts(finetune_optimizer, T_0=30, T_mult=1, eta_max=0.0001, T_up=5, gamma=0.5)\n\ndef finetune(epoch):\n    model.train()\n    running_loss = 0.0\n    for batch_idx, (inputs, targets) in enumerate(tqdm(finetune_trainloader, desc=f\"Fine-Tuning Epoch {epoch+1}\")):\n        inputs, targets = inputs.to(device), targets.to(device)\n        finetune_optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, targets)\n        loss.backward()\n        finetune_optimizer.step()\n\n        running_loss += loss.item()\n        if batch_idx % 100 == 99:\n            print(f'[Fine-Tuning Epoch {epoch + 1}, Batch {batch_idx + 1}] loss: {running_loss / 100:.3f}')\n            running_loss = 0.0\n\ndef finetune_validate(epoch):\n    model.eval()\n    correct = 0\n    total = 0\n    with torch.no_grad():\n        for inputs, targets in tqdm(testloader, desc=f\"Fine-Tuning Validation Epoch {epoch+1}\"):\n            inputs, targets = inputs.to(device), targets.to(device)\n            outputs = model(inputs)\n            _, predicted = torch.max(outputs, 1)\n            total += targets.size(0)\n            correct += predicted.eq(targets).sum().item()\n    accuracy = 100. * correct / total\n    print(f'Fine-Tuning Validation Accuracy after Epoch {epoch + 1}: {accuracy:.2f}%')\n    return accuracy\n\n# Fine-Tuning loop\nfine_tune_epochs = 15\nfor epoch in range(fine_tune_epochs):\n    finetune(epoch)\n    acc = finetune_validate(epoch)\n    finetune_scheduler.step()\n\n    # Save the fine-tuned model checkpoint if it's the best so far\n    if acc > best_acc:\n        best_acc = acc\n        torch.save(model.state_dict(), 'resnet152_cifar10_finetuned_best.pt')\n        print(f\"Fine-Tuned best model saved with accuracy: {best_acc:.2f}%\")\n\nprint(\"Fine-Tuning completed.\")\n\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-10-04T16:13:35.355585Z","iopub.execute_input":"2025-10-04T16:13:35.355853Z","iopub.status.idle":"2025-10-04T21:15:53.244454Z","shell.execute_reply.started":"2025-10-04T16:13:35.355830Z","shell.execute_reply":"2025-10-04T21:15:53.243430Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# Inference on Test Set\n# -----------------------------\n\n# Decompressing Test Data (Assuming you have a 7z file)\n# Note: Adjust the paths based on your environment\ntest_archive_path = '/kaggle/input/cifar-10/test.7z'\nextracted_path = '/kaggle/working/test'\n\nif not os.path.exists(extracted_path):\n    os.makedirs(extracted_path, exist_ok=True)\n    with py7zr.SevenZipFile(test_archive_path, mode='r') as z:\n        z.extractall(extracted_path)\n    print(\"Test data decompressed successfully.\")\nelse:\n    print(\"Test data already decompressed.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-04T22:13:14.214953Z","iopub.execute_input":"2025-10-04T22:13:14.215646Z","iopub.status.idle":"2025-10-04T22:13:14.221006Z","shell.execute_reply.started":"2025-10-04T22:13:14.215620Z","shell.execute_reply":"2025-10-04T22:13:14.220368Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"archive_path = '/kaggle/input/cifar-10/test.7z'\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-04T22:33:25.448113Z","iopub.execute_input":"2025-10-04T22:33:25.448643Z","iopub.status.idle":"2025-10-04T22:33:25.452096Z","shell.execute_reply.started":"2025-10-04T22:33:25.448622Z","shell.execute_reply":"2025-10-04T22:33:25.451301Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import py7zr, os\n\nextracted_path = '/kaggle/working/test'\n\nif not os.path.exists(extracted_path):\n    os.makedirs(extracted_path, exist_ok=True)\n    with py7zr.SevenZipFile(archive_path, mode='r') as z:\n        z.extractall(path=extracted_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-04T22:34:13.056285Z","iopub.execute_input":"2025-10-04T22:34:13.056519Z","iopub.status.idle":"2025-10-04T22:34:13.060663Z","shell.execute_reply.started":"2025-10-04T22:34:13.056504Z","shell.execute_reply":"2025-10-04T22:34:13.060057Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import py7zr\nimport os\n\narchive_path = '/kaggle/input/cifar-10/test.7z'  # Your CIFAR-10 test.7z file\nextracted_path = '/kaggle/working/test'\n\n# Create the extraction folder if it doesn't exist\nif not os.path.exists(extracted_path):\n    os.makedirs(extracted_path, exist_ok=True)\n\n# Extract the .7z archive\nwith py7zr.SevenZipFile(archive_path, mode='r') as z:\n    z.extractall(path=extracted_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-04T22:39:29.645154Z","iopub.execute_input":"2025-10-04T22:39:29.645955Z","iopub.status.idle":"2025-10-04T22:41:29.240888Z","shell.execute_reply.started":"2025-10-04T22:39:29.645928Z","shell.execute_reply":"2025-10-04T22:41:29.240334Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls /kaggle/working/test\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-04T22:42:08.159250Z","iopub.execute_input":"2025-10-04T22:42:08.159507Z","iopub.status.idle":"2025-10-04T22:42:08.334070Z","shell.execute_reply.started":"2025-10-04T22:42:08.159490Z","shell.execute_reply":"2025-10-04T22:42:08.333092Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Install required package\n!pip install py7zr\n\n# -----------------------------\n# Required Imports\n# -----------------------------\n\nimport os\nimport torch\nfrom PIL import Image\nimport pandas as pd\nimport torchvision.transforms as transforms\nfrom torch.utils.data import DataLoader, Dataset\n\n# -----------------------------\n# Model Definition: ResNet152\n# -----------------------------\n\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nclass Bottleneck(nn.Module):\n    expansion = 4\n\n    def __init__(self, in_planes, planes, stride=1):\n        super(Bottleneck, self).__init__()\n        self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(planes)\n        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm2d(planes)\n        self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False)\n        self.bn3 = nn.BatchNorm2d(planes * self.expansion)\n\n        self.shortcut = nn.Sequential()\n        if stride != 1 or in_planes != planes * self.expansion:\n            self.shortcut = nn.Sequential(\n                nn.Conv2d(in_planes, planes * self.expansion, kernel_size=1, stride=stride, bias=False),\n                nn.BatchNorm2d(planes * self.expansion)\n            )\n\n    def forward(self, x):\n        out = F.relu(self.bn1(self.conv1(x)))\n        out = F.relu(self.bn2(self.conv2(out)))\n        out = self.bn3(self.conv3(out))\n        out += self.shortcut(x)\n        out = F.relu(out)\n        return out\n\nclass ResNet(nn.Module):\n    def __init__(self, block, num_blocks, num_classes=10):\n        super(ResNet, self).__init__()\n        self.in_planes = 64\n\n        # Stem layer\n        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(64)\n\n        # ResNet layers\n        self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)\n        self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)\n        self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)\n        self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)\n\n        # Final classifier layer\n        self.linear = nn.Linear(512 * block.expansion, num_classes)\n\n        # Initialize weights\n        self._initialize_weights()\n\n    def _make_layer(self, block, planes, num_blocks, stride):\n        strides = [stride] + [1] * (num_blocks - 1)\n        layers = []\n        for stride in strides:\n            layers.append(block(self.in_planes, planes, stride))\n            self.in_planes = planes * block.expansion\n        return nn.Sequential(*layers)\n\n    def _initialize_weights(self):\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')\n                if m.bias is not None:\n                    nn.init.zeros_(m.bias)\n            elif isinstance(m, nn.BatchNorm2d):\n                nn.init.ones_(m.weight)\n                nn.init.zeros_(m.bias)\n            elif isinstance(m, nn.Linear):\n                nn.init.normal_(m.weight, 0, 0.01)\n                nn.init.zeros_(m.bias)\n\n    def forward(self, x):\n        out = F.relu(self.bn1(self.conv1(x)))\n        out = self.layer1(out)\n        out = self.layer2(out)\n        out = self.layer3(out)\n        out = self.layer4(out)\n        out = F.avg_pool2d(out, 4)\n        out = out.view(out.size(0), -1)\n        out = self.linear(out)\n        return out\n\ndef ResNet152():\n    return ResNet(Bottleneck, [3, 8, 36, 3])\n\n# -----------------------------\n# Define CIFAR-10 Classes\n# -----------------------------\n\nclasses = ['airplane', 'automobile', 'bird', 'cat', 'deer', \n           'dog', 'frog', 'horse', 'ship', 'truck']\n\n# -----------------------------\n# Custom Dataset Class\n# -----------------------------\n\nclass CustomImageDataset(Dataset):\n    def __init__(self, image_dir, transform=None):\n        \"\"\"\n        Args:\n            image_dir (str): Path to the directory with test images.\n            transform (callable, optional): Optional transform to be applied on a sample.\n        \"\"\"\n        self.image_dir = image_dir\n        self.transform = transform\n        self.image_filenames = sorted(os.listdir(image_dir))\n\n    def __len__(self):\n        return len(self.image_filenames)\n\n    def __getitem__(self, idx):\n        img_name = os.path.join(self.image_dir, self.image_filenames[idx])\n        image = Image.open(img_name).convert('RGB')\n        if self.transform:\n            image = self.transform(image)\n        # Extract image ID from filename (assuming filename starts with an integer)\n        img_id_str = os.path.basename(img_name).split('.')[0]\n        try:\n            img_id = int(img_id_str)\n        except ValueError:\n            # Handle cases where the filename does not start with an integer\n            img_id = img_id_str  # You can choose to skip or handle differently\n        return image, img_id\n\n# -----------------------------\n# Data Loading and Preprocessing\n# -----------------------------\n\n# CIFAR-10 mean and std for normalization (Ensure these match the training phase)\nCIFAR10_MEAN = (0.4914, 0.4822, 0.4465)\nCIFAR10_STD = (0.2023, 0.1994, 0.2010)\n\n# Define the test data transformations (consistent with training)\ninference_transforms = transforms.Compose([\n    transforms.Resize((32, 32)),  # CIFAR-10 images are 32x32\n    transforms.ToTensor(),\n    transforms.Normalize(CIFAR10_MEAN, CIFAR10_STD),\n])\n\n# -----------------------------\n# Instantiate the Model\n# -----------------------------\n\nmodel = ResNet152().to(device)\nprint(\"Model instantiated successfully.\")\n\n# -----------------------------\n# Load Model Weights\n# -----------------------------\n\nmodel_path = '/kaggle/working/resnet152_cifar10_finetuned_best.pt'  # Path to the fine-tuned model weights\n\nif os.path.exists(model_path):\n    model.load_state_dict(torch.load(model_path, map_location=device))\n    print(\"Model weights loaded successfully.\")\nelse:\n    raise FileNotFoundError(f\"Model weights file not found at {model_path}. Please check the path.\")\n\nmodel.eval()\n\n# -----------------------------\n# Prepare Test DataLoader\n# -----------------------------\n\n# Set the path to your test data directory on Kaggle\ntest_dir = '/kaggle/working/test/test' \n  # Adjust this path based on where your test images are extracted\n\n# Ensure the test directory exists\nif not os.path.exists(test_dir):\n    raise FileNotFoundError(f\"Test directory not found at {test_dir}. Please check the path.\")\n\n# Create the dataset and dataloader\ntest_dataset = CustomImageDataset(test_dir, transform=inference_transforms)\ntest_loader = DataLoader(test_dataset, batch_size=64, shuffle=False, num_workers=4)\n\n# -----------------------------\n# Perform Inference and Save Predictions\n# -----------------------------\n\n# Perform inference and store results\nall_predictions = []\nall_filenames = []\n\nwith torch.no_grad():\n    for inputs, img_ids in tqdm(test_loader, desc=\"Performing Inference\"):\n        inputs = inputs.to(device)\n        \n        # Forward pass\n        outputs = model(inputs)\n        \n        # Get predicted class\n        _, predicted = torch.max(outputs, 1)\n        \n        # Move predictions to CPU and convert to numpy\n        predicted = predicted.cpu().numpy()\n        \n        # Append predictions and corresponding image IDs\n        for img_id, pred in zip(img_ids, predicted):\n            # Handle non-integer img_ids if necessary\n            if isinstance(img_id, int):\n                label = classes[pred]\n                all_predictions.append((img_id, label))\n            else:\n                # If img_id is not integer, handle accordingly (e.g., skip or assign a default value)\n                label = classes[pred]\n                all_predictions.append((img_id, label))\n\n# -----------------------------\n# Save Predictions to CSV\n# -----------------------------\n\n# Convert the list of tuples to a DataFrame\nsubmission_df = pd.DataFrame(all_predictions, columns=['id', 'label'])\n\n# If you need 'id' to be integers and they are currently strings, convert them\n# This step assumes that all 'id's are integers\nif submission_df['id'].apply(lambda x: isinstance(x, int)).all():\n    submission_df['id'] = submission_df['id'].astype(int)\nelse:\n    # Handle cases where 'id's are not all integers\n    # For example, you might extract numeric part if 'id's are strings like 'test_1'\n    submission_df['id'] = submission_df['id'].apply(lambda x: int(''.join(filter(str.isdigit, x))) if isinstance(x, str) else x)\n\n# Sort the DataFrame by 'id' if necessary\nsubmission_df = submission_df.sort_values(by='id')\nsubmission_df['id'] = submission_df['id'].astype(int)\n# Save the DataFrame to a CSV file\nsubmission_df.to_csv('resnet152_cifar10_predictions_updated.csv', index=False)\n\nprint(\"Predictions saved to resnet152_cifar10_predictions.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-04T22:42:21.432147Z","iopub.execute_input":"2025-10-04T22:42:21.432792Z","iopub.status.idle":"2025-10-04T22:49:27.225260Z","shell.execute_reply.started":"2025-10-04T22:42:21.432763Z","shell.execute_reply":"2025-10-04T22:49:27.224385Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}