Criar um modelo de visão computacional com o TensorFlow

1. Antes de começar

Neste codelab, você criará um modelo de visão computacional que reconhece itens de vestuário com o TensorFlow.

Pré-requisitos

  • Conhecimento completo de Python
  • Habilidades básicas de programação

O que você aprenderá

Neste codelab, você aprenderá a:

  • Treinar uma rede neural para reconhecer artigos de vestuário
  • Conclua uma série de exercícios para orientar você na experimentação com diferentes camadas da rede

O que você vai criar

  • Uma rede neural que identifica artigos de vestuário

O que é necessário

Se você nunca criou uma rede neural para visão computacional com o TensorFlow, use o Colaboratory, um ambiente baseado em navegador que contém todas as dependências necessárias. O código do restante do codelab está sendo executado no Colab.

Caso contrário, a linguagem principal que você usará para treinar modelos é o Python. Por isso, você precisará instalá-la. Além disso, você também precisará do TensorFlow e da biblioteca NumPy. Saiba mais sobre o TensorFlow e instale-o aqui. Instale o NumPy aqui.

2. Começar a programar

Primeiro, consulte o notebook executável do Colab.

Comece importando o TensorFlow.

import tensorflow as tf
print(tf.__version__)

Você treinará uma rede neural para reconhecer itens de vestuário de um conjunto de dados comum chamado Fashion MNIST. Ela tem 70 mil itens em 10 categorias diferentes. Cada item de vestuário está em uma imagem de escala de cinza 28 x 28. Veja alguns exemplos aqui:

cab89ecf27462a95.png

Os rótulos associados ao conjunto de dados são:

Rótulo

Descrição

0

Camiseta/parte superior

1

Calça

2

Pulôver

3

Vestido

4

Casaco

5

Sandálias

6

Camisa

7

Tênis

8

Bag

9

Tornozelo

Os dados do Fashion MNIST estão disponíveis na API tf.keras.datasets. Carregue da seguinte forma:

mnist = tf.keras.datasets.fashion_mnist

Chamar load_data nesse objeto fornece dois conjuntos de duas listas: valores de treinamento e testes, que representam gráficos que mostram itens de vestuário e os rótulos deles.

(training_images, training_labels), (test_images, test_labels) = mnist.load_data()

Como são esses valores? Exiba uma imagem e um rótulo de treinamento para ver. Você pode testar índices diferentes na matriz.

import matplotlib.pyplot as plt
plt.imshow(training_images[0])
print(training_labels[0])
print(training_images[0])

A impressão dos dados do item 0 tem esta aparência:

2da84dc57109b11a.png

Você perceberá que todos os valores são números inteiros entre 0 e 255. Ao treinar uma rede neural, é mais fácil tratar todos os valores entre 0 e 1, um processo chamado de normalização. Felizmente, o Python oferece uma maneira fácil de normalizar uma lista como essa sem gerar repetições.

training_images  = training_images / 255.0
test_images = test_images / 255.0

Procure também a 42, uma inicialização diferente da inicial do índice 0.

Você deve estar se perguntando por que existem dois conjuntos de dados: treinamento e teste.

A ideia é ter um conjunto de dados para treinamento e outro que o modelo ainda não tenha encontrado para ver se consegue classificar bem os valores. Afinal, quando terminar, você vai querer usar o modelo com dados que ele não tinha visto antes! Além disso, sem dados de teste separados, você corre o risco de a rede memorizar apenas os dados de treinamento sem generalizar o conhecimento.

3. Projetar o modelo

Agora, crie o modelo. Você terá três camadas. Analise cada uma delas e explore os diferentes tipos de camadas e parâmetros usados em cada uma.

