{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"### Unzipping Dataset\nimport zipfile\n\nwith zipfile.ZipFile(\"../input/dogs-vs-cats/train.zip\",\"r\") as z:\n    z.extractall(\".\")\n    \nwith zipfile.ZipFile(\"../input/dogs-vs-cats/test1.zip\",\"r\") as z:\n    z.extractall(\".\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import os\nimport cv2\nimport time\nimport random\nimport numpy as np\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nfrom torch.utils.data import Dataset, DataLoader\n\nimport torchvision.transforms as T\nfrom torchvision.utils import make_grid\nfrom torchvision.models import vgg16\n\nfrom sklearn.model_selection import train_test_split\n\nfrom PIL import Image\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nDIR_TRAIN = \"/kaggle/working/train/\"\nDIR_TEST = \"/kaggle/working/test1\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Checking Data Format\nimgs = os.listdir(DIR_TRAIN) \ntest_imgs = os.listdir(DIR_TEST)\n\nprint(imgs[:5])\nprint(test_imgs[:5])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Class Distribution\ndogs_list = [img for img in imgs if img.split(\".\")[0] == \"dog\"]\ncats_list = [img for img in imgs if img.split(\".\")[0] == \"cat\"]\n\nprint(\"No of Dogs Images: \",len(dogs_list))\nprint(\"No of Cats Images: \",len(cats_list))\n\nclass_to_int = {\"dog\" : 0, \"cat\" : 1}\nint_to_class = {0 : \"dog\", 1 : \"cat\"}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Transforms for image - ToTensor and other augmentations\ndef get_train_transform():\n    return T.Compose([\n        T.RandomHorizontalFlip(p=0.5),\n        T.RandomRotation(15),\n        T.RandomCrop(204),\n        T.ToTensor(),\n        T.Normalize((0, 0, 0),(1, 1, 1))\n    ])\n    \ndef get_val_transform():\n    return T.Compose([\n        T.ToTensor(),\n        T.Normalize((0, 0, 0),(1, 1, 1))\n    ])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Dataset Class - for retriving images and labels\nclass CatDogDataset(Dataset):\n    \n    def __init__(self, imgs, class_to_int, mode = \"train\", transforms = None):\n        \n        super().__init__()\n        self.imgs = imgs\n        self.class_to_int = class_to_int\n        self.mode = mode\n        self.transforms = transforms\n        \n    def __getitem__(self, idx):\n        \n        image_name = self.imgs[idx]\n        \n        ### Reading, converting and normalizing image\n        #img = cv2.imread(DIR_TRAIN + image_name, cv2.IMREAD_COLOR)\n        #img = cv2.resize(img, (224,224))\n        #img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32)\n        #img /= 255.\n        img = Image.open(DIR_TRAIN + image_name)\n        img = img.resize((224, 224))\n        \n        if self.mode == \"train\" or self.mode == \"val\":\n        \n            ### Preparing class label\n            label = self.class_to_int[image_name.split(\".\")[0]]\n            label = torch.tensor(label, dtype = torch.float32)\n\n            ### Apply Transforms on image\n            img = self.transforms(img)\n\n            return img, label\n        \n        elif self.mode == \"test\":\n            \n            ### Apply Transforms on image\n            img = self.transforms(img)\n\n            return img\n            \n        \n    def __len__(self):\n        return len(self.imgs)\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Splitting data into train and val sets\ntrain_imgs, val_imgs = train_test_split(imgs, test_size = 0.25)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Dataloaders\ntrain_dataset = CatDogDataset(train_imgs, class_to_int, mode = \"train\", transforms = get_train_transform())\nval_dataset = CatDogDataset(val_imgs, class_to_int, mode = \"val\", transforms = get_val_transform())\ntest_dataset = CatDogDataset(test_imgs, class_to_int, mode = \"test\", transforms = get_val_transform())\n\ntrain_data_loader = DataLoader(\n    dataset = train_dataset,\n    num_workers = 4,\n    batch_size = 16,\n    shuffle = True\n)\n\nval_data_loader = DataLoader(\n    dataset = val_dataset,\n    num_workers = 4,\n    batch_size = 16,\n    shuffle = True\n)\n\ntest_data_loader = DataLoader(\n    dataset = test_dataset,\n    num_workers = 4,\n    batch_size = 16,\n    shuffle = True\n)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Visualize Random Images from Train set\nfor images, labels in train_data_loader:\n    \n    fig, ax = plt.subplots(figsize = (10, 10))\n    ax.set_xticks([])\n    ax.set_yticks([])\n    ax.imshow(make_grid(images, 4).permute(1,2,0))\n    break\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### GPU\ndevice = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Function to calculate accuracy\ndef accuracy(preds, trues):\n    \n    ### Converting preds to 0 or 1\n    preds = [1 if preds[i] >= 0.5 else 0 for i in range(len(preds))]\n    \n    ### Calculating accuracy by comparing predictions with true labels\n    acc = [1 if preds[i] == trues[i] else 0 for i in range(len(preds))]\n    \n    ### Summing over all correct predictions\n    acc = np.sum(acc) / len(preds)\n    \n    return (acc * 100)\n    \n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Function - One Epoch Train\ndef train_one_epoch(train_data_loader):\n    \n    ### Local Parameters\n    epoch_loss = []\n    epoch_acc = []\n    start_time = time.time()\n    \n    ###Iterating over data loader\n    for images, labels in train_data_loader:\n        \n        #Loading images and labels to device\n        images = images.to(device)\n        labels = labels.to(device)\n        labels = labels.reshape((labels.shape[0], 1)) # [N, 1] - to match with preds shape\n        \n        #Reseting Gradients\n        optimizer.zero_grad()\n        \n        #Forward\n        preds = model(images)\n        \n        #Calculating Loss\n        _loss = criterion(preds, labels)\n        loss = _loss.item()\n        epoch_loss.append(loss)\n        \n        #Calculating Accuracy\n        acc = accuracy(preds, labels)\n        epoch_acc.append(acc)\n        \n        #Backward\n        _loss.backward()\n        optimizer.step()\n    \n    ###Overall Epoch Results\n    end_time = time.time()\n    total_time = end_time - start_time\n    \n    ###Acc and Loss\n    epoch_loss = np.mean(epoch_loss)\n    epoch_acc = np.mean(epoch_acc)\n    \n    ###Storing results to logs\n    train_logs[\"loss\"].append(epoch_loss)\n    train_logs[\"accuracy\"].append(epoch_acc)\n    train_logs[\"time\"].append(total_time)\n        \n    return epoch_loss, epoch_acc, total_time\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Function - One Epoch Valid\ndef val_one_epoch(val_data_loader, best_val_acc):\n    \n    ### Local Parameters\n    epoch_loss = []\n    epoch_acc = []\n    start_time = time.time()\n    \n    ###Iterating over data loader\n    for images, labels in val_data_loader:\n        \n        #Loading images and labels to device\n        images = images.to(device)\n        labels = labels.to(device)\n        labels = labels.reshape((labels.shape[0], 1)) # [N, 1] - to match with preds shape\n        \n        #Forward\n        preds = model(images)\n        \n        #Calculating Loss\n        _loss = criterion(preds, labels)\n        loss = _loss.item()\n        epoch_loss.append(loss)\n        \n        #Calculating Accuracy\n        acc = accuracy(preds, labels)\n        epoch_acc.append(acc)\n    \n    ###Overall Epoch Results\n    end_time = time.time()\n    total_time = end_time - start_time\n    \n    ###Acc and Loss\n    epoch_loss = np.mean(epoch_loss)\n    epoch_acc = np.mean(epoch_acc)\n    \n    ###Storing results to logs\n    val_logs[\"loss\"].append(epoch_loss)\n    val_logs[\"accuracy\"].append(epoch_acc)\n    val_logs[\"time\"].append(total_time)\n    \n    ###Saving best model\n    if epoch_acc > best_val_acc:\n        best_val_acc = epoch_acc\n        torch.save(model.state_dict(),\"vgg16_best.pth\")\n        \n    return epoch_loss, epoch_acc, total_time, best_val_acc\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### VGG16 Pretrained Model\nmodel = vgg16(pretrained = True)\n\n# Modifying Head - classifier\n\nmodel.classifier = nn.Sequential(\n    nn.Linear(25088, 2048, bias = True),\n    nn.ReLU(inplace = True),\n    nn.Dropout(0.5),\n    nn.Linear(2048, 1024, bias = True),\n    nn.ReLU(inplace = True),\n    nn.Dropout(0.5),\n    nn.Linear(1024, 1, bias = True),\n    nn.Sigmoid()\n)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Defining model parameters\n\n# Optimizer\noptimizer = torch.optim.Adam(model.parameters(), lr = 0.0001)\n\n# Learning Rate Scheduler\nlr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size = 5, gamma = 0.5)\n\n#Loss Function\ncriterion = nn.BCELoss()\n\n# Logs - Helpful for plotting after training finishes\ntrain_logs = {\"loss\" : [], \"accuracy\" : [], \"time\" : []}\nval_logs = {\"loss\" : [], \"accuracy\" : [], \"time\" : []}\n\n# Loading model to device\nmodel.to(device)\n\n# No of epochs \nepochs = 15","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-output":true,"collapsed":true},"cell_type":"code","source":"### Training and Validation xD\nbest_val_acc = 0\nfor epoch in range(epochs):\n    \n    ###Training\n    loss, acc, _time = train_one_epoch(train_data_loader)\n    \n    #Print Epoch Details\n    print(\"\\nTraining\")\n    print(\"Epoch {}\".format(epoch+1))\n    print(\"Loss : {}\".format(round(loss, 4)))\n    print(\"Acc : {}\".format(round(acc, 4)))\n    print(\"Time : {}\".format(round(_time, 4)))\n    \n    ###Validation\n    loss, acc, _time, best_val_acc = val_one_epoch(val_data_loader, best_val_acc)\n    \n    #Print Epoch Details\n    print(\"\\nValidating\")\n    print(\"Epoch {}\".format(epoch+1))\n    print(\"Loss : {}\".format(round(loss, 4)))\n    print(\"Acc : {}\".format(round(acc, 4)))\n    print(\"Time : {}\".format(round(_time, 4)))\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"### Plotting Results\n\n#Loss\nplt.title(\"Loss\")\nplt.plot(np.arange(1, 16, 1), train_logs[\"loss\"], color = 'blue')\nplt.plot(np.arange(1, 16, 1), val_logs[\"loss\"], color = 'yellow')\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Loss\")\nplt.show()\n\n#Accuracy\nplt.title(\"Accuracy\")\nplt.plot(np.arange(1, 16, 1), train_logs[\"accuracy\"], color = 'blue')\nplt.plot(np.arange(1, 16, 1), val_logs[\"accuracy\"], color = 'yellow')\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Accuracy\")\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}