{"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 numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os, cv2, random, time, shutil, csv\nimport tensorflow as tf\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nfrom tqdm import tqdm\nnp.random.seed(42)\n%matplotlib inline \n\nimport keras\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Model\nfrom keras.layers import BatchNormalization, Dense, GlobalAveragePooling2D, Lambda, Dropout, InputLayer, Input\nfrom keras.utils import to_categorical\nfrom tensorflow.keras.preprocessing.image import load_img","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:05:43.569175Z","iopub.execute_input":"2023-04-04T08:05:43.569525Z","iopub.status.idle":"2023-04-04T08:05:43.581519Z","shell.execute_reply.started":"2023-04-04T08:05:43.569470Z","shell.execute_reply":"2023-04-04T08:05:43.580673Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_num_files(path):\n    '''\n    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 r, d, files in os.walk(path)])","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","execution":{"iopub.status.busy":"2023-04-04T08:05:57.343133Z","iopub.execute_input":"2023-04-04T08:05:57.343466Z","iopub.status.idle":"2023-04-04T08:05:57.349732Z","shell.execute_reply.started":"2023-04-04T08:05:57.343411Z","shell.execute_reply":"2023-04-04T08:05:57.348851Z"},"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":"2023-04-04T08:06:13.568601Z","iopub.execute_input":"2023-04-04T08:06:13.568915Z","iopub.status.idle":"2023-04-04T08:06:40.366573Z","shell.execute_reply.started":"2023-04-04T08:06:13.568859Z","shell.execute_reply":"2023-04-04T08:06:40.365554Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Read train labels.\nlabels_dataframe = pd.read_csv('/kaggle/input/dog-breed-identification/labels.csv')\n#Read sample_submission file to be modified by pridected labels.\nsample_df = pd.read_csv('/kaggle/input/dog-breed-identification/sample_submission.csv')\n#Incpect labels_dataframe.\nlabels_dataframe.head(5)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:06:44.768159Z","iopub.execute_input":"2023-04-04T08:06:44.768482Z","iopub.status.idle":"2023-04-04T08:06:45.487865Z","shell.execute_reply.started":"2023-04-04T08:06:44.768413Z","shell.execute_reply":"2023-04-04T08:06:45.487127Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Create list of alphabetically sorted labels.\ndog_breeds = sorted(list(set(labels_dataframe['breed'])))\nn_classes = len(dog_breeds)\nprint(n_classes)\ndog_breeds[:10]","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:06:49.937865Z","iopub.execute_input":"2023-04-04T08:06:49.938183Z","iopub.status.idle":"2023-04-04T08:06:49.948000Z","shell.execute_reply.started":"2023-04-04T08:06:49.938128Z","shell.execute_reply":"2023-04-04T08:06:49.947225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Map each label string to an integer label.\nclass_to_num = dict(zip(dog_breeds, range(n_classes)))","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:06:59.288679Z","iopub.execute_input":"2023-04-04T08:06:59.289023Z","iopub.status.idle":"2023-04-04T08:06:59.293703Z","shell.execute_reply.started":"2023-04-04T08:06:59.288965Z","shell.execute_reply":"2023-04-04T08:06:59.292865Z"},"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- Risize 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 lables.\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('Ouptut Data Size: ', X.shape)\n    print('Ouptut Label Size: ', y.shape)\n    return X, y","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:07:08.093828Z","iopub.execute_input":"2023-04-04T08:07:08.094146Z","iopub.status.idle":"2023-04-04T08:07:08.103017Z","shell.execute_reply.started":"2023-04-04T08:07:08.094094Z","shell.execute_reply":"2023-04-04T08:07:08.102124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#img_size chosen to be 331 to suit the used architectures.\nimg_size = (331,331,3)\nX, y = images_to_array(train_dir, labels_dataframe, img_size)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:07:11.687891Z","iopub.execute_input":"2023-04-04T08:07:11.688208Z","iopub.status.idle":"2023-04-04T08:08:43.332705Z","shell.execute_reply.started":"2023-04-04T08:07:11.688157Z","shell.execute_reply":"2023-04-04T08:08:43.331918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def 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,\n                            input_shape=input_size)(preprocessor)\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":"2023-04-04T08:09:54.987931Z","iopub.execute_input":"2023-04-04T08:09:54.988247Z","iopub.status.idle":"2023-04-04T08:09:54.994571Z","shell.execute_reply.started":"2023-04-04T08:09:54.988195Z","shell.execute_reply":"2023-04-04T08:09:54.993245Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Extract features using InceptionV3 as extractor.\nfrom keras.applications.inception_v3 import InceptionV3, preprocess_input\ninception_preprocessor = preprocess_input\ninception_features = get_features(InceptionV3,\n                                  inception_preprocessor,\n                                  img_size, X)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:10:00.008081Z","iopub.execute_input":"2023-04-04T08:10:00.008391Z","iopub.status.idle":"2023-04-04T08:11:18.745234Z","shell.execute_reply.started":"2023-04-04T08:10:00.008339Z","shell.execute_reply":"2023-04-04T08:11:18.739532Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Extract features using Xception as extractor.\nfrom keras.applications.xception import Xception, preprocess_input\nxception_preprocessor = preprocess_input\nxception_features = get_features(Xception,\n                                 xception_preprocessor,\n                                 img_size, X)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:11:21.578181Z","iopub.execute_input":"2023-04-04T08:11:21.578506Z","iopub.status.idle":"2023-04-04T08:13:05.413514Z","shell.execute_reply.started":"2023-04-04T08:11:21.578447Z","shell.execute_reply":"2023-04-04T08:13:05.412789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Extract features using NASNetLarge as extractor.\nfrom keras.applications.nasnet import NASNetLarge, preprocess_input\nnasnet_preprocessor = preprocess_input\nnasnet_features = get_features(NASNetLarge,\n                               nasnet_preprocessor,\n                               img_size, X)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:13:09.268464Z","iopub.execute_input":"2023-04-04T08:13:09.268832Z","iopub.status.idle":"2023-04-04T08:17:58.022518Z","shell.execute_reply.started":"2023-04-04T08:13:09.268756Z","shell.execute_reply":"2023-04-04T08:17:58.021684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Extract features using InceptionResNetV2 as extractor.\nfrom keras.applications.inception_resnet_v2 import InceptionResNetV2, preprocess_input\ninc_resnet_preprocessor = preprocess_input\ninc_resnet_features = get_features(InceptionResNetV2,\n                                   inc_resnet_preprocessor,\n                                   img_size, X)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:18:06.468419Z","iopub.execute_input":"2023-04-04T08:18:06.468732Z","iopub.status.idle":"2023-04-04T08:20:23.361987Z","shell.execute_reply.started":"2023-04-04T08:18:06.468676Z","shell.execute_reply":"2023-04-04T08:20:23.360817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#It's a good habit to free up some RAM memory.\n#X variable won't be needed anymore, so let's get rid of it.\ndel X","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:20:29.688913Z","iopub.execute_input":"2023-04-04T08:20:29.689229Z","iopub.status.idle":"2023-04-04T08:20:29.699415Z","shell.execute_reply.started":"2023-04-04T08:20:29.689175Z","shell.execute_reply":"2023-04-04T08:20:29.698564Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"final_features = np.concatenate([inception_features,\n                                 xception_features,\n                                 nasnet_features,\n                                 inc_resnet_features,], axis=-1)\nprint('Final feature maps shape', final_features.shape)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:20:34.027865Z","iopub.execute_input":"2023-04-04T08:20:34.028328Z","iopub.status.idle":"2023-04-04T08:20:34.179164Z","shell.execute_reply.started":"2023-04-04T08:20:34.028134Z","shell.execute_reply":"2023-04-04T08:20:34.178289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.callbacks import EarlyStopping\n#Prepare call backs\nEarlyStop_callback = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)\nmy_callback=[EarlyStop_callback]","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:20:37.257707Z","iopub.execute_input":"2023-04-04T08:20:37.258042Z","iopub.status.idle":"2023-04-04T08:20:37.262656Z","shell.execute_reply.started":"2023-04-04T08:20:37.257988Z","shell.execute_reply":"2023-04-04T08:20:37.261566Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Prepare DNN model\ndnn = keras.models.Sequential([\n    InputLayer(final_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'])\n\n#Train simple DNN on extracted features.\nh = dnn.fit(final_features, y,\n            batch_size=128,\n            epochs=60,\n            validation_split=0.1,\n            callbacks=my_callback)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:20:41.347924Z","iopub.execute_input":"2023-04-04T08:20:41.348249Z","iopub.status.idle":"2023-04-04T08:20:46.517537Z","shell.execute_reply.started":"2023-04-04T08:20:41.348193Z","shell.execute_reply":"2023-04-04T08:20:46.516908Z"},"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('Ouptut Data Size: ', X.shape)\n    return X\n\ntest_data = images_to_array2(test_dir, sample_df, img_size)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:21:02.548602Z","iopub.execute_input":"2023-04-04T08:21:02.548925Z","iopub.status.idle":"2023-04-04T08:22:52.518405Z","shell.execute_reply.started":"2023-04-04T08:21:02.548867Z","shell.execute_reply":"2023-04-04T08:22:52.517107Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Extract test data features.\ninception_features = get_features(InceptionV3, inception_preprocessor, img_size, test_data)\nxception_features = get_features(Xception, xception_preprocessor, img_size, test_data)\nnasnet_features = get_features(NASNetLarge, nasnet_preprocessor, img_size, test_data)\ninc_resnet_features = get_features(InceptionResNetV2, inc_resnet_preprocessor, img_size, test_data)\n\ntest_features = np.concatenate([inception_features,\n                                 xception_features,\n                                 nasnet_features,\n                                 inc_resnet_features],axis=-1)\nprint('Final feature maps shape', test_features.shape)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:22:57.367827Z","iopub.execute_input":"2023-04-04T08:22:57.368170Z","iopub.status.idle":"2023-04-04T08:32:56.860198Z","shell.execute_reply.started":"2023-04-04T08:22:57.368113Z","shell.execute_reply":"2023-04-04T08:32:56.859354Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Free up some space.\ndel test_data","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:33:24.288004Z","iopub.execute_input":"2023-04-04T08:33:24.288352Z","iopub.status.idle":"2023-04-04T08:33:24.317364Z","shell.execute_reply.started":"2023-04-04T08:33:24.288292Z","shell.execute_reply":"2023-04-04T08:33:24.315912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Predict test labels given test data features.\ny_pred = dnn.predict(test_features, batch_size=128)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:33:28.287763Z","iopub.execute_input":"2023-04-04T08:33:28.288090Z","iopub.status.idle":"2023-04-04T08:33:28.594439Z","shell.execute_reply.started":"2023-04-04T08:33:28.288032Z","shell.execute_reply":"2023-04-04T08:33:28.593522Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Create submission file\nfor b in dog_breeds:\n    sample_df[b] = y_pred[:,class_to_num[b]]\nsample_df.to_csv('pred.csv', index=None)","metadata":{"execution":{"iopub.status.busy":"2023-04-04T08:33:40.708398Z","iopub.execute_input":"2023-04-04T08:33:40.708703Z","iopub.status.idle":"2023-04-04T08:33:42.455268Z","shell.execute_reply.started":"2023-04-04T08:33:40.708649Z","shell.execute_reply":"2023-04-04T08:33:42.454368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Inspired by: [https://www.kaggle.com/c/dog-breed-identification/discussion/40779](http://)","metadata":{}}]}