Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/pt-br/tutorials/images/classification.ipynb
25118 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

Classificação de imagens

Este tutorial mostra como classificar imagens de flores usando um modelo tf.keras.Sequential e carregar dados usando tf.keras.utils.image_dataset_from_directory. São demonstrados os seguintes conceitos:

  • Carregamento de um dataset fora do disco de forma eficiente.

  • Identificação de overfitting e aplicação de técnicas para mitigá-lo, incluindo ampliação de dados e dropout.

Este tutorial segue um workflow básico de aprendizado de máquina:

  1. Analisar e entender os dados

  2. Criar um pipeline de entrada

  3. Criar o modelo

  4. Treinar o modelo

  5. Testar o modelo

  6. Melhorar o modelo e repetir o processo

Além disso, o notebook demonstra como converter um modelo salvo em um modelo do TensorFlow Lite para aprendizado de máquina em dispositivos móveis, embarcados e IoT.

Configuração

Importe o TensorFlow e outras bibliotecas necessárias:

import matplotlib.pyplot as plt import numpy as np import PIL import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers from tensorflow.keras.models import Sequential

Baixar e explorar o dataset

Este tutorial usa um dataset com cerca de 3.700 fotos de flores. O dataset contém cinco subdiretórios, um por classe:

flower_photo/ daisy/ dandelion/ roses/ sunflowers/ tulips/
import pathlib dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz" data_dir = tf.keras.utils.get_file('flower_photos.tar', origin=dataset_url, extract=True) data_dir = pathlib.Path(data_dir).with_suffix('')

Após baixá-lo, você terá uma cópia do dataset disponível. Há 3.670 imagens no total:

image_count = len(list(data_dir.glob('*/*.jpg'))) print(image_count)

Veja algumas rosas:

roses = list(data_dir.glob('roses/*')) PIL.Image.open(str(roses[0]))
PIL.Image.open(str(roses[1]))

E algumas tulipas

tulips = list(data_dir.glob('tulips/*')) PIL.Image.open(str(tulips[0]))
PIL.Image.open(str(tulips[1]))

Carregar os dados usando um utilitário do Keras

Agora, carregue essas imagens fora do disco, utilizando o utilitário conveniente tf.keras.utils.image_dataset_from_directory. Isso levará o diretório de flores do disco para um tf.data.Dataset com apenas algumas linhas de código. Se você quiser, também pode escrever seu próprio código de carregamento de dados do zero – confira o tutorial Carregar e pré-processar imagens.

Criar um dataset

Defina alguns parâmetros para o loader:

batch_size = 32 img_height = 180 img_width = 180

É recomendável usar uma divisão de validação ao desenvolver seu modelo. Use 80% das imagens para treinamento e 20% para validação.

train_ds = tf.keras.utils.image_dataset_from_directory( data_dir, validation_split=0.2, subset="training", seed=123, image_size=(img_height, img_width), batch_size=batch_size)
val_ds = tf.keras.utils.image_dataset_from_directory( data_dir, validation_split=0.2, subset="validation", seed=123, image_size=(img_height, img_width), batch_size=batch_size)

Os nomes das classes estão disponíveis no atributo class_names desses datasets. Eles correspondem aos nomes dos diretórios, em ordem alfabética.

class_names = train_ds.class_names print(class_names)

Visualizar os dados

Aqui estão as primeiras nove imagens do dataset de treinamento:

import matplotlib.pyplot as plt plt.figure(figsize=(10, 10)) for images, labels in train_ds.take(1): for i in range(9): ax = plt.subplot(3, 3, i + 1) plt.imshow(images[i].numpy().astype("uint8")) plt.title(class_names[labels[i]]) plt.axis("off")

Você passará esses datasets para o método Model.fit do Keras para fazer o treinamento mais adiante neste treinamento. Se você quiser, também pode fazer a iteração do dataset manualmente e recuperar lotes de imagens:

for image_batch, labels_batch in train_ds: print(image_batch.shape) print(labels_batch.shape) break

O image_batch é um tensor de formato (32, 180, 180, 3). É um lote de 32 imagens de formato 180x180x3 (a última dimensão refere-se aos canais de cores RGB). O label_batch é um tensor de formato (32,); são os rótulos correspondentes às 32 imagens.

Você pode chamar .numpy() nos tensores image_batch e labels_batch para convertê-los em um numpy.ndarray.

Configurar o dataset para melhor desempenho

