Classificação de imagem do TensorFlow: CNN (rede neural convolucional)

Índice:

Anonim

O que é Rede Neural Convolucional?

A rede neural convolucional, também conhecida como convnets ou CNN, é um método bem conhecido em aplicações de visão computacional. Este tipo de arquitetura é dominante para reconhecer objetos de uma imagem ou vídeo.

Neste tutorial, você aprenderá como construir um convnet e como usar o TensorFlow para resolver o conjunto de dados escrito à mão.

Neste tutorial, você aprenderá

  • Rede Neural Convolucional
  • Arquitetura de uma rede neural convolucional
  • Componentes de Convnets
  • Treine CNN com TensorFlow
  • Etapa 1: fazer upload do conjunto de dados
  • Etapa 2: camada de entrada
  • Etapa 3: camada convolucional
  • Etapa 4: camada de pooling
  • Etapa 5: segunda camada convolucional e camada de pooling
  • Etapa 6: camada densa
  • Etapa 7: Camada Logit

Arquitetura de uma rede neural convolucional

Pense no Facebook há alguns anos: depois que você carregou uma foto em seu perfil, foi solicitado que você adicionasse um nome ao rosto na foto manualmente. Hoje em dia, o Facebook usa convnet para marcar seu amigo na foto automaticamente.

Uma rede neural convolucional não é muito difícil de entender. Uma imagem de entrada é processada durante a fase de convolução e posteriormente atribuída um rótulo.

Uma arquitetura convnet típica pode ser resumida na imagem abaixo. Em primeiro lugar, uma imagem é enviada para a rede; isso é chamado de imagem de entrada. Em seguida, a imagem de entrada passa por um número infinito de etapas; esta é a parte convolucional da rede. Finalmente, a rede neural pode prever o dígito na imagem.

Uma imagem é composta por uma matriz de pixels com altura e largura. Uma imagem em tons de cinza tem apenas um canal, enquanto a imagem colorida tem três canais (cada um para vermelho, verde e azul). Um canal é empilhado um sobre o outro. Neste tutorial, você usará uma imagem em tons de cinza com apenas um canal. Cada pixel tem um valor de 0 a 255 para refletir a intensidade da cor. Por exemplo, um pixel igual a 0 mostrará uma cor branca, enquanto um pixel com um valor próximo a 255 será mais escuro.

Vamos dar uma olhada em uma imagem armazenada no conjunto de dados MNIST. A imagem abaixo mostra como representar a imagem da esquerda em formato de matriz. Observe que, a matriz original foi padronizada para ficar entre 0 e 1. Para cores mais escuras, o valor na matriz é cerca de 0,9, enquanto os pixels brancos têm um valor de 0.

Operação convolucional

O componente mais crítico do modelo é a camada convolucional. Esta parte visa reduzir o tamanho da imagem para cálculos mais rápidos dos pesos e melhorar sua generalização.

Durante a parte convolucional, a rede mantém as características essenciais da imagem e exclui ruídos irrelevantes. Por exemplo, a modelo está aprendendo a reconhecer um elefante em uma imagem com uma montanha ao fundo. Se você usar uma rede neural tradicional, o modelo atribuirá um peso a todos os pixels, incluindo os da montanha, o que não é essencial e pode enganar a rede.

Em vez disso, uma rede neural convolucional usará uma técnica matemática para extrair apenas os pixels mais relevantes. Essa operação matemática é chamada de convolução. Essa técnica permite que a rede aprenda recursos cada vez mais complexos em cada camada. A convolução divide a matriz em pequenos pedaços para aprender a maioria dos elementos essenciais dentro de cada pedaço.

Componentes de Convnets

Existem quatro componentes de um Convnets

  1. Convolução
  2. Não linearidade (ReLU)
  3. Pooling ou subamostragem
  4. Classificação (camada totalmente conectada)
  • Convolução

O objetivo da convolução é extrair localmente as características do objeto na imagem. Isso significa que a rede aprenderá padrões específicos dentro da imagem e será capaz de reconhecê-los em todos os lugares da imagem.

