{"cells":[{"metadata":{"_uuid":"0e76fc0e30434730944dba3616814ffd5c55ef4d"},"cell_type":"markdown","source":"### Importing Modules"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport json\nimport pandas as pd\nimport numpy as np\nimport time\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nfrom imageio import imread\nsns.set_style(\"darkgrid\")\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a82ee363ac5107d20e47ddb2e7e02d965ce183da"},"cell_type":"code","source":"import warnings\nwarnings.filterwarnings('ignore')","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import torch\nimport torchvision\nfrom torch import nn\nfrom torch import optim\nfrom torch.optim import lr_scheduler\nfrom torchvision import datasets, transforms, models\nfrom torch.utils.data import Dataset\nfrom torch.utils.data.sampler import SubsetRandomSampler","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"efdb786eb8d3da436bdc73bd3b1d8056a12d0ab7"},"cell_type":"markdown","source":"### Check if GPU is available"},{"metadata":{"trusted":true,"_uuid":"eee8fe60f083b879facc536c1f101760f2f9f2bb"},"cell_type":"code","source":"gpu = torch.cuda.is_available()\nif gpu:\n    print(\"GPU available\")\nelse:\n    print(\"GPU NOT available! Training will happen on CPU\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"750a5abfdf42818b8010ea3aa7f34cc870c73da8"},"cell_type":"markdown","source":"### Preparing Data"},{"metadata":{"trusted":true,"_uuid":"2eee7814f259644781523b6a26f251c61404624a"},"cell_type":"code","source":"DATA_PATH = \"../input/\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9464dea4a18faecac6e7edf0adb9bff50efb62a6"},"cell_type":"code","source":"df = pd.read_csv(DATA_PATH + 'train.csv')\ndf.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8f16aae3d76d7cbdef059a29371e78b7a053bd12"},"cell_type":"code","source":"n_classes = df.Id.unique()\nclass_to_idx = {class_name:idx for idx, class_name in enumerate(n_classes)}\nidx_to_classes = {idx:class_name for class_name, idx in class_to_idx.items()}","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"db5bf081d5ce3766d7065883b82e0e6b87977207"},"cell_type":"markdown","source":"### Defining Transforms"},{"metadata":{"trusted":true,"_uuid":"26fdeac5aef1029231c12d5256d807e0e82c4a49"},"cell_type":"code","source":"train_transform = transforms.Compose([\n    transforms.RandomHorizontalFlip(),\n    #transforms.RandomGrayscale(),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])\n])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7d08c2ed30af6c69cdbf72ba989a32027f1dc913"},"cell_type":"code","source":"class WhaleDataset(Dataset):\n    \"\"\"\n    Dataset to generate batches of multiple images and labels from a CSV file.\n    Purpose: To work with CSV files where the format is (file_name, cclass_label)\n    and generate batches of data(images, labels) on-the-fly.\n    \"\"\"\n    def __init__(self, csv_file_path, image_path, image_size, class_to_idx, transform=None):\n        self.data = pd.read_csv(csv_file_path)\n        self.image_path = image_path\n        self.transform = transform\n        self.class_to_idx = class_to_idx\n\n    def __len__(self):\n        \"\"\"\n        Returns the no of datapoints in the dataset\n        \"\"\"\n        return len(self.data)\n    \n    def __getitem__(self, index):\n        \"\"\"\n        Returns a batch of data given an index\n        \"\"\"\n        image_name = self.data.iloc[index, 0]\n        image = Image.open(self.image_path + image_name)\n        image = image.convert('RGB')\n        image = image.resize(image_size, Image.ANTIALIAS) \n        if self.transform is not None:\n            image = self.transform(image)\n        label = self.data.iloc[index, 1]\n        label = self.class_to_idx[label]\n        label = torch.from_numpy(np.asarray(label))\n        \n        return image, label","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b4012b951370ec62de5da8ae474459a6f93639b5"},"cell_type":"code","source":"#path of the csv file containing info about images and labels\nCSV_PATH = DATA_PATH + 'train.csv'\n#path where the actual training images are stored\nIMAGE_PATH = DATA_PATH + 'train/'\n#no of images we want to display while plotting\nn_images = 10\n#image size in width * height\nimage_size = (224,224)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"25c9f38cb154f16107ce233f017969611bf20a81"},"cell_type":"code","source":"whale_dataset = WhaleDataset(CSV_PATH, IMAGE_PATH, image_size, class_to_idx, transform=train_transform)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"533f114ce36526f30e83d35858faa1b1d77b77a4"},"cell_type":"code","source":"valid_size = 0.2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c9bbee5d2aebc46974c92350130141bd66a758e8"},"cell_type":"code","source":"no_train = len(whale_dataset)\nindices = list(range(no_train))\nnp.random.shuffle(indices)\nsplit = int(np.floor(valid_size * no_train))\ntrain_indices, valid_indices = indices[split:], indices[:split]\ntrain_sampler = SubsetRandomSampler(train_indices)\nvalid_sampler = SubsetRandomSampler(valid_indices)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2d7a575adc84ff94a47dc1253be40e5f9f8d156c"},"cell_type":"code","source":"train_loader = torch.utils.data.DataLoader(whale_dataset, batch_size=32, sampler=train_sampler)\nvalid_loader = torch.utils.data.DataLoader(whale_dataset, batch_size=32, sampler=valid_sampler)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b202702efb4ad2a27ca751f8898fe7ff5b6d66eb"},"cell_type":"markdown","source":"### Visualising Data"},{"metadata":{"trusted":true,"_uuid":"e16e9dbfe64a1ae4ef23defab0941c23e48c50cc"},"cell_type":"code","source":"images, labels = next(iter(train_loader))\n#images = images.numpy()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"978a7b3694571ef259cb4c645272b11846e971f8"},"cell_type":"code","source":"def display_image(inp, title=None):\n    inp = inp.numpy()\n    inp = np.transpose(inp, (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 = inp * std + mean\n    inp = np.clip(inp,0,1)\n    if title is not None:\n        plt.title(title)\n    plt.figure(figsize=(32,6))\n    plt.imshow(inp)\n    plt.pause(0.001)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7751c5ca3aa19f2553b2436865eff0d6dda7a764"},"cell_type":"code","source":"out = torchvision.utils.make_grid(images, nrow=8, padding=0)\n#display_image(out, title=[idx_to_classes[x.item()] for x in labels])\ndisplay_image(out, title=None)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"27cc3d252a75d22d7cf9cbee673444a76147b51f"},"cell_type":"markdown","source":"### Getting the Model"},{"metadata":{"trusted":true,"_uuid":"775084d0f82eaca7a23e8139fcf4bd7433eecff1"},"cell_type":"code","source":"model = models.resnet50(pretrained=True)\nprint(model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"81c9e821469eb419ad8b57f892b616effda3083c"},"cell_type":"code","source":"for param in model.parameters():\n    param.requires_grad = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9da688175fee88126d158a6f81d43169b8e4e3cb"},"cell_type":"code","source":"input_size = model.fc.in_features\noutput_size = model.fc.out_features\nprint(input_size)\nprint(output_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"aa442ec8fded06393dafdd65da166f2d6c461128"},"cell_type":"code","source":"last_fc = nn.Sequential(\n    nn.Linear(input_size, len(class_to_idx)),nn.Softmax(dim=1))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6a30115dd0ed65557221cd6033a0202e25984971"},"cell_type":"code","source":"model.fc = last_fc\nprint(model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"74ed4b507448df19eb405f6222a655b32a2eb857"},"cell_type":"code","source":"if gpu:\n    model.cuda()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e0e72f28d6b1866769879fd97c27c6a591d336ef"},"cell_type":"code","source":"# def prepare_dataframe(index, labels):\n#     index = index.cpu().numpy()\n#     labels = labels.cpu().numpy()\n#     df_index = pd.DataFrame(index)\n#     df_labels = pd.DataFrame(labels, columns=['target'])\n#     df = pd.concat([df_index,df_labels ], axis=1)\n#     df['precision'] = 0\n#     del df_index\n#     del df_labels\n#     return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"50e954a7f17b701674f25a3a1ca3ebeb1178b976"},"cell_type":"code","source":"def map_per_image(label, predictions):\n    label = int(label.cpu().numpy())\n    predictions = list(predictions.cpu().numpy())\n    try:\n        return 1 / (predictions.index(label) + 1)\n    except ValueError:\n        return 0.0","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"70db47f7e0f4b0a6cbfd3d601a11368677ee0697"},"cell_type":"code","source":"def map_per_batch(labels, predictions):\n    return np.mean([map_per_image(l,p) for l,p in zip(labels, predictions)])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a060d7c7c10e70b43ce8e30e316acc65745178a6"},"cell_type":"code","source":"# def get_precision(x):\n#     target = np.array(x[-2])\n#     labels = np.array(x[:-2])\n    \n#     target_position, = np.where(labels == target)\n    \n#     if len(target_position) > 0:\n#         target_position = target_position[0] + 1\n#         precision = (1 / target_position)\n#     else:\n#         precision = 0\n#     return precision","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"71386ddf7b0fce2221ece6e12166a0b6cc41df81"},"cell_type":"markdown","source":" ### Optimizers and loss functions"},{"metadata":{"trusted":true,"_uuid":"d8a05e9e7a8fe700b3a650c78b5b7e2182d47965"},"cell_type":"code","source":"optimizer = optim.SGD(model.fc.parameters(), lr=0.01, momentum=0.9)\ncriterion = nn.CrossEntropyLoss()\nscheduler = lr_scheduler.StepLR(optimizer,gamma=0.1, step_size=10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0555428a8576116473af185d2815292874b84560"},"cell_type":"code","source":"n_epochs = 30\nmin_loss = np.Inf","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"de2983b32618e48bb3110a56d2d16613951b97ee"},"cell_type":"markdown","source":"### Training Model"},{"metadata":{"trusted":true,"_uuid":"dfeaae17f4f1f6a77b45b8a54c21e7b109db6630"},"cell_type":"code","source":"training_losses = []\nvalid_losses = []\nmin_valid_loss = np.Inf","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"26b409122bcf04dacad6741ac71bfc769273e75a"},"cell_type":"code","source":"for e in range(1, n_epochs+1):\n    print(f\"-----------Epoch {e}/{n_epochs}-------------------\")\n    #switching the model to training mode\n    model.train()\n    #initialising starting values for training and validation loss\n    training_loss = 0.0\n    validation_loss = 0.0\n    #Initializing starting values for training accuracy\n    total_train = 0\n    total_correct_train = 0\n    #Initializing starting values for validation accuracy\n    total_validation = 0\n    total_correct_validation = 0\n    train_precision = 0\n    valid_precision = 0\n    for images, labels in train_loader:\n        if gpu: #move the data to GPU if available\n            images, labels = images.cuda(), labels.cuda()\n        #clearing out gradients\n        optimizer.zero_grad()\n        #doing the forward pass\n        output = model(images)\n        # Calculating training accuracy\n        # Total number of labels\n        total_train += len(labels)\n        # Getting predicted labels\n        predicted = torch.max(output.data, 1)[1]        \n        # Total correct predictions\n        total_correct_train += torch.sum(predicted == labels).item()\n        #Calculating precision\n        probs, predictions = output.topk(5, dim=1)\n        batch_precision = map_per_batch(labels, predictions)\n        #print(f\"Batch Precision is {batch_precision}\")\n        #df = prepare_dataframe(index, labels)\n        #df['precision'] = df.apply(get_precision, axis=1)\n        #batch_precision = df['precision'].sum()\n        train_precision += batch_precision\n        \n        #calculating the loss from the forward pass\n        loss = criterion(output, labels)\n        #propagating the error backwards\n        loss.backward()\n        #updating weights and biases\n        optimizer.step()\n        #adding training loss for a batch\n        training_loss += loss.item() * images.size(0)\n\n    #switching the model to evaluation mode\n    model.eval()\n    for images, labels in valid_loader:\n        with torch.no_grad():\n            if gpu: #move the data to GPU if available\n                images, labels = images.cuda(), labels.cuda()\n            #doing the forward pass for validation images\n            output = model(images)\n            \n            #calculating valdation accuracy\n            total_validation += len(images)\n            predicted = torch.max(output.data, 1)[1]\n            total_correct_validation += torch.sum(predicted == labels).item()\n            #calculating CE loss for validation images\n            loss = criterion(output, labels)\n            #adding up validation loss for a batch\n            validation_loss += loss.item() * images.size(0)\n\n    train_loss = training_loss/len(train_loader.dataset)\n    valid_loss = validation_loss/len(valid_loader.dataset)\n    print(f\"Total training precision is {train_precision}\")\n    avg_train_precision = train_precision / float(len(train_loader))\n    \n    train_accuracy = (total_correct_train / float(total_train)) * 100\n    valid_accuracy = (total_correct_validation / float(total_validation)) * 100\n    print(f\"Mean Average precision for training is {avg_train_precision}\")\n    print(f\"Training loss for epoch no {e} is {train_loss}\")\n    print(f\"Training accuracy for epoch no {e} is {train_accuracy}\")\n    print(f\"Validation loss for epoch no {e} is {valid_loss}\")\n    print(f\"Validation accuracy for epoch no {e} is {valid_accuracy}\")\n\n    training_losses.append(train_loss)\n    valid_losses.append(valid_loss)\n\n    if valid_loss <= min_valid_loss:\n        print(f\"Validation loss decreased from {min_valid_loss} to {valid_loss}.....Saving model.....\")\n        #torch.save(model.state_dict(), 'model_whale_resnet50.pt')\n        torch.save({\n            'epoch': e,\n            'model_state_dict': model.state_dict(),\n            'optimizer_state_dict': optimizer.state_dict(),\n            'val_loss': valid_loss,\n            'train_loss': train_loss\n            }, 'model_resnet50_parameters.tar')\n        min_valid_loss = valid_loss\n        \n    scheduler.step()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"54ca0bb41b5eeac4f603cc70f2bf56a9ae3a4127"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ad2b011cc5f3c12a50699064122dd9372a64353d"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"831a600130cb813587776cb1aad8619d7a09eed3"},"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}