{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Unzipping Data"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"!mkdir -p /kaggle/temp/\n!unzip ../input/dogs-vs-cats/test1.zip -d /kaggle/temp/\n!unzip ../input/dogs-vs-cats/train.zip -d /kaggle/temp/","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data_path = \"/kaggle/temp/train/\"\ntest_data_path = \"/kaggle/temp/test1/\"\nsample_submission_path = \"/kaggle/input/dogs-vs-cats/sampleSubmission.csv\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Loading Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport cv2\nimport pytorch_lightning as pl\nfrom torch.utils.data import DataLoader, Dataset, random_split\nimport torchvision.transforms as T\nfrom typing import Dict, Callable, Optional, Any, Tuple\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport multiprocessing\nimport pandas as pd\nimport numpy as np","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sample_submission = pd.read_csv(sample_submission_path)\nsample_submission.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Creating Dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"class ResizeImage(object):\n    def __init__(self, image:Image, ratio:float, pad:Tuple[float, float]):\n        self.image = image\n        self.ratio = ratio\n        self.pad = pad","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_image(path:str, new_shape: Tuple[int, int]) -> Tuple[Any, ResizeImage]:\n    # new_shape tuple [Height, Width]\n    img = Image.open(path)\n    \n    # Pillow give us [Width, Height]\n    w0, h0 = img.size \n    \n    # Scale ratio (new / old) -> min(h_new/h_old, w_new/w_old)\n    # This secure to resize the large dimension first\n    r = min(new_shape[0]/h0, new_shape[1]/w0)\n    \n    # new un_pad dimensions keeping aspec ratio\n    new_unpad = int(round(h0 * r)), int(round(w0 * r))\n    \n    # Compute padding\n    dw, dh = new_shape[1] - new_unpad[1], new_shape[0] - new_unpad[0]\n    dw /= 2; dh /= 2;\n    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))\n    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))\n    \n    # First Stage Preprocessing Transforms\n    inteli_resize = T.Compose([T.Resize(new_unpad), T.Pad((left, top, right, bottom), fill=(0,0,0))])\n    \n    return (img, ResizeImage(inteli_resize(img), r, (dw, dh)))           ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class CatsVsDogs(Dataset):\n    def __init__(self, path: str, train: bool,\n                transforms: Optional[Callable] = None,\n                new_shape: Optional[Tuple[int, int]] = (224, 224)) -> None:\n        \n        self.img_paths = os.listdir(path)\n        self.name_classes = {'cat': 0,\n                                'dog': 1}\n        self.new_shape = new_shape\n        self.transforms = transforms\n        \n        if train:\n            self.classes = [self.name_classes[img_path.split(\".\")[0]] for img_path in self.img_paths]\n        else:\n            # In this case classes will contains images ids\n            self.classes = [int(img_path.split(\".\")[0]) for img_path in self.img_paths]\n        \n        self.img_paths = [os.path.join(path, img_path) for img_path in self.img_paths]\n            \n    \n    def __getitem__(self, index: int) -> Tuple[torch.Tensor, torch.Tensor]:\n        _, resize_image = load_image(self.img_paths[index], self.new_shape)\n        if self.transforms is not None:\n            tensor_img = self.transforms(resize_image.image)\n        else:\n            transforms = T.Compose([T.ToTensor(), T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])\n            tensor_img = transforms(resize_image.image)\n        return tensor_img, torch.tensor(self.classes[index], dtype=torch.float32)\n        \n    def __len__(self) -> int:\n        return len(self.img_paths)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class CatsVsDogsDataModule(pl.LightningDataModule):\n    def __init__(self, train_dir: str, test_dir: str):\n        super().__init__()\n        self.train_dir = train_dir\n        self.test_dir = test_dir\n        self.transform = T.Compose([T.ToTensor(), T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])\n        \n        # self.dims is returned when you call dm.size()\n        # Setting default dims here because we know them.\n        # Could optionally be assigned dynamically in dm.setup()\n        self.dims = (3, 224, 224)\n\n    def prepare_data(self):\n        # download\n        pass\n\n    def setup(self, stage=None):\n        # Assign train/val datasets for use in dataloaders\n        if stage == 'fit' or stage is None:\n            dataset_full = CatsVsDogs(self.train_dir, train = True, transforms = self.transform, new_shape = self.dims[1:])\n            self.train_dataset, self.val_dataset = random_split(dataset_full, [int(len(dataset_full)*0.8), len(dataset_full) - int(len(dataset_full)*0.8)])\n\n        # Assign test dataset for use in dataloader(s)\n        if stage == 'test' or stage is None:\n            self.test_dataset = CatsVsDogs(self.test_dir, train=False,\n                                           transforms=self.transform, new_shape=self.dims[1:])\n\n    def train_dataloader(self):\n        return DataLoader(self.train_dataset, batch_size=16, shuffle=True,\n                         num_workers = multiprocessing.cpu_count())\n\n    def val_dataloader(self):\n        return DataLoader(self.val_dataset, batch_size=16, shuffle=False,\n                         num_workers = multiprocessing.cpu_count())\n\n    def test_dataloader(self):\n        return DataLoader(self.test_dataset, batch_size=16, shuffle=False,\n                         num_workers = multiprocessing.cpu_count())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Define Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nfrom torchvision import models\nimport os","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class VGG16(nn.Module):\n    def __init__(self):\n        super(VGG16, self).__init__()\n        self.vgg16 = models.vgg16(pretrained=True)\n        self.vgg16.classifier[-1] = nn.Linear(in_features = 4096, out_features = 1)\n        \n    def forward(self, x):\n        x = self.vgg16(x)\n        return x.view(-1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from pytorch_lightning.callbacks import LearningRateMonitor\nfrom pytorch_lightning.callbacks.early_stopping import EarlyStopping\n\nclass CatVsDogLitModel(pl.LightningModule):\n    def __init__(self, model: nn.Module, lr:int):\n        super(CatVsDogLitModel, self).__init__()\n        self.model = model\n        self.lr = lr\n        \n    def forward(self, x):\n        y = self.model(x)\n        return y\n    \n    def training_step(self, batch, batch_idx):\n        x, y = batch\n        bs, _, _, _ = x.size()\n        y_hat = self(x)\n        loss = F.binary_cross_entropy_with_logits(y_hat, y)\n        self.log('train_loss', loss, prog_bar=True)\n        return loss\n    \n    def validation_step(self, batch, batch_idx):\n        x, y = batch\n        bs, _, _, _ = x.size()\n        y_hat = self(x)\n        loss = F.binary_cross_entropy_with_logits(y_hat, y)\n        self.log('val_loss', loss, prog_bar=True)\n    \n    \n    def configure_optimizers(self):\n        optimizer = optim.Adam(self.parameters(), lr=self.lr)\n        scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', verbose=True)\n        return {\n           'optimizer': optimizer,\n           'lr_scheduler': scheduler, # Changed scheduler to lr_scheduler\n           'monitor': 'val_loss'\n       }","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data = CatsVsDogsDataModule(train_dir=train_data_path, test_dir=test_data_path)\n\nae_model = CatVsDogLitModel(VGG16(), 1e-4)\nlr_monitor = LearningRateMonitor(logging_interval='step')\n\ntrainer = pl.Trainer(gpus=1, max_epochs=25, amp_level='O2', precision=16, callbacks=[lr_monitor,EarlyStopping(monitor='val_loss')])\n\nlr_finder = trainer.tuner.lr_find(ae_model, data)\nlr_finder.results\n\nfig = lr_finder.plot(suggest=True)\nnew_lr = lr_finder.suggestion()\nae_model.lr = new_lr","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"trainer.fit(ae_model, data)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Get Metrics results with validation dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tqdm.notebook import tqdm\n\npbar = tqdm(total=len(data.val_dataset),\n           desc=\"Metric\")\n\nae_model.eval()\nae_model.cuda()\n \nreal_ = []\npred_ = []\nfor x, y in data.val_dataset:\n    with torch.no_grad():\n        y_hat = ae_model(x.unsqueeze(0).cuda()).sigmoid()\n        pred = (y_hat > 0.5).to(dtype=torch.float32)\n    \n    real_.append(y.item())\n    pred_.append(pred.item())\n    \n    pbar.update(1)\n    \nreal_ = np.array(real_)\npred_ = np.array(pred_)\n\naccuracy = sum(real_ == pred_)/len(real_) * 100\naccuracy","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import random\nindexes = np.where(real_ != pred_)[0]\nchoices = random.choices(range(len(indexes)), k=10)\n\nmean = np.array([0.485, 0.456, 0.406])\nstd = np.array([0.229, 0.224, 0.225])\nunormalize = T.Normalize(mean=-mean/std,\n            std=1.0/std)\n\nprint(choices)\ndata.setup(stage=\"test\")\nplt.figure(figsize=(45, 45), tight_layout=True)\nfor j, i in enumerate(choices):\n    plt.subplot(1, len(choices), j + 1)\n    x, y = data.val_dataset[indexes[i]]\n    plt.title(f\"class {list(data.test_dataset.name_classes.keys())[int(y.item())]},\" + \\\n             f\" pred {list(data.test_dataset.name_classes.keys())[int(pred_[indexes[i]])]}\")\n    plt.imshow(np.transpose(unormalize(x), (1, 2, 0)))\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Get results\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"pbar = tqdm(total=len(data.test_dataset),\n           desc=\"Test Set Predict\")\n\nae_model.eval()\nae_model.cuda()\n \npred_ = []\nidx_ = []\nfor x, y in data.test_dataset:\n    with torch.no_grad():\n        y_hat = ae_model(x.unsqueeze(0).cuda()).sigmoid()\n        pred = (y_hat > 0.5).to(dtype=torch.float32)\n    \n    idx_.append(y.item())\n    pred_.append(pred.item())\n    \n    pbar.update(1)\n    \npred_ = np.array(pred_)\nidx_ = np.array(idx_)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Save model"},{"metadata":{"trusted":true},"cell_type":"code","source":"ae_model.eval()\nae_model.cpu()\nae_model.to_torchscript(\"/kaggle/working/model.torch.pt\", example_inputs=torch.randn(1, 3, 224, 224))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Save submissions"},{"metadata":{"trusted":true},"cell_type":"code","source":"pred_ = pred_.astype(np.int64); idx_ = idx_.astype(np.int64)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = sample_submission.copy()\nsubmission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.set_index(\"id\", inplace=True, drop=True)\nsubmission.loc[idx_, \"label\"] = pred_","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.reset_index(inplace=True)\nsubmission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.to_csv(\"/kaggle/working/submission.csv\", index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}