A convolução é uma multiplicação elementar. O conceito é fácil de entender. O computador irá escanear uma parte da imagem, geralmente com uma dimensão de 3x3 e multiplicá-la em um filtro. A saída da multiplicação por elemento é chamada de mapa de características. Esta etapa é repetida até que toda a imagem seja digitalizada. Observe que, após a convolução, o tamanho da imagem é reduzido.

Abaixo, há um URL para ver em ação como funciona a convolução.

Existem vários canais disponíveis. Abaixo, listamos alguns dos canais. Você pode ver que cada filtro tem uma finalidade específica. Observe, na imagem abaixo; o Kernel é sinônimo de filtro.

Fonte

Aritmética por trás da convolução

A fase convolucional aplicará o filtro em uma pequena matriz de pixels dentro da imagem. O filtro se moverá ao longo da imagem de entrada com uma forma geral de 3x3 ou 5x5. Isso significa que a rede deslizará essas janelas por toda a imagem de entrada e calculará a convolução. A imagem abaixo mostra como funciona a convolução. O tamanho do patch é 3x3, e a matriz de saída é o resultado da operação elemento a elemento entre a matriz da imagem e o filtro.

Fonte

Você percebe que a largura e a altura da saída podem ser diferentes da largura e da altura da entrada. Acontece por causa do efeito de borda.

Efeito de borda

A imagem tem um mapa de recursos 5x5 e um filtro 3x3. Há apenas uma janela no centro onde o filtro pode filtrar uma grade 3x3. O mapa de recursos de saída será reduzido em dois blocos ao lado de uma dimensão 3x3.

Para obter a mesma dimensão de saída que a dimensão de entrada, você precisa adicionar preenchimento. O preenchimento consiste em adicionar o número certo de linhas e colunas em cada lado da matriz. Isso permitirá que a convolução se ajuste ao centro de cada bloco de entrada. Na imagem abaixo, a matriz de entrada / saída tem a mesma dimensão 5x5

Quando você define a rede, os recursos convolvidos são controlados por três parâmetros:

  1. Profundidade: define o número de filtros a serem aplicados durante a convolução. No exemplo anterior, você viu uma profundidade de 1, o que significa que apenas um filtro é usado. Na maioria dos casos, há mais de um filtro. A figura abaixo mostra as operações realizadas em uma situação com três filtros

  1. Stride: define o número de "salto do pixel" entre duas fatias. Se a distância for igual a 1, as janelas se moverão com a propagação de um pixel. Se a distância for igual a dois, as janelas saltarão 2 pixels. Se você aumentar a passada, terá mapas de recursos menores.

Exemplo de passo 1

Passo 2 da imagem

  1. Preenchimento de zeros: um preenchimento é uma operação de adição de um número correspondente de linhas e colunas em cada lado dos mapas de recursos de entrada. Nesse caso, a saída tem a mesma dimensão da entrada.
  2. Não linearidade (ReLU)

No final da operação de convolução, a saída está sujeita a uma função de ativação para permitir a não linearidade. A função de ativação usual para convnet é o Relu. Todos os pixels com valor negativo serão substituídos por zero.

  • Operação Max-pooling

Esta etapa é fácil de entender. O objetivo do pool é reduzir a dimensionalidade da imagem de entrada. As etapas são realizadas para reduzir a complexidade computacional da operação. Ao diminuir a dimensionalidade, a rede tem pesos menores para computar, evitando overfitting.

Nesta fase, você precisa definir o tamanho e a passada. Uma maneira padrão de agrupar a imagem de entrada é usar o valor máximo do mapa de características. Olhe para a foto abaixo. O "pooling" selecionará uma submatriz de quatro do mapa de recursos 4x4 e retornará o valor máximo. O agrupamento pega o valor máximo de uma matriz 2x2 e, em seguida, move essa janela em dois pixels. Por exemplo, a primeira submatriz é [3,1,3,2], o agrupamento retornará o máximo, que é 3.

Há outra operação de agrupamento, como a média.

Esta operação reduz agressivamente o tamanho do mapa de características

  • Camadas totalmente conectadas

A última etapa consiste em construir uma rede neural artificial tradicional como você fez no tutorial anterior. Você conecta todos os neurônios da camada anterior à próxima. Você usa uma função de ativação softmax para classificar o número na imagem de entrada.

