Path: blob/master/site/pt-br/hub/tutorials/tf2_text_classification.ipynb
25118 views
Copyright 2019 The TensorFlow Hub Authors.
Licensed under the Apache License, Version 2.0 (the "License");
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
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):
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.
Vamos exibir os primeiros 10 exemplos.
Vamos exibir também os primeiros 10 rótulos.
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:
google/nnlm-en-dim50-with-normalization/2 – igual a google/nnlm-en-dim50/2, mas com uma normalização de texto adicional para remover pontuações. Isso pode ajudar a ter uma melhor cobertura dos embeddings do vocabulário para tokens do texto de entrada.
google/nnlm-en-dim128-with-normalization/2 – um modelo maior, com uma dimensão de embedding igual a 128, em vez de 50 do modelo menor.
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)
.
Agora, vamos criar o modelo completo:
As camadas são empilhadas sequencialmente para construir o classificador:
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)
.O vetor de saída com tamanho fixo é passado por uma camada (
Dense
) totalmente conectada com 16 unidades ocultas.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:
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).
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:
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.
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:
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:
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.