Share via


Recursos de computação sob demanda usando funções definidas pelo usuário do Python

Este artigo descreve como criar e usar recursos sob demanda no Azure Databricks.

Os modelos de machine learning para aplicativos em tempo real geralmente exigem os valores de recursos mais recentes. No exemplo mostrado no diagrama, um recurso para um modelo de recomendação de restaurante é a distância atual do usuário de um restaurante. Esse recurso deve ser calculado "sob demanda", ou seja, no momento da solicitação de pontuação. Ao receber uma solicitação de pontuação, o modelo pesquisa a localização do restaurante e aplica uma função predefinida para calcular a distância entre a localização atual do usuário e o restaurante. Essa distância é passada como uma entrada para o modelo, juntamente com outros recursos pré-computados do repositório de recursos.

fluxo de trabalho de recursos de computação sob demanda

Para usar recursos sob demanda, seu workspace deve estar habilitado para o Catálogo do Unity e você deve usar o Databricks Runtime 13.3 LTS ML ou superior.

O que são recursos sob demanda?

"Sob demanda" refere-se a recursos cujos valores não são conhecidos antecipadamente, mas são calculados no momento da inferência. No Azure Databricks, você usa UDFs (funções definidas pelo usuário) do Python para especificar como calcular recursos sob demanda. Essas funções são governadas pelo Catálogo do Unity e detectáveis por meio do Gerenciador de Catálogos.

Workflow

Para calcular recursos sob demanda, especifique uma UDF (função definida pelo usuário) do Python que descreve como calcular os valores do recurso.

  • Durante o treinamento, você fornece essa função e suas associações de entrada no parâmetro feature_lookups da API create_training_set.
  • Você deve registrar o modelo treinado usando o método log_model do Repositório de Recursos. Isso garante que o modelo avalie automaticamente os recursos sob demanda quando ele é usado para inferência.
  • Para pontuação em lote, a API score_batch calcula e retorna automaticamente todos os valores de recursos, incluindo recursos sob demanda.
  • Quando você atende um modelo com o Serviço de Modelo do Databricks, o modelo usa automaticamente a UDF do Python para calcular recursos sob demanda para cada solicitação de pontuação.

Criar uma UDF do Python

Você pode criar uma UDF do Python em um notebook ou no Databricks SQL.

Por exemplo, a execução do código a seguir em uma célula de notebook cria o UDF example_feature do Python no catálogo main e no esquema default.

%sql
CREATE FUNCTION main.default.example_feature(x INT, y INT)
RETURNS INT
LANGUAGE PYTHON
COMMENT 'add two numbers'
AS $$
def add_numbers(n1: int, n2: int) -> int:
  return n1 + n2

return add_numbers(x, y)
$$

Depois de executar o código, você pode navegar pelo namespace de três níveis no Gerenciador de Catálogos para exibir a definição de função:

função no Gerenciador de Catálogos

Para obter mais detalhes sobre como criar UDFs do Python, consulte Registrar uma UDF do Python no Catálogo do Unity e o manual de linguagem SQL.

Como lidar com valores de recursos ausentes

Quando uma UDF do Python depende do resultado de um FeatureLookup, o valor retornado se a chave de pesquisa solicitada não for encontrada depende do ambiente. Ao usar score_batch, o valor retornado é None. Ao usar a veiculação on-line, o valor retornado é float("nan").

O código a seguir é um exemplo de como lidar com ambos os casos.

%sql
CREATE OR REPLACE FUNCTION square(x INT)
RETURNS INT
LANGUAGE PYTHON AS
$$
import numpy as np
if x is None or np.isnan(x):
  return 0
return x * x
$$

Treinar um modelo usando recursos sob demanda

Para treinar o modelo, use um FeatureFunction, que é passado para a API create_training_set no parâmetro feature_lookups.

O código de exemplo a seguir usa a UDF main.default.example_feature do Python que foi definida na seção anterior.

