{"cells":[{"metadata":{"_cell_guid":"640d0e68-aecf-4334-853c-0a359da2082d","_uuid":"28ca08cb2187dac51dbec9d7865a01ea77fa13c5"},"cell_type":"markdown","source":"# Keras model for recognizing handwritten digits"},{"metadata":{"_cell_guid":"32009b0e-bb5b-444d-9378-6d25483c35b8","_uuid":"55d7534c40ca0c94256a878bd5587e33d02d7b2f"},"cell_type":"markdown","source":"## Setup"},{"metadata":{"_cell_guid":"6d2213a8-32a1-4a1e-b8c3-dd76d4cd8300","_uuid":"7e2a608732c889af6595a6b0db4c84e7713a64af","trusted":true,"collapsed":true},"cell_type":"code","source":"# Imports\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D, MaxPooling2D\nfrom keras.layers import Dense, Flatten, Dropout\nfrom keras.optimizers import Adam\nfrom keras.losses import categorical_crossentropy\nfrom keras.utils import to_categorical\nfrom keras.datasets import mnist\n\nimport pandas as pd\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.utils import shuffle\n\n%matplotlib inline\nfrom matplotlib import pyplot as plt\n\nimport numpy as np\n# Set the seed for consistent results\nnp.random.seed(1337)","execution_count":9,"outputs":[]},{"metadata":{"_cell_guid":"6ec09bf3-5c8c-43c9-b1a6-8f55e8090852","_uuid":"0e9ca882af290cf404aef55f2a72f2f74cb105ec"},"cell_type":"markdown","source":"## Data"},{"metadata":{"_cell_guid":"be87f156-a260-434f-bf73-9db220de0532","_uuid":"0018d90db2209532d0906ed163f835f3a19d5114","trusted":true},"cell_type":"code","source":"# Collect data\ntrain = pd.read_csv(\"../input/train.csv\")\nx_test = pd.read_csv(\"../input/test.csv\")\n\ny_train_entire = train[\"label\"]\nx_train_entire = train.drop(labels = [\"label\"],axis = 1)\n\n# ...for good measure\nshuffle(x_train_entire, y_train_entire)\n\n# Split in train/validation\nx_train, x_validate, y_train, y_validate = train_test_split(x_train_entire, y_train_entire,\n                                                            test_size = 0.1)\n\nprint('Train    = ', len(x_train))\nprint('Validate = ', len(x_validate))\nprint('Test     = ', len(x_test))\n\n# Reshape to a valid tensor\nx_train_conv = x_train.values.reshape(x_train.shape[0], 28, 28, 1)\nx_validate_conv = x_validate.values.reshape(x_validate.shape[0], 28, 28, 1)\nx_test_conv = x_test.values.reshape(x_test.shape[0], 28, 28, 1)\n\n# Casts the arrays to valid number type\nx_train_conv = x_train_conv.astype('float32')\nx_validate_conv = x_validate_conv.astype('float32')\nx_test_conv = x_test_conv.astype('float32')\n\n#One-hot encode the labels\ny_train_one_hot = to_categorical(y_train, 10)\ny_validate_one_hot = to_categorical(y_validate, 10)","execution_count":10,"outputs":[]},{"metadata":{"_cell_guid":"49d65e6b-6da3-433c-b00e-8c9288ed6307","_uuid":"ba7c2ccdb6aca6696f83f533ee1cfcbb9f0391b7","collapsed":true,"trusted":true},"cell_type":"code","source":"# Adapt the data\n\n# Normalize the features from [0-255] to [0-1] \nx_train_conv /= 255\nx_validate_conv /= 255\nx_test_conv /= 255","execution_count":11,"outputs":[]},{"metadata":{"_cell_guid":"084171d4-abcd-4a34-9247-cfa51c28e7bf","_uuid":"933ec382dcea4007bd96cb6c06a4c4348f1230bd"},"cell_type":"markdown","source":"## Model"},{"metadata":{"_cell_guid":"a93c5b54-ebf2-46c0-8105-5952b36f0061","_uuid":"b25809971435393bae3c0911416cf008bfb39bc2","collapsed":true,"trusted":true},"cell_type":"code","source":"# Build model\nmodel_name = '3conv_128-256_2max'\nmodel = Sequential()\n\nmodel.add(Conv2D(filters=128, kernel_size=(3, 3), input_shape=(28, 28, 1), activation='relu'))\nmodel.add(Conv2D(filters=256, kernel_size=(3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Conv2D(filters=512, kernel_size=(3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Flatten())\nmodel.add(Dense(256, activation='relu'))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(10, activation='softmax'))","execution_count":12,"outputs":[]},{"metadata":{"_cell_guid":"4e632ece-2e98-4aac-ac13-f83abc068c25","_uuid":"df8573f809bda795aa9c6caac723399f0e38899d","trusted":true},"cell_type":"code","source":"# Compile model\nmodel.compile(loss=categorical_crossentropy,\n              optimizer=Adam(),\n              metrics=['accuracy'])\n\nmodel.summary()","execution_count":13,"outputs":[]},{"metadata":{"_cell_guid":"5e909b89-aad2-416a-84f9-2198343499e1","_uuid":"0e6468ff8486e94d7f9d654a888229747b803a71"},"cell_type":"markdown","source":"## Training"},{"metadata":{"_cell_guid":"ed0f5c8c-d8a6-4a00-8762-cf28f20f0d72","_uuid":"2cf9dcb4cabe3f65fab08bab8077a0156100e7f3","collapsed":true,"trusted":true},"cell_type":"code","source":"# Train model\nbatch_size = 128\n\nhistory = model.fit(x_train_conv, y_train_one_hot,\n                    batch_size=batch_size,\n                    epochs=10,\n                    verbose=2,\n                    validation_data=(x_validate_conv, y_validate_one_hot))\n\n#model.save_weights('persistence/' + model_name + '_weights.h5')\n#model.save('persistence/' + model_name + '_keras.h5')","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"051a9cfd-d3f0-4f41-9a6e-ad971973f717","_uuid":"626457837565b70998eb55ec357433973861668e","trusted":true},"cell_type":"code","source":"# Visualize training\n\ndef plot_training_history(history):\n    \"\"\" Plot helper function \"\"\"\n    print('Availible variables to plot: {}'.format(history.history.keys()))\n    line_style = '.-'\n    \n    # Accuracy\n    plt.subplot(1,2,1)\n    plt.plot(history.history['acc'], line_style)\n    plt.plot(history.history['val_acc'], line_style)\n    plt.ylabel('Accuracy')\n    plt.xlabel('Epoch')\n    plt.title('Model Accuracy over Epochs')\n    plt.legend(['Train', 'Validation'], loc='lower right')\n    plt.grid()\n\n    # Loss\n    plt.subplot(1,2,2)\n    plt.plot(history.history['loss'], line_style)\n    plt.plot(history.history['val_loss'], line_style)\n    plt.ylabel('Loss')\n    plt.xlabel('Epoch')\n    plt.title('Model Loss over Epochs')\n    plt.legend(['Train', 'Validation'], loc='upper right')\n    plt.grid()\n    \n    plt.tight_layout(pad=0.5, w_pad=0.5, h_pad=1.0)\n    plt.show()\n\n\nplot_training_history(history)","execution_count":14,"outputs":[]},{"metadata":{"_cell_guid":"05333acf-890f-4ce9-93c6-a464f7314603","_uuid":"4ed8d343064914c21402fc4c4caa5dee40947816"},"cell_type":"markdown","source":"## Testing"},{"metadata":{"_cell_guid":"5989556d-0f72-4fa9-a1b4-310a21c45790","_uuid":"f11df8d56a41becde29f4440bb24c3075669b383","collapsed":true,"trusted":true},"cell_type":"code","source":"# Predict test set\npredictions = model.predict(x_test_conv, verbose=0)\n\n# Select index with max probability '[0.1, 0.01, 0, 0, 1, 0, 0.1]' -> '4'\npredicted_nums = np.argmax(predictions, axis = 1)","execution_count":null,"outputs":[]},{"metadata":{"collapsed":true,"trusted":true,"_uuid":"32dec84a7bffc2b0921f3faa9a96d566d77915e6"},"cell_type":"code","source":"# Make result submission csv for Kaggle (https://www.kaggle.com/c/digit-recognizer)\nresults = pd.Series(predicted_nums, name='Label')\n\nsubmission = pd.concat((pd.Series(range(1,28001), name='ImageId'), results), axis = 1)\nsubmission.to_csv(model_name + '_submission.csv', index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}