{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"import numpy as np \nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport os\n\n#Pytorch modules\nimport torch\nimport torch.nn as nn\nimport torchvision.transforms as transforms\nimport torch.optim as optim\nimport torchvision.models as models\nfrom torch.utils.data import DataLoader,random_split\nfrom torch.functional import F\nfrom torch.utils.tensorboard import SummaryWriter\n\nfrom sklearn.preprocessing import LabelEncoder\nimport sklearn.metrics as metrics\n\nfrom PIL import Image\n\nimport os","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Load the csv file with all the classes for the training data"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Loading the csv'\ntrain_csv = pd.read_csv('/kaggle/input/landmark-recognition-2020/train.csv')\ntest_csv = pd.read_csv('/kaggle/input/landmark-recognition-2020/sample_submission.csv')\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### To find out how many images we have we take the length of the csv file, and to get the amount of classes we take unique values in the 'landmark_id' column"},{"metadata":{"trusted":true},"cell_type":"code","source":"#How many images and how many classes\nimages_amount_train = len(train_csv)\nclasses_amount_train = len(train_csv['landmark_id'].unique())\n\nprint(f\"In the train-dataset there is {images_amount_train} images from {classes_amount_train} different classes\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Count all the amount of images inside each class\nimage_pr_class = train_csv['landmark_id'].value_counts()\ngroups = pd.DataFrame(image_pr_class)\n\ngroups_new = groups.reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"groups_new.plot(kind='hist',bins=100,figsize=(10,10))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Exploring how many data samples in each class"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Count the amount of images inside each class \nclass_count = train_csv['landmark_id'].value_counts()\nclass_under5 = class_count[class_count < 5]\nclass_between5and10 = class_count[(class_count <= 10) & (class_count >= 5)]\n\nprint(f\"There are {len(class_under5)} classes with under 5 images and {len(class_between5and10)} classes with between 5 and 10 images\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Statistics of amounts of samples \ngroups.describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Limit the data\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv = train_csv.loc[:20000,:]\n\n#Select classes with 10 or above images \n#image_pr_class = train_csv['landmark_id'].value_counts()\n#class_select = image_pr_class[image_pr_class >= 100].index\n\n#train_csv = train_csv.loc[train_csv.landmark_id.isin(class_select)]\n\n#Reset index back to 0\ntrain_csv.reset_index(drop=True, inplace=True)\n\n#Make new label encoder for the new data selection\nlabel_encoder = LabelEncoder()\nlabel_encoder.fit(train_csv.landmark_id.values)\nprint('found classes', len(label_encoder.classes_))\n\ntrain_csv.landmark_id = label_encoder.transform(train_csv.landmark_id)\n\n#Calculate the weigths of the classes\ndef cal_classWeigth(x):\n    return 1-(x/20001)\n\nclasses = train_csv.landmark_id.value_counts()\nclass_weights = classes.apply(cal_classWeigth)\nclass_weights.sort_index(inplace=True)\n\nclass_weights = torch.cuda.FloatTensor(class_weights)\n\nimage_pr_class = train_csv['landmark_id'].value_counts()\ngroups = pd.DataFrame(image_pr_class)\ngroups.to_csv('./images_pr_class')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_csv.landmark_id.value_counts())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Hyperparameters"},{"metadata":{"trusted":true},"cell_type":"code","source":"ID = 1816\nLEARNINGRATE = 0.01\nMOMENTUM = 0.9 #Only used for naming\nBATCH_SIZE = 64\nNUM_CLASSES =  len(label_encoder.classes_) \nNUM_DATASAMPLES = len(train_csv)\nEPOCHS = 10","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Data loader"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Defining the dataset class for how to load the data\nclass Dataset(torch.utils.data.Dataset):\n  def __init__(self, csv_file, image_folder,transform):\n        self.csv = csv_file\n        self.folder = image_folder\n        self.transform = transform\n\n  def __len__(self):\n        return len(self.csv)\n\n  def __getitem__(self, index):\n        image_id = self.csv.iloc[index].id\n        image_path = f\"{self.folder}/{image_id[0]}/{image_id[1]}/{image_id[2]}/{image_id}.jpg\"\n        # Load data and get label\n        X = Image.open(image_path)\n        y = self.csv.iloc[index].landmark_id\n        X = self.transform(X)\n        return X, y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#define the wanted tranformation\ntransform_train=transforms.Compose([\n    transforms.Resize((32,32)),\n    transforms.ToTensor(),\n                             ])\ntransform_val=transforms.Compose([\n    transforms.Resize((32,32)),\n    transforms.ToTensor(),\n                             ])\n\n#Making the dataset from the csv file\ndataset = Dataset(train_csv,\n                        r'/kaggle/input/landmark-recognition-2020/train'\n                        ,transform_val\n                       )\n\nmsk = np.random.rand(len(train_csv)) < 0.9\ntrain = train_csv[msk]\nval = train_csv[~msk]\n\nval_dataset = Dataset(val,\n                        r'/kaggle/input/landmark-recognition-2020/train'\n                        ,transform_val\n                       )\ntrain_dataset = Dataset(train,\n                        r'/kaggle/input/landmark-recognition-2020/train'\n                        ,transform_train\n                       )\n#val_dataset, train_dataset = random_split(dataset = dataset, lengths = [int(len(dataset)*0.1),len(dataset)-int(len(dataset)*0.1)])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Showing 4 random images from 4 random classes"},{"metadata":{"trusted":true},"cell_type":"code","source":"import random\nsample_iter = iter(train_dataset)\n\nrows = 2\ncols = 2\naxes=[]\nfig=plt.figure(figsize=(10,10))\nfor a in range(rows*cols):\n    b = train_dataset.__getitem__(random.randint(0,len(train_dataset)))\n    axes.append( fig.add_subplot(rows, cols, a+1) )\n    subplot_title=(f'Class: {b[1]}')\n    axes[-1].set_title(subplot_title)  \n    plt.imshow(b[0].permute(1, 2, 0))\nfig.tight_layout()    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataloader = DataLoader(train_dataset, batch_size = BATCH_SIZE, shuffle=True, num_workers=0)\nprint(len(train_dataloader))\n\nval_dataloader = DataLoader(val_dataset, batch_size = 1, shuffle=False, num_workers=0)\nprint(len(val_dataloader))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Network"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Select ReNet18 as network\n#ResNet = models.resnet18()\nVGG16 = models.vgg16()\nnet = VGG16\n\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n#Resnet\n\n#ResNet18\n#Change the last layer to fit the classes output\n#net.fc = nn.Linear(in_features=512, out_features=NUM_CLASSES, bias=True)\n\n#Resnet50\n#Change the last layer to fit the classes output\n#net.fc = nn.Linear(in_features=2048, out_features=NUM_CLASSES, bias=True)\n\n#VGG16\nnet.classifier[6] = nn.Linear(in_features=4096, out_features=NUM_CLASSES, bias=True)\n\nnet.to(device)\nprint(device)\nprint(net)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Loss function and opimizer"},{"metadata":{"trusted":true},"cell_type":"code","source":"class_weights.to(device)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(net.parameters(), lr=LEARNINGRATE)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Training loop\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"TrainLoss = []\nValLoss = []\nTrainAcc = []\nTrainAvgAcc = []\nValAcc = []\nValAvgAcc = []\n#EPOCHS\nfor epoch in range(10):  # loop over the dataset multiple times\n    \"\"\"\n    Training loop\n    Training on the training data inside train_dataloader\n    \"\"\"\n    #Create variables to keep track of loss\n    running_loss = 0.0\n    trainrunningloss = 0.0\n    \n    print(f'Epoch: {epoch+1}')\n    \n    #Set network to train mode\n    net.train()\n    \n    #Create arrays to save labels inside\n    correct_labels = []\n    predicted_labels = []\n    \n    \n    for i, data in enumerate(train_dataloader, 0):\n        # get the inputs; data is a list of [inputs, labels]\n        inputs, labels = data[0].to(device), data[1].to(device)\n\n        # zero the parameter gradients\n        optimizer.zero_grad()\n\n        # forward + backward + optimize\n        outputs = net(inputs)\n        loss = criterion(outputs, labels)\n        trainrunningloss += loss.item()\n        \n        loss.backward()\n        optimizer.step()\n        \n        predictions = outputs.max(dim=1)[1]\n        \n        correct_labels.append(labels.cpu().numpy())\n        predicted_labels.append(predictions.detach().cpu().numpy())\n        \n        running_loss += loss.item()\n\n        # print every 100 mini-batches\n        if i % 10 == 9:    \n            print('[%d, %5d] loss: %.3f' %\n                  (epoch + 1, i + 1, running_loss / 10))\n            running_loss = 0.0\n        \n    #Calculating scores for the training loop\n    predicted_labels = np.concatenate(predicted_labels)\n    correct_labels = np.concatenate(correct_labels)\n    \n    normal_accuracy = metrics.accuracy_score(correct_labels,predicted_labels)\n    average_accuracy = metrics.balanced_accuracy_score(correct_labels,predicted_labels)\n    \n    TrainLoss.append(trainrunningloss/len(train_dataloader))\n    TrainAcc.append(normal_accuracy)\n    TrainAvgAcc.append(average_accuracy)\n    \n    print(f'Train, loss: {trainrunningloss/len(train_dataloader)} Normal acc: {normal_accuracy} Avg acc: {average_accuracy}')\n    \n    \"\"\"\n    Validation loop, here the validation data is tested on the model\n    \"\"\"\n    #Create array and variables needed\n    correct_labels = []\n    predicted_labels = []\n    valrunningloss = 0.0\n    \n    #Set the network to evaluation mode\n    net.eval()\n    with torch.no_grad():\n        for i, data in enumerate(val_dataloader, 0):\n            inputs, labels = data[0].to(device), data[1].to(device)\n            outputs = net(inputs)\n            valloss = criterion(outputs, labels)\n            \n            valrunningloss += valloss.item()\n            \n            predictions = outputs.max(dim=1)[1]\n        \n            correct_labels.append(labels.cpu().numpy())\n            predicted_labels.append(predictions.detach().cpu().numpy())\n            \n            \n    ValLoss.append(valrunningloss/len(val_dataloader))\n    \n    \n    #Calculating scores the validation\n    predicted_labels = np.concatenate(predicted_labels)\n    correct_labels = np.concatenate(correct_labels)\n    \n    normal_accuracy = metrics.accuracy_score(correct_labels,predicted_labels)\n    average_accuracy = metrics.balanced_accuracy_score(correct_labels,predicted_labels)\n    \n    print(f'Val, loss: {valrunningloss/len(val_dataloader)} Normal acc: {normal_accuracy} Avg acc: {average_accuracy}')\n    \n    ValAcc.append(normal_accuracy)\n    ValAvgAcc.append(average_accuracy)\n        \n    \nPATH = fr'./{ID}_{LEARNINGRATE}_{MOMENTUM}_{BATCH_SIZE}_{EPOCHS}_{NUM_CLASSES}_{NUM_DATASAMPLES}.pth' \ntorch.save(net.state_dict(), PATH)\nprint('Finished Training')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Saves all the data into a csv file\ndata = {'Train_Loss': TrainLoss, 'Val_Loss': ValLoss, 'Train_Acc': TrainAcc, 'Train_Avg_Acc': TrainAvgAcc,'Val_Acc': ValAcc,'Val_Avg_Acc': ValAvgAcc}\ndf = pd.DataFrame(data)\n\ndf.to_csv(fr'./{ID}_{LEARNINGRATE}_{MOMENTUM}_{BATCH_SIZE}_{EPOCHS}_{NUM_CLASSES}_{NUM_DATASAMPLES}.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Evaluating"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Trainset prediction\ncorrect_labels = []\npredicted_labels = []\ndata_arr = []\nnet.eval()\nwith torch.no_grad():\n    for i, data in enumerate(train_dataloader, 0):\n        inputs, labels = data[0].to(device), data[1].to(device)\n        outputs = net(inputs)\n        predictions = outputs.max(dim=1)[1]\n        \n        correct_labels.append(labels.cpu().numpy())\n        predicted_labels.append(predictions.detach().cpu().numpy())\n\n\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predicted_labels = np.concatenate(predicted_labels)\ncorrect_labels = np.concatenate(correct_labels)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"decoded_predicted_labels =label_encoder.inverse_transform(predicted_labels)\ndecoded_correct_labels = label_encoder.inverse_transform(correct_labels)\ndata = {'predicted labels': predicted_labels, 'correct labels': correct_labels,'decoded predicted labels': decoded_predicted_labels, 'decoded correct labels': decoded_correct_labels}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.DataFrame(data)\ndf.to_csv(r'./labels_train.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Valset prediction\ncorrect_labels = []\npredicted_labels = []\nnet.eval()\nwith torch.no_grad():\n    for i, data in enumerate(val_dataloader, 0):\n        inputs, labels = data[0].to(device), data[1].to(device)\n        outputs = net(inputs)\n        predictions = outputs.max(dim=1)[1]\n\n        correct_labels.append(labels.cpu().numpy())\n        predicted_labels.append(predictions.detach().cpu().numpy())\n\npredicted_labels = np.concatenate(predicted_labels)\ncorrect_labels = np.concatenate(correct_labels)\n\ndecoded_predicted_labels =label_encoder.inverse_transform(predicted_labels)\ndecoded_correct_labels = label_encoder.inverse_transform(correct_labels)\ndata = {'predicted labels': predicted_labels, 'correct labels': correct_labels,'decoded predicted labels': decoded_predicted_labels, 'decoded correct labels': decoded_correct_labels}\n\ndf = pd.DataFrame(data)\ndf.to_csv(r'./labels_val.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Label explore"},{"metadata":{"trusted":true},"cell_type":"code","source":"def createGraph(label_csv,images_pr_class,xlabel,ylabel):\n    #create class dataframe\n    classes = pd.DataFrame(index=label_csv['correct labels'].value_counts().index,columns=('correct','false','images','accuracy'))\n    classes['correct'] = 0\n    classes['false'] = 0\n    classes['images'] = 0\n    classes['accuracy'] = 0\n    \n    for i in range(0,len(label_csv)):\n        predicted_class = label_csv['predicted labels'][i]\n        correct_class = label_csv['correct labels'][i]\n        \n        if predicted_class == correct_class:\n            classes['correct'].loc[correct_class] +=1\n        else:\n            classes['false'].loc[correct_class] +=1\n            \n    for i in enumerate(classes.index,0):\n    \n\n        class_correct = classes['correct'].loc[i[1]].item() \n        class_false = classes['false'].loc[i[1]].item() \n\n\n        classes['images'].loc[i[1]]  = images_pr_class.loc[i[1]].item()\n        classes['accuracy'].loc[i[1]] = (class_correct/(class_correct+class_false))\n        \n    fig, ax = plt.subplots()\n    ax.scatter(classes['accuracy'],classes['images'])\n    ax.set_ylabel('Images pr class')\n    ax.set_xlabel('Accuracy for train set')\n    \n    return classes\n\ntrain_label_csv = pd.read_csv('./labels_train.csv',index_col=0)\nval_label_csv = pd.read_csv('./labels_val.csv',index_col=0)\n\nclasses_train_stats = createGraph(train_label_csv,groups,'Accuracy for train set','Images pr class')\nclasses_val_stats = createGraph(val_label_csv ,groups,'Accuracy for validation set','Images pr class')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classes_train_stats","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classes_val_stats","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Display image\nimage_id = train_csv[train_csv['landmark_id']==834].iloc[0].id\nimage_path = f\"/kaggle/input/landmark-recognition-2020/train/{image_id[0]}/{image_id[1]}/{image_id[2]}/{image_id}.jpg\"\nX = Image.open(image_path)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Submission generation"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Defining the dataset class for how to load the data\nclass Dataset(torch.utils.data.Dataset):\n  def __init__(self, csv_file, image_folder,transform):\n        self.csv = csv_file\n        self.folder = image_folder\n        self.transform = transform\n\n  def __len__(self):\n        return len(self.csv)\n\n  def __getitem__(self, index):\n        image_id = self.csv.iloc[index].id\n        image_path = f\"{self.folder}/{image_id[0]}/{image_id[1]}/{image_id[2]}/{image_id}.jpg\"\n        # Load data and get label\n        X = Image.open(image_path)\n        y = 0\n        X = self.transform(X)\n        return X, y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Test prediction\npredictions_arr = []\ndataset = Dataset(test_csv,\n                        r'/kaggle/input/landmark-recognition-2020/test'\n                        ,transform_val\n                       )\ntest_dataloader = DataLoader(dataset, batch_size = BATCH_SIZE, shuffle=True, num_workers=0)\nnet.eval()\nwith torch.no_grad():\n    for i, data in enumerate(test_dataloader, 0):\n        inputs = data[0].to(device)\n        outputs = net(inputs)\n        predictions = outputs.max(dim=1)[1]\n        \n        predictions_arr.append(predictions.detach().cpu().numpy())\n\npredictions_arr = np.concatenate(predictions_arr)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Make submission file\npredictions_arr =label_encoder.inverse_transform(predictions_arr)\ndata= {'id': test_csv['id'].values, 'landmarks': predictions_arr}\nsubmissionFile = pd.DataFrame(data)\nsubmissionFile.to_csv('./submission.csv')","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}