Aprendizado ativo para anotação de dados: Guia Gemini + Adala

Estrutura Adala - Aprendizado Ativo para Anotação de Dados

A aprendizagem ativa transforma a forma como treinamos AI modelos selecionando de forma inteligente os dados mais valiosos para anotação. Quando combinado com LLMs poderosos como Google Gêmeos, ele cria pipelines de anotação eficientes que reduzem o esforço manual e, ao mesmo tempo, mantêm alta qualidade dos dados.

Este guia explora como construir esses pipelines usando o framework Adala – uma ferramenta poderosa, porém subutilizada, para rotulagem autônoma de dados.

Implementaremos um classificador de sintomas médicos que aproveita o Gemini's capacidades por meio de um fluxo de trabalho de aprendizagem ativa estruturado.

Compreendendo o aprendizado ativo para anotação de dados

Compreendendo o aprendizado ativo para anotação de dados

A aprendizagem ativa aborda o principal desafio da aprendizagem supervisionada : a obtenção de grandes quantidades de dados rotulados. Em vez de selecionar aleatoriamente pontos de dados para anotação, os algoritmos de aprendizagem ativa identificam as amostras mais informativas que mais contribuirão para a melhoria do modelo.

Por que a aprendizagem ativa é importante:

Reduz os custos de anotação concentrando o esforço humano onde é mais importante.
Melhora precisão do modelo com menos exemplos rotulados.
Aborda o desequilíbrio de classes priorizando categorias sub-representadas.
Cria um ciclo de aprendizagem contínuo entre o modelo e anotador.

O framework Adala traz esses benefícios para os fluxos de trabalho de produção, fornecendo componentes modulares que otimizam o processo de aprendizagem ativa . Antes de mergulharmos na implementação, vamos examinar o que torna o Adala particularmente adequado para integração com plataformas de aprendizagem baseada em aprendizagem (LLMs) modernas, como o Google Gemini.

O que é Adala? Uma Introdução ao Framework

Adala (Autonomous Data Labeling Agent) é uma estrutura de código aberto projetada especificamente para implementar agentes especializados para processamento de dados . Ao contrário das ferramentas de anotação tradicionais, o Adala adota uma abordagem baseada em agentes que combina:

Arquitetura baseada em habilidades: Defina recursos específicos que seu agente de anotação precisa.
Flexibilidade de tempo de execução: Alterne entre diferentes LLMs ou tempos de execução personalizados.
Conexões ambientais: Interaja com diversas fontes de dados.
Loops de aprendizagem integrados: Treine agentes para melhorar ao longo do tempo.

Analisando o exemplo de início rápido do Adala, podemos ver como ele estrutura a classificação de sentimentos :

python

import pandas as pd
from adala.agents import Agent
from adala.environments import StaticEnvironment
from adala.skills import ClassificationSkill
from adala.runtimes import OpenAIChatRuntime
from rich import print

# Train dataset
train_df = pd.DataFrame([
    ["It was the negative first impressions, and then it started working.", "Positive"],
    ["Not loud enough and doesn't turn on like it should.", "Negative"],
    ["I don't know what to say.", "Neutral"],
    ["Manager was rude, but the most important that mic shows very flat frequency response.", "Positive"],
    ["The phone doesn't seem to accept anything except CBR mp3s.", "Negative"],
    ["I tried it before, I bought this device for my son.", "Neutral"],
], columns=["text", "sentiment"])

# Test dataset
test_df = pd.DataFrame([
    "All three broke within two months of use.",
    "The device worked for a long time, can't say anything bad.",
    "Just a random line of text."
], columns=["text"])

agent = Agent(
    # connect to a dataset
    environment=StaticEnvironment(df=train_df),
    # define a skill
    skills=ClassificationSkill(
        name='sentiment',
        instructions="Label text as positive, negative or neutral.",
        labels=["Positive", "Negative", "Neutral"],
        input_template="Text: {text}",
        output_template="Sentiment: {sentiment}"
    ),
    # define runtimes
    runtimes = {
        'openai': OpenAIChatRuntime(model='gpt-4o'),
    },
    teacher_runtimes = {
        'default': OpenAIChatRuntime(model='gpt-4o'),
    },
    default_runtime='openai',
)

