{"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":"gpu","dataSources":[{"sourceId":65471,"databundleVersionId":7211464,"sourceType":"competition"}],"dockerImageVersionId":30626,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os \nos.environ[\"KERAS_BACKEND\"] = \"tensorflow\"\n\nimport numpy as np \nimport tensorflow as tf\nimport tensorflow as tf \nfrom tensorflow.keras.layers import (Input, \n                                     GlobalAveragePooling2D, \n                                     Dense, \n                                     BatchNormalization, \n                                     Dropout,\n#                                      InstanceNormalization\n                                    )\nfrom tensorflow.keras.callbacks import EarlyStopping, LearningRateScheduler\n\nfrom tensorflow.keras.applications.efficientnet import EfficientNetB7 as EfficientNet\n\nimport matplotlib.pyplot as plt","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-12-18T11:16:11.848536Z","iopub.execute_input":"2023-12-18T11:16:11.849049Z","iopub.status.idle":"2023-12-18T11:16:23.307057Z","shell.execute_reply.started":"2023-12-18T11:16:11.849011Z","shell.execute_reply":"2023-12-18T11:16:23.306226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TRAIN_PATH = '/kaggle/input/arabic-letters-classification/Final_Arabic_Alpha_dataset/Final_Arabic_Alpha_dataset/train'\nIMAGE_SHAPE = [100, 100, 3]\nNUM_CLASSES = 65\nBATCH_SIZE = 512","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:23.309166Z","iopub.execute_input":"2023-12-18T11:16:23.310322Z","iopub.status.idle":"2023-12-18T11:16:23.314631Z","shell.execute_reply.started":"2023-12-18T11:16:23.310285Z","shell.execute_reply":"2023-12-18T11:16:23.313785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load Data ","metadata":{}},{"cell_type":"code","source":"def load_filepaths_labels(folder_path):\n    file_paths = []\n    labels = []\n\n    # List all directories (labels) in the given folder\n    for label in os.listdir(folder_path):\n        label_path = os.path.join(folder_path, label)\n\n        # Check if the item in the directory is a subdirectory\n        if os.path.isdir(label_path):\n            # List all files in the subdirectory\n            files = os.listdir(label_path)\n            \n            # Create file paths and corresponding labels\n            file_paths.extend([os.path.join(label_path, file) for file in files])\n            labels.extend([int(label)] * len(files))\n\n    return file_paths, labels","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:23.315771Z","iopub.execute_input":"2023-12-18T11:16:23.316036Z","iopub.status.idle":"2023-12-18T11:16:23.339000Z","shell.execute_reply.started":"2023-12-18T11:16:23.316013Z","shell.execute_reply":"2023-12-18T11:16:23.338216Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fileps, labels = load_filepaths_labels(TRAIN_PATH)\nfileps.pop(13107), labels.pop(13107)","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:23.339957Z","iopub.execute_input":"2023-12-18T11:16:23.340249Z","iopub.status.idle":"2023-12-18T11:16:38.971681Z","shell.execute_reply.started":"2023-12-18T11:16:23.340225Z","shell.execute_reply":"2023-12-18T11:16:38.970670Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Split features to train and validation","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ntrain_fileps, val_fileps, train_labels, val_labels = train_test_split(fileps, labels, test_size = 0.1, random_state = 42)","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:38.975359Z","iopub.execute_input":"2023-12-18T11:16:38.975645Z","iopub.status.idle":"2023-12-18T11:16:39.347433Z","shell.execute_reply.started":"2023-12-18T11:16:38.975622Z","shell.execute_reply":"2023-12-18T11:16:39.346648Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocess Data","metadata":{}},{"cell_type":"code","source":"def min_max(tensor, t):\n    # Find the indices where the values are greater than t\n        \n    indices = tf.where(tensor > t)\n#         print(indices)\n    # Find the minimum and maximum indices\n    min_ = indices[0][0]\n    max_ = indices[-1][0]\n    return min_, max_\n\ndef cut_image(image):\n    # Get the dimensions of the image\n    \n    t = 0.3\n    pos_image = tf.where(image < 0, -1 * image, image)\n    pos_image = tf.where(pos_image < t, 0.0, pos_image)            \n    \n    x_min, x_max = min_max(tf.reduce_sum(pos_image, axis=0), 1)\n    y_min, y_max = min_max(tf.reduce_sum(pos_image, axis=1), 1)\n    # Find the first and last values greater than 0.1 along the x-axis\n\n    # Crop the image using the computed indices\n    pos_image = pos_image[y_min:y_max, :, :]\n    pos_image = pos_image[:, x_min:x_max, :]\n\n    return pos_image, (x_min, x_max)\n    \ndef normalize_image(image):\n    # Assuming 'image' is a TensorFlow tensor\n    min_val = tf.reduce_min(image)\n    max_val = tf.reduce_max(image)\n    \n    # Normalize the image to the range [0, 1]\n    normalized_image = (image - min_val) / (max_val - min_val)\n\n    return normalized_image\n\ndef _1(image): \n    return 1- image\n    \ndef load_decode_image(filepath, label, cut_image_ = False):\n    # Read and decode the image\n    image = tf.io.read_file(filepath)\n    image = tf.image.decode_image(image, channels=1)\n        \n    image = tf.image.convert_image_dtype(image, tf.float32)\n    image = normalize_image(image)\n    image = _1(image)\n    \n    if cut_image_: \n        image, x_minmax = cut_image(image)\n    image = tf.image.resize_with_pad(image, target_height=IMAGE_SHAPE[0], target_width=IMAGE_SHAPE[1])\n\n    image = tf.image.grayscale_to_rgb(image)\n    return image, label\n\ndef build_dataset(filepaths, labels, batch_size = 8, cut_image_ = False, shuffle = True, prefetch = True): \n    \n    dataset = tf.data.Dataset.from_tensor_slices((filepaths, labels))\n    \n    dataset = dataset.map(lambda x, y: load_decode_image(x, y, cut_image_ = cut_image_))\n    dataset = dataset.batch(batch_size)\n    \n    if shuffle: \n        dataset = dataset.shuffle(3)\n        \n    if prefetch: \n        dataset = dataset.prefetch(tf.data.AUTOTUNE)\n        \n    return dataset ","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:39.348621Z","iopub.execute_input":"2023-12-18T11:16:39.349250Z","iopub.status.idle":"2023-12-18T11:16:39.365507Z","shell.execute_reply.started":"2023-12-18T11:16:39.349214Z","shell.execute_reply":"2023-12-18T11:16:39.364701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset_with_cut = build_dataset(fileps, labels, batch_size = 512, cut_image_ = True, shuffle = False)\ndataset_without_cut = build_dataset(fileps, labels, batch_size = 512, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:39.366406Z","iopub.execute_input":"2023-12-18T11:16:39.366681Z","iopub.status.idle":"2023-12-18T11:16:43.486234Z","shell.execute_reply.started":"2023-12-18T11:16:39.366658Z","shell.execute_reply":"2023-12-18T11:16:43.485384Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image = next(iter(dataset_with_cut))[0][10]\nimage_ = next(iter(dataset_without_cut))[0][10]\n\nplt.imshow(image_.numpy())\nplt.show()\n\nplt.imshow(image.numpy())\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:43.487402Z","iopub.execute_input":"2023-12-18T11:16:43.487677Z","iopub.status.idle":"2023-12-18T11:16:45.281066Z","shell.execute_reply.started":"2023-12-18T11:16:43.487654Z","shell.execute_reply":"2023-12-18T11:16:45.280148Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# clear memory\ndel dataset_with_cut, dataset_without_cut\n# build finnal dataset \ntrain_dataset = build_dataset(train_fileps, train_labels, batch_size = 32, cut_image_ = True)\nvalid_dataset = build_dataset(val_fileps, val_labels, batch_size = 64, cut_image_ = True)","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:45.282554Z","iopub.execute_input":"2023-12-18T11:16:45.283141Z","iopub.status.idle":"2023-12-18T11:16:45.921344Z","shell.execute_reply.started":"2023-12-18T11:16:45.283104Z","shell.execute_reply":"2023-12-18T11:16:45.920609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Define Model","metadata":{}},{"cell_type":"code","source":"enet = EfficientNet(\n    include_top=False,\n    weights='imagenet',\n    input_shape=IMAGE_SHAPE,\n    classifier_activation='softmax'\n)\nenet.trainable = False\n\ndef build_model(input_shape, n_labels): \n    inputs = Input(shape=input_shape)\n    \n    x = enet(inputs)\n    \n    # Add BatchNormalization and Dropout\n    x = BatchNormalization()(x)\n    x = Dropout(0.3)(x)\n    \n    x = GlobalAveragePooling2D()(x)\n    \n    # Add another BatchNormalization and Dropout before the output layer if needed\n    x = BatchNormalization()(x)\n    x = Dropout(0.1)(x)\n    \n    x = Dense(128, activation = 'relu')(x)\n    outputs = Dense(n_labels, activation='softmax')(x)\n    \n    return tf.keras.Model(inputs, outputs)    \nmodel = build_model(IMAGE_SHAPE, 65)\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:45.922971Z","iopub.execute_input":"2023-12-18T11:16:45.923282Z","iopub.status.idle":"2023-12-18T11:16:57.961825Z","shell.execute_reply.started":"2023-12-18T11:16:45.923255Z","shell.execute_reply":"2023-12-18T11:16:57.960887Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define EarlyStopping callback\nearly_stopping = EarlyStopping(\n    monitor='val_loss',  # You can choose a different metric if needed\n    patience=50,  # Number of epochs with no improvement after which training will be stopped\n    restore_best_weights=True,  # Restore model weights from the epoch with the best value of the monitored metric\n)\n\n# Define a simple learning rate scheduler as an example\ndef lr_scheduler(epoch, lr):\n    if epoch < 10:\n        return lr  # Keep the initial learning rate for the first 10 epochs\n    else:\n        return lr * tf.math.exp(-0.1)  # Decay the learning rate exponentially after the 10th epoch\n\n# Define LearningRateScheduler callback\nlr_scheduler = LearningRateScheduler(lr_scheduler)\n\n# Define the CrossEntropyLoss\nloss_fn = tf.keras.losses.SparseCategoricalCrossentropy()\n\n# Assuming you have already defined and compiled your model\nmodel.compile(optimizer='adam', loss=loss_fn, metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:57.963228Z","iopub.execute_input":"2023-12-18T11:16:57.963690Z","iopub.status.idle":"2023-12-18T11:16:57.997069Z","shell.execute_reply.started":"2023-12-18T11:16:57.963652Z","shell.execute_reply":"2023-12-18T11:16:57.996008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train Model","metadata":{}},{"cell_type":"code","source":"history = model.fit(train_dataset, \n          epochs = 100, \n          validation_data = valid_dataset, \n          callbacks = [early_stopping, lr_scheduler])","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:16:57.998315Z","iopub.execute_input":"2023-12-18T11:16:57.998593Z","iopub.status.idle":"2023-12-18T11:20:14.307690Z","shell.execute_reply.started":"2023-12-18T11:16:57.998568Z","shell.execute_reply":"2023-12-18T11:20:14.306210Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.save('')","metadata":{"execution":{"iopub.status.busy":"2023-12-18T11:20:14.308641Z","iopub.status.idle":"2023-12-18T11:20:14.309000Z","shell.execute_reply.started":"2023-12-18T11:20:14.308826Z","shell.execute_reply":"2023-12-18T11:20:14.308842Z"},"trusted":true},"execution_count":null,"outputs":[]}]}