{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Importing and formatting the data"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os, keras, math\nfrom keras.utils import to_categorical \nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras import layers, models, regularizers\n\n# Putting the data in to pandas DataFrames\ntrain_data = pd.read_csv('/kaggle/input/Kannada-MNIST/train.csv')\ntest_data = pd.read_csv('/kaggle/input/Kannada-MNIST/test.csv')\nextra_train_data = pd.read_csv('/kaggle/input/Kannada-MNIST/Dig-MNIST.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Formatting the data\ndef data_prep(dataframe):\n    array = dataframe.values\n    array = array[:, 1:]\n    array = array.reshape(array.shape[0], 28, 28, 1)\n    array = array.astype('float32')/255\n    return array\n\n\ntrain_X = data_prep(train_data)\ntest_X = data_prep(test_data)\n\ntrain_y = to_categorical((train_data.values)[:, 0])\n\nprint(train_X.shape, train_y.shape, test_X.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# We will be using data augmentation to allow us to simulate having a larger dataset\ndatagen = ImageDataGenerator(\n    rotation_range=40,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    shear_range=0.2)\n\ndatagen.fit(train_X)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Defining and testing the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Defining a function to build the model\ndef build_model():\n    model = models.Sequential()\n    model.add(layers.Conv2D(64, (3, 3), activation='relu', input_shape=(28, 28, 1)))\n    model.add(layers.BatchNormalization(axis=1))\n    model.add(layers.Conv2D(128, (3, 3), activation='relu'))\n    model.add(layers.MaxPooling2D((2, 2)))\n    model.add(layers.Conv2D(128, (3, 3), activation='relu'))\n    model.add(layers.BatchNormalization(axis=1))\n    model.add(layers.Conv2D(256, (3, 3), activation='relu'))\n    model.add(layers.MaxPooling2D((2, 2)))\n    model.add(layers.Flatten())\n    model.add(layers.Dense(256, activation='relu'))\n    model.add(layers.Dropout(0.3))\n    model.add(layers.Dense(256, activation='relu'))\n    model.add(layers.Dropout(0.3))\n    model.add(layers.Dense(10, activation='softmax'))\n    model.compile(optimizer='nadam', loss='categorical_crossentropy', metrics=['accuracy'])\n    return model\n\n\n# Building and fitting a model with a 0.1 validation split\ntrain_X_short = train_X[:54000]\ntrain_y_short = train_y[:54000]\nval_X = train_X[54000:]\nval_y = train_y[54000:]\nprint(train_X_short.shape, train_y_short.shape, val_X.shape, val_y.shape)\n\nmodel = build_model()\nhistory = model.fit_generator(datagen.flow(train_X_short, train_y_short, batch_size=32),\n                              validation_data=(val_X, val_y), steps_per_epoch=100, epochs=300, verbose=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plotting the training and validation accuracy\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nacc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\nepochs = [i+1 for i in range(len(acc))]\n\nacc_short = []\nval_acc_short = []\nepochs_short = []\n\nfor i in range(len(epochs)):\n    if i % (len(epochs)//30) == 0:\n        epochs_short.append(i)\n        acc_short.append(acc[i])\n        val_acc_short.append(val_acc[i])\n        \n\nplt.plot(epochs_short, acc_short, 'o', label='Training acc')\nplt.plot(epochs_short, val_acc_short, 'b', label='Validation acc')\nplt.title('Accuracy')\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Deciding how many epochs to train the model with based on the validation accuracy\n# To smooth out any random variation we will find which triplet of epochs gives the lowest average accuracy\n#   and choose the point in the middle\n\nif len(epochs) >= 4:\n    # Defining a dictionary that will hold the averages of triplets of consecutive epochs\n    triple_averages = {}\n    for i in range(1, len(epochs)-1):\n        triple_averages[i] = (val_acc[i-1] + val_acc[i] + val_acc[i+1])/3\n    # Finding the triplet giving the highest average, and selecting the point in the middle\n    for i in range(1, len(triple_averages)+1):\n        min_avg = max(list(triple_averages.values()))\n        if triple_averages[i] == min_avg:\n            epochs_num = i\nelse:\n    for i in range(len(epochs)):\n        if val_acc[i] == max(val_acc):\n            epochs_num = i+1\n            \nepochs_num *= 10/9","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Building the final model and making predictions"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Building a fresh model with no validation data\nmodel = build_model()\nhistory = model.fit(train_X, train_y, batch_size=32, epochs=int(epochs_num), verbose=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Outputting the predictions\npredictions = model.predict(test_X)\npredictions_new = np.argmax(predictions, axis=1)\noutput = pd.DataFrame({'id': test_data.id, 'label': predictions_new})\noutput.to_csv('submission.csv', index=False)\nprint('Complete')","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":1}