Prompt-Tuning eines Granite-Modells in Python mit watsonx

Autor

Anna Gutowska

AI Engineer, Developer Advocate

IBM

Was ist Prompt-Tuning?

In diesem Tutorial werden wir ein IBM® Granite Model mithilfe eines synthetischen Datensatzes, der Kundenbewertungen zu einem Hundepflegeunternehmen enthält, anpassen.

Prompt-Tuning ist eine effiziente und kostengünstige Methode, um ein Foundation Model für künstliche Intelligenz (KI) an neue nachgelagerte Aufgaben anzupassen, ohne das gesamte Modell neu zu trainieren und seine Parameter zu aktualisieren zu müssen.

Überblick über die LLM-Optimierung

Foundation Models basieren auf großen Sprachmodellen (LLMs) und erhalten große Mengen an Trainingsdaten. Häufige Anwendungsfälle von Foundation Models sind Chatbots und virtuelle Assistenten.

Es gibt verschiedene Möglichkeiten, die Interpretation von Eingaben und die Qualität der Antworten eines Foundation Models zu verbessern. Um diese Nuancen besser zu verstehen, vergleichen wir einige der Methoden.

  • Prompt Engineering ist die Optimierung der Antworten eines vorab trainierten Modells durch die Bereitstellung eines gut gestalteten Prompts. Mit dieser Technik werden keine neuen Daten eingebracht und das Modell bleibt unverändert. Bei dieser Methode erhält das Modell einen Eingabeprompt und einen konstruierten Prompt davor. Sie können zum Beispiel den Prompt: "Englisch ins Spanische übersetzen" mit der Eingabe: "Guten Morgen" verwenden. Diese Methode erfordert mehr Arbeit vom Benutzer. Diese manuelle menschliche Anstrengung zur Formulierung effektiver Prompts hilft generativen KI-Modellen jedoch, aufgabenspezifische Antworten zu produzieren, ohne dass das gesamte Foundation Model neu trainiert werden muss.
  • Die Feinabstimmung großer Sprachmodelle umfasst die Optimierung des Modells durch die Bereitstellung einer großen Anzahl beschrifteter Datensätze. Mit zunehmender Aufgabenvielfalt wird die Feinabstimmung, die die Modellgewichtungen verändert, schwieriger zu handhaben. Dies erfordert eine erhebliche Menge an Rechenressourcen. Diese Methode weist jedoch tendenziell die höchste Genauigkeit auf, da das Modell für sehr spezifische Anwendungsfälle trainiert werden kann.
  • Anders als bei der Feinabstimmung werden beim Prompt-Tuning die vortrainierten Modellgewichtungen nicht geändert. Stattdessen lenkt diese parametereffizient Technik die Antworten des Modells in die bevorzugte Richtung, indem die Prompt-Parameter angepasst werden. Das Modell wird mit einer Eingabe sowie anpassbaren Soft-Prompts versehen, die von der KI selbst generiert werden. Dieser aufgabenspezifische Kontext leitet das umfangreiche Modell dazu an, seine Antworten auf eine begrenzte Aufgabe zuzuschneiden, selbst bei begrenzten Daten.
  • Ähnlich wie beim Prompt-Tuning empfängt das Modell beim Präfix-Tuning mehrere Beispiele für bevorzugte Ausgaben. Der Unterschied besteht darin, dass auch ein Präfix in Form einer Reihe aufgabenspezifischer Vektoren enthalten ist. Die Präfix-Optimierung umfasst sowohl weiche Prompts als auch Prompts, die in die Schichten des Deep-Learning-Modells eingefügt werden. Diese sogenannten „virtuellen Token“ geben dem abgestimmten Modell die Flexibilität, eine Vielzahl neuer Aufgaben gleichzeitig zu unterstützen. Diese Methode erzielt eine ähnliche Leistung wie die Feinabstimmung aller Schichten und trainiert nur etwa 0,1 % der Parameter. Das Präfix-Tuning übertrifft sogar die Feinabstimmung in Umgebungen mit geringer Datenmenge.

Soft Prompts im Vergleich zu Hard Prompts

Harte Prompts sind benutzerorientiert und erfordern eine Reaktion des Benutzers. Ein Hard Prompt kann als Vorlage oder Anweisung für das LLM dienen, um Antworten zu generieren. Als Nächstes wird ein Beispiel für einen harten Prompt vorgestellt. Wir empfehlen Ihnen, die IBM Dokumentationsseite zu lesen, um weitere Informationen zu diesem und mehreren anderen Prompttyp zu erhalten.