Recapitular:

A rede neural convolucional compila camadas diferentes antes de fazer uma previsão. Uma rede neural tem:

  • Uma camada convolucional
  • Função de ativação Relu
  • Camada de pooling
  • Camada densamente conectada

As camadas convolucionais aplicam filtros diferentes em uma sub-região da imagem. A função de ativação Relu adiciona não linearidade, e as camadas de agrupamento reduzem a dimensionalidade dos mapas de feições.

Todas essas camadas extraem informações essenciais das imagens. Por fim, o mapa de características é alimentado para uma camada primária totalmente conectada com uma função softmax para fazer uma previsão.

Treine CNN com TensorFlow

Agora que você está familiarizado com o bloco de construção de um convnets, está pronto para construir um com o TensorFlow. Usaremos o conjunto de dados MNIST para classificação de imagens.

A preparação dos dados é a mesma do tutorial anterior. Você pode executar os códigos e pular diretamente para a arquitetura da CNN.

Você seguirá as etapas abaixo:

Etapa 1: fazer upload do conjunto de dados

Etapa 2: camada de entrada

Etapa 3: camada convolucional

Etapa 4: camada de pooling

Etapa 5: segunda camada convolucional e camada de pooling

Etapa 6: camada densa

Etapa 7: Camada Logit

Etapa 1: fazer upload do conjunto de dados

O conjunto de dados MNIST está disponível com o scikit para aprender neste URL. Faça o download e armazene-o em Downloads. Você pode carregá-lo com fetch_mldata ('MNIST original').

Crie um conjunto de treinamento / teste

Você precisa dividir o conjunto de dados com train_test_split

Dimensione os recursos

Finalmente, você pode dimensionar o recurso com MinMaxScaler

import numpy as npimport tensorflow as tffrom sklearn.datasets import fetch_mldata#Change USERNAME by the username of your machine## Windows USERmnist = fetch_mldata('C:\\Users\\USERNAME\\Downloads\\MNIST original')## Mac Usermnist = fetch_mldata('/Users/USERNAME/Downloads/MNIST original')print(mnist.data.shape)print(mnist.target.shape)from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(mnist.data, mnist.target, test_size=0.2, random_state=42)y_train = y_train.astype(int)y_test = y_test.astype(int)batch_size =len(X_train)print(X_train.shape, y_train.shape,y_test.shape )## resclaefrom sklearn.preprocessing import MinMaxScalerscaler = MinMaxScaler()# TrainX_train_scaled = scaler.fit_transform(X_train.astype(np.float64))# testX_test_scaled = scaler.fit_transform(X_test.astype(np.float64))feature_columns = [tf.feature_column.numeric_column('x', shape=X_train_scaled.shape[1:])]X_train_scaled.shape[1:]

Defina a CNN

Uma CNN usa filtros no pixel bruto de uma imagem para aprender a comparação do padrão de detalhes com o padrão global com uma rede neural tradicional. Para construir uma CNN, você precisa definir:

  1. Uma camada convolucional: aplique n número de filtros ao mapa de feições. Após a convolução, você precisa usar uma função de ativação Relu para adicionar não linearidade à rede.
  2. Camada de pooling: A próxima etapa após a convolução é reduzir a resolução do máximo do recurso. O objetivo é reduzir a dimensionalidade do mapa de recursos para evitar overfitting e melhorar a velocidade de computação. O agrupamento máximo é a técnica convencional, que divide os mapas de recursos em sub-regiões (geralmente com um tamanho 2x2) e mantém apenas os valores máximos.
  3. Camadas totalmente conectadas: todos os neurônios das camadas anteriores são conectados às próximas camadas. A CNN classificará o rótulo de acordo com as características das camadas convolucionais e reduzidas com a camada de pooling.

Arquitetura CNN

  • Camada convolucional: Aplica 14 filtros 5x5 (extraindo sub-regiões de 5x5 pixels), com função de ativação ReLU
  • Camada de pooling: executa pooling máximo com um filtro 2x2 e passo de 2 (que especifica que as regiões agrupadas não se sobrepõem)
  • Camada convolucional: Aplica 36 filtros 5x5, com função de ativação ReLU
  • Camada de pool # 2: Novamente, executa o pooling máximo com um filtro 2x2 e passo de 2
  • 1.764 neurônios, com taxa de regularização de abandono de 0,4 (probabilidade de 0,4 de qualquer elemento cair durante o treinamento)
  • Camada Densa (Camada Logits): 10 neurônios, um para cada classe de dígito alvo (0-9).

