Criação de funções implantáveis do Python
Aprenda a escrever uma função ` Python ` e, em seguida, salve-a como um recurso que você poderá usar para implantar modelos.
Para obter uma lista dos requisitos gerais para funções implantáveis, consulte Requisitos gerais para funções implantáveis. Para obter informações sobre o que ocorre durante uma implantação de função, consulte o processo de implantação de função
Requisitos gerais para funções implantáveis
Para ser implantada com sucesso, uma função deve atender aos seguintes requisitos:
- O arquivo da função ` Python `, ao ser importado, deve ter o
scoreobjeto de função como parte de seu escopo. Consulte os requisitos da função Score - A carga útil de entrada de pontuação deve atender aos requisitos que estão listados em Requisitos de entrada de pontuação
- A carga útil esperada como resultado da função
scoredeve incluir o esquema dascore_responsevariável para o código de status 200. Observe que opredictionparâmetro, cujo valor é uma matriz de objetos JSON, é obrigatório nascoresaída. - Ao usar o cliente Python para salvar uma função Python que contenha uma referência a uma função externa, apenas o código no escopo da função externa (incluindo suas funções aninhadas) é salvo. Portanto, o código fora do escopo da função externa não será salvo e, consequentemente, não estará disponível quando você implantar a função.
Requisitos da função de pontuação
- Duas maneiras de adicionar o objeto de função
scoreexistem:- explicitamente, por usuário
- implicitamente, pelo método utilizado para salvar a função Python como um ativo no repositório Watson Machine Learning
- A
scorefunção pode aceitar um único parâmetro de entrada JSON ou dois parâmetros: payload e token de portador. - A função
scoredeve retornar um objeto serializável JSON (por exemplo: dicionários ou listas).
Assinaturas de funções de pontuação compatíveis
score(payload): A autenticação (por exemplo, usando wslib ou ibm-watsonx-ai) pode ser inicializada uma única vez no momento da implantação, fora do fluxo de pontuação, e reutilizada em todas as solicitações de previsão.
score(payload, token): A autenticação pode ser inicializada dentro da função de pontuação durante a fase de previsão, permitindo o acesso baseado em tokens, com possível sobrecarga por solicitação
Requisitos para a pontuação
A carga útil de entrada da pontuação deve incluir um array com o nome
values, conforme mostrado neste esquema de exemplo. O parâmetroinput_dataé obrigatório na carga útil.. O parâmetroinput_datatambém pode incluir pares nome-valor adicionais.{"input_data": [{ "values": [["Hello world!"]] }] }A carga útil de pontuação deve ser passada como um valor de parâmetro de entrada para
score. Desta forma é possível garantir que o valor do parâmetro de entradascoreseja tratado adequadamente dentro doscore.A carga útil de entrada de pontuação deve corresponder aos requisitos de entrada para a Função de Python em questão.
A carga útil de entrada para pontuação deve incluir um array que corresponda ao esquema de dados de entrada do Exemplo.
Exemplo de esquema de dados de entrada
{"input_data": [{
"values": [["Hello, world!"]]
}]
}
Exemplo de código do ` Python ` (carga útil e 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()
Testando sua função ` Python `
Veja como você pode testar sua função ` Python `:
input_data = { "input_data": [{ "fields": [ "message" ],
"values": [[ "Hello, world!" ]]
}
]
}
function_result = score( input_data )
print( function_result )
Ele exibe a mensagem "Olá, mundo!".
Processo de implantação de funções
O código Python do seu ativo de Function é carregado como um módulo Python pelo mecanismo Watson Machine Learning usando uma instrução import . Isso significa que o código será executado exatamente uma vez (quando a função for implantada ou sempre que o pod correspondente for reiniciado). A função score que é definida pelo ativo Function é então chamada em cada solicitação de predição.
Trabalho com funções implantáveis
Use um desses métodos para criar uma função do Python que possa ser implantada:
Criação de funções implantáveis por meio da API REST
Para APIs REST, porque a função Python é carregada diretamente por meio de um arquivo, o arquivo já deve conter a função score . Qualquer uma única vez de importação que precise ser feita para ser usada posteriormente dentro da função score pode ser feita dentro do escopo global do arquivo. Quando esse arquivo é implantado como uma função do Python, as importações únicas disponíveis no escopo global são executadas durante a implantação e, posteriormente, simplesmente reutilizadas em cada solicitação de previsão.
O archive de função deve ser um arquivo .gz
Exemplo score de arquivo de função:
Score function.py
---------------------
def score(input_data):
return {'predictions': [{'values': [['Just a test']]}]}
Exemplo score de função com importações únicas:
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__]]}]}
Criação de funções implantáveis por meio do cliente do Python
Para persistir uma função do Python como um ativo, o cliente Python utiliza o wml_client.repository.store_function método. É possível salvar uma função do ` Python ` de duas maneiras:
Persistindo uma função através de um arquivo que contém a função Python
Esse método é o mesmo que persistir o arquivo da função ` Python ` por meio de APIs REST (score deve ser definido no escopo do arquivo-fonte ` Python `). Para obter mais detalhes, consulte “Criação de funções implantáveis por meio da API REST”.
Quando estiver chamando o método wml_client.repository.store_function , passe o nome do arquivo como o primeiro argumento.
Persistência de uma função por meio do objeto de função
É possível persistir objetos de função d Python, criando Closures d Python com uma função aninhada chamada score. A score função é retornada pela função externa que está sendo armazenada como um objeto de função, quando chamada. Esta função score deve atender aos requisitos que estão listados em Requisitos gerais para funções implementáveis. Nesse caso, qualquer uma vez importar e lógica de setup inicial deve ser adicionada na função aninhada externa para que eles sejam executados durante a implementação e sejam utilizados dentro da função score . Qualquer lógica recorrente que seja necessária durante a solicitação prediction deve ser incluída dentro da função score aninhada.
Amostra de função Python salvar usando o cliente Python :
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)
Nesse cenário, a função ` Python ` se encarrega de criar um arquivo ` Python ` que contém a score função e de armazenar o arquivo da função como um ativo no repositório ` Watson Machine Learning `:
score = my_deployable_function()
Utilização de funções de IA assíncronas
Principais recursos
- Defina uma
asyncfunção geradora que retorne uma função de pontuação assíncrona - Suporte à execução simultânea em implantações
- Detecção automática de execução síncrona e assíncrona pelo ambiente de execução
Exemplo: Função de IA assíncrona
async def score_generator():
"""
Async AI Function example
"""
import os
import sys
import pandas as pd
import importlib
async def score(payload):
module, attribute = payload["input_data"][0]["values"][0]
m = importlib.import_module(module)
attr_value = eval(attribute, m.__dict__)
return {
"predictions": [
{
"values": [
{module: attr_value},
{"pandas": pd.__version__},
{"sys": sys.executable}
]
}
]
}
return score
score = score_generator()
Neste exemplo:
score_generator()é uma função de fábrica assíncronascore()é a função de pontuação assíncrona- A função suporta chamadas de API externas, E/S de arquivos e tarefas assíncronas paralelas
Usando o Vault para implantar funções implantáveis de longa duração
O exemplo utiliza um cofre interno d IBM. O cofre interno destina-se principalmente a demonstrações de prova de conceito. Em ambientes de produção, é altamente recomendável que você se conecte a um cofre externo.
O token padrão que uma função do Python implantável recebe no momento da implantação expira (geralmente após 1 hora) e não pode ser atualizado internamente score() sem credenciais duradouras.
O Vault fornece credenciais de longa duração. Ao armazenar uma API, um nome de usuário ou uma senha em um segredo do Vault, você pode:
- Recupere essas credenciais com segurança durante o fluxo de implantação (usando o token de curta duração apenas uma vez).
- Use-os para inicializar um cliente sempre
score()que necessário. Essas credenciais não expiram como um token, portanto, o cliente sempre pode se autenticar novamente.
Pré-requisitos
É necessário criar uma integração com o Vault e um segredo do Vault em IBMSoftware Hub para utilizar a funcionalidade do Vault na implantação de funções do Python. Para obter mais informações, consulte a seção “Gerenciamento de segredos e cofres” na documentação do IBM Software Hub.
Armazenamento de segredos no cofre
Para armazenar seus segredos no cofre:
Recuperar o URN do cofre. Obtenha o
vault_urnpara o cofre onde os segredos precisam ser armazenados.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_urnGuarde os segredos no cofre. Use o
vault_urnpara armazenar com segurança o nome de usuário e a senha como um segredo no cofre.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()
Criação de uma função do Python que possa ser implantada e utilize segredos do Vault
Para criar uma função do Python que possa ser implantada e que utilize segredos do Vault:
- Durante o fluxo de implantação, inicialize o cliente com a URL da plataforma URL para extrair o token de implantação.
- Use este token para recuperar o segredo armazenado no cofre.
- Use os segredos do cofre recuperados para inicializar o cliente com o nome de usuário e a senha, que são compartilhados com o método `score`.
- Por fim, utilize o cliente na função de pontuação para o processamento posterior.
Consulte esta função de exemplo:
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
Criação de funções implantáveis no JupyterLab
Se você criar sua função ` Python ` em ` JupyterLab, `, seu código deve conter um #wml_python_function comentário. Se o comentário estiver faltando, a função será importada para Watson Studio como um recurso de script, em vez de um recurso de função do Python.
Veja este exemplo:
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
Acessando recursos localizados em um espaço de implantação
ibm-watson-studio-libPara acessar os recursos localizados em um espaço de implantação, é necessário inicializá-lo. A maneira de fazer isso depende do escopo.
Inicialização no escopo de implantação
No escopo da implantação, você inicializa ibm-watson-studio-lib sem passar nenhum parâmetro adicional. Veja o código de exemplo:
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
Inicialização na função de pontuação
Na função de pontuação, você deve passar seu token de portador como parâmetro. Veja o código de exemplo:
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
Acessando dados a partir da função de pontuação
Talvez você queira acessar os ativos de dados a partir da função de pontuação. Por exemplo:
- O acesso aos dados remotos deve ser feito utilizando as credenciais do usuário que está chamando a função de pontuação.
- No seu caso específico, você não pode usar o JDBC nem o cliente Watson Machine Learning Python.
Nessas situações, se você gerar um trecho de código de ingestão de dados a partir do seu notebook, o código não funcionará.
Veja estes exemplos de código como referência para acessar dados a partir da função 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_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