Vernetzen Sie sich mit uns

Schnelles Engineering

LLM mit DSPy optimieren: Eine Schritt-für-Schritt-Anleitung zum Erstellen, Optimieren und Bewerten von KI-Systemen

mm

Veröffentlicht

 on

DSPy ist ein Framework zur algorithmischen Optimierung von LM-Eingabeaufforderungen und -Gewichten

Da die Fähigkeiten großer Sprachmodelle (LLMs) immer weiter wachsen, ist die Entwicklung robuster KI-Systeme, die ihr Potenzial ausschöpfen, immer komplexer geworden. Herkömmliche Ansätze beinhalten oft komplizierte Eingabeaufforderungstechniken, Datengenerierung zur Feinabstimmung und manuelle Anleitung, um die Einhaltung domänenspezifischer Einschränkungen sicherzustellen. Dieser Prozess kann jedoch mühsam und fehleranfällig sein und ist stark auf menschliches Eingreifen angewiesen.

Enter DSPy, ein revolutionäres Framework, das die Entwicklung von KI-Systemen auf Basis von LLMs optimieren soll. DSPy führt einen systematischen Ansatz zur Optimierung von LM-Eingabeaufforderungen und -Gewichten ein, der es Entwicklern ermöglicht, anspruchsvolle Anwendungen mit minimalem manuellen Aufwand zu erstellen.

In diesem umfassenden Leitfaden untersuchen wir die Kernprinzipien von DSPy, seine modulare Architektur und die Palette der leistungsstarken Funktionen, die es bietet. Wir werden auch auf praktische Beispiele eingehen und zeigen, wie DSPy die Art und Weise verändern kann, wie Sie KI-Systeme mit LLMs entwickeln.

Was ist DSPy und warum brauchen Sie es?

DSPy ist ein Framework, das den Ablauf Ihres Programms trennt (modules) von den Parametern (LM-Eingabeaufforderungen und Gewichten) jedes Schritts. Diese Trennung ermöglicht die systematische Optimierung von LM-Eingabeaufforderungen und Gewichten, sodass Sie komplexe KI-Systeme mit höherer Zuverlässigkeit, Vorhersagbarkeit und Einhaltung domänenspezifischer Einschränkungen erstellen können.

Traditionell war die Entwicklung von KI-Systemen mit LLMs ein mühsamer Prozess, bei dem das Problem in Schritte zerlegt, für jeden Schritt komplizierte Eingabeaufforderungen erstellt, synthetische Beispiele zur Feinabstimmung generiert und die LMs manuell angeleitet wurden, bestimmte Einschränkungen einzuhalten. Dieser Ansatz war nicht nur zeitaufwändig, sondern auch fehleranfällig, da selbst geringfügige Änderungen an der Pipeline, dem LM oder den Daten eine umfangreiche Überarbeitung der Eingabeaufforderungen und Feinabstimmungsschritte erforderlich machen konnten.

DSPy begegnet diesen Herausforderungen durch die Einführung eines neuen Paradigmas: Optimierer. Diese LM-gesteuerten Algorithmen können die Eingabeaufforderungen und Gewichte Ihrer LM-Anrufe anhand einer Metrik optimieren, die Sie maximieren möchten. Durch die Automatisierung des Optimierungsprozesses ermöglicht DSPy Entwicklern, robuste KI-Systeme mit minimalem manuellen Eingriff zu erstellen und so die Zuverlässigkeit und Vorhersagbarkeit der LM-Ausgaben zu verbessern.

Die modulare Architektur von DSPy

Das Herzstück von DSPy ist eine modulare Architektur, die die Zusammenstellung komplexer KI-Systeme erleichtert. Das Framework bietet eine Reihe integrierter Module, die verschiedene Eingabetechniken abstrahieren, wie zum Beispiel dspy.ChainOfThought und dspy.ReAct. Diese Module können kombiniert und zu größeren Programmen zusammengesetzt werden, sodass Entwickler komplexe Pipelines erstellen können, die auf ihre spezifischen Anforderungen zugeschnitten sind.