Utilize a pré-busca em buffer para gerar dados a partir do disco sem o bloqueio de I/O. Veja dois métodos importantes que você deve usar ao carregar os dados:

  • Dataset.cache mantém a imagem na memória após o carregamento fora do disco durante a primeira época. Isso garantirá que o dataset não se torne um gargalo ao treinar seu modelo. Se o dataset for muito grande para a memória, você também pode usar esse método para criar um cache no disco com bom desempenho.

  • Dataset.prefetch sobrepõe o pré-processamento de dados e a execução do modelo durante o treinamento.

Os leitores interessados podem saber mais sobre ambos os métodos, além de como armazenar os dados em cache no disco, na seção Pré-busca do guia Melhor desempenho com a API tf.data.

AUTOTUNE = tf.data.AUTOTUNE train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE) val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

Padronizar os dados

Os valores dos canais RGB estão no intervalo [0, 255]. Isso não é ideal para uma rede neural. Em geral, você deve buscar diminuir seus valores de entrada.

Aqui, você padronizará os valores para colocá-los no intervalo [0, 1] usando tf.keras.layers.Rescaling:

normalization_layer = layers.Rescaling(1./255)

Há duas maneiras de usar essa camada. Você pode aplicá-la ao dataset ao chamar Dataset.map:

normalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y)) image_batch, labels_batch = next(iter(normalized_ds)) first_image = image_batch[0] # Notice the pixel values are now in `[0,1]`. print(np.min(first_image), np.max(first_image))

Ou pode incluir a camada dentro da definição do modelo para simplificar a implantação. Use a segunda estratégia aqui.

Observação: você redimensionou imagens anteriormente usando o argumento image_size de tf.keras.utils.image_dataset_from_directory. Se quiser incluir a lógica de redimensionamento no seu modelo também, pode usar a camada tf.keras.layers.Resizing.

Modelo básico do Keras

Criar o modelo

O modelo Sequential consiste em três blocos de convolução (tf.keras.layers.Conv2D) com uma camada de pooling máximo (tf.keras.layers.MaxPooling2D) em cada um. Há uma camada totalmente conectada (tf.keras.layers.Dense) com 128 unidades sobre ela, que é ativada por uma função de ativação ReLU ('relu'). Esse modelo não foi ajustado para alta exatidão — o objetivo deste tutorial é mostrar estratégia padrão.

num_classes = len(class_names) model = Sequential([ layers.Rescaling(1./255, input_shape=(img_height, img_width, 3)), layers.Conv2D(16, 3, padding='same', activation='relu'), layers.MaxPooling2D(), layers.Conv2D(32, 3, padding='same', activation='relu'), layers.MaxPooling2D(), layers.Conv2D(64, 3, padding='same', activation='relu'), layers.MaxPooling2D(), layers.Flatten(), layers.Dense(128, activation='relu'), layers.Dense(num_classes) ])

Compilar o modelo

Neste tutorial, escolha o otimizador tf.keras.optimizers.Adam e a função de perda tf.keras.losses.SparseCategoricalCrossentropy. Para ver a exatidão do treinamento e da validação para cada época de treinamento, passe o argumento metrics para Model.compile.

model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])

Resumo do modelo

Veja todas as camadas da rede usando o método Model.summary do Keras:

model.summary()

Treinar o modelo

Treine o modelo com 10 épocas usando o método Model.fit do Keras:

epochs=10 history = model.fit( train_ds, validation_data=val_ds, epochs=epochs )

Visualizar os resultados do treinamento

Crie gráficos da perda e da exatidão para os conjuntos de treinamento e avaliação:

acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss'] epochs_range = range(epochs) plt.figure(figsize=(8, 8)) plt.subplot(1, 2, 1) plt.plot(epochs_range, acc, label='Training Accuracy') plt.plot(epochs_range, val_acc, label='Validation Accuracy') plt.legend(loc='lower right') plt.title('Training and Validation Accuracy') plt.subplot(1, 2, 2) plt.plot(epochs_range, loss, label='Training Loss') plt.plot(epochs_range, val_loss, label='Validation Loss') plt.legend(loc='upper right') plt.title('Training and Validation Loss') plt.show()

Os gráficos mostram que a exatidão do treinamento e a exatidão da validação estão bem distantes entre si, e o modelo atingiu somente cerca de 60% de exatidão para o conjunto de validação.

As próximas seções do tutorial mostram como avaliar o que deu errado e tentar aumentar o desempenho geral do modelo.

Overfitting

