Connect with us

Optimiser LLM avec DSPy : Un guide étape par étape pour construire, optimiser et évaluer les systèmes d’IA Spécifier les clés d’entrée Dans DSPy, les objets Example ont une méthode with_inputs() pour marquer des champs spécifiques comme entrées : Les valeurs peuvent être accessibles en utilisant l’opérateur de point, et les méthodes comme inputs() et labels() renvoient de nouveaux objets Example contenant uniquement les clés d’entrée ou non d’entrée, respectivement. Optimiseurs dans DSPy Un optimiseur DSPy ajuste les paramètres d’un programme DSPy (c’est-à-dire les invites et/ou les poids LM) pour maximiser les métriques spécifiées. DSPy propose divers optimiseurs intégrés, chacun employant des stratégies différentes. Optimiseurs disponibles BootstrapFewShot : Génère des exemples à quelques coups en utilisant les points de données étiquetés d’entrée et de sortie fournis. BootstrapFewShotWithRandomSearch : Applique BootstrapFewShot plusieurs fois avec une recherche aléatoire sur les démonstrations générées. COPRO : Génère et affine de nouvelles instructions pour chaque étape, en les optimisant avec une montée de coordonnées. MIPRO : Optimise les instructions et les exemples à quelques coups en utilisant l’optimisation bayésienne. Choisir un optimiseur Si vous êtes incertain sur où commencer, utilisez BootstrapFewShotWithRandomSearch : Pour très peu de données (10 exemples), utilisez BootstrapFewShot. Pour un peu plus de données (50 exemples), utilisez BootstrapFewShotWithRandomSearch. Pour des jeux de données plus importants (300+ exemples), utilisez MIPRO.

Prompt engineering

Optimiser LLM avec DSPy : Un guide étape par étape pour construire, optimiser et évaluer les systèmes d’IA Spécifier les clés d’entrée Dans DSPy, les objets Example ont une méthode with_inputs() pour marquer des champs spécifiques comme entrées : Les valeurs peuvent être accessibles en utilisant l’opérateur de point, et les méthodes comme inputs() et labels() renvoient de nouveaux objets Example contenant uniquement les clés d’entrée ou non d’entrée, respectivement. Optimiseurs dans DSPy Un optimiseur DSPy ajuste les paramètres d’un programme DSPy (c’est-à-dire les invites et/ou les poids LM) pour maximiser les métriques spécifiées. DSPy propose divers optimiseurs intégrés, chacun employant des stratégies différentes. Optimiseurs disponibles BootstrapFewShot : Génère des exemples à quelques coups en utilisant les points de données étiquetés d’entrée et de sortie fournis. BootstrapFewShotWithRandomSearch : Applique BootstrapFewShot plusieurs fois avec une recherche aléatoire sur les démonstrations générées. COPRO : Génère et affine de nouvelles instructions pour chaque étape, en les optimisant avec une montée de coordonnées. MIPRO : Optimise les instructions et les exemples à quelques coups en utilisant l’optimisation bayésienne. Choisir un optimiseur Si vous êtes incertain sur où commencer, utilisez BootstrapFewShotWithRandomSearch : Pour très peu de données (10 exemples), utilisez BootstrapFewShot. Pour un peu plus de données (50 exemples), utilisez BootstrapFewShotWithRandomSearch. Pour des jeux de données plus importants (300+ exemples), utilisez MIPRO.

mm
DSPy is a framework for algorithmically optimizing LM prompts and weights

À mesure que les capacités des grands modèles de langage (LLM) continuent de s’étendre, développer des systèmes d’IA robustes qui tirent parti de leur potentiel est devenu de plus en plus complexe. Les approches conventionnelles impliquent souvent des techniques d’invocation intriquées, la génération de données pour le fine-tuning et une guidance manuelle pour assurer le respect des contraintes spécifiques au domaine. Cependant, ce processus peut être fastidieux, sujet à des erreurs et fortement dépendant de l’intervention humaine.

Entrez DSPy, un cadre révolutionnaire conçu pour rationaliser le développement de systèmes d’IA alimentés par les LLM. DSPy introduit une approche systématique pour optimiser les invites LM et les poids, permettant aux développeurs de construire des applications sophistiquées avec un minimum d’efforts manuels.

Dans ce guide complet, nous allons explorer les principes fondamentaux de DSPy, son architecture modulaire et la gamme de fonctionnalités puissantes qu’il propose. Nous allons également plonger dans des exemples pratiques, démontrant comment DSPy peut transformer la façon dont vous développez des systèmes d’IA avec les LLM.

Qu’est-ce que DSPy, et pourquoi en avez-vous besoin ?

DSPy est un cadre qui sépare le flux de votre programme (modules) des paramètres (invites LM et poids) de chaque étape. Cette séparation permet l’optimisation systématique des invites LM et des poids, vous permettant de construire des systèmes d’IA complexes avec une plus grande fiabilité, prévisibilité et respect des contraintes spécifiques au domaine.

