Emotion Analysis with Reformer Transformer Models: Optimizing Large Language Models for NLP

João Cláudio Nunes Carvalho
12 min readNov 4, 2024

--

Análise de Emoções com Modelos de Transformador Reformer: Otimizando Grandes Modelos de Linguagem para NLP

Prof. João Cláudio Nunes Carvalho

Overview

The Reformer model was proposed in the paper Reformer: The Efficient Transformer by Nikita Kitaev, Łukasz Kaiser, Anselm Levskaya.

Visão geral
O modelo Reformer foi proposto no artigo Reformer: The Efficient Transformer por Nikita Kitaev, Łukasz Kaiser, Anselm Levskaya.

Base de Dados Sintética

Vamos criar uma base de dados com 45 frases distribuídas entre seis emoções: alegria, tristeza, raiva, medo, surpresa e nojo.

1. Alegria:

  1. Estou radiante com a notícia do meu novo emprego.
  2. As crianças estavam felizes brincando no parque.
  3. Ganhei um presente maravilhoso no meu aniversário.
  4. Sinto-me pleno e satisfeito com a vida.
  5. A música me deixa em um estado de pura alegria.
  6. Foi um prazer inigualável conhecer você.
  7. A festa foi incrível, todos se divertiram muito.
  8. Estou animado para as férias que se aproximam.
  9. O sucesso do projeto me enche de felicidade.
  10. Adoro passar tempo com minha família.

2. Tristeza:

  1. Sinto falta dos tempos que passamos juntos.
  2. A perda do meu animal de estimação me deixou arrasado.
  3. Não consigo superar a melancolia deste dia chuvoso.
  4. Estou desanimado com os resultados.
  5. A despedida foi mais difícil do que imaginei.
  6. Meu coração está pesado com tanta tristeza.
  7. As lembranças me trazem lágrimas aos olhos.
  8. É doloroso ver como as coisas mudaram.
  9. Sinto-me sozinho mesmo estando entre pessoas.
  10. A notícia me deixou profundamente triste.

3. Raiva:

  1. Estou furioso com o serviço prestado.
  2. Não suporto quando me tratam com desrespeito.
  3. A injustiça deste mundo me enche de raiva.
  4. Fiquei irritado com o atraso constante.
  5. É inaceitável como eles lidaram com a situação.
  6. Minha paciência acabou depois de tanta provocação.
  7. Estou indignado com as decisões tomadas.
  8. Não tolero mentiras e enganações.
  9. A discussão me deixou muito irritado.
  10. Estou cansado de tanta negligência.

4. Medo:

  1. Tenho medo do que o futuro reserva.
  2. A escuridão da noite me deixa apreensivo.
  3. Sinto um frio na espinha quando penso nisso.
  4. Estou preocupado com a saúde da minha família.
  5. A ideia de falhar me aterroriza.
  6. Fico nervoso em lugares muito altos.
  7. Ouvi um barulho estranho e fiquei assustado.
  8. Estou ansioso sobre a entrevista amanhã.
  9. Tenho receio de enfrentar novos desafios.
  10. O filme de terror me deixou com medo.

5. Surpresa:

  1. Fiquei surpreso com a festa inesperada.
  2. Não acredito que você veio sem avisar!
  3. O resultado do exame me pegou de surpresa.
  4. Que coincidência incrível encontrá-lo aqui!
  5. Estou maravilhado com a reviravolta na história.

Análise de Emoções com o Reformer

Vamos agora realizar uma análise de emoções utilizando o modelo Reformer. O código será completamente comentado para facilitar o entendimento.

Pré-requisitos

  • Python 3.6 ou superior
  • PyTorch
  • Biblioteca transformers da Hugging Face

Passo a Passo

1. Instalar as Bibliotecas Necessárias

Abra o terminal ou prompt de comando e execute:

pip install torch transformers sklearn

2. Importar as Bibliotecas

import torch
from transformers import ReformerTokenizer, ReformerForSequenceClassification
from torch.utils.data import DataLoader, Dataset
from sklearn.model_selection import train_test_split

3. Preparar os Dados

