Fine-tuning - Personalizando Modelos de IA

📚 Aula 07 de 15
⏱️ 40 min
🔢 Módulo 3
📅 2025-08-26
Progresso do Curso 42.9% completo

🎯 Fine-tuning: O Segredo dos Modelos Personalizados

🚀

Imagine ter um modelo de IA que conhece exatamente seu negócio!

Fine-tuning é o processo de pegar um modelo pré-treinado e especializar ele nos seus dados específicos.

Nesta aula, você vai aprender a criar modelos únicos que falam a linguagem do seu negócio e resolvem problemas específicos!

🤔 O que é Fine-tuning?

Fine-tuning é como dar aulas particulares para um modelo de IA que já é inteligente. Em vez de treinar do zero, você pega um modelo que já sabe muito e ensina ele coisas específicas do seu domínio.

🧠 Analogia Simples

Imagine que você contrata um médico formado (modelo pré-treinado) e ele faz uma especialização em cardiologia (fine-tuning com dados cardíacos). Ele já sabia medicina, mas agora é expert no seu caso específico!

❌ Treino do Zero

  • Milhões de exemplos necessários
  • Semanas/meses de treino
  • Hardware muito caro
  • Expertise profunda necessária
  • Resultados incertos

✅ Fine-tuning

  • Centenas/milhares de exemplos
  • Horas/dias de treino
  • GPU doméstica suficiente
  • Processo simplificado
  • Resultados previsíveis

🎭 Tipos de Fine-tuning

🔧 Full Fine-tuning

O que é: Ajusta todos os parâmetros do modelo

Quando usar: Muitos dados disponíveis

Recursos: GPU potente necessária

Resultado: Máxima personalização

❄️ Frozen Features

O que é: Congela camadas e treina só o final

Quando usar: Classificação simples

Recursos: Muito baixo

Resultado: Rápido e básico

💡 Nossa Recomendação

Para a maioria dos casos, use LoRA (Parameter-Efficient). É o melhor custo-benefício: qualidade alta com recursos baixos!

🎯 Casos de Uso Reais

🏥 Chatbot Médico

Problema: ChatGPT genérico para consultas médicas

Solução: Fine-tune com literatura médica

Resultado: Respostas precisas e confiáveis

⚖️ Análise Jurídica

Problema: IA não entende termos legais

Solução: Treino com documentos jurídicos

Resultado: Assistente legal especializado

🛍️ E-commerce

Problema: Descrições genéricas de produtos

Solução: Fine-tune com catálogo da empresa

Resultado: Descrições no tom da marca

📚 Educação

Problema: Explicações não adaptadas ao nível

Solução: Treino com material pedagógico

Resultado: Tutor personalizado

📊 Preparação dos Dados

📋 Requisitos Básicos

Classificação de Texto 500-1000 exemplos por classe
Geração de Texto 1000-5000 pares pergunta-resposta
Classificação de Imagem 100-500 imagens por categoria
Geração de Imagem 50-200 imagens do estilo desejado

✨ Dicas para Dados de Qualidade

🎯
Relevância: Dados devem ser representativos do uso real
⚖️
Balanceamento: Distribua exemplos uniformemente entre classes
Qualidade: Melhor ter 100 exemplos perfeitos que 1000 ruins
🔄
Diversidade: Inclua variações e casos extremos

🚀 Projeto: Fine-tuning para Análise de Sentimentos

Vamos criar um modelo personalizado para analisar sentimentos de reviews de produtos brasileiros!

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from transformers import (
    AutoTokenizer, 
    AutoModelForSequenceClassification,
    TrainingArguments, 
    Trainer,
    DataCollatorWithPadding
)
import torch
from datasets import Dataset
import json
from datetime import datetime
import os