Jedes Modul enthält lernbare Parameter, darunter Anweisungen, Beispiele mit wenigen Versuchen und LM-Gewichte. Wenn ein Modul aufgerufen wird, können die Optimierer von DSPy diese Parameter feinabstimmen, um die gewünschte Metrik zu maximieren und sicherzustellen, dass die Ausgaben des LM den angegebenen Einschränkungen und Anforderungen entsprechen.

Optimieren mit DSPy

DSPy stellt eine Reihe leistungsstarker Optimierer vor, die die Leistung und Zuverlässigkeit Ihrer KI-Systeme verbessern sollen. Diese Optimierer nutzen LM-gesteuerte Algorithmen, um die Eingabeaufforderungen und Gewichte Ihrer LM-Aufrufe abzustimmen und die angegebene Metrik zu maximieren, während domänenspezifische Einschränkungen eingehalten werden.

Zu den wichtigsten in DSPy verfügbaren Optimierern gehören:

  1. BootstrapFewShot: Dieser Optimierer erweitert die Signatur, indem er automatisch optimierte Beispiele generiert und in die an das Modell gesendete Eingabeaufforderung einfügt und so ein Lernen mit wenigen Beispielen implementiert.
  2. BootstrapWenigeSchüsseMitZufälligerSuche: Gilt BootstrapFewShot mehrmalige zufällige Suche über generierte Demonstrationen, Auswahl des besten Programms über die Optimierung.
  3. MIPRO: Generiert in jedem Schritt Anweisungen und Beispiele mit wenigen Beispielen, wobei die Anweisungsgenerierung daten- und demonstrationsorientiert ist. Es verwendet Bayessche Optimierung, um den Bereich der Generierungsanweisungen und Demonstrationen in Ihren Modulen effektiv zu durchsuchen.
  4. BootstrapFinetune: Destilliert ein auf Eingabeaufforderungen basierendes DSPy-Programm in Gewichtsaktualisierungen für kleinere LMs, sodass Sie die zugrunde liegenden LLMs zur Verbesserung der Effizienz feinabstimmen können.

Durch den Einsatz dieser Optimierer können Entwickler ihre KI-Systeme systematisch optimieren und so qualitativ hochwertige Ergebnisse sicherstellen und gleichzeitig domänenspezifische Einschränkungen und Anforderungen einhalten.

Erste Schritte mit DSPy

Um die Leistungsfähigkeit von DSPy zu veranschaulichen, gehen wir ein praktisches Beispiel für den Aufbau eines Retrieval-Augmented Generation (RAG)-Systems zur Frage- und Antwortbeantwortung durch.

Schritt 1: Einrichten des Sprachmodells und des Abrufmodells

Der erste Schritt umfasst die Konfiguration des Sprachmodells (LM) und des Abrufmodells (RM) innerhalb von DSPy.

Um DSPy zu installieren, führen Sie Folgendes aus:

pip install dspy-ai

DSPy unterstützt mehrere LM- und RM-APIs sowie lokales Modell-Hosting, sodass Sie Ihre bevorzugten Modelle problemlos integrieren können.

import dspy
# Configure the LM and RM
turbo = dspy.OpenAI(model='gpt-3.5-turbo')
colbertv2_wiki17_abstracts = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts')
dspy.settings.configure(lm=turbo, rm=colbertv2_wiki17_abstracts)

Schritt 2: Laden des Datensatzes

Als Nächstes laden wir den HotPotQA-Datensatz, der eine Sammlung komplexer Frage-Antwort-Paare enthält, die normalerweise im Multi-Hop-Verfahren beantwortet werden.

from dspy.datasets import HotPotQA
# Load the dataset
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)
# Specify the 'question' field as the input
trainset = [x.with_inputs('question') for x in dataset.train]
devset = [x.with_inputs('question') for x in dataset.dev]

Schritt 3: Signaturen erstellen

DSPy verwendet Signaturen, um das Verhalten von Modulen zu definieren. In diesem Beispiel definieren wir eine Signatur für die Aufgabe der Antwortgenerierung und geben die Eingabefelder (Kontext und Frage) und das Ausgabefeld (Antwort) an.

