FeatureGenerator (FG) est un processus de transformation des données qui convertit les entrées brutes en caractéristiques prêtes pour l'entraînement du modèle. Il est conçu pour garantir la cohérence entre la génération d'échantillons hors ligne et en ligne. Ce processus est également appelé transformation de caractéristiques, car il transforme une ou plusieurs caractéristiques. Divers types d'opérateurs de caractéristiques sont disponibles pour effectuer ces opérations.
La génération de caractéristiques se concentre uniquement sur les transformations requises pour la génération d'échantillons à la fois hors ligne et en ligne. Si une opération de transformation n'est nécessaire qu'à l'étape hors ligne, ne la définissez pas comme une opération FG. Le schéma suivant illustre la position du module FG dans l'architecture d'un système de recommandation.
Le processus de génération de caractéristiques consiste en une série d'opérateurs de caractéristiques (opérateurs FG) exécutés en parallèle selon l'ordre topologique d'un graphe acyclique dirigé (DAG) défini dans le fichier de configuration.
Exemple de fichier de configuration
Configurez les opérateurs de caractéristiques dans la liste features. Chaque opérateur de caractéristique doit inclure les paramètres feature_name et feature_type. Pour les autres paramètres de configuration, reportez-vous à la rubrique Opérateurs de caractéristiques intégrés.
Le paramètre reserves spécifie les champs à transmettre tels quels depuis une tâche hors ligne, sans transformation de caractéristique.
{
"features": [
{
"feature_name": "goods_id",
"feature_type": "id_feature",
"value_type": "string",
"expression": "item:goods_id",
"default_value": "-1024",
"need_prefix": false
},
{
"feature_name": "color_pair",
"feature_type": "combo_feature",
"value_type": "string",
"expression": ["user:query_color", "item:color"],
"default_value": "",
"need_prefix": false
},
{
"feature_name": "current_price",
"feature_type": "raw_feature",
"value_type": "double",
"expression": "item:current_price",
"default_value": "0",
"need_prefix": false
},
{
"feature_name": "usr_cate1_clk_cnt_1d",
"feature_type": "lookup_feature",
"map": "user:usr_cate1_clk_cnt_1d",
"key": "item:cate1",
"need_discrete": false,
"need_key": false,
"default_value": "0",
"combiner": "max",
"need_prefix": false,
"value_type": "double"
},
{
"feature_name": "recommend_match",
"feature_type": "overlap_feature",
"method": "is_contain",
"query": "user:query_recommend",
"title": "item:recommend",
"default_value": "0"
},
{
"feature_name": "norm_title",
"feature_type": "text_normalizer",
"expression": "item:title",
"max_length": 512,
"parameter": 0,
"remove_space": false,
"is_gbk_input": false,
"is_gbk_output": false
},
{
"feature_name": "title_terms",
"feature_type": "tokenize_feature",
"expression": "feature:norm_title",
"default_value": "",
"vocab_file": "tokenizer.json",
"output_type": "word_id",
"output_delim": ","
},
{
"feature_name": "query_title_match_ratio",
"feature_type": "overlap_feature",
"method": "query_common_ratio",
"query": "user:query_terms",
"title": "feature:title_terms",
"default_value": "0"
},
{
"feature_name": "title_term_match_ratio",
"feature_type": "overlap_feature",
"method": "title_common_ratio",
"query": "user:query_terms",
"title": "feature:title_terms",
"default_value": "0"
},
{
"feature_name": "term_proximity_min_cover",
"feature_type": "overlap_feature",
"method": "proximity_min_cover",
"query": "user:query_terms",
"title": "feature:title_terms",
"default_value": "0"
}
],
"input_alias": {
"non_exist_field1": "exist_field1",
"non_exist_field2": "exist_field2"
},
"reserves": [
"request_id",
"user_id",
"is_click",
"is_pay",
"sample_weight",
"event_unix_time"
]
}
Élément de configuration spécial input_alias : dictionnaire qui mappe un nom de champ d'entrée potentiellement inexistant à un nom de champ réel. (La configuration input_alias est prise en charge à partir de la version 1.0.0. Vous pouvez généralement ignorer cette configuration.)
Cas d'utilisation 1 : définissez un alias plus court pour un nom de champ long.
Cas d'utilisation 2 : définissez un alias pour le second paramètre lorsqu'un opérateur de caractéristique personnalisé utilise la même entrée pour deux paramètres différents.
Le même champ d'entrée peut être réutilisé across différentes caractéristiques, mais ne peut pas être réutilisé au sein d'une seule transformation de caractéristique. Vous pouvez configurer input_alias pour contourner cette restriction.
Par exemple, si un opérateur de caractéristique personnalisé possède deux paramètres d'entrée qui requièrent tous deux le même champ
A, vous pouvez configurer deux entrées,AetB, ainsi qu'uninput_aliaspour mapper"B": "A". À l'exécution, les paramètres de l'opérateur de caractéristique personnalisé passent de (A, B) à (A, A).
Domaines d'entrée
Un domaine d'entrée indique l'entité d'où provient une entrée. Les quatre types suivants sont pris en charge :
user : caractéristiques côté utilisateur, y compris les profils utilisateur et les caractéristiques statistiques au niveau de l'utilisateur.
context : caractéristiques contextuelles qui changent à chaque requête, telles que l'heure, l'emplacement et la météo.
item : caractéristiques côté article, y compris les caractéristiques de contenu statique et les caractéristiques statistiques au niveau de l'article.
feature : sortie d'un autre opérateur de caractéristique.
Le domaine d'entrée feature est particulier ; il configure les dépendances entre les opérateurs de caractéristiques. Collectivement, tous les opérateurs de caractéristiques forment un graphe acyclique dirigé (DAG). Le framework exécute ces opérations de transformation de caractéristiques en parallèle selon l'ordre topologique. La topologie est illustrée dans la figure suivante.
Par défaut, la sortie des nœuds intermédiaires d'un DAG n'est pas utilisée comme sortie du FG. Vous pouvez utiliser le paramètre de configuration de caractéristique stub_type pour modifier ce comportement.
Types multivalués et séparateurs
FG prend en charge les types d'entrée complexes, tels que Array et Map, qui sont cohérents avec les types complexes de MaxCompute.
Les caractéristiques multivaluées de type chaîne peuvent utiliser chr(29) comme délimiteur.
Par exemple, dans v1^]v2^]v3, ^] est le séparateur multivalué. Il s'agit d'un seul caractère dont le code ASCII est "\x1D", et non de deux caractères. Pour saisir ce caractère, appuyez sur C-q C-5 dans emacs ou C-v C-5 dans vi.
Discrétisation des caractéristiques (binning)
Le framework prend en charge les six types d'opérations de discrétisation suivants :
hash_bucket_size : hache le résultat de la transformation de caractéristique et applique une opération modulo.
vocab_list : mappe le résultat de la transformation de caractéristique à un index dans une liste.
vocab_dict : mappe le résultat de la transformation de caractéristique à une valeur dans un dictionnaire. La valeur doit être convertible vers le type int64.
vocab_file : lit un
vocab_listouvocab_dictà partir d'un fichier.boundaries : convertit le résultat de la transformation de caractéristique en un ID de compartiment correspondant en fonction des limites spécifiées.
num_buckets : utilise directement le résultat de la transformation de caractéristique comme ID de compartiment.
hash_bucket_size
Hache le résultat de la transformation et applique une opération modulo. Cette méthode s'applique à tout type de valeur de caractéristique.
Plage de résultats : [0,
hash_bucket_size)Le résultat de la discrétisation pour une valeur vide est
hash(default_value)%hash_bucket_size.
{
"hash_bucket_size": 128000,
"default_value": "default_value"
}
vocab_list
Discrétise l'entrée en mappant une valeur de caractéristique à son index correspondant dans le tableau vocab_list.
Le type d'élément du tableau
vocab_listdoit être identique à la configurationvalue_type.-
num_oov_bucket: entier non négatif, nombre de compartiments hors vocabulaire.Toutes les entrées hors vocabulaire recevront des IDs dans la plage [vocabulary_size, vocabulary_size+num_oov_buckets) en fonction d'un hachage de la valeur d'entrée.
Un num_oov_buckets positif ne peut pas être spécifié avec
default_bucketize_value.
-
default_bucketize_value: valeur d'ID entière à renvoyer pour les valeurs de caractéristique hors vocabulaire.Vous ne pouvez pas spécifier ceci lorsque
num_oov_bucketsest positif.La valeur par défaut est
vocab_list.size().
{
"vocab_list": [
"",
"<OOV>",
"token1",
"token2",
"token3",
"token4"
],
"num_oov_bucket": 0,
"default_bucketize_value": 1
}
vocab_dict
Le résultat de la discrétisation est la valeur dans le dictionnaire vocab_dict qui correspond à la valeur de caractéristique. Cela permet de mapper différentes valeurs de caractéristique vers le même résultat de discrétisation.
Le type de données des clés dans le dictionnaire
vocab_dictdoit être identique à la configurationvalue_type.La valeur de
vocab_dictdoit être convertible vers le typeint64.-
num_oov_bucket: entier non négatif, nombre de compartiments hors vocabulaire.Toutes les entrées hors vocabulaire recevront des IDs dans la plage [vocabulary_size, vocabulary_size+num_oov_buckets) en fonction d'un hachage de la valeur d'entrée.
Un num_oov_buckets positif ne peut pas être spécifié avec
default_bucketize_value.
-
default_bucketize_value: valeur d'ID entière à renvoyer pour les valeurs de caractéristique hors vocabulaire.Ceci ne peut pas être spécifié avec un
num_oov_bucketspositif.La valeur par défaut est
vocab_dict.size().
{
"vocab_dict": {
"token1": 1,
"token2": 2,
"token3": 3,
"token4": 1
},
"num_oov_bucket": 0,
"default_bucketize_value": 4
}
vocab_file
Charge un vocab_list ou vocab_dict à partir d'un fichier.
{
"vocab_file": "vocab.txt",
"num_oov_bucket": 0,
"default_bucketize_value": 4
}
-
vocab_file: chemin d'accès au fichier de vocabulaire. Le fichier contient un vocabulaire, avec un terme par ligne. Vous pouvez éventuellement spécifier une valeur de mappage.Les chemins relatifs sont pris en charge. Lors du déploiement du service en ligne, le fichier doit être placé dans le même répertoire que
fg.json.Si seul un jeton est présent, il est mappé au numéro de ligne (à partir de 0). Si une valeur est présente, le jeton et la valeur sont séparés par un caractère d'espace blanc (un espace ou une tabulation). La valeur doit être de type
int64.
num_oov_bucketetdefault_bucketize_valueont la même signification que décrite ci-dessus.
boundaries
Regroupe les caractéristiques numériques en fonction des limites de compartiment spécifiées.
Le type d'élément du tableau
boundariesdoit être identique à la configurationvalue_type.Les compartiments incluent la limite gauche et excluent la limite droite.
Par exemple,
boundaries=[0., 1., 2.]génère les compartiments (-inf, 0.), [0., 1.), [1., 2.) et [2., +inf).
{
"boundaries": [0.0, 1.0, 2.0],
"default_value": -1
}
num_buckets
Utilise directement le résultat de la transformation de caractéristique comme ID de compartiment. Cette méthode convient aux valeurs de caractéristique convertibles en entier.
Plage de résultats : [0,
num_buckets)Si la valeur de caractéristique est en dehors de la plage configurée, elle reçoit la valeur
default_bucketize_value.
{
"num_buckets": 128000,
"default_bucketize_value": 127999
}
Opérateurs de caractéristiques intégrés
Les méthodes de configuration varient selon les opérateurs de caractéristiques. Tous les opérateurs de caractéristiques pouvant être des nœuds feuilles dans le DAG prennent en charge la discrétisation des caractéristiques.
Pour plus d'informations, reportez-vous à la rubrique Opérateurs de caractéristiques intégrés.
|
Type |
Description |
|
id_feature |
Caractéristique catégorielle |
|
raw_feature |
Caractéristique numérique |
|
expr_feature |
Caractéristique d'expression |
|
combo_feature |
Caractéristique de combinaison |
|
combine_feature |
Caractéristique de combinaison (agrégée en une seule valeur) |
|
lookup_feature |
Caractéristique de recherche dans un dictionnaire |
|
match_feature |
Caractéristique de recherche dans un dictionnaire avec clé primaire-secondaire |
|
overlap_feature |
Caractéristique de chevauchement |
|
sequence_feature |
Caractéristique de séquence |
|
text_normalizer |
Normalisation de texte |
|
tokenize_feature |
Caractéristique de tokenisation de texte |
|
bm25_feature |
Caractéristique de pertinence textuelle BM25 |
|
kv_dot_product |
Produit scalaire de vecteur KV |
|
str_replace_feature |
Remplacement de chaîne |
|
regex_replace_feature |
Remplacement par expression régulière |
|
slice_feature |
Tranchage de tableau |
Combinaisons d'opérateurs
En configurant un DAG, vous pouvez combiner divers opérateurs intégrés pour effectuer des transformations de caractéristiques puissantes.
Exemple 1 : Moyenne des 4 premiers éléments de séquence
{
"features": [
{
"feature_name": "top_n_prices",
"feature_type": "sequence_raw_feature",
"expression": "user:clk_prices",
"separator": ",",
"sequence_length": 4,
"stub_type": true
},
{
"feature_name": "top_n_avg_price",
"feature_type": "expr_feature",
"expression":"reduce_mean(top_n_prices)",
"default_value": "-1",
"variables":["feature:top_n_prices"]
}
]
}
Exemple 2 : Moyenne des éléments de séquence avec condition
{
"features": [
{
"feature_name": "valid_list",
"feature_type": "expr_feature",
"expression":"clk_times < 10",
"variables":["user:clk_times"],
"value_dimension": 5
},
{
"feature_name": "top_n_prices",
"feature_type": "bool_mask_feature",
"expression": ["user:clk_prices", "feature:valid_list"],
"value_type": "float",
"separator": ","
},
{
"feature_name": "top_n_avg_price",
"feature_type": "expr_feature",
"expression":"reduce_mean(top_n_prices)",
"default_value": "-1",
"variables":["feature:top_n_prices"]
}
]
}
Remarque : dans l'exemple précédent, clk_prices et clk_times sont deux séquences parallèles.
Opérateurs de caractéristiques personnalisés
Les opérateurs de caractéristiques personnalisés peuvent être chargés et exécutés dynamiquement par le framework sous forme de plugins.
Pour plus d'informations, reportez-vous à la rubrique Opérateurs de caractéristiques personnalisés.
Optimisation des performances
Les performances du module FG dépendent fortement de sa configuration. Le principe général consiste à minimiser les transformations de données (caractéristiques) inutiles.
Si vous pouvez traiter et transformer les données lors des étapes hors ligne ou quasi en ligne, ne les effectuez pas à l'étape FG (service de scoring en ligne).
Suivez ces recommandations pour améliorer les performances :
-
Pour les données d'entrée structurées, privilégiez l'utilisation des types complexes des tables MaxCompute (par exemple, Map et Array) plutôt que le type STRING afin de réduire la charge liée à l'analyse des chaînes.
Dans les services de scoring en ligne (tels que EasyRec Processor ou TorchEasyRec Processor), utilisez FeatureStore et FeatureDB comme stockage en ligne pour permettre la prise en charge des types complexes.
Pour un
lookup_feature, il est fortement recommandé d'utiliser le type Map pour le champmap.Pour
sequence_feature,overlap_featureetbm25_feature, il est fortement recommandé d'utiliser des entrées de type Array.Évitez d'utiliser
match_featurecar il ne prend pas en charge les types complexes. Utilisez plutôtlookup_featureen combinantpkeyetskey.
-
Évitez la surcharge liée à la conversion des types de données.
Le
value_typederaw_featurene doit pas être défini sur un type autre que float sans raison spécifique.Pour un
lookup_feature, assurez-vous que le type de clé de l'entréeMap<Key, Value>correspond au type du champ de requête.Si vous configurez une discrétisation de caractéristique de type
num_buckets,value_typedoit être défini surint64.-
Si le type optimal pour une colonne de données varie selon les scénarios, envisagez d'ajouter une copie de la colonne avec un type différent.
Par exemple, un champ doit être de type BIGINT lorsqu'il est utilisé comme champ de recherche pour
lookup_feature, mais de type STRING lorsqu'il fait partie decombo_feature.-
Dans ce cas, ajoutez une copie de la colonne pour chaque type requis : un BIGINT et un STRING. Voici un exemple de code SQL :
SELECT int_data, int_data as str_data FROM ....
Réutilisez autant que possible la logique et les calculs partagés en utilisant les dépendances de caractéristiques (mode DAG).
Configuration globale
|
Paramètre |
Type |
Valeur par défaut |
Description |
|
USE_CITY_HASH_TO_BUCKETIZE |
string |
'false' |
Indique s'il faut utiliser CityHash comme fonction de hachage pour la discrétisation des caractéristiques. |
|
USE_MULTIPLICATIVE_HASH |
string |
'false' |
Indique s'il faut utiliser le hachage multiplicatif au lieu de l'opération modulo pour le hachage des caractéristiques. Cette option est recommandée. |
|
DISABLE_FG_PRECISION |
string |
'true' |
Définissez sur 'false' pour limiter les caractéristiques à virgule flottante à six décimales. La valeur par défaut est 'true', ce qui désactive cette contrainte. |
|
DISABLE_STRING_TRIM |
string |
'false' |
Indique s'il faut désactiver la suppression des espaces de début et de fin après la division des caractéristiques de chaîne multivaluées. |
|
MONITOR_CUSTOM_OP_EVERY_N_SECONDS |
string |
'0' |
Spécifie l'intervalle en secondes pour surveiller les performances des opérateurs personnalisés et imprimer les données de performance. Une valeur de '0' désactive la surveillance. |
Remarque : les configurations précédentes doivent être cohérentes dans tous les environnements d'exécution, y compris hors ligne et en ligne, ainsi que pour l'entraînement et l'inférence. Sinon, des incohérences peuvent survenir entre le scoring en ligne et hors ligne.
Taux de collision de hachage
Voici les résultats de test sur un ensemble de données comportant 26 caractéristiques de cardinalités différentes, où le hash_bucket_size pour chaque caractéristique est défini sur 10 × sa cardinalité :
|
Type de hachage |
Cardinalité totale des caractéristiques |
Total des compartiments |
Taux de collision de hachage |
|
std::hash |
882 774 549 |
840 065 238 |
4,8381 % |
|
cityhash |
882 774 549 |
840 072 446 |
4,8373 % |
|
std+cityhash |
882 774 549 |
840 075 948 |
4,8369 % |
|
cityhash+multiplicative |
882 774 549 |
840 072 195 |
4,8373 % |
|
std+multiplicative |
882 774 549 |
840 077 306 |
4,8367 % |
En résumé, nous recommandons d'utiliser std::hash + MultiplicativeHash comme approche combinée pour optimiser les performances du modèle. std::hash est activé par défaut. MultiplicativeHash est désactivé par défaut pour des raisons de rétrocompatibilité, et vous devez l'activer manuellement en suivant les instructions ci-dessous.
De plus, CityHash est une méthode qui offre théoriquement une meilleure uniformité, mais elle n'a pas montré d'avantage significatif sur cet ensemble de données. Vous pouvez la tester davantage sur votre propre ensemble de données.
Configuration du service de scoring en ligne
Configurez ces paramètres à l'aide de variables d'environnement côté serveur. Plus précisément, vous pouvez les définir dans la configuration du service de EasyRec Processor ou de TorchEasyRec Processor.
{
"processor_envs": [
{
"name": "USE_MULTIPLICATIVE_HASH",
"value": "true"
}
]
}
Configuration des tâches hors ligne
Pour exécuter des tâches hors ligne pour FG dans l'environnement MaxCompute, reportez-vous à la rubrique Utiliser FG dans les tâches hors ligne.
Plus précisément, reportez-vous au code suivant :
from pyfg105 import run_on_odps
fg_task = run_on_odps.FgTask(...)
fg_task.add_fg_setting('USE_CITY_HASH_TO_BUCKETIZE', 'false')
fg_task.add_fg_setting('USE_MULTIPLICATIVE_HASH', 'true')
fg_task.run(o)
Configuration de l'API pyfg
Lors de l'utilisation de l'API pyfg, par exemple pour effectuer la génération de caractéristiques pendant l'entraînement, vous pouvez la configurer à l'aide de la méthode suivante.
import pyfg
pyfg.set_env('USE_MULTIPLICATIVE_HASH', 'true')
pyfg.set_env('USE_CITY_HASH_TO_BUCKETIZE', 'false')