class BrazilianSentimentAnalyzer:
    def __init__(self, model_name="neuralmind/bert-base-portuguese-cased"):
        """Inicializa o sistema de fine-tuning"""
        print("🤖 Inicializando Sistema de Fine-tuning...")
        
        self.model_name = model_name
        self.tokenizer = AutoTokenizer.from_pretrained(model_name)
        self.model = None
        self.trainer = None
        
        # Configuração de labels
        self.id2label = {0: "NEGATIVO", 1: "NEUTRO", 2: "POSITIVO"}
        self.label2id = {"NEGATIVO": 0, "NEUTRO": 1, "POSITIVO": 2}
        
        print(f"✅ Modelo base carregado: {model_name}")
    
    def create_sample_dataset(self):
        """Cria um dataset de exemplo com reviews brasileiros"""
        
        sample_data = [
            # Reviews Positivos
            ("Produto incrível, superou todas as expectativas! Recomendo muito!", "POSITIVO"),
            ("Excelente qualidade, chegou rápido e bem embalado. Nota 10!", "POSITIVO"),
            ("Adorei a compra! Produto exatamente como descrito, muito satisfeito.", "POSITIVO"),
            ("Melhor investimento que fiz este ano! Funciona perfeitamente.", "POSITIVO"),
            ("Atendimento espetacular e produto de primeira linha. Parabéns!", "POSITIVO"),
            ("Chegou antes do prazo e com qualidade excepcional. Voltarei a comprar!", "POSITIVO"),
            ("Produto maravilhoso, minha família toda adorou! Super recomendo.", "POSITIVO"),
            ("Qualidade premium pelo preço justo. Estou muito feliz com a compra!", "POSITIVO"),
            ("Funciona exatamente como prometido. Produto de excelente qualidade!", "POSITIVO"),
            ("Superou minhas expectativas! Produto top, entrega rápida.", "POSITIVO"),
            
            # Reviews Neutros
            ("Produto ok, nada excepcional mas cumpre o que promete.", "NEUTRO"),
            ("Chegou no prazo, qualidade razoável. Atende às necessidades básicas.", "NEUTRO"),
            ("Produto mediano, tem pontos positivos e negativos. Regular.", "NEUTRO"),
            ("Funciona bem, mas poderia ter mais funcionalidades pelo preço.", "NEUTRO"),
            ("Qualidade aceitável, sem grandes surpresas positivas ou negativas.", "NEUTRO"),
            ("Produto comum, nada demais. Serve para o básico.", "NEUTRO"),
            ("Entrega foi ok, produto dentro do esperado. Nem bom nem ruim.", "NEUTRO"),
            ("Cumpre sua função básica, mas não impressiona. Mediano.", "NEUTRO"),
            ("Produto regular, tem prós e contras. Aceitável pelo preço.", "NEUTRO"),
            ("Funciona como deveria, sem grandes emoções. Produto padrão.", "NEUTRO"),
            
            # Reviews Negativos
            ("Produto horrível, não funcionou nem um dia! Não recomendo!", "NEGATIVO"),
            ("Pior compra que já fiz! Qualidade péssima e atendimento terrível.", "NEGATIVO"),
            ("Chegou com defeito e o suporte não resolve. Muito frustrado!", "NEGATIVO"),
            ("Produto completamente diferente do anunciado. Me senti enganado!", "NEGATIVO"),
            ("Péssima qualidade, quebrou logo no primeiro uso. Dinheiro jogado fora!", "NEGATIVO"),
            ("Atendimento ao cliente pessimo! Produto veio errado e não trocam.", "NEGATIVO"),
            ("Não funcionou como prometido. Muito decepcionado com a compra.", "NEGATIVO"),
            ("Produto de qualidade duvidosa, não vale o dinheiro investido.", "NEGATIVO"),
            ("Chegou danificado e demorou semanas para entregar. Experiência ruim!", "NEGATIVO"),
            ("Propaganda enganosa! Produto não tem metade das funcionalidades prometidas.", "NEGATIVO"),
            
            # Mais variações...
            ("Este produto mudou minha vida! Qualidade incomparável!", "POSITIVO"),
            ("Bom produto, mas nada extraordinário. Cumpre sua função.", "NEUTRO"),
            ("Total perda de dinheiro! Produto não funciona direito.", "NEGATIVO"),
            ("Estou impressionado com a qualidade! Superou expectativas!", "POSITIVO"),
            ("Produto mediano, serve para emergência mas não é o ideal.", "NEUTRO"),
            ("Péssimo! Não comprem este produto, é uma enganação!", "NEGATIVO"),
            ("Incrível! Melhor compra que já fiz online! 5 estrelas!", "POSITIVO"),
            ("Produto ok para o preço. Nada de especial mas funciona.", "NEUTRO"),
            ("Qualidade muito abaixo do esperado. Não recomendo!", "NEGATIVO"),
            ("Fantástico! Produto chegou perfeito e funciona maravilhosamente!", "POSITIVO")
        ]
        
        # Converter para DataFrame
        df = pd.DataFrame(sample_data, columns=['texto', 'sentimento'])
        
        # Adicionar label numérico
        df['label'] = df['sentimento'].map(self.label2id)
        
        print(f"📊 Dataset criado com {len(df)} exemplos:")
        print(df['sentimento'].value_counts())
        
        return df
    
    def load_custom_dataset(self, csv_path):
        """Carrega dataset personalizado de um CSV"""
        try:
            df = pd.read_csv(csv_path)
            
            # Verificar se as colunas necessárias existem
            required_cols = ['texto', 'sentimento']
            if not all(col in df.columns for col in required_cols):
                raise ValueError(f"CSV deve conter as colunas: {required_cols}")
            
            # Converter sentimentos para labels numéricos
            df['label'] = df['sentimento'].map(self.label2id)
            
            # Remover linhas com labels inválidos
            df = df.dropna(subset=['label'])
            df['label'] = df['label'].astype(int)
            
            print(f"📁 Dataset carregado de {csv_path}")
            print(f"📊 {len(df)} exemplos encontrados:")
            print(df['sentimento'].value_counts())
            
            return df
            
        except Exception as e:
            print(f"❌ Erro ao carregar dataset: {e}")
            print("📊 Usando dataset de exemplo...")
            return self.create_sample_dataset()
    
    def prepare_dataset(self, df):
        """Prepara o dataset para treinamento"""
        print("🔄 Preparando dataset...")
        
        # Dividir em treino e validação
        train_df, val_df = train_test_split(
            df, 
            test_size=0.2, 
            random_state=42, 
            stratify=df['label']
        )
        
        # Converter para datasets do Hugging Face
        train_dataset = Dataset.from_pandas(train_df)
        val_dataset = Dataset.from_pandas(val_df)
        
        # Tokenizar
        def tokenize_function(examples):
            return self.tokenizer(
                examples['texto'], 
                truncation=True, 
                padding=True,
                max_length=512
            )
        
        train_dataset = train_dataset.map(tokenize_function, batched=True)
        val_dataset = val_dataset.map(tokenize_function, batched=True)
        
        print(f"✅ Dataset preparado:")
        print(f"   📚 Treino: {len(train_dataset)} exemplos")
        print(f"   🧪 Validação: {len(val_dataset)} exemplos")
        
        return train_dataset, val_dataset
    
    def setup_model_for_training(self):
        """Configura o modelo para fine-tuning"""
        print("🎯 Configurando modelo para treinamento...")
        
        self.model = AutoModelForSequenceClassification.from_pretrained(
            self.model_name,
            num_labels=3,  # NEGATIVO, NEUTRO, POSITIVO
            id2label=self.id2label,
            label2id=self.label2id
        )
        
        print("✅ Modelo configurado para 3 classes de sentimento")
    
    def train_model(self, train_dataset, val_dataset, output_dir="./fine_tuned_model"):
        """Executa o fine-tuning"""
        print("🚀 Iniciando Fine-tuning...")
        
        # Configurações de treinamento
        training_args = TrainingArguments(
            output_dir=output_dir,
            learning_rate=2e-5,
            per_device_train_batch_size=8,
            per_device_eval_batch_size=8,
            num_train_epochs=3,
            weight_decay=0.01,
            logging_dir=f'{output_dir}/logs',
            logging_steps=10,
            evaluation_strategy="epoch",
            save_strategy="epoch",
            load_best_model_at_end=True,
            metric_for_best_model="eval_loss",
            greater_is_better=False,
            report_to=None,  # Desabilita wandb
            save_total_limit=2
        )
        
        # Data collator
        data_collator = DataCollatorWithPadding(tokenizer=self.tokenizer)
        
        # Configurar trainer
        self.trainer = Trainer(
            model=self.model,
            args=training_args,
            train_dataset=train_dataset,
            eval_dataset=val_dataset,
            tokenizer=self.tokenizer,
            data_collator=data_collator,
        )
        
        # Treinar!
        print("⚡ Iniciando treinamento...")
        start_time = datetime.now()
        
        self.trainer.train()
        
        end_time = datetime.now()
        duration = end_time - start_time
        
        print(f"🎉 Treinamento concluído!")
        print(f"⏱️ Tempo total: {duration}")
        
        # Salvar modelo
        self.trainer.save_model()
        self.tokenizer.save_pretrained(output_dir)
        
        print(f"💾 Modelo salvo em: {output_dir}")
        
        return self.trainer.evaluate()
    
    def test_model(self, texts):
        """Testa o modelo fine-tuned com novos textos"""
        print("🧪 Testando modelo personalizado...")
        
        if not self.model or not self.trainer:
            print("❌ Modelo não foi treinado ainda!")
            return
        
        # Tokenizar textos
        inputs = self.tokenizer(texts, truncation=True, padding=True, return_tensors="pt")
        
        # Fazer predições
        with torch.no_grad():
            outputs = self.model(**inputs)
            predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
        
        # Processar resultados
        results = []
        for i, text in enumerate(texts):
            pred_probs = predictions[i].numpy()
            pred_class = np.argmax(pred_probs)
            pred_label = self.id2label[pred_class]
            confidence = pred_probs[pred_class]
            
            results.append({
                'texto': text,
                'sentimento_predito': pred_label,
                'confianca': float(confidence),
                'probabilidades': {
                    'NEGATIVO': float(pred_probs[0]),
                    'NEUTRO': float(pred_probs[1]),
                    'POSITIVO': float(pred_probs[2])
                }
            })
        
        return results
    
    def compare_with_generic_model(self, texts):
        """Compara modelo personalizado com genérico"""
        print("🆚 Comparando modelos...")
        
        # Modelo genérico
        from transformers import pipeline
        generic_classifier = pipeline(
            "sentiment-analysis", 
            model="cardiffnlp/twitter-roberta-base-sentiment-latest"
        )
        
        # Modelo personalizado
        custom_results = self.test_model(texts)
        
        print("\n" + "="*80)
        print("📊 COMPARAÇÃO: MODELO GENÉRICO vs PERSONALIZADO")
        print("="*80)
        
        for i, text in enumerate(texts):
            print(f"\n📝 Texto: '{text}'")
            
            # Resultado genérico
            generic_result = generic_classifier(text)[0]
            print(f"🤖 Genérico: {generic_result['label']} ({generic_result['score']:.3f})")
            
            # Resultado personalizado
            custom_result = custom_results[i]
            print(f"🎯 Personalizado: {custom_result['sentimento_predito']} ({custom_result['confianca']:.3f})")
            
            print("-" * 40)
    
    def save_training_report(self, eval_results, output_dir):
        """Salva relatório do treinamento"""
        report = {
            'model_name': self.model_name,
            'training_completed_at': datetime.now().isoformat(),
            'evaluation_results': eval_results,
            'label_mapping': self.id2label,
            'training_config': {
                'epochs': 3,
                'learning_rate': 2e-5,
                'batch_size': 8
            }
        }
        
        report_path = os.path.join(output_dir, 'training_report.json')
        with open(report_path, 'w', encoding='utf-8') as f:
            json.dump(report, f, indent=2, ensure_ascii=False)
        
        print(f"📋 Relatório salvo: {report_path}")