agent.learn(learning_iterations=3, accuracy_threshold=0.95)
predictions = agent.run(test_df)

Para nossa tarefa de classificação de sintomas médicos, adaptaremos essa arquitetura para integrar o Google Gemini , implementando simultaneamente uma estratégia de aprendizado ativo personalizada.

Configurando seu ambiente

Deixei's comece instalando o Adala e as dependências necessárias:

python

# Install Adala directly from GitHub
!pip install -q git+https://github.com/HumanSignal/Adala.git

# Verify installation
!pip list | grep adala

# Install additional dependencies
!pip install -q google-generativeai pandas matplotlib numpy

Também precisaremos clonar o repositório para acesso direto aos seus componentes:

python

# Clone the repository for access to source files
!git clone https://github.com/HumanSignal/Adala.git

# Ensure the package is in our Python path
import sys
sys.path.append('./Adala')

# Import key components
from Adala.adala.annotators.base import BaseAnnotator
from Adala.adala.strategies.random_strategy import RandomStrategy
from Adala.adala.utils.custom_types import TextSample, LabeledSample

Integrando o Google Gemini como um anotador personalizado

Diferentemente da implementação original, que utilizava um wrapper básico em torno do Google Gemini, construiremos um anotador mais robusto que segue os padrões de projeto do Adala. Isso torna nossa solução mais fácil de manter e extensível.

Primeiro, precisamos configurar o Google Generative AI cliente:

python

import google.generativeai as genai
import os

# Set API key from environment or enter manually
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") or getpass("Enter your Gemini API Key: ")
genai.configure(api_key=GEMINI_API_KEY)

Agora, criaremos um anotador personalizado estendendo o Adala's Classe BaseAnnotator:

python

import json
import re
from typing import List, Dict, Any, Optional

class GeminiAnnotator(BaseAnnotator):
    """Custom annotator using Google Gemini for medical symptom classification."""
    
    def __init__(self, 
                 model_name: str = "models/gemini-2.0-flash-lite", 
                 categories: List[str] = None,
                 temperature: float = 0.1):
        """Initialize the Gemini annotator.
        
        Args:
            model_name: The Gemini model to use
            categories: List of valid classification categories
            temperature: Controls randomness in generation (lower = more deterministic)
        """
        self.model = genai.GenerativeModel(
            model_name=model_name,
            generation_config={"temperature": temperature}
        )
        self.categories = categories or ["Cardiovascular", "Respiratory", 
                                         "Gastrointestinal", "Neurological"]
    
    def _build_prompt(self, text: str) -> str:
        """Create a structured prompt for the model.
        
        Args:
            text: The symptom text to classify
            
        Returns:
            A formatted prompt string
        """
        return f"""Classify this medical symptom into one of these categories:
        {', '.join(self.categories)}.
        
        Return JSON format: {{"category": "selected_category", 
        "confidence": 0.XX, "explanation": "brief_reason"}}
        
        SYMPTOM: {text}"""
    
    def _parse_response(self, response: str) -> Dict[str, Any]:
        """Extract structured data from model response.
        
        Args:
            response: Raw text response from Gemini
            
        Returns:
            Dictionary containing parsed fields
        """
        try:
            # Extract JSON from response even if surrounded by text
            json_match = re.search(r'(\{.*\})', response, re.DOTALL)
            result = json.loads(json_match.group(1) if json_match else response)
            return {
                "category": result.get("category", "Unknown"),
                "confidence": result.get("confidence", 0.0),
                "explanation": result.get("explanation", "")
            }
        except Exception as e:
            return {
                "category": "Unknown",
                "confidence": 0.0,
                "explanation": f"Error parsing response: {str(e)}"
            }
    
    def annotate(self, samples: List[TextSample]) -> List[LabeledSample]:
        """Annotate a batch of text samples.
        
        Args:
            samples: List of TextSample objects
            
        Returns:
            List of LabeledSample objects with annotations
        """
        results = []
        for sample in samples:
            prompt = self._build_prompt(sample.text)
            try:
                response = self.model.generate_content(prompt).text
                parsed = self._parse_response(response)
                
                # Create labeled sample with metadata
                labeled_sample = LabeledSample(
                    text=sample.text,
                    labels=parsed["category"],
                    metadata={
                        "confidence": parsed["confidence"],
                        "explanation": parsed["explanation"]
                    }
                )
            except Exception as e:
                # Graceful error handling
                labeled_sample = LabeledSample(
                    text=sample.text,
                    labels="Unknown",
                    metadata={"error": str(e)}
                )
            
            # Store reference to original sample
            labeled_sample._sample = sample
            results.append(labeled_sample)
            
        return results

