Modèles enregistrés réutilisables

introduction

TensorFlow Hub héberge entre autres SavedModels pour TensorFlow 2. Ils peuvent être rechargés dans un programme Python avec obj = hub.load(url) [en savoir plus ]. L' obj renvoyé est le résultat de tf.saved_model.load() (voir le guide SavedModel de TensorFlow). Cet objet peut avoir des attributs arbitraires qui sont tf.functions, tf.Variables (initialisés à partir de leurs valeurs pré-entraînées), d'autres ressources et, récursivement, d'autres objets de ce type.

Cette page décrit une interface pour être mis en œuvre par le chargé obj afin d'être réutilisés dans un programme Python tensorflow. Les SavedModels conformes à cette interface sont appelés des SavedModels réutilisables .

Réutiliser signifie construire un modèle plus grand autour d' obj , y compris la possibilité de le peaufiner. Des moyens de réglage fin en outre la formation des poids dans la charge obj dans le cadre du modèle environnant. La fonction de perte et l'optimiseur sont déterminés par le modèle environnant; obj définit uniquement le mappage des activations d'entrée sur les activations de sortie (le "passage en avant"), y compris éventuellement des techniques telles que l'abandon ou la normalisation par lots.

L'équipe TensorFlow Hub recommande d'implémenter l'interface SavedModel réutilisable dans tous les SavedModels destinés à être réutilisés dans le sens ci-dessus. De nombreux utilitaires de la bibliothèque tensorflow_hub , notamment hub.KerasLayer , nécessitent SavedModels pour l'implémenter.

Relation avec SignatureDefs

Cette interface en termes de tf.functions et d'autres fonctionnalités TF2 est distincte des signatures de SavedModel, qui sont disponibles depuis TF1 et continuent d'être utilisées dans TF2 pour l'inférence (comme le déploiement de SavedModels sur TF Serving ou TF Lite). Les signatures pour l'inférence ne sont pas assez expressives pour prendre en charge un réglage fin, et tf.function fournit une API Python plus naturelle et expressive pour le modèle réutilisé.

Relation avec les bibliothèques de création de modèles

Un SavedModel réutilisable utilise uniquement les primitives TensorFlow 2, indépendamment de toute bibliothèque de création de modèle particulière telle que Keras ou Sonnet. Cela facilite la réutilisation dans les bibliothèques de création de modèles, sans aucune dépendance vis-à-vis du code de création de modèles d'origine.

Une certaine quantité d'adaptation sera nécessaire pour charger les modèles enregistrés réutilisables ou les enregistrer à partir d'une bibliothèque de construction de modèles donnée. Pour Keras, hub.KerasLayer fournit le chargement, et l'enregistrement intégré de Keras au format SavedModel a été repensé pour TF2 dans le but de fournir un sur-ensemble de cette interface (voir le RFC de mai 2019).

Relation avec les "API Common SavedModel" spécifiques aux tâches

La définition d'interface sur cette page autorise n'importe quel nombre et type d'entrées et de sorties. Les API Common SavedModel pour TF Hub affinent cette interface générale avec des conventions d'utilisation pour des tâches spécifiques afin de rendre les modèles facilement interchangeables.

Définition d'interface

Les attributs

Un SavedModel réutilisable est un SavedModel TensorFlow 2 tel que obj = tf.saved_model.load(...) renvoie un objet qui a les attributs suivants

  • __call__ . Obligatoire. Une tf.function implémentant le calcul du modèle (le "forward pass") soumis à la spécification ci-dessous.

  • variables : Une liste d'objets tf.Variable, listant toutes les variables utilisées par toute invocation possible de __call__ , y compris celles qui __call__ et non.

    Cette liste peut être omise si elle est vide.

  • trainable_variables : Une liste d'objets tf.Variable telle que v.trainable est vraie pour tous les éléments. Ces variables doivent être un sous-ensemble de variables . Ce sont les variables à entraîner lors du réglage fin de l'objet. Le créateur de SavedModel peut choisir d'omettre ici certaines variables qui étaient à l'origine entraînables pour indiquer qu'elles ne devraient pas être modifiées lors de la mise au point.

    Cette liste peut être omise si elle est vide, en particulier si le SavedModel ne prend pas en charge le réglage fin.

  • regularization_losses : Une liste de tf.functions, chacune prenant zéro entrée et renvoyant un seul tenseur scalaire flottant. Pour un réglage précis, il est conseillé à l'utilisateur de SavedModel de les inclure en tant que conditions de régularisation supplémentaires dans la perte (dans le cas le plus simple sans mise à l'échelle supplémentaire). En règle générale, ils sont utilisés pour représenter les régularisateurs de poids. (Faute d'entrées, ces tf.functions ne peuvent pas exprimer des régulariseurs d'activité.)

    Cette liste peut être omise si elle est vide, en particulier si le SavedModel ne prend pas en charge le réglage fin ou ne souhaite pas prescrire la régularisation du poids.

