{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Imports"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport zipfile as zp\nimport os\nimport shutil\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport glob\n\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\nfrom torchvision import datasets, models, transforms\n\nfrom tqdm.autonotebook import tqdm\n\ndevice = \"cuda:0\" if torch.cuda.is_available() else 'cpu'","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load and prepare data"},{"metadata":{"trusted":true},"cell_type":"code","source":"os.makedirs('../data', exist_ok=True)\n\nbase_dir = '../input/dogs-vs-cats-redux-kernels-edition'\ntrain_dir = '../data/train'\ntest_dir = '../data/test'\n\ntrain_zip = zp.ZipFile(os.path.join(base_dir, 'train.zip'))\ntrain_zip.extractall('../data')\n\ntest_zip = zp.ZipFile(os.path.join(base_dir, 'test.zip'))\ntest_zip.extractall('../data')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"os.listdir(train_dir)[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_list = glob.glob(os.path.join(train_dir, '*.jpg'))\ntest_list = glob.glob(os.path.join(test_dir, '*.jpg'))\n\nprint(train_list[:5])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(len(train_list), len(test_list))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img_path = train_list[0]\nimg = Image.open(img_path)\n\nplt.imshow(img)\nplt.axis('off')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_list[0].split('/')[-1].split('.')[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_list, val_list = train_test_split(train_list, test_size=0.2)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Image Augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"size = 224\nmean = (0.485, 0.456, 0.406)\nstd = (0.229, 0.224, 0.225)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class ImageTransform(): \n    \n    def __init__(self, resize, mean, std): \n        self.data_transform = {\n            'train': transforms.Compose([\n                transforms.RandomResizedCrop(resize, scale=(0.5, 1.0)), \n                transforms.RandomHorizontalFlip(),\n                transforms.ToTensor(), \n                transforms.Normalize(mean, std)\n            ]), \n            'val': transforms.Compose([\n                transforms.Resize(256), \n                transforms.CenterCrop(resize),\n                transforms.ToTensor(),\n                transforms.Normalize(mean, std)\n            ])\n        }\n        \n    def __call__(self, img, phase): \n        return self.data_transform[phase](img)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load datasets with own Dataset class"},{"metadata":{"trusted":true},"cell_type":"code","source":"class ImageDataset(torch.utils.data.Dataset): \n    \n    def __init__(self, file_list, transform=None, phase='train'): \n        self.file_list = file_list\n        self.transform = transform\n        self.phase = phase\n        \n    def __len__(self): \n        self.filelength = len(self.file_list)\n        return self.filelength\n    \n    def __getitem__(self, idx): \n        img_path = self.file_list[idx]\n        img = Image.open(img_path)\n        img_transformed = self.transform(img, self.phase)\n        \n        label = img_path.split('/')[-1].split('.')[0]\n        if label == 'dog': \n            label = 1\n        elif label == 'cat': \n            label = 0\n        \n        return img_transformed, label","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size = 32\nlearning_rate = 0.001\nepochs = 2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data = ImageDataset(train_list, transform=ImageTransform(size, mean, std), phase='train')\nval_data = ImageDataset(val_list, transform=ImageTransform(size, mean, std), phase='val')\ntest_data = ImageDataset(test_list, transform=ImageTransform(size, mean, std), phase='val')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_loader = torch.utils.data.DataLoader(dataset = train_data, batch_size=batch_size, shuffle=True)\nval_loader = torch.utils.data.DataLoader(dataset = val_data, batch_size=batch_size, shuffle=True)\ntest_loader = torch.utils.data.DataLoader(dataset = test_data, batch_size=batch_size, shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Create and train Neural Network"},{"metadata":{"trusted":true},"cell_type":"code","source":"loss_function = F.cross_entropy","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train(model: nn.Module, loss_function: F, params_to_update): \n    \n    optimizer = torch.optim.SGD(params=params_to_update, lr=learning_rate, momentum=0.9)\n    \n    pbar=tqdm(total=len(train_loader))\n    \n    model.train()\n    \n    for epoch in range(epochs): \n        \n        pbar.set_description('Epoch %d/%d' % (epoch + 1, epochs))\n        pbar.reset()\n        epoch_loss = 0\n        epoch_accuracy = 0\n        \n        for data, labels in train_loader: \n            \n            data = data.to(device)\n            labels = labels.to(device)\n            \n            optimizer.zero_grad()\n            \n            preds = model(data)\n            error = loss_function(preds, labels)\n            error.backward()\n            \n            optimizer.step()\n            \n            epoch_accuracy += ((preds.argmax(dim=1) == labels).float().mean())\n            epoch_loss += error.item()\n            \n            pbar.update()\n            \n        epoch_accuracy /= len(train_loader)\n        epoch_loss /= len(train_loader)\n        \n        print('Epoch %d finished with acc: %g, loss: %g' % (epoch+1, epoch_accuracy, epoch_loss))\n    pbar.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"use_pretrained = True\nnet = models.vgg16(pretrained=use_pretrained)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"net.classifier[6] = nn.Linear(in_features=4096, out_features=2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"params_to_update = []\n\nupdate_params_name = ['classifier.6.weight', 'classifier.6.bias']\n\nfor name, param in net.named_parameters(): \n    if name in update_params_name: \n        param.requires_grad = True\n        params_to_update.append(param)\n    else: \n        param.requires_grad = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"net = net.to(device)\ntrain(net, loss_function, params_to_update)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Evaluate Neural Network"},{"metadata":{"trusted":true},"cell_type":"code","source":"def evaluate_model(model: nn.Module, dataset: torch.utils.data.DataLoader, loss_function: F): \n   \n    loss = 0\n    acc = 0\n    \n    model.eval()\n    \n    for data, labels in tqdm(dataset):\n        \n        data = data.to(device)\n        labels = labels.to(device)\n        \n        with torch.no_grad(): \n            preds = model(data)\n            \n            loss += loss_function(preds, labels).item()\n            acc += ((preds.argmax(dim=1) == labels).float().mean())\n            \n    return acc / len(dataset), loss / len(dataset)\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"acc_train, loss_train = evaluate_model(net, train_loader, loss_function)\nprint('Training set: ')\nprint('Loss: %g, Accuracy: %g' % (loss_train, acc_train))\nprint('')\n\nacc_val, loss_val = evaluate_model(net, val_loader, loss_function)\nprint('Validation set: ')\nprint('Loss: %g, Accuracy: %g' % (loss_val, acc_val))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Submit predictions"},{"metadata":{"trusted":true},"cell_type":"code","source":"id_list = []\npred_list = []\n\nwith torch.no_grad(): \n    \n    for data, paths in tqdm(test_loader): \n        \n        data = data.to(device)\n                \n        for idx in range(data.shape[0]): \n            \n            path = paths[idx]\n            img = data[idx]\n            \n            img = img.unsqueeze(0)\n            img = img.to(device)\n            \n            net.eval()\n            \n            _id = int(path.split('/')[-1].split('.')[0])            \n            prediction = net(img)\n            pred = F.softmax(prediction, dim=1)[:, 1].tolist()\n        \n            id_list.append(_id)\n            pred_list.append(pred[0])\n            \n        \nres = pd.DataFrame({\n    'id': id_list,\n    'label': pred_list\n})\n\nres.sort_values(by='id', inplace=True)\nres.reset_index(drop=True, inplace=True)\n\nres.head(10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"res.to_csv('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}