###For demonstration purposes only. It is not necessary to run this code block.
hard_prompt_template = """Generate a summary of the context that answers the question. Explain the answer in multiple steps if possible.
Answer style should match the context. Ideal Answer length is 2-3 sentences.\n\n{context}\nQuestion: {question}\nAnswer:
"""

Unter Verwendung dieser Hard-Prompt-Vorlage können einem LLM spezifische Anweisungen zur bevorzugten Ausgabestruktur und zum bevorzugten Ausgabestil bereitgestellt werden. Durch diesen expliziten Prompt würde das LLM eher gewünschte Antworten von höherer Qualität liefern.

Soft Prompts werden im Gegensatz zu Hard Prompts nicht in natürlicher Sprache verfasst. Stattdessen werden Prompts als KI-generierte, numerische Vektoren initialisiert, die an den Anfang jeder Eingabe-Einbettung angehängt werden, die das Wissen aus dem größeren Modell destilliert. Diese mangelnde Interpretierbarkeit erstreckt sich auch auf die KI, die für eine bestimmte Aufgabe optimierte Prompts auswählt. Oft kann die KI nicht erklären, warum sie diese Einbettungen ausgewählt hat. Im Vergleich zu anderen Prompting-Methoden sind diese virtuellen Token weniger rechenintensiv als die Feinabstimmung, da das Modell selbst mit festen Gewichtungen eingefroren bleibt. Soft Prompts übertreffen in der Regel auch die von Menschen entwickelten Hard Prompts.

In diesem Tutorial arbeiten wir mit weichen Prompts zur Prompt-Optimierung.

Voraussetzungen

Sie benötigen ein IBM® Cloud-Konto für das Erstellen eines watsonx.ai-Projekts.

Schritte

Schritt 1. Einrichten Ihrer Umgebung

Sie können zwar aus mehreren Tools wählen, aber dieses Tutorial führt Sie durch die Einrichtung eines IBM® Kontos für die Verwendung eines Jupyter Notebook.

  1. Melden Sie sich bei watsonx.ai mit Ihrem IBM Cloud-Konto an.

  2. Erstellen Sie ein watsonx.ai-Projekt.

    Sie können Ihre Projekt-ID in Ihrem Projekt abrufen. Klicken Sie auf die Registerkarte „Verwalten“. Kopieren Sie dann die Projekt-ID aus dem Abschnitt „Details“ der Seite „Allgemein“. Sie benötigen diese ID für dieses Tutorial.

  3. Erstellen Sie ein Jupyter Notebook.

    In diesem Schritt wird eine Notebook-Umgebung geöffnet, in der Sie den Code aus diesem Tutorial kopieren können, um das Prompt-Tuning selbst zu implementieren. Alternativ können Sie dieses Notebook auf Ihr lokales System herunterladen und als Asset in Ihr watsonx.ai-Projekt hochladen. Dieses Jupyter Notebook sowie die verwendeten Datensätzen finden Sie auf GitHub.

Schritt 2. Einrichten einer watsonx.ai Runtime-Instanz und eines API-Schlüssels

  1. Erstellen Sie eine watsonx.ai Runtime -Service-Instanz (wählen Sie Ihre entsprechende Region aus und wählen Sie den Lite-Plan, der eine kostenlose Instanz ist).

  2. Generieren Sie einen API-Schlüssel.

  3. Verknüpfen Sie die Instanz des watsonx.ai-Runtime-Service mit dem Projekt, das Sie in watsonx.ai erstellt haben.

Schritt 3. Installieren und importieren Sie relevante Bibliotheken und richten Sie Ihre Zugangsdaten ein.

Für dieses Tutorial benötigen wir einige Bibliotheken und Module. Stellen Sie sicher, dass Sie Folgendes importieren; wenn diese nicht installiert sind, können Sie das Problem mit einer schnellen PIP-Installation beheben.

#installations
%pip install ibm-watsonx-ai | tail -n 1
%pip install pandas | tail -n 1
%pip install wget | tail -n 1
%pip install scikit-learn | tail -n 1
%pip install matplotlib | tail -n 1 #imports
import wget
import pandas as pd

from ibm_watsonx_ai import APIClient
from ibm_watsonx_ai.foundation_models.utils.enums import ModelTypes
from ibm_watsonx_ai.experiment import TuneExperiment
from ibm_watsonx_ai.helpers import DataConnection
from ibm_watsonx_ai.foundation_models import ModelInference
from sklearn.metrics import accuracy_score, f1_score
from datetime import datetime