# Install databricks-feature-engineering first with:
# %pip install databricks-feature-engineering
# dbutils.library.restartPython()

from databricks.feature_engineering import FeatureEngineeringClient
from databricks.feature_engineering import FeatureFunction, FeatureLookup
from sklearn import linear_model

fe = FeatureEngineeringClient()

features = [
  # The feature 'on_demand_feature' is computed as the sum of the the input value 'new_source_input'
  # and the pre-materialized feature 'materialized_feature_value'.
  # - 'new_source_input' must be included in base_df and also provided at inference time.
  #   - For batch inference, it must be included in the DataFrame passed to 'FeatureEngineeringClient.score_batch'.
  #   - For real-time inference, it must be included in the request.
  # - 'materialized_feature_value' is looked up from a feature table.

  FeatureFunction(
      udf_name="main.default.example_feature",    # UDF must be in Unity Catalog so uses a three-level namespace
      input_bindings={
        "x": "new_source_input",
        "y": "materialized_feature_value"
      },
      output_name="on_demand_feature",
  ),
  # retrieve the prematerialized feature
  FeatureLookup(
    table_name = 'main.default.table',
    feature_names = ['materialized_feature_value'],
    lookup_key = 'id'
  )
]

# base_df includes the columns 'id', 'new_source_input', and 'label'
training_set = fe.create_training_set(
  df=base_df,
  feature_lookups=features,
  label='label',
  exclude_columns=['id', 'new_source_input', 'materialized_feature_value']     # drop the columns not used for training
)

# The training set contains the columns 'on_demand_feature' and 'label'.
training_df = training_set.load_df().toPandas()

# training_df columns ['materialized_feature_value', 'label']
X_train = training_df.drop(['label'], axis=1)
y_train = training_df.label

model = linear_model.LinearRegression().fit(X_train, y_train)

Registrar o modelo em log e registrá-lo no Catálogo do Unity

Modelos empacotados com metadados de recursos podem ser registrados no Catálogo do Unity. As tabelas de recursos usadas para criar o modelo devem ser armazenadas no Catálogo do Unity.

Para garantir que o modelo avalie automaticamente os recursos sob demanda quando ele for usado para inferência, defina o URI do Registro e registre o modelo da seguinte maneira:

import mlflow
mlflow.set_registry_uri("databricks-uc")

fe.log_model(
    model=model,
    artifact_path="main.default.model",
    flavor=mlflow.sklearn,
    training_set=training_set,
    registered_model_name="main.default.recommender_model"
)

Se a UDF do Python que define os recursos sob demanda importar todos os pacotes do Python, você deverá especificar esses pacotes usando o argumento extra_pip_requirements. Por exemplo:

import mlflow
mlflow.set_registry_uri("databricks-uc")

fe.log_model(
    model=model,
    artifact_path="model",
    flavor=mlflow.sklearn,
    training_set=training_set,
    registered_model_name="main.default.recommender_model",
    extra_pip_requirements=["scikit-learn==1.20.3"]
)

Limitação

Os recursos sob demanda podem gerar todos os tipos de dados compatíveis com o Repositório de Recursos, exceto MapType e ArrayType.

Exemplos de Notebook: recursos sob demanda

O notebook a seguir mostra um exemplo de como treinar e pontuar um modelo que usa um recurso sob demanda.

Notebook de demonstração de recursos básicos sob demanda

Obter notebook

O bloco de anotações a seguir mostra um exemplo de um modelo de recomendação de restaurante. A localização do restaurante é pesquisada de uma tabela online do Databricks. O local atual do usuário é enviado como parte da solicitação de pontuação. O modelo usa um recurso sob demanda para calcular a distância em tempo real do usuário até o restaurante. Essa distância é então usada como uma entrada para o modelo.

Notebook de demonstração de recursos de recomendação de restaurante sob demanda usando tabelas online

Obter notebook