{"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":"markdown","source":"## Load libraries","metadata":{"execution":{"iopub.status.busy":"2024-06-08T11:40:44.204322Z","iopub.execute_input":"2024-06-08T11:40:44.204686Z","iopub.status.idle":"2024-06-08T11:41:13.718425Z","shell.execute_reply.started":"2024-06-08T11:40:44.204657Z","shell.execute_reply":"2024-06-08T11:41:13.717451Z"}}},{"cell_type":"code","source":"!pip install --upgrade lightning\n!pip install wandb","metadata":{"execution":{"iopub.status.busy":"2024-06-12T16:58:35.689557Z","iopub.execute_input":"2024-06-12T16:58:35.689824Z","iopub.status.idle":"2024-06-12T16:59:04.996176Z","shell.execute_reply.started":"2024-06-12T16:58:35.689798Z","shell.execute_reply":"2024-06-12T16:59:04.995036Z"},"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","metadata":{"execution":{"iopub.status.busy":"2024-06-12T16:59:08.523610Z","iopub.execute_input":"2024-06-12T16:59:08.523982Z","iopub.status.idle":"2024-06-12T16:59:16.649171Z","shell.execute_reply.started":"2024-06-12T16:59:08.523951Z","shell.execute_reply":"2024-06-12T16:59:16.648221Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Extract data from archives","metadata":{}},{"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-12T16:59:21.407690Z","iopub.execute_input":"2024-06-12T16:59:21.408562Z","iopub.status.idle":"2024-06-12T16:59:33.124751Z","shell.execute_reply.started":"2024-06-12T16:59:21.408529Z","shell.execute_reply":"2024-06-12T16:59:33.123237Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls","metadata":{"execution":{"iopub.status.busy":"2024-06-12T16:59:33.323229Z","iopub.execute_input":"2024-06-12T16:59:33.323569Z","iopub.status.idle":"2024-06-12T16:59:34.265929Z","shell.execute_reply.started":"2024-06-12T16:59:33.323542Z","shell.execute_reply":"2024-06-12T16:59:34.264776Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Define dataset","metadata":{}},{"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-12T16:59:37.571151Z","iopub.execute_input":"2024-06-12T16:59:37.571927Z","iopub.status.idle":"2024-06-12T16:59:37.581027Z","shell.execute_reply.started":"2024-06-12T16:59:37.571893Z","shell.execute_reply":"2024-06-12T16:59:37.580160Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Define model","metadata":{}},{"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-12T16:59:39.946884Z","iopub.execute_input":"2024-06-12T16:59:39.947495Z","iopub.status.idle":"2024-06-12T16:59:39.965067Z","shell.execute_reply.started":"2024-06-12T16:59:39.947464Z","shell.execute_reply":"2024-06-12T16:59:39.964207Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Create dataset and augmentations","metadata":{}},{"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=64, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=64, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2024-06-12T16:59:41.211855Z","iopub.execute_input":"2024-06-12T16:59:41.212649Z","iopub.status.idle":"2024-06-12T16:59:41.318488Z","shell.execute_reply.started":"2024-06-12T16:59:41.212619Z","shell.execute_reply":"2024-06-12T16:59:41.317583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Set checkpoints and trainer","metadata":{}},{"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.0001)\ntrainer = pl.Trainer(\n    max_epochs=3,\n    accelerator=\"auto\",\n    callbacks=[checkpoint_callback, early_stopping_callback, progress_bar],\n    logger=wandb_logger\n)","metadata":{"execution":{"iopub.status.busy":"2024-06-12T16:59:43.623062Z","iopub.execute_input":"2024-06-12T16:59:43.623878Z","iopub.status.idle":"2024-06-12T16:59:45.827167Z","shell.execute_reply.started":"2024-06-12T16:59:43.623845Z","shell.execute_reply":"2024-06-12T16:59:45.826353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train model","metadata":{}},{"cell_type":"code","source":"trainer.fit(model, train_loader, val_loader)","metadata":{"execution":{"iopub.status.busy":"2024-06-12T16:59:52.466436Z","iopub.execute_input":"2024-06-12T16:59:52.466806Z","iopub.status.idle":"2024-06-12T17:05:02.037436Z","shell.execute_reply.started":"2024-06-12T16:59:52.466776Z","shell.execute_reply":"2024-06-12T17:05:02.036382Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Stop wandb logging","metadata":{}},{"cell_type":"code","source":"wandb.finish()","metadata":{"execution":{"iopub.status.busy":"2024-06-12T17:05:08.098732Z","iopub.execute_input":"2024-06-12T17:05:08.099667Z","iopub.status.idle":"2024-06-12T17:05:11.104765Z","shell.execute_reply.started":"2024-06-12T17:05:08.099632Z","shell.execute_reply":"2024-06-12T17:05:11.104043Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load and test best trained model","metadata":{}},{"cell_type":"code","source":"best_model = SimpleCNN.load_from_checkpoint(\"/kaggle/working/models/best-checkpoint.ckpt\", lr=0.00001, num_classes=3)","metadata":{"execution":{"iopub.status.busy":"2024-06-12T17:05:29.948626Z","iopub.execute_input":"2024-06-12T17:05:29.949315Z","iopub.status.idle":"2024-06-12T17:05:33.096594Z","shell.execute_reply.started":"2024-06-12T17:05:29.949282Z","shell.execute_reply":"2024-06-12T17:05:33.095787Z"},"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-12T17:05:33.098318Z","iopub.execute_input":"2024-06-12T17:05:33.098682Z","iopub.status.idle":"2024-06-12T17:05:53.584373Z","shell.execute_reply.started":"2024-06-12T17:05:33.098650Z","shell.execute_reply":"2024-06-12T17:05:53.583467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Delate unarchived data","metadata":{}},{"cell_type":"code","source":"!rm -rf /kaggle/working/train","metadata":{"execution":{"iopub.status.busy":"2024-06-12T17:06:45.566123Z","iopub.execute_input":"2024-06-12T17:06:45.566518Z","iopub.status.idle":"2024-06-12T17:06:47.276364Z","shell.execute_reply.started":"2024-06-12T17:06:45.566491Z","shell.execute_reply":"2024-06-12T17:06:47.275207Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}