{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport torch\nfrom PIL import Image\nfrom skimage import io, transform\nimport matplotlib.pyplot as plt\nfrom sklearn.preprocessing import LabelEncoder\nfrom torchvision import datasets, transforms\nfrom torch.utils.data import Dataset, DataLoader\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport os\nimport helper\nfrom tqdm import tqdm\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.cuda.is_available()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"if torch.cuda.is_available():\n    device = torch.device(\"cuda:0\")  # you can continue going on here, like cuda:1 cuda:2....etc. \n#     device = \"cuda\"\n    print(\"Running on the GPU\")\nelse:\n    device = torch.device(\"cpu\")\n#     device = \"cpu\"\n    print(\"Running on the CPU\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.cuda.set_device(device)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# /kaggle/input/landmark-recognition-2020/train/5/5/5/5556e34494b2761d.jpg\ntrain = pd.read_csv('/kaggle/input/landmark-recognition-2020/train.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_freq = train['landmark_id'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_freq.shape[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_freq.describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"So it is There are many many classes with very less photos. If you see the 75% percentile also has only 20 images.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"We will have to do trial and error on what is the suitable minimum no. of images for every label","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"MIN_NUM_IMAGES = 5\nlabel_freq[label_freq>MIN_NUM_IMAGES].shape[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train['landmark_id'].describe()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_labels = label_freq[label_freq>MIN_NUM_IMAGES].index","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_labels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = 150\nCROP_SIZE = 100\ntransform = transforms.Compose([transforms.Resize(IMG_SIZE),\n                                transforms.CenterCrop(CROP_SIZE),\n                                transforms.ToTensor()])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"frame = pd.read_csv('/kaggle/input/landmark-recognition-2020/train.csv')\nframe = frame.loc[frame['landmark_id'].isin(valid_labels), :]\nframe = frame.reset_index(drop=True)\nle = LabelEncoder()\nframe['landmark_id'] = le.fit_transform(frame['landmark_id'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class LandmarksDatasetTrain(Dataset):\n    \"\"\"Landmarks dataset.\"\"\" \n\n    def __init__(self, landmarks_frame, root_dir, transform=None):\n        \"\"\"\n        Args:\n            csv_file (string): Path to the csv file with annotations.\n            root_dir (string): Directory with all the images.\n            transform (callable, optional): Optional transform to be applied\n                on a sample.\n        \"\"\"\n        self.landmarks_frame = landmarks_frame\n        self.root_dir = root_dir\n        self.transform = transform \n\n    def __len__(self):\n        return len(self.landmarks_frame)\n\n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n        img_name = os.path.join(self.root_dir,self.landmarks_frame.loc[idx, 'id'][0],self.landmarks_frame.loc[idx, 'id'][1], self.landmarks_frame.loc[idx, 'id'][2], self.landmarks_frame.loc[idx, 'id'])\n        img_name += \".jpg\"\n        image = Image.open(img_name)\n        landmarks = self.landmarks_frame.loc[idx, 'landmark_id']\n        sample = {'image': image, 'landmarks': landmarks}\n\n        if self.transform:\n            sample['image'] = self.transform(sample['image'])\n            sample['landmarks'] = torch.tensor(sample['landmarks'])\n\n        return sample","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class LandmarksDatasetTest(Dataset):\n    \"\"\"Landmarks dataset.\"\"\" \n\n    def __init__(self, test_img_list, root_dir, transform=None):\n        self.test_img_list = test_img_list \n        self.root_dir = root_dir\n        self.transform = transform \n\n    def __len__(self):\n        return len(self.test_img_list)\n\n    def __getitem__(self, idx):\n        img_name = os.path.join(self.root_dir,self.test_img_list[idx])\n        image = Image.open(img_name)\n        sample = {'image': image}\n\n        if self.transform:\n            sample['image'] = self.transform(sample['image'])\n\n        return sample","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset_train = LandmarksDatasetTrain(landmarks_frame = frame,\n                                      root_dir='/kaggle/input/landmark-recognition-2020/train',\n                                      transform=transform)\n\n\ntest_images = []    \nfor dirpath, dirname, filenames in os.walk('/kaggle/input/landmark-recognition-2020/test/'):\n    for f in filenames:\n        if not os.path.basename(dirpath).startswith('.'):\n            test_images.append(\"/kaggle/input/landmark-recognition-2020/test/\"+f[0]+\"/\"+f[1]+\"/\"+f[2]+\"/\"+f)\n\ndataset_test = LandmarksDatasetTest(test_img_list=test_images,\n                                     root_dir='/kaggle/input/landmark-recognition-2020/test',\n                                     transform=transform)\n\nprint(f'\\ntrain images:')\nfor i in range(len(dataset_train)):\n    sample = dataset_train[i]\n    print(type(sample['landmarks']))\n    print(i, sample['image'].size(), sample['landmarks'].size())\n    \n    if i == 3:\n        break\n    \nprint(f'\\ntest images:')\nfor i in range(len(dataset_test)):\n    sample = dataset_test[i]\n    print(i, sample['image'].size())\n    \n    if i == 3:\n        break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_loader = DataLoader(dataset_train, batch_size=4, shuffle=True, num_workers=4, drop_last=False)\ntest_loader = DataLoader(dataset_test, batch_size=4, shuffle=True, num_workers=4, drop_last=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"frame['landmark_id'].nunique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class Net(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.fc1 = nn.Linear(CROP_SIZE*CROP_SIZE*3, 512)\n        self.conv1d1 = nn.Conv1d(512, 64, 3, stride=2)\n        self.fc2 = nn.Linear(64, 128)\n        self.conv1d2 = nn.Conv1d(128, 64, 3, stride=2)\n        self.fc3 = nn.Linear(64, 256)\n        self.conv1d3 = nn.Conv1d(256, 64, 3, stride=2)\n        self.fc4 = nn.Linear(64, 128)\n        self.fc4 = nn.Linear(256, 128)\n        self.fc5 = nn.Linear(128, 64)\n        self.fc6 = nn.Linear(64, 32)\n        self.fc7 = nn.Linear(32, 64)\n        self.fc8 = nn.Linear(64, frame['landmark_id'].nunique())\n\n    def forward(self, x):\n        x = F.relu(self.conv1d1(self.fc1(x)))\n        x = F.relu(self.conv1d2(self.fc2(x)))\n        x = F.relu(self.conv1d3(self.fc3(x)))\n        x = F.relu(self.fc4(x))\n        x = F.relu(self.fc5(x))\n        x = F.relu(self.fc6(x))\n        x = F.relu(self.fc7(x))\n        x = self.fc8(x)\n        return F.log_softmax(x, dim=1)\n\nnet = Net()\nprint(net)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch.optim as optim\n\nloss_function = nn.CrossEntropyLoss()\n# optimizer = optim.Adam(net.parameters(), lr=0.001)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.cuda.device_count()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# net.to(device)\nnet.to(torch.device('cuda:0'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!nvidia-smi","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.cuda.get_device_name()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for epoch in range(3): # 3 full passes over the data\n    optimizer = optim.Adam(net.parameters(), lr=0.001)\n    for data in tqdm(train_loader):  # `data` is a batch of data\n        X = data['image'].to(device)  # X is the batch of features\n        y = data['landmarks'].to(device) # y is the batch of targets.\n        optimizer.zero_grad()  # sets gradients to 0 before loss calc. You will do this likely every step.\n        output = net(X.view(-1,CROP_SIZE*CROP_SIZE*3))  # pass in the reshaped batch\n#         print(np.argmax(output))\n#         print(y)\n        loss = F.nll_loss(output, y)  # calc and grab the loss value\n        loss.backward()  # apply this loss backwards thru the network's parameters\n        optimizer.step()  # attempt to optimize weights to account for loss/gradients\n\n    print(loss)  # print loss. We hope loss (a measure of wrong-ness) declines! ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# torch.save(net.state_dict(), '/kaggle/working/pytorch_model')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# correct = 0\n# total = 0\n\n# with torch.no_grad():\n#     for data in testset:\n#         X, y = data\n#         output = net(X.view(-1,784))\n#         #print(output)\n#         for idx, i in enumerate(output):\n#             #print(torch.argmax(i), y[idx])\n#             if torch.argmax(i) == y[idx]:\n#                 correct += 1\n#             total += 1\n\n# print(\"Accuracy: \", round(correct/total, 3))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# # From: https://www.kaggle.com/davidthaler/gap-metric\n# def GAP_vector(pred, conf, true, return_x=False):\n#     '''\n#     Compute Global Average Precision (aka micro AP), the metric for the\n#     Google Landmark Recognition competition. \n#     This function takes predictions, labels and confidence scores as vectors.\n#     In both predictions and ground-truth, use None/np.nan for \"no label\".\n\n#     Args:\n#         pred: vector of integer-coded predictions\n#         conf: vector of probability or confidence scores for pred\n#         true: vector of integer-coded labels for ground truth\n#         return_x: also return the data frame used in the calculation\n\n#     Returns:\n#         GAP score\n#     '''\n#     x = pd.DataFrame({'pred': pred, 'conf': conf, 'true': true})\n#     x.sort_values('conf', ascending=False, inplace=True, na_position='last')\n#     x['correct'] = (x.true == x.pred).astype(int)\n#     x['prec_k'] = x.correct.cumsum() / (np.arange(len(x)) + 1)\n#     x['term'] = x.prec_k * x.correct\n#     gap = x.term.sum() / x.true.count()\n#     if return_x:\n#         return gap, x\n#     else:\n#         return gap","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}