{"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":"# 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-09-23T19:03:25.563547Z","iopub.execute_input":"2025-09-23T19:03:25.563824Z","iopub.status.idle":"2025-09-23T19:03:28.176538Z","shell.execute_reply.started":"2025-09-23T19:03:25.563801Z","shell.execute_reply":"2025-09-23T19:03:28.175171Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torchvision\nimport torchvision.transforms as transforms\nfrom torch.utils.data import DataLoader\n\n# 1. Strong data augmentation\ntransform_train = transforms.Compose([\n    transforms.RandomCrop(32, padding=4),\n    transforms.RandomHorizontalFlip(),\n    transforms.ColorJitter(0.2, 0.2, 0.2, 0.1),\n    transforms.RandomRotation(15),\n    transforms.AutoAugment(policy=transforms.AutoAugmentPolicy.CIFAR10),\n    transforms.ToTensor(),\n    transforms.Normalize((0.4914, 0.4822, 0.4465),\n                         (0.2470, 0.2435, 0.2616)),\n    transforms.RandomErasing(p=0.25, scale=(0.02, 0.2), ratio=(0.3, 3.3), value='random')\n])\n\ntransform_test = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize((0.4914, 0.4822, 0.4465),\n                         (0.2470, 0.2435, 0.2616)),\n])\n\n# 2. CIFAR-10 dataset and loaders\ntrainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train)\ntrainloader = DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2)\n\ntestset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)\ntestloader = DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)\n\n# 3. Improved ConvNet model for CIFAR-10\nclass CIFAR10ConvNet(nn.Module):\n    def __init__(self, num_classes=10):\n        super(CIFAR10ConvNet, self).__init__()\n        self.features = nn.Sequential(\n            nn.Conv2d(3, 64, 3, padding=1),\n            nn.BatchNorm2d(64),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(64, 64, 3, padding=1),\n            nn.BatchNorm2d(64),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(2),  # 16x16\n\n            nn.Conv2d(64, 128, 3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(128, 128, 3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(2),  # 8x8\n\n            nn.Conv2d(128, 256, 3, padding=1),\n            nn.BatchNorm2d(256),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(256, 256, 3, padding=1),\n            nn.BatchNorm2d(256),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d(2),  # 4x4\n        )\n        self.classifier = nn.Sequential(\n            nn.Dropout(0.5),\n            nn.Linear(256 * 4 * 4, 512),\n            nn.ReLU(inplace=True),\n            nn.Dropout(0.5),\n            nn.Linear(512, num_classes)\n        )\n\n    def forward(self, x):\n        x = self.features(x)\n        x = x.view(x.size(0), -1)  # Flatten\n        x = self.classifier(x)\n        return x\n\n# 4. Set device, model, loss, optimizer\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel = CIFAR10ConvNet().to(device)\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.AdamW(model.parameters(), lr=0.001)\nscheduler = optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.5)\n\n# 5. Training loop\ndef train(model, trainloader, criterion, optimizer, scheduler, device, epochs=100):\n    best_acc = 0\n    for epoch in range(epochs):\n        model.train()\n        running_loss = 0.0\n        correct = 0\n        total = 0\n\n        for i, (inputs, labels) in enumerate(trainloader):\n            inputs, labels = inputs.to(device), labels.to(device)\n\n            optimizer.zero_grad()\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            loss.backward()\n            optimizer.step()\n\n            running_loss += loss.item()\n            _, predicted = outputs.max(1)\n            total += labels.size(0)\n            correct += predicted.eq(labels).sum().item()\n\n        scheduler.step()\n\n        acc = 100. * correct / total\n        print(f\"Epoch [{epoch+1}/{epochs}] Loss: {running_loss/len(trainloader):.4f} | Train Acc: {acc:.2f}%\")\n\n# 6. Evaluation\ndef evaluate(model, testloader, device):\n    model.eval()\n    correct = 0\n    total = 0\n    with torch.no_grad():\n        for inputs, labels in testloader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            outputs = model(inputs)\n            _, predicted = torch.max(outputs, 1)\n            total += labels.size(0)\n            correct += (predicted == labels).sum().item()\n\n    print(f'Test Accuracy: {100 * correct / total:.2f}%')\n    return 100 * correct / total\n\n# 7. Train & evaluate\ntrain(model, trainloader, criterion, optimizer, scheduler, device, epochs=100)\nevaluate(model, testloader, device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-23T19:03:54.491799Z","iopub.execute_input":"2025-09-23T19:03:54.492791Z","iopub.status.idle":"2025-09-23T20:08:15.160461Z","shell.execute_reply.started":"2025-09-23T19:03:54.492759Z","shell.execute_reply":"2025-09-23T20:08:15.159723Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(model.state_dict(), 'cifar10_resnet.pth')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-23T20:10:07.60105Z","iopub.execute_input":"2025-09-23T20:10:07.601568Z","iopub.status.idle":"2025-09-23T20:10:07.639152Z","shell.execute_reply.started":"2025-09-23T20:10:07.601532Z","shell.execute_reply":"2025-09-23T20:10:07.638418Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install  py7zr\n# Required Imports\nimport py7zr\nimport os\nfrom tqdm import tqdm\nimport pandas as pd\nfrom PIL import Image\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\n\n# Decompressing data\nwith py7zr.SevenZipFile('/kaggle/input/cifar-10/test.7z', mode='r') as z:\n    z.extractall('/kaggle/working/')\n\n# Sorting filenames and extracting IDs from filenames\ntest_filenames = [os.path.join('/kaggle/working/test', f) for f in os.listdir('/kaggle/working/test')]\ntest_filenames.sort(key=lambda x: int(x.split('/')[-1].split('.')[0]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-23T20:10:39.986849Z","iopub.execute_input":"2025-09-23T20:10:39.987555Z","iopub.status.idle":"2025-09-23T20:12:46.746286Z","shell.execute_reply.started":"2025-09-23T20:10:39.987532Z","shell.execute_reply":"2025-09-23T20:12:46.745404Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nfrom PIL import Image\nimport torch\nimport torch.nn as nn\nimport torchvision.transforms as transforms\n\n# CIFAR-10 classes\ncifar10_classes = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']\n\n# Residual Block used for ResNet\nclass ResidualBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, stride=1):\n        super(ResidualBlock, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm2d(out_channels)\n        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n\n        # Shortcut connection to match the dimensions\n        self.shortcut = nn.Sequential()\n        if stride != 1 or in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),\n                nn.BatchNorm2d(out_channels)\n            )\n\n    def forward(self, x):\n        out = torch.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out += self.shortcut(x)  # Residual connection\n        out = torch.relu(out)\n        return out\n\n# Define the full ResNet model\nclass ResNet(nn.Module):\n    def __init__(self, block, num_blocks, num_classes=10):\n        super(ResNet, self).__init__()\n        self.in_channels = 64\n\n        # Initial convolutional 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 with residual blocks\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        # Fully connected layer for classification\n        self.fc = nn.Linear(512, num_classes)\n\n    def _make_layer(self, block, out_channels, num_blocks, stride):\n        strides = [stride] + [1] * (num_blocks - 1)\n        layers = []\n        for stride in strides:\n            layers.append(block(self.in_channels, out_channels, stride))\n            self.in_channels = out_channels\n        return nn.Sequential(*layers)\n\n    def forward(self, x):\n        out = torch.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 = torch.nn.functional.avg_pool2d(out, 4)\n        out = out.view(out.size(0), -1)  # Flatten the output\n        out = self.fc(out)\n        return out\n\n# Define ResNet18 model\ndef ResNet18():\n    return ResNet(ResidualBlock, [2, 2, 2, 2])\n\n# Inference function to predict and save results to CSV\ndef inference(model, test_folder, device, output_csv='predictions.csv'):\n    model.eval()  # Set model to evaluation mode\n    results = []\n\n    # Transform definition (same as during training)\n    transform = transforms.Compose([\n        transforms.Resize((32, 32)),  # Ensure the images are resized to 32x32\n        transforms.ToTensor(),\n        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2470, 0.2435, 0.2616)),\n    ])\n\n    # Iterate over all images in the test folder\n    for img_name in os.listdir(test_folder):\n        img_path = os.path.join(test_folder, img_name)\n        img = Image.open(img_path).convert('RGB')  # Load image and convert to RGB\n        \n        # Preprocess the image\n        img = transform(img)\n        img = img.unsqueeze(0).to(device)  # Add batch dimension and move to device\n\n        # Perform inference\n        with torch.no_grad():\n            outputs = model(img)\n            _, predicted = torch.max(outputs, 1)\n            predicted_class = cifar10_classes[predicted.item()]  # Map predicted number to class name\n\n        # Extract integer ID from filename (remove .png extension)\n        img_id = int(os.path.splitext(img_name)[0])\n\n        # Type check for the integer ID\n        if not isinstance(img_id, int):\n            raise ValueError(f\"Image ID '{img_name}' could not be converted to an integer.\")\n\n        # Save the result as a dictionary (id = integer file name, label = predicted class)\n        results.append({'id': img_id, 'label': predicted_class})\n\n    # Save the results to a CSV file\n    df = pd.DataFrame(results)\n    df.to_csv(output_csv, index=False)\n    print(f\"Predictions saved to {output_csv}\")\n\n# Example usage (Kaggle working directory for test data)\ntest_folder = '/kaggle/working/test'  # Change this to your test folder path\noutput_csv = '/kaggle/working/predictions.csv'\n\n# Initialize the ResNet model (same as in training)\nmodel = ResNet18()\n\n# Load the trained weights with strict=False\nmodel.load_state_dict(torch.load('/kaggle/working/cifar10_resnet.pth'), strict=False)  # Update with the actual path to your trained model weights\n\n# Move the model to the appropriate device (GPU or CPU)\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel = model.to(device)\n\n# Perform inference and save the results\ninference(model, test_folder, device, output_csv)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-23T20:14:39.916705Z","iopub.execute_input":"2025-09-23T20:14:39.917372Z","iopub.status.idle":"2025-09-23T20:31:14.786691Z","shell.execute_reply.started":"2025-09-23T20:14:39.917342Z","shell.execute_reply":"2025-09-23T20:31:14.78586Z"}},"outputs":[],"execution_count":null}]}