{"cells":[{"metadata":{"_uuid":"bccd3d46-09ea-478d-9266-9b3a4c9c8197","_cell_guid":"059442b1-ec00-4a8e-ab06-06b27287148d","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom tqdm.auto import tqdm\nfrom glob import glob\nimport time, gc\nimport cv2\n\nfrom tensorflow import keras\nimport matplotlib.image as mpimg\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Model\nfrom keras.models import clone_model\nfrom keras.layers import Dense,Conv2D,Flatten,MaxPool2D,Dropout,BatchNormalization, Input\nfrom keras.optimizers import Adam\nfrom keras.callbacks import ReduceLROnPlateau\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix\nimport PIL.Image as Image, PIL.ImageDraw as ImageDraw, PIL.ImageFont as ImageFont\nfrom matplotlib import pyplot as plt\nimport seaborn as sns\nfrom keras.utils import plot_model\n%matplotlib inline\ngc.enable()\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bf5e2f28-55d4-4967-aa18-40bbd71871a7","_cell_guid":"2035ba4e-5873-4ad9-b043-8d451a7b9d69","trusted":true},"cell_type":"code","source":"train_df = pd.read_csv('/kaggle/input/bengaliai-cv19/train.csv')\ntest_df = pd.read_csv('/kaggle/input/bengaliai-cv19/test.csv')\nclass_map_df = pd.read_csv('/kaggle/input/bengaliai-cv19/class_map.csv')\nsample_sub_df = pd.read_csv('/kaggle/input/bengaliai-cv19/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d0231e85-2477-4e12-b6eb-1387c7c9f772","_cell_guid":"87c0a1e5-9c69-4b42-8a3f-a5b25dd32f18","trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e5f959c2-a545-4b15-9471-6048d426b1fd","_cell_guid":"37e698e6-4213-40e2-8430-841e8c5c56aa","trusted":true},"cell_type":"code","source":"test_df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0e6ed38e-78c2-4624-a7c6-a9243025ce9b","_cell_guid":"473d4082-b646-49e2-b10f-0cea17f42d38","trusted":true},"cell_type":"code","source":"sample_sub_df.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b91b4eb5-9c45-488c-a353-8e0b5b801118","_cell_guid":"5adb3ae5-6e43-44d0-90b1-4815b834c1c3","trusted":true},"cell_type":"code","source":"class_map_df.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8951c784-9e8f-4eb0-8d86-83dab00c2e9c","_cell_guid":"24103f0f-c929-49ec-9d9d-de7df9086c16","trusted":true},"cell_type":"code","source":"print('Size of training data: {}'.format(train_df.shape))\nprint('Size of test data: {}'.format(test_df.shape))\nprint('Size of class map: {}'.format(class_map_df.shape))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"acc3e3a6-19f8-4a01-81d1-42c86785c9fd","_cell_guid":"117c3775-3493-454a-82a8-0e580c404f14","trusted":true},"cell_type":"code","source":"count = class_map_df.groupby('component_type').count().reset_index()\ncount","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8371c260-b052-4a04-8b3b-d630b85f73eb","_cell_guid":"cd761bda-7ec2-40f3-b7ec-2eddacc86f7f","trusted":true},"cell_type":"code","source":"# plotting labels. belonged to each class \nsns.barplot('component_type','label',data = count)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"17aec68d-240d-4f6f-bbfd-9f624fd27565","_cell_guid":"4c909036-372f-42c4-ad0a-fa508877774a","trusted":true},"cell_type":"code","source":" # now visualising some of the top labels in each class\n# uses pd.groupby to count the occurence of each label in all three classes    \nroot_component = train_df.groupby('grapheme_root').count().reset_index()[['grapheme_root','image_id']].sort_values(by = 'image_id', ascending = False)\nvowel_component = train_df.groupby('vowel_diacritic').count().reset_index().sort_values(by = 'image_id', ascending = False)[['vowel_diacritic','image_id']]\ncons_component = train_df.groupby('consonant_diacritic').count().reset_index().sort_values(by = 'image_id', ascending = False)[['consonant_diacritic','image_id']]\nroot_component","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"20d8c9d3-ca77-4914-a594-5225fef4696a","_cell_guid":"00ad5655-dec3-482b-a608-b98086fef355","trusted":true},"cell_type":"code","source":"# images vs grapheme_root\nplt.figure(figsize = (10,10))\nsns.barplot('grapheme_root','image_id',data = root_component,order = root_component['grapheme_root'] )","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b1ac1e00-196f-4731-a8fb-d8b9eca444c9","_cell_guid":"ba726af9-c204-4547-a7ba-dab6da1248d5","trusted":true,"_kg_hide-output":false},"cell_type":"code","source":"# images vs grapheme_root\nplt.figure(figsize = (10,10))\nsns.barplot('grapheme_root','image_id',data = root_component,order = root_component['grapheme_root'] )#","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1af60737-43e8-4da1-91c8-a2957ad88c82","_cell_guid":"d2f9b418-660f-45a9-b950-d60a55c73bbb","trusted":true},"cell_type":"code","source":"# plotting 10 most occuring among them\nplt.figure(figsize = (10,10))\nsns.barplot('grapheme_root','image_id',data = root_component.iloc[0:10],order = root_component['grapheme_root'][0:10] )","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"23cfe6fc-8db2-482f-b231-846589b58220","_cell_guid":"cb6bbcad-2d32-491a-957b-b333d2a7b849","trusted":true},"cell_type":"code","source":"# now finding how these 10 looks like\nnp.array(root_component['grapheme_root'].map(dict(class_map_df[class_map_df['component_type']=='grapheme_root'][['label', 'component']].values)))[0:10]","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6091c283-1d12-4f80-a920-9400b7b95cde","_cell_guid":"6d7f7e62-b869-47df-a8ee-380949e60bde","trusted":true},"cell_type":"code","source":"# plotting 10 least among given\nplt.figure(figsize = (10,10))\nsns.barplot('grapheme_root','image_id',data = root_component.iloc[-10:],order = root_component['grapheme_root'][-10:] )","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4c2c1549-1d9d-47c2-913e-414386b7aa33","_cell_guid":"052958f1-0404-4108-9976-6a8578daedd4","trusted":true},"cell_type":"code","source":"# now finding how these 10 looks like\nnp.array(root_component['grapheme_root'].map(dict(class_map_df[class_map_df['component_type']=='grapheme_root'][['label', 'component']].values)))[-10:]","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"19b87ace-a6b7-4195-af3f-49935509b2b5","_cell_guid":"a3a15656-576f-453d-9475-493fa4e197c7","trusted":true},"cell_type":"code","source":"# same for vowel_diacritics\n# images vs vowel_diacritic\nplt.figure(figsize = (10,10))\nsns.barplot('vowel_diacritic','image_id',data = vowel_component,order = vowel_component['vowel_diacritic'] )","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"abc28dce-653d-4c87-9cc4-12db2d7258ff","_cell_guid":"11195500-7927-4bf9-8c30-b766b0428605","trusted":true},"cell_type":"code","source":"# now finding how these  looks like\nnp.array(vowel_component['vowel_diacritic'].map(dict(class_map_df[class_map_df['component_type']=='vowel_diacritic'][['label', 'component']].values)))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e3dc5a07-b3ee-4a1b-a709-0e4797a64b31","_cell_guid":"135c3710-1e34-475a-8146-036faa7546e8","trusted":true},"cell_type":"code","source":"# same for 'consonant_diacritic'\n# images vs 'consonant_diacritic'\nplt.figure(figsize = (10,10))\nsns.barplot('consonant_diacritic','image_id',data = cons_component,order = cons_component['consonant_diacritic'] )","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"16566fc6-08c5-4d73-a241-6a2a43b5b618","_cell_guid":"b2e78d05-b231-49bd-9bc2-98f2cea4d18c","trusted":true},"cell_type":"code","source":"# now finding how these  looks like\nnp.array(cons_component['consonant_diacritic'].map(dict(class_map_df[class_map_df['component_type']=='consonant_diacritic'][['label', 'component']].values)))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bf1380ad-5949-40a6-8a87-f187c4ccedd6","_cell_guid":"e4b2eb1d-08a6-4c14-bd89-9bb24a0fa5d5","trusted":true},"cell_type":"markdown","source":"# At this stage various analysis can be made\n1. in every cases some labels are predominant have a large no. while some are relatively small\n2. To solve this, a custom data augmentor needs to be created for multi label outputs","execution_count":null},{"metadata":{"_uuid":"b08e7429-d3b3-42f9-abf9-bc266363f4c0","_cell_guid":"85e0057c-1c6c-4f42-aee8-76e9b68e97ed","trusted":true},"cell_type":"markdown","source":"# MODEL BUILDING AND TRAINING","execution_count":null},{"metadata":{"_uuid":"1d3bc5ee-aaea-4622-b13c-bee0cbfa339e","_cell_guid":"cbce7281-e0bc-468d-9279-531fbee8903b","trusted":true},"cell_type":"markdown","source":"*train data need to be processed iteratively and deleted at regulat intervals due to huge data*","execution_count":null},{"metadata":{"_uuid":"b0822152-aa43-4ac4-a6a8-9050cbf1077c","_cell_guid":"a1c9f497-3cad-4309-aeda-0a380e001846","trusted":true},"cell_type":"code","source":"train_df = train_df.drop(['grapheme'], axis=1, inplace=False)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"679ed34d-5cb3-49dd-b572-1944a775e817","_cell_guid":"5b9c2f58-e90e-42d9-ae8a-8f355324c5fc","trusted":true},"cell_type":"code","source":"train_df[['grapheme_root', 'vowel_diacritic', 'consonant_diacritic']] = train_df[['grapheme_root', 'vowel_diacritic', 'consonant_diacritic']].astype('uint8')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"928dee5c-7b50-4563-a695-7085827d9280","_cell_guid":"0857a1c9-9194-4e58-88cc-9024617b9b4f","trusted":true},"cell_type":"code","source":"IMG_SIZE=64\nN_CHANNELS=1","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6329ee9c-eb70-49bf-ac6b-365134dc64df","_cell_guid":"51a99179-b9c2-4021-8908-50699ca47450","trusted":true},"cell_type":"markdown","source":" *now uses opencv thresholding technique to centre crop the train data, taking references from some kernels","execution_count":null},{"metadata":{"_uuid":"b2f03670-3bbe-481b-9558-b5b0c8a4d2e9","_cell_guid":"fb70705c-a195-484f-b3cc-41a5db20ad96","trusted":true},"cell_type":"code","source":"def resize(df, size=64, need_progress_bar=True):\n    resized = {}\n    resize_size=64\n    if need_progress_bar:\n        for i in tqdm(range(df.shape[0])):\n            image=df.loc[df.index[i]].values.reshape(137,236)\n            _, thresh = cv2.threshold(image, 30, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)\n            contours, _ = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)[-2:]\n\n            idx = 0 \n            ls_xmin = []\n            ls_ymin = []\n            ls_xmax = []\n            ls_ymax = []\n            for cnt in contours:\n                idx += 1\n                x,y,w,h = cv2.boundingRect(cnt)\n                ls_xmin.append(x)\n                ls_ymin.append(y)\n                ls_xmax.append(x + w)\n                ls_ymax.append(y + h)\n                xmin = min(ls_xmin)\n                ymin = min(ls_ymin)\n                xmax = max(ls_xmax)\n                ymax = max(ls_ymax)\n                roi = image[ymin:ymax,xmin:xmax]\n                resized_roi = cv2.resize(roi, (resize_size, resize_size),interpolation=cv2.INTER_AREA)\n                resized[df.index[i]] = resized_roi.reshape(-1)\n\n    else:\n        for i in range(df.shape[0]):\n            #image = cv2.resize(df.loc[df.index[i]].values.reshape(137,236),(size,size),None,fx=0.5,fy=0.5,interpolation=cv2.INTER_AREA)\n            image=df.loc[df.index[i]].values.reshape(137,236)\n            _, thresh = cv2.threshold(image, 30, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)\n            contours, _ = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)[-2:]\n\n            idx = 0 \n            ls_xmin = []\n            ls_ymin = []\n            ls_xmax = []\n            ls_ymax = []\n            for cnt in contours:\n                idx += 1\n                x,y,w,h = cv2.boundingRect(cnt)\n                ls_xmin.append(x)\n                ls_ymin.append(y)\n                ls_xmax.append(x + w)\n                ls_ymax.append(y + h)\n                xmin = min(ls_xmin)\n                ymin = min(ls_ymin)\n                xmax = max(ls_xmax)\n                ymax = max(ls_ymax)\n\n                roi = image[ymin:ymax,xmin:xmax]\n                resized_roi = cv2.resize(roi, (resize_size, resize_size),interpolation=cv2.INTER_AREA)\n                resized[df.index[i]] = resized_roi.reshape(-1)\n    resized = pd.DataFrame(resized).T\n    return resized","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2044f565-d389-4d6c-b77c-c425c6a126d9","_cell_guid":"88eac72f-dc9e-4598-88f5-d25c60cc6f4f","trusted":true},"cell_type":"code","source":"def get_dummies(df):\n    cols = []\n    for col in df:\n        cols.append(pd.get_dummies(df[col].astype(str)))\n    return pd.concat(cols, axis=1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2e0124e8-b702-4875-b376-aadc0544fb7c","_cell_guid":"1c8fb351-11bf-4167-ae38-a4533622b189","trusted":true},"cell_type":"code","source":"# model preparation\n\ninputs = Input(shape = (IMG_SIZE, IMG_SIZE, 1))\n\nmodel = Conv2D(filters=32, kernel_size=(3, 3), padding='SAME', activation='relu', input_shape=(IMG_SIZE, IMG_SIZE, 1))(inputs)\nmodel = Conv2D(filters=32, kernel_size=(3, 3), padding='SAME', activation='relu')(model)\nmodel = BatchNormalization(momentum=0.15)(model)\nmodel = MaxPool2D(pool_size=(2, 2))(model)\nmodel = Conv2D(filters=32, kernel_size=(5, 5), padding='SAME', activation='relu')(model)\nmodel = Dropout(rate=0.25)(model)\n\nmodel = Conv2D(filters=64, kernel_size=(3, 3), padding='SAME', activation='relu')(model)\nmodel = Conv2D(filters=64, kernel_size=(3, 3), padding='SAME', activation='relu')(model)\nmodel = BatchNormalization(momentum=0.15)(model)\nmodel = MaxPool2D(pool_size=(2, 2))(model)\nmodel = Conv2D(filters=64, kernel_size=(5, 5), padding='SAME', activation='relu')(model)\nmodel = BatchNormalization(momentum=0.15)(model)\nmodel = Dropout(rate=0.25)(model)\n\nmodel = Conv2D(filters=128, kernel_size=(3, 3), padding='SAME', activation='relu')(model)\nmodel = Conv2D(filters=128, kernel_size=(3, 3), padding='SAME', activation='relu')(model)\nmodel = BatchNormalization(momentum=0.15)(model)\nmodel = MaxPool2D(pool_size=(2, 2))(model)\nmodel = Conv2D(filters=128, kernel_size=(5, 5), padding='SAME', activation='relu')(model)\nmodel = BatchNormalization(momentum=0.15)(model)\nmodel = Dropout(rate=0.2)(model)\n\nmodel = Conv2D(filters=256, kernel_size=(3, 3), padding='SAME', activation='relu')(model)\nmodel = Conv2D(filters=256, kernel_size=(3, 3), padding='SAME', activation='relu')(model)\nmodel = Conv2D(filters=256, kernel_size=(3, 3), padding='SAME', activation='relu')(model)\nmodel = BatchNormalization(momentum=0.15)(model)\nmodel = MaxPool2D(pool_size=(2, 2))(model)\nmodel = Conv2D(filters=256, kernel_size=(5, 5), padding='SAME', activation='relu')(model)\nmodel = BatchNormalization(momentum=0.20)(model)\nmodel = Dropout(rate=0.25)(model)\n\nmodel = Flatten()(model)\nmodel = Dense(512, activation = \"relu\",name= 'dense_')(model)\nmodel = Dropout(rate=0.25)(model)\ndense = Dense(256, activation = \"relu\",name= 'dense_1')(model)\n\nhead_root = Dense(168, activation = 'softmax',name= 'dense_2')(dense)\nhead_vowel = Dense(11, activation = 'softmax',name= 'dense_3')(dense)\nhead_consonant = Dense(7, activation = 'softmax',name= 'dense_4')(dense)\n\nmodel = Model(inputs=inputs, outputs=[head_root, head_vowel, head_consonant]) # 3 outputs one for each","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ade4c9d7-d0a4-4c1f-b06f-eac959481def","_cell_guid":"d2b26810-b967-4187-b9ba-6902d2a44120","trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fab88187-46e9-49a3-924f-31f8bd40613f","_cell_guid":"ecbdcc87-9c71-46b4-83ac-c364e00233dc","trusted":true},"cell_type":"code","source":"# plotting the model how it exactly look like\nplot_model(model, to_file='model.png')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"40506fe2-3913-47f4-9faa-2d4d343c800d","_cell_guid":"7b2b0fb4-eeeb-4fb5-971b-ef4fda54a94d","trusted":true},"cell_type":"code","source":"model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3d20da6d-bf37-4579-bd32-e72f5424e122","_cell_guid":"31732dfc-2c0c-4348-b978-7ec323976082","trusted":true},"cell_type":"code","source":"# Set a learning rate annealer. Learning rate will be half after 3 epochs if accuracy is not increased\nlearning_rate_reduction_root = ReduceLROnPlateau(monitor='dense_2_accuracy', \n                                            patience=3, \n                                            verbose=1,\n                                            factor=0.5, \n                                            min_lr=0.00001)\nlearning_rate_reduction_vowel = ReduceLROnPlateau(monitor='dense_3_accuracy', \n                                            patience=3, \n                                            verbose=1,\n                                            factor=0.5, \n                                            min_lr=0.00001)\nlearning_rate_reduction_consonant = ReduceLROnPlateau(monitor='dense_4_accuracy', \n                                            patience=3, \n                                            verbose=1,\n                                            factor=0.5, \n                                            min_lr=0.00001)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ba9088e3-931e-4f2c-bb92-e9b08df12456","_cell_guid":"1690cfcb-acaf-4196-a428-3b416b1d7e79","trusted":true},"cell_type":"code","source":"batch_size = 256\nepochs = 16","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"be720114-8e73-4da0-9bad-0e07fc31bb8d","_cell_guid":"ece0990b-f791-4715-b321-bfa583ec3ba4","trusted":true},"cell_type":"code","source":"# creating a custom data augmentor which supports multi class output\n\nclass MultiOutputDataGenerator(keras.preprocessing.image.ImageDataGenerator):\n\n    def flow(self,\n             x,\n             y=None,\n             batch_size=256,\n             shuffle=True,\n             sample_weight=None,\n             seed=None,\n             save_to_dir= None,\n             save_prefix='',\n             save_format='png',\n             subset=None):\n\n        targets = None\n        target_lengths = {}\n        ordered_outputs = []\n        for output, target in y.items():\n            if targets is None:\n                targets = target\n            else:\n                targets = np.concatenate((targets, target), axis=1)\n            target_lengths[output] = target.shape[1]\n            ordered_outputs.append(output)\n            \n        for flowx, flowy in super().flow(x, targets, batch_size=batch_size,\n                                     shuffle=shuffle):\n            target_dict = {}\n            i = 0\n            for output in ordered_outputs:\n                target_length = target_lengths[output]\n                target_dict[output] = flowy[:, i: i + target_length]\n                i += target_length\n\n            yield flowx, target_dict","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5b7aa96a-2ae3-4bf5-9824-8cf3e514e898","_cell_guid":"79a1ddac-59f5-441f-bde5-65dda2a4cf8e","trusted":true},"cell_type":"code","source":"HEIGHT = 137\nWIDTH = 236\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d9c3f9d1-d1d0-43df-8913-65ddaf6b3222","_cell_guid":"40e8cbfc-147c-4dd0-bf88-9629f45fda5b","trusted":true},"cell_type":"code","source":"# training iteratively using loops\n\ngc.enable()\nhistories = []\nfor i in range(3):\n    \n    gc.collect()\n    len(gc.get_objects())\n    train_df_new = pd.merge(pd.read_parquet(f'/kaggle/input/bengaliai-cv19/train_image_data_{i}.parquet'), train_df.iloc[i*len(train_df)//4:(i+1)*len(train_df)//4], on='image_id').drop(['image_id'], axis=1)\n    \n    # Visualize few samples of current training dataset\n    fig, ax = plt.subplots(nrows=3, ncols=4, figsize=(16, 8))\n    count=0\n    for row in ax:\n        for col in row:\n            col.imshow(resize(train_df_new.drop(['grapheme_root', 'vowel_diacritic', 'consonant_diacritic'], axis=1).iloc[[count]], need_progress_bar=False).values.reshape(-1).reshape(IMG_SIZE, IMG_SIZE).astype(np.float64))\n            count += 1\n    plt.show()\n    \n    X_train = train_df_new.drop(['grapheme_root', 'vowel_diacritic', 'consonant_diacritic'], axis=1)\n    X_train = resize(X_train)/255\n    \n    # CNN takes images in shape `(batch_size, h, w, channels)`, so reshape the images\n    X_train = X_train.values.reshape(-1, IMG_SIZE, IMG_SIZE, N_CHANNELS)\n    \n    Y_train_root = pd.get_dummies(train_df_new['grapheme_root']).values\n    Y_train_vowel = pd.get_dummies(train_df_new['vowel_diacritic']).values\n    Y_train_consonant = pd.get_dummies(train_df_new['consonant_diacritic']).values\n\n    print(f'Training images: {X_train.shape}')\n    print(f'Training labels root: {Y_train_root.shape}')\n    print(f'Training labels vowel: {Y_train_vowel.shape}')\n    print(f'Training labels consonants: {Y_train_consonant.shape}')\n\n    # Divide the data into training and validation set\n    x_train, x_test, y_train_root, y_test_root, y_train_vowel, y_test_vowel, y_train_consonant, y_test_consonant = train_test_split(X_train, Y_train_root, Y_train_vowel, Y_train_consonant, test_size=0.08, random_state=666)\n    gc.collect()\n    \n    del train_df_new\n    del X_train\n    del Y_train_root\n    del Y_train_vowel\n    del Y_train_consonant\n    len(gc.get_objects())\n    gc.collect()\n\n    # Data augmentation for creating more training data\n    datagen = MultiOutputDataGenerator(\n        featurewise_center=False,  # set input mean to 0 over the dataset\n        samplewise_center=False,  # set each sample mean to 0\n        featurewise_std_normalization=False,  # divide inputs by std of the dataset\n        samplewise_std_normalization=False,  # divide each input by its std\n        zca_whitening=False,  # apply ZCA whitening\n        rotation_range=8,  # randomly rotate images in the range (degrees, 0 to 180)\n        zoom_range = 0.15, # Randomly zoom image \n        width_shift_range=0.15,  # randomly shift images horizontally (fraction of total width)\n        height_shift_range=0.15,  # randomly shift images vertically (fraction of total height)\n        horizontal_flip=False,  # randomly flip images\n        vertical_flip=False)  # randomly flip images\n        \n    # This will just calculate parameters required to augment the given data. This won't perform any augmentations\n    datagen.flow(x_train)\n\n    # Fit the model\n    history = model.fit_generator(datagen.flow(x_train, {'dense_2': y_train_root, 'dense_3': y_train_vowel, 'dense_4': y_train_consonant}, batch_size=batch_size),\n                              epochs = epochs, validation_data = (x_test, [y_test_root, y_test_vowel, y_test_consonant]), \n                              steps_per_epoch=x_train.shape[0] // batch_size, \n                              callbacks=[learning_rate_reduction_root, learning_rate_reduction_vowel, learning_rate_reduction_consonant])\n\n    histories.append(history)\n    \n    del datagen\n    gc.collect()\n    len(gc.get_objects())\n    # Delete to reduce memory usage\n    del x_train\n    del x_test\n    del y_train_root\n    del y_test_root\n    del y_train_vowel\n    del y_test_vowel\n    del y_train_consonant\n    del y_test_consonant\n   \n    gc.collect()\n    \n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"gc.collect()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"031f4b7a-a406-42b5-8822-ee16fcc041db","_cell_guid":"ee594027-48d5-4b3c-abe7-3c8b8fbd7920","trusted":true},"cell_type":"code","source":"# functions for plotting losses and accuracies\n\ndef plot_loss(his, epoch, title):\n    plt.style.use('ggplot')\n    plt.figure()\n    plt.plot(np.arange(0, epoch), his.history['loss'], label='train_loss')\n    plt.plot(np.arange(0, epoch), his.history['dense_2_loss'], label='train_root_loss')\n    plt.plot(np.arange(0, epoch), his.history['dense_3_loss'], label='train_vowel_loss')\n    plt.plot(np.arange(0, epoch), his.history['dense_4_loss'], label='train_consonant_loss')\n    \n    plt.plot(np.arange(0, epoch), his.history['val_dense_2_loss'], label='val_train_root_loss')\n    plt.plot(np.arange(0, epoch), his.history['val_dense_3_loss'], label='val_train_vowel_loss')\n    plt.plot(np.arange(0, epoch), his.history['val_dense_4_loss'], label='val_train_consonant_loss')\n    \n    plt.title(title)\n    plt.xlabel('Epoch #')\n    plt.ylabel('Loss')\n    plt.legend(loc='upper right')\n    plt.show()\n\ndef plot_acc(his, epoch, title):\n    plt.style.use('ggplot')\n    plt.figure()\n    plt.plot(np.arange(0, epoch), his.history['dense_2_accuracy'], label='train_root_acc')\n    plt.plot(np.arange(0, epoch), his.history['dense_3_accuracy'], label='train_vowel_accuracy')\n    plt.plot(np.arange(0, epoch), his.history['dense_4_accuracy'], label='train_consonant_accuracy')\n    \n    plt.plot(np.arange(0, epoch), his.history['val_dense_2_accuracy'], label='val_root_acc')\n    plt.plot(np.arange(0, epoch), his.history['val_dense_3_accuracy'], label='val_vowel_accuracy')\n    plt.plot(np.arange(0, epoch), his.history['val_dense_4_accuracy'], label='val_consonant_accuracy')\n    plt.title(title)\n    plt.xlabel('Epoch #')\n    plt.ylabel('Accuracy')\n    plt.legend(loc='upper right')\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"49bfa547-0277-4923-b3b2-fd9024d15544","_cell_guid":"e245c944-d35a-45c9-a35f-530b3235e3ff","trusted":true},"cell_type":"code","source":"# plotting graphs for all four sets\nfor i in range(3):\n    plot_loss(histories[i], epochs, f'Training Dataset: {i}')\n    plot_acc(histories[i], epochs, f'Training Dataset: {i}')\n    \ndel histories\ngc.collect()\nlen(gc.get_objects())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.save('bengalimodal.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}