{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Importing Libraries"},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport pandas as pd\nimport pickle\nimport shutil\nimport numpy as np\nimport seaborn as sns\nfrom sklearn.datasets import load_files\nfrom keras.utils import np_utils\nimport matplotlib.pyplot as plt\nfrom keras.layers import Conv2D, MaxPooling2D, GlobalAveragePooling2D\nfrom keras.layers import Dropout, Flatten, Dense\nfrom keras.models import Sequential\nfrom keras.utils.vis_utils import plot_model\nfrom keras.callbacks import ModelCheckpoint\nfrom keras.utils import to_categorical\nfrom sklearn.metrics import confusion_matrix\nfrom sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score\n\n\nfrom PIL import ImageFile   \nfrom sklearn.model_selection import train_test_split\nfrom keras.preprocessing import image                  \nfrom tqdm import tqdm\n\nfrom keras.applications.vgg16 import VGG16","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Defining the train,test and model directories\n\n* We will create the directories for train,test and model training paths if not present"},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_DIR = \"../input/state-farm-distracted-driver-detection/imgs\"\nTEST_DIR = os.path.join(DATA_DIR,\"test\")\nTRAIN_DIR = os.path.join(DATA_DIR,\"train\")\n\nCSV_DIR = os.path.join(os.getcwd(),\"csv_files\")\n\nMODEL_PATH = os.path.join(os.getcwd(),\"model\",\"vgg16\")\nPICKLE_PATH = os.path.join(os.getcwd(),\"pickle\")\nTEST_CSV = os.path.join(os.getcwd(),\"csv_files\",\"test.csv\")\nTRAIN_CSV = os.path.join(os.getcwd(),\"csv_files\",\"train.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"if not os.path.exists(TEST_DIR):\n    print(\"Testing data does not exists\")\nif not os.path.exists(TRAIN_DIR):\n    print(\"Training data does not exists\")\nif not os.path.exists(MODEL_PATH):\n    print(\"Model path does not exists\")\n    os.makedirs(MODEL_PATH)\n    print(\"Model path created\")\nelse:\n    shutil.rmtree(MODEL_PATH)\n    os.makedirs(MODEL_PATH)\nif not os.path.exists(PICKLE_PATH):\n    os.makedirs(PICKLE_PATH)\nif not os.path.exists(CSV_DIR):\n    os.makedirs(CSV_DIR)\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"os.listdir(os.getcwd())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def create_csv(DATA_DIR,filename):\n    class_names = os.listdir(DATA_DIR)\n    data = list()\n    if(os.path.isdir(os.path.join(DATA_DIR,class_names[0]))):\n        for class_name in class_names:\n            file_names = os.listdir(os.path.join(DATA_DIR,class_name))\n            for file in file_names:\n                data.append({\n                    \"Filename\":os.path.join(DATA_DIR,class_name,file),\n                    \"ClassName\":class_name\n                })\n    else:\n        class_name = \"test\"\n        file_names = os.listdir(DATA_DIR)\n        for file in file_names:\n            data.append(({\n                \"FileName\":os.path.join(DATA_DIR,file),\n                \"ClassName\":class_name\n            }))\n    data = pd.DataFrame(data)\n    data.to_csv(os.path.join(os.getcwd(),\"csv_files\",filename),index=False)\n\ncreate_csv(TRAIN_DIR,\"train.csv\")\ncreate_csv(TEST_DIR,\"test.csv\")\ndata_train = pd.read_csv(os.path.join(os.getcwd(),\"csv_files\",\"train.csv\"))\ndata_test = pd.read_csv(os.path.join(os.getcwd(),\"csv_files\",\"test.csv\"))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_train = pd.read_csv(TRAIN_CSV)\ndata_test = pd.read_csv(TEST_CSV)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_list = list(set(data_train['ClassName'].values.tolist()))\nlabels_id = {label_name:id for id,label_name in enumerate(labels_list)}\nprint(labels_id)\ndata_train['ClassName'].replace(labels_id,inplace=True)\n\nlabels = to_categorical(data_train['ClassName'])\nprint(labels.shape)\n\nwith open(os.path.join(PICKLE_PATH,\"labels_list_vgg16.pkl\"),\"wb\") as handle:\n    pickle.dump(labels_id,handle)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data Preparation\n\n1. Converting the all the train and test images into image size of 64,64,3 \n2. Standardizing the flattened image vector "},{"metadata":{"trusted":true},"cell_type":"code","source":"xtrain,xtest,ytrain,ytest = train_test_split(data_train.iloc[:,0],labels,test_size = 0.2,random_state=42)\ndef path_to_tensor(img_path):\n    # loads RGB image as PIL.Image.Image type\n    img = image.load_img(img_path, target_size=(64, 64))\n    # convert PIL.Image.Image type to 3D tensor with shape (64, 64, 3)\n    x = image.img_to_array(img)\n    # convert 3D tensor to 4D tensor with shape (1, 64, 64, 3) and return 4D tensor\n    return np.expand_dims(x, axis=0)\n\ndef paths_to_tensor(img_paths):\n    list_of_tensors = [path_to_tensor(img_path) for img_path in tqdm(img_paths)]\n    return np.vstack(list_of_tensors)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ImageFile.LOAD_TRUNCATED_IMAGES = True                 \n# pre-process the data for Keras\ntrain_tensors = paths_to_tensor(xtrain).astype('float32')/255 - 0.5\nvalid_tensors = paths_to_tensor(xtest).astype('float32')/255 - 0.5","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# MODEL ARCHITECTURE\n\n## Approach Used\n1. Removing the top layer of VGG16 model\n2. Using the n-1 layers of VGG16 to predict the last layer of it using the flattened image vector \n3. The last layer thus achieved is a dense feature representation for a particular image\n4. Passing this layer feature through a GlobalAveragePooling Layer and a further dense softmax layer for each of 10 classes\n\n## Benefits\n\n1. Making CNN architecture from scratch involves in training of all the deep layers which results in slow training\n2. Instead of a large sparse image vector a dense feature representation used here requires less memory while training"},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"model = VGG16(include_top=False)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"train_vgg16 = model.predict(train_tensors,verbose=1)\nvalid_vgg16 = model.predict(valid_tensors,verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Train shape\",train_vgg16.shape)\nprint(\"Validation shape\",valid_vgg16.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_features = train_vgg16[0]\nvalid_features = valid_vgg16[0]","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"print(\"Train features shape\",train_features.shape)\nprint(\"Validation features shape\",valid_features.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"VGG16_model = Sequential()\nVGG16_model.add(GlobalAveragePooling2D(input_shape=train_features.shape))\nVGG16_model.add(Dense(10, activation='softmax', kernel_initializer='glorot_normal'))\n\nVGG16_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"VGG16_model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_model(VGG16_model,to_file=os.path.join(os.getcwd(),\"model\",\"vgg16\",\"model_distracted_driver_vgg16.png\"),show_shapes=True,show_layer_names=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"filepath = os.path.join(MODEL_PATH,\"distracted-{epoch:02d}-{val_accuracy:.2f}.hdf5\")\ncheckpoint = ModelCheckpoint(filepath, monitor='val_accuracy', verbose=1, save_best_only=True, mode='max',period=1)\ncallbacks_list = [checkpoint]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_history = VGG16_model.fit(train_vgg16,ytrain,validation_data = (valid_vgg16, ytest),epochs=400, batch_size=16, shuffle=True,callbacks=callbacks_list)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12))\nax1.plot(model_history.history['loss'], color='b', label=\"Training loss\")\nax1.plot(model_history.history['val_loss'], color='r', label=\"validation loss\")\nax1.set_xticks(np.arange(1, 400, 1))\nax1.set_yticks(np.arange(0, 1, 0.1))\n\nax2.plot(model_history.history['accuracy'], color='b', label=\"Training accuracy\")\nax2.plot(model_history.history['val_accuracy'], color='r',label=\"Validation accuracy\")\nax2.set_xticks(np.arange(1, 400, 1))\n\nlegend = plt.legend(loc='best', shadow=True)\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model Analysis\nFinding the Confusion matrix,Precision,Recall and F1 score to analyse the model thus created"},{"metadata":{"trusted":true},"cell_type":"code","source":"def print_confusion_matrix(confusion_matrix, class_names, figsize = (10,7), fontsize=14):\n    df_cm = pd.DataFrame(\n        confusion_matrix, index=class_names, columns=class_names, \n    )\n    fig = plt.figure(figsize=figsize)\n    try:\n        heatmap = sns.heatmap(df_cm, annot=True, fmt=\"d\")\n    except ValueError:\n        raise ValueError(\"Confusion matrix values must be integers.\")\n    heatmap.yaxis.set_ticklabels(heatmap.yaxis.get_ticklabels(), rotation=0, ha='right', fontsize=fontsize)\n    heatmap.xaxis.set_ticklabels(heatmap.xaxis.get_ticklabels(), rotation=45, ha='right', fontsize=fontsize)\n    plt.ylabel('True label')\n    plt.xlabel('Predicted label')\n    fig.savefig(os.path.join(MODEL_PATH,\"confusion_matrix.png\"))\n    return fig","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def print_heatmap(n_labels, n_predictions, class_names):\n    labels = n_labels #sess.run(tf.argmax(n_labels, 1))\n    predictions = n_predictions #sess.run(tf.argmax(n_predictions, 1))\n\n#     confusion_matrix = sess.run(tf.contrib.metrics.confusion_matrix(labels, predictions))\n    matrix = confusion_matrix(labels.argmax(axis=1),predictions.argmax(axis=1))\n    row_sum = np.sum(matrix, axis = 1)\n    w, h = matrix.shape\n\n    c_m = np.zeros((w, h))\n\n    for i in range(h):\n        c_m[i] = matrix[i] * 100 / row_sum[i]\n\n    c = c_m.astype(dtype = np.uint8)\n\n    \n    heatmap = print_confusion_matrix(c, class_names, figsize=(18,10), fontsize=20)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class_names = list()\nfor name,idx in labels_id.items():\n    class_names.append(name)\n# print(class_names)\nypred = VGG16_model.predict(valid_vgg16,verbose=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Confusion Matrix"},{"metadata":{"trusted":true},"cell_type":"code","source":"print_heatmap(ytest,ypred,class_names)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Precision Recall F1 Score"},{"metadata":{"trusted":true},"cell_type":"code","source":"ypred_class = np.argmax(ypred,axis=1)\n# print(ypred_class[:10])\nytest = np.argmax(ytest,axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"accuracy = accuracy_score(ytest,ypred_class)\nprint('Accuracy: %f' % accuracy)\n# precision tp / (tp + fp)\nprecision = precision_score(ytest, ypred_class,average='weighted')\nprint('Precision: %f' % precision)\n# recall: tp / (tp + fn)\nrecall = recall_score(ytest,ypred_class,average='weighted')\nprint('Recall: %f' % recall)\n# f1: 2 tp / (2 tp + fp + fn)\nf1 = f1_score(ytest,ypred_class,average='weighted')\nprint('F1 score: %f' % f1)","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}