model = tf.keras.models.Sequential([tf.keras.layers.Flatten(), 
                                    tf.keras.layers.Dense(128, activation=tf.nn.relu), 
                                    tf.keras.layers.Dense(10, activation=tf.nn.softmax)])
  • Sequential define uma sequência de camadas na rede neural.
  • Flatten transforma um quadrado em um vetor unidimensional.
  • Dense adiciona uma camada de neurônios.
  • As funções Activation informam a cada camada de neurônios o que fazer. Existem muitas opções, mas use estas por enquanto:
  • Relu significa que, se X for maior que 0, o retorno será X. Caso contrário, retornará 0. Ela transmite apenas valores de 0 ou mais para a próxima camada na rede.
  • Softmax usa um conjunto de valores e escolhe o maior. Por exemplo, se o resultado da última camada for [0,1, 0,1, 0,05, 0,1, 9,5, 0,1, 0,05, 0,05, 0,05], ele evitará ter que classificar para o maior valor: ele retorna [0,0,0,0,1,0,0,0,0].

4. Compile e treine o modelo

Agora que o modelo está definido, a próxima etapa é criá-lo. Crie um modelo compilando-o primeiro com as funções optimizer e loss. Depois, treine-o nos rótulos e dados de treinamento. O objetivo é que o modelo descubra a relação entre os dados de treinamento e os rótulos de treinamento. Mais tarde, convém que o modelo veja dados semelhantes aos dados de treinamento e faça uma previsão sobre como eles serão.

Observe o uso de metrics= como um parâmetro, o que permite ao TensorFlow informar a precisão do treinamento comparando os resultados previstos com as respostas conhecidas (os rótulos).