Esta implementação proporciona melhorias significativas em relação ao original:

  1. Segue a herança de classe apropriada de Adala's BaseAnotador
  2. Implementa métodos auxiliares privados para construção de prompts e análise de respostas
  3. Utiliza estruturado Manipulação de erros e dicas de tipo
  4. Fornece documentação completa

Construindo um pipeline de classificação de sintomas

Vamos criar um conjunto de dados de sintomas médicos para nossa tarefa de classificação. Diferentemente da implementação original, usaremos um conjunto de dados mais diversificado, com representação equilibrada entre as categorias:

python

# Create a more comprehensive dataset
symptom_data = [
    # Cardiovascular symptoms
    "Chest pain radiating to left arm during exercise",
    "Heart palpitations when lying down",
    "Swollen ankles and shortness of breath",
    "Dizziness when standing up quickly",
    
    # Respiratory symptoms
    "Persistent dry cough with occasional wheezing",
    "Shortness of breath when climbing stairs",
    "Coughing up yellow or green mucus",
    "Rapid breathing with chest tightness",
    
    # Gastrointestinal symptoms
    "Stomach cramps and nausea after eating",
    "Burning sensation in upper abdomen",
    "Frequent loose stools with abdominal pain",
    "Yellowing of skin and eyes",
    
    # Neurological symptoms
    "Severe headache with sensitivity to light",
    "Numbness in fingers of right hand",
    "Memory loss and confusion",
    "Tremors in hands when reaching for objects"
]

# Convert to TextSample objects
text_samples = [TextSample(text=text) for text in symptom_data]

Implementando Estratégias Avançadas de Aprendizagem Ativa

A implementação original utilizava um mecanismo simples de pontuação de prioridade. Vamos aprimorá-lo com diversas estratégias para demonstrar o Adala.'s flexibilidade:

python

import numpy as np
from typing import List, Callable

class PrioritizationStrategy:
    """Base class for sample prioritization strategies."""
    
    def score_samples(self, samples: List[TextSample]) -> np.ndarray:
        """Assign priority scores to samples.
        
        Args:
            samples: List of samples to score
            
        Returns:
            Array of scores, higher values indicate higher priority
        """
        raise NotImplementedError("Subclasses must implement this method")
    
    def select(self, samples: List[TextSample], n: int = 1) -> List[TextSample]:
        """Select the top n highest scoring samples.
        
        Args:
            samples: List of samples to select from
            n: Number of samples to select
            
        Returns:
            List of selected samples
        """
        if not samples:
            return []
        
        scores = self.score_samples(samples)
        indices = np.argsort(-scores)[:n]  # Descending order
        return [samples[i] for i in indices]

class KeywordPriority(PrioritizationStrategy):
    """Prioritize samples based on medical urgency keywords."""
    
    def __init__(self, keyword_weights: Dict[str, float]):
        """Initialize with keyword weights.
        
        Args:
            keyword_weights: Dictionary mapping keywords to priority weights
        """
        self.keyword_weights = keyword_weights
    
    def score_samples(self, samples: List[TextSample]) -> np.ndarray:
        scores = np.zeros(len(samples))
        for i, sample in enumerate(samples):
            # Base score
            scores[i] = 0.1
            
            # Add weights for each keyword found
            text_lower = sample.text.lower()
            for keyword, weight in self.keyword_weights.items():
                if keyword in text_lower:
                    scores[i] += weight
        
        return scores

class UncertaintyPriority(PrioritizationStrategy):
    """Prioritize samples based on model uncertainty."""
    
    def __init__(self, model_fn: Callable[[List[TextSample]], List[float]]):
        """Initialize with uncertainty model function.
        
        Args:
            model_fn: Function that returns uncertainty scores for samples
        """
        self.model_fn = model_fn
    
    def score_samples(self, samples: List[TextSample]) -> np.ndarray:
        # Higher uncertainty = higher priority
        return np.array(self.model_fn(samples))

