Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/pt-br/hub/tutorials/tf2_text_classification.ipynb
25118 views
Kernel: Python 3

Licensed under the Apache License, Version 2.0 (the "License");

# Copyright 2019 The TensorFlow Hub Authors. All Rights Reserved. # # 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 # # http://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. # ==============================================================================
#@title MIT License # # Copyright (c) 2017 François Chollet # IGNORE_COPYRIGHT: cleared by OSS licensing # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE.

Classificação de texto com avaliações de filmes

Este notebook classifica avaliações de filmes como positivas ou negativas, com base no texto da avaliação. Este é um exemplo de classificação binária, ou de duas classes, um tipo de problema de aprendizado de máquina importante, com diversas aplicações.

Usaremos o Large Movie Review Dataset, que contém o texto de 50 mil avaliações de filmes do Internet Movie Database. Elas são divididas em 25 mil avaliações para treinamento e 25 mil para teste. Os conjuntos de treinamento e teste são equilibrados, ou seja, contêm a mesma quantidade de avaliações positivas e negativas.

Este notebook usa tf.keras, uma API de alto nível para criar e treinar modelos no TensorFlow, e o TensorFlow Hub, uma biblioteca e plataforma para aprendizado por transferência. Para ver um tutorial de classificação de texto mais avançado usando tf.keras, confira o Guia de Classificação de texto do MLCC.

Outros modelos

Você encontra aqui modelos mais expressivos e com melhor desempenho que podem ser usados para gerar o embedding de texto.

Configuração

import numpy as np import tensorflow as tf import tensorflow_hub as hub import tensorflow_datasets as tfds import matplotlib.pyplot as plt print("Version: ", tf.__version__) print("Eager mode: ", tf.executing_eagerly()) print("Hub version: ", hub.__version__) print("GPU is", "available" if tf.config.list_physical_devices('GPU') else "NOT AVAILABLE")

Baixe o dataset do IMDB

O dataset do IMDB está disponível no TensorFlow Datasets. O seguinte código baixa o dataset do IMDB para sua máquina (ou para o runtime do Colab):

train_data, test_data = tfds.load(name="imdb_reviews", split=["train", "test"], batch_size=-1, as_supervised=True) train_examples, train_labels = tfds.as_numpy(train_data) test_examples, test_labels = tfds.as_numpy(test_data)

Explore os dados

Vamos reservar um momento para compreender o formato dos dados. Cada exemplo é uma frase representando a avaliação do filme e um rótulo correspondente. A frase não é pré-processada de nenhuma forma. O rótulo é um número inteiro igual a 0 ou 1, em que 0 é uma avaliação negativa e 1, uma avaliação positiva.

print("Training entries: {}, test entries: {}".format(len(train_examples), len(test_examples)))

Vamos exibir os primeiros 10 exemplos.

train_examples[:10]

Vamos exibir também os primeiros 10 rótulos.

train_labels[:10]

Crie o modelo

A rede neural é criada empilhando-se camadas, o que requer três decisões de arquitetura principais:

  • Como representar o texto?

  • Quantas camadas usar no modelo?

  • Quantas unidades ocultas usar em cada camada?

Neste exemplo, os dados de entrada são frases. Os rótulos a serem previstos são 0 ou 1.

Uma maneira de representar o texto é converter as frases em vetores de embeddings. Use um embedding de texto pré-treinado como a primeira camada, o que traz duas vantagens:

  • Não precisamos nos preocupar com o pré-processamento do texto.

  • Podemos nos beneficiar do aprendizado por transferência.

Neste exemplo, você usará um modelo do TensorFlow Hub chamado google/nnlm-en-dim50/2.

Existem dois outros modelos a serem testados neste tutorial:

Primeiro, vamos criar uma camada do Keras que use um modelo do TensorFlow Hub para fazer o embedding das frases e testar em alguns exemplos de entrada. O formato da saída dos embeddings gerados esperado é: (num_examples, embedding_dimension).

model = "https://tfhub.dev/google/nnlm-en-dim50/2" hub_layer = hub.KerasLayer(model, input_shape=[], dtype=tf.string, trainable=True) hub_layer(train_examples[:3])

Agora, vamos criar o modelo completo:

model = tf.keras.Sequential() model.add(hub_layer) model.add(tf.keras.layers.Dense(16, activation='relu')) model.add(tf.keras.layers.Dense(1)) model.summary()

As camadas são empilhadas sequencialmente para construir o classificador:

  1. A primeira é uma camada do TensorFlow Hub. Essa camada usa um SavedModel pré-treinado para mapear uma frase em seu vetor de embeddings. O modelo que estamos usando (google/nnlm-en-dim50/2) divide a frase em tokens, faz o embedding de cada token e depois combina o embedding. As dimensões resultantes são: (num_examples, embedding_dimension).

  2. O vetor de saída com tamanho fixo é passado por uma camada (Dense) totalmente conectada com 16 unidades ocultas.

  3. A última camada é densamente conectada com apenas um nó de saída. Isso gera como saída os logits: as log-probabilidades da classe verdadeira, segundo o modelo.

Unidades ocultas

