Aktywne uczenie się adnotacji danych: przewodnik Gemini + Adala

Adala Framework — Aktywne uczenie się adnotacji danych

Aktywne uczenie się zmienia sposób, w jaki szkolimy AI modele poprzez inteligentny wybór najcenniejszych danych do adnotacji. W połączeniu z potężne LLM lubić Google Bliźnięta, tworzy wydajne procesy adnotacji, które redukują nakład pracy ręcznej, a jednocześnie zapewniają wysoką jakość danych.

W tym przewodniku dowiesz się, jak budować takie potoki, korzystając z infrastruktury Adala – potężnego, choć niedostatecznie wykorzystywanego narzędzia do autonomicznego etykietowania danych.

Wdrożymy klasyfikator objawów medycznych wykorzystujący Gemini's możliwości poprzez ustrukturyzowany, aktywny proces uczenia się.

Zrozumienie aktywnego uczenia się w adnotacjach danych

Zrozumienie aktywnego uczenia się w adnotacjach danych

Aktywne uczenie się mierzy się z kluczowym wyzwaniem uczenia nadzorowanego : pozyskiwaniem dużych ilości oznaczonych danych. Zamiast losowo wybierać punkty danych do adnotacji, algorytmy aktywnego uczenia się identyfikują najbardziej informatywne próbki, które w największym stopniu przyczynią się do ulepszenia modelu.

Dlaczego aktywne uczenie się jest ważne:

Zmniejsza koszty adnotacji, koncentrując wysiłek ludzki tam, gdzie jest to najbardziej potrzebne.
Poprawia dokładność modelu z mniejszą liczbą oznaczonych przykładów.
Rozwiązuje problem nierównowagi klasowej poprzez nadanie priorytetu niedoreprezentowanym kategoriom.
Tworzy ciągłą pętlę uczenia się pomiędzy modelem a adnotator.

Platforma Adala wprowadza te korzyści do procesów produkcyjnych, oferując modułowe komponenty, które usprawniają proces aktywnego uczenia się . Zanim przejdziemy do implementacji, przyjrzyjmy się, co sprawia, że ​​Adala jest szczególnie odpowiednia do integracji z nowoczesnymi systemami LLM, takimi jak Google Gemini.

Czym jest Adala? Wprowadzenie do Framework

Adala (Autonomous Data Labeling Agent) to platforma open source zaprojektowana specjalnie do wdrażania wyspecjalizowanych agentów do przetwarzania danych . W przeciwieństwie do tradycyjnych narzędzi do adnotacji, Adala wykorzystuje podejście oparte na agentach, które łączy:

Architektura oparta na umiejętnościach:Zdefiniuj konkretne możliwości, których potrzebuje Twój agent adnotacji.
Elastyczność środowiska wykonawczego:Możliwość przełączania się między różnymi LLM lub niestandardowymi środowiskami wykonawczymi.
Połączenia środowiskowe:Interakcja z różnymi źródłami danych.
Wbudowane pętle uczenia się:Szkolenie agentów w celu zapewnienia im możliwości doskonalenia się w miarę upływu czasu.

Przyglądając się przykładowi szybkiego startu Adala, możemy zobaczyć, jak struktura klasyfikacji sentymentów jest skonstruowana :

pyton

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)

Na potrzeby naszego zadania klasyfikacji objawów medycznych dostosujemy tę architekturę, aby zintegrować ją z Google Gemini, jednocześnie wdrażając niestandardową strategię aktywnego uczenia się.

Konfigurowanie środowiska

Niech's zacznij od zainstalowania Adala i wymaganych zależności:

pyton

# 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

Będziemy musieli również sklonować repozytorium, aby uzyskać bezpośredni dostęp do jego komponentów:

pyton

# 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

Integracja Google Gemini jako niestandardowego adnotatora

W przeciwieństwie do pierwotnej implementacji, która wykorzystywała podstawowy wrapper wokół Google Gemini, zbudujemy bardziej rozbudowany adnotator , zgodny ze wzorcami projektowymi Adala. Dzięki temu nasze rozwiązanie będzie łatwiejsze w utrzymaniu i rozszerzaniu.

Najpierw musimy skonfigurować Generative Google AI klient:

pyton

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)

Teraz utworzymy niestandardowy adnotator, rozszerzając Adala's Klasa BaseAnnotator:

pyton

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

