Blog / AI
AI

Feinabstimmung von Gemma 3: Eine Schritt-für-Schritt-Anleitung mit benutzerdefiniertem Q&A-Datensatz

Feinabstimmung von Google Gemma 3 mit benutzerdefinierten Trustpilot-QA-Daten, vom Scraping der Bewertungen bis zur Bereitstellung, mit Bright Data und Unsloth.
29 min lesen
A graphic featuring the logo for 'Gemma 3' over a blue background, surrounded by abstract representations of code snippets and user interface elements, along with icons suggesting security and performance.

Googles neuestes Open-Weight-KI-Modell, Gemma 3, das im März 2025 veröffentlicht wurde, bietet eine beeindruckende Leistung, die mit der vieler proprietärer LLMs vergleichbar ist und gleichzeitig effizient auf Hardware mit begrenzten Ressourcen läuft. Diese Weiterentwicklung der quelloffenen KI funktioniert auf verschiedenen Plattformen und bietet Entwicklern weltweit leistungsstarke Funktionen in einem zugänglichen Format.

In diesem Leitfaden führen wir Sie durch die Feinabstimmung von Gemma 3 anhand eines benutzerdefinierten Frage-Antwort-Datensatzes, der aus Trustpilot-Bewertungen stammt. Wir verwenden Bright Data zum Scrapen von Kundenrezensionen, verarbeiten sie zu strukturierten QA-Paaren und nutzen Unsloth für eine effiziente Feinabstimmung mit minimalem Rechenaufwand. Am Ende werden Sie einen spezialisierten KI-Assistenten erstellt haben, der domänenspezifische Fragen versteht und bereit ist, auf Hugging Face Hub zu hosten.

Lasst uns eintauchen!

Gemma 3 verstehen

Die Gemma-3-Familie von Google wurde im März 2025 mit vier Parametern mit offenem Gewicht – 1B, 4B, 12B und 27B – auf den Markt gebracht, die alle auf einer einzigen GPU laufen sollen.

  • Das Modell 1B ist ein reines Textmodell mit einem 32K-Token-Kontextfenster.
  • Die Modelle 4B, 12B und 27B bieten zusätzlich eine multimodale Eingabe (Text + Bild) und unterstützen ein 128K-Token-Fenster.

Auf der LMArena-Bestenliste für menschliche Präferenzen liegt Gemma 3-27B-IT vor viel größeren Modellen wie Llama 3 405B und DeepSeek-V3 und bietet modernste Qualität, ohne einen Multi-GPU-Footprint zu benötigen.

Ein Streudiagramm, das die Modellleistung (ELO Score) im Vergleich zur Modellgröße (in Milliarden Parametern) zeigt. Das Diagramm zeigt verschiedene Modelle, die durch Punkte gekennzeichnet sind, darunter Gemma 3 27B IT, Qwen 2.5 72B Instruct, Llama 3.3 70B Instruct, Meta Llama 3.1 70B Instruct, und weitere. Die x-Achse stellt die Größe des Modells dar, während die y-Achse den ELO-Wert angibt, wobei bestimmte Punkte aufgrund ihrer Leistung hervorgehoben werden.

Bildquelle: Gemma 3 stellt sich vor

Hauptmerkmale der Gemma 3 Modelle

Hier sind einige bemerkenswerte Merkmale der Gemma 3 Modelle:

  • Multimodale Eingabe (Text + Bild) ist bei den Modellen 4B, 12B und 27B möglich.
  • Langer Kontext – biszu 128K Token (32K beim Modell 1B).
  • Mehrsprachigkeit – mehr als 35 Sprachen werden sofort unterstützt; mehr als 140 Sprachen sind vortrainiert.
  • Quantization-Aware TrainingOffizielle QAT-Versionen reduzieren den Speicherverbrauch erheblich (etwa um das Dreifache), während die hohe Qualität erhalten bleibt.
  • Funktionsaufrufe und strukturierte Ausgabe – Enthält integrierte Unterstützung für die Automatisierung von Aufrufen und den Empfang strukturierter Antworten.
  • Effizienz – Entwickelt für die Ausführung auf einer einzelnen GPU/TPU oder sogar auf Consumer-Geräten, von Handys über Laptops bis hin zu Workstations.
  • Sicherheit (ShieldGemma) – Verfügt über einen integrierten Rahmen zur Filterung von Inhalten.

Warum Fine-Tune Gemma 3?

Bei der Feinabstimmung wird ein vortrainiertes Modell wie Gemma 3 verwendet, um ihm neue Verhaltensweisen für Ihren spezifischen Bereich oder Ihre Aufgabe beizubringen, ohne dass die Zeit und die Kosten für ein Training von Grund auf anfallen. Mit seinem kompakten Design und der multimodalen Unterstützung bei den 4B+-Varianten ist Gemma 3 leichtgewichtig, erschwinglich und kann selbst auf Hardware mit begrenzten Ressourcen feinabgestimmt werden.

Zu den Vorteilen der Feinabstimmung gehören:

  • Domänenspezialisierung – Hilft dem Modell, branchenspezifische Sprache zu verstehen und spezialisierte Aufgaben innerhalb Ihrer Domäne besser zu erfüllen.
  • Wissenserweiterung – Fügt wichtige Fakten und Zusammenhänge hinzu, die in den ursprünglichen Trainingsdaten des Modells nicht enthalten waren.
  • Verfeinerung des Verhaltens – Passt die Reaktion des Modells so an, dass sie dem Ton Ihrer Marke oder dem bevorzugten Ausgabeformat entspricht.
  • Ressourcenoptimierung – Erzielt qualitativ hochwertige Ergebnisse bei deutlich geringerem Einsatz von Rechenressourcen im Vergleich zum Training eines neuen Modells von Grund auf.

Voraussetzungen

Vergewissern Sie sich, bevor Sie mit diesem Lernprogramm beginnen, dass Sie über die folgenden Informationen verfügen:

  • Python 3.9 oder höher ist auf Ihrem System installiert.
  • Grundkenntnisse in der Python-Programmierung.
  • Zugang zu einer Rechenumgebung mit GPU-Unterstützung (z. B. Google Colab, Jupyter Notebook oder Kaggle Notebooks).
  • Verständnis des maschinellen Lernens und der Grundlagen von Large Language Models (LLM).
  • Erfahrung mit einer IDE wie VS Code oder einer ähnlichen IDE.