Richten Sie Ihre Zugangsdaten ein. Geben Sie Ihren API-Schlüssel und Ihre Projekt-ID ein.

credentials = {
    "url": "https://us-south.ml.cloud.ibm.com",
    "apikey": "YOUR_API_KEY_HERE"
}

project_id = "YOUR_PROJECT_ID_HERE"

Schritt 4. Einrichten der Umgebung und Importieren des Datensatzes

Erstellen Sie als ersten Schritt beim Einrichten der Umgebung eine Instanz von APIClient mit Ihren Authentifizierungsdaten, und legen Sie Ihre project_id fest.

client = APIClient(credentials)
client.set.default_project(project_id)

Ausgabe: 

'SUCCESS'

Für dieses Tutorial verwenden wir einen synthetischen Datensatz, der aus Reviews von Hundepflegeunternehmen besteht. Über die entsprechende URL können wir den Datensatz mit dem API-Client verbinden.

Sie können jeden Datensatz Ihrer Wahl verwenden. Auf Plattformen wie HuggingFace sind mehrere Open-Source-Datensätze verfügbar.

train_filename = 'dog_grooming_reviews_train_data.json'

url = "https://raw.githubusercontent.com/AnnaGutowska/think/main/tutorials/prompt-tuning-tutorial/" + train_filename
wget.download(url)

asset_details = client.data_assets.create(name=train_filename, file_path=train_filename)
asset_id = client.data_assets.get_id(asset_details)

Output:

Creating data asset...

ERFOLG

print(asset_id)

Ausgabe: 

3b1db894-8d9e-428d-8fee-d96f328c7726

Um eine Erkenntnis zur Formatierung dieser Kunden-Reviews zu erhalten, laden wir die Daten in einen Pandas-Datenrahmen und geben ein paar Zeilen aus, die sowohl positive als auch negative Reviews anzeigen. Die Ausgabe „1“ steht für positive Bewertungen und „0“ für negative Bewertungen.

pd.set_option('display.max_colwidth', None)
df = pd.read_json(train_filename)
df[5:10]

Output:

Screenshot eines Trainingsdatensatzes mit Kommentarbeispielen und zugehörigen Werten 1 und 0, wobei 1 ein positiver Kommentar und 0 ein negativer Kommentar ist Trainingsdatensatz

Schritt 5. Abstimmen des Modells.

Die Klasse TuneExperiment ist dafür da, Experimente zu erstellen und Tunings zu planen. Damit können wir unser Experiment initialisieren und unser Foundation Model sowie unsere Trainingsdaten sowie unsere Parameter festlegen. Das Ziel dieser Prompt-Tuning-Übung besteht darin, das LLM so zu trainieren, dass es seine Antworten entsprechend den aus unserem Datensatz extrahierten Kundezufriedenheitsbewertungen anpasst. Dies ist eine Klassifizierungsaufgabe, da die Reviews entweder als positiv (1) oder negativ (0) klassifiziert werden können.

Für dieses Tutorial schlagen wir vor, ein IBM Granite Model als großes Sprachmodell zu verwenden, um ähnliche Ergebnisse zu erzielen.

experiment = TuneExperiment(credentials,
    project_id=project_id
)

prompt_tuner = experiment.prompt_tuner(name="prompt tuning tutorial",
    task_id=experiment.Tasks.CLASSIFICATION,
    base_model="ibm/granite-3-8b-instruct",
    accumulate_steps=16,
    batch_size=8,
    learning_rate=0.001,
    max_input_tokens=128,
    max_output_tokens=2,
    num_epochs=12,
    tuning_type=experiment.PromptTuningTypes.PT,
    init_text="Extract the satisfaction from the comment. Return simple '1' for satisfied customer or '0' for unsatisfied. Comment:",
    init_method="text",
    verbalizer="classify {0, 1} {{input}}",
    auto_update_model=True
)

Nachdem wir unser Tuning-Experiment nun eingerichtet haben, müssen wir es mit unserem Datensatz verknüpfen. Verwenden wir hierfür die Klasse DataConnection. Dies erfordert die Asset_ID, die wir zuvor beim Initiieren des Assets mit unserem API-Client erstellt haben.

data_conn = DataConnection(data_asset_id=asset_id)

Sie können ein KI-Modell Ihrer Wahl verwenden. Die Foundation Models, die über watsonx® abgestimmt werden können, finden Sie hier oder mit dem folgenden Befehl.

client.foundation_models.PromptTunableModels.show()

