Path: blob/master/site/pt-br/tutorials/keras/text_classification.ipynb
25118 views
Copyright 2019 The TensorFlow Authors.
Classificação de texto
Este tutorial demonstra a classificação de texto, começando pela classificação de arquivos de texto sem formatação armazenados no disco. Você treinará um classificador binário para fazer análise de sentimento para um dataset do IMDB. No final do notebook, você poderá fazer um exercício, em que treinará um classificador multiclasse para prever a tag de uma pergunta de programação no Stack Overflow.
Análise de sentimento
Este notebook treina um modelo de análise de sentimento para classificar 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.
Você usará 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.
Baixe e explore o dataset do IMDB
Vamos baixar e extrair o dataset, depois vamos explorar a estrutura de diretórios.
Os diretórios aclImdb/train/pos
e aclImdb/train/neg
contêm diversos arquivos de texto, sendo que cada um é uma única avaliação de filme. Vamos dar uma olhada em um desses arquivos.
Carregue o dataset
Agora, você vai carregar os dados para fora do disco e colocá-los em um formato adequado para o treinamento. Para isso, você usará um utilitário muito útil, o text_dataset_from_directory, que espera uma estrutura de diretórios, como mostrado abaixo.
Para preparar um dataset para fazer classificação binária, você precisa de duas pastas no disco, correspondentes a class_a
e class_b
. Elas conterão avaliações positivas e negativas de filmes, que podem ser encontradas em aclImdb/train/pos
e aclImdb/train/neg
. Como o dataset do IMDB contém pastas adicionais, você vai removê-las antes de usar o utilitário.
Agora, você usará o utilitário text_dataset_from_directory
para criar um tf.data.Dataset
com rótulos. tf.data é uma coleção de ferramentas avançadas para trabalhar com dados.
Ao realizar um experimento de aprendizado de máquina, é uma prática recomendada dividir o dataset em três: treinamento, validação e teste.
O dataset do IMDB já foi dividido em conjuntos de treinamento e teste, mas ainda falta um de validação. Vamos criar um conjunto de validação utilizando uma divisão 80/20 para os dados do treinamento por meio do argumento validation_split
abaixo.
Como podemos ver acima, há 25 mil exemplos na pasta de treinamento, das quais serão usadas 80%, ou 20 mil, para treinamento. Como veremos em breve, você pode treinar um modelo passando um dataset diretamente para model.fit
. Se você ainda estiver aprendendo sobre tf.data
, também pode fazer a iteração do dataset e exibir alguns exemplos, conforme mostrado abaixo.
Observe que a avaliação contém texto bruto (com pontuações e tags HTML, como <br/>
). Você verá como lidar com isso na próxima seção.
Os rótulos são 0 e 1. Para ver qual deles corresponde a avaliações positivas ou negativas de filmes, confira a propriedade class_names
do dataset.
Em seguida, você criará um dataset de validação e de teste. Você usará as 5 mil avaliações restantes do conjunto de treinamento para a validação.
Observação: ao usar os argumentos validation_split
e subset
, especifique uma semente aleatória ou passe shuffle=False
para que as divisões de validação e treinamento não se sobreponham.
Prepare o dataset para treinamento
Em seguida, você vai padronizar, tokenizar e vetorizar os dados usando a camada tf.keras.layers.TextVectorization
.
Padronização refere-se ao pré-processamento do texto, tipicamente para remover pontuações ou elementos HTML a fim de simplificar o dataset. Tokenização refere-se à divisão das strings em tokens (por exemplo, dividir uma frase em palavras individuais, fazendo a divisão a cada espaço). Vetorização refere-se à conversão de tokens em números para que eles possam ser alimentados em uma rede neural. Todas essas tarefas podem ser feitas com essa camada.
Como visto acima, as avaliações contêm diversas tags HTML, como <br />
. Elas não serão removidas pelo padronizador padrão na camada TextVectorization
(que converte texto em letras minúsculas e remove as pontuações por padrão, mas não retira código HTML). Você escreverá uma função de padronização personalizada para remover código HTML.
Observação: para evitar o desvio de treinamento/teste (também conhecido como desvio de treinamento/serviço), é importante pré-processar os dados de forma idêntica no momento de treinamento e teste. Para isso, a camada TextVectorization
pode ser incluída diretamente dentro do modelo, conforme exibido posteriormente neste tutorial.
Em seguida, você criará uma camada TextVectorization
, que será usada para padronizar, tokenizar e vetorizar os dados. Você deve definir output_mode
como int
para criar índices de inteiros únicos para cada token.
Observe que você está utilizando a função de divisão padrão e a função de padronização personalizada definida acima. Você também definirá algumas constantes para o modelo, como um mínimo explícito sequence_length
, que fará a camada preencher ou truncar sequências para valores exatamente iguais a sequence_length
.
Em seguida, chame adapt
para adequar o estado da camada de pré-processamento ao dataset. Isso fará com que o modelo crie um índice de strings para os números inteiros.
Observação: é importante usar somente os dados de treinamento ao chamar adapt, já que o uso do dataset de teste vazaria informações.
Vamos criar uma função para ver o resultado ao usar esta camada para pré-processar alguns dados.
Conforme visto acima, cada token foi substituído por um inteiro. Para visualizar o token (string) ao qual cada inteiro corresponde, você pode chamar .get_vocabulary()
na camada.
Está quase tudo pronto para treinar o modelo. Como etapa final de pré-processamento, você aplicará a camada TextVectorization criada anteriormente aos datasets de treinamento, validação e teste.
Configure o dataset para melhor desempenho
Há dois métodos importantes que você deve usar ao carregar os dados para garantir que a I/O não seja bloqueada.
.cache
mantém os dados na memória após o carregamento fora do disco. Isso garante 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 eficaz, que tem uma leitura mais eficiente do que vários arquivos pequenos.
/prefetch
sobrepõe o pré-processamento de dados e a execução do modelo durante o treinamento.
Saiba mais sobre ambos os métodos, além de como armazenar os dados em cache no disco, no guia sobre desempenho dos dados.
Crie o modelo
Chegou a hora de criar sua rede neural:
As camadas são empilhadas sequencialmente para construir o classificador:
A primeira é uma camada
Embedding
, que recebe avaliações codificadas em inteiros e avalia um vetor de embedding para cada palavra-índice. Esses vetores são aprendidos à medida que o modelo é treinado. Os vetores acrescentam uma dimensão à matriz de saída. As dimensões resultantes são:(batch, sequence, embedding)
(lote, sequência, embedding). Para saber mais sobre embeddings, confira o tutorial Embeddings de palavras.A segunda camada é
GlobalAveragePooling1D
, que retorna um vetor de saída de tamanho fixo para cada exemplo, calculando a média da dimensão de sequência. Dessa forma, o modelo consegue lidar com entradas de tamanho variável da forma mais simples possível.A última camada é densamente conectada com um único nó de saída.
Função de perda e otimizador
Todo 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 sigmóide), você usará a função de perda losses.BinaryCrossentropy
.
Agora, configure o modelo para usar um otimizador e uma função de perda:
Treine o modelo
Você passará o objeto dataset
ao método fit para treinar o modelo.
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 86%.
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 antes da exatidão do treinamento. Este é um exemplo de overfitting: o modelo tem desempenho melhor com os dados de treinamento em comparação a dados nunca vistos antes. 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, é possível evitar o overfitting simplesmente parando o treinamento quando a exatidão da validação deixa de aumentar. Uma forma de fazer isso é usando o callback tf.keras.callbacks.EarlyStopping
.
Exporte o modelo
No código acima, você aplicou a camada TextVectorization
ao dataset antes de alimentar o modelo com texto. Se quiser tornar o modelo capaz de processar strings brutas (por exemplo, para simplificar a implantação), é possível incluir a camada TextVectorization
dentro do modelo. Para isso, você pode criar um novo modelo usando os pesos que acabou de treinar.
Inferência de dados novos
Para fazer previsões para novos exemplos, basta chamar model.predict()
.
Ao incluir a lógica de pré-processamento de texto dentro do modelo, você pode exportar um modelo para produção que simplifica a implantação e reduz o potencial de desvio de treinamento/teste.
Há uma diferença de desempenho que você deve considerar ao escolher onde aplicar a camada TextVectorization. Ao usá-la fora do modelo, você pode fazer o processamento assíncrono na CPU e armazenar os dados em buffer ao treinar na GPU. Portanto, se você estiver treinando seu modelo na GPU, deve escolher essa opção para obter o melhor desempenho ao desenvolver o modelo. Depois, quando você estiver pronto para preparar a implantação, inclua a camada TextVectorization dentro do modelo.
Confira este tutorial para saber mais sobre como salvar modelos.
Exercício: classificação multiclasse para perguntas do Stack Overflow
Este tutorial mostrou como treinar um classificador binário do zero usando o dataset do IMDB. Você pode fazer um exercício: modifique este notebook para treinar um classificador multiclasse que preveja a tag de uma pergunta de programação feita no Stack Overflow.
Um dataset foi preparado para uso, contendo o texto de milhares de perguntas de programação (por exemplo, "Como posso ordenar um dicionário por valor no Python?") publicadas no Stack Overflow. Cada pergunta é rotulada com exatamente uma tag (Python, CSharp, JavaScript ou Java). Sua tarefa é receber uma pergunta como entrada e prever a tag apropriada, que, neste caso, é Python.
Você usará um dataset que contém milhares de perguntas extraídas do dataset público do Stack Overflow, que é bem maior, no BigQuery, contendo mais de 17 milhões de publicações.
Após baixar o dataset, você verá que ele tem uma estrutura de diretórios similar ao dataset do IMDB utilizado anteriormente:
Observação: para aumentar a dificuldade do problema de classificação, as ocorrências das palavras Python, CSharp, JavaScript e Java nas perguntas de programação foram substituídas pela palavra blank (em branco), já que diversas perguntas contêm a linguagem de programação em questão.
Para fazer este exercício, você deve modificar este notebook para que funcione com o dataset do Stack Overflow das seguintes maneiras:
Na parte superior do notebook, atualize o código que baixa o dataset do IMDB com o código que baixa o dataset do Stack Overflow, que já foi preparado. Como o dataset do Stack Overflow tem uma estrutura de diretórios parecida, você não precisará fazer muitas modificações.
Modifique a última camada do modelo para
Dense(4)
, pois agora há quatro classes de saída.Ao compilar o modelo, altere a perda para
tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
. Esta é a função de perda correta a ser usada para problemas de classificação muilticlasse, quando os rótulos de cada classe são inteiros (neste caso, podem ser 0, 1, 2 ou 3). Além disso, altere as métricas parametrics=['accuracy']
, já que este é um problema de classificação multicasse (tf.metrics.BinaryAccuracy
é usado somente para classificadores binários).Ao plotar a precisão ao longo do tempo, altere
binary_accuracy
eval_binary_accuracy
paraaccuracy
eval_accuracy
, respectivamente.Após fazer essas alterações, você poderá treinar um classificador multiclasse.
Saiba mais
Este tutorial mostrou como fazer a classificação de texto do zero. Para saber mais sobre o workflow de classificação de texto de forma geral, confira o guia Classificação de texto no Google Developers.