{"cells":[{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"from IPython.display import Image\nImage(\"../input/landmark-recognition-2020/train/0/0/0/0000059611c7d079.jpg\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"***Google Landmark Recognition 2020***\n\nLabel famous (and not-so-famous) landmarks in images\n\nThis is he third Landmark Recognition competition of the series. Did you ever go through your vacation photos and ask yourself: What is the name of this temple I visited in China? Who created this monument I saw in France? Landmark recognition can help! This technology can predict landmark labels directly from image pixels, to help people better understand and organize their photo collections. This competition challenges Kagglers to build models that recognize the correct landmark (if any) in a dataset of challenging test images.\n\n","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**Note - This is an ongoing work and I will keep adding more section as time progresses**","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**Credits ** [medium](https://towardsdatascience.com/histograms-in-image-processing-with-skimage-python-be5938962935)","execution_count":null},{"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 cv2\nfrom glob import glob\nimport gc\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\n%matplotlib inline\nimport matplotlib.pyplot as plt\nfrom IPython.display import Image,display\nimport seaborn as sns\nimport matplotlib.image as mpimg\nimport scipy.spatial.distance as dist\nfrom sklearn.model_selection import train_test_split\nfrom skimage.measure import compare_ssim\nimport os\n\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":"train = pd.read_csv('/kaggle/input/landmark-recognition-2020/train.csv')\ntrain.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Let's check for any missing values in the train label df**","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"missing = train.isnull().sum()\nall_val = train.count()\n\nmissing_train = pd.concat([missing, all_val], axis=1, keys=['Missing', 'AllObservations'])\nmissing_train","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Looks all good.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**Let's look at the class distribution**","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"## Distinct classes\nprint(\"Distinct number of classes is :\" + str(train['landmark_id'].nunique()))","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"plt.figure(figsize = (8, 8))\nplt.title('Landmark Classes Density plot')\nsns.kdeplot(train['landmark_id'], color=\"blue\", shade=True)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Looks even with no such long tails on either side. Let's look at cummulative distribution and see how image counts by classes contribute towards total images","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"landmark_id_count = pd.DataFrame(train.groupby(['landmark_id'])['landmark_id'].count())\nlandmark_id_count.rename(columns={'landmark_id': 'Count_Images'}, inplace=True)\nlandmark_id_count.reset_index(inplace=True)\nlandmark_id_count.sort_values(by=['Count_Images'],ascending=False, inplace=True)\nlandmark_id_count['Cummulative_Count'] = landmark_id_count['Count_Images'].cumsum()\nlandmark_id_count['Cummulative_Pctg']= landmark_id_count['Cummulative_Count']/landmark_id_count['Count_Images'].sum()\nlandmark_id_count['Row_id'] = np.arange(len(landmark_id_count))\nfig = plt.figure()\nax = plt.axes()\nax.plot(landmark_id_count['Row_id'], landmark_id_count['Cummulative_Pctg']);\nax.set(xlabel='Count of Classes', ylabel='Cummulative %',\n       title='Cummulative distribution of images by class count');","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Top 10 landmarks with most images in the train set**","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"landmark_id_count[['landmark_id','Count_Images']].head(10)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Landmark id  '138982' has more than 6000 images. Other than Top 7 clasess in this table, every other class has less than 1000 images","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"print(\"Number of classes that contribute 95% of total images is: \"+ str(len(landmark_id_count[landmark_id_count['Cummulative_Pctg']<=0.95])))\nprint(\"Number of classes that contribute 99% of total images is: \"+ str(len(landmark_id_count[landmark_id_count['Cummulative_Pctg']<=0.99])))\nprint(str(train['landmark_id'].nunique()- len(landmark_id_count[landmark_id_count['Cummulative_Pctg']<=0.99]))+ \" Classes contribute just about remaining 1% of images\")\nprint(\"Number of classes with just two images is:\"+ str(len(landmark_id_count[landmark_id_count['Count_Images']<=2])))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Looks like a nice evenly distributed classes of images. Let's look at some sample images from classes where we have got lot of data vs. less data**","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"mainPath = '/kaggle/input/landmark-recognition-2020/train/'\nall_img_paths = [y for x in os.walk(mainPath) for y in glob(os.path.join(x[0], '*.jpg'))]\nall_filenames = []\nfor filepath in all_img_paths:\n    FileName = os.path.basename(filepath)\n    all_filenames.append(FileName)\npath_dict = dict(zip(all_filenames,all_img_paths))","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"##Getting the list of ids where top 5 and bottom 5 categories\ntop5_cats = landmark_id_count[landmark_id_count['Row_id']<=4].landmark_id.tolist()\nbottom5_cats = landmark_id_count[landmark_id_count['Row_id']>=(landmark_id_count['Row_id'].max()-4)].landmark_id.tolist()","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"print(\"Top 5 image categories are : \" + str(top5_cats))\nprint(\"Bottom 5 image categories are : \" + str(bottom5_cats))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Looking at Top 5 categories with 4 images each**\n\nThese are samples of Landmarks where we have got lot of images","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"train['image']=train['id']+str(\".jpg\")","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"for img_cat in top5_cats:\n    process_img_lst = train[train['landmark_id']==img_cat].image.tolist()[0:4]\n    full_img_paths = [path_dict[x] for x in process_img_lst]\n    print(\"Sample image in Category:\" + str(img_cat))\n    img0 = mpimg.imread(full_img_paths[0])\n    img1 = mpimg.imread(full_img_paths[1])\n    img2 = mpimg.imread(full_img_paths[2])\n    img3 = mpimg.imread(full_img_paths[3])\n    \n    fig, ((ax0,ax1),(ax2,ax3)) = plt.subplots(nrows=2,ncols=2,figsize=(15,10))\n    ax0.imshow(img0)\n    ax0.set_title(\"Image 1\")\n    ax1.imshow(img1)\n    ax1.set_title(\"Image 2\")\n    ax2.imshow(img2)\n    ax2.set_title(\"Image 3\")\n    ax3.imshow(img3)\n    ax3.set_title(\"Image 4\")\n    plt.show()\n        \n    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Lets look at some samples which have only 2 images per categories.**\n\nThese are the images that will need creative data augmentation strategy to handle class imbalance","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"for img_cat in bottom5_cats:\n    process_img_lst = train[train['landmark_id']==img_cat].image.tolist()[0:2]\n    full_img_paths = [path_dict[x] for x in process_img_lst]\n    print(\"Sample image in Category:\" + str(img_cat))\n    img0 = mpimg.imread(full_img_paths[0])\n    img1 = mpimg.imread(full_img_paths[1])\n        \n    fig, ((ax0,ax1)) = plt.subplots(nrows=1,ncols=2,figsize=(15,10))\n    ax0.imshow(img0)\n    ax0.set_title(\"Image 1\")\n    ax1.imshow(img1)\n    ax1.set_title(\"Image 2\")\n   \n    plt.show()\n        ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"It looks like that for many of these classes that have just two images in the training data, are that of the exact same place with different orientation. Let's check the same samples that we visualized above\n\nWe will use structural similarity to do an initial assesment of this.","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"for img_cat in bottom5_cats:\n    process_img_lst = train[train['landmark_id']==img_cat].image.tolist()[0:2]\n    full_img_paths = [path_dict[x] for x in process_img_lst]\n    print(\"Structural similarity between images in Category:\" + str(img_cat))\n    img0 = cv2.imread(full_img_paths[0])\n    img0 = cv2.resize(img0, (512, 512)) \n    img0 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY)\n    img1 = cv2.imread(full_img_paths[1])\n    img1 = cv2.resize(img1, (512, 512)) \n    img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)\n    (score, diff) = compare_ssim(img0, img1, full=True)\n    diff = (diff * 255).astype(\"uint8\")\n    print(\"SSIM: {}\".format(score))\n    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Comparing the same set of 4 images  in classes where we have lots of data (we printed them in the previous cells)","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"for img_cat in top5_cats:\n    process_img_lst = train[train['landmark_id']==img_cat].image.tolist()[0:4]\n    full_img_paths = [path_dict[x] for x in process_img_lst]\n    print(\"Structural similarity between images in Category:\" + str(img_cat))\n    img0 = cv2.imread(full_img_paths[0])\n    img0 = cv2.resize(img0, (512, 512)) \n    img0 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY)\n    img1 = cv2.imread(full_img_paths[1])\n    img1 = cv2.resize(img1, (512, 512)) \n    img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)\n    img2 = cv2.imread(full_img_paths[2])\n    img2 = cv2.resize(img2, (512, 512)) \n    img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)\n    img3 = cv2.imread(full_img_paths[3])\n    img3 = cv2.resize(img3, (512, 512)) \n    img3 = cv2.cvtColor(img3, cv2.COLOR_BGR2GRAY)\n    \n    (score, diff) = compare_ssim(img0, img1, full=True)\n    diff = (diff * 255).astype(\"uint8\")\n    print(\"SSIM between first two: {}\".format(score))\n    (score, diff) = compare_ssim(img2, img3, full=True)\n    diff = (diff * 255).astype(\"uint8\")\n    print(\"SSIM between last two: {}\".format(score))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The structural similarity of the Image classes with more data are generally a bit lower than the classes with just two images. This could mean that the classes with more images have a wide variety of images and shots. Let's explore this in bit more details.\n\nLet's see if we can use SSIM to find any similar images in the test set","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"mainTestPath = '/kaggle/input/landmark-recognition-2020/test/'\nall_Testimg_paths = [y for x in os.walk(mainTestPath) for y in glob(os.path.join(x[0], '*.jpg'))]\nall_Testfilenames = []\nfor filepath in all_Testimg_paths:\n    FileName = os.path.basename(filepath)\n    all_Testfilenames.append(FileName)\npath_dict_test = dict(zip(all_Testfilenames,all_Testimg_paths))","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"process_img_lst = train[train['landmark_id']==bottom5_cats[0]].image.tolist()[0]\nfull_img_paths = path_dict[process_img_lst]\nprint(\"calculating Structural similarity with all test images:\" )\nimg0 = cv2.imread(full_img_paths)\nimg0 = cv2.resize(img0, (512, 512)) \nimg0 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY)\ntest_img_ssim = {}\nfor filepath in all_Testimg_paths:\n\n    FileName = os.path.basename(filepath)\n    img2 = cv2.imread(filepath)\n    img2 = cv2.resize(img2, (512, 512)) \n    img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)\n    (score, diff) = compare_ssim(img0, img2, full=True)\n    diff = (diff * 255).astype(\"uint8\")\n    test_img_ssim[FileName]=score","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"most_sim_test =max(test_img_ssim, key=test_img_ssim.get)\nprint(most_sim_test,path_dict_test[most_sim_test])","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"process_img_lst = train[train['landmark_id']==bottom5_cats[0]].image.tolist()[0]\nfull_img_paths = path_dict[process_img_lst]\nimg0 = cv2.imread(full_img_paths)\nimg1 = cv2.imread(path_dict_test[most_sim_test])\n\nfig, ((ax0,ax1)) = plt.subplots(nrows=1,ncols=2,figsize=(15,10))\nax0.imshow(img0)\nax0.set_title(\"Train Image\")\nax1.imshow(img1)\nax1.set_title(\"Test Image\")\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**This is quite funny!! There is no apparent similarity in the two raw images. Maybe it has something to do  with resizing and COLOR_BGR2GRAY transformation we did. Let's implement those and review the images again**","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"process_img_lst = train[train['landmark_id']==bottom5_cats[0]].image.tolist()[0]\nfull_img_paths = path_dict[process_img_lst]\nimg0 = cv2.imread(full_img_paths)\nimg0 = cv2.resize(img0, (512, 512)) \nimg0 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY)\nimg1 = cv2.imread(path_dict_test[most_sim_test])\nimg1 = cv2.resize(img1, (512, 512)) \nimg1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)\n\nfig, ((ax0,ax1)) = plt.subplots(nrows=1,ncols=2,figsize=(15,10))\nax0.imshow(img0)\nax0.set_title(\"Train Image\")\nax1.imshow(img1)\nax1.set_title(\"Test Image\")\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Looks like our hypothesis was true to some extent. Looks like by reszing the test image, we stretched the section of helicopter blades and that has lot of similarity with the cross at the top of the Church. Furthermore there are more sections in the sky in test image that now look very similar to parts of train image. Morale of the story - we need to be careful with the transformations so that we don't distort the images too much**","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**Structural similarity isn't quite able to give us any more details into similarity/difference between images. Let's look at some other ways to investigate this.**","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Let's plot intensity histograms to see this in more details","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"img0 = cv2.imread(full_img_paths)\n\ntrain_hist = plt.hist(img0.ravel(), bins = 256, color = 'orange', )\ntrain_hist = plt.hist(img0[:, :, 0].ravel(), bins = 256, color = 'red', alpha = 0.5)\ntrain_hist = plt.hist(img0[:, :, 1].ravel(), bins = 256, color = 'Green', alpha = 0.5)\ntrain_hist = plt.hist(img0[:, :, 2].ravel(), bins = 256, color = 'Blue', alpha = 0.5)\ntrain_hist = plt.xlabel('Intensity Value')\ntrain_hist = plt.ylabel('Count')\ntrain_hist = plt.legend(['Total', 'Red Channel', 'Green Channel', 'Blue Channel'])\nprint('Intensity Histogram of Train Image')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's do a similar plot for the selected test image that had the highest Structural similarity with the train image","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"img1 = cv2.imread(path_dict_test[most_sim_test])\n\ntest_hist = plt.hist(img1.ravel(), bins = 256, color = 'orange', )\ntest_hist = plt.hist(img1[:, :, 0].ravel(), bins = 256, color = 'red', alpha = 0.5)\ntest_hist = plt.hist(img1[:, :, 1].ravel(), bins = 256, color = 'Green', alpha = 0.5)\ntest_hist = plt.hist(img1[:, :, 2].ravel(), bins = 256, color = 'Blue', alpha = 0.5)\ntest_hist = plt.xlabel('Intensity Value')\ntest_hist = plt.ylabel('Count')\ntest_hist = plt.legend(['Total', 'Red Channel', 'Green Channel', 'Blue Channel'])\nprint('Intensity Histogram of Test Image')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"These two images don't look that similar anymore. \n\nLet's look at similar plots for one of the minority classes where we had just two pictures each.","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"process_img_lst = train[train['landmark_id']==bottom5_cats[0]].image.tolist()[0:2]\nfull_img_paths = [path_dict[x] for x in process_img_lst]\nprint(\"Images in Category:\" + str(img_cat))\nimg0 = cv2.imread(full_img_paths[0])\nimg1 = cv2.imread(full_img_paths[1])\nfig, ((ax0,ax1)) = plt.subplots(nrows=1,ncols=2,figsize=(15,10))\nax0.imshow(img0)\nax0.set_title(\"First Image\")\nax1.imshow(img1)\nax1.set_title(\"Second Image\")\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Let's look at Intensity Histograms of these two images one by one**","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"process_img_lst = train[train['landmark_id']==bottom5_cats[0]].image.tolist()[0:2]\nfull_img_paths = [path_dict[x] for x in process_img_lst]\nprint(\"Intensity Histogram for images in Category:\" + str(img_cat))\nprint('Intensity Histogram of First Image')\nimg0 = cv2.imread(full_img_paths[0])\nimg1 = cv2.imread(full_img_paths[1])\nimg_hist0 = plt.hist(img0.ravel(), bins = 256, color = 'orange', )\nimg_hist0 = plt.hist(img0[:, :, 0].ravel(), bins = 256, color = 'red', alpha = 0.5)\nimg_hist0 = plt.hist(img0[:, :, 1].ravel(), bins = 256, color = 'Green', alpha = 0.5)\nimg_hist0 = plt.hist(img0[:, :, 2].ravel(), bins = 256, color = 'Blue', alpha = 0.5)\nimg_hist0 = plt.xlabel('Intensity Value')\nimg_hist0 = plt.ylabel('Count')\nimg_hist0 = plt.legend(['Total', 'Red Channel', 'Green Channel', 'Blue Channel'])\n","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"print(\"Intensity Histogram for images in Category:\" + str(img_cat))\nprint('Intensity Histogram of Second Image')\nimg1 = cv2.imread(full_img_paths[1])\nimg_hist1 = plt.hist(img1.ravel(), bins = 256, color = 'orange', )\nimg_hist1 = plt.hist(img1[:, :, 0].ravel(), bins = 256, color = 'red', alpha = 0.5)\nimg_hist1 = plt.hist(img1[:, :, 1].ravel(), bins = 256, color = 'Green', alpha = 0.5)\nimg_hist1 = plt.hist(img1[:, :, 2].ravel(), bins = 256, color = 'Blue', alpha = 0.5)\nimg_hist1 = plt.xlabel('Intensity Value')\nimg_hist1 = plt.ylabel('Count')\nimg_hist1 = plt.legend(['Total', 'Red Channel', 'Green Channel', 'Blue Channel'])\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"These two Intensity Histograms look much more similar visually in their color profile. \n\nLet's look at two images from majority classes as well to confirm this hypothesis","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"process_img_lst = train[train['landmark_id']==top5_cats[2]].image.tolist()[0:2]\nfull_img_paths = [path_dict[x] for x in process_img_lst]\nprint(\"Images in Category:\" + str(img_cat))\nimg0 = cv2.imread(full_img_paths[0])\nimg1 = cv2.imread(full_img_paths[1])\nfig, ((ax0,ax1)) = plt.subplots(nrows=1,ncols=2,figsize=(15,10))\nax0.imshow(img0)\nax0.set_title(\"First Image\")\nax1.imshow(img1)\nax1.set_title(\"Second Image\")\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Let's plot the intensity histograms of these two images one by one**","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"process_img_lst = train[train['landmark_id']==top5_cats[2]].image.tolist()[0:2]\nfull_img_paths = [path_dict[x] for x in process_img_lst]\nprint(\"Intensity Histogram for images in Category:\" + str(img_cat))\nprint('Intensity Histogram of First Image')\nimg0 = cv2.imread(full_img_paths[0])\nimg_hist0 = plt.hist(img0.ravel(), bins = 256, color = 'orange', )\nimg_hist0 = plt.hist(img0[:, :, 0].ravel(), bins = 256, color = 'red', alpha = 0.5)\nimg_hist0 = plt.hist(img0[:, :, 1].ravel(), bins = 256, color = 'Green', alpha = 0.5)\nimg_hist0 = plt.hist(img0[:, :, 2].ravel(), bins = 256, color = 'Blue', alpha = 0.5)\nimg_hist0 = plt.xlabel('Intensity Value')\nimg_hist0 = plt.ylabel('Count')\nimg_hist0 = plt.legend(['Total', 'Red Channel', 'Green Channel', 'Blue Channel'])\n","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"print(\"Intensity Histogram for images in Category:\" + str(img_cat))\nprint('Intensity Histogram of Second Image')\nimg1 = cv2.imread(full_img_paths[1])\nimg_hist1 = plt.hist(img1.ravel(), bins = 256, color = 'orange', )\nimg_hist1 = plt.hist(img1[:, :, 0].ravel(), bins = 256, color = 'red', alpha = 0.5)\nimg_hist1 = plt.hist(img1[:, :, 1].ravel(), bins = 256, color = 'Green', alpha = 0.5)\nimg_hist1 = plt.hist(img1[:, :, 2].ravel(), bins = 256, color = 'Blue', alpha = 0.5)\nimg_hist1 = plt.xlabel('Intensity Value')\nimg_hist1 = plt.ylabel('Count')\nimg_hist1 = plt.legend(['Total', 'Red Channel', 'Green Channel', 'Blue Channel'])\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**The similarity is quite visible in this case as well. Keeping the RGB channels in the images while training may help us capture meaningful differences in images and help train models better.**","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**Now we will  make a smaller and trainable subset of images as Kaggle resources are not enough to train all images at once.**","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Taking a small 10% stratified sample is also quite large for Kaggle kernel. So we will now try with top 100 classes and see how Transfer Learning works.\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"path_df = pd.DataFrame(path_dict.items())\npath_df.rename(columns={ path_df.columns[0]: \"image\" }, inplace = True)\npath_df.rename(columns={ path_df.columns[1]: \"path\" }, inplace = True)\ntrain['image']=train['id']+str(\".jpg\")\ntrain_all = pd.merge(train, path_df, on='image')\ndel path_df,path_dict,all_img_paths,all_filenames\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"##Plz ignore the dataframe naming convention. I borrowed from my other kernel and didn't bother making changes :P\nfreq_ct_df_top100 = landmark_id_count.iloc[:100]\ntop100_class = freq_ct_df_top100['landmark_id'].tolist()\ntop100class_train = train_all[train_all['landmark_id'].isin (top100_class) ]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def getTrainParams():\n    data = top100class_train.copy()\n    le = preprocessing.LabelEncoder()\n    data['label'] = le.fit_transform(data['landmark_id'])\n    lbls = top100class_train['landmark_id'].tolist()\n    lb = LabelBinarizer()\n    labels = lb.fit_transform(lbls)\n    \n    return np.array(top100class_train['path'].tolist()),np.array(labels),le","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size = 64\nseed = 42\nshape = (224, 224, 3) ##desired shape of the image for resizing purposes\nval_sample = 0.1 # 10 % as validation sample","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"**Lets import some libraries for creating the models**","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import tensorflow as tf\nimport skimage.io\nfrom skimage.transform import resize\nfrom imgaug import augmenters as iaa\nfrom sklearn import preprocessing\nfrom sklearn.preprocessing import LabelBinarizer,LabelEncoder\nfrom sklearn.utils.class_weight import compute_class_weight\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers import Input, Add, Dense, Dropout, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D, AveragePooling2D, MaxPooling2D, GlobalMaxPooling2D,GlobalAveragePooling2D,Concatenate, ReLU, LeakyReLU,Reshape, Lambda\nfrom tensorflow.keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, ReduceLROnPlateau\nfrom tensorflow.keras.optimizers import Adam,SGD\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.models import Sequential, load_model, Model\nfrom tensorflow.keras.callbacks import LearningRateScheduler\nfrom tensorflow.keras.applications.xception import Xception \nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.applications.vgg16 import preprocess_input\nfrom tensorflow.keras.applications.vgg16 import decode_predictions\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras import metrics\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.applications.imagenet_utils import preprocess_input\nfrom tqdm import tqdm\nimport imgaug as ia\nfrom imgaug import augmenters as iaa\nimport keras.backend as K\nK.set_image_data_format('channels_last')\nK.set_learning_phase(1)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Credit to Michal Haltuf from whose kernel I had first learnt Data Generators two years back. You can check out his kernel here: https://www.kaggle.com/rejpalcz/cnn-128x128x4-keras-from-scratch-lb-0-328","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class Landmark2020_DataGenerator(tf.keras.utils.Sequence):\n    def __init__(self, paths, labels, batch_size, shape, shuffle = False, use_cache = False, augment = False):\n        self.paths, self.labels = paths, labels\n        self.batch_size = batch_size\n        self.shape = shape\n        self.shuffle = shuffle\n        self.use_cache = use_cache\n        self.augment = augment\n        if use_cache == True:\n            self.cache = np.zeros((paths.shape[0], shape[0], shape[1], shape[2]), dtype=np.float16)\n            self.is_cached = np.zeros((paths.shape[0]))\n        self.on_epoch_end()\n    \n    def __len__(self):\n        return int(np.ceil(len(self.paths) / float(self.batch_size)))\n    \n    def __getitem__(self, idx):\n        indexes = self.indexes[idx * self.batch_size : (idx+1) * self.batch_size]\n\n        paths = self.paths[indexes]\n        X = np.zeros((paths.shape[0], self.shape[0], self.shape[1], self.shape[2]))\n        # Generate data\n        if self.use_cache == True:\n            X = self.cache[indexes]\n            for i, path in enumerate(paths[np.where(self.is_cached[indexes] == 0)]):\n                image = self.__load_image(path)\n                self.is_cached[indexes[i]] = 1\n                self.cache[indexes[i]] = image\n                X[i] = image\n        else:\n            for i, path in enumerate(paths):\n                X[i] = self.__load_image(path)\n\n        y = self.labels[indexes]\n                \n        if self.augment == True:\n            seq = iaa.Sequential([\n                iaa.OneOf([\n                    iaa.Fliplr(0.5), # horizontal flips\n                    \n                    iaa.ContrastNormalization((0.75, 1.5)),\n                    iaa.AdditiveGaussianNoise(loc=0, scale=(0.0, 0.05*255), per_channel=0.5),\n                    iaa.Multiply((0.8, 1.2), per_channel=0.2),\n                    \n                    iaa.Affine(rotate=0),\n                    #iaa.Affine(rotate=90),\n                    #iaa.Affine(rotate=180),\n                    #iaa.Affine(rotate=270),\n                    iaa.Fliplr(0.5),\n                    #iaa.Flipud(0.5),\n                ])], random_order=True)\n\n            X = np.concatenate((X, seq.augment_images(X), seq.augment_images(X), seq.augment_images(X)), 0)\n            y = np.concatenate((y, y, y, y), 0)\n        \n        return X, y\n    \n    def on_epoch_end(self):\n        \n        # Updates indexes after each epoch\n        self.indexes = np.arange(len(self.paths))\n        if self.shuffle == True:\n            np.random.shuffle(self.indexes)\n\n    def __iter__(self):\n        \"\"\"Create a generator that iterate over the Sequence.\"\"\"\n        for item in (self[i] for i in range(len(self))):\n            yield item\n            \n    def __load_image(self, path):\n        image_norm = skimage.io.imread(path)/255.0\n        \n\n        im = resize(image_norm, (shape[0], shape[1],shape[2]), mode='reflect')\n        return im","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def create_model(input_shape, n_out):\n    inp = Input(input_shape)\n    pretrain_model = Xception(include_top=False, weights='imagenet', input_tensor=inp)\n    #x = pretrain_model.get_layer(name=\"block_13_expand_relu\").output\n    x = pretrain_model.output\n    \n    x = GlobalAveragePooling2D()(x)\n    x = Dropout(0.25)(x)\n    x = Dense(n_out, activation=\"sigmoid\")(x)\n    \n    ##Uncomment if you want to train few more layers before the head\n    #for layer in pretrain_model.layers[:160]:\n        #layer.trainable = False\n    \n    for layer in pretrain_model.layers:\n        layer.trainable = False\n        \n    return Model(inp, x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.metrics import categorical_accuracy,top_k_categorical_accuracy\ndef top_5_accuracy(y_true, y_pred):\n    return top_k_categorical_accuracy(y_true, y_pred, k=5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"nlabls = top100class_train['landmark_id'].nunique()\nmodel = create_model(input_shape=(224,224,3), n_out=nlabls)\nmodel.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc',top_5_accuracy])\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"paths, labels,_ = getTrainParams()\nkeys = np.arange(paths.shape[0], dtype=np.int)  \nnp.random.seed(seed)\nnp.random.shuffle(keys)\nlastTrainIndex = int((1-val_sample) * paths.shape[0])\n\npathsTrain = paths[0:lastTrainIndex]\nlabelsTrain = labels[0:lastTrainIndex]\n\npathsVal = paths[lastTrainIndex:]\nlabelsVal = labels[lastTrainIndex:]\n\nprint(paths.shape, labels.shape)\nprint(pathsTrain.shape, labelsTrain.shape, pathsVal.shape, labelsVal.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator = Landmark2020_DataGenerator(pathsTrain, labelsTrain, batch_size, shape, use_cache=False, augment = False, shuffle = True)\nval_generator = Landmark2020_DataGenerator(pathsVal, labelsVal, batch_size, shape, use_cache=False, shuffle = False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Due to insufficient resources we can demonstrate only 1 epoch in Kaggle environment. If you try and run more than epoch, you may end up like this. I am going to load a pre-trained model for 100 classes for 5 epochs and then train for one additional epoch. Also in this version I have switched to Xception from ResNet as that was giving better results","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"model.load_weights('/kaggle/input/xception-pass1/Xception_pass1.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"![](data:image/jpeg;base64,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)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#clr = CyclicLR(base_lr=0.005, max_lr=0.01,step_size=2000., mode='triangular')\nepochs = 1\nuse_multiprocessing = True \n#workers = 6 \nbase_cnn = model.fit_generator(\n    train_generator,\n    steps_per_epoch=len(train_generator),\n    validation_data=val_generator,\n    validation_steps=24,\n    #class_weight = class_weights,\n    epochs=epochs,\n    #callbacks = [clr],\n    use_multiprocessing=use_multiprocessing,\n    #workers=workers,\n    verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.save('Xception_pass2.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Up Next -  Making predictions and arranging the submission file for the competition.**","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**If you found this helpful - please upvote. This would motivate me to keep updating this notebook as the competition progresses further**","execution_count":null}],"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}