Output:

{'FLAN_T5_XL': 'google/flan-t5-xl', 'GRANITE_13B_INSTRUCT_V2': 'ibm/granite-13b-instruct-v2', 'LLAMA_2_13B_CHAT': 'meta-llama/llama-2-13b-chat'}

tuning_details = prompt_tuner.run(
    training_data_references=[data_conn],
    background_mode=False)

Output:

##############################################

Running '20671f17-ff53-470b-9bfe-04318ecb91d9'

##############################################


pending......
running....................................................................................................................................
completed
Training of '20671f17-ff53-470b-9bfe-04318ecb91d9' finished successfully.

Schritt 6. Werten Sie die Optimierungsergebnisse aus.

Um sicherzustellen, dass unser Prompt-Tuning abgeschlossen ist, können wir den Status überprüfen. Wenn der Status nicht als „Abgeschlossen“ angezeigt wird, warten Sie bitte, bis das Tuning abgeschlossen ist, bevor Sie fortfahren.

status = prompt_tuner.get_run_status()
print(status)

Ausgabe: 

completed

Wir können jetzt die Prompt-Tuning-Zusammenfassung abrufen. In dieser Zusammenfassung sehen Sie einen Verlustwert. Bei jedem Trainingsdurchlauf misst die Verlustfunktion die Differenz zwischen den vorhergesagten und den tatsächlichen Ergebnissen. Daher wird ein niedrigerer Verlustwert bevorzugt.

prompt_tuner.summary()

Mithilfe der Funktion plot_learning_curve() können wir die Lernkurve unserer Modellabstimmung darstellen. Eine nach unten abfallende Kurve, die sich der Null annähert, weist darauf hin, dass das Modell die erwartete Ausgabeerzeugung verbessert. Weitere Informationen zur Interpretation von Verlustfunktionsdiagrammen finden Sie in der entsprechenden IBM watsonx-Dokumentation.

prompt_tuner.plot_learning_curve()

Output:

Lernkurvendiagramme Lernkurvendiagramme

Schritt 7. Bereitstellen des optimierten Modells

Dieser Schritt, bei dem das optimierte Modell bereitgestellt wird, ist kritisch für die nächsten Schritte, nämlich für den Vergleich der Leistung des optimierten Modells mit der des vortrainierten Modells.

Hinweis: Der SERVING_NAME wird auf das aktuelle Datum und die aktuelle Uhrzeit gesetzt, da es sich dabei um einen eindeutigen Wert handeln muss.

model_id = prompt_tuner.get_model_id()

meta_props = {
    client.deployments.ConfigurationMetaNames.NAME: "PROMP TUNE DEPLOYMENT",
    client.deployments.ConfigurationMetaNames.ONLINE: {},
    client.deployments.ConfigurationMetaNames.SERVING_NAME : datetime.now().strftime('%Y_%m_%d_%H%M%S')
}

deployment_details = client.deployments.create(model_id, meta_props)

Ausgabe: 

######################################################################################

Synchronous deployment creation for id: '6aa5dd5c-0cc4-44e0-9730-18303e88e14a' started

######################################################################################


initializing.......................
ready

-----------------------------------------------------------------------------------------------
Successfully finished deployment creation, deployment_id='24a97b84-47d0-4490-9f5f-21ed2376fdd6'
-----------------------------------------------------------------------------------------------

Schritt 8. Testen des optimierten Modells

Testen wir nun die Leistung sowohl des abgestimmten Modells als auch des ursprünglichen Foundation Models, um die Auswirkungen unseres Optimierungsprozesses zu sehen. Laden wir zunächst den Testdatensatz. Dieser Datensatz sollte eine Teilmenge von Daten sein, die bei der Optimierung nicht vorhanden waren. Oft ist der Testdatensatz auch kleiner als der Trainingsdatensatz. Außerdem enthält jede Eingabe im Testdatensatz das Prompt als Präfix des Kommentars des Benutzers.

test_filename = 'dog_grooming_reviews_test_data.json'
url = "https://raw.githubusercontent.com/AnnaGutowska/think/main/tutorials/prompt-tuning-tutorial/" + test_filename
wget.download(url)
data = pd.read_json(test_filename)

Zeigen wir einen kleinen Teil des Datensatzes an, um seine Struktur besser zu verstehen.

data.head()

Output:

Screenshot eines Trainingsdatensatzes mit Kommentarbeispielen und zugehörigen Werten 1 und 0, wobei 1 ein positiver Kommentar und 0 ein negativer Kommentar ist Testdatensatz

