{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":65471,"databundleVersionId":7211464,"sourceType":"competition"}],"dockerImageVersionId":30616,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# <div> <center> <b> NN Arabic Handwriting Recognition </b> </center> </div>\n\n## <b> Credentials: </b> (E-JUST Submission)\n- Name: Yousef Ibrahim Gomaa Mahmoud\n- ID: 320210207\n- Group: 1\n- Section: AID 3\n\n## <b> Notebook Workflow: </b>\n- Environment Setup\n- Data Pre-processing\n- Data Visualization\n- Model Definition\n- Training the Model\n- Prediction\n\n## <b> Introduction: </b>\n<p> In this notebook, a model is to be trained to <b> recognize/classify arabic letters </b> using a convolutional neural network (CNN) through Keras, a TensorFlow tool. </p>\n\n## <b> Dataset: </b>\nhttps://www.kaggle.com/competitions/arabic-letters-classification","metadata":{}},{"cell_type":"markdown","source":"## Environment Setup:\n### Importing Packages","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nfrom matplotlib import pyplot as plt\nimport tensorflow as tf\nfrom tensorflow import keras","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:16.547841Z","iopub.execute_input":"2023-12-23T16:00:16.548825Z","iopub.status.idle":"2023-12-23T16:00:16.553580Z","shell.execute_reply.started":"2023-12-23T16:00:16.548787Z","shell.execute_reply":"2023-12-23T16:00:16.552485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### GPU Checkup:\nKaggle provides 2 GPUs which are relied upon heavily during the training phase.","metadata":{}},{"cell_type":"code","source":"for device in tf.config.list_physical_devices():\n    print(\": {}\".format(device.name))","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:16.563845Z","iopub.execute_input":"2023-12-23T16:00:16.564173Z","iopub.status.idle":"2023-12-23T16:00:16.569005Z","shell.execute_reply.started":"2023-12-23T16:00:16.564148Z","shell.execute_reply":"2023-12-23T16:00:16.568087Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Loading the Dataset(s):","metadata":{}},{"cell_type":"code","source":"datasets = ['/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/train',\\\n            '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/test',\n           '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset']\nNUM_CLASS = 65\nIMAGE_SIZE = (160,160)\nBATCH_SIZE = 512\nSEED = 43\nEPOCHS = 50","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:16.612790Z","iopub.execute_input":"2023-12-23T16:00:16.613042Z","iopub.status.idle":"2023-12-23T16:00:16.617750Z","shell.execute_reply.started":"2023-12-23T16:00:16.613021Z","shell.execute_reply":"2023-12-23T16:00:16.616837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- There are 65 classes to classify into (0-64)\n- Images must be resized to a consistent size in order to train properly.","metadata":{}},{"cell_type":"code","source":"# str = \"user001_heh_middle_042.png\"\n# str[8:18]","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:16.633701Z","iopub.execute_input":"2023-12-23T16:00:16.633947Z","iopub.status.idle":"2023-12-23T16:00:16.637615Z","shell.execute_reply.started":"2023-12-23T16:00:16.633926Z","shell.execute_reply":"2023-12-23T16:00:16.636684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Pre-processing:\nSplitting training data into 'Training' and 'Validation' for the model to train on.","metadata":{}},{"cell_type":"code","source":"train_images = tf.keras.utils.image_dataset_from_directory(\n    datasets[0],\n    validation_split=0.2,\n    color_mode='grayscale',\n    label_mode=\"categorical\",\n    subset=\"training\",\n    shuffle=True,\n    seed=SEED,\n    image_size=IMAGE_SIZE,\n    batch_size=BATCH_SIZE)\n","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:16.682690Z","iopub.execute_input":"2023-12-23T16:00:16.682945Z","iopub.status.idle":"2023-12-23T16:00:23.852931Z","shell.execute_reply.started":"2023-12-23T16:00:16.682922Z","shell.execute_reply":"2023-12-23T16:00:23.852125Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_validation = tf.keras.utils.image_dataset_from_directory(\n    datasets[0],\n    validation_split=0.2,\n    label_mode=\"categorical\",\n    color_mode='grayscale',\n    subset=\"validation\",\n    shuffle=True,\n    seed=SEED,\n    image_size=IMAGE_SIZE,\n    batch_size=BATCH_SIZE)","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:23.854478Z","iopub.execute_input":"2023-12-23T16:00:23.854758Z","iopub.status.idle":"2023-12-23T16:00:26.713215Z","shell.execute_reply.started":"2023-12-23T16:00:23.854733Z","shell.execute_reply":"2023-12-23T16:00:26.712260Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Visualization:","metadata":{}},{"cell_type":"code","source":"class_names = train_images.class_names\nplt.figure(figsize=(10, 10))\nfor images, labels in train_images.take(1): # Takes a batch and shows the first 9 images\n    for i in range(9):\n        ax = plt.subplot(3, 3, i + 1)\n        plt.imshow(images[i].numpy().astype(\"uint8\"), cmap=plt.cm.Greys_r)\n        plt.title(class_names[np.where(np.array(labels[i])==1)[0][0]])\n        plt.axis(\"off\")","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:26.714831Z","iopub.execute_input":"2023-12-23T16:00:26.715103Z","iopub.status.idle":"2023-12-23T16:00:29.367229Z","shell.execute_reply.started":"2023-12-23T16:00:26.715078Z","shell.execute_reply":"2023-12-23T16:00:29.366238Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for images, labels in train_images:\n    print(images.shape)\n    print(labels.shape)\n    break","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:29.369905Z","iopub.execute_input":"2023-12-23T16:00:29.370537Z","iopub.status.idle":"2023-12-23T16:00:31.929072Z","shell.execute_reply.started":"2023-12-23T16:00:29.370496Z","shell.execute_reply":"2023-12-23T16:00:31.928239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- (Batch Size, Width, Height, 1 Image Tensor Channel (Greyscale))\n- (Batch Size, Number of Classes)","metadata":{}},{"cell_type":"markdown","source":"## Model Definition:","metadata":{}},{"cell_type":"code","source":"model = tf.keras.Sequential([\n    tf.keras.layers.Rescaling(1./255),\n    tf.keras.layers.experimental.preprocessing.RandomRotation(0.1),\n    tf.keras.layers.experimental.preprocessing.RandomZoom(0.1),\n    tf.keras.layers.Conv2D(32, (3, 3), activation = 'relu', padding = 'same'),\n    tf.keras.layers.MaxPooling2D(2, 2),\n    tf.keras.layers.Conv2D(64, (3, 3), activation = 'relu', padding = 'same'),\n    tf.keras.layers.MaxPooling2D(2, 2),\n    tf.keras.layers.Conv2D(64, (3, 3), activation = 'relu', padding = 'same'),\n    tf.keras.layers.MaxPooling2D(2, 2),\n    tf.keras.layers.Conv2D(128, (3, 3), activation = 'relu', padding = 'same'),\n    tf.keras.layers.MaxPooling2D(2, 2),\n    tf.keras.layers.Conv2D(256, (3, 3), activation = 'relu', padding = 'same'),\n    tf.keras.layers.MaxPooling2D(2, 2),\n    tf.keras.layers.Flatten(),\n    tf.keras.layers.Dense(1024, activation='relu',\n#                            kernel_regularizer=tf.keras.regularizers.l2(0.001)\n                         ),\n    tf.keras.layers.Dropout(0.2),\n    tf.keras.layers.Dense(NUM_CLASS, activation=tf.nn.softmax)\n])","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:31.930222Z","iopub.execute_input":"2023-12-23T16:00:31.930551Z","iopub.status.idle":"2023-12-23T16:00:31.963636Z","shell.execute_reply.started":"2023-12-23T16:00:31.930526Z","shell.execute_reply":"2023-12-23T16:00:31.962787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model Summary:","metadata":{}},{"cell_type":"code","source":"model.build(input_shape=(BATCH_SIZE, IMAGE_SIZE[0], IMAGE_SIZE[1], 1))\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:31.964750Z","iopub.execute_input":"2023-12-23T16:00:31.965127Z","iopub.status.idle":"2023-12-23T16:00:32.221296Z","shell.execute_reply.started":"2023-12-23T16:00:31.965100Z","shell.execute_reply":"2023-12-23T16:00:32.219909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model Optimization:","metadata":{}},{"cell_type":"code","source":"learning_rate = 0.001\nlr_mod = tf.keras.optimizers.schedules.ExponentialDecay(learning_rate, decay_steps=100000,\\\n                                                             decay_rate=0.96, staircase=True)\n\nmodel.compile(optimizer = tf.keras.optimizers.Adam(learning_rate=lr_mod), loss = 'categorical_crossentropy', metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:32.222931Z","iopub.execute_input":"2023-12-23T16:00:32.223688Z","iopub.status.idle":"2023-12-23T16:00:32.238926Z","shell.execute_reply.started":"2023-12-23T16:00:32.223649Z","shell.execute_reply":"2023-12-23T16:00:32.238021Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training the Model:","metadata":{}},{"cell_type":"code","source":"h1 = model.fit(train_images,\n              validation_data=train_validation,\n              epochs=EPOCHS)","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:00:32.240119Z","iopub.execute_input":"2023-12-23T16:00:32.240766Z","iopub.status.idle":"2023-12-23T16:23:02.213792Z","shell.execute_reply.started":"2023-12-23T16:00:32.240734Z","shell.execute_reply":"2023-12-23T16:23:02.211476Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(h1.history['loss'])\nplt.plot(h1.history['val_loss'])\nplt.title('Model Loss')\nplt.ylabel('loss')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:02.215888Z","iopub.execute_input":"2023-12-23T16:23:02.216673Z","iopub.status.idle":"2023-12-23T16:23:02.527353Z","shell.execute_reply.started":"2023-12-23T16:23:02.216634Z","shell.execute_reply":"2023-12-23T16:23:02.526408Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(h1.history['accuracy'])\nplt.plot(h1.history['val_accuracy'])\nplt.title('Model Accuracy')\nplt.ylabel('accuracy')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:02.531681Z","iopub.execute_input":"2023-12-23T16:23:02.532037Z","iopub.status.idle":"2023-12-23T16:23:02.811917Z","shell.execute_reply.started":"2023-12-23T16:23:02.532012Z","shell.execute_reply":"2023-12-23T16:23:02.811040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Saving the Model:","metadata":{}},{"cell_type":"markdown","source":"Keras format:","metadata":{}},{"cell_type":"code","source":"model.save('nn-arabic-handwriting-320210207.keras')","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:02.813080Z","iopub.execute_input":"2023-12-23T16:23:02.813375Z","iopub.status.idle":"2023-12-23T16:23:03.246854Z","shell.execute_reply.started":"2023-12-23T16:23:02.813349Z","shell.execute_reply":"2023-12-23T16:23:03.245819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Loading the Model:","metadata":{}},{"cell_type":"code","source":"# model = tf.keras.models.load_model('nn-arabic-handwriting-320210207.keras')","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:03.248145Z","iopub.execute_input":"2023-12-23T16:23:03.248523Z","iopub.status.idle":"2023-12-23T16:23:03.252844Z","shell.execute_reply.started":"2023-12-23T16:23:03.248490Z","shell.execute_reply":"2023-12-23T16:23:03.251937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prediction:","metadata":{}},{"cell_type":"markdown","source":"Loading the 'Test' dataset:","metadata":{}},{"cell_type":"code","source":"test_images = tf.keras.utils.image_dataset_from_directory(\n        datasets[1],\n        labels=None,\n        label_mode=\"categorical\",\n        color_mode='grayscale',\n        shuffle=False,\n        image_size=IMAGE_SIZE,\n        batch_size=BATCH_SIZE)","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:03.254006Z","iopub.execute_input":"2023-12-23T16:23:03.254322Z","iopub.status.idle":"2023-12-23T16:23:08.716033Z","shell.execute_reply.started":"2023-12-23T16:23:03.254292Z","shell.execute_reply":"2023-12-23T16:23:08.715065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(10, 10))\nfor images in test_images.take(1): # Takes a batch and shows the first 9 images\n    for i in range(9):\n        ax = plt.subplot(3, 3, i + 1)\n        plt.imshow(images[i].numpy().astype(\"uint8\"), cmap=plt.cm.Greys_r)","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:08.717349Z","iopub.execute_input":"2023-12-23T16:23:08.718043Z","iopub.status.idle":"2023-12-23T16:23:10.505471Z","shell.execute_reply.started":"2023-12-23T16:23:08.718006Z","shell.execute_reply":"2023-12-23T16:23:10.504554Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for images in test_images:\n    print(images.shape)\n    break","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:10.506587Z","iopub.execute_input":"2023-12-23T16:23:10.506845Z","iopub.status.idle":"2023-12-23T16:23:10.824783Z","shell.execute_reply.started":"2023-12-23T16:23:10.506823Z","shell.execute_reply":"2023-12-23T16:23:10.823787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions = model.predict(test_images)","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:10.828098Z","iopub.execute_input":"2023-12-23T16:23:10.828379Z","iopub.status.idle":"2023-12-23T16:23:17.292140Z","shell.execute_reply.started":"2023-12-23T16:23:10.828355Z","shell.execute_reply":"2023-12-23T16:23:17.291281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_list = os.listdir(datasets[1])","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:17.293353Z","iopub.execute_input":"2023-12-23T16:23:17.293693Z","iopub.status.idle":"2023-12-23T16:23:17.302325Z","shell.execute_reply.started":"2023-12-23T16:23:17.293666Z","shell.execute_reply":"2023-12-23T16:23:17.301545Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_list = sorted(os.listdir(datasets[0]))\nprint(labels_list)","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:17.303464Z","iopub.execute_input":"2023-12-23T16:23:17.304108Z","iopub.status.idle":"2023-12-23T16:23:17.309587Z","shell.execute_reply.started":"2023-12-23T16:23:17.304071Z","shell.execute_reply":"2023-12-23T16:23:17.308565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions[1][22]","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:17.310749Z","iopub.execute_input":"2023-12-23T16:23:17.311034Z","iopub.status.idle":"2023-12-23T16:23:17.319875Z","shell.execute_reply.started":"2023-12-23T16:23:17.311010Z","shell.execute_reply":"2023-12-23T16:23:17.319012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Making 'predictions.csv':","metadata":{}},{"cell_type":"code","source":"predictions.shape","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:17.321024Z","iopub.execute_input":"2023-12-23T16:23:17.321300Z","iopub.status.idle":"2023-12-23T16:23:17.329457Z","shell.execute_reply.started":"2023-12-23T16:23:17.321277Z","shell.execute_reply":"2023-12-23T16:23:17.328598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_predictions = pd.DataFrame(columns=['ID','Label'], dtype=(np.int32,np.int32))\n\npredictions_mod = np.argmax(predictions, 1)\n\nfor idx,image in enumerate(sorted(img_list)):\n#     print(image, predictions_mod[idx])\n    df2 = pd.DataFrame([[int(image.split(\".\")[0]), int(labels_list[predictions_mod[idx]])]], columns=['ID','Label'])\n    df_predictions = pd.concat([df_predictions, df2])","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:17.330514Z","iopub.execute_input":"2023-12-23T16:23:17.330770Z","iopub.status.idle":"2023-12-23T16:23:21.880276Z","shell.execute_reply.started":"2023-12-23T16:23:17.330748Z","shell.execute_reply":"2023-12-23T16:23:21.879477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(predictions_mod)","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:21.881381Z","iopub.execute_input":"2023-12-23T16:23:21.881679Z","iopub.status.idle":"2023-12-23T16:23:21.886787Z","shell.execute_reply.started":"2023-12-23T16:23:21.881655Z","shell.execute_reply":"2023-12-23T16:23:21.885817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_predictions.head()","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:21.887735Z","iopub.execute_input":"2023-12-23T16:23:21.887962Z","iopub.status.idle":"2023-12-23T16:23:21.902200Z","shell.execute_reply.started":"2023-12-23T16:23:21.887942Z","shell.execute_reply":"2023-12-23T16:23:21.901209Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_predictions.sort_values(by='ID', inplace=True)","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:21.904322Z","iopub.execute_input":"2023-12-23T16:23:21.905039Z","iopub.status.idle":"2023-12-23T16:23:21.913188Z","shell.execute_reply.started":"2023-12-23T16:23:21.905013Z","shell.execute_reply":"2023-12-23T16:23:21.912295Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_predictions.reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:21.914499Z","iopub.execute_input":"2023-12-23T16:23:21.914885Z","iopub.status.idle":"2023-12-23T16:23:21.927718Z","shell.execute_reply.started":"2023-12-23T16:23:21.914836Z","shell.execute_reply":"2023-12-23T16:23:21.926792Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_predictions.to_csv('predictions.csv', index=False, header=True) ","metadata":{"execution":{"iopub.status.busy":"2023-12-23T16:23:21.928794Z","iopub.execute_input":"2023-12-23T16:23:21.929704Z","iopub.status.idle":"2023-12-23T16:23:21.958182Z","shell.execute_reply.started":"2023-12-23T16:23:21.929676Z","shell.execute_reply":"2023-12-23T16:23:21.957544Z"},"trusted":true},"execution_count":null,"outputs":[]}]}