{"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":"# Reconhecimento de digitos usando Deep Learning\n\n![image](https://ichi.pro/assets/images/max/400/1*Mw20mFOOjS0fE1j2Tiz02A.jpeg)\n\n","metadata":{}},{"cell_type":"markdown","source":"# **Tabela de conteúdos**\n\n<a id = 'max 10'></a>\n\n1. [Introdução](#1)\n  * Resumo\n\n\n2. [Importando bibliotecas e explorando dados](#2)\n  * Importação das bibliotecas\n  * Resumo das funções das bibliotecas\n  * Leitura dos dados \n  * Analise do dataset\n  * Saida de imagem\n  * Resultado de treino e validação\n\n\n3. [Criação e treinamento do modelo](#3)\n   * Criação do modelo Sequencial\n   * Compilando o modelo\n   * Treinando parte dos dados e salvando melhor modelo\n   * Resultado do treinamento\n   * Teste de acuracia e perda\n   * Teste com uma entrada qualquer\n   \n   \n4. [Avaliação do modelo](#4)\n   * Plotagem gráfico da matriz confusão\n   \n   \n5. [Gerando saida dos testes](#5)\n   * Classificação dos testes de saida\n   * Salvamento dos dados de saida\n   \n   \n6. [Teste extra de imagem com ruído](#6)\n   * Introdução de ruido na imagem e saida\n  \n","metadata":{}},{"cell_type":"markdown","source":"# **1. Introdução** <a class=\"anchor\" id=\"1\"></a>","metadata":{}},{"cell_type":"markdown","source":"O intuito dessa atividade é aplicar os conhecimentos teoricos vistos em aula e de forma pratica usando um exemplo selecionado pelo grupo em um dataset de reconhecimento de escrita manual com digitos.\nEstamos aplicando conceitos de Deep Learning, CNN usando a biblioteca como Keras/Tensor Flow para redes neurais e Sklearn para avaliação dos dados.","metadata":{}},{"cell_type":"markdown","source":"**Resumo:**\n\nO exemplo aqui desenvolvido tem como objetivo apresentar conceitos iniciais de implementação de redes neurais com Python e Tensor Flow/Keras. Esse exemplo apresenta um modelo de Rede Neural Convolucional (CNN) básico que pode ser expandido mudando o número de neurônios e camadas. Em adaptações mais avançadas, pode-se estudar possibilidade de otimização de hyperparâmetros e outras técnincas como aumento de dados.\n\nNão é nosso objetivo desenvolver e otimizar o modelo de classificação. O exemplo tem objetivo meramente acadêmico.","metadata":{}},{"cell_type":"markdown","source":"# **2. Importando bibliotecas e explorando dados** <a class=\"anchor\" id=\"2\"></a>","metadata":{}},{"cell_type":"code","source":"# Bibliotecas necessárias\n# Manipulação de dados\nimport pandas as pd\n# Redes Neurais\nfrom tensorflow import keras\nfrom tensorflow.keras.datasets import mnist\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Dropout, Conv2D, MaxPooling2D, Flatten\nfrom tensorflow.keras.optimizers import RMSprop\n# Plotagem\nimport matplotlib.pyplot as plt\n%matplotlib inline\n# Avaliação de dados\nfrom sklearn.metrics import classification_report, confusion_matrix\n","metadata":{"ExecuteTime":{"end_time":"2019-01-16T20:39:41.500258Z","start_time":"2019-01-16T20:39:39.261856Z"},"execution":{"iopub.status.busy":"2021-05-26T16:52:59.387668Z","iopub.execute_input":"2021-05-26T16:52:59.388077Z","iopub.status.idle":"2021-05-26T16:52:59.398949Z","shell.execute_reply.started":"2021-05-26T16:52:59.388042Z","shell.execute_reply":"2021-05-26T16:52:59.398089Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Resumo das funções das bibliotecas\n* Sequential: Modelo Keras vai adicionando camadas\n* Conv2D: Camada com filtros que percorrem a imagem extraindo caracterísitcas (mapas de caracteísticas)\n* MaxPooling2D: Camada que reduz a dimensionalidade dos mapas de características 2D\n* Flatten: Camada que transforma um mapa de características 2D num vetor para classficador final\n* Dense: Camada onde todas as entradas estão conectadas em cada neurônio\n* Dropout: Camada usada durante o treino e descarta aleatoriamente um percentual de conexões (reduz overfitting)","metadata":{}},{"cell_type":"code","source":"# Lendo o dataset\ntrain = pd.read_csv(\"../input/digit-recognizer/train.csv\")\n\n#Uma alternativa seria ler os dados do próprio Keras\n#(x_train, y_train), (x_test, y_test) = mnist.load_data()\n","metadata":{"execution":{"iopub.status.busy":"2021-05-26T16:52:59.400640Z","iopub.execute_input":"2021-05-26T16:52:59.401341Z","iopub.status.idle":"2021-05-26T16:53:02.567655Z","shell.execute_reply.started":"2021-05-26T16:52:59.401229Z","shell.execute_reply":"2021-05-26T16:53:02.566794Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Analisando o dataset\nprint(\"Quantidade de elementos de treino: {}\". format(len(train)))\nprint(train.head())","metadata":{"execution":{"iopub.status.busy":"2021-05-26T16:53:02.569533Z","iopub.execute_input":"2021-05-26T16:53:02.570200Z","iopub.status.idle":"2021-05-26T16:53:02.584051Z","shell.execute_reply.started":"2021-05-26T16:53:02.570151Z","shell.execute_reply":"2021-05-26T16:53:02.582764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Separando x_train e y_train\nY = train[\"label\"]\nX = train.drop(labels = [\"label\"],axis = 1)\nprint(X.head())\n# Em formato array de imagens 28 x 28\n#x = X.values.reshape(-1,28,28,1)\n#print(x[0])","metadata":{"execution":{"iopub.status.busy":"2021-05-26T16:53:02.585980Z","iopub.execute_input":"2021-05-26T16:53:02.586325Z","iopub.status.idle":"2021-05-26T16:53:02.979312Z","shell.execute_reply.started":"2021-05-26T16:53:02.586294Z","shell.execute_reply":"2021-05-26T16:53:02.978208Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(X.shape)","metadata":{"execution":{"iopub.status.busy":"2021-05-26T16:53:02.980667Z","iopub.execute_input":"2021-05-26T16:53:02.981021Z","iopub.status.idle":"2021-05-26T16:53:02.986644Z","shell.execute_reply.started":"2021-05-26T16:53:02.980990Z","shell.execute_reply":"2021-05-26T16:53:02.985173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plotando a saida\nplt.imshow(X.values[3].reshape(28,28), cmap=plt.cm.binary)\nplt.show()\nprint('Label: {}'.format(Y[3]))","metadata":{"ExecuteTime":{"end_time":"2019-01-08T20:49:47.144492Z","start_time":"2019-01-08T20:49:47.016025Z"},"execution":{"iopub.status.busy":"2021-05-26T16:53:02.988844Z","iopub.execute_input":"2021-05-26T16:53:02.989237Z","iopub.status.idle":"2021-05-26T16:53:03.143068Z","shell.execute_reply.started":"2021-05-26T16:53:02.989200Z","shell.execute_reply":"2021-05-26T16:53:03.141877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Transformando a imagem 2d em um array (imagem 28*28)\nx = X.values.reshape(42000, 28, 28, 1)\n\n#Normalizando para valores entre 0 e 1\nx = x.astype('float32')\nx /= 255\n\n#print(x[0])","metadata":{"ExecuteTime":{"end_time":"2019-01-08T20:49:57.425537Z","start_time":"2019-01-08T20:49:57.272377Z"},"execution":{"iopub.status.busy":"2021-05-26T16:53:03.146195Z","iopub.execute_input":"2021-05-26T16:53:03.146592Z","iopub.status.idle":"2021-05-26T16:53:03.521180Z","shell.execute_reply.started":"2021-05-26T16:53:03.146554Z","shell.execute_reply":"2021-05-26T16:53:03.520141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Ajustando o formato da saida\nnum_classes = 10\n\n# Convertendo para um vetor de saida com 10 dimensoes\n# ex. 8 => [0,0,0,0,0,0,0,0,1,0]\ny = keras.utils.to_categorical(Y, num_classes)\nprint(y[0])","metadata":{"ExecuteTime":{"end_time":"2019-01-08T20:50:48.007428Z","start_time":"2019-01-08T20:50:47.986527Z"},"execution":{"iopub.status.busy":"2021-05-26T16:53:03.525215Z","iopub.execute_input":"2021-05-26T16:53:03.525691Z","iopub.status.idle":"2021-05-26T16:53:03.534370Z","shell.execute_reply.started":"2021-05-26T16:53:03.525652Z","shell.execute_reply":"2021-05-26T16:53:03.532833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Separando uma parte para treino (90%) e outra para validação (10%)\nfrom sklearn.model_selection import train_test_split\nx_train, x_val, y_train, y_val = train_test_split(x, y, test_size = 0.1, random_state=5)\nprint('Quantidade de treino: {}'.format(len(x_train)))\nprint('Quantidade de validação: {}'.format(len(x_val)))","metadata":{"execution":{"iopub.status.busy":"2021-05-26T16:53:03.536974Z","iopub.execute_input":"2021-05-26T16:53:03.537333Z","iopub.status.idle":"2021-05-26T16:53:04.176528Z","shell.execute_reply.started":"2021-05-26T16:53:03.537301Z","shell.execute_reply":"2021-05-26T16:53:04.175099Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **3. Criação e treinamento do modelo** <a class=\"anchor\" id=\"3\"></a>","metadata":{}},{"cell_type":"code","source":"# Criando o modelo sequencial\nmodel = Sequential()\nmodel.add(Conv2D(20, kernel_size=(3, 3),\n                 activation='relu',\n                 input_shape=(28,28,1)))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Conv2D(40, kernel_size=(3,3), activation='relu'))\nmodel.add(Flatten())\nmodel.add(Dense(50, activation='relu'))\nmodel.add(Dropout(0.2))\nmodel.add(Dense(num_classes, activation='softmax'))\nmodel.summary()","metadata":{"ExecuteTime":{"end_time":"2019-01-08T21:38:00.233865Z","start_time":"2019-01-08T21:38:00.15079Z"},"scrolled":true,"execution":{"iopub.status.busy":"2021-05-26T16:53:04.178247Z","iopub.execute_input":"2021-05-26T16:53:04.178717Z","iopub.status.idle":"2021-05-26T16:53:04.252818Z","shell.execute_reply.started":"2021-05-26T16:53:04.178671Z","shell.execute_reply":"2021-05-26T16:53:04.251582Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Compilando o modelo\nmodel.compile(loss='categorical_crossentropy',\n              optimizer=RMSprop(),\n              metrics=['accuracy'])","metadata":{"ExecuteTime":{"end_time":"2019-01-08T21:33:17.184644Z","start_time":"2019-01-08T21:33:17.129141Z"},"execution":{"iopub.status.busy":"2021-05-26T16:53:04.254231Z","iopub.execute_input":"2021-05-26T16:53:04.254671Z","iopub.status.idle":"2021-05-26T16:53:04.269546Z","shell.execute_reply.started":"2021-05-26T16:53:04.254633Z","shell.execute_reply":"2021-05-26T16:53:04.268080Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Treinando com parte dos dados\nbatch_size = 32\nepochs = 20\n\n#Salvando o melhor modelo\ncallbacks_list = [\n    keras.callbacks.ModelCheckpoint(\n        filepath='model.h5',\n        monitor='val_loss', save_best_only=True, verbose=1),\n    keras.callbacks.EarlyStopping(monitor='val_loss', patience=10,verbose=1)\n]\n\nhistory = model.fit(x_train, y_train,\n                    batch_size=batch_size,\n                    epochs=epochs,\n                    callbacks = callbacks_list,\n                    verbose=1,\n                    validation_data=(x_val, y_val))","metadata":{"ExecuteTime":{"end_time":"2019-01-08T21:36:15.501168Z","start_time":"2019-01-08T21:33:19.322895Z"},"execution":{"iopub.status.busy":"2021-05-26T16:53:04.271279Z","iopub.execute_input":"2021-05-26T16:53:04.271625Z","iopub.status.idle":"2021-05-26T16:57:34.675042Z","shell.execute_reply.started":"2021-05-26T16:53:04.271593Z","shell.execute_reply":"2021-05-26T16:57:34.674007Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Resultado do teinamento\n\nfig, ax = plt.subplots(1,2, figsize=(16,8))\nax[0].plot(history.history['loss'], color='b', label=\"Training loss\")\nax[0].plot(history.history['val_loss'], color='r', label=\"validation loss\",axes =ax[0])\nlegend = ax[0].legend(loc='best', shadow=True)\n\nax[1].plot(history.history['accuracy'], color='b', label=\"Training accuracy\")\nax[1].plot(history.history['val_accuracy'], color='r',label=\"Validation accuracy\")\nlegend = ax[1].legend(loc='best', shadow=True)","metadata":{"ExecuteTime":{"end_time":"2019-01-08T21:36:20.243921Z","start_time":"2019-01-08T21:36:20.064201Z"},"execution":{"iopub.status.busy":"2021-05-26T16:57:34.676582Z","iopub.execute_input":"2021-05-26T16:57:34.676874Z","iopub.status.idle":"2021-05-26T16:57:35.360599Z","shell.execute_reply.started":"2021-05-26T16:57:34.676846Z","shell.execute_reply":"2021-05-26T16:57:35.359396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.models import load_model\n# Load the best saved model\nmodel = load_model('model.h5')","metadata":{"execution":{"iopub.status.busy":"2021-05-26T16:57:35.363835Z","iopub.execute_input":"2021-05-26T16:57:35.364139Z","iopub.status.idle":"2021-05-26T16:57:35.457532Z","shell.execute_reply.started":"2021-05-26T16:57:35.364109Z","shell.execute_reply":"2021-05-26T16:57:35.456152Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Testando a acuracia e perda\nscore = model.evaluate(x_val, y_val, verbose=0)\nprint('Test loss:', score[0])\nprint('Test accuracy:', score[1])","metadata":{"ExecuteTime":{"end_time":"2019-01-08T21:36:39.779842Z","start_time":"2019-01-08T21:36:38.946173Z"},"execution":{"iopub.status.busy":"2021-05-26T16:57:35.459118Z","iopub.execute_input":"2021-05-26T16:57:35.459464Z","iopub.status.idle":"2021-05-26T16:57:36.355383Z","shell.execute_reply.started":"2021-05-26T16:57:35.459431Z","shell.execute_reply":"2021-05-26T16:57:36.354162Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Testando uma entrada qualquer\nprint(y_train[10])\nprint(model.predict(x_train[10].reshape((1,28,28,1))))\nprint(model.predict_classes(x_train[10].reshape((1,28,28,1))))","metadata":{"ExecuteTime":{"end_time":"2019-01-08T21:06:04.363715Z","start_time":"2019-01-08T21:06:04.27849Z"},"execution":{"iopub.status.busy":"2021-05-26T16:58:12.627786Z","iopub.execute_input":"2021-05-26T16:58:12.628222Z","iopub.status.idle":"2021-05-26T16:58:12.717384Z","shell.execute_reply.started":"2021-05-26T16:58:12.628187Z","shell.execute_reply":"2021-05-26T16:58:12.715904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **4. Avaliação do modelo** <a class=\"anchor\" id=\"4\"></a>","metadata":{}},{"cell_type":"code","source":"import itertools\n\n#Plot the confusion matrix. Set Normalize = True/False\ndef plot_confusion_matrix(cm, classes, normalize=True, title='Confusion matrix', cmap=plt.cm.Blues):\n    \"\"\"\n    This function prints and plots the confusion matrix.\n    Normalization can be applied by setting `normalize=True`.\n    \"\"\"\n    plt.figure(figsize=(10,10))\n    plt.imshow(cm, interpolation='nearest', cmap=cmap)\n    plt.title(title)\n    plt.colorbar()\n    tick_marks = np.arange(len(classes))\n    plt.xticks(tick_marks, classes, rotation=45)\n    plt.yticks(tick_marks, classes)\n    if normalize:\n        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n        cm = np.around(cm, decimals=2)\n        cm[np.isnan(cm)] = 0.0\n    thresh = cm.max() / 2.\n    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n        plt.text(j, i, cm[i, j],\n                 horizontalalignment=\"center\",\n                 color=\"white\" if cm[i, j] > thresh else \"black\")\n    plt.tight_layout()\n    plt.ylabel('True label')\n    plt.xlabel('Predicted label')","metadata":{"execution":{"iopub.status.busy":"2021-05-26T17:15:23.948012Z","iopub.execute_input":"2021-05-26T17:15:23.948409Z","iopub.status.idle":"2021-05-26T17:15:23.959039Z","shell.execute_reply.started":"2021-05-26T17:15:23.948376Z","shell.execute_reply":"2021-05-26T17:15:23.957889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Vendo alguns reports\n# Usando sklearn\nimport numpy as np\n\n# Classificando toda base de teste\ny_pred = model.predict_classes(x_val)\n# voltando pro formato de classes\ny_test_c = np.argmax(y_val, axis=1)\ntarget_names = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']\n\n#Confution Matrix\ncm = confusion_matrix(y_test_c, y_pred)\nplot_confusion_matrix(cm, target_names, normalize=False, title='Confusion Matrix')\n\nprint('Classification Report')\nprint(classification_report(y_test_c, y_pred, target_names=target_names))","metadata":{"ExecuteTime":{"end_time":"2019-01-08T21:24:57.7654Z","start_time":"2019-01-08T21:24:57.220867Z"},"execution":{"iopub.status.busy":"2021-05-26T16:57:36.511732Z","iopub.execute_input":"2021-05-26T16:57:36.512352Z","iopub.status.idle":"2021-05-26T16:57:37.797561Z","shell.execute_reply.started":"2021-05-26T16:57:36.512296Z","shell.execute_reply":"2021-05-26T16:57:37.796465Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **5. Gerando saida dos testes** <a class=\"anchor\" id=\"5\"></a>","metadata":{}},{"cell_type":"code","source":"# Gerando saída para dataset de teste\n\n#Carrega dataset de teste\ntest = pd.read_csv(\"../input/digit-recognizer/test.csv\")\nprint(\"Quantidade de testes: {}\".format(len(test)))\n# Bota no formato numpy e normaliza\nx_test = test.values.reshape(len(test),28,28,1)\nx_test = x_test.astype('float32')\nx_test /= 255\n\n# Fazendo a classificação para dataset de teste\ny_pred = model.predict_classes(x_test)\n\n# Testando um exemplo\ni = 0\nplt.imshow(test.values[i].reshape(28,28), cmap=plt.cm.binary)\nplt.show()\nprint('Valor previsto: {}'.format(y_pred[i]))\nprint(\" \")\n\n# Botando no formato de saída\nresults = pd.Series(y_pred,name=\"Label\")\nsubmission = pd.concat([pd.Series(range(1,len(y_pred)+1),name = \"ImageId\"),results],axis = 1)\nprint(submission.head(10))\n#Salvando arquivo de saida dos testes\nsubmission.to_csv(\"output_test.csv\",index=False)","metadata":{"execution":{"iopub.status.busy":"2021-05-26T17:08:44.741942Z","iopub.execute_input":"2021-05-26T17:08:44.742470Z","iopub.status.idle":"2021-05-26T17:08:50.768980Z","shell.execute_reply.started":"2021-05-26T17:08:44.742435Z","shell.execute_reply":"2021-05-26T17:08:50.767750Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **6. Teste extra de imagem com ruído** <a class=\"anchor\" id=\"6\"></a>","metadata":{}},{"cell_type":"code","source":"#Introduzindo ruido na imagem\nimport numpy as np\nmean = 0.\nstddev = 0.2\ni=0\nnoise = np.random.normal(mean, stddev, (4200, 28, 28,1))\nx_te = x_val + noise\nx_te = np.clip(x_te, 0., 1.)\n\ny_pred = model.predict_classes(x_te)\nplt.imshow(x_te.reshape(4200, 28,28)[1], cmap=plt.cm.binary)\nplt.show()\nprint('Valor previsto: {}'.format(y_pred[1]))\n\n# Saida do teste\nscore = model.evaluate(x_te, y_val, verbose=0)\nprint('Test loss:', score[0])\nprint('Test accuracy:', score[1])","metadata":{"execution":{"iopub.status.busy":"2021-05-26T17:07:37.159689Z","iopub.execute_input":"2021-05-26T17:07:37.160078Z","iopub.status.idle":"2021-05-26T17:07:38.563115Z","shell.execute_reply.started":"2021-05-26T17:07:37.160043Z","shell.execute_reply":"2021-05-26T17:07:38.562064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Aplicando o ruído se é possivel perceber que a acuracia dos exemplos de validação decai se comparada aos resultados de imagens sem o ruído, porém obtem resultados melhores se comparados a outras abordagens como do modelo de MLP clássico, o que válida a robustez da aplicação do modelo CNN que faz uma melhor captura de padrões e regiões de pixels.","metadata":{}}]}