{"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":"!pip install torchsummary\n!pip install efficientnet_pytorch","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-01-22T13:52:22.084506Z","iopub.execute_input":"2022-01-22T13:52:22.084852Z","iopub.status.idle":"2022-01-22T13:52:40.705048Z","shell.execute_reply.started":"2022-01-22T13:52:22.084774Z","shell.execute_reply":"2022-01-22T13:52:40.704237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Computer Vision - Multiclass Classification\n\nDataset: Dog Breed Identification, from: https://www.kaggle.com/c/dog-breed-identification/overview\n\nMethod: Comparing Models\n- ResNet50\n- EfficientNet\n- VGG16\n- InceptionV3\n\nMetric: Cross Entropy Loss, Accuracy\n\nNote: Runtime: ~12 to 15 minutes for all models to train 1 epoch (use kaggle cuda gpu)","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nfrom torch.utils.data import DataLoader\nfrom torchvision import datasets, transforms, models\nfrom torchvision.utils import make_grid\nfrom torch.optim import lr_scheduler\nfrom torchsummary import summary\nfrom efficientnet_pytorch import EfficientNet\n\nimport cv2\nfrom mpl_toolkits.axes_grid1 import ImageGrid\nfrom PIL import Image\nfrom PIL import ImageFile\nfrom IPython.display import display\n\nImageFile.LOAD_TRUNCATED_IMAGES = True\n\nimport glob\nimport os\nimport random\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt \n%matplotlib inline\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:40.707431Z","iopub.execute_input":"2022-01-22T13:52:40.707889Z","iopub.status.idle":"2022-01-22T13:52:42.637393Z","shell.execute_reply.started":"2022-01-22T13:52:40.707848Z","shell.execute_reply":"2022-01-22T13:52:42.636663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def seed_everything(seed=1234):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\nseed_everything(42)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:42.638736Z","iopub.execute_input":"2022-01-22T13:52:42.639023Z","iopub.status.idle":"2022-01-22T13:52:42.647274Z","shell.execute_reply.started":"2022-01-22T13:52:42.638986Z","shell.execute_reply":"2022-01-22T13:52:42.646405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Read the dataset\n\nThe dataset provided has a training set and a test set of images of dogs but we only use the training set because the test set has hidden labels. Each image has a filename that is its unique id. The dataset comprises 120 breeds of dogs. The goal is to create a classifier capable of determining a dog's breed from a photo.","metadata":{}},{"cell_type":"code","source":"PATH = '../input/dog-breed-identification/'\nlabels = pd.read_csv(PATH + 'labels.csv')\nlabelnames = pd.read_csv(PATH + 'sample_submission.csv').keys()[1:]\nprint(\"Train folder has \", len(os.listdir(PATH+'train')),'images which matches with label\\'s', len(labels),'images')","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:42.649947Z","iopub.execute_input":"2022-01-22T13:52:42.650231Z","iopub.status.idle":"2022-01-22T13:52:44.211188Z","shell.execute_reply.started":"2022-01-22T13:52:42.650195Z","shell.execute_reply":"2022-01-22T13:52:44.210456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Basic Visualization of Dog Breed distribution","metadata":{}},{"cell_type":"code","source":"img_file = PATH+'train'\n\ndf=labels.assign(img_path=lambda x: img_file + x['id'] +'.jpg')\n\nax=pd.value_counts(df['breed'],ascending=True).plot(kind='barh',fontsize=\"40\",title=\"Class Distribution\",figsize=(50,100))\nax.set(xlabel=\"Images per class\", ylabel=\"Classes\")\nax.xaxis.label.set_size(40)\nax.yaxis.label.set_size(40)\nax.title.set_size(60)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:44.212566Z","iopub.execute_input":"2022-01-22T13:52:44.212810Z","iopub.status.idle":"2022-01-22T13:52:47.224273Z","shell.execute_reply.started":"2022-01-22T13:52:44.212775Z","shell.execute_reply":"2022-01-22T13:52:47.221963Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Create a mapping between breed to code and code to breed to easily connect the data in two directions\n\nOne hot encodding applied to the breed type\n\nSplit the dataset into\n\nTrain: 7666 datas (75%)\n\nValidation: 1534 datas (15%)\n\nTest: 1022 datas (10%)","metadata":{}},{"cell_type":"code","source":"codes = range(len(labelnames))\nbreed_to_code = dict(zip(labelnames, codes))\ncode_to_breed = dict(zip(codes, labelnames))\nlabels['target'] =  [breed_to_code[x] for x in labels.breed]\nlabels_pivot = labels.pivot('id', 'breed', 'target').reset_index().fillna(0)\n\ntrain = labels_pivot.sample(frac=0.75)\ntemp = labels_pivot[~labels_pivot['id'].isin(train['id'])]\nvalid = temp.sample(frac=0.6)\ntest = temp[~temp['id'].isin(valid['id'])]\nprint(\"Train shape: \", train.shape)\nprint(\"Validation shape: \", valid.shape)\nprint(\"Test shape:\", test.shape)\nprint(\"Data shape overview (Train):\")\nprint(train)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:47.225229Z","iopub.execute_input":"2022-01-22T13:52:47.225528Z","iopub.status.idle":"2022-01-22T13:52:47.410671Z","shell.execute_reply.started":"2022-01-22T13:52:47.225486Z","shell.execute_reply":"2022-01-22T13:52:47.409844Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels.head(5)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:47.411959Z","iopub.execute_input":"2022-01-22T13:52:47.412273Z","iopub.status.idle":"2022-01-22T13:52:47.423872Z","shell.execute_reply.started":"2022-01-22T13:52:47.412236Z","shell.execute_reply":"2022-01-22T13:52:47.423037Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The image is resized to 256x256 and then cropped the image into 224x224 randomly to avoid squashed images and normalized it using Imagenet's mean and standard deviation after converting to tensor. for train, test and valid set.\n\nFor training images, data augmentation is used which includes random rotation of 30 degrees and horizontal flip.","metadata":{}},{"cell_type":"code","source":"# Image transformations\nimg_transform = {\n    'train':transforms.Compose([\n        transforms.RandomResizedCrop(size = 256),\n        transforms.RandomRotation(degrees = 30),\n        transforms.ColorJitter(),\n        transforms.RandomHorizontalFlip(),\n        transforms.CenterCrop(size=224),  \n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406],\n                             [0.229, 0.224, 0.225])  \n    ]),\n    'valid':transforms.Compose([\n        transforms.Resize(size = 256),\n        transforms.CenterCrop(size = 224),\n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406],\n                             [0.229, 0.224, 0.225])\n    ]),\n    'test':transforms.Compose([\n        transforms.Resize(size = 256),\n        transforms.CenterCrop(size = 224),\n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406],\n                             [0.229, 0.224, 0.225])\n    ]),\n}","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:47.425368Z","iopub.execute_input":"2022-01-22T13:52:47.425843Z","iopub.status.idle":"2022-01-22T13:52:47.434833Z","shell.execute_reply.started":"2022-01-22T13:52:47.425804Z","shell.execute_reply":"2022-01-22T13:52:47.434160Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Write three separate data loaders for the training, validation, and test datasets of dog images (located at dog_images/train, dog_images/valid, and dog_images/test, respectively).","metadata":{}},{"cell_type":"code","source":"class DogBreedDataset(torch.utils.data.Dataset):\n    'Characterizes a dataset for PyTorch'\n    def __init__(self, img_dir, label, transform):\n        'Initialization'\n        self.img_dir = img_dir\n        self.transform = transform\n        self.label = label\n\n    def __len__(self):\n        'Denotes the total number of samples'\n        return len(self.label)\n\n    def __getitem__(self, index):\n        if self.label is not None:\n            img_name = '{}.jpg'.format(self.label.iloc[index, 0])\n            fullname = self.img_dir + img_name\n            image = Image.open(fullname)\n            label = self.label.iloc[index, 1:].astype('float').to_numpy()\n            label = np.argmax(label)\n            if self.transform:\n                image = self.transform(image)\n            return [image, label]\n        ","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:47.436485Z","iopub.execute_input":"2022-01-22T13:52:47.436759Z","iopub.status.idle":"2022-01-22T13:52:47.446597Z","shell.execute_reply.started":"2022-01-22T13:52:47.436722Z","shell.execute_reply":"2022-01-22T13:52:47.445798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size = 12\nnum_workers = 4\ntrain_img = DogBreedDataset(PATH+'train/', train, transform = img_transform['train'])\nvalid_img = DogBreedDataset(PATH+'train/', valid, transform = img_transform['valid'])\ntest_img = DogBreedDataset(PATH+'train/', test, transform = img_transform['test'])\n\n\ndataloaders={\n    'train':torch.utils.data.DataLoader(train_img, batch_size, num_workers = num_workers, shuffle=True),\n    'valid':torch.utils.data.DataLoader(valid_img, batch_size, num_workers = num_workers, shuffle=False),\n    'test':torch.utils.data.DataLoader(test_img, batch_size, num_workers = num_workers, shuffle=False)\n}\n","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:47.450780Z","iopub.execute_input":"2022-01-22T13:52:47.451272Z","iopub.status.idle":"2022-01-22T13:52:47.460065Z","shell.execute_reply.started":"2022-01-22T13:52:47.451231Z","shell.execute_reply":"2022-01-22T13:52:47.459315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"use_cuda = torch.cuda.is_available()","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:47.461493Z","iopub.execute_input":"2022-01-22T13:52:47.462484Z","iopub.status.idle":"2022-01-22T13:52:47.506195Z","shell.execute_reply.started":"2022-01-22T13:52:47.462444Z","shell.execute_reply":"2022-01-22T13:52:47.505472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Show some sample of the image just to make sure the transfomration and augmentation is valid","metadata":{}},{"cell_type":"code","source":"def imshow(axis, inp):\n    \"\"\"Denormalize and show\"\"\"\n    inp = inp.numpy().transpose((1, 2, 0))\n    mean = np.array([0.485, 0.456, 0.406])\n    std = np.array([0.229, 0.224, 0.225])\n    inp = std * inp + mean\n    axis.imshow(inp)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:47.507413Z","iopub.execute_input":"2022-01-22T13:52:47.508016Z","iopub.status.idle":"2022-01-22T13:52:47.516506Z","shell.execute_reply.started":"2022-01-22T13:52:47.507981Z","shell.execute_reply":"2022-01-22T13:52:47.515768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img, label = next(iter(dataloaders['test']))\nprint(img.size(), label.size())\nfig = plt.figure(1, figsize=(16, 12))\ngrid = ImageGrid(fig, 111, nrows_ncols=(3, 4), axes_pad=0.05)    \nfor i in range(img.size()[0]):\n    ax = grid[i]\n    imshow(ax, img[i])","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:47.517748Z","iopub.execute_input":"2022-01-22T13:52:47.518586Z","iopub.status.idle":"2022-01-22T13:52:50.422261Z","shell.execute_reply.started":"2022-01-22T13:52:47.518550Z","shell.execute_reply":"2022-01-22T13:52:50.420820Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We used three convolutional layers with relu activations which are followed by maxpool layers. Also, used two fully connected layers. Between fully connected layers, dropout technique with probability = 0.25 is used to avoid the overfitting.","metadata":{}},{"cell_type":"markdown","source":"Define train and test method in general","metadata":{}},{"cell_type":"code","source":"def train(n_epochs, loaders, model, optimizer, criterion, scheduler, use_cuda, save_path):\n    valid_loss_min = np.Inf \n    \n    dataset_sizes = {'train': len(loaders['train'].dataset), \n                     'valid': len(loaders['valid'].dataset),\n                     'test': len(loaders['test'].dataset)}\n    \n    for epoch in range(1, n_epochs+1):\n        train_loss = 0.0\n        train_corrects = 0.0\n        valid_loss = 0.0\n        valid_corrects = 0.0\n        \n        model.train()\n        for batch_idx, (data, target) in enumerate(loaders['train']):\n            if use_cuda:\n                data, target = data.cuda(), target.cuda()\n            \n            optimizer.zero_grad()\n            output = model(data)\n            _, preds = torch.max(output.data, 1)\n            loss = criterion(output, target)\n            loss.backward()\n            optimizer.step()\n            # Record the average training loss\n            train_loss += loss.data\n            train_corrects += torch.sum(preds == target.data)\n            \n            if batch_idx % 100 == 0:\n                print('Epoch: %d \\tBatch: %d \\tTraining Loss: %.6f' %(epoch, batch_idx + 1, train_loss / ((batch_idx + 1) * 12)))\n        \n        train_loss = train_loss / dataset_sizes['train']\n        train_corrects = train_corrects / dataset_sizes['train']\n        \n        scheduler.step()\n\n        model.eval()\n        for batch_idx, (data, target) in enumerate(loaders['valid']):\n            if use_cuda:\n                data, target = data.cuda(), target.cuda()\n                \n            # Update the average validation loss\n            output = model(data)\n            _, preds = torch.max(output.data, 1)\n            loss = criterion(output, target)\n            valid_loss += loss.data\n            valid_corrects += torch.sum(preds == target.data)\n        \n        valid_loss = valid_loss / dataset_sizes['valid']\n        valid_corrects = valid_corrects / dataset_sizes['valid']\n        \n        # Print validation statistics \n        print('Epoch: {} \\tValidation Loss: {:.4f} \\tValidation Acc: {:.4f}'.format(\n            epoch, \n            valid_loss,\n            valid_corrects\n            ))\n        \n        # Save the model if validation loss has decreased\n        if valid_loss < valid_loss_min:\n            torch.save(model.state_dict(), save_path)\n            print('Validation loss decreased ({:.4f} --> {:.4f}).  Saving model...'.format(valid_loss_min,valid_loss))\n            valid_loss_min = valid_loss    \n\n    return model","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:50.423898Z","iopub.execute_input":"2022-01-22T13:52:50.424325Z","iopub.status.idle":"2022-01-22T13:52:50.441966Z","shell.execute_reply.started":"2022-01-22T13:52:50.424287Z","shell.execute_reply":"2022-01-22T13:52:50.441265Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def test(loaders, model, optimizer, criterion, use_cuda):\n    test_loss = 0.0\n    test_corrects = 0.0\n    \n    dataset_sizes = {'train': len(loaders['train'].dataset), \n                     'valid': len(loaders['valid'].dataset),\n                     'test': len(loaders['test'].dataset)}\n    \n    model.eval()\n    for batch_idx, (data, target) in enumerate(loaders['test']):\n        if use_cuda:\n            data, target = data.cuda(), target.cuda()\n        # Update the average validation loss\n        output = model(data)\n        _, preds = torch.max(output.data, 1)\n        loss = criterion(output, target)\n        test_loss += loss.data\n        test_corrects += torch.sum(preds == target.data)\n    \n    test_loss = test_loss / dataset_sizes['test']\n    test_corrects = test_corrects / dataset_sizes['test']\n    \n    print('Test Loss: {:.4f} \\tTest Acc: {:.4f}'.format(\n        test_loss,\n        test_corrects\n        ))\n    \n    return test_loss, test_corrects","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:50.443231Z","iopub.execute_input":"2022-01-22T13:52:50.443712Z","iopub.status.idle":"2022-01-22T13:52:50.457503Z","shell.execute_reply.started":"2022-01-22T13:52:50.443673Z","shell.execute_reply":"2022-01-22T13:52:50.456959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ResNet50","metadata":{}},{"cell_type":"markdown","source":"ResNet50 is a variant of ResNet model which has 48 Convolution layers along with 1 MaxPool and 1 Average Pool layer. It has 3.8 x 10^9 Floating points operations. It is a widely used ResNet model and we have explored ResNet50 architecture in depth. You can load a pretrained version of the network trained on more than a million images from the ImageNet database.","metadata":{}},{"cell_type":"code","source":"model_resnet = models.resnet50(pretrained=True)\n\n# Freeze training for all \"features\" layers\nfor param in model_resnet.parameters():\n    param.requires_grad = False\n    \n# Replace the last fully connected layer with a Linnear layer 120 output\nin_features = model_resnet.fc.in_features\nmodel_resnet.fc = nn.Linear(in_features, 120)\n\nif use_cuda:\n    model_resnet = model_resnet.cuda()","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:50.459043Z","iopub.execute_input":"2022-01-22T13:52:50.459629Z","iopub.status.idle":"2022-01-22T13:52:59.420359Z","shell.execute_reply.started":"2022-01-22T13:52:50.459586Z","shell.execute_reply":"2022-01-22T13:52:59.419596Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Setup criterion, optimizer, and learning rate scheduler","metadata":{}},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()\nmodel_resnet_grad_paramaters = filter(lambda p: p.requires_grad, model_resnet.parameters())\noptimizer = torch.optim.SGD(model_resnet_grad_paramaters, lr=0.001, momentum = 0.9)\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:59.421866Z","iopub.execute_input":"2022-01-22T13:52:59.422132Z","iopub.status.idle":"2022-01-22T13:52:59.428842Z","shell.execute_reply.started":"2022-01-22T13:52:59.422099Z","shell.execute_reply":"2022-01-22T13:52:59.428037Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Train the ResNet50 model","metadata":{}},{"cell_type":"code","source":"n_epoch = 10\n\nmodel_resnet = train(n_epoch, dataloaders, model_resnet, optimizer, criterion, exp_lr_scheduler, use_cuda, 'model_resnet.pt')","metadata":{"execution":{"iopub.status.busy":"2022-01-22T13:52:59.430365Z","iopub.execute_input":"2022-01-22T13:52:59.430650Z","iopub.status.idle":"2022-01-22T14:03:09.108861Z","shell.execute_reply.started":"2022-01-22T13:52:59.430615Z","shell.execute_reply":"2022-01-22T14:03:09.108060Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Test the ResNet50 model","metadata":{}},{"cell_type":"code","source":"model_resnet.load_state_dict(torch.load('model_resnet.pt'))\n\nresnet_score = test(dataloaders, model_resnet, optimizer, criterion, use_cuda)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:03:09.110423Z","iopub.execute_input":"2022-01-22T14:03:09.110686Z","iopub.status.idle":"2022-01-22T14:03:16.205995Z","shell.execute_reply.started":"2022-01-22T14:03:09.110649Z","shell.execute_reply":"2022-01-22T14:03:16.205002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"summary(model_resnet, input_size=(3, 224, 224))","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:03:16.210886Z","iopub.execute_input":"2022-01-22T14:03:16.211217Z","iopub.status.idle":"2022-01-22T14:03:16.305853Z","shell.execute_reply.started":"2022-01-22T14:03:16.211176Z","shell.execute_reply":"2022-01-22T14:03:16.303494Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Train the ResNet50 without freezing the trained layer to see the comparison","metadata":{}},{"cell_type":"code","source":"model_resnet = models.resnet50(pretrained=True)\n    \n# Replace the last fully connected layer with a Linnear layer 120 output\nin_features = model_resnet.fc.in_features\nmodel_resnet.fc = nn.Linear(in_features, 120)\n\nif use_cuda:\n    model_resnet = model_resnet.cuda()\n      \ncriterion = nn.CrossEntropyLoss()\nmodel_resnet_grad_paramaters = filter(lambda p: p.requires_grad, model_resnet.parameters())\noptimizer = torch.optim.SGD(model_resnet_grad_paramaters, lr=0.001, momentum = 0.9)\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:03:16.307191Z","iopub.execute_input":"2022-01-22T14:03:16.307462Z","iopub.status.idle":"2022-01-22T14:03:17.077153Z","shell.execute_reply.started":"2022-01-22T14:03:16.307426Z","shell.execute_reply":"2022-01-22T14:03:17.076418Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_epoch = 10\n\nmodel_resnet = train(n_epoch, dataloaders, model_resnet, optimizer, criterion, exp_lr_scheduler, use_cuda, 'model_resnet.pt')","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:03:17.078455Z","iopub.execute_input":"2022-01-22T14:03:17.078712Z","iopub.status.idle":"2022-01-22T14:15:56.146968Z","shell.execute_reply.started":"2022-01-22T14:03:17.078678Z","shell.execute_reply":"2022-01-22T14:15:56.146133Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_resnet.load_state_dict(torch.load('model_resnet.pt'))\n\nresnet_score_unfreeze = test(dataloaders, model_resnet, optimizer, criterion, use_cuda)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:15:56.148962Z","iopub.execute_input":"2022-01-22T14:15:56.149229Z","iopub.status.idle":"2022-01-22T14:16:03.343350Z","shell.execute_reply.started":"2022-01-22T14:15:56.149190Z","shell.execute_reply":"2022-01-22T14:16:03.342568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# EfficientNet","metadata":{}},{"cell_type":"markdown","source":"EfficientNet is a convolutional neural network architecture and scaling method that uniformly scales all dimensions of depth/width/resolution using a compound coefficient. Unlike conventional practice that arbitrary scales these factors, the EfficientNet scaling method uniformly scales network width, depth, and resolution with a set of fixed scaling coefficients.","metadata":{}},{"cell_type":"code","source":"model_fnet = EfficientNet.from_name('efficientnet-b1')\n\n# Freeze training for all \"features\" layers\nfor param in model_fnet.parameters():\n    param.requires_grad = True\n\n# Replace the last fully connected layer with a Linnear layer 120 output\nin_features = model_fnet._fc.in_features\nmodel_fnet._fc = nn.Linear(in_features, 120)\n\n# Setup criterion, optimizer, and learning rate scheduler\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model_fnet.parameters())\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)\n\nif use_cuda:\n    model_fnet = model_fnet.cuda()","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:16:03.345225Z","iopub.execute_input":"2022-01-22T14:16:03.345738Z","iopub.status.idle":"2022-01-22T14:16:03.469747Z","shell.execute_reply.started":"2022-01-22T14:16:03.345695Z","shell.execute_reply":"2022-01-22T14:16:03.469074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Train the EfficientNet model","metadata":{}},{"cell_type":"code","source":"n_epoch = 10\n\nmodel_fnet = train(n_epoch, dataloaders, model_resnet, optimizer, criterion, exp_lr_scheduler, use_cuda, 'model_fnet.pt')","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:16:03.470885Z","iopub.execute_input":"2022-01-22T14:16:03.471285Z","iopub.status.idle":"2022-01-22T14:28:13.287522Z","shell.execute_reply.started":"2022-01-22T14:16:03.471242Z","shell.execute_reply":"2022-01-22T14:28:13.286562Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Test the EfficientNet model","metadata":{}},{"cell_type":"code","source":"model_fnet.load_state_dict(torch.load('model_fnet.pt'))\n\nfnet_score = test(dataloaders, model_fnet, optimizer, criterion, use_cuda)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:28:13.292262Z","iopub.execute_input":"2022-01-22T14:28:13.292723Z","iopub.status.idle":"2022-01-22T14:28:19.884179Z","shell.execute_reply.started":"2022-01-22T14:28:13.292647Z","shell.execute_reply":"2022-01-22T14:28:19.882567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"summary(model_fnet, input_size=(3, 224, 224))","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:28:19.886325Z","iopub.execute_input":"2022-01-22T14:28:19.886600Z","iopub.status.idle":"2022-01-22T14:28:19.957915Z","shell.execute_reply.started":"2022-01-22T14:28:19.886561Z","shell.execute_reply":"2022-01-22T14:28:19.957198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Train the EfficientNet without freezing the trained layer to see the comparison","metadata":{}},{"cell_type":"code","source":"model_fnet = EfficientNet.from_name('efficientnet-b1')\n\n# Replace the last fully connected layer with a Linnear layer 120 output\nin_features = model_fnet._fc.in_features\nmodel_fnet._fc = nn.Linear(in_features, 120)\n\n# Setup criterion, optimizer, and learning rate scheduler\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model_fnet.parameters())\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)\n\nif use_cuda:\n    model_fnet = model_fnet.cuda()","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:28:19.962491Z","iopub.execute_input":"2022-01-22T14:28:19.962677Z","iopub.status.idle":"2022-01-22T14:28:20.084002Z","shell.execute_reply.started":"2022-01-22T14:28:19.962654Z","shell.execute_reply":"2022-01-22T14:28:20.083284Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_epoch = 10\n\nmodel_fnet = train(n_epoch, dataloaders, model_resnet, optimizer, criterion, exp_lr_scheduler, use_cuda, 'model_fnet.pt')","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:28:20.085189Z","iopub.execute_input":"2022-01-22T14:28:20.085438Z","iopub.status.idle":"2022-01-22T14:40:31.193790Z","shell.execute_reply.started":"2022-01-22T14:28:20.085407Z","shell.execute_reply":"2022-01-22T14:40:31.192845Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_fnet.load_state_dict(torch.load('model_fnet.pt'))\n\nfnet_score_unfreeze = test(dataloaders, model_fnet, optimizer, criterion, use_cuda)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:40:31.195776Z","iopub.execute_input":"2022-01-22T14:40:31.196007Z","iopub.status.idle":"2022-01-22T14:40:37.634032Z","shell.execute_reply.started":"2022-01-22T14:40:31.195979Z","shell.execute_reply":"2022-01-22T14:40:37.633101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# VGG16","metadata":{}},{"cell_type":"markdown","source":"VGG16 is a convolution neural net architecture that is considered to be one of the excellent vision model architecture till date. Most unique thing about VGG16 is that instead of having a large number of hyper-parameter they focused on having convolution layers of 3x3 filter with a stride 1 and always used same padding and maxpool layer of 2x2 filter of stride 2. It follows this arrangement of convolution and max pool layers consistently throughout the whole architecture. In the end it has 2 FC(fully connected layers) followed by a softmax for output. The 16 in VGG16 refers to it has 16 layers that have weights. This network is a pretty large network and it has about 138 million (approx) parameters.","metadata":{}},{"cell_type":"code","source":"model_vgg = models.vgg16_bn(pretrained=True)\n\n# Freeze training for all \"features\" layers\nfor param in model_vgg.features.parameters():\n    param.require_grad = False\n    \nin_features = model_vgg.classifier[6].in_features\nfeatures = list(model_vgg.classifier.children())[:-1] # Remove last layer\nfeatures.extend([nn.Linear(in_features, 120)]) # Add our layer with 120 outputs\nmodel_vgg.classifier = nn.Sequential(*features)\n\n# Setup criterion, optimizer, and learning rate scheduler\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.SGD(model_vgg.parameters(), lr=0.001, momentum=0.9)\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)\n\nif use_cuda:\n    model_vgg = model_vgg.cuda()","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:40:37.635625Z","iopub.execute_input":"2022-01-22T14:40:37.635825Z","iopub.status.idle":"2022-01-22T14:41:04.318159Z","shell.execute_reply.started":"2022-01-22T14:40:37.635798Z","shell.execute_reply":"2022-01-22T14:41:04.317282Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Train the VGG16 model","metadata":{}},{"cell_type":"code","source":"n_epoch = 10\n\nmodel_vgg = train(n_epoch, dataloaders, model_vgg, optimizer, criterion, exp_lr_scheduler, use_cuda, 'model_vgg.pt')","metadata":{"execution":{"iopub.status.busy":"2022-01-22T14:41:04.319375Z","iopub.execute_input":"2022-01-22T14:41:04.319586Z","iopub.status.idle":"2022-01-22T15:04:32.819352Z","shell.execute_reply.started":"2022-01-22T14:41:04.319561Z","shell.execute_reply":"2022-01-22T15:04:32.818424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Test the VGG16 model","metadata":{}},{"cell_type":"code","source":"model_vgg.load_state_dict(torch.load('model_vgg.pt'))\n\nvgg_score = test(dataloaders, model_vgg, optimizer, criterion, use_cuda)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:04:32.824395Z","iopub.execute_input":"2022-01-22T15:04:32.826406Z","iopub.status.idle":"2022-01-22T15:04:40.207514Z","shell.execute_reply.started":"2022-01-22T15:04:32.826355Z","shell.execute_reply":"2022-01-22T15:04:40.206732Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"summary(model_vgg, input_size=(3, 224, 224))","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:04:40.212273Z","iopub.execute_input":"2022-01-22T15:04:40.214164Z","iopub.status.idle":"2022-01-22T15:04:40.254071Z","shell.execute_reply.started":"2022-01-22T15:04:40.214121Z","shell.execute_reply":"2022-01-22T15:04:40.253425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Train the VGG16 without freezing the trained layer to see the comparison","metadata":{}},{"cell_type":"code","source":"model_vgg = models.vgg16_bn(pretrained=True)\n    \nin_features = model_vgg.classifier[6].in_features\nfeatures = list(model_vgg.classifier.children())[:-1] # Remove last layer\nfeatures.extend([nn.Linear(in_features, 120)]) # Add our layer with 120 outputs\nmodel_vgg.classifier = nn.Sequential(*features)\n\n# Setup criterion, optimizer, and learning rate scheduler\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.SGD(model_vgg.parameters(), lr=0.001, momentum=0.9)\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)\n\nif use_cuda:\n    model_vgg = model_vgg.cuda()","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:04:40.258172Z","iopub.execute_input":"2022-01-22T15:04:40.260571Z","iopub.status.idle":"2022-01-22T15:04:42.472459Z","shell.execute_reply.started":"2022-01-22T15:04:40.260530Z","shell.execute_reply":"2022-01-22T15:04:42.471715Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_epoch = 10\n\nmodel_vgg = train(n_epoch, dataloaders, model_vgg, optimizer, criterion, exp_lr_scheduler, use_cuda, 'model_vgg.pt')","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:04:42.473893Z","iopub.execute_input":"2022-01-22T15:04:42.474177Z","iopub.status.idle":"2022-01-22T15:28:14.936288Z","shell.execute_reply.started":"2022-01-22T15:04:42.474133Z","shell.execute_reply":"2022-01-22T15:28:14.935456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_vgg.load_state_dict(torch.load('model_vgg.pt'))\n\nvgg_score_unfreeze = test(dataloaders, model_vgg, optimizer, criterion, use_cuda)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:28:14.938076Z","iopub.execute_input":"2022-01-22T15:28:14.938284Z","iopub.status.idle":"2022-01-22T15:28:23.024989Z","shell.execute_reply.started":"2022-01-22T15:28:14.938256Z","shell.execute_reply":"2022-01-22T15:28:23.023370Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# InceptionV3","metadata":{}},{"cell_type":"markdown","source":"Inception-v3 is a convolutional neural network architecture from the Inception family that makes several improvements including using Label Smoothing, Factorized 7 x 7 convolutions, and the use of an auxiliary classifer to propagate label information lower down the network (along with the use of batch normalization for layers in the sidehead).","metadata":{}},{"cell_type":"markdown","source":"For inceptionV3, we need to modify the train, test, and image transformation\n\nFor the train, and test, we modify that the loss receive ouput.logits as the inception3 outputs has more than logits\n\nFor the image transformation, we resize it into 299x299 for inceptionV3 able to read the input, thus below will re read the input","metadata":{}},{"cell_type":"code","source":"def inception_train(n_epochs, loaders, model, optimizer, criterion, scheduler, use_cuda, save_path):\n    valid_loss_min = np.Inf \n    \n    dataset_sizes = {'train': len(loaders['train'].dataset), \n                     'valid': len(loaders['valid'].dataset),\n                     'test': len(loaders['test'].dataset)}\n    \n    for epoch in range(1, n_epochs+1):\n        train_loss = 0.0\n        train_corrects = 0.0\n        valid_loss = 0.0\n        valid_corrects = 0.0\n        \n        model.train()\n        for batch_idx, (data, target) in enumerate(loaders['train']):\n            if use_cuda:\n                data, target = data.cuda(), target.cuda()\n            \n            optimizer.zero_grad()\n            output = model(data)\n            _, preds = torch.max(output.logits.data, 1)\n            loss = criterion(output.logits, target)\n            loss.backward()\n            optimizer.step()\n            # Record the average training loss\n            train_loss += loss.data\n            train_corrects += torch.sum(preds == target.data)\n            \n            if batch_idx % 100 == 0:\n                print('Epoch: %d \\tBatch: %d \\tTraining Loss: %.6f' %(epoch, batch_idx + 1, train_loss / ((batch_idx + 1) * 12)))\n        \n        train_loss = train_loss / dataset_sizes['train']\n        train_corrects = train_corrects / dataset_sizes['train']\n        \n        scheduler.step()\n\n        model.eval()\n        for batch_idx, (data, target) in enumerate(loaders['valid']):\n            if use_cuda:\n                data, target = data.cuda(), target.cuda()\n                \n            # Update the average validation loss\n            output = model(data)\n            _, preds = torch.max(output.data, 1)\n            loss = criterion(output, target)\n            valid_loss += loss.data\n            valid_corrects += torch.sum(preds == target.data)\n        \n        valid_loss = valid_loss / dataset_sizes['valid']\n        valid_corrects = valid_corrects / dataset_sizes['valid']\n        \n        # Print validation statistics \n        print('Epoch: {} \\tValidation Loss: {:.4f} \\tValidation Acc: {:.4f}'.format(\n            epoch, \n            valid_loss,\n            valid_corrects\n            ))\n        \n        # Save the model if validation loss has decreased\n        if valid_loss < valid_loss_min:\n            torch.save(model.state_dict(), save_path)\n            print('Validation loss decreased ({:.4f} --> {:.4f}).  Saving model...'.format(valid_loss_min,valid_loss))\n            valid_loss_min = valid_loss    \n\n    return model","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:28:23.026719Z","iopub.execute_input":"2022-01-22T15:28:23.027016Z","iopub.status.idle":"2022-01-22T15:28:23.043641Z","shell.execute_reply.started":"2022-01-22T15:28:23.026975Z","shell.execute_reply":"2022-01-22T15:28:23.042878Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def inception_test(loaders, model, optimizer, criterion, use_cuda):\n    test_loss = 0.0\n    test_corrects = 0.0\n    \n    dataset_sizes = {'train': len(loaders['train'].dataset), \n                     'valid': len(loaders['valid'].dataset),\n                     'test': len(loaders['test'].dataset)}\n    \n    model.eval()\n    for batch_idx, (data, target) in enumerate(loaders['test']):\n        if use_cuda:\n            data, target = data.cuda(), target.cuda()\n        # Update the average validation loss\n        output = model(data)\n        _, preds = torch.max(output.data, 1)\n        loss = criterion(output, target)\n        test_loss += loss.data\n        test_corrects += torch.sum(preds == target.data)\n    \n    test_loss = test_loss / dataset_sizes['test']\n    test_corrects = test_corrects / dataset_sizes['test']\n    \n    print('Test Loss: {:.4f} \\tTest Acc: {:.4f}'.format(\n        test_loss,\n        test_corrects\n        ))\n    \n    return test_loss, test_corrects","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:28:23.045381Z","iopub.execute_input":"2022-01-22T15:28:23.046195Z","iopub.status.idle":"2022-01-22T15:28:23.077809Z","shell.execute_reply.started":"2022-01-22T15:28:23.046152Z","shell.execute_reply":"2022-01-22T15:28:23.076874Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"PATH = '../input/dog-breed-identification/'\nlabels = pd.read_csv(PATH + 'labels.csv')\nlabelnames = pd.read_csv(PATH + 'sample_submission.csv').keys()[1:]","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:28:23.079306Z","iopub.execute_input":"2022-01-22T15:28:23.080748Z","iopub.status.idle":"2022-01-22T15:28:23.729071Z","shell.execute_reply.started":"2022-01-22T15:28:23.080673Z","shell.execute_reply":"2022-01-22T15:28:23.728336Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"codes = range(len(labelnames))\nbreed_to_code = dict(zip(labelnames, codes))\ncode_to_breed = dict(zip(codes, labelnames))\nlabels['target'] =  [breed_to_code[x] for x in labels.breed]\nlabels_pivot = labels.pivot('id', 'breed', 'target').reset_index().fillna(0)\n\ntrain = labels_pivot.sample(frac=0.75)\ntemp = labels_pivot[~labels_pivot['id'].isin(train['id'])]\nvalid = temp.sample(frac=0.6)\ntest = temp[~temp['id'].isin(valid['id'])]","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:28:23.730306Z","iopub.execute_input":"2022-01-22T15:28:23.730579Z","iopub.status.idle":"2022-01-22T15:28:23.785526Z","shell.execute_reply.started":"2022-01-22T15:28:23.730543Z","shell.execute_reply":"2022-01-22T15:28:23.784833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Image transformations\nimg_transform = {\n    'train':transforms.Compose([\n        transforms.RandomResizedCrop(size = 299),\n        transforms.RandomRotation(degrees = 30),\n        transforms.ColorJitter(),\n        transforms.RandomHorizontalFlip(),\n        transforms.CenterCrop(size=299),  \n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406],\n                             [0.229, 0.224, 0.225])  \n    ]),\n    'valid':transforms.Compose([\n        transforms.Resize(size = 299),\n        transforms.CenterCrop(size = 299),\n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406],\n                             [0.229, 0.224, 0.225])\n    ]),\n    'test':transforms.Compose([\n        transforms.Resize(size = 299),\n        transforms.CenterCrop(size = 299),\n        transforms.ToTensor(),\n        transforms.Normalize([0.485, 0.456, 0.406],\n                             [0.229, 0.224, 0.225])\n    ]),\n}","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:28:23.786948Z","iopub.execute_input":"2022-01-22T15:28:23.787196Z","iopub.status.idle":"2022-01-22T15:28:23.795404Z","shell.execute_reply.started":"2022-01-22T15:28:23.787164Z","shell.execute_reply":"2022-01-22T15:28:23.794609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DogBreedDataset(torch.utils.data.Dataset):\n    'Characterizes a dataset for PyTorch'\n    def __init__(self, img_dir, label, transform):\n        'Initialization'\n        self.img_dir = img_dir\n        self.transform = transform\n        self.label = label\n\n    def __len__(self):\n        'Denotes the total number of samples'\n        return len(self.label)\n\n    def __getitem__(self, index):\n        if self.label is not None:\n            img_name = '{}.jpg'.format(self.label.iloc[index, 0])\n            fullname = self.img_dir + img_name\n            image = Image.open(fullname)\n            label = self.label.iloc[index, 1:].astype('float').to_numpy()\n            label = np.argmax(label)\n            if self.transform:\n                image = self.transform(image)\n            return [image, label]","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:28:23.797108Z","iopub.execute_input":"2022-01-22T15:28:23.797428Z","iopub.status.idle":"2022-01-22T15:28:23.806780Z","shell.execute_reply.started":"2022-01-22T15:28:23.797391Z","shell.execute_reply":"2022-01-22T15:28:23.805930Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size = 12\nnum_workers = 4\ntrain_img = DogBreedDataset(PATH+'train/', train, transform = img_transform['train'])\nvalid_img = DogBreedDataset(PATH+'train/', valid, transform = img_transform['valid'])\ntest_img = DogBreedDataset(PATH+'train/', test, transform = img_transform['test'])\n\n\ndataloaders={\n    'train':torch.utils.data.DataLoader(train_img, batch_size, num_workers = num_workers, shuffle=True),\n    'valid':torch.utils.data.DataLoader(valid_img, batch_size, num_workers = num_workers, shuffle=False),\n    'test':torch.utils.data.DataLoader(test_img, batch_size, num_workers = num_workers, shuffle=False)\n}\n","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:28:23.809594Z","iopub.execute_input":"2022-01-22T15:28:23.809936Z","iopub.status.idle":"2022-01-22T15:28:23.819657Z","shell.execute_reply.started":"2022-01-22T15:28:23.809882Z","shell.execute_reply":"2022-01-22T15:28:23.818940Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_inception = models.inception_v3(pretrained=True)\n\n# Freeze training for all \"features\" layers\nfor param in model_inception.parameters():\n    param.requires_grad = False\n\n# Setup the last layer net to handle 120 outputs\n# Handle the auxilary net\naux_in_features = model_inception.AuxLogits.fc.in_features\nmodel_inception.AuxLogits.fc = nn.Linear(aux_in_features, 120)\n# Handle the primary net\nin_features = model_inception.fc.in_features\nmodel_inception.fc = nn.Linear(in_features, 120)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.SGD(model_inception.parameters(), lr=0.001, momentum=0.9)\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)\n\nif use_cuda:\n    model_inception = model_inception.cuda()","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:28:23.820864Z","iopub.execute_input":"2022-01-22T15:28:23.821200Z","iopub.status.idle":"2022-01-22T15:28:24.824367Z","shell.execute_reply.started":"2022-01-22T15:28:23.821165Z","shell.execute_reply":"2022-01-22T15:28:24.823640Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Train the InceptionV3 model","metadata":{}},{"cell_type":"code","source":"n_epoch = 10\n\nmodel_inception = inception_train(n_epoch, dataloaders, model_inception, optimizer, criterion, exp_lr_scheduler, use_cuda, 'model_inception.pt')","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:28:24.825751Z","iopub.execute_input":"2022-01-22T15:28:24.826033Z","iopub.status.idle":"2022-01-22T15:40:57.433741Z","shell.execute_reply.started":"2022-01-22T15:28:24.825999Z","shell.execute_reply":"2022-01-22T15:40:57.432052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Test the InceptionV3 model","metadata":{}},{"cell_type":"code","source":"model_inception.load_state_dict(torch.load('model_inception.pt'))\n\ninception_score = inception_test(dataloaders, model_inception, optimizer, criterion, use_cuda)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:40:57.435516Z","iopub.execute_input":"2022-01-22T15:40:57.435774Z","iopub.status.idle":"2022-01-22T15:41:06.021512Z","shell.execute_reply.started":"2022-01-22T15:40:57.435734Z","shell.execute_reply":"2022-01-22T15:41:06.020652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"summary(model_inception, input_size=(3, 299, 299))","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:41:06.023394Z","iopub.execute_input":"2022-01-22T15:41:06.023673Z","iopub.status.idle":"2022-01-22T15:41:06.140118Z","shell.execute_reply.started":"2022-01-22T15:41:06.023631Z","shell.execute_reply":"2022-01-22T15:41:06.139459Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Train the InceptionV3 without freezing the trained layer to see the comparison","metadata":{}},{"cell_type":"code","source":"model_inception = models.inception_v3(pretrained=True)\n\n# Setup the last layer net to handle 120 outputs\n# Handle the auxilary net\naux_in_features = model_inception.AuxLogits.fc.in_features\nmodel_inception.AuxLogits.fc = nn.Linear(aux_in_features, 120)\n# Handle the primary net\nin_features = model_inception.fc.in_features\nmodel_inception.fc = nn.Linear(in_features, 120)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.SGD(model_inception.parameters(), lr=0.001, momentum=0.9)\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)\n\nif use_cuda:\n    model_inception = model_inception.cuda()","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:41:06.141526Z","iopub.execute_input":"2022-01-22T15:41:06.141756Z","iopub.status.idle":"2022-01-22T15:41:06.561463Z","shell.execute_reply.started":"2022-01-22T15:41:06.141724Z","shell.execute_reply":"2022-01-22T15:41:06.560735Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_epoch = 10\n\nmodel_inception = inception_train(n_epoch, dataloaders, model_inception, optimizer, criterion, exp_lr_scheduler, use_cuda, 'model_inception.pt')","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:41:06.562756Z","iopub.execute_input":"2022-01-22T15:41:06.563018Z","iopub.status.idle":"2022-01-22T15:58:48.589509Z","shell.execute_reply.started":"2022-01-22T15:41:06.562986Z","shell.execute_reply":"2022-01-22T15:58:48.588676Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_inception.load_state_dict(torch.load('model_inception.pt'))\n\ninception_score_unfreeze = inception_test(dataloaders, model_inception, optimizer, criterion, use_cuda)","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:58:48.592708Z","iopub.execute_input":"2022-01-22T15:58:48.592956Z","iopub.status.idle":"2022-01-22T15:58:58.026620Z","shell.execute_reply.started":"2022-01-22T15:58:48.592917Z","shell.execute_reply":"2022-01-22T15:58:58.025802Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Summary","metadata":{}},{"cell_type":"code","source":"# print('CNN from scratch Acc: {:.4f}'.format(scratch_score[1]))\nprint('ResNet50 Acc: {:.4f}'.format(resnet_score[1]))\nprint('EfficientNet Acc: {:.4f}'.format(fnet_score[1]))\nprint('VGG16 Acc: {:.4f}'.format(vgg_score[1]))\nprint('Inception Acc: {:.4f}'.format(inception_score[1]))\n\n# print('CNN from scratch Loss: {:.4f}'.format(scratch_score[0]))\nprint('ResNet50 Loss: {:.4f}'.format(resnet_score[0]))\nprint('EfficientNet Loss: {:.4f}'.format(fnet_score[0]))\nprint('VGG16 Loss: {:.4f}'.format(vgg_score[0]))\nprint('Inception Loss: {:.4f}'.format(inception_score[0]))","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:58:58.030846Z","iopub.execute_input":"2022-01-22T15:58:58.031449Z","iopub.status.idle":"2022-01-22T15:58:58.046365Z","shell.execute_reply.started":"2022-01-22T15:58:58.031378Z","shell.execute_reply":"2022-01-22T15:58:58.045568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_df = pd.DataFrame(data=[[\"ResNet50\", float(format(resnet_score[1]))]], \n                          columns=['Model', 'Accuracy'])\n\ntemp_df = pd.DataFrame(data=[[\"ResNet50 Unfreeze\", float(format(resnet_score_unfreeze[1]))]], \n                          columns=['Model', 'Accuracy'])\nmodel_df = model_df.append(temp_df, ignore_index=True)\n\ntemp_df = pd.DataFrame(data=[[\"EfficientNet\", float(format(fnet_score[1]))]], \n                          columns=['Model', 'Accuracy'])\nmodel_df = model_df.append(temp_df, ignore_index=True)\n\ntemp_df = pd.DataFrame(data=[[\"EfficientNet Unfreeze\", float(format(fnet_score_unfreeze[1]))]], \n                          columns=['Model', 'Accuracy'])\nmodel_df = model_df.append(temp_df, ignore_index=True)\n\ntemp_df = pd.DataFrame(data=[[\"VGG16\", float(format(vgg_score[1]))]], \n                          columns=['Model', 'Accuracy'])\nmodel_df = model_df.append(temp_df, ignore_index=True)\n\ntemp_df = pd.DataFrame(data=[[\"VGG16 Unfreeze\", float(format(vgg_score_unfreeze[1]))]], \n                          columns=['Model', 'Accuracy'])\nmodel_df = model_df.append(temp_df, ignore_index=True)\n\ntemp_df = pd.DataFrame(data=[[\"InceptionV3\", float(format(inception_score[1]))]], \n                          columns=['Model', 'Accuracy'])\nmodel_df = model_df.append(temp_df, ignore_index=True)\n\ntemp_df = pd.DataFrame(data=[[\"InceptionV3 Unfreeze\", float(format(inception_score_unfreeze[1]))]], \n                          columns=['Model', 'Accuracy'])\nmodel_df = model_df.append(temp_df, ignore_index=True)\n\nmodel_df","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:58:58.051578Z","iopub.execute_input":"2022-01-22T15:58:58.052052Z","iopub.status.idle":"2022-01-22T15:58:58.090529Z","shell.execute_reply.started":"2022-01-22T15:58:58.051983Z","shell.execute_reply":"2022-01-22T15:58:58.089885Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_df.set_index('Model', inplace=True)\nmodel_df['Accuracy'].plot(kind='barh', figsize=(12, 8))","metadata":{"execution":{"iopub.status.busy":"2022-01-22T15:58:58.092457Z","iopub.execute_input":"2022-01-22T15:58:58.092653Z","iopub.status.idle":"2022-01-22T15:58:58.337486Z","shell.execute_reply.started":"2022-01-22T15:58:58.092628Z","shell.execute_reply":"2022-01-22T15:58:58.336784Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The InceptionV3 model successfully become the top 1 which predict 120 breeds with 85.4% accuracy. \n\nFollowed by EfficientNet with 85.7% accuracy, Resnet with 82.7% accuracy, and VGG16 with 80.0% accuracy.\n\nAnd the unfreeze version is slightly weaker than the freeze trained layer, possibly of overfitting as can be seen that in the first 3 epoch, the unfreeze is better but after some high amount of epoch, it's weaker ~1 to 2 percent","metadata":{}}]}