{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"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 in \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 \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport copy\nimport os\nprint(os.listdir(\"../input\"))\n\nfrom tqdm import tnrange, tqdm_notebook as tqdm\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"%matplotlib inline\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"603d932eb2b8777e7fec931c4d57e8efd0702be5"},"cell_type":"code","source":"TRAIN_PATH = \"../input/train/\"\ntrain_files = list(os.listdir(TRAIN_PATH))[100:]\nf = TRAIN_PATH+train_files[1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dee8362587bd2c3c795a121134c0ee6f03941563"},"cell_type":"code","source":"im = mpimg.imread(f); im.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a10c7a230ffe5d649a01c96c3fc173f888227fd4"},"cell_type":"code","source":"plt.imshow(im)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7841d16e1072fa2f827f6716cdfaae4cf4ce032b"},"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision\nimport torchvision.transforms as transforms","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fb31e803d1d9a3d5034890023357322ca5db698a"},"cell_type":"code","source":"trainalldf = pd.read_csv(\"../input/train.csv\") #, nrows=100)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2d0dc843183ef3ee997bba5d02b5eff531c97542"},"cell_type":"code","source":"trainalldf.count()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"92be9088b64854f9f321b7170f1a275b104112d5"},"cell_type":"code","source":"whaleids = sorted(list(trainalldf['Id'].drop_duplicates()))\nprint(whaleids[:5]); print(len(whaleids))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1207db1ddf0a693cd979041153a15e9c9e61083e"},"cell_type":"code","source":"whaleids_dict = dict((k,v) for v,k in enumerate(whaleids))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"963bc825cc59193b0621d330269e78fbbedacc4d"},"cell_type":"markdown","source":"## Cut resnet into new model"},{"metadata":{"trusted":true,"_uuid":"5eafd4486f8dab1c8ba8d04db3940eec03798386"},"cell_type":"code","source":"BS = 32\nimage_input_size = 224\nresnet18 = torchvision.models.resnet18(pretrained=True)\nfor p in resnet18.parameters():\n    p.requires_grad = False # Freeze all existing layers","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a4123f32dee954add4f586cbace6fd8319222f5c"},"cell_type":"code","source":"#model = nn.Sequential(*list(resnet18.children())[:-1], nn.Linear(512, len(whaleids)))\nresnet18.fc = nn.Linear(512, len(whaleids))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"99fd9758ca0b8019b3a29f4ec90e077f27ff33f5"},"cell_type":"code","source":"resnet18.to('cuda')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"533b97d3ee9500512f4227b68aed25d1d4af1d89"},"cell_type":"code","source":"norm = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\ninv_normalize = transforms.Normalize(\n    mean=[-0.485/0.229, -0.456/0.224, -0.406/0.255],\n    std=[1/0.229, 1/0.224, 1/0.255]\n)\n\ntransforms_dict = {\n    'train': transforms.Compose([transforms.RandomResizedCrop(image_input_size),\n                                 transforms.RandomHorizontalFlip(),\n                                 transforms.ToTensor(),\n                                 norm]),\n    'val': transforms.Compose([transforms.Resize(image_input_size),\n                                 transforms.CenterCrop(image_input_size),\n                                 transforms.ToTensor(),\n                                 norm])\n}\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2fdbe11abe9676467846a58a810f48b3a2ae56b0"},"cell_type":"code","source":"class WhaleImageDataset(torchvision.datasets.folder.ImageFolder):\n    def __init__(self, ROOT_PATH, tfm, images, targets=None):\n        self.ROOT_PATH = ROOT_PATH\n        self.images = images\n        self.targets = targets\n        self.trans = tfm\n        self.loader = torchvision.datasets.folder.default_loader\n    \n    def __getitem__(self, index):\n        f = self.ROOT_PATH + self.images[index]\n        im = self.loader(f)\n        if self.targets is None: # Test mode has no targets\n            return self.trans(im)\n        return self.trans(im), self.targets[index]\n    \n    def __len__(self):\n        return len(self.images)\n    ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fbf2004e9d4803937789ee235973532d0e99ae72"},"cell_type":"markdown","source":"## Split data into train/val"},{"metadata":{"trusted":true,"_uuid":"f1b77df2586d10f33b8aeef60813003c3e69e6ea"},"cell_type":"code","source":"trainallimages = trainalldf['Image'].values\ntrainallids = trainalldf['Id'].values\ntrainallclasses = np.array([whaleids_dict[id] for id in trainallids])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c8e03f7cf0b5ef900ed209359f027f02914ce20c"},"cell_type":"code","source":"from sklearn.model_selection import ShuffleSplit","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d043f478eb677e4d536141c6cfe8809d9f260a4e"},"cell_type":"code","source":"splitter = ShuffleSplit(n_splits=1, test_size=0.1)\n(train_idxs, val_idxs) = next(splitter.split(trainallimages, trainallclasses))\nidxs = {'train': train_idxs, 'val': val_idxs}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6f53360f95e9743eb33382492017c43dc52b20c6"},"cell_type":"code","source":"#train_images, train_classes = trainallimages[train_idxs], trainallclasses[train_idxs]\n#val_images, val_classes = trainallimages[val_idxs], trainallclasses[val_idxs]\nimages_dict = {phase: trainallimages[idxs[phase]] for phase in ['train', 'val']}\nclasses_dict = {phase: trainallclasses[idxs[phase]] for phase in ['train', 'val']}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c410aa93993a939fa5b203fd0d9be5792eba4211"},"cell_type":"code","source":"datasets_dict = {phase: WhaleImageDataset(TRAIN_PATH, transforms_dict[phase], images_dict[phase], classes_dict[phase]) for phase in ['train','val']}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"fc28c9cce5e6c86921b8eb16a6685c9b39eea975"},"cell_type":"code","source":"im, c = datasets_dict['train'][1]\nprint(im.shape)\nim = im.permute(1,2,0)\nim2 = inv_normalize(im)\nprint(im2.shape)\nplt.imshow(im2)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"68c8ad0704de7a9df16e5305b6b8469e64d625d6"},"cell_type":"code","source":"#train_dl = torch.utils.data.DataLoader(train_image_dataset, batch_size=BS, shuffle=True, num_workers=4)\n#val_dl = torch.utils.data.DataLoader(val_image_dataset, batch_size=BS, shuffle=True, num_workers=4)\ndataloaders_dict = {phase: torch.utils.data.DataLoader(datasets_dict[phase], batch_size=BS, shuffle=True, num_workers=1, pin_memory=True) \n                    for phase in ['train', 'val']}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d0bd3f75b8b4b4cf5fcebe6ea31ad6f766dfe144"},"cell_type":"code","source":"#X_batch, y_batch = next(iter(dataloaders_dict['train']))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6f093b06d6454686e2acb5f18514f35b44d938f6"},"cell_type":"markdown","source":"## Set up optimiser"},{"metadata":{"trusted":true,"_uuid":"94411711dc4c74bceb36936bb5ec2179c01ad87e"},"cell_type":"code","source":"opt = torch.optim.SGD(resnet18.fc.parameters(), lr=0.001, momentum=0.9)\ncrit = nn.CrossEntropyLoss()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"905cecbd589155fbb225c19f0d1c57d10c524874"},"cell_type":"code","source":"NUM_EPOCHS = 30\n\nval_acc_history = []\n\nbest_model_wts = copy.deepcopy(resnet18.state_dict())\nbest_acc = 0.0\n\nfor epoch in range(NUM_EPOCHS):\n    print('Epoch {}/{}'.format(epoch, NUM_EPOCHS - 1))\n    print('-' * 10)\n    \n    for phase in ['train', 'val']:\n        if phase == 'train':\n            resnet18.train()\n        else:\n            resnet18.eval()\n        \n        running_loss = 0.0\n        running_corrects = 0\n            \n        for X_batch, y_batch in dataloaders_dict[phase]:\n            X_batch = X_batch.to('cuda')\n            y_batch = y_batch.to('cuda')\n            \n            opt.zero_grad()\n            \n            outputs = resnet18(X_batch)\n            \n            loss = crit(outputs, y_batch)\n            \n            _, preds = torch.max(outputs, 1)\n            \n            if phase == 'train':\n                loss.backward()\n                opt.step()\n                \n            running_loss += loss.item() * X_batch.size(0)\n            running_corrects += torch.sum(preds == y_batch.data)\n            \n        epoch_loss = running_loss / len(dataloaders_dict[phase].dataset)\n        epoch_acc = running_corrects.double() / len(dataloaders_dict[phase].dataset)\n        \n        if phase == 'val' and epoch_acc > best_acc:\n            best_acc = epoch_acc\n            best_model_wts = copy.deepcopy(resnet18.state_dict())\n        if phase == 'val':\n            val_acc_history.append(epoch_acc)\n        \n        print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))     \n\n    print('\\n')\n    \nprint('Best acc: {:.4f}'.format(best_acc))\nresnet18.load_state_dict(best_model_wts)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a0733d8719dbfdbdc9e04fb216ae3e0846b1e3a4"},"cell_type":"code","source":"torch.save(resnet18.state_dict(), './resnet18.model')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a35277b4ac165dbe21d96235ed95c4c9db96a315"},"cell_type":"code","source":"resnet18.load_state_dict(torch.load('./resnet18.model'))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9452280e06096d0eff0091b805cf4e4eb3be9110"},"cell_type":"markdown","source":"## Calc metrics"},{"metadata":{"trusted":true,"_uuid":"8720946e81507b77d2256d9c8d138a5cca8d4010"},"cell_type":"code","source":"def avprec_cutoff(inds, targets, N=5, m=1):\n    rels = (inds.numpy() == targets.numpy()).astype('int')\n    pks = []\n    for ki in range(1,N+1):\n        pk = rels[:,0:ki].sum(axis=1).reshape(-1,1)/ki\n        pks.append(pk/m)\n\n    return (np.concatenate(pks, axis=1) * rels).sum(axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c9b86b3d48f3ee6e450fc12b4b565b57f6746424"},"cell_type":"code","source":"npwhaleids = np.array(whaleids)\ngap_num = 0.0\ngap_count = 0\n\nfor x_batch, y_batch in tqdm(dataloaders_dict['val']):\n    x_batch = x_batch.to('cuda')\n    outputs = resnet18(x_batch)\n    predinds = torch.argsort(outputs, dim=1, descending=True)[:,:5]\n    \n    gap_num += avprec_cutoff(predinds.to('cpu'), y_batch.view(-1,1), 5,1).sum()\n\n    gap_count += y_batch.shape[0]\n\nprint(gap_num/gap_count)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cab6adae384b55a750d7a0f6b00797cef08f03cf"},"cell_type":"markdown","source":"## Apply to test set"},{"metadata":{"trusted":true,"_uuid":"3b96da9b3be7639068fda2bbb153c08c12db9b37"},"cell_type":"code","source":"resnet18.eval()\nTEST_PATH = \"../input/test/\"\nimages_test = list(os.listdir(TEST_PATH))\ndataset_test = WhaleImageDataset(TEST_PATH, transforms_dict['val'], images_test)\ndataloader_test = torch.utils.data.DataLoader(dataset_test, batch_size=BS, shuffle=False, num_workers=1, pin_memory=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"476fde53ea9acfd38a43e0724170b0c68f1b1572"},"cell_type":"code","source":"npwhaleids = np.array(whaleids)\ntest_classnames = []\nfor test_batch in tqdm(dataloader_test):\n    test_batch = test_batch.to('cuda')\n    outputs = resnet18(test_batch)\n    predinds = torch.argsort(outputs, dim=1, descending=True)[:,:5]\n    \n    whalestrs = npwhaleids[predinds.to('cpu').detach().numpy()].tolist()\n    \n    test_classnames.extend([\" \".join(s) for s in whalestrs])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ed287cb49404432611b2d3b0ba07c34f7fd3348d"},"cell_type":"code","source":"testdf = pd.DataFrame({'Image': images_test, 'Id': test_classnames})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"86fa4c70c6f072b7b40b47eef79359d59032864a"},"cell_type":"code","source":"testdf.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6d5d9dd4808a69e9999dd901b9594aa0559dfb00"},"cell_type":"code","source":"from IPython.display import FileLink\nFileLink('submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d052ef92ae76340a101de2739d577034031b447c"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}