La fonction __call__

Un SavedModel restauré obj a un obj.__call__ attribut qui est un tf.function restauré et permet obj d'être appelé comme suit.

Synopsis (pseudo-code):

outputs = obj(inputs, trainable=..., **kwargs)

Arguments

Les arguments sont les suivants.

  • Il existe un argument positionnel requis avec un lot d'activations d'entrée du SavedModel. Son type est l'un des

    • un seul Tensor pour une seule entrée,
    • une liste de Tensors pour une séquence ordonnée d'entrées sans nom,
    • un dict de Tensors indexé par un ensemble particulier de noms d'entrée.

    (Les révisions futures de cette interface peuvent permettre des nids plus généraux.) Le créateur de SavedModel en choisit une et les formes et dtypes du tenseur. Lorsque cela est utile, certaines dimensions de la forme doivent être indéfinies (notamment la taille du lot).

  • Il peut y avoir une training argument de mot-clé facultative qui accepte un booléen Python, True ou False . La valeur par défaut est False . Si le modèle prend en charge le réglage fin, et si son calcul diffère entre les deux (par exemple, comme dans le décrochage et la normalisation par lots), cette distinction est implémentée avec cet argument. Sinon, cet argument peut être absent.

    Il n'est pas nécessaire que __call__ accepte un argument d' training valeur Tensor. Il incombe à l'appelant d'utiliser tf.cond() si nécessaire pour se tf.cond() entre eux.

  • Le créateur de SavedModel peut choisir d'accepter plus de kwargs optionnels de noms particuliers.

    • Pour les arguments à valeur Tensor, le créateur SavedModel définit leurs dtypes et formes autorisés. tf.function accepte une valeur par défaut Python sur un argument tracé avec une entrée tf.TensorSpec. De tels arguments peuvent être utilisés pour permettre la personnalisation des hyperparamètres numériques impliqués dans __call__ (par exemple, le taux d'abandon).

    • Pour les arguments à valeur Python, le créateur SavedModel définit leurs valeurs autorisées. De tels arguments peuvent être utilisés comme indicateurs pour faire des choix discrets dans la fonction tracée (mais attention à l'explosion combinatoire des traces).

La fonction __call__ restaurée doit fournir des traces pour toutes les combinaisons d'arguments autorisées. Le basculement de l' training entre True et False ne doit pas changer la permission des arguments.

Résultat

Les outputs de l'appel d' obj peuvent être

  • un seul Tensor pour une seule sortie,
  • une liste de Tensors pour une séquence ordonnée de sorties sans nom,
  • un dict de Tensors indexé par un ensemble particulier de noms de sortie.

(Les futures révisions de cette interface peuvent permettre des nids plus généraux.) Le type de retour peut varier en fonction des kwargs valorisés par Python. Cela permet aux indicateurs de produire des sorties supplémentaires. Le créateur SavedModel définit les dtypes et les formes de sortie et leur dépendance vis-à-vis des entrées.

Appelables nommés

Un SavedModel réutilisable peut fournir plusieurs éléments de modèle de la manière décrite ci-dessus en les plaçant dans des sous-objets nommés, par exemple, obj.foo , obj.bar et ainsi de suite. Chaque sous-objet fournit une méthode __call__ et des attributs de support sur les variables, etc. spécifiques à cette pièce de modèle. Pour l'exemple ci-dessus, il y aurait obj.foo.__call__ , obj.foo.variables et ainsi de suite.

Notez que cette interface ne couvre pas l'approche consistant à ajouter une fonction tf.fonction nue directement en tant que tf.foo .

Les utilisateurs de Reusable SavedModels ne doivent gérer qu'un seul niveau d'imbrication ( obj.bar mais pas obj.bar.baz ). (Les révisions futures de cette interface peuvent permettre une imbrication plus profonde et peuvent renoncer à l'exigence selon laquelle l'objet de niveau supérieur peut être appelé lui-même.)

Remarques de clôture

Relation avec les API en cours

Ce document décrit une interface d'une classe Python qui se compose de primitives telles que tf.function et tf.Variable qui survivent à un aller-retour via la sérialisation via tf.saved_model.save() et tf.saved_model.load() . Cependant, l'interface était déjà présente sur l'objet d'origine qui a été passé à tf.saved_model.save() . L'adaptation à cette interface permet l'échange d'éléments de modèle entre les API de création de modèles au sein d'un seul programme TensorFlow.