Criar redes neurais convolucionais (CNNs) para aprimorar a visão computacional

1. Antes de começar

Neste codelab, você aprenderá a usar CNNs para melhorar seus modelos de classificação de imagens.

Pré-requisitos

Este codelab baseia-se no trabalho concluído em duas parcelas anteriores, Criar um modelo de visão computacional, em que introduzimos parte do código que será usado aqui, e o codelab Criar convoluções e executar o pool, onde apresentamos as convoluções e o pool.

O que você aprenderá

  • Como melhorar a visão e a acurácia do computador com convoluções

O que você vai criar

  • Camadas para melhorar sua rede neural

O que é necessário

O código do restante do codelab está sendo executado no Colab.

Você também precisará do TensorFlow instalado e das bibliotecas instaladas no codelab anterior.

2. Melhorar a precisão da visão computacional com convoluções

Agora você sabe fazer reconhecimento de imagens de moda usando uma rede neural profunda (DNN, na sigla em inglês) com três camadas: a camada de entrada (na forma dos dados de entrada), a camada de saída (na forma da saída desejada) e uma camada oculta. Você testou vários parâmetros que influenciam a precisão final, como tamanhos diferentes de camadas ocultas e o número de períodos de treinamento.

Por conveniência, aqui está todo o código novamente. Execute-o e anote a precisão do teste exibida no final.

import tensorflow as tf
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images/255.0
test_images=test_images/255.0
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5)
test_loss, test_accuracy = model.evaluate(test_images, test_labels)
print ('Test loss: {}, Test accuracy: {}'.format(test_loss, test_accuracy*100))

Sua precisão é, aproximadamente, 89% no treinamento e 87% na validação. Você pode tornar isso ainda melhor usando convoluções, que restringem o conteúdo da imagem para se concentrar em detalhes específicos e distintos.

Se você já fez o processamento de imagem usando um filtro, as convoluções parecerão muito familiares.

Em resumo, você transmite uma matriz (geralmente 3 x 3 ou 5 x 5) para a imagem. Ao alterar os pixels subjacentes com base na fórmula dentro da matriz em questão, é possível realizar operações como a detecção de borda. Por exemplo, normalmente um 3 x 3 é definido para detecção de borda em que a célula do meio é 8, e todos os vizinhos são -1. Nesse caso, para cada pixel, é necessário multiplicar o valor por 8 e depois subtrair o valor de cada vizinho. Faça isso para cada pixel e você terá uma nova imagem com bordas melhoradas.

Isso é perfeito para visão computacional, porque aprimorar recursos como as bordas ajuda o computador a distinguir um item de outro. Melhor ainda, a quantidade de informações necessárias é muito menor, porque você treinará somente nos recursos destacados.

Esse é o conceito de redes neurais convolucionais. Adicione algumas camadas para convoluir antes que haja camadas densas. Depois, as informações enviadas a elas ficarão mais focadas e possivelmente mais precisas.

3. Teste o código

Execute o código a seguir. É a mesma rede neural que antes, mas, desta vez, as camadas convolucionais foram adicionadas primeiro. Esse processo levará mais tempo, mas observe o impacto na precisão:

import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images.reshape(60000, 28, 28, 1)
training_images=training_images / 255.0
test_images = test_images.reshape(10000, 28, 28, 1)
test_images=test_images / 255.0
model = tf.keras.models.Sequential([
  tf.keras.layers.Conv2D(64, (3, 3), activation='relu', input_shape=(28, 28, 1)),
  tf.keras.layers.MaxPooling2D(2, 2),
  tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
  tf.keras.layers.MaxPooling2D(2,2),
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.summary()
model.fit(training_images, training_labels, epochs=5)
test_loss, test_accuracy = model.evaluate(test_images, test_labels)
print ('Test loss: {}, Test accuracy: {}'.format(test_loss, test_accuracy*100))

É provável que tenha aumentado 93% nos dados de treinamento e 91% nos dados de validação.

Agora, execute-o por mais períodos, por exemplo, 20, e analise os resultados. Os resultados do treinamento podem parecer muito bons, mas os de validação podem falhar devido a um fenômeno chamado overfitting (link em inglês).

O overfitting ocorre quando a rede aprende muito bem os dados do conjunto de treinamento. Por isso, ela é especializada para reconhecer somente esses dados e, como resultado, é menos eficaz para ver outros dados em situações mais gerais. Por exemplo, se você treinou apenas calcanhar, a rede pode ser muito boa em identificar saltos, mas os tênis podem confundir.

Veja o código novamente e confira o passo a passo para criar as convoluções.

4. Coletar os dados

A primeira etapa é coletar os dados.

Você perceberá uma mudança aqui e os dados de treinamento precisarão ser remodelados. Isso ocorre porque a primeira convolução espera um único tensor contendo tudo. Portanto, em vez de 60.000 itens de 28 x 28 x 1 em uma lista, você tem uma única lista 4D de 60.000 x 28 x 28 x 1 e a mesma para as imagens de teste. Se você não fizer isso, receberá um erro ao treinar porque as convoluções não reconhecem a forma.

import tensorflow as tf
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images.reshape(60000, 28, 28, 1)
training_images = training_images/255.0
test_images = test_images.reshape(10000, 28, 28, 1)
test_images = test_images/255.0

5. Definir o modelo

Em seguida, defina o modelo. Em vez da camada de entrada na parte superior, você adicionará uma camada convolucional. Os parâmetros são:

  • O número de convoluções que você quer gerar. Um valor como 32 é um bom ponto de partida.
  • É o tamanho da matriz convolucional, neste caso uma grade 3 x 3.
  • A função de ativação a ser usada. Neste caso, use relu.
  • Na primeira camada, a forma dos dados de entrada.

Você seguirá a convolução com uma camada máxima de pooling, que é projetada para comprimir a imagem enquanto mantém o conteúdo dos recursos que foram destacados pela convolução. Ao especificar (2,2) o pool máximo, o efeito é reduzir o tamanho da imagem em um fator de 4. Ele cria uma matriz de 2 x 2 pixels e escolhe o maior valor de pixel, transformando 4 pixels em 1. Isso repete a computação pela imagem e, assim, reduz pela metade o número de pixels horizontais.

Você pode chamar model.summary() para ver o tamanho e o formato da rede. Depois de cada camada de pool máxima, o tamanho da imagem é reduzido da seguinte maneira:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_2 (Conv2D)            (None, 26, 26, 64)        640       
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 13, 13, 64)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 11, 11, 64)        36928     
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 5, 5, 64)          0         
_________________________________________________________________
flatten_2 (Flatten)          (None, 1600)              0         
_________________________________________________________________
dense_4 (Dense)              (None, 128)               204928    
_________________________________________________________________
dense_5 (Dense)              (None, 10)                1290      
=================================================================

