Migration à partir de réseaux de neurones

TensorFlow Decision Forests ( TF-DF ) est une collection d'algorithmes Decision Forest ( DF ) disponibles dans TensorFlow. Les forêts de décision fonctionnent différemment des réseaux de neurones ( NN ) : les DF ne s'entraînent généralement pas par rétropropagation ou par mini-lots. Par conséquent, les pipelines TF-DF présentent quelques différences par rapport aux autres pipelines TensorFlow.

Ce document est une liste de ces différences et un guide pour mettre à jour les pipelines TF pour utiliser TF-DF.

Ce document suppose une familiarité avec le colab pour débutants .

Ensemble de données et fonctionnalités

Ensemble de données de validation

Contrairement au paradigme standard de formation des réseaux neuronaux, les modèles TF-DF n'ont pas besoin d'un ensemble de données de validation pour surveiller le surapprentissage ou pour arrêter la formation prématurément. Si vous disposez déjà d'une répartition train/validation/test et que vous utilisez la validation pour l'une de ces raisons, vous pouvez entraîner votre TF-DF en toute sécurité sur train+validation (sauf si la répartition de validation est également utilisée pour autre chose, comme réglage des hyperparamètres).

- model.fit(train_ds, validation_data=val_ds)
+ model.fit(train_ds.concatenate(val_ds))

# Or just don't create a validation dataset

Justification : Le framework TF-DF est composé de plusieurs algorithmes. Certains d'entre eux n'utilisent pas d'ensemble de données de validation (par exemple Random Forest), tandis que d'autres le font (par exemple Gradient Boosted Trees). Les algorithmes qui le font pourraient bénéficier de différents types et tailles d’ensembles de données de validation. Par conséquent, si un ensemble de données de validation est nécessaire, il sera automatiquement extrait de l'ensemble de données de formation.

E/S du jeu de données

Entraînez-vous pendant exactement 1 époque

# Number of epochs in Keras
- model.fit(train_ds, num_epochs=5)

# Number of epochs in the dataset
- train_ds = train_ds.repeat(5)
- model.fit(train_ds)
+ model.fit(train_ds)