Traditionnellement, le développement de systèmes d’IA avec les LLM impliquait un processus fastidieux de décomposition du problème en étapes, d’élaboration d’invites intriquées pour chaque étape, de génération d’exemples synthétiques pour le fine-tuning et de guidance manuelle pour que les LM respectent des contraintes spécifiques. Cette approche n’était pas seulement chronophage mais également sujette à des erreurs, car même de petits changements dans le pipeline, le LM ou les données pouvaient nécessiter une refonte extensive des invites et des étapes de fine-tuning.

DSPy répond à ces défis en introduisant un nouveau paradigme : les optimiseurs. Ces algorithmes basés sur les LM peuvent ajuster les invites et les poids de vos appels LM, étant donné une métrique que vous souhaitez maximiser. En automatisant le processus d’optimisation, DSPy permet aux développeurs de construire des systèmes d’IA robustes avec une intervention manuelle minimale, améliorant ainsi la fiabilité et la prévisibilité des sorties LM.

Architecture modulaire de DSPy

Au cœur de DSPy se trouve une architecture modulaire qui facilite la composition de systèmes d’IA complexes. Le cadre propose un ensemble de modules intégrés qui abstraient diverses techniques d’invocation, telles que dspy.ChainOfThought et dspy.ReAct. Ces modules peuvent être combinés et composés en programmes plus grands, permettant aux développeurs de construire des pipelines intriqués adaptés à leurs besoins spécifiques.

Chaque module encapsule des paramètres apprenables, y compris les instructions, les exemples à quelques coups et les poids LM. Lorsqu’un module est invoqué, les optimiseurs de DSPy peuvent affiner ces paramètres pour maximiser la métrique souhaitée, garantissant que les sorties LM respectent les contraintes et les exigences spécifiées.

Optimisation avec DSPy

DSPy introduit une gamme d’optimiseurs puissants conçus pour améliorer les performances et la fiabilité de vos systèmes d’IA. Ces optimiseurs utilisent des algorithmes basés sur les LM pour ajuster les invites et les poids de vos appels LM, maximisant la métrique spécifiée tout en respectant les contraintes spécifiques au domaine.

Certains des optimiseurs clés disponibles dans DSPy incluent :

  1. BootstrapFewShot : Cet optimiseur étend la signature en générant et en incluant automatiquement des exemples optimisés dans l’invite envoyée au modèle, mettant en œuvre l’apprentissage à quelques coups.
  2. BootstrapFewShotWithRandomSearch : Applique BootstrapFewShot plusieurs fois avec une recherche aléatoire sur les démonstrations générées, sélectionnant le meilleur programme sur l’optimisation.
  3. MIPRO : Génère des instructions et des exemples à quelques coups à chaque étape, avec la génération d’instructions étant consciente des données et des démonstrations. Il utilise l’optimisation bayésienne pour effectuer une recherche efficace dans l’espace des instructions de génération et des démonstrations à travers vos modules.
  4. BootstrapFinetune : Distille un programme DSPy basé sur les invites en mises à jour de poids pour les LLM plus petits, vous permettant de fine-tuner les LLM sous-jacents pour une efficacité améliorée.

En utilisant ces optimiseurs, les développeurs peuvent optimiser systématiquement leurs systèmes d’IA, garantissant des sorties de haute qualité tout en respectant les contraintes et les exigences spécifiques au domaine.

Commencer avec DSPy

Pour illustrer la puissance de DSPy, décomposons un exemple pratique de construction d’un système de génération assistée par récupération (RAG) pour la question-réponse.

Étape 1 : Configurer le modèle de langage et le modèle de récupération

La première étape consiste à configurer le modèle de langage (LM) et le modèle de récupération (RM) dans DSPy.

Pour installer DSPy, exécutez :


pip install dspy-ai

DSPy prend en charge plusieurs API LM et RM, ainsi que l’hébergement de modèles locaux, ce qui facilite l’intégration de vos modèles préférés.


import dspy

# Configurez le LM et le 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)

Étape 2 : Charger le jeu de données

Ensuite, nous allons charger le jeu de données HotPotQA, qui contient une collection de paires question-réponse complexes généralement répondues de manière multihop.


from dspy.datasets import HotPotQA

# Charger le jeu de données
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)

# Spécifier le champ 'question' comme entrée
trainset = [x.with_inputs('question') for x in dataset.train]
devset = [x.with_inputs('question') for x in dataset.dev]

Étape 3 : Construire des signatures

DSPy utilise des signatures pour définir le comportement des modules. Dans cet exemple, nous allons définir une signature pour la tâche de génération de réponses, en spécifiant les champs d’entrée (contexte et question) et le champ de sortie (réponse).


class GenerateAnswer(dspy.Signature):
"""Répondez aux questions avec des réponses factuelles courtes."""

context = dspy.InputField(desc="peut contenir des faits pertinents")
question = dspy.InputField()
answer = dspy.OutputField(desc="souvent entre 1 et 5 mots")

Étape 4 : Construire le pipeline

Nous allons construire notre pipeline RAG en tant que module DSPy, qui consiste en une méthode d’initialisation (__init__) pour déclarer les sous-modules (dspy.Retrieve et dspy.ChainOfThought) et une méthode forward (forward) pour décrire le flux de contrôle de la réponse à la question en utilisant ces modules.


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)