Existem três módulos importantes para usar para criar uma CNN:

  • conv2d (). Constrói uma camada convolucional bidimensional com o número de filtros, tamanho do kernel do filtro, preenchimento e função de ativação como argumentos.
  • max_pool2d (). Constrói uma camada de pooling bidimensional usando o algoritmo de pooling máximo.
  • denso(). Constrói uma camada densa com as camadas e unidades ocultas

Você definirá uma função para construir a CNN. Vamos ver em detalhes como construir cada bloco de construção antes de agrupar tudo na função.

Etapa 2: camada de entrada

def cnn_model_fn(features, labels, mode):input_layer = tf.reshape(tensor = features["x"],shape =[-1, 28, 28, 1])

Você precisa definir um tensor com a forma dos dados. Para isso, você pode usar o módulo tf.reshape. Neste módulo, você precisa declarar o tensor a ser remodelado e a forma do tensor. O primeiro argumento são os recursos dos dados, que são definidos no argumento da função.

Uma imagem tem altura, largura e canal. O conjunto de dados MNIST é uma imagem monocromática com tamanho 28x28. Definimos o tamanho do lote como -1 no argumento de forma para que tome a forma dos recursos ["x"]. A vantagem é fazer com que os hiperparâmetros do tamanho do lote sejam ajustados. Se o tamanho do lote for definido como 7, o tensor alimentará 5.488 valores (28 * 28 * 7).

Step 3: Convolutional layer
# first Convolutional Layerconv1 = tf.layers.conv2d(inputs=input_layer,filters=14,kernel_size=[5, 5],padding="same",activation=tf.nn.relu)

A primeira camada convolucional possui 14 filtros com um tamanho de kernel de 5x5 com o mesmo preenchimento. O mesmo preenchimento significa que o tensor de saída e o tensor de entrada devem ter a mesma altura e largura. O Tensorflow adicionará zeros às linhas e colunas para garantir o mesmo tamanho.

Você usa a função de ativação Relu. O tamanho da saída será [28, 28, 14].

Etapa 4: camada de pooling

A próxima etapa após a convolução é o cálculo do pool. O cálculo de pooling reduzirá a dimensionalidade dos dados. Você pode usar o módulo max_pool2d com um tamanho de 2x2 e passo de 2. Você usa a camada anterior como entrada. O tamanho da saída será [batch_size, 14, 14, 14]

# first Pooling Layerpool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)

Etapa 5: segunda camada convolucional e camada de pooling

A segunda camada convolucional tem 32 filtros, com um tamanho de saída de [batch_size, 14, 14, 32]. A camada de pooling tem o mesmo tamanho de antes e o formato de saída é [batch_size, 14, 14, 18].

conv2 = tf.layers.conv2d(inputs=pool1,filters=36,kernel_size=[5, 5],padding="same",activation=tf.nn.relu)pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)

Etapa 6: camada densa

Em seguida, você precisa definir a camada totalmente conectada. O mapa de feições deve ser achatado antes de ser conectado à camada densa. Você pode usar a remodelagem do módulo com um tamanho de 7 * 7 * 36.

A camada densa conectará 1764 neurônios. Você adiciona uma função de ativação Relu. Além disso, você adiciona um termo de regularização do abandono com uma taxa de 0,3, o que significa que 30 por cento dos pesos serão definidos como 0. Observe que o abandono ocorre apenas durante a fase de treinamento. A função cnn_model_fn possui um modo de argumento para declarar se o modelo precisa ser treinado ou para avaliar.

pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 36])dense = tf.layers.dense(inputs=pool2_flat, units=7 * 7 * 36, activation=tf.nn.relu)dropout = tf.layers.dropout(inputs=dense, rate=0.3, training=mode == tf.estimator.ModeKeys.TRAIN)

Etapa 7: Camada Logit