Ta implementacja zapewnia znaczące udoskonalenia w stosunku do oryginału:

  1. Następuje prawidłowe dziedziczenie klas z Adala's BazaAnnotator
  2. Implementuje prywatne metody pomocnicze do szybkiego budowania i analizy odpowiedzi
  3. Używa strukturyzowanego obsługa błędów i wpisz wskazówki
  4. Zapewnia kompletną dokumentację

Budowanie kanału klasyfikacji objawów

Stwórzmy zbiór danych objawów medycznych na potrzeby naszego zadania klasyfikacyjnego. W przeciwieństwie do pierwotnej implementacji, użyjemy bardziej zróżnicowanego zbioru danych ze zrównoważoną reprezentacją w poszczególnych kategoriach:

pyton

# 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]

Wdrażanie zaawansowanych strategii aktywnego uczenia się

Oryginalna implementacja używała prostego mechanizmu punktacji priorytetów. Ulepszymy go za pomocą wielu strategii, aby zademonstrować Adala's elastyczność:

pyton

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)

Teraz pozwól's wdrożyć naszą ulepszoną pętlę aktywnego uczenia się:

pyton

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()

Uruchamianie potoku typu end-to-end

Teraz możemy uruchomić nasz kompletny proces aktywnego uczenia:

pyton

# 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}")

Zastosowania praktyczne i rozszerzenia

Ten rodzaj rurociągu ma wiele praktycznych zastosowań wykraczających poza klasyfikację objawów medycznych:

1. Moderacja treści

Priorytet treść zgłoszona przez użytkownika
Skup się na kategoriach wysokiego ryzyka
Dostosuj progi pewności na podstawie zawartości

2. Analiza opinii klientów

Zidentyfikuj pilne problemy klientów
Wychwytywanie pojawiających się problemów z produktem
Przekaż opinię odpowiednim zespołom

3. Przetwarzanie dokumentacji badań klinicznych

Wyodrębnij raporty zdarzeń niepożądanych
Klasyfikuj wyniki zgłaszane przez pacjentów
Nadaj priorytet sygnałom bezpieczeństwa

Możesz rozszerzyć tę implementację poprzez:

Dodanie pętli sprzężenia zwrotnego w celu ulepszenia adnotatora
Wdrażanie różnych strategii selekcji (różnorodność, klastrowanie)
Tworzenie interfejsu internetowego do walidacji z udziałem człowieka
Włączanie klasyfikacja wieloetykietowa w przypadku złożonych objawów

Wniosek

Integracja Adala i Google Gemini zapewnia potężne ramy do tworzenia inteligentnych procesów adnotacji. Wykorzystując strategie aktywnego uczenia się , możemy radykalnie zmniejszyć wymagany nakład pracy ręcznej, zachowując jednocześnie wysoką jakość adnotacji.

Przedstawione w tym samouczku modułowe wzorce projektowe pozwalają na łatwą adaptację do różnych domen i zadań adnotacji.

Osoby zainteresowane dalszym zgłębianiem tematu mogą skorzystać z repozytorium GitHub Adala, które oferuje dodatkowe przykłady i dokumentację rozszerzającą te koncepcje na bardziej złożone scenariusze adnotacji.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Pola oznaczone * są obowiązkowe.

Ta strona używa Akismet do redukcji spamu. Dowiedz się, jak przetwarzane są dane z Twoich komentarzy.

Dołącz Aimojo Plemię!

Dołącz do ponad 76,000 XNUMX członków i otrzymuj co tydzień fachowe porady! 
???? BONUS: Odbierz nasze 200 dolarówAI „Zestaw narzędzi Mastery Toolkit” GRATIS po rejestracji!

Trendy AI Narzędzia
SzkołaAI

Zapewnij każdemu uczniowi opiekę AI korepetytor i każdy nauczyciel na żywo wgląd w naukę Klasa K-12 AI platforma dla nauczycieli, szkół i okręgów

Omnisend

Odzyskaj utracone koszyki i zwiększ przychody dzięki AI Zasilany marketing e-mailowy Kompleksowa platforma retencji dla marek e-commerce

Dubbingowanie AI 

Zmień dowolny film w wielojęzyczne doświadczenie. Dotrzyj do odbiorców na całym świecie bez ponownego nagrywania.

Mozify AI

Zamień jedno zdjęcie produktu w gotową reklamę wideo, materiał filmowy i ostateczną edycję w jednym miejscu pracy

Hailuo AI

Twórz filmy 2K z natywnym dźwiękiem stereo z tekstu, obrazów, wideo i dźwięku w jednym miejscu MiniMax's AI generator wideo do reklam, e-commerce i krótkich treści

© Copyright 2023 - 2026 | Zostań AI Pro | Wykonane z ♥