{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.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":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":30733,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install --upgrade lightning\n!pip install wandb","metadata":{"execution":{"iopub.status.busy":"2024-06-24T15:29:31.953073Z","iopub.execute_input":"2024-06-24T15:29:31.953847Z","iopub.status.idle":"2024-06-24T15:30:01.191173Z","shell.execute_reply.started":"2024-06-24T15:29:31.953815Z","shell.execute_reply":"2024-06-24T15:30:01.190177Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport cv2\nimport torch\nimport lightning as pl\nfrom torchmetrics.classification import Accuracy, F1Score\nfrom torch.utils.data import DataLoader, Dataset\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nfrom lightning.pytorch.callbacks import ModelCheckpoint, EarlyStopping, TQDMProgressBar\nfrom lightning.pytorch.loggers import WandbLogger\nimport wandb\nfrom transformers import AutoFeatureExtractor, AutoModelForImageClassification","metadata":{"execution":{"iopub.status.busy":"2024-06-24T15:30:01.193585Z","iopub.execute_input":"2024-06-24T15:30:01.193960Z","iopub.status.idle":"2024-06-24T15:30:09.930305Z","shell.execute_reply.started":"2024-06-24T15:30:01.193923Z","shell.execute_reply":"2024-06-24T15:30:09.929549Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!unzip /kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip -d /kaggle/working/","metadata":{"execution":{"iopub.status.busy":"2024-06-24T15:30:09.935699Z","iopub.execute_input":"2024-06-24T15:30:09.936428Z","iopub.status.idle":"2024-06-24T15:30:21.455271Z","shell.execute_reply.started":"2024-06-24T15:30:09.936376Z","shell.execute_reply":"2024-06-24T15:30:21.454193Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomImageDataset(Dataset):\n    def __init__(self, image_dir, transform=None):\n        self.image_dir = image_dir\n        self.transform = transform\n        self.classes = os.listdir(image_dir)\n        self.image_paths = []\n        self.labels = []\n        \n        for img_name in os.listdir(image_dir):\n            self.image_paths.append(os.path.join(image_dir, img_name))\n            if img_name.startswith(\"cat\"):\n                self.labels.append(0)\n            else:\n                self.labels.append(1)\n        \n    def __len__(self):\n        return len(self.image_paths)\n    \n    def __getitem__(self, idx):\n        img_path = self.image_paths[idx]\n        image = cv2.imread(img_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        label = self.labels[idx]\n        \n        if self.transform:\n            augmented = self.transform(image=image)\n            image = augmented['image']\n        \n        return image, label","metadata":{"execution":{"iopub.status.busy":"2024-06-24T16:43:36.977194Z","iopub.execute_input":"2024-06-24T16:43:36.977719Z","iopub.status.idle":"2024-06-24T16:43:36.988419Z","shell.execute_reply.started":"2024-06-24T16:43:36.977683Z","shell.execute_reply":"2024-06-24T16:43:36.987337Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SimpleCNN(pl.LightningModule):\n    def __init__(self, lr):\n        super(SimpleCNN, self).__init__()\n        self.model = torch.nn.Sequential(\n            torch.nn.Conv2d(3, 32, kernel_size=3, padding=\"same\"),\n            torch.nn.ReLU(),\n            torch.torch.nn.MaxPool2d(kernel_size=2),\n            torch.nn.Dropout(p=0.25),\n            torch.nn.Conv2d(32, 64, kernel_size=3, padding=\"same\"),\n            torch.nn.ReLU(),\n            torch.nn.MaxPool2d(kernel_size=2),\n            torch.nn.Dropout(p=0.25),\n            torch.nn.Flatten(),\n            torch.nn.Linear(64 * 64 * 64, 512),\n            torch.nn.ReLU(),\n            torch.nn.Linear(512, 64),\n            torch.nn.ReLU(),\n            torch.nn.Linear(64, 1),\n            torch.nn.Sigmoid(),\n        )\n        self.loss_fn = torch.nn.BCELoss()\n        self.lr = lr\n        \n        self.train_acc = Accuracy(task=\"binary\")\n        self.val_acc = Accuracy(task=\"binary\")\n        self.train_f1 = F1Score(task=\"binary\", average='macro')\n        self.val_f1 = F1Score(task=\"binary\", average='macro')\n    \n    def forward(self, x):\n        return self.model(x)\n    \n    def training_step(self, batch, batch_idx):\n        x, y = batch\n        y_hat = self(x).squeeze()\n        y = y.type(torch.float)\n        loss = self.loss_fn(y_hat, y)\n        y_hat = ((y_hat > 0.5) == y).type(torch.float)\n        \n        self.log('train_loss', loss)\n        self.train_acc.update(y_hat, y)\n        self.train_f1.update(y_hat, y)\n        self.log('train_acc', self.train_acc)\n        self.log('train_f1', self.train_f1)\n        \n        return loss\n    \n    def validation_step(self, batch, batch_idx):\n        x, y = batch\n        y_hat = self(x).squeeze()\n        y = y.type(torch.float)\n        val_loss = self.loss_fn(y_hat, y)\n        y_hat = ((y_hat > 0.5) == y).type(torch.float)\n        \n        self.val_acc.update(y_hat, y)\n        self.val_f1.update(y_hat, y)\n        self.log('val_loss', val_loss, prog_bar=True)\n        self.log('val_acc', self.val_acc)\n        self.log('val_f1', self.val_f1)\n        \n        return val_loss\n    \n    def configure_optimizers(self):\n        optimizer = torch.optim.Adam(self.parameters(), lr=self.lr, weight_decay=0.0001)\n        return optimizer\n    \n    def on_train_epoch_end(self):\n        self.log(\"train_acc_epoch\", self.train_acc.compute(), on_epoch=True)\n        self.log(\"train_f1_epoch\", self.train_f1.compute(), on_epoch=True)\n        self.train_acc.reset()\n        self.train_f1.reset()\n    \n    def on_validation_epoch_end(self):\n        self.log(\"val_acc_epoch\", self.val_acc.compute(), on_epoch=True)\n        self.log(\"val_f1_epoch\", self.val_f1.compute(), on_epoch=True)\n        self.val_acc.reset()\n        self.val_f1.reset()","metadata":{"execution":{"iopub.status.busy":"2024-06-24T16:46:02.827172Z","iopub.execute_input":"2024-06-24T16:46:02.827705Z","iopub.status.idle":"2024-06-24T16:46:02.848005Z","shell.execute_reply.started":"2024-06-24T16:46:02.827669Z","shell.execute_reply":"2024-06-24T16:46:02.847088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_dir = '/kaggle/working/train'\ntransform = A.Compose([\n    A.Resize(256, 256),\n    A.HorizontalFlip(p=0.3),\n    A.RandomCrop(height=128, width=128, p=0.3),\n    A.Resize(256, 256),\n    A.Normalize(),\n    ToTensorV2(),\n])\n\ndataset = CustomImageDataset(image_dir, transform=transform)\ntrain_size = int(0.9 * len(dataset))\nval_size = len(dataset) - train_size\ntrain_dataset, val_dataset = torch.utils.data.random_split(dataset, [train_size, val_size], generator=torch.Generator().manual_seed(42))\ntrain_loader = DataLoader(train_dataset, batch_size=256, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=256, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2024-06-24T16:46:40.473891Z","iopub.execute_input":"2024-06-24T16:46:40.474263Z","iopub.status.idle":"2024-06-24T16:46:40.573691Z","shell.execute_reply.started":"2024-06-24T16:46:40.474234Z","shell.execute_reply":"2024-06-24T16:46:40.572893Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"checkpoint_callback = ModelCheckpoint(\n    monitor='val_loss',\n    dirpath='/kaggle/working/models/',\n    filename='best-checkpoint',\n    save_top_k=1,\n    mode='min'\n)\nearly_stopping_callback = EarlyStopping(\n    monitor='val_loss',\n    patience=7,\n    verbose=True,\n    mode='min'\n)\nprogress_bar = TQDMProgressBar(refresh_rate=10)\n\nwandb_logger = WandbLogger(project='cat_vs_dogs')\n\nmodel = SimpleCNN(lr=0.0002)\ntrainer = pl.Trainer(\n    max_epochs=30,\n    accelerator=\"auto\",\n    callbacks=[checkpoint_callback, early_stopping_callback, progress_bar],\n    logger=wandb_logger\n)","metadata":{"execution":{"iopub.status.busy":"2024-06-24T16:46:40.939807Z","iopub.execute_input":"2024-06-24T16:46:40.940212Z","iopub.status.idle":"2024-06-24T16:46:42.322374Z","shell.execute_reply.started":"2024-06-24T16:46:40.940183Z","shell.execute_reply":"2024-06-24T16:46:42.321477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainer.fit(model, train_loader, val_loader)","metadata":{"execution":{"iopub.status.busy":"2024-06-24T16:46:42.324281Z","iopub.execute_input":"2024-06-24T16:46:42.324684Z","iopub.status.idle":"2024-06-24T17:17:32.703449Z","shell.execute_reply.started":"2024-06-24T16:46:42.324649Z","shell.execute_reply":"2024-06-24T17:17:32.702388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"wandb.finish()","metadata":{"execution":{"iopub.status.busy":"2024-06-24T17:21:09.975610Z","iopub.execute_input":"2024-06-24T17:21:09.976009Z","iopub.status.idle":"2024-06-24T17:21:09.980821Z","shell.execute_reply.started":"2024-06-24T17:21:09.975977Z","shell.execute_reply":"2024-06-24T17:21:09.979787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nbest_model = SimpleCNN.load_from_checkpoint(\"/kaggle/working/models/best-checkpoint-v1.ckpt\", lr=0.0002, num_classes=3)","metadata":{"execution":{"iopub.status.busy":"2024-06-24T17:21:55.494439Z","iopub.execute_input":"2024-06-24T17:21:55.495099Z","iopub.status.idle":"2024-06-24T17:21:58.391643Z","shell.execute_reply.started":"2024-06-24T17:21:55.495063Z","shell.execute_reply":"2024-06-24T17:21:58.390639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainer = pl.Trainer()\ntrainer.validate(best_model, val_loader)","metadata":{"execution":{"iopub.status.busy":"2024-06-24T17:21:59.581002Z","iopub.execute_input":"2024-06-24T17:21:59.581672Z","iopub.status.idle":"2024-06-24T17:22:08.626942Z","shell.execute_reply.started":"2024-06-24T17:21:59.581636Z","shell.execute_reply":"2024-06-24T17:22:08.626071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!rm -rf /kaggle/working/train","metadata":{"execution":{"iopub.status.busy":"2024-06-24T17:22:16.648662Z","iopub.execute_input":"2024-06-24T17:22:16.649037Z","iopub.status.idle":"2024-06-24T17:22:18.589916Z","shell.execute_reply.started":"2024-06-24T17:22:16.649008Z","shell.execute_reply":"2024-06-24T17:22:18.588687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}