{"cells":[{"metadata":{"_uuid":"e7bca950c3cd4746a616f0f24588f763f948e3dd"},"cell_type":"markdown","source":"## Check GPU Availability\n\nMake sure that GPU is available. If not turn the GPU state to on in Settings."},{"metadata":{"trusted":true,"_uuid":"5b60be7ffe2be0750a7aa1ab5dbfd638ed7c472a","scrolled":true},"cell_type":"code","source":"!nvidia-smi","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"915aa5f0fa390094aabbff2b2ab0aa1cb954f1cc"},"cell_type":"markdown","source":"## Import Libraries\n\nImport all the required libraries."},{"metadata":{"trusted":true,"_uuid":"4e882853e3026f15655a3f1129a74621dde3f710"},"cell_type":"code","source":"import os\nimport time\nimport numpy as np\nimport pandas as pd\nimport torch\nfrom matplotlib import pyplot as plt\nfrom PIL import Image\nfrom torch.optim import Adam, lr_scheduler\nfrom torch.autograd import Variable\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn import Linear, CrossEntropyLoss\nfrom torchvision.models import densenet201, resnet152, vgg19_bn \nfrom torchvision.transforms import Compose, RandomApply, RandomAffine, ColorJitter, Normalize, ToTensor","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cd7373c09e20e6cb3be787d740e6febbfde1637d"},"cell_type":"markdown","source":"## Generate required folders\n\nGenerate the required folders to be able to\n* save the states\n* load from saved states\n* save plots\n* save results"},{"metadata":{"trusted":true,"_uuid":"25bdf58d8ed8ccd6629a02bfb6d2cefd3791d7eb"},"cell_type":"code","source":"folders = {\n    \"plots\": \"plots\",\n    \"models\": \"models\",\n    \"results\": \"results\"\n}\nfor key in folders.keys():\n    try:\n        os.makedirs(folders[key])\n    except FileExistsError:\n        # if file exists, pass\n        pass","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ec93bab7524005c5d19ffb19e5cf2bb1e4780eb0"},"cell_type":"markdown","source":"## PCam Dataset\n\nCustom dataset definition to be able to use PyTorch style of efficient data loading.\n\n### Challenges Faced\n\nA deep neural network tries to get the best performance and so having relatively more number of examples in one class is making the network to have a biased view of it's world. So, have to come up with a way to have same number of examples for each category."},{"metadata":{"trusted":true,"_uuid":"3e67bd767acd39b0579c07873a997944f9608e27"},"cell_type":"code","source":"class PCam(Dataset):\n    \"\"\"Patch Camelyon dataset.\"\"\"\n\n    def __init__(self, csv_file, root_dir, train=True, transform=None):\n        \"\"\"\n        Args:\n            csv_file (string): Path to the csv file with labels.\n            root_dir (string): Root directory.\n            train (boolean): Whether loading training or testing data. \n                            This is required to have same number of examples in each \n                            classification to be able to train better.\n            transform (callable, optional): Optional transform to be applied\n                on a sample.\n        \"\"\"\n        if train:\n            dataframe = pd.read_csv(os.path.join(root_dir, csv_file))\n            min_value = dataframe['label'].value_counts().min()\n            frames = []\n            for label in dataframe['label'].unique():\n                frames.append(dataframe[dataframe['label'] == label].sample(min_value))\n            self.labels = pd.DataFrame().append(frames).sample(frac=1).reset_index(drop=True)\n            self.data_folder = \"train\"\n        else:\n            self.labels = pd.read_csv(os.path.join(root_dir, csv_file))\n            self.data_folder = \"test\"\n        \n        self.root_dir = root_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.labels)\n\n    def __getitem__(self, idx):\n        image_name = os.path.join(self.root_dir,\n                                \"%s/%s.tif\" % (self.data_folder, self.labels.iloc[idx, 0]))\n        image = Image.open(image_name)\n        image.thumbnail((40, 40), Image.ANTIALIAS)\n        if self.transform is not None:\n            image = self.transform(image)\n\n        return self.labels.iloc[idx, 0], image, self.labels.iloc[idx, 1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3963d72c5302dcfe3d0f70e5b9a6bfe8fd942d00"},"cell_type":"code","source":"BATCH_SIZE = 32  # mini_batch size\nMAX_EPOCH = 8  # maximum epoch to train\nSTEP_SIZE = 2  # decrease in learning rate after epochs\nGAMMA = 0.1  # used in decreasing the gamma","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"85c860ea08c460253db71f3ca1f4b6b2cc71d6ea","scrolled":true},"cell_type":"code","source":"train_transform = Compose([\n    RandomAffine(45, translate=(0.15,0.15), shear=45),\n    RandomApply([ColorJitter(saturation=0.5, hue=0.5)]),\n    ToTensor(),\n    Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n])\ntest_transform = Compose(\n    [ToTensor(),\n     Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])  # torchvision.transforms.Normalize(mean, std)\n\ntrainset = PCam(csv_file='train_labels.csv', root_dir='../input', train=True, transform=train_transform)\ntrainloader = DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2)\n\ntestset = PCam(csv_file='sample_submission.csv', root_dir='../input', train=False, transform=test_transform)\ntestloader = DataLoader(testset, batch_size=BATCH_SIZE, shuffle=False, num_workers=2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"719bc0f9743a89cfccb4b8048fa8d09498b9b78a"},"cell_type":"code","source":"def eval_net(net, criterion, dataloader):\n    correct = 0\n    total = 0\n    total_loss = 0\n    net.eval()\n    \n    for data in dataloader:\n        _, images, labels = data\n        images, labels = Variable(images).cuda(), Variable(labels).cuda()\n        outputs = net(images)\n        _, predicted = torch.max(outputs.data, 1)\n        total += labels.size(0)\n        correct += (predicted == labels.data).sum().item()\n        loss = criterion(outputs, labels)\n        total_loss += loss.item()\n    return total_loss / total, correct / total","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b68c886072ea142f875ab08f71c2e46ac176ce37"},"cell_type":"code","source":"def train_net(net, criterion, eval_criterion, optimizer, scheduler):\n\n    train_loss_array = []\n    test_loss_array = []\n    train_accuracy_array = []\n    test_accuracy_array = []\n\n    print('Start training...')\n    for epoch in range(MAX_EPOCH):  # loop over the dataset multiple times\n        scheduler.step()\n        net.train()\n        running_loss = 0.0\n        for i, data in enumerate(trainloader):\n            _, inputs, labels = data\n            inputs, labels = Variable(inputs).cuda(), Variable(labels).cuda()\n\n            optimizer.zero_grad()\n            outputs = net(inputs)\n            loss = criterion(outputs, labels)\n            loss.backward()\n            optimizer.step()\n            running_loss += loss.item()\n            if i % 500 == 499:    # print every 2000 mini-batches\n                print('Step: %5d avg_batch_loss: %.5f' % (i + 1, running_loss / 500))\n                running_loss = 0.0\n        print('Finish training this EPOCH, start evaluating...')\n        train_loss, train_acc = eval_net(net, eval_criterion, trainloader)\n        test_loss, test_acc = eval_net(net, eval_criterion, testloader)\n        print('EPOCH: %d train_loss: %.5f train_acc: %.5f test_loss: %.5f test_acc %.5f' %\n              (epoch+1, train_loss, train_acc, test_loss, test_acc))\n\n        train_loss_array.append(train_loss)\n        test_loss_array.append(test_loss)\n\n        train_accuracy_array.append(train_acc)\n        test_accuracy_array.append(test_acc)\n    print('Finished Training')\n\n    # plot loss\n    plt.clf()\n    plt.plot(list(range(1, MAX_EPOCH + 1)), train_loss_array, label='Train')\n    plt.plot(list(range(1, MAX_EPOCH + 1)), test_loss_array, label='Test')\n    plt.xlabel('Epochs')\n    plt.ylabel('Loss')\n    plt.legend()\n    plt.title('Loss vs Epochs [%s]' % net.name)\n    plt.savefig('./%s/loss-%s.png' % (folders['plots'], net.name))\n\n    # plot accuracy\n    plt.clf()\n    plt.plot(list(range(1, MAX_EPOCH + 1)), train_accuracy_array, label='Train')\n    plt.plot(list(range(1, MAX_EPOCH + 1)), test_accuracy_array, label='Test')\n    plt.xlabel('Epochs')\n    plt.ylabel('Accuracy')\n    plt.legend()\n    plt.title('Accuracy vs Epochs [%s]' % net.name)\n    plt.savefig('./%s/accuracy-%s.png' % (folders['plots'], net.name))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e7b7171f39dbbe2b5921b2e9981f87ea393179ef"},"cell_type":"code","source":"def dump_results(dataloader, net):\n    net.eval()\n    results = pd.DataFrame()\n    for data in dataloader:\n        image_names, images, labels = data\n        images, labels = Variable(images).cuda(), Variable(labels).cuda()\n        outputs = net(images)\n        _, predictions = torch.max(outputs.data, 1)\n        results = results.append(pd.DataFrame({\"id\": image_names, \"label\": predictions.cpu().numpy()}))\n    results.to_csv(\"%s/%s.csv\" % (folders['results'], net.name), index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"9dd2c28ef2391187b586caadb33c36a3daadd224"},"cell_type":"code","source":"start = time.time()\ncur_net = densenet201(pretrained=True)\nnum_ftrs = cur_net.classifier.in_features\ncur_net.classifier = Linear(num_ftrs, 2)\ncur_net.name = \"DenseNet201\"\ncur_net = cur_net.cuda()\n\ncur_criterion = CrossEntropyLoss()\nval_criterion = CrossEntropyLoss(reduction='sum')\ncur_optimizer = Adam(cur_net.parameters(), lr=0.00007)\nexp_lr_scheduler = lr_scheduler.StepLR(cur_optimizer, step_size=STEP_SIZE, gamma=GAMMA)\ntrain_net(cur_net, cur_criterion, val_criterion, cur_optimizer, exp_lr_scheduler)\ndump_results(testloader, cur_net)\nprint(\"Time taken: %d secs\" % int(time.time() - start))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"0c3990e1671862faf7a4055bc1d04710ae362144"},"cell_type":"code","source":"start = time.time()\ncur_net = resnet152(pretrained=True)\nnum_ftrs = cur_net.fc.in_features\ncur_net.fc = Linear(num_ftrs, 2)\ncur_net.name = \"ResNet152\"\ncur_net = cur_net.cuda()\n\ncur_criterion = CrossEntropyLoss()\nval_criterion = CrossEntropyLoss(reduction='sum')\ncur_optimizer = Adam(cur_net.parameters(), lr=0.00007)\nexp_lr_scheduler = lr_scheduler.StepLR(cur_optimizer, step_size=STEP_SIZE, gamma=GAMMA)\ntrain_net(cur_net, cur_criterion, val_criterion, cur_optimizer, exp_lr_scheduler)\ndump_results(testloader, cur_net)\nprint(\"Time taken: %d secs\" % int(time.time() - start))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0d94a9d087fadaf72e8e25b99b90e262ee099b9b","scrolled":true},"cell_type":"code","source":"start = time.time()\ncur_net = vgg19_bn(pretrained=True)\nnum_ftrs = cur_net.classifier._modules['6'].in_features\ncur_net.classifier._modules['6'] = Linear(num_ftrs, 2)\ncur_net.name = \"VGG19\"\ncur_net = cur_net.cuda()\n\ncur_criterion = CrossEntropyLoss()\nval_criterion = CrossEntropyLoss(reduction='sum')\ncur_optimizer = Adam(cur_net.parameters(), lr=0.00007)\nexp_lr_scheduler = lr_scheduler.StepLR(cur_optimizer, step_size=STEP_SIZE, gamma=GAMMA)\ntrain_net(cur_net, cur_criterion, val_criterion, cur_optimizer, exp_lr_scheduler)\ndump_results(testloader, cur_net)\nprint(\"Time taken: %d secs\" % int(time.time() - start))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c837a1576143e8c0c2370653e1aac615c95ec41e"},"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}