# Lista de frases (45 frases divididas em 5 emoções)
sentences = [
# Alegria
"Estou radiante com a notícia do meu novo emprego.",
"As crianças estavam felizes brincando no parque.",
"Ganhei um presente maravilhoso no meu aniversário.",
"Sinto-me pleno e satisfeito com a vida.",
"A música me deixa em um estado de pura alegria.",
"Foi um prazer inigualável conhecer você.",
"A festa foi incrível, todos se divertiram muito.",
"Estou animado para as férias que se aproximam.",
"O sucesso do projeto me enche de felicidade.",
"Adoro passar tempo com minha família.",
    # Tristeza
"Sinto falta dos tempos que passamos juntos.",
"A perda do meu animal de estimação me deixou arrasado.",
"Não consigo superar a melancolia deste dia chuvoso.",
"Estou desanimado com os resultados.",
"A despedida foi mais difícil do que imaginei.",
"Meu coração está pesado com tanta tristeza.",
"As lembranças me trazem lágrimas aos olhos.",
"É doloroso ver como as coisas mudaram.",
"Sinto-me sozinho mesmo estando entre pessoas.",
"A notícia me deixou profundamente triste.",
# Raiva
"Estou furioso com o serviço prestado.",
"Não suporto quando me tratam com desrespeito.",
"A injustiça deste mundo me enche de raiva.",
"Fiquei irritado com o atraso constante.",
"É inaceitável como eles lidaram com a situação.",
"Minha paciência acabou depois de tanta provocação.",
"Estou indignado com as decisões tomadas.",
"Não tolero mentiras e enganações.",
"A discussão me deixou muito irritado.",
"Estou cansado de tanta negligência.",
# Medo
"Tenho medo do que o futuro reserva.",
"A escuridão da noite me deixa apreensivo.",
"Sinto um frio na espinha quando penso nisso.",
"Estou preocupado com a saúde da minha família.",
"A ideia de falhar me aterroriza.",
"Fico nervoso em lugares muito altos.",
"Ouvi um barulho estranho e fiquei assustado.",
"Estou ansioso sobre a entrevista amanhã.",
"Tenho receio de enfrentar novos desafios.",
"O filme de terror me deixou com medo.",
# Surpresa
"Fiquei surpreso com a festa inesperada.",
"Não acredito que você veio sem avisar!",
"O resultado do exame me pegou de surpresa.",
"Que coincidência incrível encontrá-lo aqui!",
"Estou maravilhado com a reviravolta na história."
]
# Labels correspondentes às emoções
# 0: Alegria, 1: Tristeza, 2: Raiva, 3: Medo, 4: Surpresa
labels = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # Alegria
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # Tristeza
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, # Raiva
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, # Medo
4, 4, 4, 4, 4 # Surpresa
]

OBSERVAÇÃO:

No contexto da análise de emoções, cada frase no conjunto de dados está associada a uma emoção específica. Para que o modelo possa aprender e prever as emoções correspondentes às frases, precisamos representar essas emoções em formato numérico. Isso é feito atribuindo um label (rótulo numérico) a cada emoção.

Definimos as seguintes emoções e atribuimos a elas os seguintes labels:

  • 0: Alegria
  • 1: Tristeza
  • 2: Raiva
  • 3: Medo
  • 4: Surpresa

A lista labels é uma sequência de números onde cada número corresponde à emoção da frase na mesma posição na lista sentences.

Correspondência entre Frases e Labels

As frases foram organizadas em grupos, cada um representando uma emoção específica. A lista sentences contém 45 frases no total, distribuídas entre as 5 emoções, e os labels são atribuídos na mesma ordem.

Por Que Usamos Labels Numéricos?

Os modelos de aprendizado de máquina, incluindo o Reformer, processam dados numéricos. Para que o modelo possa aprender a classificar as emoções, precisamos converter as categorias textuais (emoções) em valores numéricos. Este processo é conhecido como codificação de labels ou label encoding.

Visualização Completa

Aqui está uma representação completa para facilitar a visualização:

Índice Frase Emoção Label 0 “Estou radiante com a notícia do meu novo emprego.” Alegria 0 1 “As crianças estavam felizes brincando no parque.” Alegria 0 … … … … 10 “Sinto falta dos tempos que passamos juntos.” Tristeza 1 11 “A perda do meu animal de estimação me deixou arrasado.” Tristeza 1 … … … … 20 “Estou furioso com o serviço prestado.” Raiva 2 21 “Não suporto quando me tratam com desrespeito.” Raiva 2 … … … … 30 “Tenho medo do que o futuro reserva.” Medo 3 31 “A escuridão da noite me deixa apreensivo.” Medo 3 … … … … 40 “Fiquei surpreso com a festa inesperada.” Surpresa 4 41 “Não acredito que você veio sem avisar!” Surpresa 4 … … … …

4. Dividir os Dados em Treinamento e Teste

# Dividindo os dados em 80% para treinamento e 20% para teste
train_texts, test_texts, train_labels, test_labels = train_test_split(
sentences, labels, test_size=0.2, random_state=42
)

5. Tokenizar os Dados

