Análise de sentimentos em português utilizando Pytorch e Python
Esse é o primeiro de uma série de dois posts que irão mostrar como ajustar o BERT para realizar análise de sentimentos em português e colocar o modelo em produção a partir da criação de uma API (FastAPI + Uvicorn + Docker).
Serão coletados dados de avaliações de usuários em aplicativos da Play Store para treinar o modelo e gerar resultados como o mostrado a seguir:
O que é o BERT?
O BERT (Bidirectional Encoder Representations from Transformers), é um modelo de representação de linguagem desenvolvido por pesquisadores do Google AI e que teve seu código aberto em 2018. Ele é uma técnica de Processamento de Linguagem Natural (NLP) que apresentou resultados impressionantes em tarefas como prever a continuação de frases (SWAG) e destacar em um texto qual seria a resposta para uma dada pergunta (SQuAD).
O BERT pode ser aplicado em diferentes contextos, como na identificação de sentimentos de frases que será desenvolvida neste projeto. Para adaptá-lo, é necessário criar um classificador e realizar pequenas mudanças durante a etapa de treinamento do modelo - esse processo é chamado de Fine-Tunning.
Arquitetura
Antes de explorar a construção do modelo, é necessário entender como o BERT funciona. A principal inovação que ele trouxe foi a aplicação do treinamento bidirecional em transformers [0]— essa técnica permite um profundo entendimento do contexto trabalhado [1]. Anteriormente, a maioria das soluções analisavam uma sequência de texto da esquerda para a direita ou realizavam um treinamento combinado esquerda-direita e direita-esquerda.
Os transformers utilizados no BERT são mecanismos de atenção que aprendem relações entre palavras. Eles são compostos de codificadores (encoders) que leem um pedaço de texto de uma só vez e geram uma representação para cada palavra baseado no contexto em que elas estão inseridas.
Por exemplo, a palavra graça seria representada de uma forma na frase “O palhaço faz graça para sobreviver”e de outra em “Se conselho fosse bom, ninguém daria de graça”. Ela assume significados diferentes dependendo do contexto.
O BERT é basicamente uma pilha de codificadores de transformers. No artigo do modelo, são apresentadas as versões com 12 (base) e 24 (large) camadas. As frases a serem analisadas são quebradas em pequenos segmentos e cada um deles recebe um código chamado de token. Esses tokens são utilizados para alimentar o modelo.
Cada saída é um vetor de tamanho hidden_size (768 no BERT Base). Para alimentar o classificador de frases, será utilizado somente o primeiro vetor— o motivo ficará claro posteriormente.
Com isso, é possível dar inicio a construção da solução, que será dividida em quatro etapas:
Coleta de dados
Para criar o classificador de sentimentos é necessário um dataset de dados rotulados. Uma boa fonte de informações são as avaliações dos usuários em aplicativos da Google Play Store. Nelas, cada texto está associado a um número de 1 a 5 que indica o grau de satisfação das pessoas com as aplicações e consequentemente seus sentimentos em relação às suas experiências.
Com o auxilio do site AppAnnie, selecionou-se os Top 10 apps de comida mais baixados no Brasil e seus respectivos IDs. Essa informações serão utilizadas para extrair os dados de avaliações dos usuários utilizando o pacote Google-Play-Scraper.
| App | ID |
|:--------------:|:-----------------------------------:|
| 1. iFodd | br.com.brainweb.ifood |
| 2. Zé delivery | com.cerveceriamodelo.modelonow |
| 3. McDonald's | com.mcdo.mcdonalds |
| 4. Habibi's | habibs.alphacode.com.br |
| 5. 99Food | com.xiaojukeji.didi.brazil.customer |
| 6. Uber Eats | com.ubercab.eats |
| 7. Rappi | com.grability.rappi |
| 8. Burker King | burgerking.com.br.appandroid |
| 9. Madero | br.com.Madero |
| 10. Aiqfome | com.vanuatu.aiqfome |
A seguir serão detalhadas todas as etapas de coleta e tratamento dos dados. Caso você queira ir diretamente para o Colab Notebook construído, clique aqui.
Configuração do ambiente
Crie um novo Google Colab notebook, instale o Google-Play-Scraper e importe os pacotes necessários.
Coleta e tratamento dos dados
Defina os IDs dos apps a serem analisados e extraia informações básicas sobre cada um deles.
Feito isso, é possível coletar as avaliações dos usuários para cada um dos aplicativos. Como os textos serão divididos em três classes possíveis (positivo, negativo ou neutro) e objetivo é obter um dataset o mais balanceado possível, selecionou-se 400 amostras de avaliações com score 3 e 200 de cada uma das outras.
A ideia é que sejam atribuídos sentimentos para avaliações a partir dos scores seguindo a seguinte divisão:
Este é o resultado do dataset balanceado:
Com os dados coletados, a última etapa é salvar as informações em um csv
que servirá de entrada para o treino do classificador.
Baixe esse csv
e crie um novo Google Colab para o treino do modelo. Se preferir, acesse ao notebook completo aqui.
Pré-processamento dos dados
Nessa etapa, será necessário fazer o upload do arquivo reviews.csv
no notebook utilizado. Espera-se que seu ambiente tenha a seguinte estrutura:
Conforme citado anterioremente, o BERT requer que os textos de entrada sejam convertidos em tokens. Para isso, será utilizada a biblioteca transformers do Hugging Face. Ela precisa ser instalada e um tokenizer inicializado com um BERT pré-treinado. Como esse projeto baseia-se na análise de textos em portugês, utilizou-se o BERTimbau, um modelo que foi treinado no dataset BrWaC (Brazilian Web as Corpus).
Feito isso, o processo de tokenização de frases torna-se muito simples:
No entanto, para cumprir os requisitos de entrada do BERT é preciso ciar vetores de 0s e 1s chamados attention mask, que indicam quais token devem ser considerados como válidos, e adicionar mais três tokens especiais nos textos:
[SEP] (102)
- Marca o fim de uma frase
[CLS] (101)
- Deve ser colocado no inicio de cada frase para o BERT saber que trata-se de um problema de classificação.
[PAD] (0)
- Tokens de valor 0 que devem ser adicionados às sentenças para garantir que todas tenham o mesmo tamanho
Isso será feito com o auxílio do método encode_plus(), conforme o exemplo abaixo:
Como o BERT trabalha com um tamanho fixo de entrada, um dos parâmetros chave durante o processo de tokenização é a escolha do valor máximo desssa entrada (max_length).
Esse valor será definido analisando a distribuição dos tokens presentes no dataset. Como a maioria deles tem um tamanho menor que 125, será escolhido um max_lenght de 160 apenas para garantir que todos os casos serão cobertos.
Com todas essas informações, o dataset está pronto para ser criado.
Classificação de sentimentos
O classificador irá receber como entrada a última camada de saída do BERT e classificar os sentimentos da sequência de entrada em positivo, negativo ou neutro.
Como todo o trabalho pesado ja foi feito, o classificador será composto apenas de uma camada de dropout para regularização e uma camada totalmente conectada para a saída.
Treinamento
Com o objetivo de reproduzir o processo de treinamento descrito no artigo do BERT, será utilizada a implementação feita pelo Hugging Face do otimizador Adam (AdamW) e também um scheduler linear, mas sem etapas de warmup.
Para definir os hiperparâmetros do modelo serão utilizadas as recomendações feitas pelos autores do BERT:
- Batch size: 16, 32
- Learning rate (Adam): 5e-5, 3e-5, 2e-5
O trecho de código a seguir define esses valores e cria as funções de treinamento e validação do modelo.
Feito isso, o treinamento pode ser iniciado:
Um checkpoint do melhor modelo obtido durante o treinamento foi salvo no arquivo best_model_state.bin. Abaixo, é possível analisar as acurácias de treino e validação.
Observa-se que ao final das 10 épocas a acurácia de treinamento começa a se aproximar de 100%. Ajustando os parâmetros, o modelo pode ficar ainda melhor, mas esses resultados são suficientes para o propósito desse projeto.
Para avaliar outras métricas, será utilizado o método classification_report do sklearn em conjunto uma função auxiliar para obter as predições.
A partir das predições realizadas nos dados de teste, pode-se notar que a maioria das métricas associadas ao sentimento neutro ficaram abaixo do observado nos sentimentos positivo e negativo.
Intuitivamente, é possível dizer que os comentário neutros realmente são mais dificeis de ser identificados pois muito do que aparece neles também pode estar presente em frases com teor positivo ou negativo. Esse mesmo resultado pode ser confirmado na matriz de confusão:
Hora de testar o modelo! Algumas frases aleatórias foram escritas para simular como a solução se comportaria em um cenário real:
O modelo apresentou resultados consistentes nos testes realizados e está pronto para ser colocado em produção. Mas isso é papo para um outro post…. Baixe os pesos treinados (best_model_state.bin) em seu computador e guarde para o próximo artigo.
Nele, será mostrado como criar uma API e um sistema web capazes de se comunicarem em tempo real para realizar as inferências. Vamos produtizar a solução :)
Referências
[0] Vaswani, Ashish, et al. “Attention is all you need.” arXiv preprint arXiv:1706.03762 (2017).
[1] Devlin, Jacob, et al. “Bert: Pre-training of deep bidirectional transformers for language understanding.” arXiv preprint arXiv:1810.04805 (2018).