Nachdem wir den Testdatensatz geladen haben, extrahieren wir die Eingaben und Ausgaben.

prompts = list(data.input)
satisfaction = list(data.output)
prompts_batch = ["\n".join([prompt]) for prompt in prompts]

Um zu veranschaulichen, wie wir den Inhalt des Datensatzes extrahiert haben, können wir ein Beispiel für Eingabe und Ausgabe drucken.

prompts[0]

Output:

'Extract the satisfaction from the comment. Return simple 1 for satisfied customer or 0 for unsatisfied.\nComment: Long wait times.\nSatisfaction:\n'

In diesem Beispiel wird das Prompt eingeführt, gefolgt von der Kunden-Review zu langen Wartezeiten und schließlich ist die Zufriedenheit 0, was eine negative Bewertung bedeutet.

satisfaction[0]

Ausgabe: 

0

Nachdem wir nun den Testdatensatz haben, wollen wir die Genauigkeit und den F1-Wert unseres abgestimmten Modells testen. Der F1-Wert ist der Mittelwert für Präzision und Rückruf des Modells. Dazu benötigen wir deployment_id. Beachten Sie, dass concurrency_limit auf 2 gesetzt ist, um zu vermeiden, dass das Ratenlimit der API erreicht wird. Dies ist die Anzahl der Anfragen, die parallel gesendet werden.

deployment_id = deployment_details['metadata']['id']

tuned_model = ModelInference(
    deployment_id=deployment_id,
    api_client=client
)

tuned_model_results = tuned_model.generate_text(prompt=prompts_batch, concurrency_limit=2)
print(f'accuracy_score: {accuracy_score(satisfaction, [int(float(x)) for x in tuned_model_results])}, f1_score: {f1_score(satisfaction, [int(float(x)) for x in tuned_model_results])}')

Output:

accuracy_score: 0.9827586206896551, f1_score: 0.9827586206896551

Angesichts der hohen Genauigkeit und des F1-Wertes unseres Modells testen wir die Leistung desselben Granite-Modells ohne jegliche Optimierung.

base_model = ModelInference(
    model_id="ibm/granite-3-8b-instruct",
    api_client=client
)

base_model_results = base_model.generate_text(prompt=prompts_batch, concurrency_limit=2)

print(f'base model accuracy_score: {accuracy_score(satisfaction, [int(x) for x in base_model_results])}, base model f1_score: {f1_score(satisfaction, [int(x) for x in base_model_results])}')

Output:

base model accuracy_score: 0.9310344827586207, base model f1_score: 0.9298245614035088

Unser optimiertes Modell übertrifft das vortrainierte Foundation Model. Da das optimierte Modell auf das Extrahieren von Zufriedenheitswerten spezialisiert ist, kann es für andere Aufgaben der Zufriedenheitsanalyse verwendet werden. Gut gemacht!

Zusammenfassung

In diesem Tutorial haben Sie mit der watsonx API ein Prompt-Tuning an einem IBM Granite-Modell durchgeführt. Ihr optimiertes und bereitgestelltes Modell hat das Foundation Model mit einer um etwa 5 % höheren Genauigkeit erfolgreich übertroffen.

Weiterführende Lösungen
IBM watsonx.ai

Trainieren, validieren, optimieren und implementieren Sie generative KI, Foundation Models und maschinelle Lernfunktionen mit IBM watsonx.ai, einem Studio der nächsten Generation für AI Builder in Unternehmen. Erstellen Sie KI-Anwendungen mit einem Bruchteil der Zeit und Daten.

watsonx.ai erkunden
Lösungen im Bereich künstlicher Intelligenz

Setzen Sie KI in Ihrem Unternehmen ein
– mit branchenführendem Fachwissen im Bereich KI und dem umfassenden Lösungsportfolio von IBM an Ihrer Seite.

Erkunden Sie KI-Lösungen
Beratung und Services zu künstlicher Intelligenz (KI)

Die KI-Services von IBM Consulting unterstützen Sie dabei, die Art und Weise, wie Unternehmen mit KI arbeiten, neu zu denken.

KI-Services entdecken
Machen Sie den nächsten Schritt

Mithilfe von KI liefert IBM Concert wichtige Erkenntnisse über Ihre Abläufe und gibt anwendungsspezifische Empfehlungen zur Verbesserung. Entdecken Sie, wie Concert Ihr Unternehmen voranbringen kann.

Entdecken Sie Concert Erkunden Sie Lösungen zur Geschäftsprozessautomatisierung