Aller au contenu principal

Entraîner des modèles avec des tables de fonctionnalités

Pour entraîner un modèle à l'aide du Magasin de fonctionnalités Databricks ou de l'ancien Magasin de fonctionnalités Workspace, vous devez d'abord créer un dataset d'entraînement qui définit les fonctionnalités à utiliser et comment les joindre. Lorsque vous entraînez ensuite le modèle, il conserve les références à ces fonctionnalités.

Lorsque vous entraînez un modèle en utilisant l'ingénierie des fonctionnalités dans Unity Catalog, vous pouvez voir la lignée du modèle dans l'Explorateur de catalogues. Les tables et les fonctions qui ont été utilisées pour créer le modèle sont automatiquement suivies et affichées. Voir la gouvernance et la traçabilité des fonctionnalités.

Lorsque vous utilisez le modèle pour l'inférence, vous pouvez choisir qu'il récupère les valeurs des fonctionnalités du Magasin de fonctionnalités. Vous pouvez également servir le modèle avec Model Serving et il recherchera automatiquement les fonctionnalités publiées dans des magasins en ligne. Les modèles du Magasin de fonctionnalités sont également compatibles avec l'interface pyfunc MLflow, vous pouvez donc utiliser MLflow pour effectuer des inférences par batch avec des tables de fonctionnalités.

Si votre modèle utilise des variables d'environnement, apprenez-en davantage sur la façon de les utiliser lors de la diffusion du modèle en ligne à l'adresse Configurer l'accès aux Ressources à partir des Endpoint de déploiement de modèles.

Un modèle peut utiliser au maximum 50 tables et 100 fonctions pour l'entraînement.

Créez un dataset d'entraînement

Pour sélectionner des fonctionnalités spécifiques à partir d'une table de fonctionnalités pour l'entraînement de modèles, vous créez un dataset d'entraînement à l'aide de l'API FeatureEngineeringClient.create_training_set (pour Feature Engineering dans Unity Catalog) ou de l'API FeatureStoreClient.create_training_set (pour le Magasin de fonctionnalités du Workspace) et un objet appelé FeatureLookup. Un FeatureLookup spécifie chaque fonctionnalité à utiliser dans le jeu d'entraînement, y compris le nom de la table de fonctionnalités, le(s) nom(s) des fonctionnalités et la/les clé(s) à utiliser lors de la jointure de la table de fonctionnalités avec le DataFrame transmis à create_training_set. Consultez Recherche de fonctionnalités pour plus d'informations.

