Format Hub TF1

Lors de son lancement en 2018, TensorFlow Hub proposait un seul type d'actif : le format TF1 Hub pour l'importation dans les programmes TensorFlow 1.

Cette page explique comment utiliser le format TF1 Hub dans TF1 (ou le mode de compatibilité TF1 de TF2) avec la classe hub.Module et les API associées. (L'utilisation typique est de construire un tf.Graph , éventuellement à l'intérieur d'un TF1 Estimator , en combinant un ou plusieurs modèles au format TF1 Hub avec tf.compat.layers ou tf.layers ).

Les utilisateurs de TensorFlow 2 (hors mode de compatibilité TF1) doivent utiliser la nouvelle API avec hub.load() ou hub.KerasLayer . La nouvelle API charge le nouveau type d'actif TF2 SavedModel, mais offre également une prise en charge limitée pour le chargement du format TF1 Hub dans TF2 .

Utiliser un modèle au format TF1 Hub

Instancier un modèle au format TF1 Hub

Un modèle au format TF1 Hub est importé dans un programme TensorFlow en créant un objet hub.Module à partir d'une chaîne avec son URL ou son chemin de système de fichiers, tel que :

m = hub.Module("path/to/a/module_dir")

Remarque : Pour plus d'informations sur les autres types de handles valides, cliquez ici .

Cela ajoute les variables du module au graphique TensorFlow actuel. L'exécution de leurs initialiseurs lira leurs valeurs pré-entraînées à partir du disque. De même, des tableaux et autres états sont ajoutés au graphique.

Modules de mise en cache

Lors de la création d'un module à partir d'une URL, le contenu du module est téléchargé et mis en cache dans le répertoire temporaire du système local. L'emplacement où les modules sont mis en cache peut être remplacé à l'aide de la variable d'environnement TFHUB_CACHE_DIR . Pour plus de détails, voir Mise en cache .

Appliquer un module

Une fois instancié, un module m peut être appelé zéro ou plusieurs fois comme une fonction Python des entrées tensorielles aux sorties tensorielles :

y = m(x)

Chacun de ces appels ajoute des opérations au graphique TensorFlow actuel pour calculer y à partir de x . S'il s'agit de variables avec des poids entraînés, ceux-ci sont partagés entre toutes les applications.

Les modules peuvent définir plusieurs signatures nommées afin de permettre leur application de plusieurs manières (de la même manière que les objets Python ont des méthodes ). La documentation d'un module doit décrire les signatures disponibles. L'appel ci-dessus applique la signature nommée "default" . N'importe quelle signature peut être sélectionnée en passant son nom à l'argument facultatif signature= .

Si une signature a plusieurs entrées, elles doivent être transmises sous forme de dict, avec les clés définies par la signature. De même, si une signature a plusieurs sorties, celles-ci peuvent être récupérées sous forme de dict en passant as_dict=True , sous les clés définies par la signature (la clé "default" est pour la seule sortie renvoyée si as_dict=False ). Ainsi, la forme la plus générale d’application d’un module ressemble à :

outputs = m(dict(apples=x1, oranges=x2), signature="fruit_to_pet", as_dict=True)
y1 = outputs["cats"]
y2 = outputs["dogs"]

Un appelant doit fournir toutes les entrées définies par une signature, mais il n'est pas obligatoire d'utiliser toutes les sorties d'un module. TensorFlow exécutera uniquement les parties du module qui finissent comme dépendances d'une cible dans tf.Session.run() . En effet, les éditeurs de modules peuvent choisir de fournir diverses sorties pour des utilisations avancées (comme des activations de couches intermédiaires) en plus des sorties principales. Les consommateurs de modules doivent gérer les sorties supplémentaires avec élégance.

Essayer des modules alternatifs

Chaque fois qu'il existe plusieurs modules pour la même tâche, TensorFlow Hub encourage à les équiper de signatures (interfaces) compatibles de sorte qu'en essayer différentes soit aussi simple que de faire varier la poignée du module comme un hyperparamètre à valeur de chaîne.

À cette fin, nous maintenons une collection de signatures communes recommandées pour les tâches courantes.

Création d'un nouveau module

Remarque sur la compatibilité

Le format TF1 Hub est adapté à TensorFlow 1. Il n'est que partiellement pris en charge par TF Hub dans TensorFlow 2. Veuillez plutôt envisager de publier dans le nouveau format TF2 SavedModel .

Le format TF1 Hub est similaire au format SavedModel de TensorFlow 1 au niveau syntaxique (mêmes noms de fichiers et messages de protocole) mais sémantiquement différent pour permettre la réutilisation, la composition et le recyclage des modules (par exemple, stockage différent des initialiseurs de ressources, balisage différent). conventions pour les métagraphes). Le moyen le plus simple de les distinguer sur le disque est la présence ou l'absence du fichier tfhub_module.pb .

