{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Import of all the libraries we'll use\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sn\nimport os\nfrom IPython.display import display, Image\n\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\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# Libraries useful for our neural network model\n        \nfrom keras.preprocessing.image import load_img\nfrom keras.preprocessing.image import img_to_array\nfrom keras.applications.inception_resnet_v2 import InceptionResNetV2, preprocess_input\nfrom keras.models import Model\nimport keras\nimport tensorflow as tf\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.layers import BatchNormalization, Dense, GlobalAveragePooling2D, Lambda, Dropout, InputLayer, Input\nfrom keras.callbacks import EarlyStopping\nfrom tqdm import tqdm\nfrom keras.utils import to_categorical\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_num_files(path):\n    '''\n    Function which counts the number of files in a folder.\n    '''\n    if not os.path.exists(path):\n        return 0\n    return sum([len(files) for root, directory, files in os.walk(path)])","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:47:09.504533Z","iopub.execute_input":"2021-06-11T12:47:09.504841Z","iopub.status.idle":"2021-06-11T12:47:09.511032Z","shell.execute_reply.started":"2021-06-11T12:47:09.504808Z","shell.execute_reply":"2021-06-11T12:47:09.509906Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Data Paths\ntrain_dir = '/kaggle/input/dog-breed-identification/train'\ntest_dir = '/kaggle/input/dog-breed-identification/test'\n# Count/Print train and test samples.\ndata_size = get_num_files(train_dir)\ntest_size = get_num_files(test_dir)\nprint('Data samples size: ', data_size)\nprint('Test samples size: ', test_size)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:47:09.513423Z","iopub.execute_input":"2021-06-11T12:47:09.513775Z","iopub.status.idle":"2021-06-11T12:47:09.551766Z","shell.execute_reply.started":"2021-06-11T12:47:09.513741Z","shell.execute_reply":"2021-06-11T12:47:09.550732Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Read CSV of our data\n\nsample_df = pd.read_csv('/kaggle/input/dog-breed-identification/sample_submission.csv')\nlabels = pd.read_csv(\"../input/dog-breed-identification/labels.csv\")\nlabels.head(5)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:47:09.553507Z","iopub.execute_input":"2021-06-11T12:47:09.553864Z","iopub.status.idle":"2021-06-11T12:47:10.131037Z","shell.execute_reply.started":"2021-06-11T12:47:09.553828Z","shell.execute_reply":"2021-06-11T12:47:10.130124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create list of alphabetically sorted labels.\ndog_breeds = sorted(list(set(labels['breed'])))\nn_classes = len(dog_breeds)\nprint(n_classes)\ndog_breeds[:10]","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:47:10.132411Z","iopub.execute_input":"2021-06-11T12:47:10.132747Z","iopub.status.idle":"2021-06-11T12:47:10.144086Z","shell.execute_reply.started":"2021-06-11T12:47:10.132712Z","shell.execute_reply":"2021-06-11T12:47:10.143041Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Map each label string to an integer label.\n\nclass_to_num = dict(zip(dog_breeds, range(n_classes)))\nclass_to_num","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:47:10.145704Z","iopub.execute_input":"2021-06-11T12:47:10.146065Z","iopub.status.idle":"2021-06-11T12:47:10.159977Z","shell.execute_reply.started":"2021-06-11T12:47:10.146029Z","shell.execute_reply":"2021-06-11T12:47:10.158957Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def images_to_array(data_dir, labels_dataframe, img_size = (224,224,3)):\n    '''\n    1- Read image samples from certain directory.\n    2- Resize it, then stack them into one big numpy array.\n    3- Read sample's label form the labels dataframe.\n    4- One hot encode labels array.\n    5- Shuffle Data and label arrays.\n    '''\n    images_names = labels_dataframe['id']\n    images_labels = labels_dataframe['breed']\n    data_size = len(images_names)\n    # initailize output arrays.\n    X = np.zeros([data_size, img_size[0], img_size[1], img_size[2]], dtype=np.uint8)\n    y = np.zeros([data_size,1], dtype=np.uint8)\n    # read data and labels.\n    for i in tqdm(range(data_size)):\n        image_name = images_names[i]\n        img_dir = os.path.join(data_dir, image_name+'.jpg')\n        img_pixels = load_img(img_dir, target_size=img_size)\n        X[i] = img_pixels\n        \n        image_breed = images_labels[i]\n        y[i] = class_to_num[image_breed]\n    \n    # One hot encoder\n    y = to_categorical(y)\n    # shuffle    \n    ind = np.random.permutation(data_size)\n    X = X[ind]\n    y = y[ind]\n    print('Output Data Size: ', X.shape)\n    print('Output Label Size: ', y.shape)\n    return X, y","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:47:10.161505Z","iopub.execute_input":"2021-06-11T12:47:10.161922Z","iopub.status.idle":"2021-06-11T12:47:10.172432Z","shell.execute_reply.started":"2021-06-11T12:47:10.161867Z","shell.execute_reply":"2021-06-11T12:47:10.171154Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Calling of the function to get the arrays of our images\nimg_size = (331,331,3)\nX, y = images_to_array(train_dir, labels, img_size)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:47:10.175799Z","iopub.execute_input":"2021-06-11T12:47:10.176231Z","iopub.status.idle":"2021-06-11T12:48:19.64745Z","shell.execute_reply.started":"2021-06-11T12:47:10.176181Z","shell.execute_reply":"2021-06-11T12:48:19.646556Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get the different features of our database\n\ndef get_features(model_name, data_preprocessor, input_size, data):\n    '''\n    1- Create a feature extractor to extract features from the data.\n    2- Returns the extracted features and the feature extractor.\n    '''\n    # Prepare pipeline.\n    input_layer = Input(input_size)\n    preprocessor = Lambda(data_preprocessor)(input_layer)\n    base_model = model_name(weights='imagenet', include_top=False, input_shape=input_size)(preprocessor)\n    base_model.trainable = False\n    avg = GlobalAveragePooling2D()(base_model)\n    feature_extractor = Model(inputs = input_layer, outputs = avg)\n    # Extract feature.\n    feature_maps = feature_extractor.predict(data, batch_size=64, verbose=1)\n    print('Feature maps shape: ', feature_maps.shape)\n    return feature_maps","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:48:19.650743Z","iopub.execute_input":"2021-06-11T12:48:19.651043Z","iopub.status.idle":"2021-06-11T12:48:19.660708Z","shell.execute_reply.started":"2021-06-11T12:48:19.651015Z","shell.execute_reply":"2021-06-11T12:48:19.659761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train, X_validation, y_train, y_validation = train_test_split(X, y, test_size=0.3, random_state=6)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:48:19.662346Z","iopub.execute_input":"2021-06-11T12:48:19.663171Z","iopub.status.idle":"2021-06-11T12:48:20.741573Z","shell.execute_reply.started":"2021-06-11T12:48:19.663128Z","shell.execute_reply":"2021-06-11T12:48:20.740709Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# get extracted features\ninc_resnet_preprocessor = preprocess_input\ninc_resnet_features = get_features(InceptionResNetV2, inc_resnet_preprocessor, img_size, X_train)\ninc_resnet_features_valid = get_features(InceptionResNetV2, inc_resnet_preprocessor, img_size, X_validation)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:48:20.742804Z","iopub.execute_input":"2021-06-11T12:48:20.743154Z","iopub.status.idle":"2021-06-11T12:49:53.840662Z","shell.execute_reply.started":"2021-06-11T12:48:20.743118Z","shell.execute_reply":"2021-06-11T12:49:53.839813Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Deletion of X to free some memory\n\ndel X","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:49:53.843477Z","iopub.execute_input":"2021-06-11T12:49:53.843732Z","iopub.status.idle":"2021-06-11T12:49:53.85675Z","shell.execute_reply.started":"2021-06-11T12:49:53.843706Z","shell.execute_reply":"2021-06-11T12:49:53.856005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define an early stopping to stop after a number of epochs which the validation loss doesn't decrease anymore\n\nEarlyStop_callback = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)\nmy_callback=[EarlyStop_callback]","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:49:53.859796Z","iopub.execute_input":"2021-06-11T12:49:53.860073Z","iopub.status.idle":"2021-06-11T12:49:53.867737Z","shell.execute_reply.started":"2021-06-11T12:49:53.860046Z","shell.execute_reply":"2021-06-11T12:49:53.866868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Prepare DNN model\n\ndnn = keras.models.Sequential([\n    InputLayer(inc_resnet_features.shape[1:]),\n    Dropout(0.7),\n    Dense(n_classes, activation='softmax')\n])\n\ndnn.compile(optimizer='adam',\n              loss='categorical_crossentropy',\n              metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:49:53.870174Z","iopub.execute_input":"2021-06-11T12:49:53.870458Z","iopub.status.idle":"2021-06-11T12:49:53.902739Z","shell.execute_reply.started":"2021-06-11T12:49:53.870432Z","shell.execute_reply":"2021-06-11T12:49:53.902005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train simple DNN on extracted features.\nh = dnn.fit(inc_resnet_features, y_train,\n            batch_size=128,\n            validation_data = (inc_resnet_features_valid, y_validation),\n            epochs=60,\n            callbacks=my_callback)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:49:53.903836Z","iopub.execute_input":"2021-06-11T12:49:53.904166Z","iopub.status.idle":"2021-06-11T12:50:00.822176Z","shell.execute_reply.started":"2021-06-11T12:49:53.904132Z","shell.execute_reply":"2021-06-11T12:50:00.821348Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def images_to_array2(data_dir, labels_dataframe, img_size = (224,224,3)):\n    '''\n    Do same as images_to_array but omit some unnecessary steps for test data.\n    '''\n    images_names = labels_dataframe['id']\n    data_size = len(images_names)\n    X = np.zeros([data_size, img_size[0], img_size[1], 3], dtype=np.uint8)\n    \n    for i in tqdm(range(data_size)):\n        image_name = images_names[i]\n        img_dir = os.path.join(data_dir, image_name+'.jpg')\n        img_pixels = tf.keras.preprocessing.image.load_img(img_dir, target_size=img_size)\n        X[i] = img_pixels\n        \n    print('Output Data Size: ', X.shape)\n    return X\n\ntest_data = images_to_array2(test_dir, sample_df, img_size)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:50:00.82347Z","iopub.execute_input":"2021-06-11T12:50:00.823787Z","iopub.status.idle":"2021-06-11T12:51:35.953149Z","shell.execute_reply.started":"2021-06-11T12:50:00.823751Z","shell.execute_reply":"2021-06-11T12:51:35.952297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"inc_resnet_features_test = get_features(InceptionResNetV2, inc_resnet_preprocessor, img_size, test_data)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:51:35.954368Z","iopub.execute_input":"2021-06-11T12:51:35.954719Z","iopub.status.idle":"2021-06-11T12:52:52.637825Z","shell.execute_reply.started":"2021-06-11T12:51:35.954681Z","shell.execute_reply":"2021-06-11T12:52:52.636921Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Deletion of test_data to free some memory\n\ndel test_data","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:52:52.640937Z","iopub.execute_input":"2021-06-11T12:52:52.641213Z","iopub.status.idle":"2021-06-11T12:52:52.75196Z","shell.execute_reply.started":"2021-06-11T12:52:52.641169Z","shell.execute_reply":"2021-06-11T12:52:52.750937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Predict test labels given test data features\n\ny_pred = dnn.predict(inc_resnet_features_test, batch_size=128)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:52:52.753249Z","iopub.execute_input":"2021-06-11T12:52:52.753753Z","iopub.status.idle":"2021-06-11T12:52:52.942785Z","shell.execute_reply.started":"2021-06-11T12:52:52.753716Z","shell.execute_reply":"2021-06-11T12:52:52.941761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(y_pred[0])\nprint(f\"Max value (probability of prediction): {np.max(y_pred[0])}\") # the max probability value","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:52:52.944099Z","iopub.execute_input":"2021-06-11T12:52:52.94446Z","iopub.status.idle":"2021-06-11T12:52:52.954482Z","shell.execute_reply.started":"2021-06-11T12:52:52.944422Z","shell.execute_reply":"2021-06-11T12:52:52.950352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_key(my_dict, val):\n    \"\"\" Function which returns the key of a dictionary according to its value \"\"\"\n    for key, value in my_dict.items():\n         if val == value:\n             return key\n    return \"key doesn't exist\"","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:52:52.956087Z","iopub.execute_input":"2021-06-11T12:52:52.956831Z","iopub.status.idle":"2021-06-11T12:52:52.962703Z","shell.execute_reply.started":"2021-06-11T12:52:52.956789Z","shell.execute_reply":"2021-06-11T12:52:52.961417Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# predicted by the model\nprint(f\"Sum: {np.sum(y_pred[0])}\") # because we used softmax activation in our model, this will be close to 1\nprint(f\"Max index: {np.argmax(y_pred[0])}\") # the index of where the max value in predictions[0] occurs\nprint(f\"Predicted label: {get_key(class_to_num, np.argmax(y_pred[0]))}\")","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:52:52.964348Z","iopub.execute_input":"2021-06-11T12:52:52.964747Z","iopub.status.idle":"2021-06-11T12:52:52.97548Z","shell.execute_reply.started":"2021-06-11T12:52:52.964708Z","shell.execute_reply":"2021-06-11T12:52:52.974106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create pandas DataFrame with empty columns\npreds_df = pd.DataFrame(columns=[\"id\"] + list(dog_breeds))\npreds_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:52:52.980392Z","iopub.execute_input":"2021-06-11T12:52:52.980776Z","iopub.status.idle":"2021-06-11T12:52:53.009351Z","shell.execute_reply.started":"2021-06-11T12:52:52.980744Z","shell.execute_reply":"2021-06-11T12:52:53.008598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Inclusion of our images in the dataframe\n\ntest_path = \"../input/dog-breed-identification/test/\"\npreds_df[\"id\"] = [os.path.splitext(path)[0] for path in os.listdir(test_path)]\npreds_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:52:53.010589Z","iopub.execute_input":"2021-06-11T12:52:53.010983Z","iopub.status.idle":"2021-06-11T12:52:53.07005Z","shell.execute_reply.started":"2021-06-11T12:52:53.010926Z","shell.execute_reply":"2021-06-11T12:52:53.06916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds_df.loc[:,list(dog_breeds)]= y_pred\npreds_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:52:53.071144Z","iopub.execute_input":"2021-06-11T12:52:53.071494Z","iopub.status.idle":"2021-06-11T12:52:53.153937Z","shell.execute_reply.started":"2021-06-11T12:52:53.071467Z","shell.execute_reply":"2021-06-11T12:52:53.152914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def loading_image(path):\n    \"\"\" Function which loads an image and makes a prediction on its breed \"\"\"\n    Image(path)\n    img_g = load_img('../input/testing-images/index.jpeg',target_size = img_size)\n    img_g = np.expand_dims(img_g, axis=0)\n    test_features = get_features(InceptionResNetV2, inc_resnet_preprocessor, img_size, img_g)\n    predg = dnn.predict(test_features)\n    return predg","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:52:53.155355Z","iopub.execute_input":"2021-06-11T12:52:53.155717Z","iopub.status.idle":"2021-06-11T12:52:53.16117Z","shell.execute_reply.started":"2021-06-11T12:52:53.155681Z","shell.execute_reply":"2021-06-11T12:52:53.160355Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"prediction = loading_image(\"../input/testing-images/20210602_202544.jpg\")","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:52:53.162781Z","iopub.execute_input":"2021-06-11T12:52:53.163162Z","iopub.status.idle":"2021-06-11T12:53:03.172349Z","shell.execute_reply.started":"2021-06-11T12:52:53.163125Z","shell.execute_reply":"2021-06-11T12:53:03.171198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Displaying of the prediction\n\nprint(f\"Predicted label: {get_key(class_to_num, np.argmax(prediction[0]))}\")\nprint(f\"Probability of prediction: {round(np.max(prediction[0]) * 100, 3)} %\")","metadata":{"execution":{"iopub.status.busy":"2021-06-11T12:53:03.173882Z","iopub.execute_input":"2021-06-11T12:53:03.174255Z","iopub.status.idle":"2021-06-11T12:53:03.179956Z","shell.execute_reply.started":"2021-06-11T12:53:03.174215Z","shell.execute_reply":"2021-06-11T12:53:03.179105Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_confusion_matrix(data_pred_cls,data_predicted_cls):\n    # This is called from print_test_accuracy() below.\n\n\n    # cls_pred is an array of the predicted class-number for\n    # all images in the test-set.\n  \n    # Get the confusion matrix using sklearn.\n    df_cm = confusion_matrix(y_true=data_pred_cls,\n                          y_pred=data_predicted_cls, normalize = 'true')\n\n\n    # Print the confusion matrix as text.\n    print(df_cm)\n    breeds_dataframe = pd.DataFrame(df_cm, columns=dog_breeds)\n    \n    # Plot the confusion matrix as an image.\n    plt.figure(figsize = (40,35))\n    \n    # plt.matshow(cm)\n\n\n    # Make various adjustments to the plot.\n#     plt.colorbar()\n#     tick_marks = np.arange(n_classes)\n#     plt.xticks(tick_marks, dog_breeds, rotation=90)\n#     plt.yticks(tick_marks, dog_breeds)\n#     plt.xlabel('Predicted')\n#     plt.ylabel('True')\n\n\n    # Ensure the plot is shown correctly with multiple plots\n    # in a single Notebook cell.\n    sn.heatmap(breeds_dataframe, annot=False, xticklabels=breeds_dataframe.columns, yticklabels=breeds_dataframe.columns)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T13:23:04.390702Z","iopub.execute_input":"2021-06-11T13:23:04.391036Z","iopub.status.idle":"2021-06-11T13:23:04.396502Z","shell.execute_reply.started":"2021-06-11T13:23:04.391005Z","shell.execute_reply":"2021-06-11T13:23:04.395467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_validation_toPred_cls = np.argmax(y_validation, axis=1)\ny_pred_valid = dnn.predict(inc_resnet_features_valid)\ndf_validation_predicted_cls = np.argmax(y_pred_valid, axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T13:23:07.168882Z","iopub.execute_input":"2021-06-11T13:23:07.169235Z","iopub.status.idle":"2021-06-11T13:23:07.276971Z","shell.execute_reply.started":"2021-06-11T13:23:07.169182Z","shell.execute_reply":"2021-06-11T13:23:07.276079Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_confusion_matrix(df_validation_toPred_cls,df_validation_predicted_cls)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T13:23:09.521108Z","iopub.execute_input":"2021-06-11T13:23:09.521478Z","iopub.status.idle":"2021-06-11T13:23:13.759402Z","shell.execute_reply.started":"2021-06-11T13:23:09.521447Z","shell.execute_reply":"2021-06-11T13:23:13.758594Z"},"trusted":true},"execution_count":null,"outputs":[]}]}