Étape 5 : Optimiser le pipeline

Avec le pipeline défini, nous pouvons maintenant l’optimiser en utilisant les optimiseurs de DSPy. Dans cet exemple, nous allons utiliser l’optimiseur BootstrapFewShot, qui génère et sélectionne des invites efficaces pour nos modules en fonction d’un jeu de formation et d’une métrique de validation.


from dspy.teleprompt import BootstrapFewShot

# Métrique de validation
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

# Configurer l'optimiseur
teleprompter = BootstrapFewShot(metric=validate_context_and_answer)

# Compiler le programme
compiled_rag = teleprompter.compile(RAG(), trainset=trainset)

Étape 6 : Évaluer le pipeline

Après avoir compilé le programme, il est essentiel de l’évaluer sur un jeu de développement pour garantir qu’il répond aux niveaux de précision et de fiabilité souhaités.


from dspy.evaluate import Evaluate

# Configurer l'évaluateur
evaluate = Evaluate(devset=devset, metric=validate_context_and_answer, num_threads=4, display_progress=True, display_table=0)

# Évaluer le programme RAG compilé
evaluation_result = evaluate(compiled_rag)

print(f"Résultat de l'évaluation : {evaluation_result}")

Étape 7 : Inspecter l’historique du modèle

Pour une compréhension plus approfondie des interactions du modèle, vous pouvez examiner les générations les plus récentes en inspectant l’historique du modèle.


# Inspecter l'historique du modèle
turbo.inspect_history(n=1)

Étape 8 : Faire des prédictions

Avec le pipeline optimisé et évalué, vous pouvez maintenant l’utiliser pour faire des prédictions sur de nouvelles questions.


# Exemple de question
question = "Quel prix le premier livre de Gary Zukav a-t-il reçu ?"

# Faire une prédiction en utilisant le programme RAG compilé
prediction = compiled_rag(question)

print(f"Question : {question}")
print(f"Réponse : {prediction.answer}")
print(f"Contextes récupérés : {prediction.context}")

Exemple minimal fonctionnel avec DSPy

Maintenant, décomposons un autre exemple minimal fonctionnel en utilisant le jeu de données GSM8K et le modèle OpenAI GPT-3.5-turbo pour simuler des tâches d’invocation dans DSPy.

Configuration

Tout d’abord, assurez-vous que votre environnement est correctement configuré :


import dspy
from dspy.datasets.gsm8k import GSM8K, gsm8k_metric

# Configurer le LM
turbo = dspy.OpenAI(model='gpt-3.5-turbo-instruct', max_tokens=250)
dspy.settings.configure(lm=turbo)

# Charger les questions mathématiques du jeu de données GSM8K
gsm8k = GSM8K()
gsm8k_trainset, gsm8k_devset = gsm8k.train[:10], gsm8k.dev[:10]

print(gsm8k_trainset)

Le jeu de données gsm8k_trainset et gsm8k_devset contient une liste d’exemples avec chaque exemple ayant un champ question et réponse.

Définir le module

Ensuite, définissez un programme personnalisé en utilisant le module ChainOfThought pour la raisonnement étape par étape :


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

def forward(self, question):
return self.prog(question=question)

Compiler et évaluer le modèle

Maintenant, compilez-le avec le téléprompteur BootstrapFewShot :


from dspy.teleprompt import BootstrapFewShot

# Configurer l'optimiseur
config = dict(max_bootstrapped_demos=4, max_labeled_demos=4)

# Optimiser en utilisant la métrique gsm8k_metric
teleprompter = BootstrapFewShot(metric=gsm8k_metric, **config)
optimized_cot = teleprompter.compile(CoT(), trainset=gsm8k_trainset)

# Configurer l'évaluateur
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)

# Inspecter l'historique du modèle
turbo.inspect_history(n=1)

Cet exemple démontre comment configurer votre environnement, définir un module personnalisé, compiler un modèle et évaluer rigoureusement ses performances en utilisant le jeu de données et la configuration du téléprompteur fournis.

Gestion des données dans DSPy

DSPy fonctionne avec des ensembles de formation, de développement et de test. Pour chaque exemple dans vos données, vous avez généralement trois types de valeurs : les entrées, les étiquettes intermédiaires et les étiquettes finales. Bien que les étiquettes intermédiaires ou finales soient facultatives, avoir quelques exemples d’entrée est essentiel.

Créer des objets d’exemple

Les objets d’exemple dans DSPy sont similaires aux dictionnaires Python mais viennent avec des utilitaires utiles :


qa_pair = dspy.Example(question="C'est une question ?", answer="C'est une réponse.")

print(qa_pair)
print(qa_pair.question)
print(qa_pair.answer)

J'ai passé les cinq dernières années à me plonger dans le monde fascinant de l'apprentissage automatique et de l'apprentissage profond. Ma passion et mon expertise m'ont conduit à contribuer à plus de 50 projets de génie logiciel divers, avec un accent particulier sur l'IA/ML. Ma curiosité permanente m'a également attiré vers le traitement automatique des langues, un domaine que je suis impatient d'explorer plus en détail.