Approche générale

Pour définir un nouveau module, un éditeur appelle hub.create_module_spec() avec une fonction module_fn . Cette fonction construit un graphique représentant la structure interne du module, en utilisant tf.placeholder() pour les entrées à fournir par l'appelant. Ensuite, il définit les signatures en appelant hub.add_signature(name, inputs, outputs) une ou plusieurs fois.

Par exemple:

def module_fn():
  inputs = tf.placeholder(dtype=tf.float32, shape=[None, 50])
  layer1 = tf.layers.dense(inputs, 200)
  layer2 = tf.layers.dense(layer1, 100)
  outputs = dict(default=layer2, hidden_activations=layer1)
  # Add default signature.
  hub.add_signature(inputs=inputs, outputs=outputs)

...
spec = hub.create_module_spec(module_fn)

Le résultat de hub.create_module_spec() peut être utilisé, au lieu d'un chemin, pour instancier un objet module dans un graphe TensorFlow particulier. Dans ce cas, il n'y a pas de point de contrôle et l'instance de module utilisera à la place les initialiseurs de variables.

Toute instance de module peut être sérialisée sur disque via sa méthode export(path, session) . L'exportation d'un module sérialise sa définition ainsi que l'état actuel de ses variables en session dans le chemin transmis. Cela peut être utilisé lors de l'exportation d'un module pour la première fois, ainsi que lors de l'exportation d'un module optimisé.

Pour des raisons de compatibilité avec les estimateurs TensorFlow, hub.LatestModuleExporter exporte les modules à partir du dernier point de contrôle, tout comme tf.estimator.LatestExporter exporte l'intégralité du modèle à partir du dernier point de contrôle.

Les éditeurs de modules doivent mettre en œuvre une signature commune lorsque cela est possible, afin que les consommateurs puissent facilement échanger des modules et trouver celui qui convient le mieux à leur problème.

Exemple réel

Jetez un œil à notre exportateur de modules d'intégration de texte pour un exemple concret de la façon de créer un module à partir d'un format d'intégration de texte courant.

Réglage fin

L'entraînement des variables d'un module importé avec celles du modèle qui l'entoure est appelé réglage fin . Un réglage fin peut aboutir à une meilleure qualité, mais ajoute de nouvelles complications. Nous conseillons aux consommateurs de se pencher sur les réglages fins seulement après avoir exploré des ajustements de qualité plus simples, et seulement si l'éditeur du module le recommande.

Pour les consommateurs

Pour activer le réglage fin, instanciez le module avec hub.Module(..., trainable=True) pour rendre ses variables entraînables et importez REGULARIZATION_LOSSES de TensorFlow. Si le module comporte plusieurs variantes de graphiques, assurez-vous de choisir celle qui convient à la formation. Habituellement, c'est celui avec les balises {"train"} .

Choisissez un régime d'entraînement qui ne gâche pas les poids pré-entraînés, par exemple un taux d'apprentissage inférieur à celui d'un entraînement à partir de zéro.

Pour les éditeurs

Afin de faciliter le réglage pour les consommateurs, veuillez garder à l'esprit les points suivants :

  • Le réglage fin nécessite une régularisation. Votre module est exporté avec la collection REGULARIZATION_LOSSES , qui place votre choix de tf.layers.dense(..., kernel_regularizer=...) etc. dans ce que le consommateur obtient de tf.losses.get_regularization_losses() . Préférez cette manière de définir les pertes de régularisation L1/L2.

  • Dans le modèle d'éditeur, évitez de définir la régularisation L1/L2 via les paramètres l1_ et l2_regularization_strength de tf.train.FtrlOptimizer , tf.train.ProximalGradientDescentOptimizer et d'autres optimiseurs proximaux. Ceux-ci ne sont pas exportés avec le module, et la définition globale des forces de régularisation peut ne pas être appropriée pour le consommateur. À l'exception de la régularisation L1 dans les modèles larges (c'est-à-dire linéaires clairsemés) ou larges et profonds, il devrait être possible d'utiliser des pertes de régularisation individuelles à la place.

  • Si vous utilisez l'abandon, la normalisation par lots ou des techniques de formation similaires, définissez leurs hyperparamètres sur des valeurs qui ont du sens pour de nombreuses utilisations attendues. Le taux d'abandon devra peut-être être ajusté en fonction de la propension au surapprentissage du problème cible. Dans la normalisation par lots, l'élan (c'est-à-dire le coefficient de décroissance) doit être suffisamment faible pour permettre un réglage précis avec de petits ensembles de données et/ou de grands lots. Pour les consommateurs avancés, envisagez d’ajouter une signature qui expose le contrôle des hyperparamètres critiques.