Nos gráficos acima, a exatidão do treinamento fica cada vez mais linear ao longo do tempo, enquanto a exatidão da validação fica empacada em 60% no processo de treinamento. Além disso, a diferença de exatidão entre o treinamento e a validação é perceptível, um sinal de overfitting.

Quando há uma pequena quantidade de exemplos de treinamento, às vezes o modelo aprende com ruídos ou detalhes indesejados dos exemplos de treinamento, ao ponto de impactar negativamente o desempenho do modelo para novos exemplos. Esse fenômeno é conhecido como overfitting e significa que o modelo terá dificuldades de generalizar para um novo dataset.

Existem diversas formas de combater o overfitting no processo de treinamento. Neste tutorial, usaremos a ampliação de dados e adicionaremos dropout ao seu modelo.

Ampliação de dados

Geralmente o overfitting ocorre quando há uma pequena quantidade de exemplos de treinamento. A ampliação de dados usa a estratégia de gerar dados adicionais de treinamento a partir dos exemplos existentes ampliando-os por meio do uso de transformações aleatórias que geram imagens que parecem críveis. Isso ajuda a expor o modelo a mais aspectos dos dados e a generalizar de forma melhor.

Você implementará a ampliação de dados usando as seguintes camadas de pré-processamento do Keras: tf.keras.layers.RandomFlip, tf.keras.layers.RandomRotation e tf.keras.layers.RandomZoom. Elas podem ser incluídas dentro do seu modelo da mesma forma que outras camadas e podem ser executadas na GPU.

data_augmentation = keras.Sequential( [ layers.RandomFlip("horizontal", input_shape=(img_height, img_width, 3)), layers.RandomRotation(0.1), layers.RandomZoom(0.1), ] )

Veja alguns exemplos ampliados por meio da ampliação de dados na mesma imagem diversas vezes:

plt.figure(figsize=(10, 10)) for images, _ in train_ds.take(1): for i in range(9): augmented_images = data_augmentation(images) ax = plt.subplot(3, 3, i + 1) plt.imshow(augmented_images[0].numpy().astype("uint8")) plt.axis("off")

Você adicionará a ampliação de dados ao seu modelo antes do treinamento no próximo passo.

Dropout

Outra técnica para reduzir o overfitting é acrescentar regularização de dropout{:.external} à rede.

Ao aplicar dropout em uma camada, ela descarta aleatoriamente (definindo a ativação como zero) uma quantidade de unidades de saída da camada durante o processo de treinamento. O dropout recebe um número fracionário como valor de entrada, como 0.1, 0.2, 0.4, etc. Isso significa descartar 10%, 20% ou 40%, respectivamente, das unidades de saída da camada aplicada, de forma aleatória.

Crie uma nova rede neural com tf.keras.layers.Dropout antes de treiná-la usando as imagens ampliadas:

model = Sequential([ data_augmentation, layers.Rescaling(1./255), layers.Conv2D(16, 3, padding='same', activation='relu'), layers.MaxPooling2D(), layers.Conv2D(32, 3, padding='same', activation='relu'), layers.MaxPooling2D(), layers.Conv2D(64, 3, padding='same', activation='relu'), layers.MaxPooling2D(), layers.Dropout(0.2), layers.Flatten(), layers.Dense(128, activation='relu'), layers.Dense(num_classes, name="outputs") ])

Compilar e treinar o modelo

model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])
model.summary()
epochs = 15 history = model.fit( train_ds, validation_data=val_ds, epochs=epochs )

Visualizar os resultados do treinamento

Após aplicar a ampliação de dados e o tf.keras.layers.Dropout, há menos overfitting do que antes, e a exatidão do treinamento e da validação fica mais alinhada:

acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss'] epochs_range = range(epochs) plt.figure(figsize=(8, 8)) plt.subplot(1, 2, 1) plt.plot(epochs_range, acc, label='Training Accuracy') plt.plot(epochs_range, val_acc, label='Validation Accuracy') plt.legend(loc='lower right') plt.title('Training and Validation Accuracy') plt.subplot(1, 2, 2) plt.plot(epochs_range, loss, label='Training Loss') plt.plot(epochs_range, val_loss, label='Validation Loss') plt.legend(loc='upper right') plt.title('Training and Validation Loss') plt.show()

Fazer previsões com base em novos dados

Use seu modelo para classificar uma imagem que não estava incluída nos conjuntos de treinamento e validação.

Observação: as camadas de ampliação de dados e de dropout ficam inativas no momento da inferência.