# Exemplo de uso completo
if __name__ == "__main__":
    print("🎯 INICIANDO FINE-TUNING DE ANÁLISE DE SENTIMENTOS")
    print("="*60)
    
    # Inicializar sistema
    analyzer = BrazilianSentimentAnalyzer()
    
    # Carregar dados (use seu CSV ou dataset de exemplo)
    # df = analyzer.load_custom_dataset("meus_reviews.csv")  # Seu CSV
    df = analyzer.create_sample_dataset()  # Dataset de exemplo
    
    # Preparar dataset
    train_dataset, val_dataset = analyzer.prepare_dataset(df)
    
    # Configurar modelo
    analyzer.setup_model_for_training()
    
    # Treinar modelo
    eval_results = analyzer.train_model(train_dataset, val_dataset)
    
    # Salvar relatório
    analyzer.save_training_report(eval_results, "./fine_tuned_model")
    
    # Testar com novos exemplos
    test_texts = [
        "Este produto é simplesmente fantástico! Melhor compra do ano!",
        "Produto chegou quebrado e o atendimento é péssimo. Não recomendo!",
        "Produto ok, nada demais mas funciona. Preço justo.",
        "Adorei! Superou todas as minhas expectativas. 5 estrelas!",
        "Muito decepcionado com a qualidade. Não vale o dinheiro."
    ]
    
    print("\n" + "="*60)
    print("🧪 TESTANDO MODELO PERSONALIZADO")
    print("="*60)
    
    results = analyzer.test_model(test_texts)
    
    for result in results:
        print(f"\n📝 '{result['texto']}'")
        print(f"🎯 Sentimento: {result['sentimento_predito']} ({result['confianca']:.3f})")
        print(f"📊 Probabilidades:")
        for sentiment, prob in result['probabilidades'].items():
            print(f"   {sentiment}: {prob:.3f}")
    
    # Comparar com modelo genérico
    print("\n" + "="*60)
    print("🆚 COMPARAÇÃO COM MODELO GENÉRICO")
    print("="*60)
    
    analyzer.compare_with_generic_model(test_texts)
    
    print(f"\n🎉 FINE-TUNING CONCLUÍDO COM SUCESSO!")
    print(f"💾 Modelo salvo em: ./fine_tuned_model")
    print(f"🚀 Agora você tem um modelo personalizado para análise de sentimentos!")

