Følg os

Hurtig teknik

Optimer LLM med DSPy: En trin-for-trin guide til at bygge, optimere og evaluere AI-systemer

mm

Udgivet

 on

DSPy er en ramme til algoritmisk optimering af LM-prompter og vægte

Efterhånden som mulighederne for store sprogmodeller (LLM'er) fortsætter med at udvide, er udviklingen af ​​robuste AI-systemer, der udnytter deres potentiale, blevet stadig mere kompleks. Konventionelle tilgange involverer ofte indviklede promptteknikker, datagenerering til finjustering og manuel vejledning for at sikre overholdelse af domænespecifikke begrænsninger. Denne proces kan dog være kedelig, fejltilbøjelig og stærkt afhængig af menneskelig indgriben.

Indtast DSPy, en revolutionær ramme designet til at strømline udviklingen af ​​AI-systemer drevet af LLM'er. DSPy introducerer en systematisk tilgang til optimering af LM-prompter og vægte, hvilket gør det muligt for udviklere at bygge sofistikerede applikationer med minimal manuel indsats.

I denne omfattende guide vil vi udforske kerneprincipperne i DSPy, dens modulære arkitektur og rækken af ​​kraftfulde funktioner, den tilbyder. Vi vil også dykke ned i praktiske eksempler og demonstrere, hvordan DSPy kan transformere den måde, du udvikler AI-systemer med LLM'er.

Hvad er DSPy, og hvorfor har du brug for det?

DSPy er en ramme, der adskiller strømmen af ​​dit program (modules) fra parametrene (LM-prompter og vægte) for hvert trin. Denne adskillelse giver mulighed for systematisk optimering af LM-prompter og vægte, hvilket gør det muligt for dig at bygge komplekse AI-systemer med større pålidelighed, forudsigelighed og overholdelse af domænespecifikke begrænsninger.

Traditionelt involverede udvikling af AI-systemer med LLM'er en møjsommelig proces med at nedbryde problemet i trin, skabe indviklede prompter for hvert trin, generere syntetiske eksempler til finjustering og manuelt guide LM'erne til at overholde specifikke begrænsninger. Denne tilgang var ikke kun tidskrævende, men også tilbøjelig til fejl, da selv mindre ændringer i pipeline, LM eller data kunne nødvendiggøre omfattende omarbejdning af prompter og finjusteringstrin.

DSPy løser disse udfordringer ved at introducere et nyt paradigme: optimizere. Disse LM-drevne algoritmer kan justere meddelelserne og vægten af ​​dine LM-opkald, givet en metrik, du ønsker at maksimere. Ved at automatisere optimeringsprocessen giver DSPy udviklere mulighed for at bygge robuste AI-systemer med minimal manuel indgriben, hvilket forbedrer pålideligheden og forudsigeligheden af ​​LM-output.

DSPy's modulære arkitektur

I hjertet af DSPy ligger en modulær arkitektur, der letter sammensætningen af ​​komplekse AI-systemer. Rammen giver et sæt indbyggede moduler, der abstraherer forskellige promptteknikker, som f.eks dspy.ChainOfThought og dspy.ReAct. Disse moduler kan kombineres og sammensættes til større programmer, hvilket giver udviklere mulighed for at bygge indviklede pipelines, der er skræddersyet til deres specifikke krav.

Hvert modul indkapsler parametre, der kan læres, inklusive instruktionerne, eksempler på få skud og LM-vægte. Når et modul påkaldes, kan DSPy's optimizere finjustere disse parametre for at maksimere den ønskede metrisk, hvilket sikrer, at LM's output overholder de specificerede begrænsninger og krav.

Optimering med DSPy

DSPy introducerer en række kraftfulde optimeringsværktøjer designet til at forbedre ydeevnen og pålideligheden af ​​dine AI-systemer. Disse optimeringsværktøjer udnytter LM-drevne algoritmer til at justere meddelelserne og vægten af ​​dine LM-opkald, og maksimerer den specificerede metrik, mens de overholder domænespecifikke begrænsninger.

Nogle af de vigtigste optimeringsværktøjer tilgængelige i DSPy inkluderer:

  1. BootstrapFewShot: Denne optimering udvider signaturen ved automatisk at generere og inkludere optimerede eksempler i den prompt, der sendes til modellen, og implementere få-skuds-læring.
  2. BootstrapFewShotWithRandomSearch: Gælder BootstrapFewShot flere gange med tilfældig søgning over genererede demonstrationer, valg af det bedste program frem for optimeringen.
  3. MIPRO: Genererer instruktioner og få-skuds eksempler i hvert trin, hvor instruktionsgenereringen er data- og demonstrationsbevidst. Den bruger Bayesian Optimization til effektivt at søge i genereringsinstruktioner og demonstrationer på tværs af dine moduler.
  4. BootstrapFinetune: Destillerer et prompt-baseret DSPy-program til vægtopdateringer til mindre LM'er, så du kan finjustere de underliggende LLM'er for øget effektivitet.

Ved at udnytte disse optimeringsværktøjer kan udviklere systematisk optimere deres AI-systemer og sikre output af høj kvalitet, mens de overholder domænespecifikke begrænsninger og krav.

Kom godt i gang med DSPy

For at illustrere kraften ved DSPy, lad os gennemgå et praktisk eksempel på at bygge et RAG-system (Retrieval-Augmented Generation) til besvarelse af spørgsmål.

Trin 1: Opsætning af sprogmodellen og genfindingsmodellen

Det første trin involverer konfiguration af sprogmodellen (LM) og genfindingsmodellen (RM) i DSPy.

Sådan installeres DSPy run:

pip install dspy-ai

DSPy understøtter flere LM- og RM-API'er samt lokal modelhosting, hvilket gør det nemt at integrere dine foretrukne modeller.

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)

