{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Transfer Learning in pytorch using Resnet18"},{"metadata":{"trusted":true},"cell_type":"code","source":"%matplotlib inline\n%config InlineBackend.figure_format = 'retina'\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\nimport os\nfrom collections import OrderedDict\nimport torch\nfrom torch import nn\nfrom torch import optim\nimport torch.nn.functional as F\nfrom torchvision import datasets, transforms, models","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Most of the pretrained models require the input to be 224x224 images. Also, we'll need to match the normalization used when the models were trained. Each color channel was normalized separately, the means are `[0.485, 0.456, 0.406]` and the standard deviations are `[0.229, 0.224, 0.225]`."},{"metadata":{"trusted":true},"cell_type":"code","source":"#download the pretrained model\nimport torchvision.models as models\nmodel = models.resnet18(pretrained = True)\nmodel\n\n#switch device to gpu if available\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntrain_dir = '../input/train/train'\ntest_dir = '../input/test1/test1'\ntrain_files = os.listdir(train_dir)\ntest_files = os.listdir(test_dir)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from torch.utils.data import Dataset, DataLoader, ConcatDataset\nfrom PIL import Image\nimport torchvision\nclass CatDogDataset(Dataset):\n    def __init__(self, file_list, dir, mode='train', transform = None):\n        self.file_list = file_list\n        self.dir = dir\n        self.mode= mode\n        self.transform = transform\n        if self.mode == 'train':\n            if 'dog' in self.file_list[0]:\n                self.label = 1\n            else:\n                self.label = 0\n            \n    def __len__(self):\n        return len(self.file_list)\n    \n    def __getitem__(self, idx):\n        img = Image.open(os.path.join(self.dir, self.file_list[idx]))\n        if self.transform:\n            img = self.transform(img)\n        if self.mode == 'train':\n            img = img.numpy()\n            return img.astype('float32'), self.label\n        else:\n            img = img.numpy()\n            return img.astype('float32'), self.file_list[idx]\n        \ndata_transform = transforms.Compose([\n    transforms.Resize(256),\n    transforms.ColorJitter(),\n    transforms.RandomCrop(224),\n    transforms.RandomHorizontalFlip(),\n    transforms.Resize(128),\n    transforms.ToTensor()\n])\n\ncat_files = [tf for tf in train_files if 'cat' in tf]\ndog_files = [tf for tf in train_files if 'dog' in tf]\n\ncats = CatDogDataset(cat_files, train_dir, transform = data_transform)\ndogs = CatDogDataset(dog_files, train_dir, transform = data_transform)\n\ncatdogs = ConcatDataset([cats, dogs])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataloader = DataLoader(catdogs, batch_size = 64, shuffle=True, num_workers=4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"samples, labels = iter(dataloader).next()\nplt.figure(figsize=(16,24))\ngrid_imgs = torchvision.utils.make_grid(samples[:24])\nnp_grid_imgs = grid_imgs.numpy()\n# in tensor, image is (batch, width, height), so you have to transpose it to (width, height, batch) in numpy to show it.\nplt.imshow(np.transpose(np_grid_imgs, (1,2,0)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Training Only the Classifier"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Freeze the parameters \nfor param in model.parameters():\n    param.requires_grad = False ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Classifier architecture to put on top of resnet18\nfc = nn.Sequential(OrderedDict([\n    ('fc1', nn.Linear(512,100)),\n    ('relu', nn.ReLU()),\n    ('fc2', nn.Linear(100,2)),\n    ('output', nn.LogSoftmax(dim=1))\n]))\n\nmodel.fc = fc","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#shifting model to gpu\nmodel.to(device)\nmodel","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#function to train the model\ndef train(model, trainloader, criterion, optimizer, epochs = 5):\n    train_loss =[]\n    for e in range(epochs):\n        running_loss =0\n        for images, labels in trainloader:\n            inputs, labels = images.to(device), labels.to(device)\n\n            optimizer.zero_grad()\n            img = model(inputs)\n            \n            loss = criterion(img, labels)\n            running_loss+=loss\n            loss.backward()\n            optimizer.step()\n        print(\"Epoch : {}/{}..\".format(e+1,epochs),\n         \"Training Loss: {:.6f}\".format(running_loss/len(trainloader))) \n        train_loss.append(running_loss)\n    plt.plot(train_loss,label=\"Training Loss\")\n    plt.show() \n    \n    \n    \nepochs = 3\nmodel.train()\noptimizer = optim.Adam(model.fc.parameters(), lr=0.001)\ncriterion = nn.NLLLoss()    \ntrain(model,dataloader,criterion, optimizer, epochs)            \n            ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Save the model\nfilename_pth = 'ckpt_resnet18_catdog.pth'\ntorch.save(model.state_dict(), filename_pth)\n\n\n#Transform the test dataset\ntest_transform = transforms.Compose([\n    transforms.Resize((128,128)),\n    transforms.ToTensor()\n])\n\ntestset = CatDogDataset(test_files, test_dir, mode='test', transform = test_transform)\ntestloader = DataLoader(testset, batch_size = 64, shuffle=False, num_workers=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Prediction on Testset"},{"metadata":{"trusted":true},"cell_type":"code","source":"\nmodel.eval()\nfn_list = []\npred_list = []\nfor x, fn in testloader:\n    with torch.no_grad():\n        x = x.to(device)\n        output = model(x)\n        pred = torch.argmax(output, dim=1)\n        fn_list += [n[:-4] for n in fn]\n        pred_list += [p.item() for p in pred]\n\nsubmission = pd.DataFrame({\"id\":fn_list, \"label\":pred_list})\nsubmission.to_csv('preds_resnet18.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"samples, _ = iter(testloader).next()\nsamples = samples.to(device)\nfig = plt.figure(figsize=(24, 16))\nfig.tight_layout()\noutput = model(samples[:24])\npred = torch.argmax(output, dim=1)\npred = [p.item() for p in pred]\nad = {0:'cat', 1:'dog'}\nfor num, sample in enumerate(samples[:24]):\n    plt.subplot(4,6,num+1)\n    plt.title(ad[pred[num]])\n    plt.axis('off')\n    sample = sample.cpu().numpy()\n    plt.imshow(np.transpose(sample, (1,2,0)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"References:<br>\n[densenet](https://www.kaggle.com/jaeboklee/pytorch-cat-vs-dog) <br>\n[Udacity Transfer Learning](https://classroom.udacity.com/courses/ud188/lessons/c5706f76-0e30-4b48-b74e-c19fafc33a75/concepts/c33dec4c-ff16-465f-88e9-e95365e7b522)"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.6.8"}},"nbformat":4,"nbformat_minor":1}