{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"from tensorflow.keras.applications.resnet import preprocess_input \nfrom sklearn.model_selection import train_test_split\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport pandas as pd\nimport numpy as np","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Loading the names and labels csv file"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv('../input/dog-breed-identification/labels.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Retaining only the required 10 breeds"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = train_df.loc[(train_df.breed == 'beagle') | (train_df.breed == 'doberman') | (train_df.breed == 'chihuahua') | (train_df.breed == 'french_bulldog') | (train_df.breed == 'golden_retriever') | (train_df.breed == 'malamute') | (train_df.breed == 'pug') | (train_df.breed == 'saint_bernard') | (train_df.breed == 'scottish_deerhound') | (train_df.breed == 'tibetan_mastiff')].reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Numbers of images per category of dog breeds"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.breed.value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Creating path for each image, for helper function to decode the image."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_paths = '../input/dog-breed-identification/train/' + train_df['id'] + '.jpg'","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Getting the lables into one-hot encoding format"},{"metadata":{"trusted":true},"cell_type":"code","source":"labels = pd.get_dummies(train_df.breed).values","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"column_names = pd.get_dummies(train_df.breed).columns.to_list()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Spliting the data into train and test purpose."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_path, valid_path, train_labels, valid_labels = train_test_split(train_paths, labels, test_size=0.3, random_state=42)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Creating dataset with the tf.data API for faster computational speed"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_ds = tf.data.Dataset.from_tensor_slices((train_path, train_labels))\nvalid_ds = tf.data.Dataset.from_tensor_slices((valid_path, valid_labels))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Helper function that will take the path and return tf.float32 dtype tensors of the image."},{"metadata":{"trusted":true},"cell_type":"code","source":"def decode_train_data(image_path, label):\n    \n    img = tf.io.read_file(image_path)\n    img = tf.io.decode_jpeg(img, channels=3)\n    img = tf.cast(img, tf.float32) / 255.0\n    img = tf.image.resize(img,[312,312])\n    \n    return img, label","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Mapping the helper function for decoding with num_parallel_calls=AUTOTUNE to do multiple operations parallelly. "},{"metadata":{"trusted":true},"cell_type":"code","source":"train_ds = train_ds.map(decode_train_data, num_parallel_calls=tf.data.experimental.AUTOTUNE)\nvalid_ds = valid_ds.map(decode_train_data, num_parallel_calls=tf.data.experimental.AUTOTUNE)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Data augmentation is really helpful when we are dealing with low number of train samples. It creates more samples from already exiting samples by tweaking little information in it."},{"metadata":{"trusted":true},"cell_type":"code","source":"def augment(img, label):\n    img = tf.image.random_flip_left_right(img)\n    img = tf.image.random_flip_up_down(img)\n    return img, label","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Also a helper fuction which has many utilities like caching for faster data retrival, batching the train samples in a set of 16, shuffling the data for true randomness and prefectching the data for the model, so the delivery of next set of sample batch wouldn't become the bottleneck in the architecture."},{"metadata":{"trusted":true},"cell_type":"code","source":"def configure_for_performance(ds, batch_size = 16):\n    \n    ds = ds.cache('/kaggle/dump.tfcache')\n    ds = ds.map(augment, num_parallel_calls=tf.data.experimental.AUTOTUNE)\n    ds = ds.repeat()\n    ds = ds.shuffle(buffer_size=25)\n    ds = ds.batch(batch_size)\n    ds = ds.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)\n    return ds","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_ds_batch = configure_for_performance(train_ds)\nvalid_ds_batch = valid_ds.batch(32)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### First we instantiates the ResNet50 architecture as base model with 'ImageNet' weights as default and we set layers of the model as trainable"},{"metadata":{"trusted":true},"cell_type":"code","source":"base_model = tf.keras.applications.ResNet50(include_top=False,weights=\"imagenet\")\nfor layers in base_model.layers:\n    layers.trainable=True","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### We are creating our transfer learning model with base layer as the ResNet50 layer. We added the data augmentation in the model as it will happen parallelly in CPU while the CNN will train in GPU. While using the ResNet50, Keras expects a specific kind of input preprocessing, we have to pass the inputs through the Preprocess_input for better processing. Then it passes through few other layers and finally at last dense layers, we set the no. of unique labels for prediction with softmax activation\n"},{"metadata":{},"cell_type":"markdown","source":"### After defining the model, we add optimizers, loss funtion and metrics for evaluation fo the model. Here we used Adam with a learning rate of 3e-4 and loss function as Categorical_crossentropy as we have categorical labels."},{"metadata":{"trusted":true},"cell_type":"code","source":"def build_model():\n    inputs = tf.keras.layers.Input(shape=(312, 312, 3))\n    preprocess = preprocess_input(inputs)\n    outputs_resnet = base_model(preprocess)\n    global_avg_pooling = tf.keras.layers.GlobalAveragePooling2D()(outputs_resnet)\n    dense_1= tf.keras.layers.Dense(512, kernel_regularizer = 'l2')(global_avg_pooling)\n    bn_1 = tf.keras.layers.BatchNormalization()(dense_1)\n    activation = tf.keras.layers.Activation('relu')(bn_1)\n    dropout = tf.keras.layers.Dropout(0.4)(activation)\n    dense_2 = tf.keras.layers.Dense(10, activation='softmax')(dropout)\n    \n    \n    model = tf.keras.Model(inputs, dense_2)\n    \n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(lr = 3e-4),\n        loss='categorical_crossentropy',\n        metrics='acc'\n    )\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Initialize the model and check it Summary."},{"metadata":{"trusted":true},"cell_type":"code","source":"model = build_model()\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Here we define callbacks for our model. This include saving the Modelcheckpoint, which monitor the validation loss to reduce the learning rate if it sees that the model is not improving for 4 epochs and also saves the model with lowest validation loss."},{"metadata":{"trusted":true},"cell_type":"code","source":"checkpoint = tf.keras.callbacks.ModelCheckpoint(\n    './model.h5', save_best_only=True, monitor='val_loss', mode='min')\nlr_reducer = tf.keras.callbacks.ReduceLROnPlateau(\n    monitor=\"val_loss\", patience=4, min_lr=1e-5, mode='min')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Here we set the epochs and steps_per_epoch(no. of samples/batch_size) and then start traing our model."},{"metadata":{"trusted":true},"cell_type":"code","source":"steps_per_epoch = len(train_paths) // 16\nepochs = 60\nhistory = model.fit(\n                train_ds_batch, \n                validation_data = valid_ds_batch, \n                epochs = epochs,\n                callbacks=[checkpoint, lr_reducer],\n                steps_per_epoch = steps_per_epoch\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Graph plot of Accurarcy and loss of the model during the training."},{"metadata":{"trusted":true},"cell_type":"code","source":"acc = history.history['acc']\nval_acc = history.history['val_acc']\n\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs_range = range(epochs)\n\nplt.figure(figsize=(8, 8))\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Training Accuracy')\nplt.plot(epochs_range, val_acc, label='Validation Accuracy')\nplt.legend(loc='lower right')\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Training Loss')\nplt.plot(epochs_range, val_loss, label='Validation Loss')\nplt.legend(loc='upper right')\nplt.title('Training and Validation Loss')\nplt.show()","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}