{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# <font color='blue'>Data Science Academy - Python Fundamentos - Capítulo 12</font>\n",
    "\n",
    "## Download: http://github.com/dsacademybr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Detecção de Emoções em Imagens com Inteligência Artificial"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://www.kaggle.com/c/facial-keypoints-detector"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Redes Neurais Convolucionais"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Em redes neurais convolucionais, os dados de entrada são muitas vezes moldados como uma matriz 3D (número de canais, largura da imagem, altura), que preserva a relação espacial entre os pixels. Na figura abaixo, a imagem 3 é um único canal (tons de cinza) de dados, portanto, a dimensão de entrada é especificada como uma tupla (1, largura da imagem, altura da imagem)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![MNIST-flat](https://www.cntk.ai/jup/cntk103a_MNIST_input.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Imagens de cor de cena natural são frequentemente apresentadas como canais de cor Vermelho-Verde-Azul (RGB). A dimensão de entrada dessas imagens é especificada como uma tupla (3, largura da imagem, altura da imagem). Se houver dados de entrada RGB como uma varredura volumétrica com largura de volume, altura de volume e profundidade de volume representando os 3 eixos, o formato de dados de entrada será especificado por uma tupla de 4 valores (3, largura de volume, altura de volume, profundidade de volume). Desta forma, podemos especificar as imagens de entrada em espaço arbitrário de dimensão superior."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![input-rgb](https://www.cntk.ai/jup/cntk103d_rgb.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "CNN é uma rede feedforward composta de diversas camadas de tal forma que a saída de uma camada torna-se a entrada para a próxima camada (semelhante ao MLP). Em MLP, todos os pares possíveis de pixels de entrada são conectados aos nós de saída com cada par tendo um peso, conduzindo assim a uma explosão combinatória de parâmetros a serem aprendidos e também aumentando a possibilidade de overfitting. As camadas de convolução aproveitam a disposição espacial dos pixels e aprendem vários filtros que reduzem significativamente a quantidade de parâmetros na rede. O tamanho do filtro é um parâmetro da camada de convolução.\n",
    "\n",
    "Nesta seção, apresentamos os fundamentos das operações de convolução. \n",
    "\n",
    "### Camada de Convolução\n",
    "\n",
    "Uma camada de convolução é um conjunto de filtros. Cada filtro é definido por uma matriz de peso (** W **) e bias ($ b $).\n",
    "\n",
    "![input-filter](https://www.cntk.ai/jup/cntk103d_filterset.png)\n",
    "\n",
    "Estes filtros são varridos através da imagem que realiza o dot product entre os pesos e o valor de entrada correspondente ($\\vec{x}^T$). O valor de bias é adicionado à saída do dot product e a soma resultante é opcionalmente mapeada através de uma função de ativação. Esse processo é ilustrado na seguinte animação."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<img src=\"https://www.cntk.ai/jup/cntk103d_conv2d_final.gif\" width=\"300\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import display, Image\n",
    "Image(url=\"https://www.cntk.ai/jup/cntk103d_conv2d_final.gif\", width= 300)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As camadas de convolução incorporam as seguintes características-chave:\n",
    "\n",
    "  - Em vez de estar totalmente conectado a todos os pares de nós de entrada e saída, cada nó de convolução é ** conectado localmente ** a um subconjunto de nós de entrada localizados em uma região de entrada menor, também chamada de campo receptivo (RF). A figura acima ilustra pequenas regiões 3 x 3 na imagem como a região RF. No caso de uma imagem RGB, haveria três dessas 3 x 3 regiões, uma de cada um dos 3 canais de cor.\n",
    "   \n",
    "   \n",
    "   - Em vez de ter um único conjunto de pesos (como em uma camada Densa), camadas convolucionais têm vários conjuntos (mostrado na figura com várias cores), chamado ** filtros **. Cada filtro detecta características dentro de cada RF possível na imagem de entrada. A saída da convolução é um conjunto de sub-camadas `n` (mostradas na animação abaixo) onde ` n` é o número de filtros (consulte a figura acima).\n",
    "   \n",
    "     \n",
    "   - Dentro de uma subcamada, em vez de cada nó ter seu próprio conjunto de pesos, um único conjunto de ** pesos compartilhados ** são usados por todos os nós nessa subcamada. Isso reduz o número de parâmetros a serem aprendidos. Isso também abre a porta para vários aspectos da aprendizagem profunda que permitiu a construção de soluções muito práticas:\n",
    "     -- Manuseio de imagens maiores (digamos 512 x 512)\n",
    "     -- Tentando maiores tamanhos de filtro (correspondente a um RF maior) como 11 x 11\n",
    "     -- Aprender mais filtros (digamos 128)\n",
    "     -- Explorar arquiteturas mais profundas (mais de 100 camadas)\n",
    "     -- Alcançar a invariância de tradução (a capacidade de reconhecer um recurso independentemente de onde eles aparecem na imagem)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Strides e Padding\n",
    "\n",
    "** Como os filtros são posicionados? ** Em geral, os filtros são dispostos em telhas sobrepostas, da esquerda para a direita e de cima para baixo. Cada camada de convolução tem um parâmetro para especificar a `filter_shape`, especificando a largura e a altura do filtro no caso das imagens de cena mais naturais. Há um parâmetro (`strides`) que controla a distância até a etapa para a direita ao mover os filtros através de vários RF's em uma linha, e até que ponto para descer quando se move para a próxima linha. O parâmetro booleano `pad` controla se a entrada deve ser preenchida em torno das bordas para permitir um mosaico completo dos RFs perto das bordas.\n",
    "\n",
    "A animação acima mostra os resultados com um `filter_shape` = (3, 3),` strides` = (2, 2) e `pad` = False. As duas animações abaixo mostram os resultados quando `pad` é definido como True. Primeiro, com um passo de 2 e segundo tendo um passo de 1.\n",
    "\n",
    "Nota: a forma da saída é diferente entre as duas configurações. Muitas vezes a sua decisão de pad e os valores de stride é baseada na forma da camada de saída necessária."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Stride = 2\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<img src=\"https://www.cntk.ai/jup/cntk103d_padding_strides.gif\" width=\"200\" height=\"200\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Stride = 1\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<img src=\"https://www.cntk.ai/jup/cntk103d_same_padding_no_strides.gif\" width=\"200\" height=\"200\"/>"
      ],
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Image\n",
    "\n",
    "# Plot images com strides de 2 e 1 e padding habilitado\n",
    "images = [(\"https://www.cntk.ai/jup/cntk103d_padding_strides.gif\" , 'Stride = 2'),\n",
    "          (\"https://www.cntk.ai/jup/cntk103d_same_padding_no_strides.gif\", 'Stride = 1')]\n",
    "\n",
    "for im in images:\n",
    "    print(im[1])\n",
    "    display(Image(url=im[0], width=200, height=200))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pooling Layer\n",
    "\n",
    "Muitas vezes, é necessário controlar o número de parâmetros, especialmente em redes profundas. Para cada camada de saída da camada de convolução (cada camada, corresponde à saída de um filtro), pode-se ter uma camada de agrupamento (Pooling). As camadas de agrupamento são tipicamente introduzidas para:\n",
    "- Reduzir a dimensionalidade da camada anterior (acelerando a rede),\n",
    "- Torna o modelo mais tolerante a alterações no local do objeto na imagem. Por exemplo, mesmo quando um dígito é deslocado para um lado da imagem em vez de estar no meio.\n",
    "\n",
    "É comum inserir periodicamente uma camada de agrupamento entre as camadas Convolucionais sucessivas em uma arquitetura ConvNet. Sua função é reduzir progressivamente o tamanho espacial da representação para reduzir a quantidade de parâmetros e de computação na rede e, portanto, também para controlar o overfitting. A Camada de Agrupamento opera independentemente em cada fatia de profundidade da entrada e redimensiona-a espacialmente, usando a operação MAX. A forma mais comum é uma camada de pooling com filtros de tamanho 2x2 aplicado com um stride de 2 downsamples cada fatia de profundidade na entrada por 2 ao longo de largura e altura, descartando 75% das ativações. Cada operação MAX, neste caso, seria tomar um máximo de 4 números (pequena região 2x2 em alguma fatia de profundidade). A dimensão da profundidade permanece inalterada.\n",
    "\n",
    "Vale ressaltar que existem apenas duas variações comumente observadas na camada de Max Pooling encontradas na prática: Uma camada de agrupamento com F = 3, S = 2 (também chamada de pool de sobreposição) e mais comumente F = 2, S = 2. Agrupando tamanhos com campos receptivos maiores pode destruir a rede e travar a máquina.\n",
    "\n",
    "O cálculo em um nó de pooling é muito mais simples do que um nó de feedforward normal. Ele não tem peso, bias ou função de ativação. Ele usa uma função de agregação simples (como max ou average) para calcular sua saída. A função mais comumente usada é \"max\" - um nó de pooling máximo simplesmente fornece o máximo dos valores de entrada correspondentes à posição do filtro da entrada. A figura abaixo mostra os valores de entrada em uma região 4 x 4. A tamanho máximo da janela de agrupamento é 2 x 2 e começa a partir do canto superior esquerdo. O valor máximo dentro da janela torna-se a saída da região. Cada vez que o modelo é deslocado pela quantidade especificada pelo parâmetro stride (como mostrado na figura abaixo) e a operação de pooling máximo é repetida.\n",
    "![maxppool](https://cntk.ai/jup/201/MaxPooling.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Rede Convolucional Típica\n",
    "\n",
    "![mnist-conv-mp](http://www.cntk.ai/jup/conv103d_mnist-conv-mp.png)\n",
    "\n",
    "Uma CNN típica contém um conjunto de camadas alternadas de convolução e agrupamento (Pooling) seguido por uma camada de saída densa para a classificação. Você encontrará variantes desta estrutura em muitas redes profundas clássicas (VGG, AlexNet, etc.). Isto está em contraste com a rede MLP, que consiste em 2 camadas densas seguidas por uma camada de saída densa.\n",
    "\n",
    "As ilustrações são apresentadas no contexto de imagens bidimensionais (2D), mas o conceito e os componentes podem operar em qualquer dado dimensional. O esquema acima mostra 2 camadas de convolução e 2 camadas de agrupamento máximo. Uma estratégia típica é aumentar o número de filtros nas camadas mais profundas, reduzindo o tamanho espacial de cada camada intermediária. Camadas intermediárias."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A figura a seguir ilustra o modelo que vamos construir. Observe que os parâmetros no modelo abaixo devem ser experimentados. Estes são frequentemente chamados de hiperparâmetros de rede. Aumentar a forma do filtro leva a um aumento no número de parâmetros do modelo, aumenta o tempo de computação e ajuda o modelo a se ajustar melhor aos dados. No entanto, corre-se o risco de [overfitting](https://en.wikipedia.org/wiki/Overfitting). Normalmente, o número de filtros nas camadas mais profundas é maior do que o número de filtros nas camadas anteriores. Escolhemos 8 e 16 como número de filtros para a primeira e segunda camadas, respectivamente. Estes hiperparâmetros devem ser experimentados durante a construção do modelo.\n",
    "\n",
    "![conv-only](https://www.cntk.ai/jup/cntk103d_convonly2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** Compreendendo os parâmetros **:\n",
    "\n",
    "\n",
    "Nosso modelo tem duas camadas de convolução, cada uma com peso e bias. Isso adiciona até 4 tensores de parâmetro. Adicionalmente, a camada densa tem tensores de peso e de bias. Assim, os tensores de 6 parâmetros.\n",
    "\n",
    "Vamos agora contar o número de parâmetros:\n",
    "- * Primeira camada de convolução *: Existem 8 filtros cada um de tamanho (1 x 5 x 5) onde 1 é o número de canais na imagem de entrada. Isto adiciona até 200 valores na matriz de peso e 8 valores de bias.\n",
    "\n",
    "\n",
    "- * Segunda camada de convolução *: Existem 16 filtros cada um de tamanho (8 x 5 x 5) onde 8 é o número de canais na entrada para a segunda camada (= saída da primeira camada). Isto adiciona até 3200 valores na matriz de peso e 16 valores de bias.\n",
    "\n",
    "\n",
    "- * Última camada densa *: Existem 16 x 7 x 7 valores de entrada e produz 10 valores de saída correspondentes aos 10 dígitos no conjunto de dados MNIST. Isto corresponde a (16 x 7 x 7) x 10 valores de peso e 10 valores de bias.\n",
    "\n",
    "Adicionando estes acima dá os 11274 parâmetros no modelo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Construindo e Treinando o Modelo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Definindo os Dados e Hyperparâmetros"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Imports\n",
    "import os\n",
    "import sys\n",
    "import inspect\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import matplotlib.pyplot as plt\n",
    "from modulos import utils\n",
    "from datetime import datetime\n",
    "from tensorflow.python.framework import ops\n",
    "from sklearn.metrics.classification import accuracy_score\n",
    "from sklearn.metrics import precision_recall_fscore_support\n",
    "import warnings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1.8.0'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Versão do TensorFlow\n",
    "# Para instalar a mesma versão do TF, use: \n",
    "# CPU: pip install tensorflow==1.8 (no prompt ou terminal)\n",
    "# GPU: pip install tensorflow_gpu==1.8 (no prompt ou terminal)\n",
    "tf.__version__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "warnings.filterwarnings(\"ignore\")\n",
    "os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'\n",
    "ops.reset_default_graph()\n",
    "np.random.seed(123456789)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "FLAGS = tf.flags.FLAGS\n",
    "tf.flags.DEFINE_string(\"data_dir\", \"dataset/\", \"Caminho para o diretório com dados de treino e de teste\")\n",
    "tf.flags.DEFINE_string(\"logs_dir\", \"modelo/\", \"Caminho para o diretório onde o modelo será gravado\")\n",
    "tf.flags.DEFINE_string(\"mode\", \"train\", \"mode: train (Default)/ test\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Hyperparâmetros\n",
    "BATCH_SIZE = 128\n",
    "LEARNING_RATE = 1e-3\n",
    "MAX_ITERATIONS = 1000\n",
    "REGULARIZATION = 1e-3\n",
    "IMAGE_SIZE = 48\n",
    "NUM_LABELS = 7\n",
    "VALIDATION_PERCENT = 0.1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Funções Auxiliares Para Construção do Modelo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add_to_regularization_loss(W, b):\n",
    "    tf.add_to_collection(\"losses\", tf.nn.l2_loss(W))\n",
    "    tf.add_to_collection(\"losses\", tf.nn.l2_loss(b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def weight_variable(shape, stddev=0.02, name=None):\n",
    "    initial = tf.truncated_normal(shape, stddev=stddev)\n",
    "    if name is None:\n",
    "        return tf.Variable(initial)\n",
    "    else:\n",
    "        return tf.get_variable(name, initializer=initial)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def bias_variable(shape, name=None):\n",
    "    initial = tf.constant(0.0, shape=shape)\n",
    "    if name is None:\n",
    "        return tf.Variable(initial)\n",
    "    else:\n",
    "        return tf.get_variable(name, initializer=initial)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Construção do Modelo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def emotionCNN(dataset):\n",
    "    \n",
    "    # Camada de Convolução 1\n",
    "    with tf.name_scope(\"conv1\") as scope:\n",
    "        tf.summary.histogram(\"W_conv1\", weights['wc1'])\n",
    "        tf.summary.histogram(\"b_conv1\", biases['bc1'])\n",
    "        conv_1 = tf.nn.conv2d(dataset, weights['wc1'], strides=[1, 1, 1, 1], padding=\"SAME\")\n",
    "        h_conv1 = tf.nn.bias_add(conv_1, biases['bc1'])\n",
    "        h_1 = tf.nn.relu(h_conv1)\n",
    "        h_pool1 = tf.nn.max_pool(h_1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding=\"SAME\")\n",
    "        add_to_regularization_loss(weights['wc1'], biases['bc1'])\n",
    "\n",
    "    # Camada de Convolução 2\n",
    "    with tf.name_scope(\"conv2\") as scope:\n",
    "        tf.summary.histogram(\"W_conv2\", weights['wc2'])\n",
    "        tf.summary.histogram(\"b_conv2\", biases['bc2'])\n",
    "        conv_2 = tf.nn.conv2d(h_pool1, weights['wc2'], strides=[1, 1, 1, 1], padding=\"SAME\")\n",
    "        h_conv2 = tf.nn.bias_add(conv_2, biases['bc2'])\n",
    "        h_2 = tf.nn.relu(h_conv2)\n",
    "        h_pool2 = tf.nn.max_pool(h_2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding=\"SAME\")\n",
    "        add_to_regularization_loss(weights['wc2'], biases['bc2'])\n",
    "\n",
    "    # Camada Totalmente Conectada 1\n",
    "    with tf.name_scope(\"fc_1\") as scope:\n",
    "        prob = 0.5\n",
    "        image_size = IMAGE_SIZE // 4\n",
    "        h_flat = tf.reshape(h_pool2, [-1, image_size * image_size * 64])\n",
    "        tf.summary.histogram(\"W_fc1\", weights['wf1'])\n",
    "        tf.summary.histogram(\"b_fc1\", biases['bf1'])\n",
    "        h_fc1 = tf.nn.relu(tf.matmul(h_flat, weights['wf1']) + biases['bf1'])\n",
    "        h_fc1_dropout = tf.nn.dropout(h_fc1, prob)\n",
    "        \n",
    "    # Camada Totalmente Conectada 2\n",
    "    with tf.name_scope(\"fc_2\") as scope:\n",
    "        tf.summary.histogram(\"W_fc2\", weights['wf2'])\n",
    "        tf.summary.histogram(\"b_fc2\", biases['bf2'])\n",
    "        pred = tf.matmul(h_fc1_dropout, weights['wf2']) + biases['bf2']\n",
    "\n",
    "    return pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Pesos e Bias do Modelo\n",
    "weights = {\n",
    "    'wc1': weight_variable([5, 5, 1, 32], name=\"W_conv1\"),\n",
    "    'wc2': weight_variable([3, 3, 32, 64],name=\"W_conv2\"),\n",
    "    'wf1': weight_variable([int((IMAGE_SIZE // 4) * (IMAGE_SIZE // 4)) * 64, 256],name=\"W_fc1\"),\n",
    "    'wf2': weight_variable([256, NUM_LABELS], name=\"W_fc2\")\n",
    "}\n",
    "\n",
    "biases = {\n",
    "    'bc1': bias_variable([32], name=\"b_conv1\"),\n",
    "    'bc2': bias_variable([64], name=\"b_conv2\"),\n",
    "    'bf1': bias_variable([256], name=\"b_fc1\"),\n",
    "    'bf2': bias_variable([NUM_LABELS], name=\"b_fc2\")\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def loss(pred, label):\n",
    "    cross_entropy_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=label))\n",
    "    tf.summary.scalar('Entropy', cross_entropy_loss)\n",
    "    reg_losses = tf.add_n(tf.get_collection(\"losses\"))\n",
    "    tf.summary.scalar('Reg_loss', reg_losses)\n",
    "    return cross_entropy_loss + REGULARIZATION * reg_losses"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train(loss, step):\n",
    "    return tf.train.AdamOptimizer(LEARNING_RATE).minimize(loss, global_step=step)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_next_batch(images, labels, step):\n",
    "    offset = (step * BATCH_SIZE) % (images.shape[0] - BATCH_SIZE)\n",
    "    batch_images = images[offset: offset + BATCH_SIZE]\n",
    "    batch_labels = labels[offset:offset + BATCH_SIZE]\n",
    "    return batch_images, batch_labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Listas para resultados de treinamento\n",
    "train_error_list = []\n",
    "train_step_list = []\n",
    "\n",
    "# Listas para resultados de validação\n",
    "valid_error_list = []\n",
    "valid_step_list = []"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Treinamento"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[]\n",
      "[]\n"
     ]
    }
   ],
   "source": [
    "def main(argv=None):\n",
    "    \n",
    "    # Carrega os dados\n",
    "    train_images, train_labels, valid_images, valid_labels, test_images = utils.read_data(FLAGS.data_dir)\n",
    "    \n",
    "    print(\"\\nTamanho do Dataset de Treino: %s\" % train_images.shape[0])\n",
    "    print('Tamanho do Dataset de Validação: %s' % valid_images.shape[0])\n",
    "    print(\"Tamanho do Dataset de Teste: %s\" % test_images.shape[0])\n",
    "\n",
    "    global_step = tf.Variable(0, trainable=False)\n",
    "    dropout_prob = tf.placeholder(tf.float32)\n",
    "    input_dataset = tf.placeholder(tf.float32, [None, IMAGE_SIZE, IMAGE_SIZE, 1], name=\"input\")\n",
    "    input_labels = tf.placeholder(tf.float32, [None, NUM_LABELS])\n",
    "\n",
    "    pred = emotionCNN(input_dataset)\n",
    "    output_pred = tf.nn.softmax(pred, name=\"output\")\n",
    "    loss_val = loss(pred, input_labels)\n",
    "    train_op = train(loss_val, global_step)\n",
    "\n",
    "    summary_op = tf.summary.merge_all()\n",
    "    init_op = tf.global_variables_initializer()\n",
    "\n",
    "    with tf.Session() as sess:\n",
    "        sess.run(init_op)\n",
    "        summary_writer = tf.summary.FileWriter(FLAGS.logs_dir, sess.graph)\n",
    "        saver = tf.train.Saver()\n",
    "        ckpt = tf.train.get_checkpoint_state(FLAGS.logs_dir)\n",
    "        if ckpt and ckpt.model_checkpoint_path:\n",
    "            saver.restore(sess, ckpt.model_checkpoint_path)\n",
    "            print(\"Modelo Restaurado!\")\n",
    "\n",
    "        for step in range(MAX_ITERATIONS):\n",
    "            batch_image, batch_label = get_next_batch(train_images, train_labels, step)\n",
    "            feed_dict = {input_dataset: batch_image, input_labels: batch_label}\n",
    "\n",
    "            sess.run(train_op, feed_dict=feed_dict)\n",
    "            if step % 10 == 0:\n",
    "                train_loss, summary_str = sess.run([loss_val, summary_op], feed_dict=feed_dict)\n",
    "                summary_writer.add_summary(summary_str, global_step=step)\n",
    "                train_error_list.append(train_loss)\n",
    "                train_step_list.append(step)\n",
    "                print(\"Taxa de Erro no Treinamento: %f\" % train_loss)\n",
    "\n",
    "            if step % 100 == 0:\n",
    "                valid_loss = sess.run(loss_val, feed_dict={input_dataset: valid_images, input_labels: valid_labels})\n",
    "                valid_error_list.append(valid_loss)\n",
    "                valid_step_list.append(step)\n",
    "                print(\"%s Taxa de Erro na Validação: %f\" % (datetime.now(), valid_loss))\n",
    "                saver.save(sess, FLAGS.logs_dir + 'model.ckpt', global_step=step)\n",
    "        \n",
    "        # Plot do erro durante o treinamento\n",
    "        plt.plot(train_step_list, train_error_list, 'r--', label='Erro no Treinamento Por Iteração', linewidth=4)\n",
    "        plt.title('Erro no Treinamento Por Iteração')\n",
    "        plt.xlabel('Iteração')\n",
    "        plt.ylabel('Erro no Treinamento')\n",
    "        plt.legend(loc='upper right')\n",
    "        plt.show()\n",
    "\n",
    "        # Plot do erro durante a validação\n",
    "        plt.plot(valid_step_list, valid_error_list, 'r--', label='Erro na Validação Por Iteração', linewidth=4)\n",
    "        plt.title('Erro na Validação Por Iteração')\n",
    "        plt.xlabel('Iteração')\n",
    "        plt.ylabel('Erro na Validação')\n",
    "        plt.legend(loc='upper right')\n",
    "        plt.show()  \n",
    "\n",
    "print(train_error_list) \n",
    "print(valid_error_list) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Lendo train.csv ...\n",
      "(4178, 48, 48, 1)\n",
      "(4178, 7)\n",
      "Lendo test.csv ...\n",
      "\n",
      "Salvando ...\n",
      "\n",
      "Tamanho do Dataset de Treino: 3761\n",
      "Tamanho do Dataset de Validação: 417\n",
      "Tamanho do Dataset de Teste: 1312\n",
      "WARNING:tensorflow:From <ipython-input-13-dec8419985f4>:2: softmax_cross_entropy_with_logits (from tensorflow.python.ops.nn_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "\n",
      "Future major versions of TensorFlow will allow gradients to flow\n",
      "into the labels input on backprop by default.\n",
      "\n",
      "See @{tf.nn.softmax_cross_entropy_with_logits_v2}.\n",
      "\n",
      "Taxa de Erro no Treinamento: 1.929399\n",
      "2018-06-11 18:37:17.809532 Taxa de Erro na Validação: 1.929255\n",
      "Taxa de Erro no Treinamento: 1.817885\n",
      "Taxa de Erro no Treinamento: 1.891102\n",
      "Taxa de Erro no Treinamento: 1.835397\n",
      "Taxa de Erro no Treinamento: 1.832039\n",
      "Taxa de Erro no Treinamento: 1.865427\n",
      "Taxa de Erro no Treinamento: 1.802101\n",
      "Taxa de Erro no Treinamento: 1.664342\n",
      "Taxa de Erro no Treinamento: 1.561122\n",
      "Taxa de Erro no Treinamento: 1.381925\n",
      "Taxa de Erro no Treinamento: 1.420945\n",
      "2018-06-11 18:37:53.262153 Taxa de Erro na Validação: 1.285564\n",
      "Taxa de Erro no Treinamento: 1.192030\n",
      "Taxa de Erro no Treinamento: 1.065625\n",
      "Taxa de Erro no Treinamento: 1.211729\n",
      "Taxa de Erro no Treinamento: 1.092896\n",
      "Taxa de Erro no Treinamento: 1.123945\n",
      "Taxa de Erro no Treinamento: 1.102716\n",
      "Taxa de Erro no Treinamento: 1.109048\n",
      "Taxa de Erro no Treinamento: 1.030627\n",
      "Taxa de Erro no Treinamento: 1.039998\n",
      "Taxa de Erro no Treinamento: 0.885504\n",
      "2018-06-11 18:38:28.893173 Taxa de Erro na Validação: 0.946695\n",
      "Taxa de Erro no Treinamento: 0.971113\n",
      "Taxa de Erro no Treinamento: 0.773806\n",
      "Taxa de Erro no Treinamento: 0.962329\n",
      "Taxa de Erro no Treinamento: 0.759960\n",
      "Taxa de Erro no Treinamento: 0.840750\n",
      "Taxa de Erro no Treinamento: 0.866023\n",
      "Taxa de Erro no Treinamento: 0.878915\n",
      "Taxa de Erro no Treinamento: 0.715216\n",
      "Taxa de Erro no Treinamento: 0.627392\n",
      "Taxa de Erro no Treinamento: 0.745460\n",
      "2018-06-11 18:39:02.765121 Taxa de Erro na Validação: 0.809955\n",
      "Taxa de Erro no Treinamento: 0.826810\n",
      "Taxa de Erro no Treinamento: 0.758084\n",
      "Taxa de Erro no Treinamento: 0.830328\n",
      "Taxa de Erro no Treinamento: 0.737692\n",
      "Taxa de Erro no Treinamento: 0.631383\n",
      "Taxa de Erro no Treinamento: 0.685231\n",
      "Taxa de Erro no Treinamento: 0.687877\n",
      "Taxa de Erro no Treinamento: 0.609782\n",
      "Taxa de Erro no Treinamento: 0.592490\n",
      "Taxa de Erro no Treinamento: 0.644231\n",
      "2018-06-11 18:39:38.297391 Taxa de Erro na Validação: 0.733738\n",
      "Taxa de Erro no Treinamento: 0.620003\n",
      "Taxa de Erro no Treinamento: 0.635934\n",
      "Taxa de Erro no Treinamento: 0.572669\n",
      "Taxa de Erro no Treinamento: 0.611553\n",
      "Taxa de Erro no Treinamento: 0.528749\n",
      "Taxa de Erro no Treinamento: 0.497544\n",
      "Taxa de Erro no Treinamento: 0.523367\n",
      "Taxa de Erro no Treinamento: 0.475813\n",
      "Taxa de Erro no Treinamento: 0.503535\n",
      "Taxa de Erro no Treinamento: 0.571714\n",
      "2018-06-11 18:40:14.902051 Taxa de Erro na Validação: 0.656546\n",
      "Taxa de Erro no Treinamento: 0.569328\n",
      "Taxa de Erro no Treinamento: 0.523675\n",
      "Taxa de Erro no Treinamento: 0.555101\n",
      "Taxa de Erro no Treinamento: 0.464529\n",
      "Taxa de Erro no Treinamento: 0.423420\n",
      "Taxa de Erro no Treinamento: 0.379337\n",
      "Taxa de Erro no Treinamento: 0.496138\n",
      "Taxa de Erro no Treinamento: 0.477538\n",
      "Taxa de Erro no Treinamento: 0.508547\n",
      "Taxa de Erro no Treinamento: 0.501289\n",
      "2018-06-11 18:40:49.902435 Taxa de Erro na Validação: 0.675489\n",
      "Taxa de Erro no Treinamento: 0.406566\n",
      "Taxa de Erro no Treinamento: 0.446144\n",
      "Taxa de Erro no Treinamento: 0.429603\n",
      "Taxa de Erro no Treinamento: 0.371047\n",
      "Taxa de Erro no Treinamento: 0.405003\n",
      "Taxa de Erro no Treinamento: 0.482020\n",
      "Taxa de Erro no Treinamento: 0.528508\n",
      "Taxa de Erro no Treinamento: 0.427659\n",
      "Taxa de Erro no Treinamento: 0.422047\n",
      "Taxa de Erro no Treinamento: 0.461822\n",
      "2018-06-11 18:41:24.653874 Taxa de Erro na Validação: 0.650056\n",
      "Taxa de Erro no Treinamento: 0.464994\n",
      "Taxa de Erro no Treinamento: 0.336006\n",
      "Taxa de Erro no Treinamento: 0.388088\n",
      "Taxa de Erro no Treinamento: 0.439418\n",
      "Taxa de Erro no Treinamento: 0.359850\n",
      "Taxa de Erro no Treinamento: 0.429025\n",
      "Taxa de Erro no Treinamento: 0.416877\n",
      "Taxa de Erro no Treinamento: 0.323073\n",
      "Taxa de Erro no Treinamento: 0.427577\n",
      "Taxa de Erro no Treinamento: 0.372024\n",
      "2018-06-11 18:41:58.696306 Taxa de Erro na Validação: 0.661805\n",
      "Taxa de Erro no Treinamento: 0.264303\n",
      "Taxa de Erro no Treinamento: 0.402984\n",
      "Taxa de Erro no Treinamento: 0.254359\n",
      "Taxa de Erro no Treinamento: 0.380275\n",
      "Taxa de Erro no Treinamento: 0.444294\n",
      "Taxa de Erro no Treinamento: 0.337435\n",
      "Taxa de Erro no Treinamento: 0.375707\n",
      "Taxa de Erro no Treinamento: 0.442624\n",
      "Taxa de Erro no Treinamento: 0.266163\n",
      "Taxa de Erro no Treinamento: 0.321579\n",
      "2018-06-11 18:42:34.101171 Taxa de Erro na Validação: 0.545605\n",
      "Taxa de Erro no Treinamento: 0.423147\n",
      "Taxa de Erro no Treinamento: 0.292303\n",
      "Taxa de Erro no Treinamento: 0.392608\n",
      "Taxa de Erro no Treinamento: 0.285588\n",
      "Taxa de Erro no Treinamento: 0.232512\n",
      "Taxa de Erro no Treinamento: 0.266831\n",
      "Taxa de Erro no Treinamento: 0.311395\n",
      "Taxa de Erro no Treinamento: 0.384060\n",
      "Taxa de Erro no Treinamento: 0.374475\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYwAAAEWCAYAAAB1xKBvAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzt3Xd4VGX2wPHvoSNFUMoKoSoivUUUVMCKIoogsrZdG/buroplbav+dN1lhdVVURQruKIiKgoWFHBFCAoosEIQxSAdQm8J5/fHe4fpyZ0kk0km5/M882Tuve+9894ZmDNvF1XFGGOMKUylVGfAGGNM+WABwxhjjC8WMIwxxvhiAcMYY4wvFjCMMcb4YgHDGGOMLxYwTIUgItNE5KJU58OUPBGpISKLROQtEeklIn9LdZ7SlQWMNCYiP4vILhHZHvJ4KtX5KoyIPBuS370isi9k+6OiXFNVT1PV10s6r8kkIg+LyLhinP+a9/5tF5FNXtA8soTyNlxEvgjZzhGRfiVx7SJoD/wHmAw8BUxIUT7SngWM9HeWqtYOedwQK5GIVPGzrzSo6jWB/AKPAm+G5P+MyPSpymc58aj3PjYDNgEvJnqBZL+/IlJJRIr8XaSq36rqg6r6qqr2UNVvSzJ/JsgCRgUlIpeKyFci8k8R2QQ8EGdfJRG5V0R+EZF1IvKKiBwc55r9vF+af/LSrhaRy0KOH+ydv9673r1F+aIQkSNEREXkMhFZCUzz9h8nIrNFJFdE5otIn5BzZonIpd7z4SLypXefuSLyk4icFpJ2uIgsEZFtIrJcRIaHHDvFK7nd5d3HbyJylogMFJFl3i/5O0LSVxKRu73rbBCRCSJSP+I+/ui9b+tFZIR3bCBwB3CRV0KY5+3PEJEPvNdZJiKX+3nPVHUHMB7o6F2nhoiM9j6jVSIyUkSqRdzj3SKyBni+kM9jPNAE+MjL620+P4+/isjXwA6geUHvu3fOEO86W0UkO/CZ+TjvGi/9RhGZJCKH+XnPTAyqao80fQA/A6fEOXYpkAfcCFQBasbZdzmQDbQGagPvAK/GuWY/7/yHgKrAAGAnUN87/grwHlAHaAksBa4o5B4eAF6L2HcEoMBLwEFePpsBG4H+uB9CpwMbgEO9c2YBl3rPhwP7vHur7N3vryHXP8u7XwFOAnYBnb1jp3j3eI93j9cC64DXvPenM7AbaO6l/zPwFdAUqAGMDbx/IffxrHesO7AHaOMdfxgYF3HvXwH/Ckm/Aegb5717DXjAe14HeBOY7m0/CvwXaAg0Ar4B7o+4x0eBakDNGNceDnwRsp0D9AvZ9vN5/Ay0897HKoW8772BXOBk73rNgLY+Pq/TvM+nq/ee/Rv4PNX/N8vrI+UZsEcSP1z3H3K79x8t8LjSO3YpsDIifax9nwHXhWy3xX3ZVonxev28/6xVQvatA47FfTHvAdqHHLs69Esnzj08QPyA0Txk3z3ASzHyfpH3PDJg/C8kXV3veg3i5OED4Hrv+Snee1rZ267vndsjJP0CYKD3fBkhX+jeF90e70svcB+/Czn+LTDUex4WMIBW3ntfK2TfE8ALcfL9Gi545QKrgUlAK+/YL8BpIWnPBLJD7nE3UK2Az6WwgOHn87ivkM8+9H0fCzzh89996Hkv46rlQj/rfCCjNP8vpsvDqqTS3zmqWi/kEVq98GuM9JH7muC+XAJ+wf0abBzn9Taqal7I9k7cL+8GuF+rkddq6uMe4gnNawvgAq/6I1dEcnGBqkmcc9dE5BEvn3jVS9941T65uF+pDULSb1DVfO/5Lu/v2pDjuwLXApoD74fk6XtckGgUSKyqkXmpTWxNvNfeEbKvsPfwMe9zP0xVz1HVFd7+wyj4s1irqnsLuG5h/HweYf/WCnnfmwHLY71QIeeF/ftV1a3AZor3767CsoBRscWaqjhy32+4//wBzXHVFWtJzAbcr+PIa61K8DoHqPeT0fMr7hdtaHCspapPJHJNEakJTAT+D2isqvVwbSRSxGzmAKdG5KtGRJCIJ9Zn0UBEaoXsK+p7uJqCP4tEp7GOTO/n8zhwjo/3/Vfg8MgX9XFe2L9fEamDKxUW+d9dRWYBwxRmPHCriLQSkdBeS3mFnBfG+0X+H+AREakjIi2A23DVJiXhVWCwiJwqIpW9Rt0TRSReCSOe6riS0Hog32t8PrkY+XoWeFREmgOISCMROdvnuWuBliIiAF7pIMu7XnUR6QpcBhSlu/B44D4RaSAiDYG/ULzPYi2uHSEg0c+jsPd9LDDcu0Ylr/G/rY/zxgNXiEhnEamOCywzVTWnGPdaYVnASH/vS/g4jHcTPP9F3H/+GcAKXN32jUXMy424HjE/4eqw36AI3TxjUdWfgcG4L771wErgTyT4b1xVc4FbgXdx3VCH4urEi2ok8DHwmYhswzU0H+3z3DdxX4abRGSOt+/3QBtcldpE4G5VnV6EfD2Ia2v5HliIa/T+vyJcJ+BR4EGv+umWRD+Pwt53Vf0vcCUwGtcGMR1o5uO8j3GdMN7FlaqaAzaAs4gkvFRvjDFlm4g8iOvp9GWq81LRWAnDGFNueNWiK4ETU52XishGyBpjypMZuEbswanOSEVkVVLGGGN8SVqVlIg0E5Hp3pD9RSJyc4w04k1PkC0iC0Wke8ixS8RNfbBMRC5JVj6NMcb4k7QShjdfy2Gq+q3X93kebhDZ4pA0A3A9ZwYAxwCjVPUYETkE130wE9dXex5uJO3mgl6zQYMG2rJly6TcjzHGpKN58+ZtUNWGftImrQ1DVVfjurGhqttEZAludOXikGSDgFe8AVizRaSeF2j6AZ+o6iYAEfkENxfN+IJes2XLlmRlZZX4vRhjTLoSkV8KT+WUSi8pEWkJdMP19Q7VlPDpAXK8ffH2x7r2VSKSJSJZ69evL6ksG2OMiZD0gOF1g3sbuMWbxyXscIxTtID90TtVx6hqpqpmNmzoq1RljDGmCJIaMESkKi5YvK6q78RIkoObVCwgAzf3S7z9xhhjUiRpbRje/DdjgSWqOjJOssnADSIyAdfovUVVV4vIVNx8OfW9dKcBdyUrryY97Nu3j5ycHHbv3p3qrBhT5tSoUYOMjAyqVq1a5Gskc+DeccAfgO9FZL63727cXC6o6rPAFFwPqWzctM6Xecc2ichfgbneeQ8FGsCNiScnJ4c6derQsmVLvPn6jDG4dY82btxITk4OrVq1KvJ1ktlLahaFTAnt9Y66Ps6xFymhielMxbB7924LFsbEICIceuihFLdjkM0lZdKKBQtjYiuJ/xsWMAL274dVtqaKMcbEU7EDxs6d8Pe/w6BB0LAh9OgBNreWKYbKlSvTtWvXA4/HHnss1VkC4JhjjqFr1640b96chg0bHsjfzz//7Psa99xzD9OnF2XpjeT56aefmDBhQkLnZGdnU7NmTbp27Ur79u25/vrrKc6MFxkZGeTm5rJp0yaeffbZIl8nERdddBF9+/bl0ksvJT8/v/ATSkqqFxUvyUePHj00Ifv2qdaqperChHssXZrYNUyZsXjx4lRnQWvVqlVomry8vLDtffv2JSs7UV566SW9/vrr4x6PzFtZ98knn+igQYMSOmfZsmXapUsXVVXdu3ev9u7dW9977z1f58b6rJo2baqbN28Ou65f+/fv1/z8/ITOKY5Y/0eALPX5HVuxSxhVqkCvXuH7Zs0KPl+8GFasKN08mZIjUrRHjx4lnpWWLVvy0EMPcfzxx/PWW2/Rr18/7r77bvr27cuoUaP45ZdfOPnkk+ncuTMnn3wyK1eujLrGAw88wOWXX06/fv1o3bo1o0ePPnBs5MiRdOzYkY4dO/Lkk0/6zldeXh716tXj3nvvpWfPnsyZM4e5c+fSt29fevTowRlnnMHatW759osvvphJkyYB7lf1Aw88QLdu3ejcuTNLly4FYPbs2fTq1Ytu3bpx3HHHsWzZMgBeeOEFhgwZwsCBA2nVqhXPPPMMTzzxBN26daN3797k5uYCsGzZMvr370+PHj3o06fPgetefPHF3HzzzfTu3ZvWrVvz7rtu4cgRI0Ywffp0unbtyujRo9m1axeXXHIJnTp1onv37syYMaPA+69atSq9evUiOzub/fv3c9ttt9GxY0c6derExIkTAfj000855ZRTOP/88+nWrVvca40YMYIff/yRrl27MmLECAAee+wxevbsSefOnXnooYcAV8Lp2LEj11xzDd27d2f16tVcddVVZGZm0qFDhwPpAL755ht69epFly5dOPbYY9m3b1/c9zjRey8Sv5GlPDwSLmGoqj74YHgJ47LL3P7bbw/uGzUq8euaUhf16yn0c03k0b17kfNQqVIl7dKly4HHhAkTVFW1RYsW+vjjjx9I17dvX7322msPbA8cOFDHjRunqqpjx46N+av5/vvv1169eunu3bt1/fr1esghh+jevXs1KytLO3bsqNu3b9dt27Zp+/bt9dtvv42Zv8gSxr59+xTQt99+W1VVd+/erb169dL169erquprr72mV155paqqXnTRRfruu++qqvtV/e9//1tVVUeNGqVXX321qqrm5uYeKKV89NFHOmzYMFVVff755/XII4/U7du365o1a7ROnTr6/PPPq6rqDTfcoP/6179UVbVfv36anZ2tqqqzZs3SU0899cBrn3/++bp//35dsGCBtm3bVlWjSxiPPfaYDh8+XFVVf/jhB23evLnu2bMn7D0ILQls375du3XrptOmTdMJEyZo//79NS8vT1evXq0ZGRm6du1a/eSTT7RWrVr6yy+/xHxP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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x10d409dd8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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SOmmbt3KPZT09HTuu+8+jjvuOF577TWysrK4/fbb6d27N6NGjWL58uX07duXTp060bdvX1asWFFsH8OHD+fyyy8nKyuLww47rMgP4Nlnn023bt1o3749Y8aMKbZtmzZtaNiwIV9/Xdg92aRJk7jgggsAuPrqq8nMzKR9+/bcc889Ud/D+vXrAXjwwQdp06YNJ510UpH/cp999lmOPvpoMjIyGDRoUMF/3GvXrmXgwIFkZGTQuXNnsrOz2bZtG3379qVr16507NiRN998s2A/TzzxBB06dKBDhw6MHDky7vE94YQTWLp0KQATJkygY8eOdOjQgVtuuaWgTL169bj77rvp3r07s2bNirif0aNHs3r1avr06UOfPm5IiA8//JCePXvStWtXzj33XLZt21ZwPEI/06Dee4mpaqWaunXrpqVyxx2qUDhlZZVuP6bSWrBgQdEFod+Hkkxdu5Y6hmrVqmlGRkbBNHHiRFVVPfTQQ3XEiBEF5Xr37q1XX311wfwZZ5yhY8eOVVXV5557TgcMGFBs3/fcc4/27NlTd+3apbm5uXrAAQfo7t27VVV1w4YNqqq6Y8cObd++va5fv77Y9n//+9/1hhtuUFXVWbNmaWZmZsG6/O3z8vK0d+/e+sMPPxTE+e233xa8h9zcXM3OztYOHTro9u3bdfPmzXr44Yfro48+qqpa5HXvuOMOHT16tKqqnnfeeQXP9+zZo5s3by54VFXNzc3Vww8/XPft21ew/23btunWrVu1Xbt2+t133xV7P/nxqKpec801evPNN+uqVau0ZcuWum7dOt2zZ4/26dNHp06dqqqqgL766qvF9qOqeumll+prr71WbL+5ubl6/PHH67Zt21RV9ZFHHtF77723oFzoZ5rM917su+7eX7Ym8BubGtVHAEOGwIMPFs5Pnw7Ll8OhhwYWkkk9saqPzj///Kjzs2bNYsoU133YkCFDuPnmmyPu4/TTT6dWrVrUqlWLpk2bsnbtWlq0aMHo0aOZOtUNy71y5Up+/vlnGjduXGTbCy64gF69evH4448zceJEBg8eXLBu0qRJjBkzhry8PH799VcWLFhAp06dIsbw+eefM3DgwILqlbPOOqtg3U8//cSdd97Jpk2b2LZtG6eeeioAn376KS+99BIA1atXZ//992fPnj3cfvvtzJw5k2rVqrFq1SrWrl3LF198wcCB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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x10d5a2048>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "ename": "SystemExit",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "An exception has occurred, use %tb to see the full traceback.\n",
      "\u001b[0;31mSystemExit\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "if __name__ == \"__main__\":\n",
    "    tf.app.run()\n",
    "    print(\"Treinanento concluído\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Para adquirir conhecimento técnico sólido e especializado em Deep Learning, Visão Computacional, Processamento de Linguagem Natural e outros temas relacionados à Inteligência Artificial, confira nosso programa completo: <a href=\"https://www.datascienceacademy.com.br/pages/formacao-inteligencia-artificial\">Formação Inteligência Artificial</a>."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Fim"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Obrigado - Data Science Academy - <a href=\"http://facebook.com/dsacademybr\">facebook.com/dsacademybr</a>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