Sie benötigen auch Zugangsdaten für externe Dienste:

Erstellen eines benutzerdefinierten Datensatzes für die Feinabstimmung

Die Feinabstimmung funktioniert am besten, wenn Ihr Datensatz das Verhalten, das das Modell lernen soll, genau widerspiegelt. Durch die Erstellung eines benutzerdefinierten Datensatzes, der auf Ihren speziellen Anwendungsfall zugeschnitten ist, können Sie die Leistung des Modells erheblich verbessern. Denken Sie an die klassische Regel: “Garbage in, garbage out”. Deshalb ist es so wichtig, Zeit in die Vorbereitung des Datensatzes zu investieren.

Ein qualitativ hochwertiger Datensatz sollte:

  • Passen Sie Ihren spezifischen Anwendungsfall an – Je besser Ihr Datensatz mit Ihrer Zielanwendung übereinstimmt, desto relevanter werden die Ergebnisse Ihres Modells sein.
  • Konsistente Formatierung – Eine einheitliche Struktur (z. B. Frage-Antwort-Paare) hilft dem Modell, Muster effektiver zu lernen.
  • Verschiedene Beispiele einbeziehen – Eine Vielzahl von Szenarien hilft dem Modell, über verschiedene Inputs hinweg zu verallgemeinern.
  • Sauber und fehlerfrei – Die Beseitigung von Inkonsistenzen und Störungen verhindert, dass das Modell unerwünschtes Verhalten aufnimmt.

Wir beginnen mit Rohbewertungen wie dieser:

Ein Screenshot eines Trustpilot-Unternehmensprofils in der Kategorie Elektronik & Technologie, das eine schlechte Bewertung von 2,3 Sternen aus 873 Bewertungen zeigt, mit der Option, eine Bewertung zu schreiben oder die Website zu besuchen. Das Profil wird beansprucht, und es gibt einen Hinweis, dass Unternehmen keine Anreize für das Verbergen von Bewertungen bieten können.

Und wandeln Sie sie in strukturierte Frage-Antwort-Paare wie dieses um:

Eine Datentabelle, die Zeilen mit drei Spalten enthält: "id", "Frage" und "Antwort". Die Spalte "Frage" enthält Anfragen im Zusammenhang mit dem HubSpot-Kundensupport und der Kundenzufriedenheit, während die Spalte "Antwort" Einblicke auf der Grundlage von Kundenrezensionen bietet.

Anhand dieses Datensatzes wird Gemma 3 lernen, Erkenntnisse aus Kundenfeedback zu gewinnen, Stimmungsmuster zu erkennen und umsetzbare Empfehlungen zu geben.

Setup-Schritte

#1 Bibliotheken installieren: Öffnen Sie Ihre Projektumgebung und installieren Sie alle notwendigen Python-Bibliotheken, die in der Datei requirements.txt aufgeführt sind. Sie können dies tun, indem Sie den folgenden Befehl in Ihrem Terminal oder Notebook ausführen:

pip install -r requirements.txt

#2 Konfigurieren Sie die Umgebungsvariablen: Erstellen Sie eine .env-Datei im Stammverzeichnis Ihres Projekts und speichern Sie Ihre API-Schlüssel sicher.

OPENAI_API_KEY="your_openai_key_here"
HF_TOKEN="your_hugging_face_token_here"

Schritt 1: Datenerhebung mit Bright Data

Der entscheidende erste Schritt ist die Datenbeschaffung. Um unseren Datensatz für die Feinabstimmung zu erstellen, werden wir Bewertungsrohdaten von Trustpilot sammeln. Aufgrund der robusten Anti-Bot-Maßnahmen von Trustpilot werden wir die Trustpilot Scraper API von Bright Data verwenden. Diese API verwaltet IP-Rotation, CAPTCHA-Auflösung und dynamische Inhalte und ermöglicht so eine effiziente Sammlung strukturierter Bewertungen in großem Umfang, ohne die Komplexität des Aufbaus einer eigenen Scraping-Lösung.

Hier finden Sie ein Python-Skript, das Ihnen Schritt für Schritt zeigt, wie Sie die API von Bright Data zum Sammeln von Bewertungen verwenden:

import time
import json
import requests
from typing import Optional

# --- Configuration ---
API_KEY = "YOUR_API_KEY"  # Replace with your Bright Data API key
DATASET_ID = "gd_lm5zmhwd2sni130p"  # Replace with your Dataset ID
TARGET_URL = "https://www.trustpilot.com/review/hubspot.com"  # Target company page
OUTPUT_FILE = "trustpilot_reviews.json"  # Output file name
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
TIMEOUT = 30  # Request timeout in seconds

# --- Functions ---
def trigger_snapshot() -> Optional[str]:
    """Triggers a Bright Data snapshot collection job."""
    print(f"Triggering snapshot for: {TARGET_URL}")
    try:
        resp = requests.post(
            "https://api.brightdata.com/datasets/v3/trigger",
            headers=HEADERS,
            params={"dataset_id": DATASET_ID},
            json=[{"url": TARGET_URL}],
            timeout=TIMEOUT,
        )
        resp.raise_for_status()  # Raise HTTPError for bad responses (4xx or 5xx)
        snapshot_id = resp.json().get("snapshot_id")
        print(f"Snapshot triggered successfully. ID: {snapshot_id}")
        return snapshot_id
    except requests.RequestException as e:
        print(f"Error triggering snapshot: {e}")
    except json.JSONDecodeError:
        print(f"Error decoding trigger response: {resp.text}")
    return None

def wait_for_snapshot(snapshot_id: str) -> Optional[list]:
    """Polls the API until snapshot data is ready and returns it."""
    check_url = f"https://api.brightdata.com/datasets/v3/snapshot/{snapshot_id}"
    print(f"Waiting for snapshot {snapshot_id} to complete...")
    while True:
        try:
            resp = requests.get(
                check_url,
                headers=HEADERS,
                params={"format": "json"},
                timeout=TIMEOUT,
            )
            resp.raise_for_status()
            # Check if response is the final data (list) or status info (dict)
            if isinstance(resp.json(), list):
                print("Snapshot data is ready.")
                return resp.json()
            else:
                pass
        except requests.RequestException as e:
            print(f"Error checking snapshot status: {e}")
            return None  # Stop polling on error
        except json.JSONDecodeError:
            print(f"Error decoding snapshot status response: {resp.text}")
            return None  # Stop polling on error

        print("Data not ready yet. Waiting 30 seconds...")
        time.sleep(30)