Finalmente, você pode definir a última camada com a previsão do modelo. A forma de saída é igual ao tamanho do lote e 10, o número total de imagens.

# Logits Layerlogits = tf.layers.dense(inputs=dropout, units=10) 

Você pode criar um dicionário contendo as classes e a probabilidade de cada classe. O módulo tf.argmax () com retorna o valor mais alto se as camadas logit. A função softmax retorna a probabilidade de cada classe.

predictions = {# Generate predictions"classes": tf.argmax(input=logits, axis=1),"probabilities": tf.nn.softmax(logits, name="softmax_tensor") }

Você só deseja retornar a previsão de dicionário quando o modo estiver definido como previsão. Você adiciona estes códigos para exibir as previsões

if mode == tf.estimator.ModeKeys.PREDICT:return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)

A próxima etapa consiste em calcular a perda do modelo. No último tutorial, você aprendeu que a função de perda para um modelo multiclasse é a entropia cruzada. A perda é facilmente calculada com o seguinte código:

# Calculate Loss (for both TRAIN and EVAL modes)loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)

A etapa final é otimizar o modelo, ou seja, encontrar os melhores valores dos pesos. Para isso, você usa um otimizador de descida gradiente com uma taxa de aprendizado de 0,001. O objetivo é minimizar a perda

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)train_op = optimizer.minimize(loss=loss,global_step=tf.train.get_global_step())

Você terminou com a CNN. No entanto, você deseja exibir as métricas de desempenho durante o modo de avaliação. A métrica de desempenho para um modelo multiclasse é a métrica de precisão. O Tensorflow é equipado com um módulo de precisão com dois argumentos, os rótulos e os valores previstos.

eval_metric_ops = {"accuracy": tf.metrics.accuracy(labels=labels, predictions=predictions["classes"])}return tf.estimator.EstimatorSpec(mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)

É isso. Você criou sua primeira CNN e está pronto para agrupar tudo em uma função para usá-la para treinar e avaliar o modelo.

def cnn_model_fn(features, labels, mode):"""Model function for CNN."""# Input Layerinput_layer = tf.reshape(features["x"], [-1, 28, 28, 1])# Convolutional Layerconv1 = tf.layers.conv2d(inputs=input_layer,filters=32,kernel_size=[5, 5],padding="same",activation=tf.nn.relu)# Pooling Layerpool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)# Convolutional Layer #2 and Pooling Layerconv2 = tf.layers.conv2d(inputs=pool1,filters=36,kernel_size=[5, 5],padding="same",activation=tf.nn.relu)pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)# Dense Layerpool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 36])dense = tf.layers.dense(inputs=pool2_flat, units=7 * 7 * 36, activation=tf.nn.relu)dropout = tf.layers.dropout(inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN)# Logits Layerlogits = tf.layers.dense(inputs=dropout, units=10)predictions = {# Generate predictions (for PREDICT and EVAL mode)"classes": tf.argmax(input=logits, axis=1),"probabilities": tf.nn.softmax(logits, name="softmax_tensor")}if mode == tf.estimator.ModeKeys.PREDICT:return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)# Calculate Lossloss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)# Configure the Training Op (for TRAIN mode)if mode == tf.estimator.ModeKeys.TRAIN:optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)train_op = optimizer.minimize(loss=loss,global_step=tf.train.get_global_step())return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op)# Add evaluation metrics Evaluation modeeval_metric_ops = {"accuracy": tf.metrics.accuracy(labels=labels, predictions=predictions["classes"])}return tf.estimator.EstimatorSpec(mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)

As etapas abaixo são iguais aos tutoriais anteriores.

Em primeiro lugar, você define um estimador com o modelo CNN.

# Create the Estimatormnist_classifier = tf.estimator.Estimator(model_fn=cnn_model_fn, model_dir="train/mnist_convnet_model")

Um CNN leva muitas vezes para treinar, portanto, você cria um gancho Logging para armazenar os valores das camadas softmax a cada 50 iterações.

# Set up logging for predictionstensors_to_log = {"probabilities": "softmax_tensor"}logging_hook = tf.train.LoggingTensorHook(tensors=tensors_to_log, every_n_iter=50)