No processamento de linguagem natural (PLN), antes de alimentar textos em um modelo como o Reformer, precisamos converter esses textos em uma representação numérica que o modelo possa entender. Isso é feito através de um processo chamado tokenização.

# Carregando o tokenizer do Reformer pré-treinado
tokenizer = ReformerTokenizer.from_pretrained('google/reformer-crime-and-punishment')
# Tokenizando os textos de treinamento e teste
train_encodings = tokenizer(train_texts, truncation=True, padding=True)
test_encodings = tokenizer(test_texts, truncation=True, padding=True)

Explicação:

  • ReformerTokenizer.from_pretrained():
  • Método utilizado para carregar um tokenizer que já foi pré-treinado.
  • O tokenizer vem com um vocabulário e regras de tokenização específicas que foram aprendidas durante o pré-treinamento.
  • Argumento 'google/reformer-crime-and-punishment':
  • Este é o nome de um modelo pré-treinado disponível na biblioteca transformers da Hugging Face.
  • google/reformer-crime-and-punishment é um modelo Reformer que foi pré-treinado no texto do livro "Crime e Castigo" de Fiódor Dostoiévski.
  • Embora o livro seja originalmente em russo, o modelo foi treinado em uma versão em inglês.
  • O que acontece nesta linha?:
  • O tokenizer é carregado com o vocabulário e as regras de tokenização aprendidas durante o pré-treinamento no corpus específico.
  • Isso garante que a tokenização dos textos de entrada seja compatível com o modelo Reformer que será usado posteriormente.

Observação Importante:

  • Idioma: Como o modelo foi pré-treinado em textos em inglês, pode haver limitações ao aplicar esse tokenizer e modelo em textos em português. Isso pode afetar o desempenho do modelo na tarefa de análise de emoções em português.

Não existe um Reformer pré-treinado em português, existem modelos multilíngues que suportam o português e podem ser usados para tarefas de processamento de linguagem natural:

  • XLM-RoBERTa: Um modelo robusto e multilíngue treinado em 100 idiomas, incluindo o português. Ele tem mostrado bons resultados em diversas tarefas e pode ser adaptado para análise de emoções.
  • python Copiar código from transformers import XLMRobertaTokenizer, XLMRobertaForSequenceClassification # Carregando o tokenizer e o modelo pré-treinado tokenizer = XLMRobertaTokenizer.from_pretrained('xlm-roberta-base') model = XLMRobertaForSequenceClassification.from_pretrained('xlm-roberta-base', num_labels=5)
  • mBERT (Multilingual BERT): Treinado em 104 idiomas, incluindo o português. Pode ser usado para tarefas de classificação de texto.
  • python Copiar código from transformers import BertTokenizer, BertForSequenceClassification tokenizer = BertTokenizer.from_pretrained('bert-base-multilingual-cased') model = BertForSequenceClassification.from_pretrained('bert-base-multilingual-cased', num_labels=5)

Esses modelos já têm conhecimento do português e podem ser fine-tuned (ajustados) para a sua tarefa específica de análise de emoções.

Passos para Treinar o Reformer em Português

  • Coletar um Corpus: Reúna uma quantidade substancial de texto em português (várias dezenas de gigabytes, se possível).
  • Pré-processamento: Limpe e prepare o texto para o treinamento.
  • Treinamento: Use frameworks como PyTorch e a biblioteca transformers para treinar o Reformer do zero ou adaptar um modelo existente.
  • Considerações: Este processo é intensivo em recursos computacionais e tempo. É recomendado apenas se você tiver acesso a GPUs ou TPUs potentes.

Custo computacional altíssimo…

6. Criar um Dataset Customizado

O código apresentado abaixo define uma classe personalizada chamada EmotionDataset, que herda da classe Dataset do PyTorch. O principal objetivo dessa classe é organizar e preparar os dados tokenizados e os labels correspondentes para serem usados no treinamento e na avaliação de um modelo de aprendizado de máquina, como o Reformer ou outros modelos de linguagem.

Criamos uma classe Dataset personalizada para preparar os dados para o modelo.

class EmotionDataset(Dataset):
def __init__(self, encodings, labels):
self.encodings = encodings # Encodings dos textos
self.labels = labels # Labels correspondentes
    def __getitem__(self, idx):
# Retorna um item (amostra) do dataset
item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
item['labels'] = torch.tensor(self.labels[idx], dtype=torch.long)
return item
def __len__(self):
# Retorna o tamanho do dataset
return len(self.labels)
# Instanciando os datasets de treinamento e teste
train_dataset = EmotionDataset(train_encodings, train_labels)
test_dataset = EmotionDataset(test_encodings, test_labels)

