Análise de sentimentos com um "ChatGPT" de código aberto

Fellipe Gomes
Data Hackers
Published in
12 min readMay 3, 2024

--

Como executar localmente o LLM pré treinado de código aberto LLAMA2 para realizar uma análise de sentimentos em Python

POR QUE ANÁLISE DE SENTIMENTOS?

Compreender os sentimentos por trás de grandes volumes de texto tornou-se essencial, pois em um mundo cada vez mais digitalizado, a capacidade de compreender as respostas e emoções em larga escala das pessoas diante de produtos, eventos ou tópicos específicos não é apenas valiosa por fornecer insights, mas também se tornou uma necessidade para alavancar negócios e tornar-se cada vez mais competitivo.

Análise de sentimento, também chamada de mineração de opinião, é o campo de estudo que analisa as opiniões, sentimentos, avaliações, apreciações, atitudes e emoções das pessoas em relação a entidades como produtos, serviços, organizações, indivíduos, questões, eventos, tópicos e seus atributos. Liu 2020

POR QUE LARGE LANGUAGE MODELS?

A abordagem comum para resolver problemas de NLP envolviam a aplicação de text mining, embeddings como word2vec e GloVe (Global Vectors for Word Representation) e técnicas de Machine Learning, onde modelos como Random Forest, SVM, Naive Bayes, KNN, Ensembles e até mesmo Regressão eram frequentemente utilizados para classificar textos. Além disso, o uso de redes neurais recorrentes (RNNs) sempre foi uma alternativa valiosa, especialmente em situações que demandavam o processamento de dados sequenciais, sendo a LSTM (Long Short-Term Memory) uma variante eficaz para lidar com o desafio conhecido como vanishing gradient.

Já no cenário atual de modelos pré-treinados, o BERT (Bidirectional Encoder Representations from Transformers) também teve bastante destaque nesse domínio antes da ascensão do ChatGPT, demonstrando a viabilidade como um método gerador de texto e mostraram o poder que as redes neurais têm para gerar longas sequências de texto que antes pareciam inatingíveis.

GPT-3 supera seus antecessores em termos de contagem de parâmetros

Embora já existam há algum tempo, os LLMs ganharam a mídia através do ChatGPT, interface de chat da OpenAI para modelos LLM GPT-3 lançado em 2020, com 175 milhões de parâmetros, que já teve uma série de avanços significativos nos últimos anos como seu irmão maior, o GPT-4 lançado em 2023 conta com incríveis 100 trílhões de parâmetros.

The comparison between GPT-3 and GPT-4 based on the number of parameters used in their architecture

Modelos com mais de 100 bilhões de parâmetros já podem ser considerados muito grandes, com conhecimento mundial muito rico. Esses modelos maiores conseguem “aprender” ainda mais informações sobre muitas coisas sobre fisica, filosofia, ciência, programação, etc sendo cada vez mais úteis para ajudar em tarefas que envolvam conhecimento profundo ou raciocinio complexo, sendo um bom “parceiro” para brainstorming.

⚠️ Atenção!
Afirmar que maiores modelos são sempre melhores não é verdade. O tempo de processamento, latência e o custo também irão aumentar, por isso abordagens alternativas também devem ser consideradas.

COMO FUNCIONAM OS LLMS?

Os LLMs são modelos de Machine Learning que usam algoritmos de Deep Learning para processar e compreender a linguagem natural, gerando texto de maneira eficaz. Esses modelos são treinados com grandes volumes de dados da internet, adquirindo a capacidade de identificar padrões na composição de palavras e frases. A idéia básica por trás desses modelos é que são capazes de gerar texto prevendo repetidamente a próxima palavra oferecendo resultados rápidos e diversas aplicações práticas em várias áreas

APLICAÇÕES

Diferentemente de uma ferramenta de busca como o Google, o ChatGPT não recupera informações, mas cria frases e textos completos em tempo real com base no processamento de um imenso volume de dados, veja alguns exemplos de uso para diferentes tarefas:

✍️ ESCRITA:

  • Colaboração em brainstorming, sugerindo nomes;
  • Elaboração de templates para comunicados e e-mails;
  • Tradução automática.

📖 LEITURA:

  • Revisão de textos;
  • Sumarização de artigos extensos;
  • Análise de sentimentos, possibilitando a criação de dashboards para acompnhamento ao longo do tempo.

💬 CONVERSA:

  • Diálogos e aconselhamentos;
  • Coaching de carreira;
  • Planejamento de viagens; Sugestões de receitas;
  • Conversação interativa com documentos PDF;
  • Atendimento ao cliente;
  • Realização de pedidos.

O QUE FAREMOS AQUI?