Você está pronto para estimar o modelo. Você define um tamanho de lote de 100 e embaralha os dados. Observe que definimos etapas de treinamento de 16.000, pode levar muito tempo para treinar. Ser paciente.

# Train the modeltrain_input_fn = tf.estimator.inputs.numpy_input_fn(x={"x": X_train_scaled},y=y_train,batch_size=100,num_epochs=None,shuffle=True)mnist_classifier.train(input_fn=train_input_fn,steps=16000,hooks=[logging_hook])

Agora que o modelo está pronto, você pode avaliá-lo e imprimir os resultados

# Evaluate the model and print resultseval_input_fn = tf.estimator.inputs.numpy_input_fn(x={"x": X_test_scaled},y=y_test,num_epochs=1,shuffle=False)eval_results = mnist_classifier.evaluate(input_fn=eval_input_fn)print(eval_results)
INFO:tensorflow:Calling model_fn.INFO:tensorflow:Done calling model_fn.INFO:tensorflow:Starting evaluation at 2018-08-05-12:52:41INFO:tensorflow:Graph was finalized.INFO:tensorflow:Restoring parameters from train/mnist_convnet_model/model.ckpt-15652INFO:tensorflow:Running local_init_op.INFO:tensorflow:Done running local_init_op.INFO:tensorflow:Finished evaluation at 2018-08-05-12:52:56INFO:tensorflow:Saving dict for global step 15652: accuracy = 0.9589286, global_step = 15652, loss = 0.13894269{'accuracy': 0.9689286, 'loss': 0.13894269, 'global_step': 15652}

Com a arquitetura atual, você obtém uma precisão de 97%. Você pode alterar a arquitetura, o tamanho do lote e o número de iterações para melhorar a precisão. A rede neural CNN teve um desempenho muito melhor do que a RNA ou a regressão logística. No tutorial sobre rede neural artificial, você obteve uma precisão de 96%, que é menor do que o CNN. Os desempenhos da CNN são impressionantes com um conjunto de imagens maior , tanto em termos de computação de velocidade quanto de precisão.

Resumo

Uma rede neural convolucional funciona muito bem para avaliar a imagem. Este tipo de arquitetura é dominante para reconhecer objetos de uma imagem ou vídeo.

Para construir uma CNN, você precisa seguir seis etapas:

Etapa 1: camada de entrada:

Esta etapa remodela os dados. A forma é igual à raiz quadrada do número de pixels. Por exemplo, se uma imagem tem 156 pixels, a forma é 26x26. Você precisa especificar se a imagem tem cor ou não. Se sim, então você tinha 3 para a forma- 3 para RGB-, caso contrário, 1.

input_layer = tf.reshape(tensor = features["x"],shape =[-1, 28, 28, 1]) 

Etapa 2: camada convolucional

Em seguida, você precisa criar as camadas convolucionais. Você aplica filtros diferentes para permitir que a rede aprenda recursos importantes. Você especifica o tamanho do kernel e a quantidade de filtros.

conv1 = tf.layers.conv2d(inputs=input_layer,filters=14,kernel_size=[5, 5],padding="same",activation=tf.nn.relu)

Etapa 3: camada de pooling

Na terceira etapa, você adiciona uma camada de pool. Esta camada diminui o tamanho da entrada. Ele faz isso tomando o valor máximo da submatriz a. Por exemplo, se a submatriz for [3,1,3,2], o agrupamento retornará o máximo, que é 3.

pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2) 

Etapa 4: adicionar camada convolucional e camada de pooling

Nesta etapa, você pode adicionar o quanto quiser, camadas conv e camadas de pool. O Google usa arquitetura com mais de 20 camadas conv.

Etapa 5: camada densa

O passo 5 aplainar o anterior para criar camadas totalmente conectadas. Nesta etapa, você pode usar uma função de ativação diferente e adicionar um efeito de dropout.

pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 36])dense = tf.layers.dense(inputs=pool2_flat, units=7 * 7 * 36, activation=tf.nn.relu)dropout = tf.layers.dropout(inputs=dense, rate=0.3, training=mode == tf.estimator.ModeKeys.TRAIN)

Etapa 6: Camada Logit

A etapa final é a previsão.

logits = tf.layers.dense(inputs=dropout, units=10)