# Create a combined strategy
keyword_weights = {
    "chest": 0.5,
    "pain": 0.4,
    "breathing": 0.4, 
    "dizz": 0.3,
    "head": 0.2,
    "numb": 0.2
}

keyword_strategy = KeywordPriority(keyword_weights)

Agora deixe's implementar nosso ciclo de aprendizagem ativo aprimorado:

python

from matplotlib import pyplot as plt
from IPython.display import clear_output
import time

def run_active_learning_loop(
    samples: List[TextSample],
    annotator: GeminiAnnotator,
    strategy: PrioritizationStrategy,
    iterations: int = 5,
    batch_size: int = 1,
    visualization_interval: int = 1
):
    """Run an active learning loop with visualization.
    
    Args:
        samples: Pool of unlabeled samples
        annotator: Annotation system
        strategy: Sample selection strategy
        iterations: Number of learning iterations
        batch_size: Samples to annotate per iteration
        visualization_interval: How often to update visualizations
    
    Returns:
        List of labeled samples
    """
    labeled_samples = []
    remaining_samples = list(samples)
    
    print("\nStarting Active Learning Loop:")
    
    for i in range(iterations):
        print(f"\n--- Iteration {i+1}/{iterations} ---")
        
        # Filter out already labeled samples
        remaining_samples = [
            s for s in remaining_samples 
            if s not in [getattr(l, '_sample', l) for l in labeled_samples]
        ]
        
        if not remaining_samples:
            print("No more samples to label. Stopping.")
            break
        
        # Select most important samples
        selected = strategy.select(remaining_samples, n=batch_size)
        
        # Annotate selected samples
        newly_labeled = annotator.annotate(selected)
        labeled_samples.extend(newly_labeled)
        
        # Display annotation results
        for sample in newly_labeled:
            print(f"Text: {sample.text}")
            print(f"Category: {sample.labels}")
            print(f"Confidence: {sample.metadata.get('confidence', 0):.2f}")
            explanation = sample.metadata.get('explanation', '')
            print(f"Explanation: {explanation[:100]}..." if len(explanation) > 100 else explanation)
            print()
        
        # Visualize results periodically
        if (i + 1) % visualization_interval == 0:
            visualize_results(labeled_samples)
            
    return labeled_samples

def visualize_results(labeled_samples: List[LabeledSample]):
    """Create visualizations of annotation results.
    
    Args:
        labeled_samples: List of labeled samples to visualize
    """
    if not labeled_samples:
        return
        
    # Extract data
    categories = [s.labels for s in labeled_samples]
    confidence = [s.metadata.get("confidence", 0) for s in labeled_samples]
    texts = [s.text[:30] + "..." for s in labeled_samples]
    
    # Set up plots
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
    
    # Plot 1: Confidence by category
    category_counts = {}
    category_confidence = {}
    
    for cat, conf in zip(categories, confidence):
        if cat not in category_counts:
            category_counts[cat] = 0
            category_confidence[cat] = 0
        category_counts[cat] += 1
        category_confidence[cat] += conf
    
    for cat in category_confidence:
        category_confidence[cat] /= category_counts[cat]
    
    cats = list(category_counts.keys())
    counts = list(category_counts.values())
    avg_conf = list(category_confidence.values())
    
    x = np.arange(len(cats))
    width = 0.35
    
    ax1.bar(x - width/2, counts, width, label='Count')
    ax1.bar(x + width/2, avg_conf, width, label='Avg Confidence')
    ax1.set_xticks(x)
    ax1.set_xticklabels(cats, rotation=45)
    ax1.set_title('Category Distribution and Confidence')
    ax1.legend()
    
    # Plot 2: Individual sample confidence
    sorted_indices = np.argsort(confidence)
    ax2.barh(range(len(texts)), [confidence[i] for i in sorted_indices])
    ax2.set_yticks(range(len(texts)))
    ax2.set_yticklabels([texts[i] for i in sorted_indices])
    ax2.set_title('Sample Confidence')
    ax2.set_xlabel('Confidence')
    
    plt.tight_layout()
    plt.show()