model.compile(optimizer = tf.keras.optimizers.Adam(),
              loss = 'sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(training_images, training_labels, epochs=5)

Quando model.fit for executado, você verá perda e precisão:

Epoch 1/5
60000/60000 [=======] - 6s 101us/sample - loss: 0.4964 - acc: 0.8247
Epoch 2/5
60000/60000 [=======] - 5s 86us/sample - loss: 0.3720 - acc: 0.8656
Epoch 3/5
60000/60000 [=======] - 5s 85us/sample - loss: 0.3335 - acc: 0.8780
Epoch 4/5
60000/60000 [=======] - 6s 103us/sample - loss: 0.3134 - acc: 0.8844
Epoch 5/5
60000/60000 [=======] - 6s 94us/sample - loss: 0.2931 - acc: 0.8926

Quando o treinamento do modelo for concluído, você verá um valor de precisão no final da época final. O código pode ser algo como 0,8926, como acima. Isso indica que a rede neural tem uma classificação de 89% precisa ao classificar os dados de treinamento. Em outras palavras, ele descobriu uma correspondência de padrão entre a imagem e os rótulos que funcionavam 89% do tempo. Não era muito bom, mas não era ruim. Ele foi treinado apenas em cinco eras e concluído rapidamente.

5. Testar o modelo

Qual seria o desempenho do modelo com os dados que não viu? É por isso que você tem o conjunto de teste. Você chama model.evaluate e transmite os dois conjuntos, e ele informa a perda de cada um. Faça um teste:

model.evaluate(test_images, test_labels)

E esta é a saída:

10000/10000 [=====] - 1s 56us/sample - loss: 0.3365 - acc: 0.8789
[0.33648381242752073, 0.8789]

Esse exemplo retornou uma precisão de 0,8789, o que significa que ela era aproximadamente 88% precisa. Os valores podem ser um pouco diferentes.

Como esperado, os dados do modelo não são tão precisos quanto os dados treinados. Saiba mais sobre o TensorFlow para saber como melhorar isso.

Para ver mais detalhes, faça os exercícios na próxima etapa.

6. Exercícios de exploração

Exercício 1

Para este primeiro exercício, execute o seguinte código:

classifications = model.predict(test_images)
print(classifications[0])

Ela cria um conjunto de classificações para cada uma das imagens de teste e exibe a primeira entrada nas classificações. A saída após a execução é uma lista de números. Por que você acha que isso é e o que esses números representam?

Tente executar print(test_labels[0]) para receber um 9. Isso ajuda você a entender a aparência da lista?

A saída do modelo é uma lista de 10 números. Esses números são uma probabilidade de que o valor classificado seja o rótulo correspondente. Por exemplo, o primeiro valor na lista é a probabilidade de que a roupa seja da classe 0 e a próxima seja um 1. Observe que todas são probabilidades muito baixas, exceto uma. Além disso, devido ao Softmax, todas as probabilidades da lista totalizam 1,0.

A lista e os rótulos são 0, portanto, a inicialização do tornozelo que contém o rótulo 9 significa que ele é o 10o das 10 classes. A lista com o 10o elemento sendo o valor mais alto significa que a rede neural previu que o item que está classificando é provavelmente uma inicialização do tornozelo.

Exercício 2

Veja as camadas no seu modelo. Teste diferentes valores na camada densa com 512 neurônios.

Quais resultados diferentes você recebe em termos de perda e tempo de treinamento? Por que você acha que esse é o caso?

Por exemplo, se você aumentar para 1.024 neurônios, terá que fazer mais cálculos, deixando o processo mais lento. No entanto, nesse caso, eles causam um bom impacto porque o modelo é mais preciso. Isso não significa que mais é sempre melhor. Você pode atingir a lei de diminuir devoluções muito rapidamente.

Exercício 3

O que aconteceria se você removesse a camada Flatten(). Por que você acha que esse é o caso?

Você receberá um erro sobre o formato dos dados. Os detalhes do erro podem parecer vagos no momento, mas reforçam a regra geral de que a primeira camada na sua rede deve ter o mesmo formato dos dados. Atualmente, seus dados são imagens de 28 x 28, e 28 camadas de 28 neurônios seriam inviáveis, portanto, faz mais sentido separar essas 28,28 em 784 x 1.

Em vez de escrever todo o código, adicione a camada Flatten() no início. Depois que as matrizes forem carregadas no modelo, elas serão separadas automaticamente.

Exercício 4

Considere as camadas finais (saída). Por que existem 10 delas? O que aconteceria se você tivesse um valor diferente de 10?

Tente treinar a rede com 5. Você receberá um erro assim que encontrar um valor inesperado. Outra regra geral: o número de neurônios na última camada precisa corresponder ao número de classes que você está classificando. Nesse caso, são os dígitos de 0 a 9, então há 10 deles, portanto, você precisa ter 10 neurônios na camada final.

Exercício 5

Considerar os efeitos de camadas adicionais na rede. O que acontecerá se você adicionar outra camada entre a que tem o 512 e a camada final com 10?

Não há um impacto significativo, porque são dados relativamente simples. Para dados muito mais complexos, as camadas extras costumam ser necessárias.

Exercício 6

Antes do treinamento, você normalizou os dados, indo de valores de 0 a 255 para valores que eram de 0 a 1. Qual seria o impacto de removê-la? Este é o código completo para ser testado. As duas linhas que normalizam os dados são comentadas.

Por que você acha que gera resultados diferentes? Há uma ótima resposta neste link do Stack Overflow.

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/255.0
#test_images=test_images/255.0
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
model.fit(training_images, training_labels, epochs=5)
model.evaluate(test_images, test_labels)
classifications = model.predict(test_images)
print(classifications[0])
print(test_labels[0])

7. Explorar callbacks

Antes, quando você treinava por eras extras, você tinha um problema em que sua perda poderia mudar. Pode levar um tempo para esperar o treinamento fazer isso e você pode ter pensado que seria bom parar o treinamento quando alcançasse o valor desejado, como 95% de precisão. Se você chega a isso após três períodos, por que esperar para que ele termine muito mais períodos?

Como em qualquer outro programa, você tem callbacks. Veja na prática:

import tensorflow as tf

class myCallback(tf.keras.callbacks.Callback):
  def on_epoch_end(self, epoch, logs={}):
    if(logs.get('accuracy')>0.95):
      print("\nReached 95% accuracy so cancelling training!")
      self.model.stop_training = True

callbacks = myCallback()
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(512, activation=tf.nn.relu),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5, callbacks=[callbacks])

8. Parabéns

Você criou seu primeiro modelo de visão computacional! Para saber como melhorar os modelos de visão computacional, consulte Como criar convoluções e pooling.