{"cells":[{"metadata":{"_uuid":"d01ebee346c60a96f247e5e95be95f09a08c554d"},"cell_type":"markdown","source":"# Laboratório 2 - Classificação de imagens\n\nNesse laboratório vamos utilizar um conjunto de dados público de imagens de dígitos (de 0 a 9), o <a href=\"https://en.wikipedia.org/wiki/MNIST_database\">MNIST</a>.  Nós exploraremos algumas arquiteturas de redes neurais para identificar corretamente um dígito."},{"metadata":{"trusted":true,"_uuid":"9f9997f8a99cd5abac2e7ce5e2bb86ddcdb0292a"},"cell_type":"code","source":"import numpy as np\nnp.random.seed(5)\n\n#from keras.datasets import mnist\nfrom keras.models import Sequential\nfrom keras import layers\nfrom keras.utils import np_utils","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"90ea1666d2bcf1d341f0f17f7e981aaed4e665d1"},"cell_type":"markdown","source":"## Parte 1 - Carregando os dados\n\nCarregando os datasets MNIST disponíveis "},{"metadata":{"trusted":true,"_uuid":"00b5660f7f18b24cbb07e2981631f5c9844c5865"},"cell_type":"code","source":"def load_data(path):\n    with np.load(path) as f:\n        x_train, y_train = f['x_train'], f['y_train']\n        x_test, y_test = f['x_test'], f['y_test']\n        return (x_train, y_train), (x_test, y_test)\n\n(X_train, y_train), (X_test, y_test) = load_data('../input/mnist-numpy/mnist.npz')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d171e704208ee74c68ed260bee01e87e4efc6c50"},"cell_type":"markdown","source":"Agora vamos explorar os dados"},{"metadata":{"trusted":true,"_uuid":"d9f50007084d9ea726d2f11701a6103590128a57"},"cell_type":"code","source":"print(X_train.shape)\nprint(y_train.shape)\nprint(X_test.shape)\nprint(y_test.shape)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e1641a47841b0a59f615e6ddf3cff4fff02d6f59"},"cell_type":"markdown","source":"Note que temos imagens de 28x28 pixels. São 60000 imagens de treinamento e 10000 para teste. Agora vamos visualizar uma imagem e seu rótulo."},{"metadata":{"trusted":true,"_uuid":"5f3692947808f2fb16d45af4852ea75be89b6473"},"cell_type":"code","source":"%matplotlib inline\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport matplotlib.cm as cm\n\nfig, ax = plt.subplots(ncols=10, nrows=1, figsize=(10, 5))\namostra = np.random.choice(60000, 10) #escolhe 10 imagens dentre as 60000\n\nfor i in range(len(amostra)):\n    imagem = np.array(X_train[amostra[i]])\n    ax[i].imshow(imagem, cmap = cm.Greys_r)\n    ax[i].get_xaxis().set_ticks([])\n    ax[i].get_yaxis().set_ticks([])\n    ax[i].set_title(y_train[amostra[i]]) # Coloca o label como título da figura.\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9d506b690019e520a91ec47373764a2745c63d05"},"cell_type":"markdown","source":"Os dados estão em valores entre 0 e 255. Vamos reescaloná-los para valores entre 0 e 1."},{"metadata":{"trusted":true,"_uuid":"5c8f266bf7a4684fb9d3ef9deb0b0007815f01e6"},"cell_type":"code","source":"X_train = X_train.astype('float32') / 255.\nX_test = X_test.astype('float32') / 255.","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"792ac222648a37bf70e2cb639315f7d52934e75d"},"cell_type":"markdown","source":"E convertemos o vetor com o número representado em cada imagem num formato apropriado para o Keras"},{"metadata":{"trusted":true,"_uuid":"00ac69ca9868d3e0aeca94033b99d4010145e3ce"},"cell_type":"code","source":"n_classes = 10 #são 10 classes: números de 0 a 9\nY_train = np_utils.to_categorical(y_train, n_classes)\nY_test = np_utils.to_categorical(y_test, n_classes)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a50644b2e72774f9258ee2926b4a1237651d9ac1"},"cell_type":"markdown","source":"## Parte 2 - Usando uma rede neural tradicional\n\nNa nossa primeira tentativa, vamos usar uma rede neural tradicional com apenas uma camada de neurônios escondida."},{"metadata":{"_uuid":"f67174962ae0083e3eb62cecb882db2221903427"},"cell_type":"markdown","source":"Primeiro formatamos os dados para em vez de ser uma matriz 28x28, ser um vetor de 784 valores."},{"metadata":{"trusted":true,"_uuid":"fe200ad468ae0ddd42cbde8b6d6d5466785b0fa1"},"cell_type":"code","source":"X_train_flat = X_train.reshape(60000, 784)\nX_test_flat = X_test.reshape(10000, 784)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a14008672046669291f6b2ae05f8d3cadda7be4c"},"cell_type":"code","source":"#Parâmetros\nnb_epoch = 15\nbatch_size = 128","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ac4832ef244f5833252239197666817e5fb69343"},"cell_type":"markdown","source":"Agora montamos nossa rede neural"},{"metadata":{"trusted":true,"_uuid":"418c710dd796f56f23d07f753bc01eb8f517d9bf","scrolled":false},"cell_type":"code","source":"model = Sequential()\nmodel.add(layers.Dense(512, input_shape=(784,)))\nmodel.add(layers.Activation('relu'))\nmodel.add(layers.Dense(10))\nmodel.add(layers.Activation('softmax'))\n\nmodel.summary()\n\nmodel.compile(loss='categorical_crossentropy',\n              optimizer='adam', metrics=['accuracy'])\n\nhistory = model.fit(X_train_flat, Y_train,\n                    batch_size=batch_size, epochs=nb_epoch,\n                    verbose=1, validation_data=(X_test_flat, Y_test))\n\nscore = model.evaluate(X_test_flat, Y_test, verbose=0)\nprint('Test score:', score[0])\nprint('Test accuracy:', score[1])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0628c85cfe0dfcbc1d558d5da10c55956ab648da"},"cell_type":"markdown","source":"Com nosso primeiro modelo, conseguimos um resultado já muito bom, de 98,18% de acurácia e um Categorical log-loss de 0.073. Vamos acrescentar mais uma camada na nossa rede neural e ver como fica."},{"metadata":{"trusted":true,"_uuid":"0c7f0845d9ba295ac805672c95e118433bb1436d"},"cell_type":"code","source":"model2 = Sequential()\nmodel2.add(layers.Dense(512, input_shape=(784,)))\nmodel2.add(layers.Activation('relu'))\n## Nova camada\nmodel2.add(layers.Dense(512))\nmodel2.add(layers.Activation('relu'))\n\nmodel2.add(layers.Dense(10))\nmodel2.add(layers.Activation('softmax'))\n\nmodel2.summary()\n\nmodel2.compile(loss='categorical_crossentropy',\n              optimizer='adam', metrics=['accuracy'])\n\nhistory = model2.fit(X_train_flat, Y_train,\n                    batch_size=batch_size, epochs=nb_epoch,\n                    verbose=1, validation_data=(X_test_flat, Y_test))\n\nscore = model2.evaluate(X_test_flat, Y_test, verbose=0)\nprint('Test score:', score[0])\nprint('Test accuracy:', score[1])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"46be4f873a811700a5518bd12157672b669eb901"},"cell_type":"markdown","source":"O nosso resultado piorou. Isso pode ocorrer por alguns motivos. O primeiro é que aumentando o número de parâmetros a serem aprendidos na nossa rede, precisaríamos de mais épocas para treiná-la. O segundo é que a nossa rede pode estar se adaptando demais aos dados de treino e sendo incapaz de generalizar nos dados de teste (*Overfiting*). Há outros motivos, relacionados aos parâmetros, mas vamos nos ater a esses por enquanto.\n\nPara o segundo problema, podemos usar a técnica de <a href=\"http://www.jmlr.org/papers/volume15/srivastava14a.old/source/srivastava14a.pdf\">Dropout</a>, que tem se mostrado muito efetiva na prevenção de *overfitting*. "},{"metadata":{"trusted":true,"_uuid":"271efe63f82a8fe1a9e55e2d78898d6485202865","scrolled":false},"cell_type":"code","source":"model3 = Sequential()\nmodel3.add(layers.Dense(512, input_shape=(784,)))\nmodel3.add(layers.Activation('relu'))\nmodel3.add(layers.Dropout(0.3)) # percentual de neurônios que serão zerados durante o aprendizado\nmodel3.add(layers.Dense(512))\nmodel3.add(layers.Activation('relu'))\nmodel3.add(layers.Dropout(0.3)) # percentual de neurônios que serão zerados durante o aprendizado\nmodel3.add(layers.Dense(10))\nmodel3.add(layers.Activation('softmax'))\n\nmodel3.summary()\n\nmodel3.compile(loss='categorical_crossentropy',\n              optimizer='adam', metrics=['accuracy'])\n\nhistory = model3.fit(X_train_flat, Y_train,\n                    batch_size=batch_size, epochs=nb_epoch,\n                    verbose=1, validation_data=(X_test_flat, Y_test))\n\nscore = model3.evaluate(X_test_flat, Y_test, verbose=0)\nprint('Test score:', score[0])\nprint('Test accuracy:', score[1])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"561ad2594833b84865e4484c65cee2e709836402"},"cell_type":"markdown","source":"Com nosso terceiro modelo, obtivemos um resultado um pouco melhor de Log-loss e um pouco pior de acurácia que o primeiro modelo.  Claro que é uma comparação simplista, pois poderíamos variar uma série de parâmetros para fazer essas comparações."},{"metadata":{"_uuid":"7397711fd944061a6d4b1c4b96f062120f806767"},"cell_type":"markdown","source":"## Parte 3 - Rede Neural Convolucional\n\nAgora vamos mudar de técnica, e tentar usar uma <a href=\"http://cs231n.github.io/convolutional-networks/\">rede neural convolucional</a>.\n\nPrimeiro temos de formatar os dados para um array com dimensões (n_exemplos, n_pixel_x, n_pixel_y, n_cores)"},{"metadata":{"trusted":true,"_uuid":"276788cb2a74f19f6e711eface608abd27a90e00"},"cell_type":"code","source":"img_rows = 28\nimg_cols = 28\n\nX_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1)\nX_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5a3121459eebc8c5baf505ad2f16c9a047e22589"},"cell_type":"markdown","source":"Agora montamos nossa rede convolucional"},{"metadata":{"trusted":true,"_uuid":"3a1c45d80f23ffeeb677bf64de3ee7de24804c55"},"cell_type":"code","source":"## Parâmetros\nbatch_size = 2048\nn_filters = 32 #número de filtros\nn_pool = 2 #Tamanho da camada de pooling\nn_conv = 3 #Tamanho da kernel do filtro ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"12d3eb41f7a36ecbe714ddbf33ead0f7c29e718a"},"cell_type":"code","source":"model4 = Sequential()\nmodel4.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))\nmodel4.add(layers.Dropout(0.5))\nmodel4.add(layers.MaxPooling2D((2, 2)))\nmodel4.add(layers.Conv2D(64, (3, 3), activation='relu'))\nmodel4.add(layers.Dropout(0.5))\nmodel4.add(layers.MaxPooling2D((2, 2)))\nmodel4.add(layers.Conv2D(64, (3, 3), activation='relu'))\nmodel4.add(layers.Dropout(0.5))\nmodel4.add(layers.Flatten())\nmodel4.add(layers.Dense(64, activation='relu'))\nmodel4.add(layers.Dense(10, activation='softmax'))\nmodel4.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['accuracy'])\n\nmodel4.summary()\n\nmodel4.fit(X_train, Y_train, batch_size=batch_size, epochs=30, \n          verbose=1, validation_data=(X_test, Y_test))\nscore = model4.evaluate(X_test, Y_test, verbose=0)\nprint('Test score:', score[0])\nprint('Test accuracy:', score[1])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"47e99c2a400ae20d7b0167ae12d97aea8d884fdd"},"cell_type":"markdown","source":"Com a mudança de arquitetura, podemos ver que de quase 50% no Categorical Log-loss (de 0,06 para 0,04) e a acurácia chegou a 99,2%"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}