{"cells":[{"metadata":{},"cell_type":"markdown","source":"# **Exploration**"},{"metadata":{},"cell_type":"markdown","source":"How many images does the dataset consist of?"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport os\nimport random\nimport cv2\nimport keras\nfrom PIL import Image\nfrom sklearn.preprocessing import LabelEncoder\nfrom keras.layers import *\nfrom keras import Sequential\n\ndata = pd.read_csv('/kaggle/input/landmark-recognition-2020/train.csv')\n\nimages = data.shape[0]\nprint(\"Number of images:\", images)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"How many classes? How many images per class?\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"classes = len(data['landmark_id'].unique())\nprint(\"Number of classes:\", classes)\nprint(\"Average number of images per class:\",round(images/classes,2))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Show a histogram of the number of instances per class"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(20,6))\nplt.hist(data.landmark_id, bins=1000);\nplt.title('Images per class', fontsize=16)\nplt.xlabel('Class number')\nplt.ylabel('Number of images')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"How many classes have less than 5 training samples? And between 5 and 10 training samples?"},{"metadata":{"trusted":true},"cell_type":"code","source":"data5 = (data['landmark_id'].value_counts() <= 5).sum()\ndata10 = (data['landmark_id'].value_counts() <= 10).sum()\nprint(\"Number of classes with less than 5 training samples:\", data5)\nprint(\"Number of classes with between 5 and 10 training samples:\", data10-data5)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Show 4 sample images from 4 random classes"},{"metadata":{"trusted":true},"cell_type":"code","source":"path='/kaggle/input/landmark-recognition-2020/train/'\n\n\nprint(\"4 sample images from random classes:\")\nfig=plt.figure(figsize=(16, 16))\nfor i in range(1,5):\n    a = random.choices(os.listdir(path), k=3)\n    folder = path+a[0]+'/'+a[1]+'/'+a[2]\n    random_img = random.choice(os.listdir(folder))\n    img = np.array(Image.open(folder+'/'+random_img))\n    fig.add_subplot(1, 4, i)\n    plt.imshow(img)\n    plt.axis('off')\n\nplt.show()\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Consider if/how the data distribution will affect training of a classifier\n\nThe classifier will definitely work better for some classes than others, when some classes have thousands of training images and others have below 10, or even 5. It will be practically imposible to make a perfect classifer, when there are classes with such few samples."},{"metadata":{},"cell_type":"markdown","source":"# **Classification**"},{"metadata":{"trusted":true},"cell_type":"code","source":"samples = 20000\n\ndata = data.loc[:samples,:]\nclasses = len(data['landmark_id'].unique())\n\nlencoder = LabelEncoder()\nlencoder.fit(data[\"landmark_id\"])\n\nmodel = Sequential()\nmodel.add(Input(shape=(224,224,3)))\nmodel.add(BatchNormalization())\nmodel.add(Conv2D(64, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(64, kernel_size = (3,3), padding = \"same\"))\nmodel.add(MaxPooling2D())\nmodel.add(Conv2D(128, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(128, kernel_size = (3,3), padding = \"same\"))\nmodel.add(MaxPooling2D())\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(MaxPooling2D())\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(MaxPooling2D())\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(MaxPooling2D())\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(Conv2D(256, kernel_size = (3,3), padding = \"same\"))\nmodel.add(MaxPooling2D())\nmodel.add(Flatten())\nmodel.add(Dense(4096, activation = \"relu\"))\nmodel.add(Dense(4096, activation = \"relu\"))\nmodel.add(Dense(classes, activation=\"softmax\"))\nprint(model.summary())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"opt = keras.optimizers.Adagrad(learning_rate = 0.001, initial_accumulator_value=0.01, epsilon=1e-07)\nmodel.compile(optimizer=opt,\n             loss=\"sparse_categorical_crossentropy\",\n             metrics=[\"accuracy\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def encode_label(lbl):\n    return lencoder.transform(lbl)\n    \ndef decode_label(lbl):\n    return lencoder.inverse_transform(lbl)\n\ndef get_image_from_number(num, data):\n    fname, label = data.iloc[num,:]\n    fname = fname + \".jpg\"\n    f1 = fname[0]\n    f2 = fname[1]\n    f3 = fname[2]\n    path = os.path.join(f1,f2,f3,fname)\n    im = cv2.imread(os.path.join(r\"/kaggle/input/landmark-recognition-2020/train\",path))\n    return im, label\n\ndef image_reshape(im, target_size):\n    return cv2.resize(im, target_size)\n    \ndef get_batch(dataframe,start, batch_size):\n    image_array = []\n    label_array = []\n    \n    end_img = start+batch_size\n    if end_img > len(dataframe):\n        end_img = len(dataframe)\n\n    for idx in range(start, end_img):\n        n = idx\n        im, label = get_image_from_number(n, dataframe)\n        im = image_reshape(im, (224, 224)) / 255.0\n        image_array.append(im)\n        label_array.append(label)\n        \n    label_array = encode_label(label_array)\n    return np.array(image_array), np.array(label_array)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size = 10\nepoch_shuffle = True\nweight_classes = True\nepochs = 10\n\ntrain, validate = np.split(data.sample(frac=1), [int(.8*len(data))])\nprint(\"Training on:\", len(train), \"samples\")\nprint(\"Validation on:\", len(validate), \"samples\")\n    \nfor e in range(epochs):\n    print(\"Epoch: \", str(e+1) + \"/\" + str(epochs))\n    if epoch_shuffle:\n        train = train.sample(frac = 1)\n    for it in range(int(np.ceil(len(train)/batch_size))):\n\n        X_train, y_train = get_batch(train, it*batch_size, batch_size)\n\n        model.train_on_batch(X_train, y_train)\n        \n\nmodel.save(\"Model.h5\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size = 10\n\nerrors = 0\ngood_preds = []\nbad_preds = []\n\nfor it in range(int(np.ceil(len(validate)/batch_size))):\n\n    X_train, y_train = get_batch(validate, it*batch_size, batch_size)\n\n    result = model.predict(X_train)\n    cla = np.argmax(result, axis=1)\n    for idx, res in enumerate(result):\n        if cla[idx] != y_train[idx]:\n            errors = errors + 1\n            bad_preds.append([batch_size*it + idx, cla[idx], res[cla[idx]]])\n        else:\n            good_preds.append([batch_size*it + idx, cla[idx], res[cla[idx]]])\n\nprint(\"Total errors: \", errors, \"out of\", len(validate), \"\\nAccuracy:\", np.round(100*(len(validate)-errors)/len(validate),2), \"%\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Breaking down results"},{"metadata":{},"cell_type":"markdown","source":"Visualize five examples where classification went well, and five where classification failed"},{"metadata":{"trusted":true},"cell_type":"code","source":"n = plt.hist(data[\"landmark_id\"],bins=data[\"landmark_id\"].unique())\nplt.close()\nfreq_info = n[0]\n\ntemp = []\nfor cla, amt in enumerate(freq_info):\n    temp.append([cla, amt])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"good_preds = np.array(good_preds)\ngood_preds = np.array(sorted(good_preds, key = lambda x: x[2], reverse=True))\n\nprint(\"5 images where classification went well:\")\nfig=plt.figure(figsize=(16, 16))\nfor i in range(1,6):\n    n = int(good_preds[i,0])\n    img, lbl = get_image_from_number(n, validate)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    fig.add_subplot(1, 5, i)\n    plt.imshow(img)\n    lbl2 = np.array(int(good_preds[i,1])).reshape(1,1)\n    sample_cnt = int(temp[int(encode_label(np.array([lbl])))-1][1])\n    plt.title(\"Label: \" + str(lbl) + \"\\nClassified as: \" + str(decode_label(lbl2)) + \"\\nSamples in class \" + str(lbl) + \": \" + str(sample_cnt))\n    plt.axis('off')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"bad_preds = np.array(bad_preds)\nbad_preds = np.array(sorted(bad_preds, key = lambda x: x[2], reverse=True))\n\nprint(\"5 images where classification failed:\")\nfig=plt.figure(figsize=(16, 16))\nfor i in range(1,6):\n    n = int(bad_preds[i,0])\n    img, lbl = get_image_from_number(n, validate)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    fig.add_subplot(1, 5, i)\n    plt.imshow(img)\n    lbl2 = np.array(int(bad_preds[i,1])).reshape(1,1)\n    sample_cnt = int(temp[int(encode_label(np.array([lbl])))-1][1])\n    plt.title(\"Label: \" + str(lbl) + \"\\nClassified as: \" + str(decode_label(lbl2)) + \"\\nSamples in class \" + str(lbl) + \": \" + str(sample_cnt))\n    plt.axis('off')\n    \nplt.show()","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}