{"cells":[{"metadata":{"_uuid":"8b3d80ed7ad56834d70ed4d6e012f46257579e07","trusted":true},"cell_type":"code","source":"# Libraries\nimport os\nimport numpy as np\nimport pandas as pd\nimport cv2\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nfrom sklearn.model_selection import train_test_split\n\nimport torch \nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision\nimport torchvision.transforms as transforms\nfrom torch.utils.data import TensorDataset, DataLoader, Dataset","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b0b625dddcf44cd8db7690bf380c6cb25f555cbd","trusted":true},"cell_type":"code","source":"## Parameters for model\n\n# Hyper parameters\nnum_epochs = 8\nnum_classes = 2\nbatch_size = 128\nlearning_rate = 0.002\n\n# Device configuration\ndevice = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"08fbba4de055ecb31736a3e5358252ca8180244b","trusted":true},"cell_type":"code","source":"labels = pd.read_csv('../input/train_labels.csv')\nsub = pd.read_csv('../input/sample_submission.csv')\ntrain_path = '../input/train/'\ntest_path = '../input/test/'","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"16937da840e0d80e2604e0d362171796516886d3","trusted":true},"cell_type":"code","source":"#Splitting data into train and val\ntrain, val = train_test_split(labels, stratify=labels.label, test_size=0.1)\nlen(train), len(val)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"64e44031b4f051993af3648cdb99877563f37d6f"},"cell_type":"markdown","source":"**Simple custom generator**"},{"metadata":{"_uuid":"a5f0097544dc230bb794e75a163196f08de0c13c","trusted":true},"cell_type":"code","source":"class MyDataset(Dataset):\n    def __init__(self, df_data, data_dir = './', transform=None):\n        super().__init__()\n        self.df = df_data.values\n        self.data_dir = data_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, index):\n        img_name,label = self.df[index]\n        img_path = os.path.join(self.data_dir, img_name+'.tif')\n        image = cv2.imread(img_path)\n        if self.transform is not None:\n            image = self.transform(image)\n        return image, label","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cbacdb7bcd20d414d115cde200f564934b69f308","trusted":true},"cell_type":"code","source":"trans_train = transforms.Compose([transforms.ToPILImage(),\n                                  transforms.Pad(64, padding_mode='reflect'),\n                                  transforms.RandomHorizontalFlip(), \n                                  transforms.RandomVerticalFlip(),\n                                  transforms.RandomRotation(20), \n                                  transforms.ToTensor(),\n                                  transforms.Normalize(mean=[0.5, 0.5, 0.5],std=[0.5, 0.5, 0.5])])\n\ntrans_valid = transforms.Compose([transforms.ToPILImage(),\n                                  transforms.Pad(64, padding_mode='reflect'),\n                                  transforms.ToTensor(),\n                                  transforms.Normalize(mean=[0.5, 0.5, 0.5],std=[0.5, 0.5, 0.5])])\n\ndataset_train = MyDataset(df_data=train, data_dir=train_path, transform=trans_train)\ndataset_valid = MyDataset(df_data=val, data_dir=train_path, transform=trans_valid)\n\nloader_train = DataLoader(dataset = dataset_train, batch_size=batch_size, shuffle=True, num_workers=0)\nloader_valid = DataLoader(dataset = dataset_valid, batch_size=batch_size//2, shuffle=False, num_workers=0)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ac596a6914e7455f1326c01eb532d7b36b972e7f"},"cell_type":"markdown","source":"**Model**"},{"metadata":{"_uuid":"f32c84715ab1c585a56b41fc71c05c42d55bfd4b","trusted":true},"cell_type":"code","source":"class SimpleCNN(nn.Module):\n    def __init__(self):\n        # ancestor constructor call\n        super(SimpleCNN, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=2)\n        self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=2)\n        self.conv3 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=2)\n        self.conv4 = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, padding=2)\n        self.conv5 = nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, padding=2)\n        self.bn1 = nn.BatchNorm2d(32)\n        self.bn2 = nn.BatchNorm2d(64)\n        self.bn3 = nn.BatchNorm2d(128)\n        self.bn4 = nn.BatchNorm2d(256)\n        self.bn5 = nn.BatchNorm2d(512)\n        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)\n        self.avg = nn.AvgPool2d(8)\n        self.fc = nn.Linear(512 * 1 * 1, 2) # !!!\n    def forward(self, x):\n        x = self.pool(F.leaky_relu(self.bn1(self.conv1(x)))) # first convolutional layer then batchnorm, then activation then pooling layer.\n        x = self.pool(F.leaky_relu(self.bn2(self.conv2(x))))\n        x = self.pool(F.leaky_relu(self.bn3(self.conv3(x))))\n        x = self.pool(F.leaky_relu(self.bn4(self.conv4(x))))\n        x = self.pool(F.leaky_relu(self.bn5(self.conv5(x))))\n        x = self.avg(x)\n        #print(x.shape) # lifehack to find out the correct dimension for the Linear Layer\n        x = x.view(-1, 512 * 1 * 1) # !!!\n        x = self.fc(x)\n        return x","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a7ad501f705b587971ced8aec0d36d866af0bed2"},"cell_type":"markdown","source":"**Important note:** You may notice that in lines with # !!! there is not very clear 512 \\* 1 \\* 1. This is the dimension of the picture before the FC layers (H x W x C), then you have to calculate it manually (in Keras, for example, .Flatten () does everything for you). However, there is one life hack — just make print (x.shape) in forward () (commented out line). You will see the size (batch_size, C, H, W) - you need to multiply everything except the first (batch_size), this will be the first dimension of Linear (), and it is in C H W that you need to \"expand\" x before feeding to Linear ()."},{"metadata":{"_uuid":"67522fc88f034ddb684f9fba0e154c341760d1d1","trusted":true},"cell_type":"code","source":"model = SimpleCNN().to(device)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a56a159ba70e958c82e518d718be99bd41c17299","trusted":true},"cell_type":"code","source":"# Loss and optimizer\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adamax(model.parameters(), lr=learning_rate)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"dca29061dd5d6a60ba95f16dbaea70e6dc822150","trusted":true},"cell_type":"code","source":"\n# Train the model\ntotal_step = len(loader_train)\nfor epoch in range(num_epochs):\n    for i, (images, labels) in enumerate(loader_train):\n        images = images.to(device)\n        labels = labels.to(device)\n        \n        # Forward pass\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n        \n        # Backward and optimize\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        \n        if (i+1) % 100 == 0:\n            print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}' \n                   .format(epoch+1, num_epochs, i+1, total_step, loss.item()))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9de7463bf94c03149a7121ce2bb96dc05ecf2d7b"},"cell_type":"markdown","source":"**Accuracy Check**"},{"metadata":{"_uuid":"998c3c05a3c3fb6fc7f2523dddff50496490d051","trusted":true},"cell_type":"code","source":"# Test the model\nmodel.eval()  # eval mode (batchnorm uses moving mean/variance instead of mini-batch mean/variance)\nwith torch.no_grad():\n    correct = 0\n    total = 0\n    for images, labels in loader_valid:\n        images = images.to(device)\n        labels = labels.to(device)\n        outputs = model(images)\n        _, predicted = torch.max(outputs.data, 1)\n        total += labels.size(0)\n        correct += (predicted == labels).sum().item()\n          \n    print('Test Accuracy of the model on the 22003 test images: {} %'.format(100 * correct / total))\n\n# Save the model checkpoint\ntorch.save(model.state_dict(), 'model.ckpt')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c1c0709b4a1e7edea538eda5168819a7b949eedf"},"cell_type":"markdown","source":"**CSV submission**"},{"metadata":{"_uuid":"4d03acf3711d8036703041276749bbaf2ef64e71","trusted":true},"cell_type":"code","source":"dataset_valid = MyDataset(df_data=sub, data_dir=test_path, transform=trans_valid)\nloader_test = DataLoader(dataset = dataset_valid, batch_size=32, shuffle=False, num_workers=0)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b85e1661e660b45486ab1b46a4d925e18f541b75","trusted":true},"cell_type":"code","source":"\nmodel.eval()\n\npreds = []\nfor batch_i, (data, target) in enumerate(loader_test):\n    data, target = data.cuda(), target.cuda()\n    output = model(data)\n\n    pr = output[:,1].detach().cpu().numpy()\n    for i in pr:\n        preds.append(i)\nsub.shape, len(preds)\nsub['label'] = preds\nsub.to_csv('s.csv', index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.6.6"}},"nbformat":4,"nbformat_minor":1}