Trin 2: Indlæsning af datasættet

Dernæst indlæser vi HotPotQA-datasættet, som indeholder en samling af komplekse spørgsmål-svar-par, der typisk besvares på en multi-hop måde.

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]

Trin 3: Byg signaturer

DSPy bruger signaturer til at definere opførsel af moduler. I dette eksempel definerer vi en signatur for svargenereringsopgaven, der specificerer inputfelterne (kontekst og spørgsmål) og outputfeltet (svar).

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

Trin 4: Opbygning af rørledningen

Vi bygger vores RAG-pipeline som et DSPy-modul, som består af en initialiseringsmetode (__init__) til at erklære undermodulerne (dspy.Retrieve og dspy.ChainOfThought) og en fremadrettet metode (fremad) til at beskrive kontrolflowet for besvarelse spørgsmålet ved hjælp af disse moduler.

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)

Trin 5: Optimering af rørledningen

Med pipeline defineret kan vi nu optimere den ved hjælp af DSPy's optimizere. I dette eksempel vil vi bruge BootstrapFewShot optimizer, som genererer og udvælger effektive prompter til vores moduler baseret på et træningssæt og en metrik til validering.

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)

Trin 6: Evaluering af rørledningen

Efter kompilering af programmet er det vigtigt at evaluere dets ydeevne på et udviklingssæt for at sikre, at det opfylder den ønskede nøjagtighed og pålidelighed.

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

Trin 7: Inspicering af modelhistorik

For en dybere forståelse af modellens interaktioner kan du gennemgå de seneste generationer ved at inspicere modellens historie.

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

Trin 8: Lav forudsigelser

Med pipelinen optimeret og evalueret, kan du nu bruge den til at lave forudsigelser på nye spørgsmål.

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

Minimalt arbejdseksempel med DSPy

Lad os nu gå gennem et andet minimalt fungerende eksempel ved at bruge GSM8K datasæt og OpenAI GPT-3.5-turbo-modellen til at simulere promptopgaver inden for DSPy.

Opsætning

Først skal du sikre dig, at dit miljø er korrekt konfigureret:

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)

gsm8k_togsæt og gsm8k_devset Datasæt indeholder en liste over eksempler, hvor hvert eksempel har et spørgsmål og svar felt.

Definer modulet

Derefter skal du definere et brugerdefineret program ved at bruge ChainOfThought-modulet til trin-for-trin-ræsonnement:

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

Kompiler og evaluer modellen

Kompiler det nu med 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)

Dette eksempel viser, hvordan du opsætter dit miljø, definerer et brugerdefineret modul, kompilerer en model og nøje evaluerer dens ydeevne ved hjælp af det medfølgende datasæt og teleprompter-konfigurationer.

