{"cells":[{"metadata":{},"cell_type":"markdown","source":"# <center>  <font color=blue> Understanding The problematic Of The Project  : An Overview </center>  \n![](https://img00.deviantart.net/e3fa/i/2017/024/c/6/onirbaan_bengali_logo_by_botagainsthumanity-dawkgdn.png)\n\n   "},{"metadata":{},"cell_type":"markdown","source":"# Introduction: \nSolving problems with Artificial intelligence in a competitive manner has long been absent in Bangladesh and Bengali-speaking community. On the other hand, there has not been a well structured database for Bengali Handwritten digits for mass public use. To bring out the best minds working in machine learning and use their expertise to create a model which can easily recognize Bengali Handwritten digits, Bengali.AI organize Computer Vision Challenge."},{"metadata":{},"cell_type":"markdown","source":"# About Bengali: \nBengali (/bɛŋˈɡɔːli/),also known by its endonym Bangla , is an Indo-Aryan language primarily spoken by the Bengalis in South Asia. It is the official and most widely spoken language of Bangladesh and second most widely spoken of the 22 scheduled languages of India, behind Hindi. With approximately 228 million native speakers and another 37 million as second language speakers,Bengali is the fifth most-spoken native language and the seventh most spoken language by total number of speakers in the world."},{"metadata":{},"cell_type":"markdown","source":"# About Bengali.AI:\nBengali.AI is a community working to solve the absence of open-sourced datasets for Bengali Computer Vision/Natural Language Processing research. Bengali.AI has launched a pilot competition through which we are also making our first dataset public, which has more than 85,000+ Bengali Handwritten Digits. It’s a month-long online machine learning competition where the participants have to train their computer/model on our open-sourced database ‘NumtaDB’ to be able to detect handwritten Bengali digits (০,১,২,৩,...) and test the performance on a hidden test set through Kaggle’s online platform. It is the first of a series of competitions called “Bengali.AI Computer Vision Challenge” through which we wish to open-source more datasets in the future.  \n\n### Website :    <center>            http://www.bengali.ai </center>  \n### Industry: <center> Research </center>\n### Company size : <center> 2-10 employees </center>\n### Headquarters : <center> Dhaka,Dhaka </center>\n### Type: <center> Sole Proprietorship </center>\n### Founded : <center> 2018 </center>"},{"metadata":{},"cell_type":"markdown","source":"# What is Grapheme ? \nOne of a set of orthographic symbols (letters or combinations of letters) in a given language that serve to distinguish one word from another and usually correspond to or represent phonemes, e. g. the f in fun, the ph in phantom, and the gh in laugh.\nA grapheme is a written symbol that represents a sound (phoneme). This can be a single letter, or could be a sequence of letters, such as ai, sh, igh, tch etc. So when we say the sound /t/ this is a phoneme, but when we write the letter 't' this is a grapheme."},{"metadata":{},"cell_type":"markdown","source":"# What is the diacritics: \nIn phonetics, a diacritical mark is a  symbol—added to a letter that alters its sense, function, or pronunciation. It is also known as a diacritic or an accent mark. A diacritical mark is a point, sign, or squiggle added or attached to a letter or character to indicate appropriate stress, special pronunciation, or unusual sounds not common in the Roman alphabet."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","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 in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../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))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":false},"cell_type":"markdown","source":"# Importing datas:"},{"metadata":{"trusted":true},"cell_type":"code","source":"train=pd.read_csv('/kaggle/input/bengaliai-cv19/train.csv')\ntest=pd.read_csv('/kaggle/input/bengaliai-cv19/test.csv')\nsubmission=pd.read_csv('/kaggle/input/bengaliai-cv19/sample_submission.csv')\nclass_map=pd.read_csv('/kaggle/input/bengaliai-cv19/class_map.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data explorations:"},{"metadata":{"trusted":true},"cell_type":"code","source":"# An overview on training data.\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# General statistics on our training data.\ntrain.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# An overview on class_map data\nclass_map.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# General statstics on class_map data.\nclass_map.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# An overview on test data.\ntest.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# General infos on test datas.\ntest.info()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<font color='blue'> The above analyse show that our datas don't encompass any missing values .   \nLet's continue !</font>\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Now we will give a table which summarize our datasets shapes.\ndata=[train,test,class_map,submission]\ndata_names=['train','test','class_map','submission']\ntb=pd.DataFrame({'dataset':data_names,'shapes':[c.shape for c in data]})\ntb","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Now we will give a table which summarize the number of uniques values, per each element in the grapheme \n#used in the training images.\nelements=['grapheme_root','vowel_diacritic','consonant_diacritic']\ntble=pd.DataFrame({'element':elements,'counts':[len(train[c].unique()) for c in elements]})\ntble","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def most_used_element(df,element,n):\n    \"\"\"This function allow to determinate the n  most used value per each type element in our training\n       data.\n       \n       Args:\n       df(dataframe): the introduced dataset which contrain the training data that the function will \n                      analyse\n       element(str): the element type that we want to analyse his frequency .\n       n(int): the number of the top used elemement that we want to extracte.\n       \n       Returns:\n       \n       dff(Dataframe): the dataframe wich will give the requested most used components with their frequency\n                       of using.\n       \n       \"\"\"\n    sorted_element=df[element].value_counts(normalize=False,sort=True, ascending=False).reset_index\\\n    (name='frequency')[0:n]\n    ddf=class_map[class_map['component_type']==element]\n    components=[]\n    for i in range(n):\n        lb=sorted_element.loc[i,'index']\n        comp=ddf[ddf['label']==lb].index[0]\n        components.append(comp)\n    ddf=ddf.loc[components].drop(['component_type','label'],axis=1)\n    ddf['frequency']=sorted_element['frequency'].to_numpy()\n    \n    return ddf","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from PIL import Image\nfrom PIL import ImageDraw\nfrom PIL import ImageFont\n\ndef draw_char(char):\n    \"\"\"This function allow to draw image from the component which represent each element.\n    \n    Args: \n    char(str): it's the component of the element that we want to draw his image .\n    \n    Returns:\n    img(PIL image): the drawn image from the introduced component which represent the bengali element.\n    \n    \"\"\"\n    height=236\n    width=236\n    img=Image.new('RGB',(width,height))\n    draw=ImageDraw.Draw(img)\n    font=ImageFont.truetype('/kaggle/input/banglafonts/SolaimanLipi.ttf',120)\n    w,h=draw.textsize(char,font=font)\n    draw.text(((width-w)/2,(height-h)/2),char,font=font)\n    return img ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# the 10 most used grapheme root \ngrapheme_root_10=most_used_element(train,'grapheme_root',10)\ngrapheme_root_10","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Visualisation of the most used grapheme_root\nimport matplotlib.pyplot as plt \nfig,ax=plt.subplots(2,5,figsize=(25,15))\nax=ax.flatten()\nfor i in range(10):\n   ax[i].imshow(draw_char(grapheme_root_10['component'].iloc[i]),cmap='Greys')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# The 5 most used vowel_diacritic\nvowel_diacritic_5=most_used_element(train,'vowel_diacritic',5)\nvowel_diacritic_5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Visualization of the most used vowel_diacritic\nfig=plt.figure(figsize=(20,20))\nfor i in range(5):\n    fig.add_subplot(151+i)\n    plt.imshow(draw_char(vowel_diacritic_5['component'].iloc[i]),cmap='Greys')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# The 5 most used consonant_diacritic\nvowel_diacritic_5=most_used_element(train,'consonant_diacritic',5)\nvowel_diacritic_5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Visualization of the most used consonant_diacritic\nfig,ax=plt.subplots(1,5,figsize=(20,20))\nax=ax.flatten()\nfor i in range(5):\n    ax[i].imshow(draw_char(vowel_diacritic_5['component'].iloc[i]),cmap='Greys')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Images visualizations :"},{"metadata":{"trusted":true},"cell_type":"code","source":"def image_visualization(dt,image_id):\n    \"\"\"This function allow to return the pixel matrix of the image correspond to the introduced image_id,in\n       the introduced dataframe. The function return also the grapheme_root,consonant_diacritic and the \n       vowel_diacritic correspond to the introduced image_id. If the introduced image_id not found in the \n       introduced dataframe, the function return None.\n       \n       Args:\n       dt(DataFrame): the introduced dataframe that the function will use to extract the matrix pixel correspond\n                      to the introduced image_id .\n       image_id(str): The image_id of the image that we want to extract there datas and their labels .\n       \n       Returns: \n       im,grapheme_root,consonant_diacritic,vowel_diacritic (tuple): the pixel matrix of the grey image and their\n       labels if exist.\n\n       \"\"\"\n    \n    im=dt[dt['image_id']==image_id].values.flatten()[1:]\n    if im.size > 0 :\n        im=im.astype('float').reshape(137,236)\n        tr=train[train['image_id']==image_id].index\n        grapheme_root=train.iloc[tr[0]]['grapheme_root']\n        consonant_diacritic=train.iloc[tr[0]]['consonant_diacritic']\n        vowel_diacritic=train.iloc[tr[0]]['vowel_diacritic']\n        return im,grapheme_root,consonant_diacritic,vowel_diacritic\n        \n        \n    else :\n        return(None)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import random\nseq=random.sample(list(train.index),100) # generate a random 100 values from the index values of the train datas\nfig,ax=plt.subplots(5,2,figsize=(15,35))\nax=ax.flatten()\nj=1\nf='/kaggle/input/bengaliai-cv19/train_image_data_0.parquet'\ndf=pd.read_parquet(f)\nfor i in seq :\n    image_id=train.iloc[i]['image_id']\n    vis=image_visualization(df,image_id)\n    if (vis is not None) & (j<=10):\n       \n       \n       ax[j-1].imshow(vis[0],cmap='Greys')\n       ax[j-1].set_title(\"grapheme_root:{} ,consonant_diacritic:{} ,vowel_diacritic:{}\".format(vis[1],vis[2],vis[3]),fontsize=14)\n       \n       j+=1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Image preprocessing :"},{"metadata":{"trusted":true},"cell_type":"code","source":"import keras\n# create class which allow to data augmentation for multioutput. \nclass MultiOutputDataGenerator(keras.preprocessing.image.ImageDataGenerator):\n\n    def flow(self,\n             x,\n             y=None,\n             batch_size=32,\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\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":{"trusted":true},"cell_type":"code","source":"from PIL import Image , ImageOps\ndef preprocessing (img):\n    \"\"\" \"\"\"\n    image= Image.fromarray(img).convert('L')\n    image= ImageOps.autocontrast(image)\n    return image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Visualize how the threshol operation, could ameliorate the image quality\nsample_image=df.drop(['image_id'],axis=1).loc[df.index[1]]\nsample_image=sample_image.values.astype('float').reshape(137,236)\nthreshold_image=preprocessing(sample_image)\n\nfig,ax=plt.subplots(1,2,figsize=(10,20))\nax=ax.flatten()\nax[0].imshow(sample_image , cmap='Greys')\nax[0].set_title('Origin image ')\nax[1].imshow(threshold_image , cmap='Greys')\nax[1].set_title('preprocessed image')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.array(threshold_image)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tqdm.auto import tqdm\nimport cv2\ndef 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            img=preprocessing(image)\n            img=np.array(img)\n            \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 = img[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    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":{},"cell_type":"markdown","source":"# CNN architecture "},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.models import Sequential , Model\nfrom keras.layers import Dense,Conv2D,MaxPooling2D,Dropout,Flatten,Input,BatchNormalization,MaxPool2D,Input\n\n\nInputs= Input(shape=(64,64,1)) # create a cnn \n# add the first convolutional layer, followed by a relu layer .\nmodel=(Conv2D(32,(3,3),input_shape=(64,64,1),padding='same',activation='relu'))(Inputs)\n# add a second convolutional layer, followed by a relu layer .\nmodel=(Conv2D(32,(3,3),padding='same',activation='relu'))(model)\nmodel=(Conv2D(32,(3,3),padding='same',activation='relu'))(model)\nmodel=(Conv2D(32,(3,3),padding='same',activation='relu'))(model)\nmodel=(MaxPool2D(pool_size=(2,2),strides=(2,2)))(model)\nmodel=(Conv2D(32,(3,3),padding='same',activation='relu'))(model)\nmodel=BatchNormalization(momentum=0.15)(model)\nmodel=Dropout(rate=0.3)(model)\nmodel=(Conv2D(64,(3,3),padding='same',activation='relu'))(model)\nmodel=(Conv2D(64,(3,3),padding='same',activation='relu'))(model)\nmodel=(Conv2D(64,(3,3),padding='same',activation='relu'))(model)\nmodel=(Conv2D(64,(3,3),padding='same',activation='relu'))(model)\nmodel=(MaxPool2D(pool_size=(2,2),strides=(2,2)))(model)\nmodel=(Conv2D(64,(3,3),padding='same',activation='relu'))(model)\nmodel=BatchNormalization(momentum=0.15)(model)\nmodel=Dropout(rate=0.3)(model)\nmodel=(Conv2D(128,(3,3),padding='same',activation='relu'))(model)\nmodel=(Conv2D(128,(3,3),padding='same',activation='relu'))(model)\nmodel=(Conv2D(128,(3,3),padding='same',activation='relu'))(model)\nmodel=(Conv2D(128,(3,3),padding='same',activation='relu'))(model)\nmodel=(MaxPool2D(pool_size=(2,2),strides=(2,2)))(model)\nmodel=(Conv2D(128,(3,3),padding='same',activation='relu'))(model)\nmodel=BatchNormalization(momentum=0.15)(model)\nmodel=Dropout(rate=0.3)(model)\nmodel=(Conv2D(256,(3,3),padding='same',activation='relu'))(model)\nmodel=(Conv2D(256,(3,3),padding='same',activation='relu'))(model)\nmodel=(MaxPool2D(pool_size=(2,2),strides=(2,2)))(model)\nmodel=(Conv2D(256,(3,3),padding='same',activation='relu'))(model)\nmodel=(Conv2D(256,(3,3),padding='same',activation='relu'))(model)\nmodel=(MaxPool2D(pool_size=(2,2),strides=(2,2)))(model)\nmodel=(Conv2D(256,(3,3),padding='same',activation='relu'))(model)\nmodel=(Flatten())(model)\nmodel=BatchNormalization(momentum=0.15)(model)\nmodel=Dropout(rate=0.3)(model)\nmodel=Dense(1024,activation='relu')(model)\n\ndense=Dense(512,activation='relu')(model)\nsubdense=Dense(256,activation='relu')(dense)\nconsonant=Dense(7,activation='softmax')(dense)\ngrapheme=Dense(168,activation='softmax')(subdense)\nvowel=Dense(11,activation='softmax')(dense)\nmodel=Model(inputs=Inputs,outputs=[consonant,grapheme,vowel])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.utils import plot_model\nplot_model(model,to_file='model.png',show_shapes=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# CNN compilation :"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.optimizers import Adam\nfrom keras.losses import categorical_crossentropy\nmodel.compile(optimizer='Adam',loss='categorical_crossentropy',metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.callbacks import ReduceLROnPlateau\n#Reducing learning rate when accuracy has stopped improving.\n#We will use a callback wich will control the accuracy and reduce learning rate by 40% when the quantity\n#controlled had not enhanced after 4 epochs \nlr_consonant=ReduceLROnPlateau(monitor='dense_4_accuracy',factor=0.4,patience=4,min_lr=0.00001)\nlr_grapheme=ReduceLROnPlateau(monitor='dense_5_accuracy',factor=0.4,patience=4,min_lr=0.00001)\nlr_vowel=ReduceLROnPlateau(monitor='dense_6_accuracy',factor=0.4,patience=4,min_lr=0.00001)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Incremental learning :"},{"metadata":{},"cell_type":"markdown","source":"Because of the size of the traing data encompassed in the parquet files . We will use hereunder an incremental training method wich allow us to train our network by steps. In each step we load a file parquet and we do all the required operations to train our network, then we get rid of the loaded files to not consume a\nhuge memory."},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.utils import to_categorical\nfrom sklearn.model_selection import train_test_split\nfor i in range(4):\n    df=pd.merge(pd.read_parquet('/kaggle/input/bengaliai-cv19/train_image_data_{}.parquet'.format(i)),train,\\\n                on='image_id',how='left').drop(['image_id','grapheme'],axis=1)\n   \n    X=df.drop(['grapheme_root','vowel_diacritic','consonant_diacritic'],axis=1)\n    X=resize(X)/255\n                                                                                                   \n    X=X.to_numpy().reshape(-1,64,64,1)\n    Y_consonant=pd.get_dummies(df['consonant_diacritic']).to_numpy()\n    Y_grapheme=pd.get_dummies(df['grapheme_root']).to_numpy()\n    Y_vowel=pd.get_dummies(df['vowel_diacritic']).to_numpy()\n    del(df)\n    # Divide the data into training and test data\n    xtr,xts,ytr_consonant,yts_consonant,ytr_grapheme,yts_grapheme,ytr_vowel,yts_vowel=train_test_split(X,\\\n                                                            Y_consonant,Y_grapheme,Y_vowel,test_size=0.1)\n    \n    del(X)\n    del(Y_consonant)\n    del(Y_grapheme)\n    del(Y_vowel)\n    #data augmentation .\n    datagen=MultiOutputDataGenerator(rotation_range=10 # rotate the image\\\n                                    ,zoom_range=0.15,width_shift_range=0.2,height_shift_range=0.15)\n    datagen.fit(xtr)\n    fichier=[]\n    #train the model.\n    md=model.fit_generator(datagen.flow(xtr,{'dense_4':ytr_consonant,'dense_5':ytr_grapheme,'dense_6':\\\n                                             ytr_vowel},batch_size=256),steps_per_epoch=len(xtr)/256,\\\n                          epochs=40,validation_data=(xts,[yts_consonant,yts_grapheme,yts_vowel]),\\\n                          callbacks=[lr_consonant,lr_grapheme,lr_vowel])\n    fichier.append(md)\n    # reduce memory\n    del(xtr)\n    del(xts)\n    del(ytr_consonant)\n    del(yts_consonant)\n    del(ytr_grapheme)\n    del(yts_grapheme)\n    del(ytr_vowel)\n    del(yts_vowel)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ant=[]\nfor i in range(4):\n    ts=pd.read_parquet('/kaggle/input/bengaliai-cv19/test_image_data_{}.parquet'.format(i))\n    ts=ts.drop(['image_id'],axis=1)\n    ts=resize(ts,need_progress_bar=True)\n    tss=ts.to_numpy()/255\n    tss=tss.reshape(-1,64,64,1)\n    prediction=model.predict(tss)\n    l=len(ts)\n    del(ts)\n    m=0\n    del(tss)\n    for j in range(l):\n        ant.append(np.argmax(prediction[0][m]))\n        ant.append(np.argmax(prediction[1][m]))\n        ant.append(np.argmax(prediction[2][m]))\n        m+=1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission['target']=ant","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.to_csv('submission.csv',index=False)","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}