class GenerateAnswer(dspy.Signature):
"""Answer questions with short factoid answers."""
context = dspy.InputField(desc="may contain relevant facts")
question = dspy.InputField()
answer = dspy.OutputField(desc="often between 1 and 5 words")

Schritt 4: Erstellen der Pipeline

Wir erstellen unsere RAG-Pipeline als DSPy-Modul, das aus einer Initialisierungsmethode (__init__) zum Deklarieren der Untermodule (dspy.Retrieve und dspy.ChainOfThought) und einer Weiterleitungsmethode (forward) zum Beschreiben des Kontrollflusses zur Beantwortung der Frage mithilfe dieser Module besteht.

class RAG(dspy.Module):
    def __init__(self, num_passages=3):
    super().__init__()
        self.retrieve = dspy.Retrieve(k=num_passages)
        self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
    def forward(self, question):
        context = self.retrieve(question).passages
        prediction = self.generate_answer(context=context, question=question)
        return dspy.Prediction(context=context, answer=prediction.answer)

Schritt 5: Optimieren der Pipeline

Nachdem die Pipeline definiert ist, können wir sie nun mit den Optimierern von DSPy optimieren. In diesem Beispiel verwenden wir den Optimierer BootstrapFewShot, der basierend auf einem Trainingssatz und einer Metrik zur Validierung effektive Eingabeaufforderungen für unsere Module generiert und auswählt.

from dspy.teleprompt import BootstrapFewShot
# Validation metric
def validate_context_and_answer(example, pred, trace=None):
answer_EM = dspy.evaluate.answer_exact_match(example, pred)
answer_PM = dspy.evaluate.answer_passage_match(example, pred)
return answer_EM and answer_PM
# Set up the optimizer
teleprompter = BootstrapFewShot(metric=validate_context_and_answer)
# Compile the program
compiled_rag = teleprompter.compile(RAG(), trainset=trainset)

Schritt 6: Auswerten der Pipeline

Nach dem Kompilieren des Programms muss unbedingt seine Leistung auf einem Entwicklungsset bewertet werden, um sicherzustellen, dass es die gewünschte Genauigkeit und Zuverlässigkeit aufweist.

from dspy.evaluate import Evaluate
# Set up the evaluator
evaluate = Evaluate(devset=devset, metric=validate_context_and_answer, num_threads=4, display_progress=True, display_table=0)
# Evaluate the compiled RAG program
evaluation_result = evaluate(compiled_rag)
print(f"Evaluation Result: {evaluation_result}")

Schritt 7: Modellverlauf prüfen

Um die Interaktionen des Modells besser zu verstehen, können Sie die neuesten Generationen überprüfen, indem Sie den Verlauf des Modells untersuchen.

# Inspect the model's history
turbo.inspect_history(n=1)

Schritt 8: Vorhersagen treffen

Nachdem die Pipeline optimiert und ausgewertet wurde, können Sie sie nun verwenden, um Vorhersagen zu neuen Fragen zu treffen.

# Example question
question = "Which award did Gary Zukav's first book receive?"
# Make a prediction using the compiled RAG program
prediction = compiled_rag(question)
print(f"Question: {question}")
print(f"Answer: {prediction.answer}")
print(f"Retrieved Contexts: {prediction.context}")

Minimales Arbeitsbeispiel mit DSPy

Lassen Sie uns nun ein weiteres minimales Arbeitsbeispiel durchgehen, bei dem GSM8K-Datensatz und das OpenAI GPT-3.5-Turbo-Modell zum Simulieren von Eingabeaufforderungsaufgaben innerhalb von DSPy.

Einrichtung

Stellen Sie zunächst sicher, dass Ihre Umgebung richtig konfiguriert ist:

import dspy
from dspy.datasets.gsm8k import GSM8K, gsm8k_metric
# Set up the LM
turbo = dspy.OpenAI(model='gpt-3.5-turbo-instruct', max_tokens=250)
dspy.settings.configure(lm=turbo)
# Load math questions from the GSM8K dataset
gsm8k = GSM8K()
gsm8k_trainset, gsm8k_devset = gsm8k.train[:10], gsm8k.dev[:10]
print(gsm8k_trainset)

