{"cells":[{"metadata":{},"cell_type":"markdown","source":"[Thanks for this source for getting reference on building pipeline](https://www.kaggle.com/nroman/melanoma-pytorch-starter-efficientnet?scriptVersionId=36599817)","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"# **What are we going to build  ?**\n### We will be building a neural network which consumes an image to predict the probability of being cancer ","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"# Setup Block","execution_count":null},{"metadata":{"_uuid":"4a62c5b6-8419-40d7-9ae3-85983c6d5f33","_cell_guid":"7c7f21f9-0b8f-4d1d-b6e6-84d64b615b46","trusted":true,"_kg_hide-output":true,"collapsed":true},"cell_type":"code","source":"!pip install efficientnet_pytorch torchtoolbox","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Why do we need these ?**\n> These are some of the libraries we need to import for running the network","execution_count":null},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport cv2\nfrom efficientnet_pytorch import EfficientNet\nimport torchtoolbox.transform as transforms\nimport torch\nimport torchvision\nimport torch.nn.functional as F\nimport torch.nn as nn\nimport torch.optim as optim\n\nfrom torch.utils import data\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\n!pip install torchsummary\nfrom torchsummary import summary\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**What is this MelanomaDataset class definition useful for ?**\n> In Pytorch we design our dataset as per torch.utils.data.Dataset which helps in training the model.<br>\nWe need to implement 3 classes\n-  \\_\\_init__ : The method which is useful for setting up the variables\n- \\_\\_getitem__ : The method needed to access each item in the dataset\n- \\_\\_len__ : The method needed to get the length of dataset","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from torch.utils.data import Dataset, DataLoader\nclass MelanomaDataset(Dataset):\n    def __init__(self, df: pd.DataFrame, imfolder: str, transforms_object= None):\n        self.data_frame = df\n        self.path_to_folder = imfolder\n        self.transforms_object = transforms_object\n        \n    def __getitem__(self, index):\n        image_name_at_index = self.data_frame.loc[index,'image_name']\n        load_path = self.path_to_folder +image_name_at_index+'.jpg'\n        image_data = cv2.imread(load_path)\n        if self.transforms_object:\n            image_data = self.transforms_object(image_data)\n        if 'target' in self.data_frame.columns.values:\n            y = self.data_frame.loc[index,'target']\n        else :\n            y = 1\n        return image_data,y\n        \n    def __len__(self):\n        return self.data_frame.shape[0]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Is this the actual Neural network Architecture  ?**\n> Yes. The variable 'arch' is actually a pretrained neural network architecture called Efficientnet-B1 <br>\n> We are build layers over this \"network\" > 128 > 16 > 1 <br>\n> The last layer gives a number whose transformation will give us the probability <br>\n\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"\n\nclass deeper_network(nn.Module):\n    def __init__(self,arch):\n        super(deeper_network,self).__init__()\n        self.arch = arch\n        self.arch._fc = nn.Linear(in_features=1280,out_features=512, bias=True)\n        self.fin_net = nn.Sequential(self.arch,\n                                     nn.Linear(512,128),\n                                     nn.LeakyReLU(),\n                                     nn.Linear(128,16),\n                                     nn.LeakyReLU(),\n                                     nn.Linear(16,1))\n    def forward(self,inputs):\n        output = self.fin_net(inputs)\n        return output","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training Block","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**So what's the next step ?**\n> We will now prepare the data for training with transformation to suit our pipeline<br>\n> The data will be taken in via a dataframe<br>\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv('../input/siim-isic-melanoma-classification/train.csv')\ntest_df = pd.read_csv('../input/siim-isic-melanoma-classification/test.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_transform = transforms.Compose([\n                                    transforms.RandomResizedCrop(size=256,scale=(0.7,1)), # Take 70 - 100 % of the area and scale the image to 256 x 256 size\n                                    transforms.RandomHorizontalFlip(),# Take the image and flip it horizontally or not 50% chance\n                                    transforms.RandomVerticalFlip(), # Take the image and flip it vertically or not 50% chance\n                                    transforms.ToTensor(), # Convert to tensor\n                                    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]) # Adjust the values of image to standardise","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"model_eff = EfficientNet.from_pretrained('efficientnet-b1')\n# print(summary(model_eff,(3, 256, 256)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**What's a dataloader and why do we need it ?**\n> Data loader is a part of torch.utils package and it gives us an iterable object.<br>\n> For training the model we need data in batches with some level of sophistication such as shuffling, batch size etc<br>\n> Data loader can provide all these functionalities for us\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"path_for_jpeg= '../input/siim-isic-melanoma-classification/jpeg/train/'\ntrain_dataset = MelanomaDataset(train_df,path_for_jpeg,transforms_object=train_transform)\ntrain_loader_args = dict(shuffle=True, batch_size=64)\ntrain_loader = data.DataLoader(train_dataset, **train_loader_args)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model Setup","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**How we actually proceed now for training ?**\n> To train the network we need only 3 things <br>\n- THE NETWORK : Yes. Pretty obvious. We need the main network \"deep_net\" mentioned below\n- THE CRITERION : Criterion is a evaluation method which helps the model evaluate the predictions and gives error values on each prediction. Here its 'BCEWithLogitsLoss'\n- THE OPTIMIZER : Optimizer is kind of a correction module. It corrects the model itself by updating values which pleases the criterion. Here we are using 'Adam'","execution_count":null},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"arch = EfficientNet.from_pretrained('efficientnet-b1') \n\n#setup\ndeep_net = deeper_network(arch)\ncriterion = nn.BCEWithLogitsLoss()\noptimizer = optim.Adam(deep_net.parameters())\n\n# Sometimes, I just use my previously trained network and load it just before training again\ndeep_net.load_state_dict(torch.load('../input/effnet-v2/effnet_v2',map_location=torch.device('cpu'))) ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**What is cuda ?**\n> Ahh.. It is a command which enables the use of GPU <br>\n\n**But what's GPU ?**\n> Its fullform is Graphics processing Unit. Inshort it can process things **much** faster CPU <br>\n> Its one of those things that gave Deep learning wings to fly","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.cuda.is_available()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"use_cuda = True\nif use_cuda and torch.cuda.is_available():\n    deep_net.cuda() # converting the model into GPU enabled variable","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model Training","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"model = deep_net\nimport time","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Whats this piece of code ?**\n> Read the comments. This is the crux of all the drama we have been doing. <br>\n> This is how we train the model. If you dont understand. Its ok !","execution_count":null},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"model.train()\nfor e in range(2,4):\n    \n    # variables to log results\n    running_loss = 0.0\n    total_predictions = 0.0\n    correct_predictions = 0.0\n    start_time = time.time()\n    \n    #loop for running the training in batches\n    for batch_idx, (image_data_array, target) in enumerate(train_loader):\n        \n        #setting up batch data \n        optimizer.zero_grad()   # .backward() accumulates gradients\n        image_data_array = image_data_array.float().cuda()\n        target = target.long().cuda() # all data & model on same device\n        \n        #Prediction\n        outputs = model(image_data_array)\n\n        #Measuring the Error\n        loss = criterion(outputs, target.reshape(-1,1).float())\n        \n        #Logging Error\n        predictions = torch.round(torch.sigmoid(outputs))\n        total_predictions += target.size(0)\n        correct_predictions += (target.cpu() ==predictions.squeeze().cpu()).sum().item()\n        running_loss += loss.item()\n        \n        #Correcting the model to reduce the error\n        loss.backward()\n        optimizer.step()\n    \n    acc = (correct_predictions/total_predictions)*100.0\n    end_time = time.time()\n\n    running_loss /= len(train_loader)\n    print('Training Loss: ', round(running_loss,3), 'Time: ',round(end_time - start_time,3), 's')\n    print('Training Accuracy: ', round(acc,3), '%')\n    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**What are we missing ?**\n- We have not at all validated the model. Whether its overfitting or underfitting \n- We havent fine tuned the model to improve accuracy is on validation set\n- We have not played with criterion or optimizers<br>\n\n**But why havent we done all this ^^ ?**\n- I am too lazy to do all of that and explain. But in a forked notebook of this version, I will do all of it and some sophisticated techniques but wont explain.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.save(model.state_dict(), 'effnet_v1')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"# Prediction Block","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**So now we need to predict on test data ?**\n> Yes. Get the test data, pass it through same transformation but DONT SHUFFLE (please)","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-output":true,"collapsed":true},"cell_type":"code","source":"path_for_jpeg= '../input/siim-isic-melanoma-classification/jpeg/test/'\ntest_dataset = MelanomaDataset(test_df,path_for_jpeg,transforms_object=train_transform)\ntest_loader_args = dict(shuffle=False, batch_size=10) # DONT SHUFFLE\ntest_loader = data.DataLoader(test_dataset, **test_loader_args)\nmodel.eval()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Why is there a sigmoid function in the script?**\n> The last output of nueral network is float point number with dimenion 1 which is also unrestricted. While evaluating we use sigmoid inside BCEWithLogitsLoss. Thus while predicting we need to use sigmoid to convert that boundless number into probability.<br>\n\n**What's sigmoid ?**\n> sigmoid(x) = 1/(1 +e^(-x))\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"fin_temp=np.empty((0,))\nfor batch_idx, (image_data_array, target) in enumerate(test_loader):\n    image_data_array = image_data_array.float()#.cuda()\n    target = target.long()#.cuda() # all data & model on same device\n    outputs = model(image_data_array)\n    temp = torch.sigmoid(outputs).cpu().detach().numpy().squeeze()\n    fin_temp = np.concatenate([fin_temp,temp])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"Y_submission = test_df[['image_name']].copy()\nY_submission['target'] = fin_temp","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Are we done ? Can I go home ?**\n> Yeah. Its the end. Upload the csv file and get your ranking on leaderboard.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"Y_submission.to_csv('/kaggle/working/image_v3.csv',index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}