{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Handwritten Character Recognition with Neural Network\n\nThis notebook contains code to build a deep learning model for recognizing handwritten characters, i.e, English alphabets from A-Z and 0-9.\nA neural network is modelled and trained over a dataset containing images of alphabets and numbers.","metadata":{}},{"cell_type":"markdown","source":"### Required Packages","metadata":{}},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings('ignore')\nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport cv2\nimport numpy as np\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Flatten, Conv2D, MaxPool2D, Dropout\nfrom tensorflow.keras.optimizers import SGD, Adam\nfrom keras.callbacks import ReduceLROnPlateau, EarlyStopping\nfrom tensorflow.keras.utils import to_categorical\nimport pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.utils import shuffle","metadata":{"execution":{"iopub.status.busy":"2022-07-31T11:47:55.143720Z","iopub.execute_input":"2022-07-31T11:47:55.144895Z","iopub.status.idle":"2022-07-31T11:48:02.832553Z","shell.execute_reply.started":"2022-07-31T11:47:55.144729Z","shell.execute_reply":"2022-07-31T11:48:02.831256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Data Fetching","metadata":{}},{"cell_type":"code","source":"# alphabet dataset\ndf1 = pd.read_csv(\"../input/az-handwritten-alphabets-in-csv-format/A_Z Handwritten Data.csv\")\n\n# digit dataset\ndf2 = pd.read_csv(\"../input/digit-recognizer/train.csv\")\n\n# combining both the datasets to get a single data set\ndf1['0'] = df1['0']+10\ndf1.columns = df2.columns\nframes = [df1, df2]  \ndf = pd.concat(frames)\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2022-07-31T11:48:10.311886Z","iopub.execute_input":"2022-07-31T11:48:10.312567Z","iopub.status.idle":"2022-07-31T11:48:49.388903Z","shell.execute_reply.started":"2022-07-31T11:48:10.312531Z","shell.execute_reply":"2022-07-31T11:48:49.387654Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Feature Selections","metadata":{}},{"cell_type":"code","source":"X = df.drop('label',axis = 1) #feautures\ny = df['label'] #target","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:02:59.301214Z","iopub.execute_input":"2022-07-31T07:02:59.301516Z","iopub.status.idle":"2022-07-31T07:03:00.456138Z","shell.execute_reply.started":"2022-07-31T07:02:59.301489Z","shell.execute_reply":"2022-07-31T07:03:00.455239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Data Splitting","metadata":{}},{"cell_type":"code","source":"train_x, test_x, train_y, test_y = train_test_split(X, y, test_size = 0.2)\n\ntrain_x = np.reshape(train_x.values, (train_x.shape[0], 28,28))\ntest_x = np.reshape(test_x.values, (test_x.shape[0], 28,28))\n\nprint(\"Train data shape: \", train_x.shape)\nprint(\"Test data shape: \", test_x.shape)","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:03:00.458375Z","iopub.execute_input":"2022-07-31T07:03:00.459188Z","iopub.status.idle":"2022-07-31T07:03:04.415638Z","shell.execute_reply.started":"2022-07-31T07:03:00.459156Z","shell.execute_reply":"2022-07-31T07:03:04.414607Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Exploratory Data Analysis","metadata":{}},{"cell_type":"code","source":"# check for missing data\ndef missing_data(data):\n    total = data.isnull().sum().sort_values(ascending = False)\n    percent = (data.isnull().sum()/data.isnull().count()*100).sort_values(ascending = False)\n    return pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])\nmissing_data(df)","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:03:04.416901Z","iopub.execute_input":"2022-07-31T07:03:04.417232Z","iopub.status.idle":"2022-07-31T07:03:06.235596Z","shell.execute_reply.started":"2022-07-31T07:03:04.417203Z","shell.execute_reply":"2022-07-31T07:03:06.234459Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# checking Characters distribution\nword_dict = {0:'0',1:'1',2:'2',3:'3',4:'4',5:'5',6:'6',7:'7',8:'8',9:'9',10:'A',11:'B',12:'C',13:'D',14:'E',15:'F',16:'G',17:'H',18:'I',19:'J',20:'K',21:'L',22:'M',23:'N',24:'O',25:'P',26:'Q',27:'R',28:'S',29:'T',30:'U',31:'V',32:'W',33:'X', 34:'Y',35:'Z'}\ny_int = np.int0(y)\ncount = np.zeros(36, dtype='int')\nfor i in y_int:\n    count[i] +=1\n\nalphabets = []\nfor i in word_dict.values():\n    alphabets.append(i)\n\nfig, ax = plt.subplots(1,1, figsize=(15,15))\nax.barh(alphabets, count)\n\nplt.xlabel(\"Number of elements \")\nplt.ylabel(\"Characters\")\nplt.grid()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:03:06.237532Z","iopub.execute_input":"2022-07-31T07:03:06.237976Z","iopub.status.idle":"2022-07-31T07:03:07.035144Z","shell.execute_reply.started":"2022-07-31T07:03:06.237912Z","shell.execute_reply":"2022-07-31T07:03:07.034068Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# printing some shuffled samples\n\nshuff = shuffle(train_x[:-100])\nshuff = shuff.astype(np.uint8)\nfig, ax = plt.subplots(3,3, figsize = (10,10))\naxes = ax.flatten()\n\nfor i in range(9):\n    _, shu = cv2.threshold(shuff[i], 30, 200, cv2.THRESH_BINARY)\n    axes[i].imshow(np.reshape(shuff[i], (28,28)), cmap=\"Greys\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:03:07.037824Z","iopub.execute_input":"2022-07-31T07:03:07.038891Z","iopub.status.idle":"2022-07-31T07:03:14.008078Z","shell.execute_reply.started":"2022-07-31T07:03:07.038847Z","shell.execute_reply":"2022-07-31T07:03:14.006915Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Data Preprocessing","metadata":{}},{"cell_type":"code","source":"train_X = train_x.reshape(train_x.shape[0],train_x.shape[1],train_x.shape[2],1)\nprint(\"New shape of train data: \", train_X.shape)\ntest_X = test_x.reshape(test_x.shape[0], test_x.shape[1], test_x.shape[2],1)\nprint(\"New shape of train data: \", test_X.shape)","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:03:14.009802Z","iopub.execute_input":"2022-07-31T07:03:14.011125Z","iopub.status.idle":"2022-07-31T07:03:14.019364Z","shell.execute_reply.started":"2022-07-31T07:03:14.011065Z","shell.execute_reply":"2022-07-31T07:03:14.018024Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_yOHE = to_categorical(train_y, num_classes = 36, dtype='int')\nprint(\"New shape of train labels: \", train_yOHE.shape)\ntest_yOHE = to_categorical(test_y, num_classes = 36, dtype='int')\nprint(\"New shape of test labels: \", test_yOHE.shape)","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:03:14.021647Z","iopub.execute_input":"2022-07-31T07:03:14.022200Z","iopub.status.idle":"2022-07-31T07:03:14.060884Z","shell.execute_reply.started":"2022-07-31T07:03:14.022152Z","shell.execute_reply":"2022-07-31T07:03:14.059854Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model","metadata":{}},{"cell_type":"code","source":"model = Sequential()\n\nmodel.add(Conv2D(filters=32, kernel_size=(3, 3), activation='relu', input_shape=(28,28,1)))\nmodel.add(MaxPool2D(pool_size=(2, 2), strides=2))\n\nmodel.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu', padding = 'same'))\nmodel.add(MaxPool2D(pool_size=(2, 2), strides=2))\n\nmodel.add(Conv2D(filters=128, kernel_size=(3, 3), activation='relu', padding = 'valid'))\nmodel.add(MaxPool2D(pool_size=(2, 2), strides=2))\n\nmodel.add(Flatten())\n\nmodel.add(Dense(64,activation =\"relu\"))\nmodel.add(Dense(128,activation =\"relu\"))\n\nmodel.add(Dense(36,activation =\"softmax\"))","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:03:14.063770Z","iopub.execute_input":"2022-07-31T07:03:14.064211Z","iopub.status.idle":"2022-07-31T07:03:14.296188Z","shell.execute_reply.started":"2022-07-31T07:03:14.064181Z","shell.execute_reply":"2022-07-31T07:03:14.295023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer = Adam(learning_rate=0.001), loss='categorical_crossentropy', metrics=['accuracy'])\n\nhistory = model.fit(train_X, train_yOHE, epochs=5,  validation_data = (test_X,test_yOHE))","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:03:14.297699Z","iopub.execute_input":"2022-07-31T07:03:14.298626Z","iopub.status.idle":"2022-07-31T07:06:29.869686Z","shell.execute_reply.started":"2022-07-31T07:03:14.298580Z","shell.execute_reply":"2022-07-31T07:06:29.868860Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:06:29.871795Z","iopub.execute_input":"2022-07-31T07:06:29.872571Z","iopub.status.idle":"2022-07-31T07:06:29.881031Z","shell.execute_reply.started":"2022-07-31T07:06:29.872525Z","shell.execute_reply":"2022-07-31T07:06:29.879800Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Accuracy Metrics","metadata":{}},{"cell_type":"code","source":"print(\"The validation accuracy is :\", history.history['val_accuracy'][0]*100)\nprint(\"The training accuracy is :\", history.history['accuracy'][0]*100)\nprint(\"The validation loss is :\", history.history['val_loss'][0]*100)\nprint(\"The training loss is :\", history.history['loss'][0]*100)","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:06:29.882615Z","iopub.execute_input":"2022-07-31T07:06:29.883682Z","iopub.status.idle":"2022-07-31T07:06:29.894282Z","shell.execute_reply.started":"2022-07-31T07:06:29.883641Z","shell.execute_reply":"2022-07-31T07:06:29.893137Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"score = model.evaluate(test_X,test_yOHE, verbose = 0)\nprint('Test loss: {}%'.format(score[0] * 100))\nprint('Test score: {}%'.format(score[1] * 100))\n\nprint(\"MLP Error: %.2f%%\" % (100 - score[1] * 100))","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:06:29.895840Z","iopub.execute_input":"2022-07-31T07:06:29.896451Z","iopub.status.idle":"2022-07-31T07:06:44.551172Z","shell.execute_reply.started":"2022-07-31T07:06:29.896418Z","shell.execute_reply":"2022-07-31T07:06:44.550254Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Learning Curve","metadata":{}},{"cell_type":"code","source":"def draw_learning_curve(history, keys=['accuracy', 'loss']):\n    plt.figure(figsize=(20,8))\n    for i, key in enumerate(keys):\n        plt.subplot(1, 2, i + 1)\n        sns.lineplot(x = history.epoch, y = history.history[key])\n        sns.lineplot(x = history.epoch, y = history.history['val_' + key])\n        plt.title('Learning Curve')\n        plt.ylabel(key.title())\n        plt.xlabel('Epoch')\n#         plt.ylim(ylim)\n        plt.legend(['train', 'test'], loc='best')\n    plt.show()\ndraw_learning_curve(history)","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:06:44.552375Z","iopub.execute_input":"2022-07-31T07:06:44.552787Z","iopub.status.idle":"2022-07-31T07:06:44.561073Z","shell.execute_reply.started":"2022-07-31T07:06:44.552754Z","shell.execute_reply":"2022-07-31T07:06:44.559991Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Predictions","metadata":{}},{"cell_type":"code","source":"fig, axes = plt.subplots(3,3, figsize=(8,9))\naxes = axes.flatten()\nfor i,ax in enumerate(axes):\n    img = np.reshape(test_X[i], (28,28))\n    ax.imshow(img, cmap=\"Greys\")\n    \n    pred = word_dict[np.argmax(test_yOHE[i])]\n    ax.set_title(\"Prediction: \"+pred)\n    ax.grid()","metadata":{"execution":{"iopub.status.busy":"2022-07-31T07:06:59.159203Z","iopub.execute_input":"2022-07-31T07:06:59.159611Z","iopub.status.idle":"2022-07-31T07:07:00.303094Z","shell.execute_reply.started":"2022-07-31T07:06:59.159569Z","shell.execute_reply":"2022-07-31T07:07:00.302117Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Saving Model","metadata":{}},{"cell_type":"code","source":"model.save(r'model_hand.h5')","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}