{"metadata":{"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"},"colab":{"provenance":[],"gpuType":"T4","authorship_tag":"ABX9TyMYF7tAbdRnAopf3K6gszuZ"},"accelerator":"GPU","kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":30887,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install albumentations opencv-python wandb timm","metadata":{"id":"DdSyMKrJqatQ","executionInfo":{"status":"ok","timestamp":1739541011915,"user_tz":-420,"elapsed":8356,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"outputId":"8cb14267-5828-4632-9afb-c320f303d8e5","trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:04.709978Z","iopub.execute_input":"2025-04-05T03:14:04.710282Z","iopub.status.idle":"2025-04-05T03:14:09.026078Z","shell.execute_reply.started":"2025-04-05T03:14:04.710252Z","shell.execute_reply":"2025-04-05T03:14:09.025304Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!unzip -q /kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip -d train\n!unzip -q /kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip -d test\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:09.027108Z","iopub.execute_input":"2025-04-05T03:14:09.027388Z","iopub.status.idle":"2025-04-05T03:14:25.480209Z","shell.execute_reply.started":"2025-04-05T03:14:09.027367Z","shell.execute_reply":"2025-04-05T03:14:25.479047Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 1, Import libs","metadata":{"id":"uBsSneZgnGyq"}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torchvision import datasets, transforms\nfrom torch.utils.data import Dataset, DataLoader\nimport torch.optim.lr_scheduler as lr_scheduler\nimport torchvision.models as models\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport random\nimport time\nfrom sklearn.model_selection import train_test_split\n\nimport wandb\nfrom torchsummary import summary\nimport torch.nn.init as init\nimport pandas as pd\nfrom PIL import Image\nimport os\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nimport cv2\nfrom sklearn.metrics import accuracy_score\nfrom sklearn.model_selection import train_test_split\nimport timm\n\n","metadata":{"id":"o6m6egxfnfn2","executionInfo":{"status":"ok","timestamp":1739541324200,"user_tz":-420,"elapsed":355,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:25.481325Z","iopub.execute_input":"2025-04-05T03:14:25.481600Z","iopub.status.idle":"2025-04-05T03:14:35.957109Z","shell.execute_reply.started":"2025-04-05T03:14:25.481577Z","shell.execute_reply":"2025-04-05T03:14:35.956330Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BATCH_SIZE = 64\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nNUM_CLASSES = 2\nNUM_EPOCHS = 50\nLEARNING_RATE = 3e-4\nLR_DECAY = 0.2\nSTEP_SIZE = 5\nDROP_OUT = 0.3\n\nCHECKPOINT_PATH = \"model.pth\"\nWANDB = True\n","metadata":{"id":"TPRLVyOfwz67","executionInfo":{"status":"ok","timestamp":1739541086727,"user_tz":-420,"elapsed":81,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:35.959230Z","iopub.execute_input":"2025-04-05T03:14:35.959589Z","iopub.status.idle":"2025-04-05T03:14:36.010646Z","shell.execute_reply.started":"2025-04-05T03:14:35.959570Z","shell.execute_reply":"2025-04-05T03:14:36.009832Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 2, Prepare data","metadata":{"id":"6Aewu2r6pULw"}},{"cell_type":"code","source":"img = Image.open('/kaggle/working/train/train/cat.1.jpg')\nplt.imshow(img)","metadata":{"id":"WdPUlBm3pdnZ","executionInfo":{"status":"ok","timestamp":1739541087960,"user_tz":-420,"elapsed":1311,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"outputId":"70db5573-6677-40c0-edff-9244a8158a46","trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.012579Z","iopub.execute_input":"2025-04-05T03:14:36.012925Z","iopub.status.idle":"2025-04-05T03:14:36.361607Z","shell.execute_reply.started":"2025-04-05T03:14:36.012892Z","shell.execute_reply":"2025-04-05T03:14:36.360696Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"list_dir = os.listdir('/kaggle/working/train/train')\ntrain_list_dir, test_list_dir = train_test_split(list_dir, test_size=0.4)\nval_list_dir, test_list_dir = train_test_split(test_list_dir, test_size=0.5)","metadata":{"id":"yblJAmMTx42E","executionInfo":{"status":"ok","timestamp":1739541087961,"user_tz":-420,"elapsed":40,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.362564Z","iopub.execute_input":"2025-04-05T03:14:36.362790Z","iopub.status.idle":"2025-04-05T03:14:36.385532Z","shell.execute_reply.started":"2025-04-05T03:14:36.362772Z","shell.execute_reply":"2025-04-05T03:14:36.384743Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = A.Compose([\n    A.Resize(width=224, height=224),\n    A.RandomBrightnessContrast(p=0.2),\n    A.HorizontalFlip(p=0.5),\n    A.Rotate(limit=10, p=0.3, border_mode=cv2.BORDER_CONSTANT),\n    A.RGBShift(r_shift_limit=25, g_shift_limit=25, b_shift_limit=25, p=0.2),\n    A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),\n    ToTensorV2(),  # Move ToTensorV2 to the end of the pipeline\n\n])\ntest_transform = A.Compose([\n    A.Resize(width=224, height=224),\n    A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),\n    ToTensorV2(),  # Move ToTensorV2 to the end of the pipeline\n])","metadata":{"id":"KeFJ_cpytv_A","executionInfo":{"status":"ok","timestamp":1739541087961,"user_tz":-420,"elapsed":33,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.386317Z","iopub.execute_input":"2025-04-05T03:14:36.386601Z","iopub.status.idle":"2025-04-05T03:14:36.396611Z","shell.execute_reply.started":"2025-04-05T03:14:36.386572Z","shell.execute_reply":"2025-04-05T03:14:36.395823Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class DogCatDataset(Dataset):\n    def __init__(self, root_dir, list_dir, transform=None):\n        \"\"\"\n        Args:\n            root_dir (str): Path to the directory containing images.\n            transform (callable, optional): Optional transforms to apply to images.\n        \"\"\"\n        self.root_dir = root_dir\n        self.transform = transform\n        self.image_files = []\n\n        # Collect image paths and labels\n        for file in list_dir:\n            if file.startswith(\"cat.\"):\n                self.image_files.append((file, 0))  # 0 for cat\n            elif file.startswith(\"dog.\"):\n                self.image_files.append((file, 1))  # 1 for dog\n\n        self.image_files.sort()  # Optional: Sort for consistent ordering\n\n    def __len__(self):\n        return len(self.image_files)\n\n    def __getitem__(self, idx):\n        img_name, label = self.image_files[idx]\n        img_path = os.path.join(self.root_dir, img_name)\n        image = np.array(Image.open(img_path).convert(\"RGB\"))  # Ensure RGB format\n\n        if self.transform:\n            image = self.transform(image=image)\n\n        return image['image'], torch.tensor(label, dtype=torch.long)\n","metadata":{"id":"Ldy5rD_TrJ1P","executionInfo":{"status":"ok","timestamp":1739541584372,"user_tz":-420,"elapsed":533,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.397419Z","iopub.execute_input":"2025-04-05T03:14:36.397699Z","iopub.status.idle":"2025-04-05T03:14:36.414295Z","shell.execute_reply.started":"2025-04-05T03:14:36.397679Z","shell.execute_reply":"2025-04-05T03:14:36.413611Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dataset = DogCatDataset(root_dir='/kaggle/working/train/train', list_dir=train_list_dir, transform=transform)\nval_dataset = DogCatDataset(root_dir='/kaggle/working/train/train', list_dir=val_list_dir, transform=test_transform)\ntest_dataset = DogCatDataset(root_dir='/kaggle/working/train/train', list_dir=test_list_dir, transform=test_transform)","metadata":{"id":"1vWOmVMTtLp9","executionInfo":{"status":"ok","timestamp":1739541584372,"user_tz":-420,"elapsed":3,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.414958Z","iopub.execute_input":"2025-04-05T03:14:36.415200Z","iopub.status.idle":"2025-04-05T03:14:36.449747Z","shell.execute_reply.started":"2025-04-05T03:14:36.415179Z","shell.execute_reply":"2025-04-05T03:14:36.449073Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE,\n                          shuffle=True, num_workers=os.cpu_count())\nval_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE,\n                        shuffle=False, num_workers=os.cpu_count())\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE,\n                        shuffle=False, num_workers=os.cpu_count())","metadata":{"id":"sp0qmJnZwxwU","executionInfo":{"status":"ok","timestamp":1739541584372,"user_tz":-420,"elapsed":3,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.450483Z","iopub.execute_input":"2025-04-05T03:14:36.450758Z","iopub.status.idle":"2025-04-05T03:14:36.463162Z","shell.execute_reply.started":"2025-04-05T03:14:36.450731Z","shell.execute_reply":"2025-04-05T03:14:36.462413Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3, Model","metadata":{"id":"dCWDrstyyWM5"}},{"cell_type":"code","source":"class SimpleCNN(nn.Module):\n    def __init__(self, num_classes):\n        super(SimpleCNN, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1)\n        self.bn1 = nn.BatchNorm2d(32)\n        self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)\n        self.dropout = nn.Dropout(p=0.5)\n        \n        self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1)\n        self.bn2 = nn.BatchNorm2d(64)\n        \n        self.flatten = nn.Flatten()\n        self.relu = nn.ReLU()        \n        self.fc1 = nn.Linear(64 * 56 * 56, 512)  # Changed from 128 to 64 channels\n        self.fc2 = nn.Linear(512, num_classes)\n        # Apply Xavier initialization\n        self._initialize_weights()\n        \n    def _initialize_weights(self):\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear):\n                nn.init.xavier_uniform_(m.weight)\n                if m.bias is not None:\n                    nn.init.zeros_(m.bias)    \n    def forward(self, x):\n        x = self.pool(self.relu(self.bn1(self.conv1(x))))\n        x = self.pool(self.relu(self.bn2(self.conv2(x))))\n        \n        x = self.flatten(x)\n        x = self.relu(self.fc1(x))\n        x = self.dropout(x)\n        x = self.fc2(x)\n        \n        return x","metadata":{"id":"FkGal9FVydpi","executionInfo":{"status":"ok","timestamp":1739541584675,"user_tz":-420,"elapsed":306,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.464058Z","iopub.execute_input":"2025-04-05T03:14:36.464270Z","iopub.status.idle":"2025-04-05T03:14:36.479536Z","shell.execute_reply.started":"2025-04-05T03:14:36.464252Z","shell.execute_reply":"2025-04-05T03:14:36.478723Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn \n\nVGG_types = {\n    \"VGG16\": [64, 64, \"M\",\n              128, 128, \"M\",\n              256, 256, 256, \"M\",\n              512, 512, 512, \"M\",\n              512, 512, 512, \"M\",\n    ],\n    \"VGG19\": [64, 64, \"M\",\n              128, 128, \"M\",\n              256, 256, 256, 256, \"M\",\n              512, 512, 512, 512, \"M\",\n              512, 512, 512, 512, \"M\",\n    ],\n}\n\n\nclass VGG_net(nn.Module):\n    def __init__(self, VGG_name, in_channels=3, num_classes=1):\n        super(VGG_net, self).__init__()\n        self.in_channels = in_channels\n        self.conv_layers = self.create_conv_layers(VGG_types[VGG_name])\n\n        self.fcs = nn.Sequential(\n            nn.Linear(512 * 7 * 7, 4096),\n            nn.ReLU(),\n            nn.Dropout(p=0.5),\n            nn.Linear(4096, 4096),\n            nn.ReLU(),\n            nn.Dropout(p=0.5),\n            nn.Linear(4096, num_classes),\n        )\n\n    def forward(self, x):\n        x = self.conv_layers(x)\n        x = x.reshape(x.shape[0], -1)\n        x = self.fcs(x)\n        return x\n\n    def create_conv_layers(self, architecture):\n        layers = []\n        in_channels = self.in_channels\n\n        for x in architecture:\n            if type(x) == int:\n                out_channels = x\n\n                layers += [\n                    nn.Conv2d(\n                        in_channels=in_channels,\n                        out_channels=out_channels,\n                        kernel_size=(3, 3),\n                        stride=(1, 1),\n                        padding=(1, 1),\n                    ),\n                    nn.BatchNorm2d(x),\n                    nn.ReLU(),\n                ]\n                in_channels = x\n            elif x == \"M\":\n                layers += [nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 2))]\n\n        return nn.Sequential(*layers)\n\n\ndef VGG16(in_channels=3, num_classes=1):\n    return VGG_net(\"VGG16\", in_channels=3, num_classes=1)\n\ndef VGG19(in_channels=3, num_classes=1):\n    return VGG_net(\"VGG19\", in_channels=3, num_classes=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.480377Z","iopub.execute_input":"2025-04-05T03:14:36.480627Z","iopub.status.idle":"2025-04-05T03:14:36.499627Z","shell.execute_reply.started":"2025-04-05T03:14:36.480597Z","shell.execute_reply":"2025-04-05T03:14:36.498811Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n\nclass AlexNet(nn.Module):\n    def __init__(self, num_classes=1000):\n        super(AlexNet, self).__init__()\n        self.num_classes = num_classes\n        self.conv1 = nn.Conv2d(\n            in_channels=3,\n            out_channels=96,\n            kernel_size=11,\n            stride=4,\n            padding=0,\n        )\n        self.batchnorm1 = nn.BatchNorm2d(96)\n        self.conv2 = nn.Conv2d(\n            in_channels=96,\n            out_channels=256,\n            kernel_size=5,\n            stride=1,   \n            padding=2,\n        )\n        self.batchnorm2 = nn.BatchNorm2d(256)\n        self.conv3 = nn.Conv2d(\n            in_channels=256,\n            out_channels=384,\n            kernel_size=3,\n            stride=1,\n            padding=1,\n        )\n        self.batchnorm3 = nn.BatchNorm2d(384)\n        self.conv4 = nn.Conv2d(\n            in_channels=384,\n            out_channels=384,\n            kernel_size=3,\n            stride=1,\n            padding=1,\n        )\n        self.batchnorm4 = nn.BatchNorm2d(384)\n        self.conv5 = nn.Conv2d(\n            in_channels=384,\n            out_channels=256,\n            kernel_size=3,\n            stride=1,\n            padding=1,\n        )\n        self.batchnorm5 = nn.BatchNorm2d(256)\n        self.dropout = nn.Dropout(p=0.5)\n        self.relu = nn.ReLU()\n        self.pool = nn.MaxPool2d(kernel_size=3, stride=2)\n        self.flatten = nn.Flatten()\n        self.linear1 = nn.Linear(6400, 4096)\n        self.linear2 = nn.Linear(4096, 4096)\n        self.linear3 = nn.Linear(4096, num_classes)\n    def forward(self, x):\n        x = self.relu(self.batchnorm1(self.conv1(x)))        \n        x = self.pool(x)\n        x = self.relu(self.batchnorm2(self.conv2(x)))      \n        x = self.pool(x)\n        x = self.relu(self.batchnorm3(self.conv3(x)))  \n        x = self.relu(self.batchnorm4(self.conv4(x)))  \n        x = self.relu(self.batchnorm5(self.conv5(x)))  \n        x = self.pool(x)\n        x = self.dropout(x)\n        # print('The shape of x is: ', x.shape)\n        x = self.flatten(x)\n        x = self.linear1(x)\n        x = self.dropout(x)\n        x = self.linear2(x)\n        x = self.linear3(x)\n        return x\n    \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.502399Z","iopub.execute_input":"2025-04-05T03:14:36.502618Z","iopub.status.idle":"2025-04-05T03:14:36.519531Z","shell.execute_reply.started":"2025-04-05T03:14:36.502592Z","shell.execute_reply":"2025-04-05T03:14:36.518777Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n\n\nclass block(nn.Module):\n    def __init__(\n        self, in_channels, intermediate_channels, identity_downsample=None, stride=1\n    ):\n        super().__init__()\n        self.expansion = 4\n        self.conv1 = nn.Conv2d(\n            in_channels,\n            intermediate_channels,\n            kernel_size=1,\n            stride=1,\n            padding=0,\n            bias=False,\n        )\n        self.bn1 = nn.BatchNorm2d(intermediate_channels)\n        self.conv2 = nn.Conv2d(\n            intermediate_channels,\n            intermediate_channels,\n            kernel_size=3,\n            stride=stride,\n            padding=1,\n            bias=False,\n        )\n        self.bn2 = nn.BatchNorm2d(intermediate_channels)\n        self.conv3 = nn.Conv2d(\n            intermediate_channels,\n            intermediate_channels * self.expansion,\n            kernel_size=1,\n            stride=1,\n            padding=0,\n            bias=False,\n        )\n        self.bn3 = nn.BatchNorm2d(intermediate_channels * self.expansion)\n        self.relu = nn.ReLU()\n        self.identity_downsample = identity_downsample\n        self.stride = stride\n\n    def forward(self, x):\n        identity = x.clone()\n\n        x = self.conv1(x)\n        x = self.bn1(x)\n        x = self.relu(x)\n        x = self.conv2(x)\n        x = self.bn2(x)\n        x = self.relu(x)\n        x = self.conv3(x)\n        x = self.bn3(x)\n\n        if self.identity_downsample is not None:\n            identity = self.identity_downsample(identity)\n\n        x += identity\n        x = self.relu(x)\n        return x\n\n\nclass ResNet(nn.Module):\n    def __init__(self, block, layers, image_channels, num_classes):\n        super(ResNet, self).__init__()\n        self.in_channels = 64\n        self.conv1 = nn.Conv2d(\n            image_channels, 64, kernel_size=7, stride=2, padding=3, bias=False\n        )\n        self.bn1 = nn.BatchNorm2d(64)\n        self.relu = nn.ReLU()\n        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)\n\n        # Essentially the entire ResNet architecture are in these 4 lines below\n        self.layer1 = self._make_layer(\n            block, layers[0], intermediate_channels=64, stride=1\n        )\n        self.layer2 = self._make_layer(\n            block, layers[1], intermediate_channels=128, stride=2\n        )\n        self.layer3 = self._make_layer(\n            block, layers[2], intermediate_channels=256, stride=2\n        )\n        self.layer4 = self._make_layer(\n            block, layers[3], intermediate_channels=512, stride=2\n        )\n\n        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))\n        self.fc = nn.Linear(512 * 4, num_classes)\n        \n\n    def forward(self, x):\n        x = self.conv1(x)\n        x = self.bn1(x)\n        x = self.relu(x)\n        x = self.maxpool(x)\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)\n\n        x = self.avgpool(x)\n        x = x.reshape(x.shape[0], -1)\n        x = self.fc(x)\n\n        return x\n\n    def _make_layer(self, block, num_residual_blocks, intermediate_channels, stride):\n        identity_downsample = None\n        layers = []\n\n        # Either if we half the input space for ex, 56x56 -> 28x28 (stride=2), or channels changes\n        # we need to adapt the Identity (skip connection) so it will be able to be added\n        # to the layer that's ahead\n        if stride != 1 or self.in_channels != intermediate_channels * 4:\n            identity_downsample = nn.Sequential(\n                nn.Conv2d(\n                    self.in_channels,\n                    intermediate_channels * 4,\n                    kernel_size=1,\n                    stride=stride,\n                    bias=False,\n                ),\n                nn.BatchNorm2d(intermediate_channels * 4),\n            )\n\n        layers.append(\n            block(self.in_channels, intermediate_channels, identity_downsample, stride)\n        )\n\n        # The expansion size is always 4 for ResNet 50,101,152\n        self.in_channels = intermediate_channels * 4\n\n        # For example for first resnet layer: 256 will be mapped to 64 as intermediate layer,\n        # then finally back to 256. Hence no identity downsample is needed, since stride = 1,\n        # and also same amount of channels.\n        for i in range(num_residual_blocks - 1):\n            layers.append(block(self.in_channels, intermediate_channels))\n\n        return nn.Sequential(*layers)\n\n\ndef ResNet50(img_channel=3, num_classes=1000):\n    return ResNet(block, [3, 4, 6, 3], img_channel, num_classes)\n\n\ndef ResNet101(img_channel=3, num_classes=1000):\n    return ResNet(block, [3, 4, 23, 3], img_channel, num_classes)\n\n\ndef ResNet152(img_channel=3, num_classes=1000):\n    return ResNet(block, [3, 8, 36, 3], img_channel, num_classes)\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.520921Z","iopub.execute_input":"2025-04-05T03:14:36.521161Z","iopub.status.idle":"2025-04-05T03:14:36.539631Z","shell.execute_reply.started":"2025-04-05T03:14:36.521143Z","shell.execute_reply":"2025-04-05T03:14:36.538843Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# model = AlexNet(num_classes=1).to(DEVICE)\nmodel = VGG16(num_classes=1).to(DEVICE)","metadata":{"id":"PW9QQdMly__W","executionInfo":{"status":"ok","timestamp":1739541584675,"user_tz":-420,"elapsed":3,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:36.540419Z","iopub.execute_input":"2025-04-05T03:14:36.540626Z","iopub.status.idle":"2025-04-05T03:14:38.029402Z","shell.execute_reply.started":"2025-04-05T03:14:36.540602Z","shell.execute_reply":"2025-04-05T03:14:38.028710Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"temp = torch.rand((1, 3, 224, 224)).to(DEVICE)\nx = model(temp)\nprint(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:38.030062Z","iopub.execute_input":"2025-04-05T03:14:38.030255Z","iopub.status.idle":"2025-04-05T03:14:39.251961Z","shell.execute_reply.started":"2025-04-05T03:14:38.030238Z","shell.execute_reply":"2025-04-05T03:14:39.251159Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define loss function and optimizer. No need for scheduler\nloss_fn = nn.BCEWithLogitsLoss(reduction='sum')  # Use BCEWithLogitsLoss\noptimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE)\n","metadata":{"id":"hK0J2D0FzOEF","executionInfo":{"status":"ok","timestamp":1739541584675,"user_tz":-420,"elapsed":3,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:39.252745Z","iopub.execute_input":"2025-04-05T03:14:39.253019Z","iopub.status.idle":"2025-04-05T03:14:39.257457Z","shell.execute_reply.started":"2025-04-05T03:14:39.252990Z","shell.execute_reply":"2025-04-05T03:14:39.256607Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if WANDB:\n    wandb.login(key='4a5d5d3b091931e391f5f23b25e6932dd6fdcb63')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:39.258212Z","iopub.execute_input":"2025-04-05T03:14:39.258481Z","iopub.status.idle":"2025-04-05T03:14:40.444200Z","shell.execute_reply.started":"2025-04-05T03:14:39.258450Z","shell.execute_reply":"2025-04-05T03:14:40.443223Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PROJECT = \"classification project 2\"\nRESUME = \"allow\"\n# Start WandB logging\nif WANDB:\n    wandb.init(\n        project=PROJECT,\n        resume=RESUME,\n        name=\"VGG16\",\n        config={\n            \"learning_rate\": LEARNING_RATE,\n            \"epochs\": NUM_EPOCHS,\n            \"batch_size\": BATCH_SIZE,\n    \n        },\n    )\n    wandb.watch(model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:40.445111Z","iopub.execute_input":"2025-04-05T03:14:40.445410Z","iopub.status.idle":"2025-04-05T03:14:40.459488Z","shell.execute_reply.started":"2025-04-05T03:14:40.445383Z","shell.execute_reply":"2025-04-05T03:14:40.458726Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nbest_val_loss = float('inf')\nbest_val_acc = 0\n\nfor epoch in range(1, NUM_EPOCHS + 1):\n    start_time = time.time()\n    model.train()  \n    train_loss = 0\n    train_accuracy = 0\n\n    for data, target in train_loader:\n        data, target = data.to(DEVICE), target.to(DEVICE).float()  \n        optimizer.zero_grad()\n        \n        output = model(data).squeeze(1)  # Ensure shape (batch_size,)\n        loss = loss_fn(output, target)  # Compute BCE loss\n        loss.backward()\n        optimizer.step()\n\n        # Convert logits to probabilities, then to class labels (0 or 1)\n        preds = (torch.sigmoid(output) > 0.5).float()  \n        train_accuracy += (preds == target).sum().item()\n        train_loss += loss.item()\n\n    train_loss /= len(train_loader.dataset)\n    train_accuracy /= len(train_loader.dataset)\n    time_taken = time.time() - start_time\n\n    # Validation Phase\n    model.eval()\n    val_loss = 0\n    val_accuracy = 0\n\n    with torch.no_grad():\n        for data, target in val_loader:\n            data, target = data.to(DEVICE), target.to(DEVICE).float()\n            output = model(data).squeeze(1)  \n            \n            loss = loss_fn(output, target)\n            val_loss += loss.item()\n\n            preds = (torch.sigmoid(output) > 0.5).float()\n            val_accuracy += (preds == target).sum().item()\n\n    val_loss /= len(val_loader.dataset)\n    val_accuracy /= len(val_loader.dataset)\n\n    if WANDB:\n        wandb.log({\n            \"train_loss\": train_loss,\n            \"train_accuracy\": train_accuracy,\n            \"val_loss\": val_loss,\n            \"val_accuracy\": val_accuracy,\n        })\n\n    # Log metrics\n    print(\n        f\"Epoch {epoch}: Train Loss: {train_loss:.4f} | \"\n        f\"Train Accuracy: {train_accuracy:.5f} | \"\n        f\"Val Loss: {val_loss:.4f} | \"\n        f\"Val Accuracy: {val_accuracy:.5f} | \"\n        f\"Time taken: {time_taken:.4f}\"\n    )\n\n    # Save best model\n    if val_accuracy > best_val_acc:\n        best_val_acc = val_accuracy\n        torch.save(model.state_dict(), CHECKPOINT_PATH)\n        print(\"=\" * 50)\n        print(\"New best checkpoint saved!\")\n        print(\"=\" * 50)\n","metadata":{"id":"8u_vu8AivcNc","executionInfo":{"status":"error","timestamp":1739541703529,"user_tz":-420,"elapsed":118856,"user":{"displayName":"Trọng tâm Nguyễn","userId":"00603692508187108432"}},"outputId":"803000ff-c3af-4f55-a8ab-e77aa848149a","trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:14:40.460244Z","iopub.execute_input":"2025-04-05T03:14:40.460438Z","iopub.status.idle":"2025-04-05T03:17:06.302224Z","shell.execute_reply.started":"2025-04-05T03:14:40.460422Z","shell.execute_reply":"2025-04-05T03:17:06.301152Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.load_state_dict(torch.load(CHECKPOINT_PATH))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:17:06.303344Z","iopub.execute_input":"2025-04-05T03:17:06.303703Z","iopub.status.idle":"2025-04-05T03:17:06.832886Z","shell.execute_reply.started":"2025-04-05T03:17:06.303669Z","shell.execute_reply":"2025-04-05T03:17:06.832154Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test_dataset = TestDataset(root_dir=\"/kaggle/working/test/test\", transform=test_transform)\n# test_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:17:06.833791Z","iopub.execute_input":"2025-04-05T03:17:06.834128Z","iopub.status.idle":"2025-04-05T03:17:06.837434Z","shell.execute_reply.started":"2025-04-05T03:17:06.834096Z","shell.execute_reply":"2025-04-05T03:17:06.836506Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# predictions = []\n\nmodel.eval()  # Set model to evaluation mode\n# with torch.no_grad():  # Disable gradients for inference\n#     for images, filenames in test_loader:\n#         images = images.to(DEVICE)  # Move images to GPU\n#         outputs = model(images)  # Forward pass\n\n#         # Apply sigmoid to get the probability of class 1 (dog)\n#         probs = torch.sigmoid(outputs).cpu().squeeze().numpy()\n\n#         # Store filename & probability of being a dog (class 1)\n#         for filename, prob in zip(filenames, probs):\n#             predictions.append((filename, float(prob)))  # Ensure prob is a Python float\ntest_loss = 0\ntest_accuracy = 0\n\n\nwith torch.no_grad():\n    for data, target in test_loader:\n        data, target = data.to(DEVICE), target.to(DEVICE).float()\n        output = model(data).squeeze(1)  \n        \n        loss = loss_fn(output, target)\n        test_loss += loss.item()\n        preds = (torch.sigmoid(output) > 0.5).float()\n        test_accuracy += (preds == target).sum().item()\ntest_loss /= len(test_loader.dataset)\ntest_accuracy /= len(test_loader.dataset)\n\nprint(\n    f\"Test Loss: {test_loss:.4f} | \"\n    f\"Test Accuracy: {test_accuracy:.5f} | \"\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:17:06.838315Z","iopub.execute_input":"2025-04-05T03:17:06.838608Z","iopub.status.idle":"2025-04-05T03:17:21.795329Z","shell.execute_reply.started":"2025-04-05T03:17:06.838569Z","shell.execute_reply":"2025-04-05T03:17:21.794330Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# df = pd.DataFrame(predictions, columns=[\"id\", \"label\"])\n# df[\"id\"] = df[\"id\"].str.replace(\".jpg\", \"\", regex=False)  # Remove \".jpg\" extension if needed\n# df.to_csv(\"submission.csv\", index=False)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:17:21.796358Z","iopub.execute_input":"2025-04-05T03:17:21.796699Z","iopub.status.idle":"2025-04-05T03:17:21.800406Z","shell.execute_reply.started":"2025-04-05T03:17:21.796667Z","shell.execute_reply":"2025-04-05T03:17:21.799485Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.cuda.empty_cache()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T03:17:21.801364Z","iopub.execute_input":"2025-04-05T03:17:21.801675Z","iopub.status.idle":"2025-04-05T03:17:21.894961Z","shell.execute_reply.started":"2025-04-05T03:17:21.801645Z","shell.execute_reply":"2025-04-05T03:17:21.894251Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}