Das gsm8k_trainset und gsm8k_devset Datensätze enthalten eine Liste von Beispielen, wobei jedes Beispiel ein Frage- und Antwortfeld hat.

Definieren Sie das Modul

Definieren Sie als Nächstes ein benutzerdefiniertes Programm unter Verwendung des ChainOfThought-Moduls zum schrittweisen Denken:

class CoT(dspy.Module):
def __init__(self):
super().__init__()
self.prog = dspy.ChainOfThought("question -> answer")
def forward(self, question):
return self.prog(question=question)

Kompilieren und Auswerten des Modells

Kompilieren Sie es nun mit dem BootstrapFewShot Teleprompter:

from dspy.teleprompt import BootstrapFewShot
# Set up the optimizer
config = dict(max_bootstrapped_demos=4, max_labeled_demos=4)
# Optimize using the gsm8k_metric
teleprompter = BootstrapFewShot(metric=gsm8k_metric, **config)
optimized_cot = teleprompter.compile(CoT(), trainset=gsm8k_trainset)
# Set up the evaluator
from dspy.evaluate import Evaluate
evaluate = Evaluate(devset=gsm8k_devset, metric=gsm8k_metric, num_threads=4, display_progress=True, display_table=0)
evaluate(optimized_cot)
# Inspect the model's history
turbo.inspect_history(n=1)

Dieses Beispiel zeigt, wie Sie Ihre Umgebung einrichten, ein benutzerdefiniertes Modul definieren, ein Modell kompilieren und seine Leistung anhand der bereitgestellten Datensatz- und Teleprompter-Konfigurationen genau bewerten.

Datenmanagement in DSPy

DSPy arbeitet mit Trainings-, Entwicklungs- und Testsätzen. Für jedes Beispiel in Ihren Daten haben Sie normalerweise drei Arten von Werten: Eingaben, Zwischenbeschriftungen und endgültige Beschriftungen. Während Zwischen- oder endgültige Beschriftungen optional sind, sind einige Beispieleingaben unerlässlich.

Beispielobjekte erstellen

Beispielobjekte in DSPy ähneln Python-Wörterbüchern, verfügen jedoch über nützliche Dienstprogramme:

qa_pair = dspy.Example(question="This is a question?", answer="This is an answer.")
print(qa_pair)
print(qa_pair.question)
print(qa_pair.answer)

Ausgang:

Example({'question': 'This is a question?', 'answer': 'This is an answer.'}) (input_keys=None)
This is a question?
This is an answer.

Eingabeschlüssel angeben

In DSPy verfügen Beispielobjekte über eine Methode with_inputs(), um bestimmte Felder als Eingaben zu markieren:

print(qa_pair.with_inputs("question"))
print(qa_pair.with_inputs("question", "answer"))

Auf Werte kann mit dem Punktoperator zugegriffen werden, und Methoden wie inputs() und labels() geben neue Beispielobjekte zurück, die jeweils nur Eingabe- oder Nicht-Eingabeschlüssel enthalten.

Optimierer in DSPy

Ein DSPy-Optimierer stimmt die Parameter eines DSPy-Programms (z. B. Eingabeaufforderungen und/oder LM-Gewichte) ab, um bestimmte Metriken zu maximieren. DSPy bietet verschiedene integrierte Optimierer, die jeweils unterschiedliche Strategien verwenden.

Verfügbare Optimierer

  • BootstrapFewShot: Generiert Beispiele mit wenigen Versuchen unter Verwendung der bereitgestellten beschrifteten Eingabe- und Ausgabedatenpunkte.
  • BootstrapWenigeSchüsseMitZufälligerSuche: Wendet BootstrapFewShot mehrmals mit zufälliger Suche über generierte Demonstrationen an.
  • COPRO: Generiert und verfeinert neue Anweisungen für jeden Schritt und optimiert sie durch koordinierten Aufstieg.
  • MIPRO: Optimiert Anweisungen und Beispiele mit wenigen Versuchen mithilfe der Bayesschen Optimierung.

Auswählen eines Optimierers