🎉 O que você acabou de criar:

  • ✅ Sistema completo de fine-tuning
  • ✅ Modelo personalizado para sentimentos BR
  • ✅ Comparação com modelos genéricos
  • ✅ Sistema de avaliação automática
  • ✅ Relatórios de treinamento
  • ✅ Pipeline de teste robusto

⚙️ Hiperparâmetros e Otimização

📚 Learning Rate

O que é: Velocidade de aprendizado

2e-5: Padrão seguro 1e-5: Mais conservador 5e-5: Mais agressivo

Dica: Comece com 2e-5, aumente se for lento, diminua se instável

🏃‍♂️ Epochs

O que é: Quantas vezes ver todos os dados

3: Padrão 5: Mais dados 1: Poucos dados

Dica: Monitore a validação, pare se começar a piorar

📦 Batch Size

O que é: Quantos exemplos por vez

8: GPU pequena 16: GPU média 32: GPU potente

Dica: Maior = mais estável, mas usa mais memória

⚖️ Weight Decay

O que é: Previne overfitting

0.01: Padrão 0.1: Mais regularização 0.001: Menos regularização

Dica: Aumente se modelo decorar os dados

📊 Avaliando seu Modelo

🎯 Accuracy

Percentual de acertos geral

Acertos / Total × 100

