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 des tf.functions, des tf.Variables (initialisés à partir de leurs valeurs pré-entraînées), d'autres ressources et, de manière récursive, d'autres objets de ce type.

Cette page décrit une interface à implémenter par l' obj chargé afin d'être réutilisé dans un programme TensorFlow Python. Les SavedModels conformes à cette interface sont appelés Réutilisables SavedModels .

Réutiliser signifie construire un modèle plus grand autour obj , y compris la possibilité de l'affiner. Le réglage fin signifie un entraînement plus approfondi des poids dans l' obj chargé 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 sortie (le "passe avant"), incluant éventuellement des techniques telles que l'abandon ou la normalisation par lots.

L'équipe TensorFlow Hub recommande d'implémenter l'interface réutilisable SavedModel 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 de 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 suffisamment expressives pour prendre en charge un réglage fin, et tf.function fournit une API Python plus naturelle et plus expressive pour le modèle réutilisé.

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

Un SavedModel réutilisable utilise uniquement des primitives TensorFlow 2, indépendamment de toute bibliothèque de création de modèles particulière comme Keras ou Sonnet. Cela facilite la réutilisation dans les bibliothèques de création de modèles, sans dépendances sur le code de création de modèles d'origine.

Un certain degré d'adaptation sera nécessaire pour charger des modèles sauvegardés réutilisables ou les enregistrer à partir d'une bibliothèque de création de modèles donnée. Pour Keras, hub.KerasLayer assure le chargement, et la sauvegarde intégrée de Keras au format SavedModel a été repensée pour TF2 dans le but de fournir un surensemble de cette interface (voir la RFC de mai 2019).

Relation avec les "API communes SavedModel" spécifiques à la tâche

La définition de l'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 de l'interface

Attributs

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

  • __call__ . Requis. Une tf.function implémentant le calcul du modèle (la « passe directe ») soumise à la spécification ci-dessous.

  • variables : Une liste d'objets tf.Variable, répertoriant toutes les variables utilisées par toute invocation possible de __call__ , y compris celles pouvant être entraînées et non entraînées.

    Cette liste peut être omise si elle est vide.

  • trainable_variables : Une liste d'objets tf.Variable telle que v.trainable soit vrai 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 pouvaient à l'origine être entraînées pour indiquer qu'elles ne doivent pas être modifiées lors du réglage fin.

    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 flottant scalaire. Pour un réglage fin, il est conseillé à l'utilisateur de SavedModel de les inclure comme termes de régularisation supplémentaires dans la perte (dans le cas le plus simple, sans mise à l'échelle supplémentaire). Généralement, ceux-ci sont utilisés pour représenter des régularisateurs de poids. (Faute d'entrées, ces tf.functions ne peuvent pas exprimer de régularisateurs 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 une régularisation du poids.

La fonction __call__

Un obj SavedModel restauré a un attribut obj.__call__ qui est une tf.function restaurée et permet d'appeler obj comme suit.

Synopsis (pseudo-code) :

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

Arguments

Les arguments sont les suivants.

  • Il existe un argument positionnel obligatoire 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 saisi par un ensemble particulier de noms d'entrée.

    (Les révisions futures de cette interface pourraient permettre des imbrications plus générales.) Le créateur de SavedModel choisit l'une d'entre elles ainsi que les formes et types de tenseurs. Lorsque cela est utile, certaines dimensions de la forme doivent être indéfinies (notamment la taille du lot).

  • Il peut y avoir une training facultative d'argument de mot-clé 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 l'abandon et la normalisation par lots), cette distinction est implémentée avec cet argument. Sinon, cet argument pourrait être absent.

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

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

    • Pour les arguments à valeur Tensor, le créateur de SavedModel définit leurs types et formes autorisés. tf.function accepte une valeur Python par défaut sur un argument qui est 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 valorisés Python, le créateur de 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. L'inversion training entre True et False ne doit pas modifier la licéité des arguments.

Résultat

Les outputs de l'appel 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 saisi par un ensemble particulier de noms de sortie.

(Les révisions futures de cette interface pourraient permettre des imbrications plus générales.) 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 types et formes de sortie et leur dépendance aux 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 , etc. Chaque sous-objet fournit une méthode __call__ et des attributs de prise en charge concernant 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 simple tf.function directement en tant que tf.foo .

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

Remarques finales

Relation avec les API en cours

Ce document décrit une interface d'une classe Python composée de primitives comme 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 transmis à 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.