Wenn Sie nicht sicher sind, wo Sie beginnen sollen, verwenden Sie BootstrapFewShotWithRandomSearch:

Verwenden Sie für sehr wenige Daten (10 Beispiele) BootstrapFewShot.
Für etwas mehr Daten (50 Beispiele) verwenden Sie BootstrapFewShotWithRandomSearch.
Verwenden Sie für größere Datensätze (über 300 Beispiele) MIPRO.

So verwenden Sie BootstrapFewShotWithRandomSearch:

from dspy.teleprompt import BootstrapFewShotWithRandomSearch
config = dict(max_bootstrapped_demos=4, max_labeled_demos=4, num_candidate_programs=10, num_threads=4)
teleprompter = BootstrapFewShotWithRandomSearch(metric=YOUR_METRIC_HERE, **config)
optimized_program = teleprompter.compile(YOUR_PROGRAM_HERE, trainset=YOUR_TRAINSET_HERE)

Speichern und Laden optimierter Programme

Nachdem Sie ein Programm durch einen Optimierer laufen lassen haben, speichern Sie es für die zukünftige Verwendung:

optimized_program.save(IHR_SPEICHERPFAD)

Ein gespeichertes Programm laden:

loaded_program = YOUR_PROGRAM_CLASS()
loaded_program.load(path=YOUR_SAVE_PATH)

Erweiterte Funktionen: DSPy-Assertionen

DSPy-Assertionen automatisieren die Durchsetzung von Rechenbeschränkungen für LMs und verbessern die Zuverlässigkeit, Vorhersagbarkeit und Richtigkeit der LM-Ausgaben.

Verwenden von Behauptungen

Definieren Sie Validierungsfunktionen und deklarieren Sie Behauptungen nach der jeweiligen Modellgenerierung. Zum Beispiel:

dspy.Suggest(
len(query) <= 100,
"Query should be short and less than 100 characters",
)
dspy.Suggest(
validate_query_distinction_local(prev_queries, query),
"Query should be distinct from: " + "; ".join(f"{i+1}) {q}" for i, q in enumerate(prev_queries)),
)

Transformieren von Programmen mit Behauptungen

from dspy.primitives.assertions import assert_transform_module, backtrack_handler
baleen_with_assertions = assert_transform_module(SimplifiedBaleenAssertions(), backtrack_handler)

Alternativ können Sie Assertionen auch direkt im Programm aktivieren:

baleen_with_assertions = SimplifiedBaleenAssertions().activate_assertions()

Behauptungsbasierte Optimierungen

DSPy-Assertionen funktionieren mit DSPy-Optimierungen, insbesondere mit BootstrapFewShotWithRandomSearch, einschließlich Einstellungen wie:

  • Kompilierung mit Assertionen
  • Kompilierung + Inferenz mit Behauptungen

Zusammenfassung

DSPy bietet einen leistungsstarken und systematischen Ansatz zur Optimierung von Sprachmodellen und deren Eingabeaufforderungen. Indem Sie die in diesen Beispielen beschriebenen Schritte befolgen, können Sie komplexe KI-Systeme problemlos erstellen, optimieren und bewerten. Das modulare Design und die erweiterten Optimierer von DSPy ermöglichen eine effiziente und effektive Integration verschiedener Sprachmodelle und machen es zu einem wertvollen Werkzeug für alle, die im Bereich NLP und KI arbeiten.

Unabhängig davon, ob Sie ein einfaches Frage-Antwort-System oder eine komplexere Pipeline erstellen, bietet DSPy die nötige Flexibilität und Robustheit für eine hohe Leistung und Zuverlässigkeit.

Ich habe die letzten fünf Jahre damit verbracht, in die faszinierende Welt des maschinellen Lernens und des Deep Learning einzutauchen. Meine Leidenschaft und mein Fachwissen haben dazu geführt, dass ich an über 50 verschiedenen Software-Engineering-Projekten mitgewirkt habe, mit besonderem Schwerpunkt auf KI/ML. Meine anhaltende Neugier hat mich auch zur Verarbeitung natürlicher Sprache geführt, einem Bereich, den ich gerne weiter erforschen möchte.