Bom: > 85%

🔍 Precision

Dos que disse que era X, quantos eram realmente X

Verdadeiros Positivos / (VP + Falsos Positivos)

Bom: > 80%

📈 Recall

Dos que eram X, quantos conseguiu identificar

Verdadeiros Positivos / (VP + Falsos Negativos)

Bom: > 80%

⚖️ F1-Score

Média harmônica entre Precision e Recall

2 × (Precision × Recall) / (Precision + Recall)

Bom: > 80%

💡 Como Interpretar os Resultados

Accuracy alta, Loss baixa ✅ Modelo excelente!
Treino bom, Validação ruim ⚠️ Overfitting - mais dados ou regularização
Ambos ruins ❌ Underfitting - mais epochs ou learning rate
Melhora lenta 🔄 Aumentar learning rate

💎 Melhores Práticas

📊 Dados

  • Qualidade > Quantidade
  • Balance as classes
  • Validação representativa
  • Limpe dados inconsistentes

🎯 Treinamento

  • Comece conservador
  • Monitore overfitting
  • Use early stopping
  • Salve checkpoints

🧪 Testes

  • Teste com dados não vistos
  • Casos extremos
  • Compare com baseline
  • Métricas relevantes ao negócio

🚀 Deploy

  • Versione seus modelos
  • Monitore performance
  • Mantenha dados atualizados
  • Retreine periodicamente

💰 Oportunidades de Negócio

🏥 Saúde

Aplicação: Análise de prontuários médicos

Valor: R$ 50.000 - R$ 200.000 por projeto

Exemplo: Classificar gravidade de casos

🏢 Empresarial

Aplicação: Chatbots especializados

Valor: R$ 20.000 - R$ 100.000 por projeto

Exemplo: Atendimento específico do setor

📱 Marketing

Aplicação: Análise de sentimentos de marca

Valor: R$ 10.000 - R$ 50.000 mensais

Exemplo: Monitor de reputação online

📚 Educação

Aplicação: Tutores IA personalizados

Valor: R$ 30.000 - R$ 150.000 por instituição

Exemplo: Assistente pedagógico especializado

🎯 Parabéns! Você Dominou Fine-tuning!

Você acabou de aprender uma das habilidades mais valiosas em IA: personalizar modelos para problemas específicos!

O que você conquistou hoje:

  • ✅ Compreensão completa do Fine-tuning
  • ✅ Sistema profissional de treinamento
  • ✅ Modelo personalizado funcionando
  • ✅ Técnicas de otimização avançadas
  • ✅ Métodos de avaliação robustos
  • ✅ Visão comercial das oportunidades

Na próxima aula, vamos aprender a processar e analisar documentos com IA, extraindo insights valiosos de PDFs, contratos e relatórios!

"Com Fine-tuning, você não usa IA - você cria IA personalizada"

- Isaque Victor

🎯 Teste Seus Conhecimentos