def save_reviews(reviews: list, output_file: str) -> bool:
    """Saves the collected reviews list to a JSON file."""
    try:
        with open(output_file, "w", encoding="utf-8") as f:
            json.dump(reviews, f, indent=2, ensure_ascii=False)
        print(f"Successfully saved {len(reviews)} reviews to {output_file}")
        return True
    except (IOError, TypeError) as e:
        print(f"Error saving reviews to file: {e}")
        return False
    except Exception as e:
        print(f"An unexpected error occurred during saving: {e}")
        return False

def main():
    """Main execution flow for collecting Trustpilot reviews."""
    print("Starting Trustpilot review collection process...")
    snapshot_id = trigger_snapshot()
    if not snapshot_id:
        print("Failed to trigger snapshot. Exiting.")
        return

    reviews = wait_for_snapshot(snapshot_id)
    if not reviews:
        print("Failed to retrieve reviews from snapshot. Exiting.")
        return

    if not save_reviews(reviews, OUTPUT_FILE):
        print("Failed to save the collected reviews.")
    else:
        print("Review collection process completed.")

if __name__ == "__main__":
    main()

Dieses Skript führt die folgenden Schritte aus:

  • Authentifizierung: Es verwendet Ihren API_KEY zur Authentifizierung bei der Bright Data-API über den Authorization-Header.
  • Sammlung auslösen: Er sendet eine POST-Anfrage, um eine Datenerfassung für die angegebene TARGET_URL (in diesem Fall die Trustpilot-Seite von HubSpot) auszulösen, die mit Ihrer DATASET_ID verknüpft ist.
  • Auf Fertigstellung warten: Die API wird regelmäßig mit der zurückgegebenen snapshot_id abgefragt, um zu prüfen, ob die Datensammlung abgeschlossen ist.
  • Abrufen von Daten: Sobald die API anzeigt, dass die Daten bereit sind, holt das Skript die Überprüfungsdaten im JSON-Format ab.
  • Ausgabe speichern: Es speichert die gesammelte Liste der Bewertungsobjekte in einer strukturierten JSON-Datei(trustpilot_reviews.json).

Jede Überprüfung in der resultierenden JSON-Datei enthält detaillierte Informationen, wie z. B.:

{
    "review_id": "680af52fb0bab688237f75c5",
    "review_date": "2025-04-25T04:36:31.000Z",
    "review_rating": 1,
    "review_title": "Cancel Auto Renewal Doesn't Work",
    "review_content": "I was with Hubspot for almost 3 years...",
    "reviewer_name": "Steven Barrett",
    "reviewer_location": "AU",
    "is_verified_review": false,
    "review_date_of_experience": "2025-04-19T00:00:00.000Z",
    // Additional fields omitted for brevity
}

Erfahren Sie in unserem Leitfaden, wie Sie die besten Daten für die LLM-Ausbildung finden: Top-Quellen für LLM-Ausbildungsdaten.

Schritt 2: Umwandlung von JSON in Markdown

Nach dem Sammeln der rohen Überprüfungsdaten besteht der nächste Schritt darin, sie in ein sauberes, lesbares Format zu konvertieren, das für die Verarbeitung geeignet ist. Wir werden Markdown verwenden, das eine leichtgewichtige Klartextstruktur bietet, die das Rauschen bei der Tokenisierung reduziert, die Leistung der Feinabstimmung potenziell verbessert und eine konsistente Trennung zwischen verschiedenen Inhaltsabschnitten gewährleistet.

Um die Konvertierung durchzuführen, führen Sie einfach dieses Skript aus 👉 convert-trustpilot-json-to-markdown.py

Dieses Skript liest die JSON-Daten aus der Ausgabe von Schritt 1 und generiert eine Markdown-Datei mit einer strukturierten Zusammenfassung und einzelnen Kundenrezensionen.

Hier ist ein Beispiel für die Markdown-Ausgabestruktur:

# HubSpot Review Summary
[Visit Website](https://www.hubspot.com/)
**Overall Rating**: 2.3
**Total Reviews**: 873
**Location**: United States
**Industry**: Electronics & Technology

> HubSpot is a leading growth platform... Grow Better.
---

### Review by Steven Barrett (AU)
- **Posted on**: April 25, 2025
- **Experience Date**: April 19, 2025
- **Rating**: 1
- **Title**: *Cancel Auto Renewal Doesn't Work*

I was with Hubspot for almost 3 years... Avoid.

[View Full Review](https://www.trustpilot.com/reviews/680af52fb0bab688237f75c5)

---

Warum KI-Agenten Markdown gegenüber HTML bevorzugen, erfahren Sie in unserem Leitfaden.

Schritt 3: Chunking und Verarbeitung des Dokuments

Wenn das Markdown-Dokument fertig ist, besteht der nächste wichtige Schritt darin, es in kleinere, überschaubare Teile zu zerlegen. Dies ist wichtig, da Large Language Models (LLMs) eine Begrenzung der Eingabe-Token haben und die Feinabstimmung oft am besten mit Beispielen von angemessener Länge funktioniert. Außerdem kann die Verarbeitung dieser Stücke die Klarheit und Kohärenz des Modells verbessern.

Wir verwenden den RecursiveCharacterTextSplitter von LangChain, um die Markdown-Datei aufzuteilen. Diese Methode unterteilt den Text rekursiv auf der Grundlage einer Liste von Trennzeichen, was dazu beiträgt, zusammengehörige Textstücke zusammenzuhalten. Um den Kontext zu erhalten, der sich über die Aufteilungspunkte erstrecken könnte, wird eine Überlappung zwischen aufeinanderfolgenden Chunks angewendet. Für diesen Prozess verwenden wir eine Chunk-Größe von 1.024 Zeichen mit einer Überlappung von 256 Zeichen.

Nach der Aufteilung wird jeder Chunk optional an einen LLM (wie GPT-4o) weitergeleitet, um seine Gesamtklarheit und Kohärenz zu verbessern, wobei die ursprüngliche Bedeutung des Rezensionstextes strikt beibehalten wird. Dieser Verbesserungsschritt zielt darauf ab, die Datenstruktur und den Inhalt innerhalb jedes Chunks für den nachfolgenden Feinabstimmungsprozess optimal zu verdeutlichen.

Jedem verarbeiteten Chunk wird dann eine eindeutige Kennung zugewiesen und in einem JSON-Lines-Dateiformat (.jsonl) gespeichert, um ihn für die nächste Stufe der Pipeline vorzubereiten.

Hier ist die Python-Funktion unter Verwendung des LLM zur Verbesserung der Übersichtlichkeit:

def improve_review_chunk(text: str, client: OpenAI, model: str = "gpt-4o") -> str:
    prompt = """Improve this review's clarity while preserving its meaning:
{text}

Return only the improved text without additional commentary."""
    response = client.chat.completions.create(
            model=model,
            messages=[
                {"role": "system", "content": prompt},
                {"role": "user", "content": text}
            ]
        )
    return response.choices[0].message.content

Den vollständigen Code für diesen Schritt finden Sie hier 👉 split-markdown-into-chunks.py

Die Ausgabe ist eine JSON-Zeilendatei, in der jede Zeile einen Überprüfungsabschnitt mit einem eindeutigen Bezeichner und dem potenziell verbesserten Inhalt der Überprüfung darstellt:

[
  {
    "id": "f8a3b1c9-e4d5-4f6a-8b7c-2d9e0a1b3c4d", // Unique chunk ID
    "review": "# HubSpot Review Summary\\n\\n[Visit Website](https://www.hubspot.com/)...\\n---\\n\\n### Review by Steven Barrett (AU)\\n- **Posted on**: April 25, 2024...\\n- **Rating**: 1\\n- **Title**: *Cancel Auto Renewal Doesn't Work*\\n\\nI was with Hubspot for almost 3 years... [Text continues - may be improved]" // Chunk content (potentially refined)
  },
  // ... more chunk objects
]

Schritt 4: Erzeugen von QA-Paaren

Der letzte Schritt der Datenaufbereitung wandelt die verarbeiteten Review Chunks in strukturierte Frage-Antwort-Paare (QA) um, die für die Feinabstimmung eines Sprachmodells geeignet sind. Wir verwenden GPT-4o von OpenAI, um ein QA-Paar für jedes Chunk in der in Schritt 3 erstellten .jsonl-Datei zu erzeugen.

Für jeden Chunk ruft das Skript die OpenAI-API über eine sorgfältig gestaltete Systemabfrage auf:

SYSTEM_PROMPT = """
You are an expert at transforming customer reviews into insightful question–answer pairs. For each review, generate exactly 1 high-quality QA pair.

PURPOSE:
These QA pairs will train a customer service AI to understand feedback patterns about HubSpot products and identify actionable insights.

GUIDELINES FOR QUESTIONS:
- Make questions general and applicable to similar situations
- Phrase from a stakeholder perspective (e.g., "What feature gaps are causing customer frustration?")
- Focus on product features, usability, pricing, or service impact

GUIDELINES FOR ANSWERS:
- Provide analytical responses (3–5 sentences)
- Extract insights without quoting verbatim
- Offer actionable recommendations
- Maintain objectivity and clarity

FORMAT REQUIREMENTS:
- Start with "Q: " followed by your question
- Then "A: " followed by a plain-text answer
"""

Das Skript enthält integrierte Ratenbegrenzungs- und Wiederholungsmechanismen, um vorübergehende API-Unterbrechungen zu bewältigen und eine stabile Ausführung zu gewährleisten. Die vollständige Implementierung finden Sie in generate-qa-pairs.py.

Die Ausgabe wird als JSON-Array gespeichert, wobei jedes Objekt ein generiertes Frage-Antwort-Paar enthält, das mit der ID des ursprünglichen Chunks verknüpft ist:

[
  {
    "id": "82d53a10-9f37-4d03-8d3b-38812e39ecdc",
    "question": "How can pricing and customer support issues impact customer satisfaction and retention for HubSpot?",
    "answer": "Pricing concerns, particularly when customers feel they are overpaying for services they find unusable or unsupported, can significantly impact customer satisfaction and retention..."
  }
  // ... more QA pairs
]

Nach der Erstellung ist es sehr empfehlenswert, den resultierenden QA-Datensatz in den Hugging Face Hub zu verschieben. Dadurch wird er für die Feinabstimmung und den Austausch leicht zugänglich. Ein Beispiel für den veröffentlichten Datensatz können Sie hier sehen: trustpilot-reviews-qa-dataset.

Feinabstimmung von Gemma 3 mit Unsloth: Schritt-für-Schritt

Nun, da wir unseren benutzerdefinierten Q&A-Datensatz vorbereitet haben, können wir das Gemma 3-Modell feinabstimmen. Wir verwenden Unsloth, eine Open-Source-Bibliothek, die im Vergleich zu den Standardimplementierungen von Hugging Face erhebliche Verbesserungen in Bezug auf Speicher und Geschwindigkeit für das LoRA/QLoRA-Training bietet. Diese Optimierungen machen die Feinabstimmung von Modellen wie Gemma 3 auf Single-GPU-Systemen zugänglicher, sofern der Grafikprozessor über ausreichend VRAM verfügt.

Gemma 3 Größe Ungefährer VRAM-Bedarf* Geeignete Plattformen
4B ~15 GB Kostenloses Google Colab (T4), Kaggle (P100 16 GB)
12B ≥24 GB Colab Pro+ (A100/A10), RTX 4090, A40
27B 22-24 GB (mit 4-Bit-QLoRA, Stapelgröße = 1); sonst ~40 GB A100 40 GB, H100, Multi-GPU-Konfigurationen

Hinweis: Die VRAM-Anforderungen können je nach Stapelgröße, Sequenzlänge und spezifischen Quantisierungsverfahren variieren. Die Anforderungen für das Modell 27B gelten für 4-Bit-QLoRA und eine kleine Stapelgröße (z. B. 1 oder 2); höhere Stapelgrößen oder eine weniger aggressive Quantisierung erfordern wesentlich mehr VRAM (~40 GB+).

Anfängern wird empfohlen, mit dem 4B-Modell auf einem kostenlosen Colab-Notebook zu beginnen, da es das Laden, Trainieren und den Einsatz von Unsloth bequem unterstützt. Ein Upgrade auf die 12B- oder 27B-Modelle sollte nur in Erwägung gezogen werden, wenn Zugang zu GPUs mit höherem RAM oder zu kostenpflichtigen Cloud-Tiers besteht.

Gehen Sie folgendermaßen vor, um den Laufzeittyp in Google Colab zu ändern und einen T4-Grafikprozessor auszuwählen:

  1. Klicken Sie oben auf das Menü Laufzeit.
  2. Wählen Sie Laufzeittyp ändern.
  3. Wählen Sie im daraufhin angezeigten Dialogfeld unter Hardwarebeschleuniger die Option GPU.
  4. Klicken Sie auf Speichern, um die Änderungen zu übernehmen.
Screenshot einer Programmierumgebung mit der Option zum Ändern des Laufzeittyps in einem Python-Notebook, mit verschiedenen Hardware-Beschleunigungsoptionen einschließlich T4 GPU und einer Anzeige des Ladefortschritts für Modelldateien auf der linken Seite.

Schritt 1: Einrichten der Umgebung

Installieren Sie zunächst die erforderlichen Bibliotheken. Wenn Sie sich in einer Colab- oder Jupyter-Umgebung befinden, können Sie diese Befehle direkt in einer Codezelle ausführen.

%%capture
!pip install --no-deps unsloth vllm
import sys, re, requests; modules = list(sys.modules.keys())
for x in modules: sys.modules.pop(x) if "PIL" in x or "google" in x else None
!pip install --no-deps bitsandbytes accelerate xformers==0.0.29.post3 peft "trl==0.15.2" triton cut_cross_entropy unsloth_zoo
!pip install sentencepiece protobuf datasets huggingface_hub hf_transfer

# vLLM requirements - vLLM breaks Colab due to reinstalling numpy
f = requests.get("https://raw.githubusercontent.com/vllm-project/vllm/refs/heads/main/requirements/common.txt").content
with open("vllm_requirements.txt", "wb") as file:
    file.write(re.sub(rb"(transformers|numpy|xformers)[^\n]{1,}\n", b"", f))
!pip install -r vllm_requirements.txt

Hier ist eine kurze Erklärung der wichtigsten installierten Pakete:

  • unsloth: Bietet die wichtigsten Optimierungen für schnelleres und speichereffizienteres LLM-Training und -Laden unter Verwendung von Techniken wie Fused Kernels.
  • peft: Parametereffiziente Feinabstimmungsmethoden (wie LoRA). Erlaubt das Training einer kleinen Anzahl zusätzlicher Parameter anstelle des vollständigen Modells.
  • trl: Transformer Reinforcement Learning. Enthält den SFTTrainer, der den Prozess der überwachten Feinabstimmung vereinfacht.
  • Bits und Bytes: Ermöglicht eine k-Bit-Quantisierung (4-Bit und 8-Bit), wodurch der Speicherbedarf des Modells erheblich reduziert wird.
  • beschleunigen: Hugging Face Bibliothek zur nahtlosen Ausführung von PyTorch-Training über verschiedene Hardwarekonfigurationen (Single-GPU, Multi-GPU, etc.).
  • Datensätze: Hugging Face-Bibliothek zum effizienten Laden, Verarbeiten und Verwalten von Datensätzen.
  • transformers: Hugging Face’s Kernbibliothek für vortrainierte Modelle, Tokenizer und Dienstprogramme.
  • huggingface_hub: Hilfsprogramme zur Interaktion mit dem Hugging Face Hub (Login, Download, Upload).
  • vllm (Optional): Eine schnelle LLM-Inferenzmaschine. Kann separat installiert werden, wenn sie für den Einsatz benötigt wird.

Schritt 2: Authentifizierung mit umarmendem Gesicht

Sie müssen sich von Ihrer Umgebung aus beim Hugging Face Hub anmelden, um das Modell herunterzuladen und das feinabgestimmte Ergebnis möglicherweise später hochzuladen.

import os
from huggingface_hub import login
from google.colab import userdata

hf_token = userdata.get('HF_TOKEN')
if not hf_token:
    raise ValueError("Please set your HF_TOKEN environment variable before running.")

try:
    login(hf_token)
    print("Successfully logged in to Hugging Face Hub.")
except Exception as e:
    print(f"Error logging in to Hugging Face Hub: {e}")

In Google Colab können Sie Ihr Hugging Face-Token am sichersten über die Registerkarte “Geheimnisse” verwalten:

Ein Screenshot von Google Colab zeigt den Abschnitt "Secrets", in dem Nutzer Umgebungsvariablen konfigurieren können. Es werden Optionen zum Hinzufügen eines neuen Geheimnisses angezeigt, wobei der Name "HF_TOKEN" und der entsprechende Wert hervorgehoben sind. Eine Anleitung zum Zugriff auf die Geheimnisse in Python finden Sie weiter unten.

Schritt 3: Laden des Modells und des Tokenizers

Um mit der Feinabstimmung zu beginnen, laden wir das auf Gemma-3-Befehle abgestimmte Modell mithilfe von Unsloths FastModel effizient. Für dieses Beispiel verwenden wir das Modell unsloth/gemma-3-4b-it, eine quantisierte 4-Bit-Version, die von Unsloth so optimiert wurde, dass sie in die Speicherbeschränkungen typischer Colab-GPUs passt.

Schau dir die Gemma 3 Kollektion von Unsloth auf Hugging Face an. Sie umfasst Modelle in den Größen 1B, 4B, 12B und 27B, erhältlich in den Formaten GGUF, 4-bit und 16-bit.

from unsloth import FastModel
from unsloth.chat_templates import get_chat_template
import torch # Import torch for checking CUDA

# Ensure CUDA is available
if not torch.cuda.is_available():
    raise RuntimeError("CUDA is not available. A GPU is required for this tutorial.")
print(f"CUDA available: {torch.cuda.is_available()}")
print(f"CUDA device name: {torch.cuda.get_device_name(0)}")

model, tokenizer = FastModel.from_pretrained(
    model_name="unsloth/gemma-3-4b-it", # Using the 4B instruction-tuned model optimized by Unsloth
    max_seq_length=2048, # Set max context length
    load_in_4bit=True,   # Enable 4-bit quantization
    full_finetuning=False, # Use PEFT (LoRA)
    token=hf_token,      # Pass your Hugging Face token
)

# Apply the correct chat template for Gemma 3
tokenizer = get_chat_template(tokenizer, chat_template="gemma-3")

print("Model and Tokenizer loaded successfully.")

Was in diesem Code passiert:

  • FastModel.from_pretrained(): Unsloths optimierter Modelllader.
  • model_name="unsloth/gemma-3-4b-it": Gibt die zu ladende Modellvariante an. Wir wählen die von Unsloth voroptimierte Version mit 4B-Befehlsabstimmung(it).
  • max_seq_length=2048: Legt die maximale Anzahl von Token fest, die das Modell auf einmal verarbeiten kann. Passen Sie dies auf der Grundlage der Länge Ihrer Datenchunks und des gewünschten Kontextfensters an, um die Speichernutzung und die Fähigkeit zur Verarbeitung längerer Eingaben auszugleichen.
  • load_in_4bit=True: Unerlässlich für das Training mit begrenztem VRAM. Dies lädt die Modellgewichte in 4-Bit-Präzision unter Verwendung von BitsandBytes.
  • full_finetuning=False: Weist Unsloth an, das Modell für die PEFT/LoRA-Feinabstimmung vorzubereiten, was bedeutet, dass nur die Adapterschichten trainiert werden und nicht alle Modellparameter.
  • get_chat_template(tokenizer, chat_template="gemma-3"): Bringt den Tokenizer dazu, Aufforderungen automatisch in das von Gemma 3 erwartete Chat-Format zu formatieren(<start_of_turn>user\n...\n<end_of_turn><start_of_turn>model\n...\n<end_of_turn>). Dies ist von entscheidender Bedeutung für die korrekte Feinabstimmung von Modellen zur Befolgung von Anweisungen und um sicherzustellen, dass das Modell lernt, Antworten in den erwarteten Gesprächsabfolgen zu generieren.

Schritt 4: Laden und Vorbereiten des Datensatzes für das Training

Wir laden den Datensatz, den wir zuvor in den Hugging Face Hub hochgeladen haben, und wandeln ihn dann in das vom Tokenizer und Trainer erwartete chatbasierte Format um.

from datasets import load_dataset
from unsloth.chat_templates import standardize_data_formats, train_on_responses_only # train_on_responses_only imported earlier

# 1. Load the dataset from Hugging Face Hub
dataset_name = "triposatt/trustpilot-reviews-qa-dataset" # Replace with your dataset name
dataset = load_dataset(dataset_name, split="train")

print(f"Dataset '{dataset_name}' loaded.")
print(dataset)

# 2. Normalize any odd formats (ensure 'question' and 'answer' fields exist)
dataset = standardize_data_formats(dataset)
print("Dataset standardized.")

# 3. Define a function to format examples into chat template
def formatting_prompts_func(examples):
    """Formats question-answer pairs into Gemma 3 chat template."""
    questions = examples["question"]
    answers = examples["answer"]
    texts = []
    for q, a in zip(questions, answers):
        # Structure the conversation as a list of roles and content
        conv = [
            {"role": "user", "content": q},
            {"role": "assistant", "content": a},
        ]
        # Apply the chat template
        txt = tokenizer.apply_chat_template(
            conv,
            tokenize=False, # Return string, not token IDs
            add_generation_prompt=False # Don't add the model's start tag at the end yet
        )
        # Gemma 3 tokenizer adds <bos> by default, which the trainer will re-add
        # We remove it here to avoid double <bos> tokens
        txt = txt.removeprefix(tokenizer.bos_token)
        texts.append(txt)
    return {"text": texts}

# 4. Apply the formatting function to the dataset
dataset = dataset.map(formatting_prompts_func, batched=True, remove_columns=["question", "answer"])
print("Dataset formatted with chat template.")
print(dataset) # Inspect the new 'text' column

In diesem Code:

  • load_dataset(): Holt unseren Q&A-Datensatz aus dem Hugging Face Hub.
  • standardize_data_formats(): Sorgt für einheitliche Feldnamen in verschiedenen Datensätzen und sucht in diesem Fall speziell nach “Frage” und “Antwort”.
  • formatting_prompts_func(): Diese wichtige Funktion verarbeitet Stapel unserer Q&A-Paare. Sie verwendet die Methode tokenizer.apply_chat_template(), um sie in Zeichenketten umzuwandeln, die für die Feinabstimmung der Gemma 3-Anweisungen korrekt formatiert sind. Dieses Format enthält spezielle Turn-Token wie <start_of_turn>user\n und <start_of_turn>model\n, die für das Modell wichtig sind, um die Gesprächsstruktur zu verstehen. Wir entfernen das anfängliche <bos>-Token, da der SFTTrainer sein eigenes hinzufügt.
  • dataset.map(...): Wendet die Funktion "formatting_prompts_func" effizient auf den gesamten Datensatz an, wobei eine neue Spalte “text” mit den formatierten Zeichenfolgen erstellt und die ursprünglichen Spalten entfernt werden.

Schritt 5: Konfigurieren von LoRA und des Trainers

Jetzt konfigurieren wir die PEFT (LoRA)-Einstellungen und den SFTTrainer aus der trl-Bibliothek. LoRA funktioniert, indem kleine, trainierbare Matrizen in Schlüsselschichten des vortrainierten Modells injiziert werden. Nur diese kleinen Adaptermatrizen werden während der Feinabstimmung aktualisiert, was die Anzahl der zu trainierenden Parameter drastisch reduziert und somit die Speichernutzung minimiert.

from trl import SFTTrainer, SFTConfig
import torch

# 1. Configure LoRA
model = FastModel.get_peft_model(
    model,
    r=8, # LoRA rank (a common value) - lower rank means fewer parameters, higher means more expressive
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj", # Attention layers
        "gate_proj", "up_proj", "down_proj"      # MLP layers
    ],
    # Set True if you want to fine-tune language layers (recommended for text tasks)
    # and Attention/MLP modules (where LoRA is applied)
    finetune_language_layers=True,
    finetune_attention_modules=True,
    finetune_mlp_modules=True,
    # finetune_vision_layers=False, # Only relevant for multimodal models (12B/27B)
    lora_alpha=8, # LoRA scaling factor (often set equal to r)
    lora_dropout=0, # Dropout for LoRA layers
    bias="none", # Don't train bias terms
    use_gradient_checkpointing="unsloth", # Memory optimization
    random_state=1000, # Seed for reproducibility
    use_rslora=False, # Rank-Stabilized LoRA (optional alternative)
    # modules_to_save=["embed_tokens", "lm_head"], # Optional: train embedding/output layers
)

print("Model configured for PEFT (LoRA).")

# 2. Configure the SFTTrainer
# Determine a reasonable max_steps based on dataset size and epochs
# For demonstration, a small number of steps is used (e.g., 30)
# For a real use case, calculate steps = (dataset_size / batch_size / grad_accum) * num_epochs
dataset_size = len(dataset)
per_device_train_batch_size = 2 # Adjust based on your GPU VRAM
gradient_accumulation_steps = 4 # Accumulate gradients to simulate larger batch size (batch_size * grad_accum = 8)
num_train_epochs = 3 # Example: 3 epochs

# Calculate total training steps
total_steps = int((dataset_size / per_device_train_batch_size / gradient_accumulation_steps) * num_train_epochs)
# Ensure max_steps is not 0 if dataset is small or calculation results in < 1 step
max_steps = max(30, total_steps) # Set a minimum or calculate properly

print(f"Calculated total training steps for {num_train_epochs} epochs: {total_steps}. Using max_steps={max_steps}")

sft_config = SFTConfig(
    dataset_text_field="text", # The column in our dataset containing the formatted chat text
    per_device_train_batch_size=per_device_train_batch_size,
    gradient_accumulation_steps=gradient_accumulation_steps,
    warmup_steps=max(5, int(max_steps * 0.03)), # Warmup for first few steps (e.g., 3% of total steps)
    max_steps=max_steps, # Total number of training steps
    learning_rate=2e-4, # Learning rate
    logging_steps=max(1, int(max_steps * 0.01)), # Log every 1% of total steps (min 1)
    optim="adamw_8bit", # 8-bit AdamW optimizer (memory efficient)
    weight_decay=0.01, # L2 regularization
    lr_scheduler_type="linear", # Linear learning rate decay
    seed=3407, # Random seed
    report_to="none", # Disable reporting to platforms like W&B unless needed
    output_dir="./results", # Directory to save checkpoints and logs
)

# 3. Build the SFTTrainer instance
trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    eval_dataset=None, # Optional: provide a validation dataset
    args=sft_config,
)

