{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"markdown","source":"Explore a API do Keras e aprenda como utilizar os recursos explicados aqui: funções de ativação, inicialização de pesos, normalização por lote e dropout. Aplique em alguns modelos MLP para os conjuntos MNIST e Fashion MNIST. Não fique preso ao que foi mencionado na aula: pesquise sobre e utilize outras funções de ativação, inicializações, etc. O objetivo é que você ganhe familiaridade com a biblioteca e autonomia para navegar na API e implementar os recursos em seus modelos."},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nfrom tensorflow import keras\nfrom sklearn.model_selection import train_test_split\nimport numpy as np\nfrom sklearn.metrics import accuracy_score\nfrom sklearn.metrics import confusion_matrix\nimport seaborn as sns\n\nfrom random import choices","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Digit Recognizer"},{"metadata":{},"cell_type":"markdown","source":"## Importando Dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"digits_PATH = '/kaggle/input/digit-recognizer/'\n\ndigits_train = pd.read_csv(digits_PATH+'train.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X, y = digits_train.iloc[:,1:].values/255, digits_train.iloc[:,0].values","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"N_images = 50\n\n# localização dos exemplos na matriz de dados \nrows = choices(range(0, 42000), k=N_images)\n\n# selecionando os dígitos, já no formato de matriz\ndigitos = [X[i].reshape(28,28) for i in rows]\nlabel_value = y[rows]\n\n# criando figura do matplotlib\nfig, ax = plt.subplots(5, int(len(rows)/5),figsize=(18,10))\n\n# plotando!\nfor i in range(len(rows)):\n    j = int(i/10)\n    k = i - j*10\n    ax[j, k].imshow(digitos[i], cmap = plt.cm.binary, interpolation=\"nearest\")\n    ax[j, k].set_title(label_value[i])\n    ax[j, k].axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Funcões Auxiliares"},{"metadata":{"trusted":true},"cell_type":"code","source":"def compare_confusion_matriz(modelo, X_treino, X_validacao, y_treino, y_validacao):\n    \n    y_validacao_pred = modelo.predict(X_validacao)\n    y_train_pred = modelo.predict(X_treino)\n    \n    if isinstance(m, keras.models.Sequential):\n        y_validacao_pred = np.argmax(y_validacao_pred, axis=1)\n        y_train_pred = np.argmax(y_train_pred, axis=1)\n    \n    confusao_val = confusion_matrix(y_validacao, y_validacao_pred)\n    confusao_tr = confusion_matrix(y_treino, y_train_pred)\n    \n    fig, ax = plt.subplots(1, 2,figsize=(20,10))\n    sns.heatmap(pd.DataFrame(confusao_val), ax=ax[0], cbar=False, annot=True)\n    ax[0].set_title('Matriz de confusão validação', size=20)\n    ax[0].set_yticklabels(ax[0].get_xticklabels(), rotation=0, size=15)\n    ax[0].set_xticklabels(ax[0].get_yticklabels(), rotation=0, size=15)\n    sns.heatmap(pd.DataFrame(confusao_tr), ax=ax[1], cbar=False, annot=True)\n    ax[1].set_title('Matriz de confusão treino', size=20)\n    ax[1].set_yticklabels(ax[1].get_xticklabels(), rotation=0, size=15)\n    ax[1].set_xticklabels(ax[1].get_yticklabels(), rotation=0, size=15)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def acuracia(modelo, X_treino, X_validacao, y_treino, y_validacao):\n\n    y_validacao_pred = modelo.predict(X_validacao)\n    y_train_pred = modelo.predict(X_treino)\n    \n    if isinstance(m, keras.models.Sequential):\n        y_validacao_pred = np.argmax(y_validacao_pred, axis=1)\n        y_train_pred = np.argmax(y_train_pred, axis=1)\n    \n    acc_tr = accuracy_score(y_treino, y_train_pred)\n    acc_val = accuracy_score(y_validacao, y_validacao_pred)\n\n    return {'Acurácia do treino': acc_tr, 'Acurácia da validação': acc_val}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_erros(model, X, target):\n\n    y_pred = model.predict(X)\n    y_pred = np.argmax(y_pred, axis=1)\n    \n    predicao = pd.DataFrame(data={'predicao':y_pred, 'target':target})\n    predicao_erros = predicao[predicao.predicao != predicao.target]\n    \n    N_images = 50\n\n    # localização dos exemplos na matriz de dados \n    rows = predicao_erros.index[:N_images]\n\n    # selecionando os dígitos, já no formato de matriz\n    digitos = [X[i].reshape(28,28) for i in rows]\n    label = predicao.loc[rows, 'target']\n    label_errors = predicao.loc[rows, 'predicao']\n\n    # criando figura do matplotlib\n    fig, ax = plt.subplots(5, int(len(rows)/5),figsize=(18,10))\n\n    # plotando!\n    for i in range(len(rows)):\n        j = int(i/10)\n        k = i - j*10\n        ax[j, k].imshow(digitos[i], cmap = plt.cm.binary, interpolation=\"nearest\")\n        ax[j, k].set_title(f'{label.iloc[i]} confused {label_errors.iloc[i]}')\n        ax[j, k].axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Keras"},{"metadata":{"trusted":true},"cell_type":"code","source":"X_treino, X_validacao, y_treino, y_validacao = train_test_split(X, y, test_size=0.2, random_state=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"m = keras.models.Sequential()\n\nm.add(keras.layers.Dense(200, input_shape = (784,), activation=\"relu\"))\nm.add(keras.layers.Dense(10, activation=\"softmax\"))\n\nm.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time \n\nH = m.fit(X_treino, y_treino, \n          batch_size = 200, epochs = 10, \n          validation_data = (X_validacao, y_validacao));","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"compare_confusion_matriz(m, X_treino, X_validacao, y_treino, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"acuracia(m, X_treino, X_validacao, y_treino, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"O modelo apresentou uma acurácia de 97% o que é um bom resultado. O programa confunde 9 com 4 (que é bastante lógico), 7 com 1 (também aceitável), 7 com 2, 7 com 9. Vamos avaliar os números que foram avaliados errado."},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_erros(m, X_validacao, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"É possível ver claramente o porque do programa confundir muitos desses números. O primeiro elemento eu chutaria que é um 8, segundo o gabarito é um 9 e o programa chutou 3, última linha há dois números que são praticamente iguais porem um é 9 e o outro 4. Porém alguns números são claros de identificar, logo o modelo pode ser melhorado."},{"metadata":{},"cell_type":"markdown","source":"## Otimização do modelo"},{"metadata":{},"cell_type":"markdown","source":"### Número de neurônios na camada oculta"},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time \n\nneurons_list = [10, 20, 40, 100, 150, 200, 300, 400, 600, 1000]\nacuracia_dict = dict()\n\nfor value in neurons_list:\n    m = keras.models.Sequential()\n\n    m.add(keras.layers.Dense(value, input_shape = (784,), activation=\"relu\"))\n    m.add(keras.layers.Dense(10, activation=\"softmax\"))\n\n    m.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n\n    H = m.fit(X_treino, y_treino, \n              batch_size = 200, epochs = 20, \n              validation_data = (X_validacao, y_validacao));\n\n    acuracia_dict[value] = acuracia(m, X_treino, X_validacao, y_treino, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.DataFrame(acuracia_dict).T.plot()\nplt.xlabel('Número de neurônios na camada interna')\nplt.ylabel('Acuracia')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Até 600 neurônios na camada interna há uma alteração significativa na acuracia do modelo."},{"metadata":{},"cell_type":"markdown","source":"### Adição de mais uma camada de neurônios"},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time \n\nneurons_list = [10, 20, 40, 100, 200]\nacuracia_dict = dict()\n\nfor value in neurons_list:\n    m = keras.models.Sequential()\n\n    m.add(keras.layers.Dense(600, input_shape = (784,), activation=\"relu\"))\n    m.add(keras.layers.Dense(value, input_shape = (600,), activation=\"relu\"))\n    m.add(keras.layers.Dense(10, activation=\"softmax\"))\n\n    m.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n\n    H = m.fit(X_treino, y_treino, \n              batch_size = 200, epochs = 20, \n              validation_data = (X_validacao, y_validacao));\n\n    acuracia_dict[value] = acuracia(m, X_treino, X_validacao, y_treino, y_validacao)\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.DataFrame(acuracia_dict).T.plot()\nplt.xlabel('Número de neurônios na segunda camada interna')\nplt.ylabel('Acuracia')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"A adição de mais uma camada de 25 neurônios melhorou um pouco o ajuste."},{"metadata":{},"cell_type":"markdown","source":"### Batch Size"},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time \n\nbatch_size_list = [50, 70, 100, 200, 300, 400]\nacuracia_dict = dict()\n\nfor value in batch_size_list:\n    m = keras.models.Sequential()\n\n    m.add(keras.layers.Dense(600, input_shape = (784,), activation=\"relu\"))\n    m.add(keras.layers.Dense(25, input_shape = (600,), activation=\"relu\"))\n    m.add(keras.layers.Dense(10, activation=\"softmax\"))\n\n    m.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n\n    H = m.fit(X_treino, y_treino, \n              batch_size = value, epochs = 20, \n              validation_data = (X_validacao, y_validacao));\n\n    acuracia_dict[value] = acuracia(m, X_treino, X_validacao, y_treino, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.DataFrame(acuracia_dict).T.plot()\nplt.xlabel('Batch Size')\nplt.ylabel('Acuracia')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Parece que o batch size de 200 otimizar o tempo e possui um bom resultado (em 75 parece ter um pico mas ele é um efeito da aleatóriedade do modelo)"},{"metadata":{},"cell_type":"markdown","source":"### Funções de ativação"},{"metadata":{"trusted":true},"cell_type":"code","source":"activation_list = ['relu', 'selu', 'tanh', 'sigmoid']\nacuracia_dict = dict()\n\nfor activation in activation_list:\n    m = keras.models.Sequential()\n\n    m.add(keras.layers.Dense(600, input_shape = (784,), activation=activation))\n    m.add(keras.layers.Dense(25, input_shape = (600,), activation=activation))\n    m.add(keras.layers.Dense(10, activation=\"softmax\"))\n\n    m.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n\n    H = m.fit(X_treino, y_treino, \n              batch_size = 200, epochs = 20, \n              validation_data = (X_validacao, y_validacao));\n\n    acuracia_dict[activation] = acuracia(m, X_treino, X_validacao, y_treino, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.DataFrame(acuracia_dict).T.plot.bar()\nplt.xlabel('Activação')\nplt.ylabel('Acuracia')\nplt.ylim(0.95, 1.02)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"A melhor função de ativação foi relu"},{"metadata":{},"cell_type":"markdown","source":"### Optimizer"},{"metadata":{"trusted":true},"cell_type":"code","source":"optimizer_list = ['SGD', 'RMSprop', 'Adam', 'Adadelta', 'Adagrad', 'Adamax', 'Nadam', 'Ftrl']\nacuracia_dict = dict()\n\nfor optimizer in optimizer_list:\n    m = keras.models.Sequential()\n\n    m.add(keras.layers.Dense(600, input_shape = (784,), activation='relu'))\n    m.add(keras.layers.Dense(25, input_shape = (600,), activation='relu'))\n    m.add(keras.layers.Dense(10, activation=\"softmax\"))\n\n    m.compile(loss='sparse_categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])\n\n    H = m.fit(X_treino, y_treino, \n              batch_size = 200, epochs = 20, \n              validation_data = (X_validacao, y_validacao));\n\n    acuracia_dict[optimizer] = acuracia(m, X_treino, X_validacao, y_treino, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.DataFrame(acuracia_dict).T.plot.bar()\nplt.xlabel('Optimizer')\nplt.ylabel('Acuracia')\nplt.ylim(0.90, 1.05)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As otimizações RMSprop, Adam, Adamax e Nadam apresentaram o mesmo resultado."},{"metadata":{},"cell_type":"markdown","source":"## Dropout"},{"metadata":{"trusted":true},"cell_type":"code","source":"dropout_list = [0.05, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5, 0.8, 0.9]\nacuracia_dict = dict()\n\nfor dropout in dropout_list:\n    m = keras.models.Sequential()\n\n    m.add(keras.layers.Dense(600, input_shape = (784,), activation='relu'))\n    m.add(keras.layers.Dropout(dropout))\n    m.add(keras.layers.Dense(25, input_shape = (600,), activation='relu'))\n    m.add(keras.layers.Dense(10, activation=\"softmax\"))\n\n    m.compile(loss='sparse_categorical_crossentropy', optimizer='Adam', metrics=['accuracy'])\n    \n\n    H = m.fit(X_treino, y_treino, \n              batch_size = 200, epochs = 20, \n              validation_data = (X_validacao, y_validacao));\n\n    acuracia_dict[dropout] = acuracia(m, X_treino, X_validacao, y_treino, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.DataFrame(acuracia_dict).T.plot.bar()\nplt.xlabel('Dropout')\nplt.ylabel('Acuracia')\nplt.ylim(0.94, 1.05)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Parece que um Dropout de até 0.5 o Dropout não influênciou a precisão do modelo mas diminuiu o sobre ajuste. Após isso começa a diminuir a precisão. Provavelmente indicando que uma primeira camada com metade dos neurônios já é o suficiente."},{"metadata":{"trusted":true},"cell_type":"code","source":"m = keras.models.Sequential()\n\nm.add(keras.layers.Dense(300, input_shape = (784,), activation='relu'))\nm.add(keras.layers.Dense(25, input_shape = (600,), activation='relu'))\nm.add(keras.layers.Dense(10, activation=\"softmax\"))\n\nm.compile(loss='sparse_categorical_crossentropy', optimizer='Adam', metrics=['accuracy'])\n\nH = m.fit(X_treino, y_treino, \n          batch_size = 200, epochs = 20, \n          validation_data = (X_validacao, y_validacao));\n\nacuracia_dict[optimizer] = acuracia(m, X_treino, X_validacao, y_treino, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"acuracia(m, X_treino, X_validacao, y_treino, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Metade dos neurônios renderam um resultado ainda sim muito próximo."},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_erros(m, X_validacao, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_pred = m.predict(X_validacao)\ny_pred = np.argmax(y_pred, axis=1)\n\npredicao = pd.DataFrame(data={'predicao':y_pred, 'target':y_validacao})\npredicao_erros = predicao[predicao.predicao != predicao.target]\n\npredicao_erros","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"acuracia(m, X_treino, X_validacao, y_treino, y_validacao)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"O modelo conseguiu alcançar 98% de taxa de acerto. Existem ainda pontos onde pode ser melhorados, vendo as imagens que ele falhou a reconhecer é possível perceber claramente porque ele tem tanta dificuldade em localizar os padrões."}],"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}