Nosso objetivo aqui é realizar uma análise de sentimentos para classificar sentenças como positivas ou negativas utilizando algum LLM pré-treinado. Embora a OpenAI já tenha sido uma organização sem fins lucrativos que lançava seus projetos como código aberto, desde o lançamento do ChatGPT ela se tornou uma empresa que mantém a propriedade de seus códigos fonte. Isso significa que apesar da facilidade de criar aplicações, modelos mais poderosos e relativamente baratos, desenvolvedores de IA não podem modificar o GPT-3 para atender às nossa necessidades específicas ou incorporá-lo em seus próprios projetos de maneira livre e gratuita. Portanto teremos de recorrer à alternativas não tão(*) open source como o Llama 2 da Meta que permite total controle sobre o modelo, rodar em nosso próprio computador/servidor e nós dá o controle sobre a privacidade dos nossos dados.

(*) “Código aberto” 🤔
Não é totalmente código aberto pois por mais que a Meta tenha disponibilizado o modelo treinado para uso livre, ele não compartilha os dados de treinamento do modelo ou o código usado para treiná-lo.

MÃOS A OBRA!

INICIAR AMBIENTE DE TRABALHO

Primeiramente vamos carregar todas as dependencias necessárias para executar os códigos a seguir:

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from wordcloud import WordCloud
from PIL import Image
from nltk.corpus import stopwords
from collections import Counter
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score
from llama_cpp import Llama
from tqdm.notebook import tqdm
tqdm.pandas()

CARREGAR DADOS

Utilizaremos uma versão traduzida do dataset IMdb para o português, um conjunto de dados do Internet Movie Database (IMDB), que é uma das maiores e mais abrangentes bases de dados online sobre filmes e programas de televisão.

#Importar todo conjunto de dados
df = pd.read_csv('input/imdb-reviews-pt-br.csv', index_col='id')
# Obter amostra de tamanho 100
_, df = train_test_split(df, test_size=100, random_state=42, shuffle=True)

INFORMAÇÕES GERAIS

Esse dataset inclui avaliações e críticas de filmes feitas por usuários do IMDB, bem como informações sobre os próprios filmes, como título, ano de lançamento, gênero, etc.

ANÁLISE EXPLORATÓRIA

DISTRIBUIÇÃO DOS SENTIMENTOS NA AMOSTRA

Primeiro vamos entender como ficou distribuída a proporção dos sentimentos na amostra coletada:

📌 Interpretação: Coletei uma amostra aleatória simples de tamanho n=100 de todas as reviews que contém aproximadamente metade de cada sentimento para diminuir o tempo computacional de execução no meu computador.

PALAVRAS MAIS FREQUENTES PARA CADA SENTIMENTO

Núvens de palavras das resenhas dos filmes que foram anotadas como positivos e como negativos nas duas linguas disponíveis no dataset:

Núvem de palavras mais frequentes das resenhas em 🇺🇲 Inglês

Núvem de palavras mais frequentes das resenhas em 🇧🇷 Português

📌 Interpretação: Como esperado, mesmo com a mudança na língua, a frequência das palavras é exibida de maneira muito similar de acordo com cada sentimento.

ANÁLISE DE SENTIMENTOS

FAMÍLIA LLAMA 2 DE LARGE LANGUAGE MODELS (LLMS)

Nesta seção, exploraremos o Llama 2, um modelo de código aberto, e discutiremos as vantagens e desvantagens em relação aos LLMs de código fechado ou remotos.

TAMANHO DO MODELO

Para saber qual modelo utilizar, primeiramente precisamos ter em mente algumas noções sobre a quantidade de parâmetros e tamanhos dos LLM. No geral:

  • 1 Bilhão: Bons em correspondência de padrões e algum conhecimento básico do mundo (como por exemplo classificar avaliações por sentimento)
  • 10 Bilhões: Maior conhecimento mundial, conhecem mais fatos esotéricos sobre o mundo e melhoram em seguir instruções básicas (bom para chatbot para pedidos de comida);
  • 100+ Bilhões: Muito grandes, com conhecimento mundial muito rico, saberão coisas sobre física , filosofia, ciência e assim por diante e serão melhores em raciocínios complexos (tarefas que envolvem conhecimento profundo ou raciocínio complexo, parceiro para brainstorming)

Para uma análise de sentimentos simples, não é necessário um modelo com 100 bilhões de parâmetros. Modelos menores, como os com 7 bilhões de parâmetros, podem ser suficientes e menos computacionalmente exigentes.

CÓDIGO ABERTO OU FECHADO

Embora próximos, os LLMs de código aberto ainda não conseguem igualar o poder e a precisão dos aplicativos de código fechado disponíveis comercialmente, como GPT-4 e Bard (Gemini). Mesmo sendo menos poderosos, existem alguns prós e contras pelos quais podemos pesar na hora de escolher a melhor opção:

Open Source

  • Total controle sobre o modelo
  • Pode rodar em nosso próprio computador/servidor
  • Controle sobre a privacidade dos dados

Closed

  • Fácil de criar aplicações
  • Maiores e mais poderosos
  • Relativamente barato
  • Existe um certo risco de depender do fornecedor

Utilizaremos a abordagem de código aberto por ser mais prática para fins de estudos, pois além de gratuita, não exige internet, registros ou chaves de API.

USO REMOTO OU LOCAL

Podemos interagir com o modelo de linguagem grande (LLM) do Llama 2 via API da Hugging Face, seguindo as instruções do repositório oficial da Meta ou podemos baixar os arquivos do modelo em formato GGML para o Llama 2 7B Chat do Meta Llama 2. Os formatos GGML são utilizados para inferência de CPU + GPU usando o principamente o pacote llama-cpp-python.

Para mais informações sobre como configurar o modelo consulte este link

def load_llama_model(model_path="./input/llama-2-7b-chat.ggmlv3.q2_K.bin", language='en', seed=42):
# Determinar o tamanho da janela de contexto com base no idioma
if language == 'en':
context_window = df.text_en.map(len).max()
elif language == 'pt':
context_window = df.text_pt.map(len).max()
else:
raise ValueError("Language must be 'en' or 'pt'.")

# Carregar o modelo Llama
return Llama(model_path=model_path,
verbose=False,
n_ctx=context_window,
seed=seed)

Para obter os melhores resultados, devemos ser o mais claro e específicos possível nas interações. Porém devemos iniciar com um prompt simples e rápido para ir direcionando o modelo na direção desejada e avaliando os resultados obtidos e ajustando gradualmente o prompt para refinar e aprimorar a resposta desejada

def classify_sentiment_llama(text, llama_model):
# Construir a prompt para o modelo Llama
prompt = f''' \
Q: Answer with just one word, \
does the following text express a \
positive or negative feeling? \
{text} \
A:'''
# Obter a saída do modelo Llama
output = llama_model(prompt, max_tokens=3)
return output["choices"][0]["text"]

Com nosso prompt definido, já podemos carregar o modelo:

# Carregar o modelo Llama para o idioma desejado
llama_model = load_llama_model(language='en')
## llama.cpp: loading model from ./llama-2-7b-chat.ggmlv3.q2_K.bin
## llama_model_load_internal: format = ggjt v3 (latest)
## llama_model_load_internal: n_vocab = 32000
## llama_model_load_internal: n_ctx = 4320
## llama_model_load_internal: n_embd = 4096
## llama_model_load_internal: n_mult = 256
## llama_model_load_internal: n_head = 32
## llama_model_load_internal: n_head_kv = 32
## llama_model_load_internal: n_layer = 32
## llama_model_load_internal: n_rot = 128
## llama_model_load_internal: n_gqa = 1
## llama_model_load_internal: rnorm_eps = 5.0e-06
## llama_model_load_internal: n_ff = 11008
## llama_model_load_internal: freq_base = 10000.0
## llama_model_load_internal: freq_scale = 1
## llama_model_load_internal: ftype = 10 (mostly Q2_K)
## llama_model_load_internal: model size = 7B
## llama_model_load_internal: ggml ctx size = 0.08 MB
## llama_model_load_internal: mem required = 2733.66 MB (+ 2160.00 MB per state)
## llama_new_context_with_model: kv self size = 2160.00 MB
## llama_new_context_with_model: compute buffer total size = 295.35 MB

Após instanciar o modelo, basta aplicá-lo em nossa base de dados. (apliquei o mesmo modelo tanto para as reviews e português quanto em inglês).

df['sentiment_llm_en'] = df.text_en.progress_apply(lambda x: classify_sentiment_llama(x, llama_model))

Como este modelo é o mais básico e não alteramos nenhum parâmetro (como por exemplo temperature, que determina se o output será mais aleatório ou mais previsível) pode ser que a saída não saia padronizada e necessite de algum pós-processamento. Vejamos como foram os outputs do LLM:

📌 Interpretação: É possível observar que o modelo pré-treinado conseguiu reconhecer de maneira bastante coerente o sentimento dos trechos para as categorias pos e neg, porém, não vieram padronizadas exatamente como solicitamos ao modelo.

Como a saída não foi padronizada, vamos realizar algum pós-processamento para padronizar as classes como pos ou neg para possibilitar avaliar o desempenho do modelo com base em métricas de classificação.

conditions = [
(df.sentiment_llm_en.str.contains('(?i)(?:pos|fun)')),
(df.sentiment_llm_en.str.contains('(?i)(?:neg|horrible|melanchol)'))
]
pd.crosstab(df.sentiment, np.select(conditions, ['pos', 'neg'], default='other'))

Com os outputs padronizados em duas classes, podemos verificar como foi a acurácia do modelo.