print("SFTTrainer built.")

# 4. Mask out the input portion for training
# This teaches the model to only generate the assistant’s response
# It prevents the model from just copying the user’s prompt
# Pass the literal prefixes for instruction and response turns from the chat template
trainer = train_on_responses_only(
    trainer,
    instruction_part="<start_of_turn>user\n", # Literal string before user content
    response_part="<start_of_turn>model\n",  # Literal string before model content
)

print("Trainer configured to train only on responses.")

In diesem Code:

  • FastModel.get_peft_model(): Konfiguriert das geladene Modell für die LoRA-Feinabstimmung mit den angegebenen Parametern. r ist der LoRA-Rang, der die Größe der Adaptermatrizen steuert. target_modules gibt an, welche Modellschichten (wie Aufmerksamkeit und MLP-Projektionen) diese Adapter erhalten. lora_alpha ist ein Skalierungsfaktor. use_gradient_checkpointing ist eine speicherschonende Technik von Unsloth.
  • SFTConfig(): Definiert die Trainings-Hyperparameter für den SFTTrainer. per_device_train_batch_size und gradient_accumulation_steps arbeiten zusammen, um die effektive Batchgröße zu bestimmen, die für die Berechnung von Gradienten verwendet wird. max_steps legt die Gesamtanzahl der Trainingsiterationen fest. learning_rate, optim, weight_decay und lr_scheduler_type steuern den Optimierungsprozess. dataset_text_field teilt dem Trainer mit, welche Spalte im Datensatz die formatierten Trainingsbeispiele enthält.
  • SFTTrainer(): Instanziiert den Trainer, der das mit LoRA konfigurierte Modell, den vorbereiteten Datensatz, den Tokenizer und die in SFTConfig definierten Trainingsargumente zusammenführt.
  • train_on_responses_only(): Eine Utility-Funktion (Teil von trl und kompatibel mit Unsloth), die die Verlustberechnung des Trainers modifiziert. Sie stellt den Verlust so ein, dass er nur für die Token berechnet wird, die der erwarteten Antwort des Modells entsprechen(<start_of_turn>model\n...), und ignoriert die Token der Eingabeaufforderung des Benutzers(<start_of_turn>user\n...). Dies ist wichtig, um dem Modell beizubringen, relevante Antworten zu generieren und nicht einfach die Eingabeaufforderung zu wiederholen oder zu vervollständigen. Wir stellen die genauen Zeichenfolgen-Präfixe zur Verfügung, die in der Chat-Vorlage verwendet werden, um diese Abschnitte abzugrenzen.

