{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nprint(os.listdir(\"../input\"))\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn import preprocessing\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torchvision import datasets, transforms, models\nimport time\nimport math","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train_dir, Test_dir\nbase_dir = '../input/dogs-vs-cats-redux-kernels-edition'\ntrain_dir = '../data/train'\ntest_dir = '../data/test'","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import zipfile\n# Extract All Data From Zip to \"../data\" Directory\nwith zipfile.ZipFile(os.path.join(base_dir, 'train.zip')) as train_zip:\n    train_zip.extractall('../data')\n    \nwith zipfile.ZipFile(os.path.join(base_dir, 'test.zip')) as test_zip:\n    test_zip.extractall('../data')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check File Name\nos.listdir(train_dir)[:5]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_files = os.listdir(train_dir)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(img_files)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CatDogDataset(Dataset):\n    def __init__(self, image_paths, transform):\n        super().__init__()\n        self.paths = image_paths\n        self.len = len(self.paths)\n        self.transform = transform\n        \n    def __len__(self): return self.len\n    \n    def __getitem__(self, index): \n        path = self.paths[index]\n        image = Image.open(path).convert('RGB')\n        image = self.transform(image)\n        label = 0 if 'cat' in path else 1\n        return (image, label)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5,), (0.5,))\n])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import random","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_path(p): return f\"../data/train/{p}\"\nimg_files = list(filter(lambda x: x != '../input/dogs-vs-cats-redux-kernels-edition/train/train', img_files))\nimg_files = list(map(train_path, img_files))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(img_files)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"random.shuffle(img_files)\ntrain_files = img_files[:20000]\nvalid = img_files[20000:]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_files[:5]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train_files)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(valid)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ds = CatDogDataset(train_files, transform)\ntrain_dl = DataLoader(train_ds, batch_size=100)\nlen(train_ds), len(train_dl)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"valid_ds = CatDogDataset(valid, transform)\nvalid_dl = DataLoader(valid_ds, batch_size=100)\nlen(valid_ds), len(valid_dl)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Transfer Learning","metadata":{}},{"cell_type":"code","source":"model = models.densenet121(pretrained=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This model is built out of two main parts, the features and the classifier. The features part is a stack of convolutional layers and overall works as a feature detector that can be fed into a classifier. The classifier part is a single fully-connected layer `(classifier): Linear(in_features=1024, out_features=1000)`. This layer was trained on the ImageNet dataset, so it won't work for our specific problem. That means we need to replace the classifier, but the features will work perfectly on their own. In general, I think about pre-trained networks as amazingly good feature detectors that can be used as the input for simple feed-forward classifiers.","metadata":{}},{"cell_type":"code","source":"# Freeze parameters so we don't backprop through them\nfor param in model.parameters():\n    param.requires_grad = False\n\nfrom collections import OrderedDict\nclassifier = nn.Sequential(OrderedDict([\n                          ('fc1', nn.Linear(1024, 512)),\n                          ('relu', nn.ReLU()),\n                          ('fc2', nn.Linear(512, 2)),\n                          ('output', nn.LogSoftmax(dim=1))\n                          ]))\n    \nmodel.classifier = classifier\nmodel.cuda()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"losses = []\naccuracies = []\nepoches = 5\nstart = time.time()\nloss_fn = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr = 0.001)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for epoch in range(epoches):\n    epoch_loss = 0\n    epoch_accuracy = 0\n    for X, y in train_dl:\n        X = X.cuda()\n        y = y.cuda()\n        preds = model(X)\n        preds = torch.exp(preds)\n        loss = loss_fn(preds, y)\n        \n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        \n        accuracy = ((preds.argmax(dim=1) == y).float().mean())\n        epoch_accuracy += accuracy\n        epoch_loss += loss\n        print('.', end='', flush=True)\n        \n    epoch_accuracy = epoch_accuracy/len(train_dl)\n    accuracies.append(epoch_accuracy)\n    epoch_loss = epoch_loss / len(train_dl)\n    losses.append(epoch_loss)\n    print(\"Epoch: {}, train loss: {:.4f}, train accuracy: {:.4f}, time: {}\".format(epoch, epoch_loss, epoch_accuracy, time.time() - start))\n\n\n    with torch.no_grad():\n        val_epoch_loss = 0\n        val_epoch_accuracy = 0\n        for val_X, val_y in valid_dl:\n            val_X = val_X.cuda()\n            val_y = val_y.cuda()\n            val_preds = model(val_X)\n            val_preds = torch.exp(val_preds)\n            val_loss = loss_fn(val_preds, val_y)\n\n            val_epoch_loss += val_loss            \n            val_accuracy = ((val_preds.argmax(dim=1) == val_y).float().mean())\n            val_epoch_accuracy += val_accuracy\n        val_epoch_accuracy = val_epoch_accuracy/len(valid_dl)\n        val_epoch_loss = val_epoch_loss / len(valid_dl)\n        print(\"Epoch: {}, valid loss: {:.4f}, valid accuracy: {:.4f}, time: {}\\n\".format(epoch, val_epoch_loss, val_epoch_accuracy, time.time() - start))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}