Datahåndtering i DSPy

DSPy opererer med træning, udvikling og testsæt. For hvert eksempel i dine data har du typisk tre typer værdier: input, mellemliggende etiketter og endelige etiketter. Mens mellemliggende eller endelige etiketter er valgfrie, er det vigtigt at have nogle få eksempler på input.

Oprettelse af eksempelobjekter

Eksempelobjekter i DSPy ligner Python-ordbøger, men kommer med nyttige værktøjer:

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)

Output:

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

Angivelse af inputtaster

I DSPy har eksempelobjekter en with_inputs()-metode til at markere specifikke felter som input:

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

Værdier kan tilgås ved hjælp af prikoperatoren, og metoder som inputs() og labels() returnerer nye eksempelobjekter, der kun indeholder henholdsvis input- eller non-input-nøgler.

Optimizere i DSPy

En DSPy optimizer tuner parametrene for et DSPy-program (dvs. prompter og/eller LM-vægte) for at maksimere specificerede metrikker. DSPy tilbyder forskellige indbyggede optimizere, der hver anvender forskellige strategier.

Tilgængelige optimeringsværktøjer

  • BootstrapFewShot: Genererer få-shot eksempler ved hjælp af de medfølgende mærkede input- og outputdatapunkter.
  • BootstrapFewShotWithRandomSearch: Anvender BootstrapFewShot flere gange med tilfældig søgning over genererede demonstrationer.
  • COPRO: Genererer og forfiner nye instruktioner for hvert trin, optimerer dem med koordinatstigning.
  • MIPRO: Optimerer instruktioner og få-shot eksempler ved hjælp af Bayesian Optimization.

Valg af en Optimizer

Hvis du ikke er sikker på, hvor du skal starte, så brug BootstrapFewShotWithRandomSearch:

For meget få data (10 eksempler), brug BootstrapFewShot.
For lidt flere data (50 eksempler), brug BootstrapFewShotWithRandomSearch.
For større datasæt (300+ eksempler), brug MIPRO.

Sådan bruger du 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)

Lagring og indlæsning af optimerede programmer

Når du har kørt et program gennem en optimering, skal du gemme det til fremtidig brug:

optimized_program.save(DIN_SAVE_PATH)

Indlæs et gemt program:

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

Avancerede funktioner: DSPy Assertions

DSPy Assertions automatiserer håndhævelsen af ​​beregningsmæssige begrænsninger på LM'er, hvilket forbedrer pålideligheden, forudsigeligheden og korrektheden af ​​LM-output.

Brug af påstande

Definer valideringsfunktioner og erklær påstande efter den respektive modelgenerering. For eksempel:

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

At transformere programmer med påstande

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

Alternativt kan du aktivere påstande direkte på programmet:

baleen_with_assertions = SimplifiedBaleenAssertions().activate_assertions()

Påstandsdrevne optimeringer

DSPy Assertions fungerer med DSPy-optimeringer, især med BootstrapFewShotWithRandomSearch, herunder indstillinger som:

  • Kompilering med påstande
  • Kompilering + slutning med påstande

Konklusion

DSPy tilbyder en kraftfuld og systematisk tilgang til optimering af sprogmodeller og deres prompter. Ved at følge de trin, der er beskrevet i disse eksempler, kan du nemt bygge, optimere og evaluere komplekse AI-systemer. DSPy's modulære design og avancerede optimizere giver mulighed for effektiv og effektiv integration af forskellige sprogmodeller, hvilket gør det til et værdifuldt værktøj for alle, der arbejder inden for NLP og AI.

Uanset om du bygger et simpelt spørgsmålsbesvarelsessystem eller en mere kompleks pipeline, giver DSPy den fleksibilitet og robusthed, der er nødvendig for at opnå høj ydeevne og pålidelighed.

Jeg har brugt de sidste fem år på at fordybe mig i den fascinerende verden af ​​Machine Learning og Deep Learning. Min passion og ekspertise har ført mig til at bidrage til over 50 forskellige software engineering projekter, med særligt fokus på AI/ML. Min vedvarende nysgerrighed har også trukket mig hen imod Natural Language Processing, et felt jeg er ivrig efter at udforske yderligere.