Schritt 6: Training des Modells

Nachdem alles eingerichtet ist, können wir mit der Feinabstimmung beginnen. Die Methode trainer.train() bearbeitet die Trainingsschleife auf der Grundlage der in der SFTConfig bereitgestellten Konfigurationen.

# Optional: clear CUDA cache before training
torch.cuda.empty_cache()

print("Starting training...")
# Use mixed precision training for efficiency
# Unsloth automatically handles float16/bf16 based on GPU capabilities and model
with torch.amp.autocast(device_type="cuda", dtype=torch.float16): # Or torch.bfloat16 if supported
     trainer.train()

print("Training finished.")

Der Trainer gibt Aktualisierungen des Fortschritts aus, einschließlich des Trainingsverlusts. Sie sollten beobachten, dass der Verlust schrittweise abnimmt, was darauf hinweist, dass das Modell aus den Daten lernt. Die gesamte Trainingszeit hängt von der Größe des Datensatzes, der Modellgröße, den Hyperparametern und der verwendeten GPU ab. Für unseren Beispieldatensatz und das 4B-Modell auf einem T4-Grafikprozessor sollte das Training für 200 Schritte relativ schnell abgeschlossen sein (z. B. unter 15-30 Minuten, abhängig von der genauen Einrichtung und der Datenlänge).