Utilisez le paramètre feature_names lorsque vous créez un(e) FeatureLookup. feature_names accepte un seul nom de fonctionnalité, une liste de noms de fonctionnalité, ou None pour rechercher toutes les fonctionnalités (à l'exclusion des clés primaires) dans la table de fonctionnalités au moment de la création de l'ensemble d'entraînement.

remarque

Le type et l'ordre des colonnes lookup_key dans le DataFrame doivent correspondre au type et à l'ordre des clés primaires (à l'exclusion des clés timestamp) de la table de caractéristiques de référence.

Les colonnes Timestamp ne doivent pas être utilisées en tant que lookup_key.

important

DATE ou TIMESTAMP colonnes utilisées comme clés primaires doivent être déclarées comme clés de série temporelle. Si une table de caractéristiques contient une colonne de clé primaire DATE ou TIMESTAMP qui n'est pas désignée comme clé de série temporelle, les appels à create_feature_spec(), create_training_set() et publish_table() renvoient une erreur.

Pour résoudre ce problème, utilisez l'une des approches suivantes :

  • Déclarez la colonne comme colonne de série chronologique : si la colonne représente des heures d’événement ou des heures d’observation et que vous souhaitez un comportement de recherche ponctuelle, utilisez le timeseries_columns paramètre lors de la création de la table. Voir les jonctions de caractéristiques à un point dans le temps.
  • Modifier le type de colonne en STRING : si la colonne est utilisée comme clé de recherche simple pour une sémantique de correspondance exacte (non basée sur le temps), modifiez le type de colonne en STRING pour éviter la restriction.

Cet article comprend des exemples de code pour les deux versions de la syntaxe.

Dans cet exemple, le DataFrame renvoyé par trainingSet.load_df contient une colonne pour chaque fonctionnalité de feature_lookups. Il préserve toutes les colonnes du DataFrame fourni à create_training_set, à l'exception de celles exclues à l'aide de exclude_columns.

Python
from databricks.feature_engineering import FeatureEngineeringClient, FeatureLookup

# The model training uses two features from the 'customer_features' feature table and
# a single feature from 'product_features'
feature_lookups = [
FeatureLookup(
table_name='ml.recommender_system.customer_features',
feature_names=['total_purchases_30d', 'total_purchases_7d'],
lookup_key='customer_id'
),
FeatureLookup(
table_name='ml.recommender_system.product_features',
feature_names=['category'],
lookup_key='product_id'
)
]

fe = FeatureEngineeringClient()

# Create a training set using training DataFrame and features from Feature Store
# The training DataFrame must contain all lookup keys from the set of feature lookups,
# in this case 'customer_id' and 'product_id'. It must also contain all labels used
# for training, in this case 'rating'.
training_set = fe.create_training_set(
df=training_df,
feature_lookups=feature_lookups,
label='rating',
exclude_columns=['customer_id', 'product_id']
)

training_df = training_set.load_df()

Créer un TrainingSet lorsque les clés de recherche ne correspondent pas aux clés primaires

Utilisez l'argument lookup_key dans le FeatureLookup pour le nom de la colonne dans le jeu d'entraînement. create_training_set effectue une jointure ordonnée entre les colonnes de l'ensemble d'entraînement spécifiées dans l'argument lookup_key en utilisant l'ordre dans lequel les clés primaires ont été spécifiées lors de la création de la table de caractéristiques.

Dans cet exemple, recommender_system.customer_features a les clés primaires suivantes : customer_id, dt.

La table de fonctionnalités recommender_system.product_features a la clé primaire product_id.

Si le training_df comporte les colonnes suivantes :

  • cid
  • transaction_dt
  • product_id
  • rating

le code suivant créera les recherches de fonctionnalités correctes pour le TrainingSet:

Python
feature_lookups = [
FeatureLookup(
table_name='ml.recommender_system.customer_features',
feature_names=['total_purchases_30d', 'total_purchases_7d'],
lookup_key=['cid', 'transaction_dt']
),
FeatureLookup(
table_name='ml.recommender_system.product_features',
feature_names=['category'],
lookup_key='product_id'
)
]

Lorsque create_training_set est appelé, il crée un dataset d'entraînement en effectuant une jointure gauche, joignant les tables recommender_system.customer_features et training_df à l'aide des clés (customer_id,dt) correspondant à (cid,transaction_dt), comme indiqué dans le code suivant :

Python
customer_features_df = spark.sql("SELECT * FROM ml.recommender_system.customer_features")
product_features_df = spark.sql("SELECT * FROM ml.recommender_system.product_features")

training_df.join(
customer_features_df,
on=[training_df.cid == customer_features_df.customer_id,
training_df.transaction_dt == customer_features_df.dt],
how="left"
).join(
product_features_df,
on="product_id",
how="left"
)

Créer un TrainingSet contenant deux fonctionnalités portant le même nom provenant de différentes tables de fonctionnalités

Utilisez l'argument facultatif output_name dans le FeatureLookup. Le nom fourni est utilisé à la place du nom de la fonctionnalité dans le DataFrame renvoyé par TrainingSet.load_df. Par exemple, avec le code suivant, le DataFrame renvoyé par training_set.load_df inclut les colonnes customer_height et product_height.

Python
feature_lookups = [
FeatureLookup(
table_name='ml.recommender_system.customer_features',
feature_names=['height'],
lookup_key='customer_id',
output_name='customer_height',
),
FeatureLookup(
table_name='ml.recommender_system.product_features',
feature_names=['height'],
lookup_key='product_id',
output_name='product_height'
),
]

fe = FeatureEngineeringClient()

with mlflow.start_run():
training_set = fe.create_training_set(
df=df,
feature_lookups=feature_lookups,
label='rating',
exclude_columns=['customer_id']
)
training_df = training_set.load_df()

Créer un TrainingSet à l'aide de la même fonctionnalité plusieurs fois

Pour créer un TrainingSet utilisant la même fonctionnalité jointe par différentes clés de recherche, utilisez plusieurs FeatureLookups. Utilisez un output_name unique pour chaque sortie FeatureLookup.

Python
feature_lookups = [
FeatureLookup(
table_name='ml.taxi_data.zip_features',
feature_names=['temperature'],
lookup_key=['pickup_zip'],
output_name='pickup_temp'
),
FeatureLookup(
table_name='ml.taxi_data.zip_features',
feature_names=['temperature'],
lookup_key=['dropoff_zip'],
output_name='dropoff_temp'
)
]

Créez un ensemble d'entraînement pour les Modèles de machine learning non supervisés

Définissez label=None lors de la création d'un TrainingSet pour les modèles d'apprentissage non supervisé. Par exemple, le TrainingSet suivant peut être utilisé pour regrouper différents clients en fonction de leurs intérêts :

Python
feature_lookups = [
FeatureLookup(
table_name='ml.recommender_system.customer_features',
feature_names=['interests'],
lookup_key='customer_id',
),
]

fe = FeatureEngineeringClient()
with mlflow.start_run():
training_set = fe.create_training_set(
df=df,
feature_lookups=feature_lookups,
label=None,
exclude_columns=['customer_id']
)

training_df = training_set.load_df()

Créez un TrainingSet lorsque vous utilisez une vue comme table de caractéristiques

Pour utiliser une vue comme table de fonctionnalités, vous devez utiliser databricks-feature-engineering version 0,7,0 ou ultérieure, qui est intégrée à Databricks Runtime 16.0 ML.

La vue doit être une vue SELECT simple à partir de la table Delta source. Une vue SELECT simple est définie comme une vue créée à partir d'une seule table Delta dans Unity Catalog qui peut être utilisée comme table de fonctionnalités, et dont les clés primaires sont sélectionnées sans clauses JOIN, GROUP BY ou DISTINCT. Les mots-clés acceptables dans l'instruction SQL sont SELECT, FROM, WHERE, ORDER BY, LIMIT et OFFSET.

Dans l'exemple suivant, ml.recommender_system.customer_table contient les clés primaires cid et dt, où dt est une colonne de séries temporelles. L'exemple suppose que le dataframe training_df contient les colonnes cid, dt et label:

Python
from databricks.feature_engineering import FeatureEngineeringClient, FeatureLookup

customer_features_df = spark.sql("CREATE OR REPLACE VIEW ml.recommender_system.customer_features AS SELECT cid, dt, pid, rating FROM ml.recommender_system.customer_table WHERE rating > 3")

feature_lookups = [
FeatureLookup(
table_name='ml.recommender_system.customer_features',
feature_names=['pid', 'rating'],
lookup_key=['cid'],
timestamp_lookup_key='dt'
),
]

fe = FeatureEngineeringClient()

training_set = fe.create_training_set(
df=training_df,
feature_lookups=feature_lookups,
label='label'
)

training_df = training_set.load_df()

Créer un jeu d'entraînement avec des valeurs default

Lors de la création d'un dataset d'entraînement, vous pouvez spécifier des valeurs default pour les fonctionnalités afin de gérer les cas où le Magasin de fonctionnalités ne dispose pas d'une valeur de fonctionnalité calculée pour un ID.

Pour spécifier les default values, utilisez le paramètre default_values dans le FeatureLookup.

L'exemple suivant montre comment spécifier des valeurs par default pour un ensemble de fonctionnalités :

Python
feature_lookups = [
FeatureLookup(
table_name="ml.recommender_system.customer_features",
feature_names=[
"membership_tier",
"age",
"page_views_count_30days",
],
lookup_key="customer_id",
default_values={
"age": 18,
"membership_tier": "bronze"
},
),
]

Si les colonnes de features sont renommées en utilisant le parameter rename_outputs, default_values doit utiliser les noms de features renommées.

Python
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
}
)