Veja o código completo da CNN:

model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D(2, 2),
#Add another convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
#Now flatten the output. After this you'll just have the same DNN structure as the non convolutional version
tf.keras.layers.Flatten(),
#The same 128 dense layers, and 10 output layers as in the pre-convolution example:
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])

6. Compile e treine o modelo

Compile o modelo, chame o método fit para fazer o treinamento e avalie a perda e a acurácia do conjunto de teste.

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5)
test_loss, test_acc = model.evaluate(test_images, test_labels)
print ('Test loss: {}, Test accuracy: {}'.format(test_loss, test_acc*100))

7. Visualizar as convoluções e os pools

Esse código mostra as convoluções graficamente. O print (test_labels[:100]) mostra os primeiros 100 rótulos no conjunto de teste, e é possível ver que aqueles no índice 0, 23 e 28 têm o mesmo valor (9). Todos são calçados. Observe o resultado da execução da convolução em cada um para começar a ver os recursos comuns entre eles. Agora, quando a DNN está treinando com esses dados, ela está trabalhando com muito menos informações e pode estar encontrando a comum entre os sapatos com base nessa combinação de convolução e pool.

print(test_labels[:100])
[9 2 1 1 6 1 4 6 5 7 4 5 7 3 4 1 2 4 8 0 2 5 7 9 1 4 6 0 9 3 8 8 3 3 8 0 7
 5 7 9 6 1 3 7 6 7 2 1 2 2 4 4 5 8 2 2 8 4 8 0 7 7 8 5 1 1 2 3 9 8 7 0 2 6
 2 3 1 2 8 4 1 8 5 9 5 0 3 2 0 6 5 3 6 7 1 8 0 1 4 2]

Agora você pode selecionar algumas das imagens correspondentes para esses rótulos e renderizar como elas serão exibidas pelas convoluções. Portanto, no código a seguir, FIRST_IMAGE, SECOND_IMAGE e THIRD_IMAGE são todos os índices do valor 9, uma inicialização do tornozelo.

import matplotlib.pyplot as plt
f, axarr = plt.subplots(3,4)
FIRST_IMAGE=0
SECOND_IMAGE=23
THIRD_IMAGE=28
CONVOLUTION_NUMBER = 6
from tensorflow.keras import models
layer_outputs = [layer.output for layer in model.layers]
activation_model = tf.keras.models.Model(inputs = model.input, outputs = layer_outputs)
for x in range(0,4):
  f1 = activation_model.predict(test_images[FIRST_IMAGE].reshape(1, 28, 28, 1))[x]
  axarr[0,x].imshow(f1[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
  axarr[0,x].grid(False)
  f2 = activation_model.predict(test_images[SECOND_IMAGE].reshape(1, 28, 28, 1))[x]
  axarr[1,x].imshow(f2[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
  axarr[1,x].grid(False)
  f3 = activation_model.predict(test_images[THIRD_IMAGE].reshape(1, 28, 28, 1))[x]
  axarr[2,x].imshow(f3[0, : , :, CONVOLUTION_NUMBER], cmap='inferno')
  axarr[2,x].grid(False)

Você verá algo parecido com o exemplo a seguir, em que a convolução está assumindo a essência da sola do sapato, identificando-a efetivamente como uma característica comum entre todos os sapatos.

6c9109bcc640a1ec.png

8. Exercícios

Exercício 1

Tente editar as convoluções. Mude o número de convoluções de 32 para 16 ou 64. Qual é o impacto disso na precisão e no tempo de treinamento?

Exercício 2

Remova a convolução final. Qual é o impacto disso na precisão ou no tempo de treinamento?

Exercício 3

Adicionar mais convoluções. Qual é o impacto disso?

Exercício 4

Remova todas as convoluções, exceto a primeira. Qual é o impacto disso? Faça testes.

9. Parabéns

Você criou sua primeira CNN. Para saber como aprimorar ainda mais seus modelos de visão computacional, consulte Usar redes neurais convolucionais (CNNs) com imagens complexas.