Implementierbare Python -Funktionen schreiben
Erfahren Sie, wie Sie eine Python Funktion schreiben und diese dann als Asset speichern, das Sie zum Bereitstellen von Modellen verwenden können.
Eine Liste der allgemeinen Anforderungen für bereitstellbare Funktionen finden Sie unter Allgemeine Anforderungen für bereitstellbare Funktionen. Informationen zu den Vorgängen während einer Funktionsbereitstellung finden Sie unter Prozess zur Bereitstellung von Funktionen
Allgemeine Anforderungen für bereitstellbare Funktionen
Für eine erfolgreiche Bereitstellung muss eine Funktion die folgenden Anforderungen erfüllen:
- Die Python-Funktionsdatei muss beim Import das Funktionsobjekt
scoreals Teil seines Geltungsbereichs enthalten. Weitere Informationen finden Sie unter Anforderungen an die Funktion 'score' - Die Eingabe für die Bewertung muss die Anforderungen erfüllen, die unter „Anforderungen an die Eingabe für die Bewertung“ aufgeführt sind
- Die Ausgabenutzdaten, die als Ausgabe von
scoreerwartet werden, müssen das Schema der Variablenscore_responsefür den Statuscode 200 enthalten. Beachten Sie, dass die Angabe des Parameterspredictionmit einem Array aus JSON-Objekten als Wert in der Ausgabescoreverbindlich ist. - Wenn Sie den Python-Client verwenden, um eine Python-Funktion zu speichern, die einen Verweis auf eine übergeordnete Funktion enthält, wird nur der Code im Geltungsbereich der übergeordneten Funktion (einschließlich der verschachtelten Funktionen) gespeichert. Daher wird der Code außerhalb des Bereichs der übergeordneten Funktion nicht gespeichert und ist daher beim Bereitstellen der Funktion nicht verfügbar.
Anforderungen an die Funktion 'score'
- Es gibt zwei Möglichkeiten, das
scoreFunktionsobjekt hinzuzufügen:- explizit, nach Benutzer
- implizit durch die Methode, die zum Speichern der Python-Funktion als Asset im Watson Machine Learning-Repository verwendet wird
- Die
scoreFunktion kann einen einzelnen JSON-Eingabeparameter oder zwei Parameter akzeptieren: Nutzlast und Bearer-Token. - Die Funktion
scoremuss ein serialisierbares JSON-Objekt (z. B. Wörterverzeichnisse oder Listen) zurückgeben.
Anforderungen an Scoring-Eingabe
Die Scoring-Eingabenutzdaten müssen ein Array mit dem Namen
valuesenthalten, wie in diesem Beispielschema gezeigt. Derinput_dataParameter ist in der Nutzlast obligatorisch. Derinput_dataParameter kann auch zusätzliche Name-Wert-Paare enthalten.{"input_data": [{ "values": [["Hello world!"]] }] }Die Scoring-Eingabedaten müssen als Eingabeparameterwert für
scoreübergeben werden. Auf diese Weise können Sie sicherstellen, dass der Wert desscoreEingabeparameters innerhalb der entsprechend verarbeitetscorewird.Die Scoring-Eingabenutzdaten müssen den Anforderungen für die Eingabe der betreffenden Python-Funktion entsprechen.
Die Scoring-Eingabenutzdaten müssen ein Array enthalten, das dem Datenschema der Beispieleingabe entspricht.
Datenschema der Beispieleingabe
{"input_data": [{
"values": [["Hello, world!"]]
}]
}
Beispielcode Python (Nutzlast und Token)
#wml_python_function
def my_deployable_function():
def score(payload, token):
message_from_input_payload = payload.get("input_data")[0].get("values")[0][0]
response_message = "Received message - {0}".format(message_from_input_payload)
# Score using the pre-defined model
score_response = {
'predictions': [{'fields': ['Response_message_field'],
'values': [[response_message]]
}]
}
return score_response
return score
score = my_deployable_function()
Testen Sie Ihre Python Funktion
So können Sie Ihre Python Funktion testen:
input_data = { "input_data": [{ "fields": [ "message" ],
"values": [[ "Hello, world!" ]]
}
]
}
function_result = score( input_data )
print( function_result )
Es gibt die Meldung „Hallo, Welt!“ zurück.
Prozess zur Bereitstellung von Funktionen
Der Python Code Ihres Funktions-Assets wird von der Watson Machine Learning Engine mithilfe einer import Anweisung als Modul Python geladen. Dies bedeutet, dass der Code genau einmal ausgeführt wird (wenn die Funktion bereitgestellt wird oder bei jedem Neustart des entsprechenden Pods). Die score Funktion, die durch das Funktions-Asset definiert ist, wird dann bei jeder Vorhersageanforderung aufgerufen.
Verarbeitung bereitstellbarer Funktionen
Verwenden Sie eine der folgenden Methoden, um eine bereitstellbare Python-Funktion zu erstellen:
Bereitstellbare Funktionen über REST-API erstellen
Bei REST-APIs muss die score Funktion bereits in der Datei enthalten sein, da die Python Funktion direkt über eine Datei hochgeladen wird. Jeder einmalige Import, der für die spätere Verwendung innerhalb der score Funktion erforderlich ist, kann im globalen Bereich der Datei vorgenommen werden. Wenn diese Datei als Python-Funktion bereitgestellt wird, werden die im globalen Bereich verfügbaren einmaligen Importe während der Bereitstellung ausgeführt und später bei jeder Vorhersageanforderung einfach erneut verwendet.
Das Funktionsarchiv muss eine .gz Datei sein.
Beispielfunktionsdatei score:
Score function.py
---------------------
def score(input_data):
return {'predictions': [{'values': [['Just a test']]}]}
Beispielfunktion score mit einmaligen Importen:
import subprocess
subprocess.check_output('pip install gensim --user', shell=True)
import gensim
def score(input_data):
return {'predictions': [{'fields': ['gensim_version'], 'values': [[gensim.__version__]]}]}
Bereitstellbare Funktionen über den Python-Client erstellen
Um eine Python-Funktion als Asset als persistent zu definieren, verwendet der Python-Client die Methode wml_client.repository.store_function. Sie können eine Python Funktion auf zwei Arten beibehalten:
Eine Funktion über eine Datei hinweg beibehalten, die die Python Funktion enthält
Diese Methode entspricht dem persistenten Speichern der Python-Funktionsdatei über REST-APIs (score muss im Geltungsbereich der Python-Quellendatei definiert sein). Weitere Informationen finden Sie unter Bereitstellbare Funktionen über REST-API erstellen.
Wenn Sie die wml_client.repository.store_function Methode aufrufen, übergeben Sie den Dateinamen als erstes Argument.
Funktion über das Funktionsobjekt als persistent definieren
Sie können Python-Funktionsobjekte persistent speichern, indem Sie Python-Abschlüsse mit einer verschachtelten Funktion namens score erstellen. Die Funktion score wird von der übergeordneten Funktion zurückgegeben, die beim Aufruf als Funktionsobjekt gespeichert wird. Diese score Funktion muss die Anforderungen erfüllen, die unter Allgemeine Anforderungen für bereitstellbare Funktionen aufgeführt sind. In diesem Fall müssen alle einmaligen Importe und die Logik für die Ersteinrichtung in der äußeren verschachtelten Funktion hinzugefügt werden, damit sie während der Bereitstellung ausgeführt und innerhalb der score Funktion verwendet werden. Jede wiederkehrende Logik, die während der prediction Anfrage benötigt wird, muss innerhalb der verschachtelten score Funktion hinzugefügt werden.
Beispielfunktion Python speichern mithilfe des Python Clients:
def my_deployable_function():
import subprocess
subprocess.check_output('pip install gensim', shell=True)
import gensim
def score(input_data):
import
message_from_input_payload = payload.get("input_data")[0].get("values")[0][0]
response_message = "Received message - {0}".format(message_from_input_payload)
# Score using the pre-defined model
score_response = {
'predictions': [{'fields': ['Response_message_field', 'installed_lib_version'],
'values': [[response_message, gensim.__version__]]
}]
}
return score_response
return score
function_meta = {
client.repository.FunctionMetaNames.NAME:"test_function",
client.repository.FunctionMetaNames.SOFTWARE_SPEC_ID: sw_spec_id
}
func_details = client.repository.store_function(my_deployable_function, function_meta)
In diesem Szenario übernimmt die Python Funktion die Aufgabe, eine Python Datei zu erstellen, die die score Funktion enthält, und die Funktionsdatei als Asset im Watson Machine Learning Repository zu speichern:
score = my_deployable_function()
Verwendung von Vault zum Bereitstellen von lang laufenden Funktionen
Das Beispiel verwendet einen IBM internen Tresor. Der interne Tresorraum ist in erster Linie für Proof-of-Concept-Demonstrationen vorgesehen. In Produktionsumgebungen wird dringend empfohlen, eine Verbindung zu einem externen Tresor herzustellen.
Das Standard-Token, das eine bereitstellbare Python Funktion zum Zeitpunkt der Bereitstellung erhält, läuft ab (in der Regel nach einer Stunde) und kann ohne dauerhafte score() Anmeldedaten nicht innerhalb aktualisiert werden.
Vault stellt langlebige Anmeldedaten bereit. Durch das Speichern einer API, eines Benutzernamens oder eines Passworts in einem Vault-Geheimnis können Sie:
- Rufen Sie diese Anmeldedaten während des Bereitstellungsablaufs sicher ab (verwenden Sie das kurzlebige Token nur einmal).
- Verwenden Sie sie, um bei Bedarf einen
score()Client innerhalb zu initialisieren. Diese Anmeldedaten verfallen nicht wie ein Token, sodass sich der Client jederzeit erneut authentifizieren kann.
Voraussetzungen
Sie müssen eine Tresorintegration und einen Tresorgeheimnis in erstellen, um die Tresorfunktionalität für IBMSoftware Hub die Bereitstellung von Python Funktionen nutzen zu können. Weitere Informationen finden Sie unter Verwalten von Geheimnissen und Tresoren in der IBMSoftware Hub Dokumentation.
Geheimnisse im Tresor speichern
So speichern Sie Ihre Geheimnisse im Tresor:
Rufen Sie die URN des Tresors ab. Holen Sie den
vault_urnfür den Tresor, in dem Geheimnisse aufbewahrt werden müssen.import requests host = os.environ.get("RUNTIME_ENV_APSX_URL") token = client._get_icptoken()provider_name = "internal" url = host + "/zen-data/v2/vaults" headers = { "Content-Type": "application/json", "Authorization": "Bearer " + token } params = {"provider_name": provider_name} response = requests.get(url, headers=headers, params=params, verify=False) vault_list = response.json()["vaults"] vault_urn = vault_list[0]["vault_urn"] vault_urnGeheimnisse im Tresor aufbewahren. Verwenden Sie die
vault_urnOption, um den Benutzernamen und das Passwort sicher als Geheimnis im Tresor zu speichern.url = host + "/zen-data/v2/secrets" headers = { "Content-Type": "application/json", "Authorization": "Bearer " + token } data = { "secret_name": secret_name, "description": "This is my secret", "secret": { "credentials": { "username": username, "password": password } }, "type": "credentials", "vault_urn": vault_urn } response = requests.post(url, headers=headers, json=data) response.json()
Erstellen einer bereitstellbaren Python Funktion, die Geheimnisse aus dem Tresor verwendet
So erstellen Sie eine bereitstellbare Python Funktion, die Geheimnisse aus dem Tresor verwendet:
- Initialisieren Sie während des Bereitstellungsablaufs den Client mit der Plattform, um das URL Bereitstellungstoken zu extrahieren.
- Verwenden Sie dieses Token, um das gespeicherte Geheimnis aus dem Tresor abzurufen.
- Verwenden Sie die abgerufenen Tresor-Geheimnisse, um den Client mit dem Benutzernamen und dem Passwort zu initialisieren, die mit der Score-Methode geteilt werden.
- Verwenden Sie schließlich den Client in der Score-Funktion für die weitere Verarbeitung.
Siehe diese Beispielfunktion:
def my_deployable_fun_with_secret(space_id=space_id, secret_name=secret_name):
from ibm_watsonx_ai import APIClient, Credentials
import requests
import os
# initialize a client, This will pick up token from the backend available in deploy flow.
# This way of initializing will not work in score()
host = os.environ.get("RUNTIME_ENV_APSX_URL")
credentials = Credentials(
instance_id="openshift",
url=host,
version="5.1",
)
wx_client = APIClient(credentials)
first_token = wx_client._get_icptoken()
# The user stores their username / password (could be apikey also)
# in the secret that is identified by the "secret_name" in the code.
# We use this first_token to fetch this information
# The reason is: first_token will expire after some time, and we need
# credentials that will not expire if we need to use it with a client
# for the deployment lifetime.
def get_secret_urn(secret_name):
nonlocal host
url = host + "/zen-data/v2/secrets"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
}
params = {"secret_name": secret_name}
response = requests.get(url, headers=headers, params=params, verify=False)
secrets_list = response.json()["secrets"]
return secrets_list[0]["secret_urn"]
def get_secret_details(secret_urn):
nonlocal host
url = host + "/zen-data/v2/secrets/" + secret_urn
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer " + token
}
response = requests.get(url, headers=headers, verify=False)
secret_details = response.json()
return secret_details['data']['secret']['credentials']
# we get the secret information, with the helper functions
# get_secret_urn, get_secret_details
secret_urn = get_secret_urn(secret_name)
client_credentials = get_secret_details(secret_urn)
vault_username = client_credentials['username']
vault_password = client_credentials['password']
# We now initialize wx_score_client a client object which
# does not use token , but username and password
from ibm_watsonx_ai import APIClient, Credentials
creds = Credentials(
url=os.environ.get("RUNTIME_ENV_APSX_URL"),
username=vault_username,
password=vault_password,
instance_id="openshift",
version="5.1"
)
wx_score_client = APIClient(credentials=creds)
wx_score_client.set.default_space(space_id)
def score(payload):
# wx_score_client can be used inside score() function
# and will work as long as the username / password it was used to initialize with
# is not revoked
use_score_token = wx_score_client.repository.list()["ID"].tolist()
score_response = {
"predictions": [
{
"fields": [
"use_score_token"
],
"values": [
use_score_token
]
}
]
}
return score_response
return score
Bereitstellbaren Funktionen in JupyterLab erstellen
Wenn Sie Ihre Python-Funktion in JupyterLab erstellen, muss Ihr Code den Kommentar #wml_python_function enthalten. Wenn der Kommentar fehlt, wird die Funktion nicht als Python-Funktionsasset, sondern als Script-Asset in Watson Studio importiert.
Sehen Sie sich dieses Beispiel an:
from tornado.escape import json_encode, json_decode, url_escape
# Define scoring function
def callModel(payload_scoring):
print(json.dumps(payload_scoring))
predictions =[]
for value in payload_scoring:
sums = []
for value in payload_scoring["input_data"][0]["values"]:
first = value[0]
second = value[1]
sums.append([first, second, first + second])
predictions.append({"fields": ["FIRST", "SECOND", "SUM"],"values": sums})
return {"predictions": predictions}
#wml_python_function
def score(input):
"""AI function example.
Example:
{"input_data": [{"fields":["FIRST","SECOND","values":[[1,2]]}]}
"""
# Score using the pre-defined model
prediction = callModel(input);
return prediction
Zugriff auf Assets, die sich in einem Bereitstellungsbereich befinden
Um auf Assets zuzugreifen, die sich in einem Bereitstellungsbereich befinden, müssen Sie initialisieren ibm-watson-studio-lib. Die Vorgehensweise hängt vom Umfang ab.
Initialisierung im Bereitstellungsbereich
Im Bereitstellungsbereich initialisieren ibm-watson-studio-lib Sie ohne zusätzliche Parameter zu übergeben. Siehe Beispielcode:
def my_deployable_function():
from ibm_watson_studio_lib import access_project_or_space
wslib = access_project_or_space()
token = wslib.auth.get_current_token()
def score( payload ):
message_from_input_payload = payload.get("input_data")[0].get("values")[0][0]
response_message = "Received message - {0}".format(message_from_input_payload)
score_response = {
'predictions': [{'fields': ['Response_message_field'],
'values': [[response_message]]
}]
}
return score
Initialisierung innerhalb der Score-Funktion
In der Score-Funktion müssen Sie Ihr Bearer-Token als Parameter übergeben. Siehe Beispielcode:
def my_deployable_function():
from ibm_watson_studio_lib import access_project_or_space
def score(payload , token):
wslib = access_project_or_space({"token": token})
message_from_input_payload = payload.get("input_data")[0].get("values")[0][0]
response_message = "Received message - {0}".format(message_from_input_payload)
score_response = {
'predictions': [{'fields': ['Response_message_field'],
'values': [[response_message]]
}]
}
return score
Zugriff auf Daten aus der Score-Funktion
Möglicherweise möchten Sie innerhalb der Score-Funktion auf Datenbestände zugreifen. Beispiel:
- Auf Remote-Daten muss mit den Anmeldedaten des Benutzers zugegriffen werden, der die Score-Funktion aufruft.
- In Ihrem speziellen Anwendungsfall können Sie weder noch den JDBCWatson Machine LearningPython Client verwenden.
Wenn Sie in solchen Situationen einen Code-Schnipsel für die Datenerfassung aus Ihrem Notizbuch heraus generieren, schlägt der Code fehl.
Siehe diese Codebeispiele als Referenz für den Zugriff auf Daten aus der Score-Funktion heraus:
def my_deployable_function():
import itc_utils.flight_service as itcfs
from ibm_watson_studio_lib import access_project_or_space
def score(payload, token):
# token is from the predictions header.
# Use it to initialise a Flight client here under score.
# This ensures multi tenancy of predictions endpoint
user_wslib = access_project_or_space({"token": token})
# read the table named IRIS from database with the connection provided
# the connection should be promoted to space prior to deployment.
# The connection with name `db2_conn1` is expected to be already present under `space`
db_query = {
'connection_name': 'db2_conn1',
'interaction_properties': { 'table_name': 'IRIS'}
}
# Fetch data with Flight client
flight_client = itcfs.get_flight_client(wslib=user_wslib)
flight_info = itcfs.get_flight_info(flight_client, nb_data_request=db_query, wslib=user_wslib)
df = itcfs.read_pandas_and_concat(flight_client, flight_info, timeout=240)
# return the first 2 rows with the column names
score_response = {
"predictions": [{
"fields": list(df.columns),
"values": df.iloc[:2].values.tolist()
}]
}
return score_response
return score
def my_deployable_function():
import itc_utils.flight_service as itcfs
from ibm_watson_studio_lib import access_project_or_space
def score(payload, token):
# token is from the predictions header.
# Use it to initialise a Flight client here under score.
# This ensures multi tenancy of predictions endpoint
user_wslib = access_project_or_space({"token": token})
# read the table named IRIS from database with the connection provided
# the connection should be promoted to space prior to deployment.
# The connection with name `db2_conn1` is expected to be already present under `space`
db_query = {
'connection_name': 'db2_conn1',
'interaction_properties': { 'table_name': 'IRIS'}
}
# Fetch data with Flight client
flight_client = itcfs.get_flight_client(wslib=user_wslib)
flight_descriptor = itcfs.get_flight_descriptor(nb_data_request=db_query, wslib=user_wslib)
flight_info = flight_client.get_flight_info(flight_descriptor)
df = itcfs.read_pandas_and_concat(flight_client, flight_info, timeout=240)
# return the first 2 rows with the column names
score_response = {
"predictions": [{
"fields": list(df.columns),
"values": df.iloc[:2].values.tolist()
}]
}
return score_response
return score