Entraînez les modèles et effectuez l'inférence par batch avec des tables de fonctionnalités

Lorsque vous entraîne un modèle à l'aide de fonctionnalités du Magasin de fonctionnalités, le modèle conserve les références aux fonctionnalités. Lorsque vous utilisez le modèle pour l'inférence, vous pouvez choisir de lui faire récupérer les valeurs de fonctionnalités du Magasin de fonctionnalités. Vous devez fournir la ou les clé(s) primaire(s) des fonctionnalités utilisées dans le modèle. Le modèle récupère les fonctionnalités dont il a besoin du Magasin de fonctionnalités dans votre workspace. Il joint ensuite les valeurs des fonctionnalités si nécessaire pendant la notation.

Pour prendre en charge la recherche de fonctionnalités au moment de l'inférence :

  • Vous devez Log le modèle en utilisant la méthode log_model de FeatureEngineeringClient (pour l'Ingénierie des fonctionnalités dans Unity Catalog) ou FeatureStoreClient (pour le Magasin de fonctionnalités du Workspace).

  • Vous devez utiliser le DataFrame renvoyé par TrainingSet.load_df pour entraîner le modèle. Si vous modifiez ce DataFrame de quelque manière que ce soit avant de l'utiliser pour entraîner le modèle, les modifications ne sont pas appliquées lorsque vous utilisez le modèle pour l'inférence. Cela diminue les performances du modèle.

  • Le type de modèle doit avoir un python_flavor correspondant dans MLflow. MLflow prend en charge la plupart des frameworks d'entraînement de modèles Python, notamment :

    • Scikit-learn
    • keras
    • PyTorch
    • SparkML
    • LightGBM
    • xgboost
    • TensorFlow Keras (en utilisant le/la python_flavor mlflow.keras)
  • Modèles MLflow PyFunc personnalisés

Python
# Train model
import mlflow
from sklearn import linear_model

feature_lookups = [
FeatureLookup(
table_name='ml.recommender_system.customer_features',
feature_names=['total_purchases_30d'],
lookup_key='customer_id',
),
FeatureLookup(
table_name='ml.recommender_system.product_features',
feature_names=['category'],
lookup_key='product_id'
)
]

fe = FeatureEngineeringClient()

with mlflow.start_run():

# df has columns ['customer_id', 'product_id', 'rating']
training_set = fe.create_training_set(
df=df,
feature_lookups=feature_lookups,
label='rating',
exclude_columns=['customer_id', 'product_id']
)

training_df = training_set.load_df().toPandas()

# "training_df" columns ['total_purchases_30d', 'category', 'rating']
X_train = training_df.drop(['rating'], axis=1)
y_train = training_df.rating

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

fe.log_model(
model=model,
artifact_path="recommendation_model",
flavor=mlflow.sklearn,
training_set=training_set,
registered_model_name="recommendation_model"
)

# Batch inference

# If the model at model_uri is packaged with the features, the FeatureStoreClient.score_batch()
# call automatically retrieves the required features from Feature Store before scoring the model.
# The DataFrame returned by score_batch() augments batch_df with
# columns containing the feature values and a column containing model predictions.

fe = FeatureEngineeringClient()

# batch_df has columns 'customer_id' and 'product_id'
predictions = fe.score_batch(
model_uri=model_uri,
df=batch_df
)

# The 'predictions' DataFrame has these columns:
# 'customer_id', 'product_id', 'total_purchases_30d', 'category', 'prediction'

Utiliser des valeurs de feature personnalisées lors du scoring d’un modèle package avec des métadonnées de feature

By default, un modèle package avec des métadonnées de fonctionnalités recherche les fonctionnalités dans les tables de fonctionnalités au moment de l'inférence. Pour utiliser des valeurs de fonctionnalités personnalisées pour la notation, incluez-les dans le DataFrame transmis à FeatureEngineeringClient.score_batch (pour Data Engineering dans Unity Catalog) ou FeatureStoreClient.score_batch (pour Workspace Magasin de fonctionnalités).

Par exemple, supposons que vous packagiez un modèle avec ces deux features :

Python
feature_lookups = [
FeatureLookup(
table_name='ml.recommender_system.customer_features',
feature_names=['account_creation_date', 'num_lifetime_purchases'],
lookup_key='customer_id',
),
]

Lors de l'inférence, vous pouvez fournir des valeurs personnalisées pour la fonctionnalité account_creation_date en appelant score_batch sur un DataFrame qui comprend une colonne nommée account_creation_date. Dans ce cas, l'API recherche uniquement la fonctionnalité num_lifetime_purchases depuis le Magasin de fonctionnalités et utilise les valeurs de colonne personnalisées account_creation_date fournies pour la notation du modèle.

Python
# batch_df has columns ['customer_id', 'account_creation_date']
predictions = fe.score_batch(
model_uri='models:/ban_prediction_model/1',
df=batch_df
)

Entraîner et évaluer un modèle à l'aide d'une combinaison de fonctionnalités du Magasin de fonctionnalités et de données résidant en dehors du Magasin de fonctionnalités

Vous pouvez entraîner un modèle en utilisant une combinaison de fonctionnalités du Magasin de fonctionnalités et de données provenant de l'extérieur du Magasin de fonctionnalités. Lorsque vous package le modèle avec les métadonnées de fonctionnalité, le modèle récupère les valeurs de fonctionnalité du Magasin de fonctionnalités pour l'inférence.

Pour entraîner un modèle, incluez les données supplémentaires sous forme de colonnes dans le DataFrame transmis à FeatureEngineeringClient.create_training_set (pour Feature Engineering dans Unity Catalog) ou à FeatureStoreClient.create_training_set (pour le Magasin de fonctionnalités du Workspace). Cet exemple utilise la fonctionnalité total_purchases_30d du Magasin de fonctionnalités et la colonne externe browser.

Python
feature_lookups = [
FeatureLookup(
table_name='ml.recommender_system.customer_features',
feature_names=['total_purchases_30d'],
lookup_key='customer_id',
),
]

fe = FeatureEngineeringClient()

# df has columns ['customer_id', 'browser', 'rating']
training_set = fe.create_training_set(
df=df,
feature_lookups=feature_lookups,
label='rating',
exclude_columns=['customer_id'] # 'browser' is not excluded
)

Lors de l'inférence, le DataFrame utilisé dans FeatureStoreClient.score_batch doit inclure la colonne browser.

Python
# At inference, 'browser' must be provided
# batch_df has columns ['customer_id', 'browser']
predictions = fe.score_batch(
model_uri=model_uri,
df=batch_df
)

Chargez des modèles et effectuez une inférence par batch à l'aide de MLflow

Une fois qu'un modèle a été enregistré à l'aide de la méthode log_model de FeatureEngineeringClient (pour l'Ingénierie des fonctionnalités dans Unity Catalog) ou de FeatureStoreClient (pour le Magasin de fonctionnalités du Workspace), MLflow peut être utilisé lors de l'inférence. mlflow.pyfunc.predict récupère les valeurs de fonctionnalités du Magasin de fonctionnalités et joint également toutes les valeurs fournies au moment de l'inférence. Vous devez fournir la ou les clé(s) primaire(s) des fonctionnalités utilisées dans le modèle.

remarque

L'inférence par lot avec MLflow requiert MLflow 2,11 ou une version ultérieure. Les modèles qui utilisent des tables de fonctionnalités de séries chronologiques ne sont pas pris en charge. Pour effectuer l'inférence par batch avec des tables de caractéristiques de séries temporeelles, utilisez score_batch. Consultez Entraîner des modèles et effectuer l'inférence par batch avec des tables de caractéristiques.

Python
# Train model
import mlflow
from sklearn import linear_model

feature_lookups = [
FeatureLookup(
table_name='ml.recommender_system.customer_features',
feature_names=['total_purchases_30d'],
lookup_key='customer_id',
),
FeatureLookup(
table_name='ml.recommender_system.product_features',
feature_names=['category'],
lookup_key='product_id'
)
]

fe = FeatureEngineeringClient()

with mlflow.start_run():

# df has columns ['customer_id', 'product_id', 'rating']
training_set = fe.create_training_set(
df=df,
feature_lookups=feature_lookups,
label='rating',
exclude_columns=['customer_id', 'product_id']
)

training_df = training_set.load_df().toPandas()

# "training_df" columns ['total_purchases_30d', 'category', 'rating']
X_train = training_df.drop(['rating'], axis=1)
y_train = training_df.rating

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

fe.log_model(
model=model,
artifact_path="recommendation_model",
flavor=mlflow.sklearn,
training_set=training_set,
registered_model_name="recommendation_model",
#refers to the default value of "result_type" if not provided at inference
params={"result_type":"double"},
)

# Batch inference with MLflow

# NOTE: the result_type parameter can only be used if a default value
# is provided in log_model. This is automatically done for all models
# logged using Databricks Runtime for ML 15.0 or above.
# For earlier Databricks Runtime versions, use set_result as shown below.

# batch_df has columns 'customer_id' and 'product_id'
model = mlflow.pyfunc.load_model(model_version_uri)

# If result_type parameter is provided in log_model
predictions = model.predict(df, {"result_type":"double"})

# If result_type parameter is NOT provided in log_model
model._model_impl.set_result_type("double")
predictions = model.predict(df)

Gérer les valeurs de caractéristiques manquantes

Lorsqu'une clé de recherche inexistante est transmise au modèle pour la prédiction, la valeur de fonctionnalité récupérée par FeatureLookup peut être None ou NaN, selon l'environnement. Votre implémentation de modèle devrait être capable de gérer les deux valeurs.

  • Pour les applications hors ligne utilisant fe.score_batch, la valeur renvoyée pour une fonctionnalité manquante est NaN.
  • Pour les applications en ligne utilisant Model Serving, la valeur renvoyée peut être None ou NaN:
    • Si aucune des clés de recherche fournies n'existe, la valeur est None.
    • Si seul un sous-ensemble des clés de recherche n'existe pas, la valeur est NaN.

Pour gérer les valeurs de fonctionnalité manquantes lors de l'utilisation de fonctionnalités à la demande, consultez Comment gérer les valeurs de fonctionnalité manquantes.

Dépannage

Message d'erreur : Could not find lookup key columns ... required by FeatureLookups.

OU

Message d'erreur : Unable to join feature table '...' because timestamp lookup key '...' not found in DataFrame.

L'appel create_training_set a échoué car une clé primaire ou une clé Timestamp est manquante dans le DataFrame d'entraînement. Le DataFrame d'entraînement doit contenir toutes les clés de recherche et les clés de recherche Timestamp de l'ensemble des recherches de fonctionnalités.

Exemples de Notebooks

Le Notebook de base montre comment créer une table de fonctionnalités, l'utiliser pour entraîner un modèle et exécuter un scoring par batch à l'aide de la recherche automatique de fonctionnalités. Il affiche également l'interface utilisateur d'ingénierie des fonctionnalités, que vous pouvez utiliser pour rechercher des fonctionnalités et comprendre comment celles-ci sont créées et utilisées.

Notebook d'exemple de Feature Engineering de base dans Unity Catalog

Le notebook d'exemple de taxi illustre le processus de création et de mise à jour de fonctionnalités, et de leur utilisation pour l'entraînement de modèles et l'inférence par batch.

Notebook d'exemple de Feature Engineering dans Unity Catalog pour les taxis