7. Carregar o Modelo Reformer para Classificação

# Carregando o modelo Reformer pré-treinado para classificação de sequência
# Especificamos o número de labels (emoções) que o modelo deve prever
model = ReformerForSequenceClassification.from_pretrained(
'google/reformer-crime-and-punishment',
num_labels=5 # Temos 5 emoções diferentes
)

8. Configurar o Treinamento

Configuramos o otimizador, o scheduler e os DataLoaders.

from torch.optim import AdamW
from transformers import get_scheduler
# DataLoader para o conjunto de treinamento
train_loader = DataLoader(train_dataset, batch_size=4, shuffle=True)
# DataLoader para o conjunto de teste
test_loader = DataLoader(test_dataset, batch_size=4, shuffle=False)
# Definindo o otimizador AdamW com taxa de aprendizado de 5e-5
optimizer = AdamW(model.parameters(), lr=5e-5)
# Configurando o scheduler para ajustar a taxa de aprendizado durante o treinamento
num_epochs = 3
num_training_steps = num_epochs * len(train_loader)
lr_scheduler = get_scheduler(
name="linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps
)

9. Treinar o Modelo

# Verificando se há GPU disponível e definindo o dispositivo
device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
model.to(device) # Movendo o modelo para o dispositivo selecionado
from tqdm.auto import tqdm# Barra de progresso para acompanhar o treinamento
progress_bar = tqdm(range(num_training_steps))
model.train() # Definindo o modelo em modo de treinamento
for epoch in range(num_epochs):
for batch in train_loader:
# Movendo o batch de dados para o dispositivo
batch = {k: v.to(device) for k, v in batch.items()}
# Executando o forward pass
outputs = model(**batch)
loss = outputs.loss # Calculando a perda (loss)
# Backpropagation
loss.backward()
# Atualizando os pesos
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()
# Atualizando a barra de progresso
progress_bar.update(1)

10. Avaliar o Modelo

model.eval()  # Definindo o modelo em modo de avaliação
correct = 0 # Contador de previsões corretas
total = 0 # Total de previsões
with torch.no_grad():
for batch in test_loader:
# Movendo o batch de dados para o dispositivo
batch = {k: v.to(device) for k, v in batch.items()}
# Executando o forward pass
outputs = model(**batch)
# Obtendo as previsões do modelo
predictions = torch.argmax(outputs.logits, dim=-1)
# Atualizando o contador de acertos
correct += (predictions == batch['labels']).sum().item()
total += batch['labels'].size(0)
# Calculando a acurácia
accuracy = correct / total
print(f'Acurácia no conjunto de teste: {accuracy * 100:.2f}%')

