{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"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":"gpu","dataSources":[{"sourceId":6799,"databundleVersionId":4225553,"sourceType":"competition"}],"dockerImageVersionId":30822,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport torch\nfrom torch import nn\nfrom torchvision.io import read_image\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision.transforms import v2\nimport glob\nimport shutil\nfrom tqdm import tqdm\nimport matplotlib.pyplot as plt\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:01.010649Z","iopub.execute_input":"2025-01-01T03:23:01.010933Z","iopub.status.idle":"2025-01-01T03:23:05.390677Z","shell.execute_reply.started":"2025-01-01T03:23:01.010901Z","shell.execute_reply":"2025-01-01T03:23:05.390012Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Making labels from ImageNet ","metadata":{}},{"cell_type":"code","source":"id2labels = {}\nclass2id = {}\nid2class = {}\nids = []\n\nwith open('/kaggle/input/imagenet-object-localization-challenge/LOC_synset_mapping.txt', 'r') as file:\n    for idx, line in enumerate(file):\n        parts = line.split(' ', 1)  # Split at the first space\n        synset_id = parts[0]\n        description = parts[1].strip() if len(parts) > 1 else ''\n        id2labels[synset_id] = description\n        class2id[idx] = synset_id\n        id2class[synset_id] = idx\n        ids.append(synset_id)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:05.39195Z","iopub.execute_input":"2025-01-01T03:23:05.392605Z","iopub.status.idle":"2025-01-01T03:23:05.408555Z","shell.execute_reply.started":"2025-01-01T03:23:05.39257Z","shell.execute_reply":"2025-01-01T03:23:05.407744Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"os.makedirs('labels/train', exist_ok=True)\nos.makedirs('labels/val', exist_ok=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:05.41036Z","iopub.execute_input":"2025-01-01T03:23:05.410591Z","iopub.status.idle":"2025-01-01T03:23:05.413839Z","shell.execute_reply.started":"2025-01-01T03:23:05.41057Z","shell.execute_reply":"2025-01-01T03:23:05.413163Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dirs = glob.glob('/kaggle/input/imagenet-object-localization-challenge/ILSVRC/Data/CLS-LOC/train/*')\ni, j = 0, 0\nfor img_folder_path in tqdm(train_dirs):\n    i += 1\n    synset_id = os.path.basename(img_folder_path)\n    class_id = id2class[synset_id]\n\n    img_files = glob.glob(os.path.join(f\"/kaggle/input/imagenet-object-localization-challenge/ILSVRC/Data/CLS-LOC/train/{synset_id}/\", \"*.JPEG\"))\n    img_files = [os.path.basename(img) for img in img_files]\n    j += len(img_files)\n    with open(f'labels/train/train_labels.csv', 'a') as f:\n        if i == 1: \n            f.write(\"image, class \\n\")\n        for img in img_files:\n            f.write(f'{img}, {class_id} \\n')\n\nprint(f'Total number of training folders: {i}')\nprint(f'Total number of training images: {j}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:05.414847Z","iopub.execute_input":"2025-01-01T03:23:05.415153Z","iopub.status.idle":"2025-01-01T03:23:27.709419Z","shell.execute_reply.started":"2025-01-01T03:23:05.415122Z","shell.execute_reply":"2025-01-01T03:23:27.708684Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('/kaggle/input/imagenet-object-localization-challenge/LOC_val_solution.csv')\ndf.sort_values(by='ImageId', inplace=True)\n\nj = 0\nfor i, row in tqdm(df.iterrows()):\n    j += 1\n    parts = row['PredictionString'].split(' ', 1)\n    img = row['ImageId'] + '.JPEG'\n    class_id = id2class[parts[0]]\n    with open(f'labels/val/val_labels.csv', 'a') as f:\n        f.write(f'{img}, {class_id} \\n')\n\nprint(f'Total number of valuation images: {j}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:27.710191Z","iopub.execute_input":"2025-01-01T03:23:27.710433Z","iopub.status.idle":"2025-01-01T03:23:32.117913Z","shell.execute_reply.started":"2025-01-01T03:23:27.710405Z","shell.execute_reply":"2025-01-01T03:23:32.117124Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Create custom dataset","metadata":{}},{"cell_type":"code","source":"df2 = pd.read_csv('/kaggle/working/labels/train/train_labels.csv')\ndf2.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:32.118742Z","iopub.execute_input":"2025-01-01T03:23:32.119024Z","iopub.status.idle":"2025-01-01T03:23:32.915339Z","shell.execute_reply.started":"2025-01-01T03:23:32.118987Z","shell.execute_reply":"2025-01-01T03:23:32.914578Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Make training dataset and dataloader","metadata":{}},{"cell_type":"code","source":"class ImageNetCLS(Dataset):\n    def __init__(self, annotations_file, img_dir, transform=None, target_transform=None, train=True):\n        self.img_labels = pd.read_csv(annotations_file)\n        self.img_dir = img_dir\n        self.transform = transform\n        self.target_transform = target_transform\n        self.train = train\n\n    def __len__(self):\n        return len(self.img_labels)\n\n    def __getitem__(self, idx):\n        img_file = self.img_labels.iloc[idx, 0]  # Assuming the first column in the CSV has image filenames\n        class_id = self.img_labels.iloc[idx, 1]  # Assuming the second column in the CSV has class labels\n\n        # Construct full image path\n        if self.train:\n            folder_path = os.path.join(self.img_dir, class2id[class_id])\n            img_path = os.path.join(folder_path, img_file)\n        else:\n            img_path = os.path.join(self.img_dir, img_file)\n\n        \n        # Read image\n        image = read_image(img_path)\n        # Convert grayscale (1 channel) to RGB (3 channels)\n        if image.shape[0] == 1:\n            image = image.expand(3, -1, -1)  # Duplicate the single channel to create 3 channels\n    \n        # Handle RGBA images (4 channels) by converting to RGB\n        elif image.shape[0] == 4:\n            image = image[:3, :, :]  # Retain only the first 3 channels (RGB)\n\n        # Apply transforms\n        if self.transform:\n            image = self.transform(image)\n\n        # Apply target_transform\n        if self.target_transform:\n            class_id = self.target_transform(class_id)\n\n        return image, class_id\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:32.916076Z","iopub.execute_input":"2025-01-01T03:23:32.916368Z","iopub.status.idle":"2025-01-01T03:23:32.922651Z","shell.execute_reply.started":"2025-01-01T03:23:32.916344Z","shell.execute_reply":"2025-01-01T03:23:32.921814Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Define a transform to load the images\n# transform = v2.Compose([\n#     v2.Resize(256),   # Resize shorter side to 256\n#     v2.CenterCrop(224),  # Crop to 224x224\n#     v2.ToTensor()  # Convert to tensor and scale to [0, 1]\n# ])\n\n# # Load your dataset (replace with your dataset path)\n# train_annotations_file = '/kaggle/working/labels/train/train_labels.csv'\n# train_img_dir= '/kaggle/input/imagenet-object-localization-challenge/ILSVRC/Data/CLS-LOC/train/'\n\n# dataset = ImageNetCLS(annotations_file=train_annotations_file, \n#                   img_dir=train_img_dir,\n#                   transform=transform,\n#                   train=True)\n# dataloader = DataLoader(dataset, batch_size=32, shuffle=False, num_workers=4)\n\n# # Initialize accumulators\n# channel_sum = torch.zeros(3)  # For R, G, B\n# channel_squared_sum = torch.zeros(3)\n# num_pixels = 0\n\n# # Iterate through the dataset\n# for images, _ in dataloader:  # Images shape: [batch_size, 3, H, W]\n#     num_pixels += images.size(0) * images.size(2) * images.size(3)  # Count pixels in the batch\n#     channel_sum += images.sum(dim=[0, 2, 3])  # Sum over batch, height, and width\n#     channel_squared_sum += (images ** 2).sum(dim=[0, 2, 3])  # Sum of squares for std computation\n\n# # Compute mean and std\n# mean = channel_sum / num_pixels\n# std = torch.sqrt(channel_squared_sum / num_pixels - mean ** 2)\n\n# print(f\"Mean: {mean}\")\n# print(f\"Std: {std}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:32.92339Z","iopub.execute_input":"2025-01-01T03:23:32.923606Z","iopub.status.idle":"2025-01-01T03:23:32.943257Z","shell.execute_reply.started":"2025-01-01T03:23:32.923587Z","shell.execute_reply":"2025-01-01T03:23:32.942574Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_annotations_file = '/kaggle/working/labels/train/train_labels.csv'\ntrain_img_dir= '/kaggle/input/imagenet-object-localization-challenge/ILSVRC/Data/CLS-LOC/train/'\n\nS = 256\ntrain_transform = v2.Compose([\n    v2.Resize(S),\n    v2.RandomCrop((224,244)),\n    v2.RandomHorizontalFlip(p=0.5),\n    v2.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),\n    v2.ToTensor(),\n    v2.ToDtype(torch.float32, scale=True),\n    v2.Normalize(mean = [0.485, 0.456, 0.406],  std = [0.229, 0.224, 0.225]),\n])\ntrain_dataset = ImageNetCLS(annotations_file=train_annotations_file, \n                            img_dir=train_img_dir,\n                            transform=train_transform,\n                            train=True)\n\nval_annotations_file = '/kaggle/working/labels/val/val_labels.csv'\nval_img_dir = '/kaggle/input/imagenet-object-localization-challenge/ILSVRC/Data/CLS-LOC/val'\n\nQ = 256\nval_transform = v2.Compose([\n    v2.Resize(Q),\n    v2.RandomCrop((224,244)),\n    v2.ToTensor(),\n    v2.ToDtype(torch.float32, scale=True),\n    v2.Normalize(mean = [0.485, 0.456, 0.406],  std = [0.229, 0.224, 0.225]),\n])\nval_dataset = ImageNetCLS(annotations_file=val_annotations_file, \n                             img_dir=val_img_dir,\n                             transform=val_transform,\n                             train=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:35:02.67347Z","iopub.execute_input":"2025-01-01T03:35:02.673784Z","iopub.status.idle":"2025-01-01T03:35:03.431637Z","shell.execute_reply.started":"2025-01-01T03:35:02.673754Z","shell.execute_reply":"2025-01-01T03:35:03.430667Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dataloader = DataLoader(train_dataset, batch_size=64, shuffle=True)\nval_dataloader = DataLoader(val_dataset, batch_size=64, shuffle=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:35:24.522229Z","iopub.execute_input":"2025-01-01T03:35:24.522532Z","iopub.status.idle":"2025-01-01T03:35:24.526452Z","shell.execute_reply.started":"2025-01-01T03:35:24.52251Z","shell.execute_reply":"2025-01-01T03:35:24.525542Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# for image, label in val_dataloader:\n#     print(f\"Image type: {image.shape} {label}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:35:28.595371Z","iopub.execute_input":"2025-01-01T03:35:28.595645Z","iopub.status.idle":"2025-01-01T03:35:37.233915Z","shell.execute_reply.started":"2025-01-01T03:35:28.595625Z","shell.execute_reply":"2025-01-01T03:35:37.232807Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# for image, label in train_dataloader:\n#     print(f'{image.shape} {label}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:33.762673Z","iopub.status.idle":"2025-01-01T03:23:33.762907Z","shell.execute_reply":"2025-01-01T03:23:33.762811Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Build network architecture","metadata":{}},{"cell_type":"code","source":"# Get cpu, gpu or mps device for training.\ndevice = (\n    \"cuda\"\n    if torch.cuda.is_available()\n    else \"mps\"\n    if torch.backends.mps.is_available()\n    else \"cpu\"\n)\nprint(f\"Using {device} device\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:33.763401Z","iopub.status.idle":"2025-01-01T03:23:33.763637Z","shell.execute_reply":"2025-01-01T03:23:33.763543Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class VGG16(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.features = nn.Sequential(\n            # Block 1\n            nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n\n            # Block 2\n            nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n\n            # Block 3 \n            nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n\n            # Block 4\n            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n\n            # Block 5\n            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding='same'),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2),\n        )\n\n        self.classifier = nn.Sequential(\n            nn.Flatten(),\n            nn.Linear(512 * 7 * 7, 4096),\n            nn.Dropout(p=0.5),\n            nn.Linear(4096, 4096),\n            nn.Dropout(p=0.5),\n            nn.Linear(4096, 1000),\n        )\n\n    def forward(self, x):\n        x = self.features(x)\n        logits = self.classifier(x)\n        return logits\n\nmodel = VGG16().to(device)\nprint(model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:33.76452Z","iopub.status.idle":"2025-01-01T03:23:33.764798Z","shell.execute_reply":"2025-01-01T03:23:33.764659Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Weights and bias initialization\nimport torch.nn.init as init\n\ndef initialize_weights(m):\n    if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear):\n        init.xavier_uniform_(m.weight)\n        if m.bias is not None:\n            init.constant_(m.bias, 0)\n\nmodel.apply(initialize_weights)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:33.765456Z","iopub.status.idle":"2025-01-01T03:23:33.765752Z","shell.execute_reply":"2025-01-01T03:23:33.765644Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.optim.lr_scheduler import StepLR\n\nloss_fn = nn.CrossEntropyLoss()\noptimizer = torch.optim.SGD(\n    model.parameters(),\n    lr=1e-2,\n    momentum=0.9,\n    weight_decay=5e-4,   \n)\n\n# Decrease learning rate by a factor of 10 every specified number of iterations \nscheduler = StepLR(optimizer, step_size=25, gamma=0.1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:33.766493Z","iopub.status.idle":"2025-01-01T03:23:33.766878Z","shell.execute_reply":"2025-01-01T03:23:33.766709Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train(dataloader, model, loss_fn, optimizer):\n    size = len(dataloader.dataset)\n    model.train()\n    total_loss = 0\n    for batch, (X, y) in enumerate(dataloader):\n        X, y = X.to(device), y.to(device)\n\n        pred = model(X)\n        loss = loss_fn(pred, y)\n        total_loss += loss.item()\n\n        loss.backward()\n        optimizer.step()\n        optimizer.zero_grad()\n\n    scheduler.step()\n    avg_train_loss = total_loss / len(dataloader)\n    return avg_train_loss\n\n\ndef test(dataloader, model, loss_fn):\n    size = len(dataloader.dataset)\n    num_batches = len(dataloader)\n    model.eval()\n\n    test_loss, correct = 0, 0\n    with torch.no_grad():\n        for X, y in dataloader:\n            X, y = X.to(device), y.to(device)\n            pred = model(X)\n            test_loss += loss_fn(pred, y).item()\n            correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n    avg_test_loss = test_loss / num_batches\n    accuracy = correct / size\n    return accuracy, avg_test_loss","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:33.767612Z","iopub.status.idle":"2025-01-01T03:23:33.768143Z","shell.execute_reply":"2025-01-01T03:23:33.767952Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"epochs = 1\nfor t in range(epochs):\n    avg_train_loss = train(train_dataloader, model, loss_fn, optimizer)\n    if t == 0 or (t + 1) % 5 == 0 or t == epochs - 1:  # Print every 5 epochs or the last epoch\n        accuracy, avg_test_loss = test(val_dataloader, model, loss_fn)\n        print(f\"Epoch {t+1}\\n-------------------------------\")\n        print(f\"Train Avg Loss: {avg_train_loss:>8f}\")\n        print(f\"Test Accuracy: {(100 * accuracy):>0.1f}%, Test Avg Loss: {avg_test_loss:>8f} \\n\")\nprint(\"Done!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-01T03:23:33.768718Z","iopub.status.idle":"2025-01-01T03:23:33.769102Z","shell.execute_reply":"2025-01-01T03:23:33.768925Z"}},"outputs":[],"execution_count":null}]}