DESEMPENHO

Como estamos diante de um problema de classificação, avaliaremos o desempenho do modelo com matrizes de confusão para entender a as taxas de acerto e calcular a acurácia pois o dataset é balanceado.

📌 Interpretação: A acurácia geral para a língua Inglesa foi superior quando aplicado o mesmo modelo para a língua portuguesa. Vale lembrar que este modelo foi treinado em Inglês e estamos utilizado a menor das opções.

O desempenho deste modelo é muito interessante, principalmente por já ser pré treinado, não sendo necessário gastar tanto tempo na sua construção mas para afirmar que este modelo é bom precisamos entender qual seria o resultado para resolver este problemas se utilizassemos a abordagem mais simples possível.

VADER

O VADER (Valence Aware Dictionary and sEntiment Reasoner) é uma abordagem mais simples e rápida em comparação aos LLMs. Não requer o treinamento de um modelo, mas depende de léxicos de palavras relacionadas a sentimentos. Pode ser facilmente utilizado via bibliotecas de código aberto em Python, como vaderSentiment para inglês e LeIA (Léxico para Inferência Adaptada) para português.

A abordagem é direta: no léxico (uma coleção de palavras), cada palavra já possui uma nota atribuída. Ao passar um documento (frase), retorna um dicionário com o escore de polaridade com base no escore das palavras no texto. O dicionário inclui o valor do sentimento geral normalizado (compound), variando de -1 (extremamente negativo) a +1 (extremamente positivo). Esse valor pode ser usado para descrever o sentimento predominante no texto, considerando os seguintes limites:

  • Sentimento positivo: compound >= 0.05
  • Sentimento negativo: compound <= -0.05
  • Sentimento neutro: (compound > -0.05) e (compound < 0.05)

A execução do código é bem rápida, sendo útil para referência como baseline ou em casos em que temos baixo recurso computacional e um grande volume de dados para classificar.

DESEMPENHO

Como estamos diante de um problema de classificação, avaliaremos o desempenho do modelo com matrizes de confusão para entender a as taxas de acerto e calcular a acurácia pois o dataset é balanceado.

📌 Interpretação: A acurácia geral do método foi praticamente o mesmo para ambas as linguas. Na lingua inglesa observamos mais casos de falsos positivos (22%), já na lingua portuguesa observamos mais casos de falsos negativos (14%).

Essa abordagem é boa para ser utilizada como baseline pois quase todas as abordagens tradicionais de Machine Learning para a tarefa de análise de sentimentos necessitam de tempo para desenvolvimento, treino, validação e sustentação de modelos.

RESULTADO FINAL

Avaliamos o desempenho de ambas as abordagens para determinar se o uso do LLM justificou-se em comparação com a abordagem mais simples para a execução da tarefa de análise de sentimentos.

📌 Interpretação: A acurácia geral foi consideravelmente maior para o modelo Llama2 em ambas as línguas, mesmo sendo treinado principalmente em dados da língua inglesa.

CONCLUSÃO E DISCUSSÃO

Os avanços tecnológicos na área são verdadeiramente impressionantes e evidenciam a rápida evolução da inteligência artificial. É importante estarmos sempre atentos a essas mudanças, pois a área de LLMs está em constante crescimento e melhorias significativas são desenvolvidas diariamente.

Em meio a tantos avanços, também é importante reconhecer as limitações desses modelos. Um dos desafios é o corte de conhecimento (knowledge cutoffs), o que significa que o modelo é treinado até uma determinada data, como 2022, portanto não possui conhecimento sobre eventos ou desenvolvimentos que ocorreram após essa data. Além disso, os LLMs estão sujeitos a “hallucinations”, ou seja, podem inventar informações em um tom muito confiante, o que pode levar a resultados imprecisos ou até mesmo prejudiciais.

Outras limitações incluem restrições no input e output dos modelos, o que pode tornar difícil lidar com grandes volumes de dados ou fornecer resultados completos de uma só vez. Além disso, os LLMs geralmente não funcionam bem com dados estruturados, como tabelas, e podem reproduzir vieses e toxicidade presentes na sociedade, o que levanta preocupações éticas e sociais importantes.

Portanto, enquanto enquanto exploramos esse vasto campo das redes neurais, é essencial abordar essas limitações e desenvolver soluções que permitam o uso ético e responsável dessas poderosas ferramentas de IA.

SOBRE O AUTOR

Me chamo Fellipe Gomes, sou formado em estatística e atuo como cientista de dados desde 2018. Compartilho meus estudos e evolução por meio de artigos, tutoriais e projetos de código aberto. Se quiser saber mais sobre meu trabalho, sinta-se à vontade para entrar em contato através das minhas redes sociais LinkedIn, GitHub e Kaggle.

REFERÊNCIAS

--

--