## Most Important
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
from pathlib import Path
from PIL import Image

## less Important
from functools import partial
import os
from scipy import stats
import missingno as msno
import joblib
import tarfile
import shutil
import urllib

## Sklearn
from sklearn import datasets
## Preprocessing
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
## Metrics
from sklearn.metrics import accuracy_score

## tensorflow & Keras
import tensorflow as tf    ## i will use tf for every thing and for keras using tf.keras
"""
## Loading the Data and Look at the Big Picture
"""
"""
`Only for training here`
"""
train_labels = pd.read_csv('../input/arabic-hwr-ai-pro-intake1/train.csv')
train_images = Path(r'../input/arabic-hwr-ai-pro-intake1/train')

## read these all training images paths as Series
train_images_paths = pd.Series(sorted(list(train_images.glob(r'*.png'))), name='Filepath').astype(str)

train_images_paths.head()
train_labels['label'].unique()
train_labels['label'] = train_labels['label'] - 1
train_labels['label'].unique()
"""
## Explore the Data
"""
img_key_value = {}
for value in train_labels['label'].unique():
    img_key_value[value] = train_labels[train_labels['label']==value].index[0]
    
img_index = list(img_key_value.values())
img_label = list(img_key_value.keys())

fig, ax = plt.subplots(4, 7, figsize=(12, 8))

i = 0
for row in range(4):
    for col in range(7):
        plt.sca(ax[row, col])
        plt.title(f'label = {img_label[i]}')
        img = plt.imread(train_images_paths.iloc[img_index[i]])
        plt.imshow(img)
        plt.axis('off')
        i+=1
np.asarray(plt.imread(train_images_paths.iloc[0])).shape

from PIL import Image
img = Image.open(train_images_paths.iloc[0]).convert('L')
np.asarray(img)/255
print('Number of Instances in train_set =>', len(train_images_paths))
print('Number of Instances in train_labels =>', len(train_labels))

print()

img = plt.imread(train_images_paths.iloc[img_index[20]])
print('shape of each Image is =>', img.shape)

img
"""
## Data Preprocessing
"""
train_full_labels = train_labels['label'].values
train_full_set = np.empty((13440, 64, 64), dtype=np.float32)
newsize = (64, 64)

for idx, path in enumerate(train_images_paths):
    img = Image.open(path).convert('L')
    img = img.resize(newsize)
    img = np.asarray(img)/255
    train_full_set[idx] = img
    
train_full_set = train_full_set.reshape(train_full_set.shape[0], train_full_set.shape[1],\
                                        train_full_set.shape[2], 1)
print('train_full_set.shape =>', train_full_set.shape)
print('train_full_labels.shape =>', train_full_labels.shape)
"""
## Split the Data
"""
X_train, X_valid, y_train, y_valid = train_test_split(train_full_set, train_full_labels,\
                                        test_size=0.1, stratify=train_full_labels, random_state=42)

print('X_train.shape =>', X_train.shape)
print('X_valid.shape =>', X_valid.shape)
print('y_train.shape =>', y_train.shape)
print('y_valid.shape =>', y_valid.shape)
y_valid[y_valid == 1].shape
np.random.seed(10)
"""
## Model Training
"""
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, GlobalAveragePooling2D, BatchNormalization, Dropout, Dense

def create_model(optimizer='adam', kernel_initializer='he_normal', activation='relu'):
  # create model
  model = Sequential()
  model.add(Conv2D(filters=16, kernel_size=3, padding='same', input_shape=(64, 64, 1), kernel_initializer=kernel_initializer, activation=activation))
  model.add(BatchNormalization())
  model.add(MaxPooling2D(pool_size=2))
  model.add(Dropout(0.1))

  model.add(Conv2D(filters=32, kernel_size=3, padding='same', kernel_initializer=kernel_initializer, activation=activation))
  model.add(BatchNormalization())
  model.add(MaxPooling2D(pool_size=2))
  model.add(Dropout(0.1))

  model.add(Conv2D(filters=64, kernel_size=3, padding='same', kernel_initializer=kernel_initializer, activation=activation))
  model.add(BatchNormalization())
  model.add(MaxPooling2D(pool_size=2))
  model.add(Dropout(0.1))

  model.add(Conv2D(filters=128, kernel_size=3, padding='same', kernel_initializer=kernel_initializer, activation=activation))
  model.add(BatchNormalization())
  model.add(MaxPooling2D(pool_size=2))
  model.add(Dropout(0.1))
  model.add(GlobalAveragePooling2D())
  
  #Fully connected final layer
  model.add(Dense(28, activation='softmax'))
    
  # Compile model
  model.compile(loss='sparse_categorical_crossentropy', metrics=['accuracy'], optimizer=optimizer)
  return model
model = create_model(optimizer='Adam', kernel_initializer='uniform', activation='relu')
model.summary()
from keras.callbacks import ModelCheckpoint, EarlyStopping

# using checkpoints to save model weights to be used later instead of training again on the same epochs.
checkpointer = ModelCheckpoint(filepath='weights6.hdf5', verbose=1, save_best_only=True)
early_stopp = EarlyStopping(patience=10, restore_best_weights=True)
history = model.fit(X_train, y_train, 
                    validation_data=(X_valid, y_valid),
                    epochs=100, batch_size=20, verbose=1)
# history = model.fit(X_train, y_train, 
#                     validation_data=(X_valid, y_valid),
#                     epochs=100, batch_size=20, verbose=1, callbacks=[checkpointer, early_stopp])
pd.DataFrame(history.history).plot(figsize=(10, 6));
loss_all_data, acc_all_data = model.evaluate(train_full_set, train_full_labels, verbose=0)
print('loss_all_data =>', loss_all_data)
print('acc_all_data =>', acc_all_data)
"""
## Evaluation on Testing DataSet
"""
test_labels = pd.read_csv('../input/arabic-hwr-ai-pro-intake1/test.csv')
test_images = Path(r'../input/arabic-hwr-ai-pro-intake1/test')

## read these all training images paths as Series
test_images_paths = pd.Series(sorted(list(test_images.glob(r'*.png'))), name='Filepath').astype(str)

test_images_paths.head()
print('Number of Instances in test_set is', len(test_images_paths))
test_full_set = np.empty((3360, 64, 64), dtype=np.float32)
newsize = (64, 64)

for idx, path in enumerate(test_images_paths):
    img = Image.open(path).convert('L')
    img = img.resize(newsize)
    img = np.asarray(img)/255
    test_full_set[idx] = img
    
test_full_set = test_full_set.reshape(test_full_set.shape[0], test_full_set.shape[1],\
                                        test_full_set.shape[2], 1)
print('test_full_set.shape =>', test_full_set.shape)
y_preds_classes = np.argmax(model.predict(test_full_set) , axis=-1)
y_preds_classes = y_preds_classes + 1
y_preds_classes.shape
test_labels['label'] = y_preds_classes
test_labels['label'].value_counts().plot(kind='bar')
test_labels[['id', 'label']].to_csv('/kaggle/working/submission.csv', index=False)
"""
## Done :D
"""