Executando o pipeline de ponta a ponta

Agora podemos executar nosso pipeline completo de aprendizado ativo:

python

# Initialize components
categories = ["Cardiovascular", "Respiratory", "Gastrointestinal", "Neurological"]
annotator = GeminiAnnotator(categories=categories)
strategy = keyword_strategy

# Run the active learning loop
labeled_data = run_active_learning_loop(
    samples=text_samples,
    annotator=annotator,
    strategy=strategy,
    iterations=5,
    visualization_interval=2
)

# Final visualization and analysis
visualize_results(labeled_data)

# Print summary statistics
print("\nAnnotation Summary:")
print(f"Total samples annotated: {len(labeled_data)}")

categories = [s.labels for s in labeled_data]
unique_categories = set(categories)
print(f"Categories found: {len(unique_categories)}")
for category in unique_categories:
    count = categories.count(category)
    print(f"  - {category}: {count} samples ({count/len(labeled_data):.1%})")

avg_confidence = sum(s.metadata.get("confidence", 0) for s in labeled_data) / len(labeled_data)
print(f"Average confidence: {avg_confidence:.2f}")

Aplicações práticas e extensões

Este pipeline tem inúmeras aplicações práticas além da classificação de sintomas médicos:

1. Moderação de conteúdo

Priorizar conteúdo relatado pelo usuário
Foco em categorias de alto risco
Adapte os limites de confiança com base no tipo de conteúdo

2. Análise de Feedback do Cliente

Identificar urgente problemas do cliente
Capturar problemas emergentes de produtos
Encaminhe o feedback para as equipes apropriadas

3. Processamento de Documentos de Ensaios Clínicos

Extrair relatórios de eventos adversos
classificar resultados relatados pelo paciente
Priorizar sinais de segurança

Você pode estender essa implementação por:

Adicionando um loop de feedback para melhoria do anotador
Implementar diferentes estratégias de seleção (diversidade, agrupamento)
Criação de uma interface web para validação humana no circuito
Possibilitando classificação multi-rótulo para sintomas complexos

Conclusão

A integração do Adala e do Google Gemini fornece uma estrutura poderosa para a construção de fluxos de trabalho de anotação inteligentes. Ao aproveitar estratégias de aprendizado ativo , podemos reduzir drasticamente o esforço manual necessário, mantendo anotações de alta qualidade.

Os padrões de design modular demonstrados neste tutorial permitem uma fácil adaptação a diferentes domínios e tarefas de anotação.

Para aqueles interessados ​​em explorar mais a fundo, o repositório Adala no GitHub oferece exemplos e documentação adicionais para estender esses conceitos a cenários de anotação mais complexos.

Deixa um comentário

Seu endereço de e-mail não será publicado. Os campos obrigatórios estão marcados com um *

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados de comentários são processados.

Participe no Aimojo Tribo!

Junte-se a mais de 76,000 membros para receber dicas privilegiadas toda semana! 
🎁 BONUS: Receba nossos $ 200 “AI “Kit de ferramentas de domínio” GRÁTIS ao se inscrever!

Tendência AI Ferramentas
Dreamz.ai

Construa, converse e veja seus contatos privados. AI namorada, com mensagens de vídeo incluídas em todos os planos premium. Sem censura para maiores de 18 anos AI Chat de acompanhamento para adultos que desejam controle total.

Caixa de Fantasia

AI Geração de imagens e vídeos adultos sem renovação automática. Criação de conteúdo NSFW com pagamento por crédito a partir de instruções de texto.

humata

Transforme qualquer documento em informações práticas e instantâneas. O AI Assistente de análise de documentos e PDFs com tecnologia integrada

Iris.ai

AI Base de conhecimento que transforma dados corporativos em inteligência confiável e auditável. Precisão AI para P&D regulamentada e gestão do conhecimento empresarial

Mente

AI Busca bibliográfica avançada que encontra os artigos que outros não encontram. O assistente de pesquisa criado para cientistas, por cientistas.

© Copyright 2023 - 2026 | Torne-se um AI Pro | Feito com ♥