Schritt 7: Testen des Feinabstimmungsmodells (Inferenz)

Nach dem Training testen wir unser feinabgestimmtes Modell, um zu sehen, wie gut es auf Fragen reagiert, die auf den Trustpilot-Bewertungsdaten basieren, auf denen es trainiert wurde. Wir werden die Methode model.generate mit einem TextStreamer für eine interaktivere Ausgabe verwenden.

from transformers import TextStreamer

# Define some test questions related to the dataset content
questions = [
    "What are common issues or complaints mentioned in the reviews?",
    "What do customers like most about the product/service?",
    "How is the customer support perceived?",
    "Are there any recurring themes regarding pricing or value?"
    # Add more questions here based on your dataset content
]

# Set up a streamer for real-time output
# skip_prompt=True prevents printing the input prompt again
# skip_special_tokens=True removes chat template tokens from output
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)

print("\n--- Testing Fine-Tuned Model ---")

# Iterate through questions and generate answers
for idx, q in enumerate(questions, start=1):
    # Build the conversation prompt in the correct Gemma 3 chat format
    conv = [{"role": "user", "content": q}]

    # Apply the chat template and add the generation prompt token
    # add_generation_prompt=True includes the <start_of_turn>model tag
    prompt = tokenizer.apply_chat_template(
        conv,
        add_generation_prompt=True,
        tokenize=False
    )

    # Tokenize the prompt and move to GPU
    inputs = tokenizer([prompt], return_tensors="pt", padding=True).to("cuda")

    # Display the question
    print(f"\n=== Question {idx}: {q}\n")

    # Generate the response with streaming
    # Pass the tokenized inputs directly to model.generate
    _ = model.generate(
        **inputs,
        streamer=streamer, # Use the streamer for token-by-token output
        max_new_tokens=256, # Limit the response length
        temperature=0.7, # Control randomness (lower=more deterministic)
        top_p=0.95, # Nucleus sampling
        top_k=64, # Top-k sampling
        use_cache=True, # Use cache for faster generation
        # Add stopping criteria if needed, e.g., stopping after <end_of_turn>
        # eos_token_id=tokenizer.eos_token_id,
    )
    # Add a separator after each answer
    print("\n" + "="*40)

