{"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":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n#for dirname, _, filenames in os.walk('/kaggle/input'):\n #   for filename in filenames:\n  #      print(os.path.join(dirname, filename))\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom PIL import Image\nimport torch\nfrom torch.utils.data import Dataset, DataLoader, SubsetRandomSampler\nimport torchvision.models as models\nimport torch.nn as nn\nimport torchvision.transforms as transforms\nimport torch.optim as optim","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CreateDataset(Dataset):\n    \n    def __init__(self, img_dir, dataframe, transform=None):\n        self.labels_frame = dataframe\n        self.img_dir = img_dir\n        self.transform = transform\n        \n    def __len__(self):\n        return len(self.labels_frame)\n    \n    def __getitem__(self, idx):\n        img_name = os.path.join(self.img_dir, self.labels_frame.id[idx]) + \".jpg\"\n        image = Image.open(img_name)\n        label = self.labels_frame.target[idx]\n        \n        if self.transform:\n            image = self.transform(image)\n        \n        return [image, label]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Read labels file\ndataframe = pd.read_csv('/kaggle/input/dog-breed-identification/labels.csv')\n\nlabel_names = pd.read_csv('/kaggle/input/dog-breed-identification/sample_submission.csv')\n\ntest_frame = pd.DataFrame(data=label_names['id'])\ntest_frame['target'] = label_names['id']\n\nlabels = dataframe['breed']\n\nsubmission_file = pd.DataFrame(index=label_names.index, columns=label_names.keys())\nsubmission_file['id'] = label_names['id']\n\nlabel_names.drop(['id'], axis=1, inplace=True)\n\ncode = range(len(label_names))\n\nbreed_to_code = dict(zip(label_names, code))\n\ncode_to_breed = dict(zip(code, label_names))\n\ndataframe['target'] =  [breed_to_code[x] for x in dataframe.breed]\n\ntrain_dir = '/kaggle/input/dog-breed-identification/train'\ntest_dir = '/kaggle/input/dog-breed-identification/test'\n\ntrain_transform = transforms.Compose([transforms.Resize((256,256)),\n                                      transforms.CenterCrop(224),\n                                transforms.RandomHorizontalFlip(),\n                                transforms.RandomRotation(5),\n                                        transforms.ToTensor(),\n                                         transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                                 std=[0.229, 0.224, 0.225])])\n\ntrain_data = CreateDataset(train_dir, dataframe, train_transform)\n\ntest_transform = transforms.Compose([transforms.Resize((256,256)),\n                                    transforms.CenterCrop(224),\n                                    transforms.ToTensor(),\n                                    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                                                         std=[0.229, 0.224, 0.225])])\n\ntest_data = CreateDataset(test_dir, test_frame, test_transform)\n\nplt.imshow(train_data[10][0][0])\nprint(code_to_breed[train_data[10][1]])\n\nprint(train_data[11][1])","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Specify data loaders\n\nbatch_size = 64\nnum_workers = 0\n    \n# obtain training indices that will be used for validation\nvalid_size = 0.2\nnum_train = len(train_data)\nindices = list(range(num_train))\nnp.random.shuffle(indices)\nsplit = int(np.floor(valid_size * num_train))\ntrain_idx, valid_idx = indices[split:], indices[:split]\n\n# define samplers for obtaining training and validation batches\ntrain_sampler = SubsetRandomSampler(train_idx)\nvalid_sampler = SubsetRandomSampler(valid_idx)\n\ntrain_loader = DataLoader(train_data, batch_size=batch_size, sampler=train_sampler, num_workers=num_workers)\ntest_loader = DataLoader(test_data, batch_size=1, num_workers=num_workers)\nvalid_loader = DataLoader(train_data, batch_size=batch_size, sampler=valid_sampler, num_workers=num_workers)\nloaders_transfer = {'train':train_loader,'test':test_loader,'valid':valid_loader}","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# check if CUDA is available\nuse_cuda = torch.cuda.is_available()\n\n# Specify model architecture \nmodel_transfer = models.vgg16(pretrained=True)\n\n# Freeze training for all \"features\" layers\nfor param in model_transfer.features.parameters():\n    param.requires_grad = False\n    \nmodel_transfer.classifier[6] = torch.nn.Linear(model_transfer.classifier[6].in_features,120)\n\nif use_cuda:\n    model_transfer = model_transfer.cuda()\n    \ncriterion_transfer = torch.nn.CrossEntropyLoss()\noptimizer_transfer = optim.SGD(model_transfer.classifier.parameters(),lr=0.001)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train(n_epochs, loaders, model, optimizer, criterion, use_cuda, save_path):\n    \"\"\"returns trained model\"\"\"\n    # initialize tracker for minimum validation loss\n    valid_loss_min = np.Inf \n    \n    for epoch in range(1, n_epochs+1):\n        # initialize variables to monitor training and validation loss\n        train_loss = 0.0\n        valid_loss = 0.0\n        \n        ###################\n        # train the model #\n        ###################\n        model.train()\n        for batch_idx, (data, target) in enumerate(loaders['train']):\n            # move to GPU\n            if use_cuda:\n                data, target = data.cuda(), target.cuda()\n            ## find the loss and update the model parameters accordingly\n            ## record the average training loss, using something like\n            ## train_loss = train_loss + ((1 / (batch_idx + 1)) * (loss.data - train_loss))\n            optimizer.zero_grad()\n            output = model(data)\n            loss = criterion(output,target)\n            \n            loss.backward()\n            optimizer.step()\n            train_loss += ((1 / (batch_idx + 1)) * (loss.data - train_loss))\n        ######################    \n        # validate the model #\n        ######################\n        model.eval()\n        for batch_idx, (data, target) in enumerate(loaders['valid']):\n            # move to GPU\n            if use_cuda:\n                data, target = data.cuda(), target.cuda()\n            ## update the average validation loss\n            output = model(data)\n            loss = criterion(output,target)\n            valid_loss += ((1 / (batch_idx + 1)) * (loss.data - valid_loss))\n\n        \n        # print training/validation statistics \n        print('Epoch: {} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f}'.format(\n            epoch, \n            train_loss,\n            valid_loss\n            ))\n        \n        ## Save the model if validation loss has decreased\n        if valid_loss <= valid_loss_min:\n            print('Validation loss decreased ({:.6f} --> {:.6f}). Saving model...'.format(\n            valid_loss_min,valid_loss))\n            torch.save(model.state_dict(),save_path)\n            valid_loss_min = valid_loss\n    # return trained model\n    return model","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train the model\n\nn_epochs = 40\n\nmodel_transfer = train(n_epochs, loaders_transfer, model_transfer, optimizer_transfer, criterion_transfer, use_cuda,'model_transfer.pt')\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def test(loaders, model, submission, use_cuda):\n    model.eval()\n    for index, (data, _) in enumerate(loaders['test']):\n        # move to GPU\n        if use_cuda:\n            data = data.cuda()\n        # forward pass: compute predicted outputs by passing inputs to the model\n        output = model(data)\n        output = nn.functional.softmax(output)\n        output = np.squeeze(output).cpu().detach().numpy()\n        submission.iloc[index, 1:121] = output","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if use_cuda:\n    model_transfer.load_state_dict(torch.load('./model_transfer.pt'))\nelse:\n    model_transfer.load_state_dict(torch.load('./model_transfer.pt', map_location=lambda storage, loc: storage))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test(loaders_transfer, model_transfer, submission_file, use_cuda)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_file.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}