sunflower_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/592px-Red_sunflower.jpg" sunflower_path = tf.keras.utils.get_file('Red_sunflower', origin=sunflower_url) img = tf.keras.utils.load_img( sunflower_path, target_size=(img_height, img_width) ) img_array = tf.keras.utils.img_to_array(img) img_array = tf.expand_dims(img_array, 0) # Create a batch predictions = model.predict(img_array) score = tf.nn.softmax(predictions[0]) print( "This image most likely belongs to {} with a {:.2f} percent confidence." .format(class_names[np.argmax(score)], 100 * np.max(score)) )

Usar o TensorFlow Lite

O TensorFlow Lite é um conjunto de ferramentas que permite aprendizado de máquina em dispositivos, pois ajuda os desenvolvedores e executarem os modelos em dispositivos móveis, embarcados e de borda.

Converter o modelo Sequential do Keras em um modelo do TensorFlow Lite

Para usar o modelo treinado em aplicações em dispositivos, primeiro converta-o em um formato de modelo menor e mais eficiente, chamado de modelo do TensorFlow Lite.

Neste exemplo, pegue o modelo Sequential do Keras treinado e use tf.lite.TFLiteConverter.from_keras_model para gerar um modelo do TensorFlow Lite:

# Convert the model. converter = tf.lite.TFLiteConverter.from_keras_model(model) tflite_model = converter.convert() # Save the model. with open('model.tflite', 'wb') as f: f.write(tflite_model)

O modelo do TensorFlow Lite que você salvou no passo anterior pode conter diversas assinaturas de função. A API de conversão de modelos do Keras usa a assinatura padrão automaticamente. Saiba mais sobre as assinaturas do TensorFlow Lite.

Executar o modelo do TensorFlow Lite

No Python, você pode acessar as assinaturas do modelo do TensorFlow salvo usando a classe tf.lite.Interpreter.

Carregue o modelo com o Interpreter:

TF_MODEL_FILE_PATH = 'model.tflite' # The default path to the saved TensorFlow Lite model interpreter = tf.lite.Interpreter(model_path=TF_MODEL_FILE_PATH)

Exiba as assinaturas do modelo convertido para obter os nomes das entradas (e das saídas):

interpreter.get_signature_list()

Neste exemplo, você tem uma assinatura padrão chamada serving_default. Além disso, o nome das 'inputs' (entradas) é 'sequential_1_input', enquanto as 'outputs' (saídas) são chamadas 'outputs'. Você pode conferir os nomes dessa primeira e última camadas do Keras ao executar Model.summary, conforme demonstrado anteriormente neste tutorial.

Agora, você pode testar o modelo do TensorFlow carregado realizando a inferência em uma imagem de amostra com tf.lite.Interpreter.get_signature_runner, passando o nome da assinatura da seguinte forma:

classify_lite = interpreter.get_signature_runner('serving_default') classify_lite

Similar ao que você fez anteriormente neste tutorial, é possível usar o modelo do TensorFlow Lite para classificar imagens que não estavam incluídas nos testes de treinamento e validação.

Você já transformou essa imagem em um tensor e a salvou como img_array. Agora, passe-a ao primeiro argumento (o nome das 'inputs') do modelo do TensorFlow Lite carregado (predictions_lite), compute ativações softmax e depois exiba a previsão para a classe com a probabilidade mais alta computada.

predictions_lite = classify_lite(sequential_1_input=img_array)['outputs'] score_lite = tf.nn.softmax(predictions_lite)
print( "This image most likely belongs to {} with a {:.2f} percent confidence." .format(class_names[np.argmax(score_lite)], 100 * np.max(score_lite)) )

A previsão gerada pelo modelo do Lite deve ser quase idêntica às previsões geradas pelo modelo original:

print(np.max(np.abs(predictions - predictions_lite)))

Das cinco classes — 'daisy' (margarida), 'dandelion' (dente-de-leão), 'roses' (rosa), 'sunflowers' (girassol) e 'tulips' (tulipa) — o modelo deve prever que a imagem pertence aos girassóis, que é o mesmo resultado de antes da conversão em um modelo do TensorFlow Lite.

Próximos passos

Este tutorial mostrou como treinar um modelo para fazer classificação de imagens, testá-lo, convertê-lo no formato TensorFlow Lite para aplicações em dispositivos (como um aplicativo de classificação de imagens) e realizar inferência com o modelo TensorFlow Lite usando a API do Python.

Saiba mais sobre o TensorFlow Lite consultando os tutoriais e guias.