{"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":"markdown","source":"In this notebook, we perform below steps to understand the modeling challenges\n1. Create custom data loader. \n    \n    This is required to read id from train.csv and then load the image, transform it. We also re-do the class labels, as class id is greater than number of unique classes\n\n2. Custom function to visulaize images of one batch\n3. Function to create pre-trained model\n4. Training loop\n\nDue to huge amount of data, its difficult to complete training for one epoch. We probably need some data cleaning to reduce the number of images being sent to training","metadata":{}},{"cell_type":"code","source":"!pip install torchsummary","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:12.108524Z","iopub.execute_input":"2021-08-15T12:10:12.109106Z","iopub.status.idle":"2021-08-15T12:10:19.704332Z","shell.execute_reply.started":"2021-08-15T12:10:12.108981Z","shell.execute_reply":"2021-08-15T12:10:19.703275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport random\nimport math\n\nimport os\nimport tqdm\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\nimport seaborn as sns\n\nfrom IPython.display import display\n\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.utils.data.sampler import SubsetRandomSampler\nimport torch.nn as nn\nimport torch.optim as optim\nimport torchvision.transforms as transforms\nfrom torchvision.models import vgg19\n\nfrom torchsummary import summary\n\nfrom pathlib import Path\nimport PIL\nfrom PIL import Image\n\n\n\n","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:19.706437Z","iopub.execute_input":"2021-08-15T12:10:19.706877Z","iopub.status.idle":"2021-08-15T12:10:21.438497Z","shell.execute_reply.started":"2021-08-15T12:10:19.706817Z","shell.execute_reply":"2021-08-15T12:10:21.437590Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def seed_all(seed):\n    \"\"\"Utility function to set seed across all pytorch process for repeatable experiment\n    \"\"\"\n    if not seed:\n        seed = 10\n\n    print(\"[ Using Seed : \", seed, \" ]\")\n\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n    torch.cuda.manual_seed(seed)\n    np.random.seed(seed)\n    random.seed(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n\nseed_all(100)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:21.440408Z","iopub.execute_input":"2021-08-15T12:10:21.440763Z","iopub.status.idle":"2021-08-15T12:10:21.456290Z","shell.execute_reply.started":"2021-08-15T12:10:21.440723Z","shell.execute_reply":"2021-08-15T12:10:21.455330Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def seed_worker(worker_id):\n    \"\"\"Utility function to set random seed for DataLoader\n    \"\"\"\n    worker_seed = torch.initial_seed() % 2**32\n    numpy.random.seed(worker_seed)\n    random.seed(worker_seed)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:21.458235Z","iopub.execute_input":"2021-08-15T12:10:21.458636Z","iopub.status.idle":"2021-08-15T12:10:21.463924Z","shell.execute_reply.started":"2021-08-15T12:10:21.458596Z","shell.execute_reply":"2021-08-15T12:10:21.462789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_dir = Path(\"../input/landmark-recognition-2021/\")\ntrain_dir = data_dir / \"train\"\ntest_dir = data_dir / \"test\"\ntrain_file = data_dir / \"train.csv\"\nsub_file = data_dir / \"sample_submission.csv\"","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:21.465479Z","iopub.execute_input":"2021-08-15T12:10:21.466092Z","iopub.status.idle":"2021-08-15T12:10:21.473003Z","shell.execute_reply.started":"2021-08-15T12:10:21.466054Z","shell.execute_reply":"2021-08-15T12:10:21.471715Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv(train_file)\nsub_df = pd.read_csv(sub_file)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:21.474512Z","iopub.execute_input":"2021-08-15T12:10:21.474955Z","iopub.status.idle":"2021-08-15T12:10:22.899935Z","shell.execute_reply.started":"2021-08-15T12:10:21.474916Z","shell.execute_reply":"2021-08-15T12:10:22.899029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display(train_df.head())\ndisplay(sub_df.head())","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:22.901178Z","iopub.execute_input":"2021-08-15T12:10:22.901551Z","iopub.status.idle":"2021-08-15T12:10:22.927148Z","shell.execute_reply.started":"2021-08-15T12:10:22.901514Z","shell.execute_reply":"2021-08-15T12:10:22.926233Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## landmark_id value > number of classes, this leads to error during training pytorch model\nlandmark_id_map = {lid:i for i, lid in enumerate(train_df.landmark_id.unique())}\ntrain_df['landmark_id'] = train_df['landmark_id'].map(landmark_id_map)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:22.930457Z","iopub.execute_input":"2021-08-15T12:10:22.930850Z","iopub.status.idle":"2021-08-15T12:10:23.088260Z","shell.execute_reply.started":"2021-08-15T12:10:22.930815Z","shell.execute_reply":"2021-08-15T12:10:23.087338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Building a custom data loader to load the data in batches for pytorch\n\nclass LandMarkData(Dataset):\n    \n    def __init__(self, data_file, data_dir, transform=None, data_type=\"train\"):\n        \"\"\"\n        data_file str: file which contains image_id and its class\n        data_dir str: directory where data is present\n        \"\"\"\n        \n        self.data_file = pd.read_csv(data_file)\n        ## landmark_id value > number of classes, this leads to error during training pytorch model\n        if data_type == \"train\":\n            self.landmark_id_map = {lid:i for i, lid in enumerate(self.data_file.landmark_id.unique())}\n            self.data_file['landmark_id'] = self.data_file['landmark_id'].map(self.landmark_id_map)\n        elif data_type == \"test\":\n            print(\"Test data will not have landmarkd id, hence no mapping\")\n        self.data_dir = data_dir\n        self.transform = transform\n    \n    def __len__(self):\n        return len(self.data_file)\n    \n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n        img_id = self.data_file.iloc[idx, 0]\n        img_class = self.data_file.iloc[idx, 1]\n        img_path = os.path.join(self.data_dir, img_id[0], img_id[1], img_id[2], f'{img_id}.jpg')\n        img = Image.open(img_path)\n        if self.transform is not None:\n            img = transform(img)\n        sample = [img, img_class, img_id]\n        \n        return sample","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:23.090451Z","iopub.execute_input":"2021-08-15T12:10:23.090960Z","iopub.status.idle":"2021-08-15T12:10:23.101660Z","shell.execute_reply.started":"2021-08-15T12:10:23.090916Z","shell.execute_reply":"2021-08-15T12:10:23.100535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## define basic transforms\n\ntransform = transforms.Compose([ transforms.CenterCrop(224), \n                               transforms.ToTensor()])","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:23.103541Z","iopub.execute_input":"2021-08-15T12:10:23.104494Z","iopub.status.idle":"2021-08-15T12:10:23.115391Z","shell.execute_reply.started":"2021-08-15T12:10:23.104438Z","shell.execute_reply":"2021-08-15T12:10:23.114323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data = LandMarkData(train_file, train_dir, transform, \"train\")\ntest_data = LandMarkData(sub_file, test_dir, transform, \"test\")","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:23.116756Z","iopub.execute_input":"2021-08-15T12:10:23.117112Z","iopub.status.idle":"2021-08-15T12:10:24.279193Z","shell.execute_reply.started":"2021-08-15T12:10:23.117073Z","shell.execute_reply":"2021-08-15T12:10:24.278004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Manually Checking if dataloader and transforms are getting applied or not.\n## All images should be 224*224\nprint(f\"Image Shape               || Image Class|| Image Id\")\nprint(\"-\"*60)\nsamples = train_df['id'].sample(10, random_state=100).index\nfor sample in samples:\n    img_sample = train_data[sample]\n    print(f\"{img_sample[0].shape} || {img_sample[1]}      || {img_sample[2]}\")","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:24.280667Z","iopub.execute_input":"2021-08-15T12:10:24.281065Z","iopub.status.idle":"2021-08-15T12:10:24.479541Z","shell.execute_reply.started":"2021-08-15T12:10:24.281019Z","shell.execute_reply":"2021-08-15T12:10:24.478640Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Manually Checking if dataloader and transforms are getting applied or not.\n## All images should be 224*224\nprint(f\"Image Shape               || Image Class|| Image Id\")\nprint(\"-\"*60)\nsamples = sub_df['id'].sample(10, random_state=100).index\nfor sample in samples:\n    img_sample = test_data[sample]\n    print(f\"{img_sample[0].shape} || {img_sample[1]} || {img_sample[2]}\")","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:24.482635Z","iopub.execute_input":"2021-08-15T12:10:24.482965Z","iopub.status.idle":"2021-08-15T12:10:24.584528Z","shell.execute_reply.started":"2021-08-15T12:10:24.482934Z","shell.execute_reply":"2021-08-15T12:10:24.582525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Taking 20% as valid data\nvalid_size = 0.2\nbatch_size = 8","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:24.585843Z","iopub.execute_input":"2021-08-15T12:10:24.586247Z","iopub.status.idle":"2021-08-15T12:10:24.591090Z","shell.execute_reply.started":"2021-08-15T12:10:24.586206Z","shell.execute_reply":"2021-08-15T12:10:24.590018Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Splitting train data into valid data. Please note this is vanila split, \n# we need to have better split or agumentation as many landmarks have very few images\nnum_train = len(train_data)\nindices = list(range(num_train))\nnp.random.seed(100)\nnp.random.shuffle(indices)\nsplit = int(np.floor(num_train*valid_size))\nvalid_idx, train_idx = indices[:split], indices[split:]\nassert len(valid_idx) + len(train_idx) == num_train","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:24.592929Z","iopub.execute_input":"2021-08-15T12:10:24.593495Z","iopub.status.idle":"2021-08-15T12:10:25.014778Z","shell.execute_reply.started":"2021-08-15T12:10:24.593453Z","shell.execute_reply":"2021-08-15T12:10:25.013800Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_sampler = SubsetRandomSampler(train_idx)\nvalid_sampler = SubsetRandomSampler(valid_idx)\ntrain_loader = DataLoader(train_data, batch_size=batch_size, sampler=train_sampler, num_workers=0, worker_init_fn=seed_worker)\nvalid_loader = DataLoader(train_data, batch_size=batch_size, sampler=valid_sampler, num_workers=0, worker_init_fn=seed_worker)\ntest_loader = DataLoader(test_data, batch_size=batch_size, num_workers=0, worker_init_fn=seed_worker)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:25.016102Z","iopub.execute_input":"2021-08-15T12:10:25.016488Z","iopub.status.idle":"2021-08-15T12:10:25.027610Z","shell.execute_reply.started":"2021-08-15T12:10:25.016451Z","shell.execute_reply":"2021-08-15T12:10:25.026518Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_images(loader, num_images=5):\n    images, label, img_id = next(iter(loader))\n    # convert to numpy and transpose as (Batch Size, Height, Width, Channel) as needed by matplotlib\n    images = images.numpy().transpose(0, 2, 3, 1)\n    \n    # Analysing images of a train batch\n    num_cols = 5\n    num_rows = 1\n    if num_images > 5:\n        num_cols = 5\n        num_rows = math.ceil(num_images / 5)\n    np.random.seed(100)\n    indices = np.random.choice(range(len(label)), size=num_images, replace=False)\n    width = 20\n    height = 5*num_rows\n    plt.figure(figsize=(width, height))\n    for i, idx in enumerate(indices):\n        plt.subplot(num_rows, num_cols, i + 1)\n        image = images[idx]\n        plt.imshow(image);\n        plt.title(f'label: {label[idx]}\\n img_id: {img_id[idx]}');\n        plt.axis(\"off\")\n    plt.show()\n","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:25.030232Z","iopub.execute_input":"2021-08-15T12:10:25.031103Z","iopub.status.idle":"2021-08-15T12:10:25.161808Z","shell.execute_reply.started":"2021-08-15T12:10:25.031057Z","shell.execute_reply":"2021-08-15T12:10:25.160469Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#plotting one batch of images from train\nplot_images(train_loader, batch_size)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:25.163510Z","iopub.execute_input":"2021-08-15T12:10:25.164027Z","iopub.status.idle":"2021-08-15T12:10:30.958882Z","shell.execute_reply.started":"2021-08-15T12:10:25.163981Z","shell.execute_reply":"2021-08-15T12:10:30.957861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#plotting one batch images from valid\nplot_images(valid_loader, batch_size)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:30.960134Z","iopub.execute_input":"2021-08-15T12:10:30.960531Z","iopub.status.idle":"2021-08-15T12:10:32.744440Z","shell.execute_reply.started":"2021-08-15T12:10:30.960493Z","shell.execute_reply":"2021-08-15T12:10:32.743270Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_images(test_loader, batch_size)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:32.746033Z","iopub.execute_input":"2021-08-15T12:10:32.746509Z","iopub.status.idle":"2021-08-15T12:10:33.729360Z","shell.execute_reply.started":"2021-08-15T12:10:32.746467Z","shell.execute_reply":"2021-08-15T12:10:33.728230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Post plotting images from test set, where out of 8 images probably 4 are for landmark and rest are human faces and fish, this shows that lot of images in test data are out of sample. Hence, even before we predict on test set, we need to run some similarity check and not predict for out of sample images","metadata":{}},{"cell_type":"code","source":"def get_pretrained_model(model_name=vgg19, num_class=10, use_gpu=False):\n    \"\"\" Wrapper function to get pre-trained model \n    \"\"\"\n    model_transfer = model_name(pretrained=True)\n    for params in model_transfer.features.parameters():\n        params.requires_grad=False\n\n    in_features = model_transfer.classifier[6].in_features\n    last_layer = nn.Linear(in_features, num_class)\n    model_transfer.classifier[6] = last_layer\n    if use_gpu:\n        model_transfer.cuda()\n    return model_transfer","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:33.731463Z","iopub.execute_input":"2021-08-15T12:10:33.731890Z","iopub.status.idle":"2021-08-15T12:10:33.739589Z","shell.execute_reply.started":"2021-08-15T12:10:33.731801Z","shell.execute_reply":"2021-08-15T12:10:33.738414Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"use_cuda = torch.cuda.is_available()","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:33.741528Z","iopub.execute_input":"2021-08-15T12:10:33.741995Z","iopub.status.idle":"2021-08-15T12:10:33.784386Z","shell.execute_reply.started":"2021-08-15T12:10:33.741955Z","shell.execute_reply":"2021-08-15T12:10:33.783160Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = get_pretrained_model(vgg19, train_df.landmark_id.nunique(), use_cuda)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:33.789158Z","iopub.execute_input":"2021-08-15T12:10:33.789570Z","iopub.status.idle":"2021-08-15T12:10:39.706533Z","shell.execute_reply.started":"2021-08-15T12:10:33.789534Z","shell.execute_reply":"2021-08-15T12:10:39.705530Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## Checking model summary using torchsummary\nsummary(model, (3,224,224))","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:39.708349Z","iopub.execute_input":"2021-08-15T12:10:39.708713Z","iopub.status.idle":"2021-08-15T12:10:39.963796Z","shell.execute_reply.started":"2021-08-15T12:10:39.708664Z","shell.execute_reply":"2021-08-15T12:10:39.962919Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Using Vanilla CrossEntropyLoss, it would be better to give the weight for each class due to high imbalance\ncriteria = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:39.966950Z","iopub.execute_input":"2021-08-15T12:10:39.967235Z","iopub.status.idle":"2021-08-15T12:10:39.971809Z","shell.execute_reply.started":"2021-08-15T12:10:39.967205Z","shell.execute_reply":"2021-08-15T12:10:39.970937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loaders = {'train': train_loader, 'valid': valid_loader, 'test': test_loader}","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:39.973252Z","iopub.execute_input":"2021-08-15T12:10:39.973620Z","iopub.status.idle":"2021-08-15T12:10:39.981585Z","shell.execute_reply.started":"2021-08-15T12:10:39.973581Z","shell.execute_reply":"2021-08-15T12:10:39.980763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"save_path = \"../working/\"","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:39.983033Z","iopub.execute_input":"2021-08-15T12:10:39.983311Z","iopub.status.idle":"2021-08-15T12:10:39.994082Z","shell.execute_reply.started":"2021-08-15T12:10:39.983284Z","shell.execute_reply":"2021-08-15T12:10:39.993179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from time import time","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:39.995522Z","iopub.execute_input":"2021-08-15T12:10:39.995913Z","iopub.status.idle":"2021-08-15T12:10:40.003724Z","shell.execute_reply.started":"2021-08-15T12:10:39.995885Z","shell.execute_reply":"2021-08-15T12:10:40.002735Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train(n_epochs, loaders, model, optimizer, criterion, use_cuda, save_path, num_batch=1, verbose=False):\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        start_time = time()\n        \n        ###################\n        # train the model #\n        ###################\n        # set the module to training mode\n        model.train()\n#         import pdb; pdb.set_trace()\n        for batch_idx, (data, target, img_id) in enumerate(loaders['train']):\n            # move to GPU\n            if use_cuda:\n                data, target = data.cuda(), target.cuda()\n\n            ## TODO: 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.item() - train_loss))\n            optimizer.zero_grad()\n            out = model(data)\n            loss = criterion(out, target)\n            loss.backward()\n            optimizer.step()\n            train_loss = train_loss + ((1 / (batch_idx + 1)) * (loss.data.item() - train_loss))\n            train_loss += loss.data.item()*data.size(0)\n            if verbose:\n                print(f\"idx: {batch_idx} Train Loss:{train_loss/(data.size(0) * (batch_idx + 1)) : .6f}\")\n            if batch_idx > num_batch:\n                train_images_used = data.size(0)*(batch_idx + 1)\n                break\n\n            \n        torch.cuda.empty_cache()\n        ######################    \n        # validate the model #\n        ######################\n        # set the model to evaluation mode\n        model.eval()\n        for batch_idx, (data, target, img_id) in enumerate(loaders['valid']):\n            # move to GPU\n            if use_cuda:\n                data, target = data.cuda(), target.cuda()\n\n            ## TODO: update average validation loss \n            out = model(data)\n            loss = criterion(out, target)\n            valid_loss += loss.data.item()*data.size(0) \n            if verbose:\n                print(f\"idx: {batch_idx} Valid Loss:{valid_loss / (data.size(0) * (batch_idx + 1)) : .6f}\")\n            if batch_idx > num_batch:\n                valid_images_used = data.size(0)*(batch_idx + 1)\n                break\n        train_loss = train_loss/ train_images_used\n        valid_loss = valid_loss / valid_images_used\n\n            \n            \n        end_time = time()\n        time_taken = end_time - start_time\n        # print training/validation statistics \n        print('Epoch: {} \\t Time: {:.2f} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f}'.format(\n            epoch, \n            time_taken,\n            train_loss,\n            valid_loss\n            ))\n\n        ## TODO: if the validation loss has decreased, save the model at the filepath stored in save_path\n        if valid_loss < valid_loss_min:\n            if verbose:\n                print(f\"Valid loss reduced from {valid_loss_min :.6f} to {valid_loss :.6f}, saving model\")\n            valid_loss_min = valid_loss\n            torch.save(model.state_dict(), save_path)\n              \n    return model","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:40.005145Z","iopub.execute_input":"2021-08-15T12:10:40.005621Z","iopub.status.idle":"2021-08-15T12:10:40.021584Z","shell.execute_reply.started":"2021-08-15T12:10:40.005580Z","shell.execute_reply":"2021-08-15T12:10:40.020588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tqdm","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:40.022983Z","iopub.execute_input":"2021-08-15T12:10:40.023608Z","iopub.status.idle":"2021-08-15T12:10:40.034617Z","shell.execute_reply.started":"2021-08-15T12:10:40.023563Z","shell.execute_reply":"2021-08-15T12:10:40.033524Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict(loaders, model, use_cuda, landmark_reverse_map):\n    \n    \n    # set the module to evaluation mode\n    model.eval()\n    sf = nn.Softmax(dim=1)\n    img_id_list = []\n    confidence_list = []\n    label_list = []\n    tot_batch = len(loaders['test'])\n    for batch_idx, (data, _, img_id) in enumerate(tqdm.tqdm(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 = sf(output)\n        output = torch.max(output, dim=1)\n        confidence = output[0].cpu().detach().numpy()\n        label=output[1].cpu().detach().numpy()\n        \n        img_id_list.extend(list(img_id))\n        confidence_list.extend(confidence.tolist())\n        label_list.extend(label.tolist())\n    \n    predict_df = pd.DataFrame({'id': img_id_list, \n                               'landmarks': label_list, \n                               'conf': confidence_list})\n    predict_df['landmarks'] = predict_df['landmarks'].map(landmark_reverse_map)\n    predict_df['landmarks'] = predict_df['landmarks'].astype(str) +\" \" + predict_df['conf'].round(6).astype(str)\n\n    predict_df.drop(\"conf\", axis=1, inplace=True)\n    return predict_df\n        \n\n        \n        ","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:40.038040Z","iopub.execute_input":"2021-08-15T12:10:40.038385Z","iopub.status.idle":"2021-08-15T12:10:40.048793Z","shell.execute_reply.started":"2021-08-15T12:10:40.038347Z","shell.execute_reply":"2021-08-15T12:10:40.047404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# data is huge, running 1000 batches for 10 epoch, with an assumption that atleast model will see each class once\n\nnum_epochs = 20\nmodel_transfer = train(num_epochs, loaders, model, optimizer, \n                      criteria, use_cuda, os.path.join(save_path,'model_transfer.pt'),num_batch=1000, verbose=False)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T12:10:40.050172Z","iopub.execute_input":"2021-08-15T12:10:40.050885Z","iopub.status.idle":"2021-08-15T14:34:46.356427Z","shell.execute_reply.started":"2021-08-15T12:10:40.050839Z","shell.execute_reply":"2021-08-15T14:34:46.355527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Loading the best model\nmodel.load_state_dict(torch.load(os.path.join(save_path,'model_transfer.pt')))","metadata":{"execution":{"iopub.status.busy":"2021-08-15T14:34:46.359713Z","iopub.execute_input":"2021-08-15T14:34:46.359977Z","iopub.status.idle":"2021-08-15T14:34:49.207037Z","shell.execute_reply.started":"2021-08-15T14:34:46.359949Z","shell.execute_reply":"2021-08-15T14:34:49.206172Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"landmark_reverse_map = dict(zip(train_data.landmark_id_map.values(), train_data.landmark_id_map.keys()))","metadata":{"execution":{"iopub.status.busy":"2021-08-15T14:34:49.208388Z","iopub.execute_input":"2021-08-15T14:34:49.208838Z","iopub.status.idle":"2021-08-15T14:34:49.219305Z","shell.execute_reply.started":"2021-08-15T14:34:49.208793Z","shell.execute_reply":"2021-08-15T14:34:49.218498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"out = predict(loaders, model, use_cuda, landmark_reverse_map)","metadata":{"execution":{"iopub.status.busy":"2021-08-15T14:34:49.220697Z","iopub.execute_input":"2021-08-15T14:34:49.221284Z","iopub.status.idle":"2021-08-15T14:38:30.048939Z","shell.execute_reply.started":"2021-08-15T14:34:49.221233Z","shell.execute_reply":"2021-08-15T14:38:30.047881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display(out.tail())","metadata":{"execution":{"iopub.status.busy":"2021-08-15T14:38:30.050292Z","iopub.execute_input":"2021-08-15T14:38:30.050784Z","iopub.status.idle":"2021-08-15T14:38:30.061972Z","shell.execute_reply.started":"2021-08-15T14:38:30.050744Z","shell.execute_reply":"2021-08-15T14:38:30.060537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"out.to_csv(\"submission.csv\")","metadata":{"execution":{"iopub.status.busy":"2021-08-15T14:38:30.063150Z","iopub.execute_input":"2021-08-15T14:38:30.063837Z","iopub.status.idle":"2021-08-15T14:38:30.109835Z","shell.execute_reply.started":"2021-08-15T14:38:30.063797Z","shell.execute_reply":"2021-08-15T14:38:30.109022Z"},"trusted":true},"execution_count":null,"outputs":[]}]}