Justification : les utilisateurs de réseaux de neurones entraînent souvent un modèle en N étapes (ce qui peut impliquer une boucle sur l'ensemble de données > 1 fois), en raison de la nature de SGD . TF-DF s'entraîne en lisant l'intégralité de l'ensemble de données, puis en exécutant l'entraînement à la fin. 1 époque est nécessaire pour lire l'ensemble de données complet, et toute étape supplémentaire entraînera des E/S de données inutiles, ainsi qu'un entraînement plus lent.

Ne mélangez pas l'ensemble de données

Les ensembles de données n'ont pas besoin d'être mélangés (sauf si input_fn ne lit qu'un échantillon de l'ensemble de données).

- train_ds = train_ds.shuffle(5)
- model.fit(train_ds)
+ model.fit(train_ds)

Justification : TF-DF mélange l'accès aux données en interne après avoir lu l'ensemble de données complet en mémoire. Les algorithmes TF-DF sont déterministes (si l'utilisateur ne modifie pas la graine aléatoire). L'activation de la lecture aléatoire ne fera que rendre l'algorithme non déterministe. Le brassage a du sens si l'ensemble de données d'entrée est ordonné et que input_fn ne va en lire qu'un échantillon (l'échantillon doit être aléatoire). Cependant, cela rendra la procédure de formation non déterministe.

Ne pas ajuster la taille du lot

La taille du lot n'affectera pas la qualité du modèle

- train_ds = train_ds.batch(hyper_parameter_batch_size())
- model.fit(train_ds)
# The batch size does not matter.
+ train_ds = train_ds.batch(64)
+ model.fit(train_ds)

Justification : Étant donné que TF-DF est toujours formé sur l'ensemble de données complet après sa lecture, la qualité du modèle ne variera pas en fonction de la taille du lot (contrairement aux algorithmes de formation en mini-lots comme SGD où des paramètres tels que le taux d'apprentissage doivent être ajustés conjointement). Il doit donc être supprimé des balayages d'hyperparamètres. La taille du lot n’aura un impact que sur la vitesse des E/S de l’ensemble de données.

Grands ensembles de données

Contrairement aux réseaux neuronaux, qui peuvent parcourir à l’infini des mini-lots d’un vaste ensemble de données, les forêts de décision nécessitent un ensemble de données fini qui tient en mémoire pour leurs procédures de formation. La taille de l'ensemble de données a des implications en termes de performances et de mémoire.

Il y a des rendements décroissants pour l’augmentation de la taille de l’ensemble de données, et les algorithmes DF ont sans doute besoin de moins d’exemples pour la convergence que les grands modèles NN. Au lieu d'augmenter le nombre d'étapes de formation (comme dans un NN), vous pouvez essayer d'augmenter la quantité de données pour voir où le compromis de calcul est logique. Par conséquent, c'est une bonne idée d'essayer d'abord la formation sur un (petit) sous-ensemble de l'ensemble de données.

La solution alternative consiste à utiliser une formation distribuée . La formation distribuée est un excellent moyen d'augmenter la taille de l'ensemble de données si plusieurs machines sont disponibles. Bien que tous les algorithmes distribués soient disponibles pour répartir le calcul, ils ne sont pas tous capables de répartir l’utilisation de la RAM. Consultez la documentation pour plus de détails.

Combien d'exemples utiliser

Il doit tenir en mémoire sur la machine sur laquelle le modèle s'entraîne :

  • Notez que ce n'est pas la même chose que la taille des exemples sur le disque.

  • En règle générale, une valeur numérique ou catégorielle utilise 4 octets de mémoire. Ainsi, un ensemble de données avec 100 fonctionnalités et 25 millions d'exemples occupera ~ 10 Go (= 100 * 25 * 10 ^ 6 * 4 octets) de mémoire.

  • Les fonctionnalités catégorielles (par exemple, le texte tokenisé) prennent plus de mémoire (4 octets par jeton + 12 octets par fonctionnalité).

Tenez compte de votre budget temps de formation

  • Bien qu'ils soient généralement plus rapides que NN pour les ensembles de données plus petits (par exemple <100 000 exemples), les algorithmes d'entraînement DF n'évoluent pas linéairement avec la taille de l'ensemble de données ; plutôt, ~O(features x num_examples x log(num_examples)) dans la plupart des cas.

  • Le temps de formation dépend des hyper-paramètres. Les paramètres les plus impactants sont : (1) le nombre d'arbres ( num_trees ), (2) l'exemple de taux d'échantillonnage ( subsample for GBT) et (3) le taux d'échantillonnage des attributs ( num_candidate_attributes_ratio ).

  • Les fonctionnalités définies par catégorie sont plus chères que les autres fonctionnalités. Le coût est contrôlé par le paramètre categorical_set_split_greedy_sampling .

  • Les fonctionnalités Sparse Oblique (désactivées par défaut) donnent de bons résultats mais sont coûteuses à calculer.

Règles empiriques pour la mise à l’échelle des données

Nous vous suggérons de commencer par une petite partie des données (<10 000 exemples), ce qui devrait vous permettre d'entraîner un modèle TF-DF en quelques secondes ou quelques minutes dans la plupart des cas. Ensuite, vous pouvez augmenter les données à un rythme fixe (par exemple 40 % de plus à chaque fois), en vous arrêtant lorsque les performances de l'ensemble de validation ne s'améliorent pas ou que l'ensemble de données ne tient plus en mémoire.

Normalisation/prétraitement des fonctionnalités

Ne transformez pas les données avec des colonnes de fonctionnalités

Les modèles TF-DF ne nécessitent pas de fournir explicitement une sémantique et des transformations de fonctionnalités. Par défaut, toutes les fonctionnalités de l'ensemble de données (autres que l'étiquette) seront détectées et utilisées par le modèle. La sémantique des fonctionnalités sera détectée automatiquement et pourra être remplacée manuellement si nécessaire.

# Estimator code
- feature_columns = [
-   tf.feature_column.numeric_column(feature_1),
-   tf.feature_column.categorical_column_with_vocabulary_list(feature_2, ['First', 'Second', 'Third'])
-   ]
- model = tf.estimator.LinearClassifier(feature_columns=feature_columnes)
# Use all the available features. Detect the type automatically.
+ model = tfdf.keras.GradientBoostedTreesModel()

Vous pouvez également spécifier un sous-ensemble d'entités en entrée :

+ features = [
+   tfdf.keras.FeatureUsage(name="feature_1"),
+   tfdf.keras.FeatureUsage(name="feature_2")
+   ]
+ model = tfdf.keras.GradientBoostedTreesModel(features=features, exclude_non_specified_features=True)

Si nécessaire, vous pouvez forcer la sémantique d’une fonctionnalité.

+ forced_features = [
+   tfdf.keras.FeatureUsage(name="feature_1", semantic=tfdf.keras.FeatureSemantic.CATEGORICAL),
+   ]
+ model = tfdf.keras.GradientBoostedTreesModel(features=features)

Justification : alors que certains modèles (comme les réseaux de neurones) nécessitent une couche d'entrée standardisée (par exemple, mappages de différents types de fonctionnalités → intégrations), les modèles TF-DF peuvent consommer des fonctionnalités catégorielles et numériques de manière native, ainsi que détecter automatiquement les types sémantiques des fonctionnalités. basé sur les données.

Ne pas prétraiter les fonctionnalités

Les algorithmes d'arbre de décision ne bénéficient pas de certains des prétraitements de fonctionnalités classiques utilisés pour les réseaux de neurones. Ci-dessous, certaines des stratégies de traitement des fonctionnalités les plus courantes sont explicitement répertoriées, mais un point de départ sûr consiste à supprimer tous les prétraitements conçus pour faciliter la formation des réseaux neuronaux.

Ne pas normaliser les caractéristiques numériques

- def zscore(value):
-   return (value-mean) / sd

- feature_columns = [tf.feature_column.numeric_column("feature_1",normalizer_fn=zscore)]

Rationnel : les algorithmes de forêt de décision prennent en charge de manière native les caractéristiques numériques non normalisées, car les algorithmes de fractionnement n'effectuent aucune transformation numérique de l'entrée. Certains types de normalisation (par exemple la normalisation zscore) n'aideront pas à la stabilité numérique de la procédure de formation, et d'autres (par exemple le découpage des valeurs aberrantes) peuvent nuire à l'expressivité du modèle final.

Ne codez pas de fonctionnalités catégorielles (par exemple, hachage, one-hot ou intégration)

- integerized_column = tf.feature_column.categorical_column_with_hash_bucket("feature_1",hash_bucket_size=100)
- feature_columns = [tf.feature_column.indicator_column(integerized_column)]
- integerized_column = tf.feature_column.categorical_column_with_vocabulary_list('feature_1', ['bob', 'george', 'wanda'])
- feature_columns = [tf.feature_column.indicator_column(integerized_column)]

Justification : TF-DF prend en charge nativement les fonctionnalités catégorielles et traitera un élément de vocabulaire « transformé » comme un simple élément supplémentaire dans son vocabulaire interne (qui peut être configuré via des hyperparamètres de modèle). Certaines transformations (comme le hachage) peuvent entraîner des pertes. Les intégrations ne sont pas prises en charge à moins qu'elles ne soient pré-entraînées, car les modèles Decision Forest ne sont pas différenciables (voir colab intermédiaire ). Notez que les stratégies de vocabulaire spécifiques au domaine (par exemple, suppression des mots vides, normalisation du texte) peuvent toujours être utiles.

Comment gérer les fonctionnalités de texte

TF-DF prend en charge nativement les fonctionnalités définies par catégorie . Par conséquent, les sacs de n-grammes tokenisés peuvent être consommés de manière native.

Alternativement, le texte peut également être consommé via une intégration pré-entraînée .

Les ensembles catégoriels sont efficaces en matière d'échantillonnage sur de petits ensembles de données, mais coûteux à former sur de grands ensembles de données. La combinaison d'ensembles catégoriels et d'une intégration pré-entraînée peut souvent donner de meilleurs résultats que si l'un ou l'autre est utilisé seul.

Ne remplacez pas les fonctionnalités manquantes par des valeurs magiques

Justification : TF-DF prend en charge nativement les valeurs manquantes. Contrairement aux réseaux de neurones, qui peuvent propager les NaN aux gradients s'il y a des NaN dans l'entrée, TF-DF s'entraînera de manière optimale si l'algorithme voit la différence entre une valeur manquante et une valeur sentinelle.

- feature_columns = [
- tf.feature_column.numeric_column("feature_1", default_value=0),
- tf.feature_column.numeric_column("feature_1_is_missing"),
- ]

Gestion des images et des séries temporelles

Il n'existe pas d'algorithme standard pour consommer les fonctionnalités d'images ou de séries temporelles dans les forêts de décision, un travail supplémentaire est donc nécessaire pour les utiliser.

Justification : La convolution, le LSTM, l'attention et d'autres algorithmes de traitement de séquence sont des architectures spécifiques aux réseaux neuronaux.

Il est possible de gérer ces fonctionnalités en utilisant les stratégies suivantes :

  • Ingénierie des fonctionnalités

    • Images : l'utilisation d'images avec Random Forest était populaire à un moment donné (par exemple

      Microsoft Kinect , mais aujourd'hui, les réseaux de neurones sont à la pointe de la technologie.

    • Séries chronologiques : les [ statistiques mobiles ] peuvent fonctionner étonnamment bien pour les données de séries chronologiques comportant relativement peu d'exemples (par exemple, les signes vitaux dans le domaine médical).

    • Modules d'intégration : les modules d'intégration de réseaux neuronaux peuvent fournir des fonctionnalités riches pour un algorithme de forêt de décision. Le colab intermédiaire montre comment combiner une intégration tf-hub et un modèle TF-DF.

Pipeline de formation

N'utilisez pas d'accélérateurs matériels, par exemple GPU, TPU

La formation TF-DF ne prend pas (encore) en charge les accélérateurs matériels. Toute la formation et l'inférence sont effectuées sur le CPU (parfois en utilisant SIMD).

Notez que l'inférence TF-DF sur le processeur (en particulier lorsqu'elle est utilisée à l'aide des bibliothèques Yggdrasil C++) peut être étonnamment rapide (sous la microseconde par exemple et par cœur de processeur).

N'utilisez pas de points de contrôle ou de crochets à mi-entraînement

TF-DF ne prend pas (actuellement) en charge le point de contrôle du modèle, ce qui signifie que les hooks qui s'attendent à ce que le modèle soit utilisable avant la fin de la formation ne sont en grande partie pas pris en charge. Le modèle ne sera disponible qu'après avoir entraîné le nombre d'arbres demandé (ou s'être arrêté plus tôt).

Les crochets Keras s'appuyant sur l'étape de formation ne fonctionneront pas non plus – en raison de la nature de la formation TF-DF, le modèle s'entraîne à la fin de la première époque et sera constant après cette époque. L’étape correspond uniquement aux E/S du jeu de données.

Déterminisme du modèle

L'algorithme de formation TF-DF est déterministe, c'est-à-dire qu'une formation deux fois sur le même ensemble de données donnera exactement le même modèle. Ceci est différent des réseaux de neurones entraînés avec TensorFlow. Pour préserver ce déterminisme, les utilisateurs doivent s'assurer que les lectures des ensembles de données sont également déterministes.

Configuration de la formation

Spécifiez une tâche (par exemple classification, classement) au lieu d'une perte (par exemple entropie croisée binaire)

- model = tf_keras.Sequential()
- model.add(Dense(64, activation=relu))
- model.add(Dense(1)) # One output for binary classification

- model.compile(loss=tf_keras.losses.BinaryCrossentropy(from_logits=True),
-               optimizer='adam',
-               metrics=['accuracy'])
# The loss is automatically determined from the task.
+ model = tfdf.keras.GradientBoostedTreesModel(task=tf_keras.Task.CLASSIFICATION)

# Optional if you want to report the accuracy.
+ model.compile(metrics=['accuracy'])

Justification : tous les algorithmes d'apprentissage TF-DF n'utilisent pas une perte. Pour ceux qui le font, la perte est automatiquement détectée à partir de la tâche et imprimée dans le résumé du modèle. Vous pouvez également le remplacer avec l'hyper-paramètre de perte.

Les hyper-paramètres sont sémantiquement stables

Tous les hyper-paramètres ont des valeurs par défaut. Ces valeurs sont les premiers candidats raisonnables à essayer. Il est garanti que les valeurs des hyperparamètres par défaut ne changeront jamais. Pour cette raison, les nouveaux hyper-paramètres ou améliorations d’algorithmes sont désactivés par défaut.

Les utilisateurs qui souhaitent utiliser les derniers algorithmes, mais qui ne souhaitent pas optimiser eux-mêmes les hyper-paramètres peuvent utiliser les "modèles d'hyper-paramètres" fournis par TF-DF. De nouveaux modèles d'hyperparamètres seront publiés avec les mises à jour du package.

# Model with default hyper-parameters.
model = tfdf.keras.GradientBoostedTreesModel()

# List the hyper-parameters (with default value) and hyper-parameters templates of the GBT learning algorithm (in colab)
?tfdf.keras.GradientBoostedTreesModel

# Use a hyper-parameter template.
model = tfdf.keras.GradientBoostedTreesModel(hp_template="winner_1")

# Change one of the hyper-parameters.
model = tfdf.keras.GradientBoostedTreesModel(num_trees=500)

# List all the learning algorithms available
tfdf.keras.get_all_models()

Débogage du modèle

Cette section présente quelques façons de visualiser/déboguer/interpréter le modèle. Le colab pour débutants contient un exemple de bout en bout.

Résumé du modèle simple

# Text description of the model, training logs, feature importances, etc.
model.summary()

Journaux de formation et Tensorboard

# List of metrics
logs = model.make_inspector().training_logs()
print(logs)

Ou en utilisant TensorBoard :

% load_ext
tensorboard
model.make_inspector().export_to_tensorboard("/tmp/tensorboard_logs")
% tensorboard - -logdir
"/tmp/tensorboard_logs"

Importance des fonctionnalités

model.make_inspector().variable_importances()

Tracer les arbres

tfdf.model_plotter.plot_model_in_colab(model, tree_idx=0)

Accéder à l'arborescence

tree = model.make_inspector().extract_tree(tree_idx=0)
print(tree)

(Voir Colab avancé )

N'utilisez pas de stratégies de distribution TensorFlow

TF-DF ne prend pas encore en charge les stratégies de distribution TF. Les configurations multi-travailleurs seront ignorées et la formation n'aura lieu que sur le manager.

- with tf.distribute.MirroredStrategy():
-    model = ...
+ model = ....

Modèles empilables

Les modèles TF-DF ne rétropropagent pas les gradients. Par conséquent, ils ne peuvent pas être composés avec des modèles NN à moins que les NN ne soient déjà formés.

Migration depuis tf.estimator.BoostedTrees {Classifier/Regressor/Estimator}

Bien qu'ils semblent similaires, les arbres boostés TF-DF et Estimator sont des algorithmes différents. TF-DF implémente les papiers classiques Random Forest et Gradient Boosted Machine (utilisant des arbres) . Le tf.estimator.BoostedTreesEstimator est un algorithme approximatif d'arbres boostés par gradient avec une procédure de formation par mini-lots décrite dans cet article.

Certains hyper-paramètres ont une sémantique similaire (par exemple num_trees), mais ils ont des implications différentes en matière de qualité. Si vous avez réglé les hyperparamètres sur votre tf.estimator.BoostedTreesEstimator, vous devrez réajuster vos hyperparamètres dans TF-DF pour obtenir les résultats optimaux.

Pour les utilisateurs d'Yggdrasil

Yggdrasil Decision Forest est la bibliothèque de formation et d'inférence de base utilisée par TF-DF. La configuration et les modèles de formation sont compatibles entre eux (c'est-à-dire que les modèles formés avec TF-DF peuvent être utilisés avec l'inférence Yggdrasil).

Cependant, certains algorithmes d’Yggdrasil ne sont pas (encore) disponibles dans TF-DF.

  • Arbre boosté par dégradé avec échantillonnage fragmenté.