O modelo acima possui duas camadas intermediárias ou "ocultas", entre a entrada e a saída. O número de saídas (unidades, nós ou neurônios) é a dimensão do espaço representacional da camada. Em outras palavras, a quantidade de liberdade permitida à rede ao aprender uma representação interna.

Se um modelo tiver mais unidades ocultas (um espaço de representação de dimensão superior) e/ou mais camadas, a rede poderá aprender representações mais complexas. No entanto, isso deixa a rede mais cara do ponto de vista computacional e pode levar ao aprendizado de padrões indesejados – padrões que melhoram o desempenho para os dados de treinamento, mas não para os dados de teste. Isto é chamado de overfitting, e falaremos mais sobre o tema posteriormente.

Função de perda e otimizador

Um modelo precisa de uma função de perda e um otimizador para o treinamento. Como este é um problema de classificação binária e o modelo gera como saída uma probabilidade (uma camada de unidade única com uma ativação sigmoide), usaremos a função de perda binary_crossentropy.

Essa não é a única opção para a função de perda. Por exemplo, você pode optar por mean_squared_error. Porém, de forma geral, binary_crossentropy lida melhor com probabilidades, pois mede a "distância" entre distribuições de probabilidade ou, no nosso caso, entre a distribuição de verdade fundamental (ground-truth) e as previsões.

Depois, quando lidarmos com problemas de regressão (por exemplo, para prever o preço de uma casa), veremos como usar outra função de perda chamada Erro Quadrático Médio.

Agora, configure o modelo para usar um otimizador e uma função de perda:

model.compile(optimizer='adam', loss=tf.losses.BinaryCrossentropy(from_logits=True), metrics=[tf.metrics.BinaryAccuracy(threshold=0.0, name='accuracy')])

Crie um conjunto de validação

Durante o treinamento, queremos verificar a exatidão do modelo para dados que ele nunca viu. Crie um dataset de validação separando 10 mil exemplos dos dados de treinamento originais. (Por que não usar o dataset de testes agora? Nosso objetivo é desenvolver e ajustar o modelo usando apenas os dados de treinamento e, em seguida, usar os dados de teste apenas uma vez para avaliar a exatidão).

x_val = train_examples[:10000] partial_x_train = train_examples[10000:] y_val = train_labels[:10000] partial_y_train = train_labels[10000:]

Treine o modelo

Treine o modelo com 40 épocas em minilotes com 512 amostras. São feitas 40 iterações em todas as amostras nos tensores x_train e y_train. Durante o treinamento, monitore a perda e a exatidão do modelo para as 10 mil amostras do conjunto de validação:

history = model.fit(partial_x_train, partial_y_train, epochs=40, batch_size=512, validation_data=(x_val, y_val), verbose=1)

Avalie o modelo

Vamos conferir o desempenho do modelo. Serão retornados dois valores: perda (um número que representa o erro; quanto menor, melhor) e exatidão.

results = model.evaluate(test_examples, test_labels) print(results)

Essa estratégia bem simples atinge uma exatidão de cerca de 87%. Com estratégias mais avançadas, a exatidão do modelo deve se aproximar de 95%.

Crie um gráfico de exatidão e perda ao longo do tempo

model.fit() retorna um objeto History que contém um dicionário com tudo o que aconteceu durante o treinamento:

history_dict = history.history history_dict.keys()

Há quatro entradas: uma para cada métrica monitorada durante o treinamento e a validação. Você usará esses valores para plotar a perda do treinamento e da validação para fins comparativos, além da exatidão do treinamento e da validação:

acc = history_dict['accuracy'] val_acc = history_dict['val_accuracy'] loss = history_dict['loss'] val_loss = history_dict['val_loss'] epochs = range(1, len(acc) + 1) # "bo" is for "blue dot" plt.plot(epochs, loss, 'bo', label='Training loss') # b is for "solid blue line" plt.plot(epochs, val_loss, 'b', label='Validation loss') plt.title('Training and validation loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.legend() plt.show()
plt.clf() # clear figure plt.plot(epochs, acc, 'bo', label='Training acc') plt.plot(epochs, val_acc, 'b', label='Validation acc') plt.title('Training and validation accuracy') plt.xlabel('Epochs') plt.ylabel('Accuracy') plt.legend() plt.show()

Neste gráfico, os pontos representam a perda e exatidão do treinamento, enquanto as linhas sólidas representam a perda e exatidão da validação.

Observe que a perda do treinamento diminui a cada época, e a exatidão do treinamento aumenta a cada época. Isso é o esperado ao usar uma otimização do método do gradiente descendente, que deve minimizar a quantidade desejada em cada iteração.

Esse não é o caso para a perda e exatidão de validação, que parecem atingir o pico após 20 épocas. Este é um exemplo de overfitting: o modelo tem desempenho melhor com os dados de treinamento em comparação a dados nunca vistos. Após esse ponto, o modelo sofre uma sobreotimização e aprende representações específicas dos dados de treinamento que não oferecem boas generalizações para os dados de teste.

Para este caso específico, podemos evitar o overfitting simplesmente interrompendo o treinamento após aproximadamente 20 épocas. Mais para a frente, você verá como fazer isso automaticamente com um callback.