Observações Importantes

  • Tamanho do Dataset: Com apenas 45 frases, o modelo pode não alcançar uma alta acurácia ou generalizar bem para novos dados. Em aplicações reais, é recomendado utilizar um dataset maior.
  • Uso do Reformer: O Reformer é projetado para sequências longas. Como nossas frases são curtas, o ganho em eficiência não será tão evidente, mas o exercício é válido para entender o processo.
  • Comentário no Código: Todo o código foi comentado para facilitar o entendimento de cada etapa.
  • Ambiente de Execução: Se possível, utilize uma GPU para acelerar o treinamento. Se não tiver uma GPU disponível, o código ainda funcionará, mas o treinamento será mais lento.
  • O treinamento que configuramos utiliza o modelo Reformer para realizar análise de emoções em um conjunto de dados de 45 frases em português, categorizadas em cinco emoções: Alegria, Tristeza, Raiva, Medo e Surpresa.
  • Dado o contexto e as especificidades do seu setup, aqui estão os resultados esperados e considerações importantes:
  • 1. Desempenho do Modelo
  • Acurácia no Conjunto de Teste: Devido ao tamanho reduzido do conjunto de dados, é provável que o modelo alcance uma acurácia limitada no conjunto de teste. A acurácia pode variar significativamente, mas pode ficar próxima do acaso (em torno de 20% para cinco classes), especialmente em dados não vistos durante o treinamento.
  • Overfitting (Sobreajuste): Com apenas 45 frases, o modelo pode facilmente sobreajustar aos dados de treinamento, aprendendo padrões específicos dos exemplos fornecidos em vez de generalizar para novos dados. Isso resultaria em alta acurácia no treinamento, mas baixa acurácia no teste.
  • Confusão entre Classes: O modelo pode ter dificuldade em distinguir entre emoções semelhantes ou interpretar corretamente emoções menos representadas, como “Surpresa”, que possui menos exemplos.
  • 2. Limitações Devidas ao Tamanho do Conjunto de Dados
  • Dataset Pequeno: Modelos de deep learning, como o Reformer, geralmente exigem grandes quantidades de dados para aprender padrões significativos. Um conjunto de 45 frases é insuficiente para treinar efetivamente um modelo tão complexo.
  • Desbalanceamento de Classes: A distribuição desigual entre as classes (por exemplo, apenas 5 frases para “Surpresa”) pode levar o modelo a ser tendencioso em favor das classes com mais exemplos.
  • 3. Considerações sobre o Idioma
  • Modelo Pré-treinado em Inglês: O modelo Reformer que você está usando ('google/reformer-crime-and-punishment') foi pré-treinado em textos em inglês. Aplicá-lo diretamente em textos em português pode resultar em desempenho insatisfatório, pois o modelo não possui conhecimento prévio das estruturas linguísticas do português.
  • Tokenizador Inadequado: O tokenizador associado ao modelo também foi treinado em inglês, o que pode causar tokenizações inadequadas para o português, afetando negativamente a entrada do modelo.
  • 4. Adequação do Modelo Reformer
  • Comprimento das Sequências: O Reformer é projetado para lidar eficientemente com sequências muito longas. Como suas frases são curtas, você não aproveitará os benefícios principais do Reformer.
  • Modelos Alternativos: Modelos como BERT ou RoBERTa pré-treinados em português (por exemplo, o BERTimbau) podem ser mais adequados e oferecer melhor desempenho para a tarefa.
  • 5. Resumo dos Resultados Esperados
  • Baixa Acurácia Geral: Devido aos fatores mencionados, espera-se que o modelo tenha dificuldade em aprender a distinguir entre as diferentes emoções.
  • Resultados Inconsistentes: O modelo pode apresentar desempenho variável, acertando algumas previsões por acaso e errando em outras.
  • Dificuldades com Emoções Menos Representadas: Emoções com menos exemplos, como “Surpresa”, provavelmente serão classificadas incorretamente.
  • 6. Recomendações para Melhorar o Desempenho
  1. Expandir o Conjunto de Dados:
  • Colete mais frases para cada emoção, visando centenas ou milhares de exemplos por classe.
  • Utilize fontes como redes sociais, artigos, livros ou bases de dados públicas de emoções.
  1. Balancear as Classes:
  • Certifique-se de que cada emoção tenha um número semelhante de exemplos para evitar vieses no modelo.
  1. Usar Modelos Pré-treinados em Português:
  • BERTimbau: Um modelo BERT pré-treinado em português que captura nuances da língua.
  • XLM-RoBERTa: Um modelo multilíngue que suporta português e pode ser fine-tuned para sua tarefa.
  1. Data Augmentation (Aumento de Dados):
  • Aplique técnicas de aumento de dados, como sinônimos, tradução e paraphraseamento, para gerar mais exemplos.
  1. Modelos Mais Simples:
  • Considere utilizar algoritmos de aprendizado de máquina tradicionais, como SVM ou Naive Bayes, com extração de características (TF-IDF), que podem funcionar melhor em conjuntos de dados pequenos.
  1. Estratificação na Divisão dos Dados:
  • Use o parâmetro stratify=labels na função train_test_split para garantir que a proporção de classes seja mantida nos conjuntos de treinamento e teste.
  • python Copiar código train_texts, test_texts, train_labels, test_labels = train_test_split( sentences, labels, test_size=0.2, random_state=42, stratify=labels )
  1. Avaliação Detalhada:
  • Utilize métricas como precisão, revocação e F1-score para cada classe, além da acurácia geral.
  • Analise a matriz de confusão para entender quais classes estão sendo confundidas pelo modelo.
  • 7. Considerações Finais
  • Limitações Técnicas: O uso do Reformer com um dataset pequeno e em um idioma diferente do que foi pré-treinado limita severamente o desempenho esperado.
  • Necessidade de Ajustes: Para obter resultados significativos, é crucial ajustar o modelo e o conjunto de dados às necessidades da tarefa.
  • Validade dos Resultados: Os resultados obtidos com o setup atual devem ser interpretados com cautela, pois podem não refletir a capacidade real do modelo em uma aplicação prática.

<meta name=”google-site-verification” content=”OsrOHdMZXLBE-hDNNcga2Ik27b_jN6hSEG7hvAXfGQ4" />

--

--

João Cláudio Nunes Carvalho
João Cláudio Nunes Carvalho

Written by João Cláudio Nunes Carvalho

Professor of Physics at the Federal Institute of Ceará. Phd in physics(UFC). MBA in Data Science and Analytics — USP — University of São Paulo

No responses yet