print("\n--- Testing Complete ---")

Sehen Sie sich die Antworten des Modells in der folgenden Abbildung an:

Text zur Diskussion von Kundenrezensionen, in dem häufige Beschwerden über Kommunikationsverzögerungen und Probleme mit der Produktqualität, positives Feedback zum benutzerfreundlichen Design und den CRM-Funktionen von HubSpot, die Wahrnehmung des Kundensupports als freundlich und effizient sowie Themen bezüglich des Preis-Leistungs-Verhältnisses bei Preisstrategien hervorgehoben werden.

🔥 Großartig, es funktioniert gut!

Ein erfolgreicher Feinabstimmungsprozess bedeutet, dass das Modell Antworten generiert, die analytischer sind und sich direkt aus dem Bewertungsinhalt ableiten, auf den es abgestimmt wurde, und die den Stil und die Erkenntnisse Ihres benutzerdefinierten Datensatzes widerspiegeln, anstatt allgemeine Antworten zu geben.

Schritt 8: Speichern und Übertragen des feinabgestimmten Modells

Zum Schluss speichern Sie Ihre feinabgestimmten LoRA-Adapter und Tokenizer. Sie können sie lokal speichern und auch an den Hugging Face Hub übertragen, um die gemeinsame Nutzung, Versionierung und Bereitstellung zu erleichtern.

# Define local path and Hub repository ID
new_model_local = "gemma-3-4b-trustpilot-qa-adapter" # Local directory name
new_model_online = "YOUR_HF_USERNAME/gemma-3-4b-trustpilot-qa" # Hub repo name

# 1. Save locally
print(f"Saving model adapter and tokenizer locally to '{new_model_local}'...")
model.save_pretrained(new_model_local)
tokenizer.save_pretrained(new_model_local)
print("Saved locally.")

# 2. Push to Hugging Face Hub
print(f"Pushing model adapter and tokenizer to Hugging Face Hub '{new_model_online}'...")
model.push_to_hub(new_model_online, token=hf_token)
tokenizer.push_to_hub(new_model_online, token=hf_token)

Das fein abgestimmte Modell ist jetzt auf Hugging Face Hub verfügbar:

Screenshot der Hugging-Face-Modellkarte für "triposatt/gemma-3-4b-trustpilot-qa", der die Details des Modells einschließlich Entwickler, Lizenz und Informationen über den Feinabstimmungsprozess mit Unsloath und der TRL-Bibliothek von Hugging Face anzeigt.

Schlussfolgerung

Dieser Leitfaden demonstriert einen End-to-End-Ansatz zur Feinabstimmung von Google Gemma 3 für einen praktischen Anwendungsfall: die Generierung analytischer Antworten aus Kundenrezensionen. Wir haben den gesamten Arbeitsablauf abgedeckt – vom Sammeln hochwertiger, domänenspezifischer Daten über die Web Scraper API von Bright Data über die Strukturierung in ein QA-Format mit LLM-gestützter Verarbeitung bis hin zur effizienten Feinabstimmung des Gemma 3 4B-Modells mit der Unsloth-Bibliothek auf ressourcenbeschränkter Hardware.

Das Ergebnis ist eine spezialisierte LLM, die in der Lage ist, Erkenntnisse zu gewinnen und Stimmungen aus rohen Bewertungsdaten zu interpretieren und sie in strukturierte, umsetzbare Antworten umzuwandeln. Diese Methode ist äußerst anpassungsfähig – Sie können denselben Arbeitsablauf anwenden, um Gemma 3 (oder andere geeignete LLMs) auf verschiedene domänenspezifische Datensätze abzustimmen und so KI-Assistenten zu schaffen, die auf unterschiedliche Bedürfnisse zugeschnitten sind.

Weitere Informationen zu KI-gesteuerten Datenextraktionsstrategien finden Sie in diesen zusätzlichen Ressourcen:

Weitere Optimierungen und Beispiele für die Verwendung von Unsloth finden Sie in der Unsloth Notebooks Collection.

Keine Kreditkarte erforderlich