Partager via


Calcul des fonctionnalités à la demande

Cet article explique comment créer et utiliser des fonctionnalités à la demande dans Azure Databricks.

Pour utiliser des caractéristiques à la demande, votre espace de travail doit prendre en charge Unity Catalog et vous devez utiliser Databricks Runtime 13.3 LTS ML ou ultérieur.

Présentation des caractéristiques à la demande

Le terme « à la demande » fait référence à des caractéristiques dont les valeurs ne sont pas connues à l’avance, mais qui sont calculées au moment de l’inférence. Dans Azure Databricks, vous utilisez des fonctions Python définies par l’utilisateur (UDF) pour spécifier comment calculer les caractéristiques à la demande. Ces fonctions sont régies par Unity Catalog et sont découvrables dans Catalog Explorer.

Spécifications

  • Pour utiliser une fonction définie par l'utilisateur (UDF) pour créer un jeu d’entraînement, ou pour établir un point de terminaison pour le service des fonctionnalités, vous devez avoir le privilège sur le catalogue USE CATALOG et le privilège system sur le schéma dans le catalogue Unity USE SCHEMA.

Flux de travail

Pour calculer une caractéristique à la demande, spécifiez une fonction Python définie par l’utilisateur (UDF) qui décrit comment calculer les valeurs de la caractéristique.

  • Pendant l’entraînement, fournissez cette fonction et ses liaisons d’entrée au paramètre feature_lookups de l’API create_training_set.
  • Vous devez enregistrer le modèle entraîné à l’aide de la méthode log_model du magasin de caractéristiques. De cette façon, le modèle évalue automatiquement les caractéristiques à la demande quand il est utilisé pour l’inférence.
  • Pour le scoring par lots, l’API score_batch calcule et retourne automatiquement toutes les valeurs de caractéristiques, y compris celles à la demande.
  • Quand vous servez un modèle avec le service de modèles Mosaic AI, le modèle utilise automatiquement la fonction UDF Python afin de calculer les caractéristiques à la demande pour chaque demande de scoring.

Créer une fonction UDF Python

Vous pouvez créer une fonction UDF Python à l’aide de code SQL ou Python. Les exemples suivants créent une fonction UDF Python dans le catalogue main et le schéma default.

Python

Pour utiliser Python, vous devez d’abord installer le databricks-sdk[openai] package. Utilisez %pip install ce qui suit :

%pip install unitycatalog-ai[databricks]
dbutils.library.restartPython()

Ensuite, utilisez du code similaire à ce qui suit pour créer une fonction UDF Python :

from unitycatalog.ai.core.databricks import DatabricksFunctionClient

client = DatabricksFunctionClient()

CATALOG = "main"
SCHEMA = "default"

def add_numbers(number_1: float, number_2: float) -> float:
  """
  A function that accepts two floating point numbers, adds them,
  and returns the resulting sum as a float.

  Args:
      number_1 (float): The first of the two numbers to add.
      number_2 (float): The second of the two numbers to add.

  Returns:
      float: The sum of the two input numbers.
  """
  return number_1 + number_2

function_info = client.create_python_function(
  func=add_numbers,
  catalog=CATALOG,
  schema=SCHEMA,
  replace=True
)

Databricks SQL - Outil de requête de base de données

Le code suivant montre comment utiliser Databricks SQL pour créer une fonction UDF Python :

%sql
CREATE OR REPLACE FUNCTION main.default.add_numbers(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)
$$

Après avoir exécuté le code, vous pouvez parcourir l’espace de noms à trois niveaux dans Catalog Explorer pour voir la définition de la fonction :

fonction dans Catalog Explorer

Pour plus d’informations sur la création de fonctions UDF Python, consultez Inscrire une fonction UDF Python auprès d’Unity Catalog et le manuel du langage SQL.

Comment gérer les valeurs de fonctionnalité manquantes

Lorsqu’une fonction UDF Python dépend du résultat d’une fonctionnalité Lookup, la valeur retournée si la clé de recherche demandée est introuvable dépend de l’environnement. Lors de l’utilisation de score_batch, la valeur retournée est None. Lors de l’utilisation du service en ligne, la valeur retournée est float("nan").

Le code suivant est un exemple de la manière de traiter les deux cas.

%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
$$

Entraîner un modèle avec des caractéristiques à la demande

Pour entraîner le modèle, utilisez une FeatureFunction qui est passée à l’API create_training_set dans le paramètre feature_lookups.

L’exemple de code suivant utilise la fonction UDF Python main.default.example_feature définie dans la section précédente.

# 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 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)

Spécifier les valeurs par défaut

Pour spécifier des valeurs par défaut pour les fonctionnalités, utilisez le default_values paramètre dans le FeatureLookup.

FeatureLookup(
  table_name = 'main.default.table',
  feature_names = ['materialized_feature_value'],
  lookup_key = 'id',
  default_values={
    "materialized_feature_value": 0
  }
)

Si les colonnes de caractéristiques sont renommées à l’aide du rename_outputs paramètre, default_values doivent utiliser les noms de fonctionnalités renommés.

FeatureLookup(
  table_name = 'main.default.table',
  feature_names = ['materialized_feature_value'],
  lookup_key = 'id',
  rename_outputs={"materialized_feature_value": "feature_value"},
  default_values={
    "feature_value": 0
  }
)

Consigner le modèle et l’inscrire auprès d’Unity Catalog

Les modèles empaquetés avec des métadonnées de caractéristique peuvent être inscrits auprès d’Unity Catalog. Les tables de caractéristiques utilisées pour créer le modèle doivent être stockées dans Unity Catalog.

Pour vous assurer que le modèle évalue automatiquement les caractéristiques à la demande quand il est utilisé pour l’inférence, vous devez définir l’URI du registre, puis consigner le modèle, comme suit :

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"
)

Si la fonction UDF Python qui définit les caractéristiques à la demande importe des packages Python, vous devez spécifier ces packages à l’aide de l’argument extra_pip_requirements. Par exemple :

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"]
)

Limite

Les caractéristiques à la demande peuvent générer en sortie tous les types de données pris en charge par le magasin de caractéristiques, sauf MapType et ArrayType.

Exemples de notebooks : caractéristiques à la demande

Le notebook suivant présente un exemple montrant comment effectuer l’apprentissage et le scoring d’un modèle qui utilise une caractéristique à la demande.

Notebook de base de démonstration des caractéristiques à la demande

Obtenir le notebook

Le notebook suivant présente un exemple de modèle de recommandation de restaurant. L’emplacement du restaurant est recherché à partir d’une table Databricks en ligne. L’emplacement actuel de l’utilisateur est envoyé dans le cadre de la demande de scoring. Le modèle utilise une caractéristique à la demande pour calculer la distance en temps réel entre l’utilisateur et le restaurant. Cette distance est ensuite utilisée comme entrée du modèle.

Fonctionnalités à la demande de suggestions de restaurants en utilisant un notebook de démonstration de tables en ligne

Obtenir le notebook