Compatibilité des versions TensorFlow

Ce document s'adresse aux utilisateurs qui ont besoin d'une compatibilité descendante entre différentes versions de TensorFlow (que ce soit pour le code ou les données) et aux développeurs qui souhaitent modifier TensorFlow tout en préservant la compatibilité.

Versionnement sémantique 2.0

TensorFlow suit Semantic Versioning 2.0 ( semver ) pour son API publique. Chaque version de TensorFlow a la forme MAJOR.MINOR.PATCH . Par exemple, la version 1.2.3 de TensorFlow a la version MAJOR 1, la version MINOR 2 et la version PATCH 3. Les modifications apportées à chaque numéro ont la signification suivante :

  • MAJEUR : modifications potentiellement incompatibles avec les versions antérieures. Le code et les données qui fonctionnaient avec une version majeure précédente ne fonctionneront pas nécessairement avec la nouvelle version. Cependant, dans certains cas, les graphiques et points de contrôle TensorFlow existants peuvent être migrés vers la version la plus récente ; voir Compatibilité des graphiques et des points de contrôle pour plus de détails sur la compatibilité des données.

  • MINEUR : Fonctionnalités rétrocompatibles, améliorations de vitesse, etc. Le code et les données qui fonctionnaient avec une version mineure précédente et qui dépendent uniquement de l'API publique non expérimentale continueront de fonctionner sans changement. Pour plus de détails sur ce qui constitue ou non l'API publique, consultez Ce qui est couvert .

  • PATCH : Corrections de bugs rétrocompatibles.

Par exemple, la version 1.0.0 a introduit des modifications rétrocompatibles par rapport à la version 0.12.1. Cependant, la version 1.1.1 était rétrocompatible avec la version 1.0.0.

Ce qui est couvert

Seules les API publiques de TensorFlow sont rétrocompatibles entre les versions mineures et les correctifs. Les API publiques comprennent

  • Toutes les fonctions et classes Python documentées dans le module tensorflow et ses sous-modules, à l'exception de

    • Symboles privés : toute fonction, classe, etc., dont le nom commence par _
    • Symboles expérimentaux et tf.contrib , voir ci-dessous pour plus de détails.

    Notez que le code dans les répertoires examples/ et tools/ n'est pas accessible via le module tensorflow Python et n'est donc pas couvert par la garantie de compatibilité.

    Si un symbole est disponible via le module tensorflow Python ou ses sous-modules, mais n'est pas documenté, il n'est pas considéré comme faisant partie de l'API publique.

  • L'API de compatibilité (en Python, le module tf.compat ). Dans les versions majeures, nous pouvons publier des utilitaires et des points de terminaison supplémentaires pour aider les utilisateurs dans la transition vers une nouvelle version majeure. Ces symboles API sont obsolètes et non pris en charge (c'est-à-dire que nous n'ajouterons aucune fonctionnalité et nous ne corrigerons pas les bogues autres que la correction des vulnérabilités), mais ils relèvent de nos garanties de compatibilité.

  • L'API TensorFlow C :

  • Les fichiers tampons de protocole suivants :

Numéro de version distinct pour TensorFlow Lite

Actuellement, TensorFlow Lite est distribué dans le cadre de TensorFlow. Cependant, nous nous réservons le droit de publier ultérieurement des modifications aux API TensorFlow Lite selon un calendrier différent de celui des autres API TensorFlow, ou même de déplacer TensorFlow Lite vers une distribution source distincte et/ou un référentiel source distinct de TensorFlow.

Pour cette raison, nous utilisons un numéro de version différent pour TensorFlow Lite ( TFLITE_VERSION_STRING dans tensorflow/lite/version.h et TfLiteVersion() dans tensorflow/lite/c/c_api.h ) que pour TensorFlow ( TF_VERSION_STRING dans tensorflow/core/public/version.h et TF_Version() dans tensorflow/c/c_api.h ). Actuellement, ces deux numéros de version ont la même valeur. Mais à l’avenir, ils pourraient diverger ; par exemple, nous pouvons incrémenter le numéro de version majeure de TensorFlow Lite sans incrémenter le numéro de version majeure de TensorFlow, ou vice versa.

La surface de l'API couverte par le numéro de version de TensorFlow Lite est composée des API publiques suivantes :

Les symboles expérimentaux ne sont pas couverts ; voir ci-dessous pour plus de détails.

Numéro de version distinct pour les API d'extension TensorFlow Lite

TensorFlow Lite fournit des API C pour étendre l'interpréteur TensorFlow Lite avec des « opérations personnalisées », qui fournissent des opérations définies par l'utilisateur dans un graphique, ou des « délégués », qui permettent de déléguer le calcul d'un graphique (ou d'un sous-ensemble d'un graphique) à un back-end personnalisé. Ces API, que nous appelons collectivement « API d'extension TensorFlow Lite », nécessitent des dépendances plus intimes sur certains détails de l'implémentation de TensorFlow Lite.

Nous nous réservons le droit d'apporter à l'avenir des modifications à ces API, y compris potentiellement des modifications non rétrocompatibles, selon un calendrier différent de celui des autres API TensorFlow Lite. Nous utilisons donc un numéro de version différent pour les API d'extension TensorFlow Lite que les numéros de version pour TensorFlow Lite ou TensorFlow (qui ont été décrits dans la section précédente). Nous introduisons de nouvelles API dans TensorFlow Lite version 2.15 pour obtenir la version des API d'extension TensorFlow Lite ( TFLITE_EXTENSION_APIS_VERSION_STRING dans tensorflow/lite/version.h et TfLiteExtensionApisVersion() dans tensorflow/lite/c/c_api.h ). Le numéro de version des API d'extension TensorFlow Lite est actuellement le même que celui de TensorFlow et TensorFlow Lite. Mais à l’avenir, ils pourraient diverger ; par exemple, nous pouvons incrémenter le numéro de version principale des API de l'extension TensorFlow Lite sans incrémenter le numéro de version principale de TensorFlow Lite, ou vice versa.

La surface de l'API couverte par le numéro de version des API de l'extension TensorFlow Lite est composée des API publiques suivantes :

Encore une fois, les symboles expérimentaux ne sont pas couverts ; voir ci-dessous pour plus de détails.

Ce qui n'est pas couvert

Certaines parties de TensorFlow peuvent changer de manière rétrocompatible à tout moment. Ceux-ci inclus:

  • API expérimentales : Pour faciliter le développement, nous exemptons certains symboles API clairement marqués comme expérimentaux des garanties de compatibilité. En particulier, les éléments suivants ne sont couverts par aucune garantie de compatibilité :

    • n'importe quel symbole dans le module tf.contrib ou ses sous-modules ;
    • tout symbole (module, fonction, argument, propriété, classe, constante, type, package, etc.) dont le nom contient experimental ou Experimental ; ou
    • tout symbole dont le nom complet inclut un module, une classe ou un package lui-même expérimental. Cela inclut les champs et les sous-messages de tout tampon de protocole appelé experimental .
  • Autres langages : API TensorFlow dans des langages autres que Python et C, tels que :

    et les API TensorFlow Lite dans des langages autres que Java/Kotlin, C, Objective-C et Swift, en particulier

  • Détails des opérations composites : de nombreuses fonctions publiques en Python s'étendent à plusieurs opérations primitives dans le graphique, et ces détails feront partie de tous les graphiques enregistrés sur le disque en tant que GraphDef s. Ces détails peuvent changer pour les versions mineures. En particulier, les tests de régression qui vérifient la correspondance exacte entre les graphiques sont susceptibles d'être interrompus dans les versions mineures, même si le comportement du graphique devrait rester inchangé et que les points de contrôle existants fonctionneront toujours.

  • Détails numériques à virgule flottante : les valeurs à virgule flottante spécifiques calculées par les opérations peuvent changer à tout moment. Les utilisateurs doivent se fier uniquement à la précision approximative et à la stabilité numérique, et non aux bits spécifiques calculés. Les modifications apportées aux formules numériques dans les versions mineures et les correctifs devraient entraîner une précision comparable ou améliorée, avec la mise en garde que dans l'apprentissage automatique, une précision améliorée de formules spécifiques peut entraîner une diminution de la précision de l'ensemble du système.

  • Nombres aléatoires : les nombres aléatoires spécifiques calculés peuvent changer à tout moment. Les utilisateurs doivent se fier uniquement à des distributions et à une force statistique approximativement correctes, et non aux bits spécifiques calculés. Consultez le guide de génération de nombres aléatoires pour plus de détails.

  • Asymétrie de version dans Tensorflow distribué : l'exécution de deux versions différentes de TensorFlow dans un seul cluster n'est pas prise en charge. Il n'y a aucune garantie quant à la compatibilité ascendante du protocole filaire.

  • Bogues : Nous nous réservons le droit d'apporter des modifications de comportement rétrocompatibles (mais pas à l'API) si l'implémentation actuelle est clairement rompue, c'est-à-dire si elle contredit la documentation ou si un comportement prévu bien connu et bien défini n'est pas correctement implémenté en raison de à un bug. Par exemple, si un optimiseur prétend implémenter un algorithme d'optimisation bien connu mais ne correspond pas à cet algorithme en raison d'un bug, nous corrigerons l'optimiseur. Notre correctif peut casser le code en s'appuyant sur un mauvais comportement de convergence. Nous noterons ces changements dans les notes de version.

  • API inutilisée : nous nous réservons le droit d'apporter des modifications rétrocompatibles aux API pour lesquelles nous ne trouvons aucune utilisation documentée (en effectuant un audit de l'utilisation de TensorFlow via la recherche GitHub). Avant d'apporter de telles modifications, nous annoncerons notre intention d'effectuer la modification sur la liste de diffusionnounce@ , en fournissant des instructions sur la façon de résoudre tout problème (le cas échéant), et attendrons deux semaines pour donner à notre communauté la possibilité de partager ses commentaires. .

  • Comportement d'erreur : nous pouvons remplacer les erreurs par un comportement sans erreur. Par exemple, nous pouvons modifier une fonction pour calculer un résultat au lieu de générer une erreur, même si cette erreur est documentée. Nous nous réservons également le droit de modifier le texte des messages d'erreur. De plus, le type d'une erreur peut changer à moins que le type d'exception pour une condition d'erreur spécifique ne soit spécifié dans la documentation.

Compatibilité des SavedModels, des graphiques et des points de contrôle

SavedModel est le format de sérialisation préféré à utiliser dans les programmes TensorFlow. Les SavedModels contiennent deux parties : un ou plusieurs graphiques codés sous forme GraphDefs et un point de contrôle. Les graphiques décrivent le flux de données des opérations à exécuter et les points de contrôle contiennent les valeurs tensorielles enregistrées des variables dans un graphique.

De nombreux utilisateurs de TensorFlow créent des SavedModels, puis les chargent et les exécutent avec une version ultérieure de TensorFlow. Conformément à semver , les SavedModels écrits avec une version de TensorFlow peuvent être chargés et évalués avec une version ultérieure de TensorFlow avec la même version majeure.

Nous offrons des garanties supplémentaires pour les SavedModels pris en charge . Nous appelons un SavedModel qui a été créé en utilisant uniquement des API non obsolètes, non expérimentales et non compatibles dans la version majeure N de TensorFlow un SavedModel pris en charge dans la version N . Tout SavedModel pris en charge dans la version majeure N de TensorFlow peut être chargé et exécuté avec la version majeure de TensorFlow N+1 . Cependant, les fonctionnalités requises pour construire ou modifier un tel modèle peuvent ne plus être disponibles, cette garantie ne s'applique donc qu'au SavedModel non modifié.

Nous nous efforcerons de préserver la compatibilité ascendante le plus longtemps possible, afin que les fichiers sérialisés soient utilisables sur de longues périodes.

Compatibilité GraphDef

Les graphiques sont sérialisés via le tampon de protocole GraphDef . Pour faciliter les modifications rétrocompatibles des graphiques, chaque GraphDef possède un numéro de version distinct de la version TensorFlow. Par exemple, la version 17 GraphDef a déconseillé l'opération inv au profit de reciprocal . La sémantique est :

  • Chaque version de TensorFlow prend en charge un intervalle de versions GraphDef . Cet intervalle sera constant dans toutes les versions de correctifs et n’augmentera que dans les versions mineures. La suppression de la prise en charge d'une version GraphDef ne se produira que pour une version majeure de TensorFlow (et uniquement alignée sur la prise en charge de la version garantie pour SavedModels).

  • Les graphiques nouvellement créés se voient attribuer le dernier numéro de version GraphDef .

  • Si une version donnée de TensorFlow prend en charge la version GraphDef d'un graphique, elle se chargera et sera évaluée avec le même comportement que la version de TensorFlow utilisée pour le générer (à l'exception des détails numériques à virgule flottante et des nombres aléatoires comme indiqué ci-dessus), quelle que soit la principale version de TensorFlow. En particulier, un GraphDef compatible avec un fichier de point de contrôle dans une version de TensorFlow (comme c'est le cas dans un SavedModel) restera compatible avec ce point de contrôle dans les versions ultérieures, tant que GraphDef est pris en charge.

    Notez que cela s'applique uniquement aux graphiques sérialisés dans GraphDefs (et SavedModels) : le code qui lit un point de contrôle peut ne pas être en mesure de lire les points de contrôle générés par le même code exécutant une version différente de TensorFlow.

  • Si la limite supérieure GraphDef est augmentée à X dans une version (mineure), il faudra au moins six mois avant que la limite inférieure ne soit augmentée à X. Par exemple (nous utilisons ici des numéros de version hypothétiques) :

    • TensorFlow 1.2 peut prendre en charge les versions 4 à 7 GraphDef .
    • TensorFlow 1.3 pourrait ajouter la version 8 GraphDef et prendre en charge les versions 4 à 8.
    • Au moins six mois plus tard, TensorFlow 2.0.0 pourrait abandonner la prise en charge des versions 4 à 7, ne laissant que la version 8.

    Notez que, étant donné que les versions majeures de TensorFlow sont généralement publiées à plus de 6 mois d'intervalle, les garanties pour les SavedModels pris en charge détaillées ci-dessus sont bien plus solides que la garantie de 6 mois pour GraphDefs.

Enfin, lorsque la prise en charge d'une version GraphDef sera abandonnée, nous tenterons de fournir des outils pour convertir automatiquement les graphiques vers une version plus récente GraphDef prise en charge.

Compatibilité des graphiques et des points de contrôle lors de l'extension de TensorFlow

Cette section n'est pertinente que lorsque vous apportez des modifications incompatibles au format GraphDef , par exemple lors de l'ajout d'opérations, de la suppression d'opérations ou de la modification des fonctionnalités d'opérations existantes. La section précédente devrait suffire à la plupart des utilisateurs.

Compatibilité ascendante et partielle

Notre système de gestion des versions comporte trois exigences :

  • Compatibilité descendante pour prendre en charge le chargement de graphiques et de points de contrôle créés avec les anciennes versions de TensorFlow.
  • Compatibilité ascendante pour prendre en charge les scénarios dans lesquels le producteur d'un graphique ou d'un point de contrôle est mis à niveau vers une version plus récente de TensorFlow avant le consommateur.
  • Activez TensorFlow évolutif de manière incompatible. Par exemple, supprimer des opérations, ajouter des attributs et supprimer des attributs.

Notez que même si le mécanisme de version GraphDef est distinct de la version TensorFlow, les modifications rétrocompatibles apportées au format GraphDef sont toujours limitées par la gestion des versions sémantiques. Cela signifie que la fonctionnalité ne peut être supprimée ou modifiée qu'entre les versions MAJOR de TensorFlow (telles que 1.7 à 2.0 ). De plus, la compatibilité ascendante est appliquée dans les versions de correctifs ( 1.x.1 à 1.x.2 par exemple).

Pour obtenir une compatibilité ascendante et descendante et savoir quand appliquer les modifications de format, les graphiques et les points de contrôle disposent de métadonnées qui décrivent quand ils ont été produits. Les sections ci-dessous détaillent l'implémentation de TensorFlow et les directives pour l'évolution des versions GraphDef .

Schémas de versions de données indépendants

Il existe différentes versions de données pour les graphiques et les points de contrôle. Les deux formats de données évoluent à des rythmes différents l'un de l'autre et également à des rythmes différents de TensorFlow. Les deux systèmes de gestion de versions sont définis dans core/public/version.h . Chaque fois qu'une nouvelle version est ajoutée, une note est ajoutée à l'en-tête détaillant ce qui a changé et la date.

Données, producteurs et consommateurs

Nous distinguons les types suivants d'informations sur la version des données :

  • producteurs : binaires qui produisent des données. Les producteurs ont une version ( producer ) et une version consommateur minimale avec laquelle ils sont compatibles ( min_consumer ).
  • consumer : binaires qui consomment des données. Les consommateurs ont une version ( consumer ) et une version minimale du producteur avec lesquelles ils sont compatibles ( min_producer ).

Chaque élément de données versionnées possède un champ VersionDef versions qui enregistre le producer qui a créé les données, le min_consumer avec lequel elles sont compatibles et une liste des versions bad_consumers qui ne sont pas autorisées.

Par défaut, lorsqu'un producteur crée des données, les données héritent des versions producer et min_consumer du producteur. bad_consumers peut être défini si des versions grand public spécifiques sont connues pour contenir des bogues et doivent être évitées. Un consommateur peut accepter une donnée si les conditions suivantes sont toutes vraies :

  • consumer >= min_consumer des données
  • producer de données >= min_producer du consommateur
  • consumer n'est pas dans les données bad_consumers

Étant donné que les producteurs et les consommateurs proviennent de la même base de code TensorFlow, core/public/version.h contient une version de données principale qui est traitée comme producer ou consumer en fonction du contexte et à la fois min_consumer et min_producer (requis respectivement par les producteurs et les consommateurs) . Spécifiquement,

  • Pour les versions GraphDef , nous avons TF_GRAPH_DEF_VERSION , TF_GRAPH_DEF_VERSION_MIN_CONSUMER et TF_GRAPH_DEF_VERSION_MIN_PRODUCER .
  • Pour les versions de point de contrôle, nous avons TF_CHECKPOINT_VERSION , TF_CHECKPOINT_VERSION_MIN_CONSUMER et TF_CHECKPOINT_VERSION_MIN_PRODUCER .

Ajouter un nouvel attribut par défaut à une opération existante

Suivre les instructions ci-dessous vous permet d'obtenir une compatibilité ascendante uniquement si l'ensemble des opérations n'a pas changé :

  1. Si la compatibilité ascendante est souhaitée, définissez strip_default_attrs sur True lors de l'exportation du modèle à l'aide des méthodes tf.saved_model.SavedModelBuilder.add_meta_graph_and_variables et tf.saved_model.SavedModelBuilder.add_meta_graph de la classe SavedModelBuilder ou tf.estimator.Estimator.export_saved_model .
  2. Cela supprime les attributs valorisés par défaut au moment de la production/exportation des modèles. Cela garantit que le tf.MetaGraphDef exporté ne contient pas le nouvel attribut op lorsque la valeur par défaut est utilisée.
  3. Ce contrôle pourrait permettre aux consommateurs obsolètes (par exemple, servir des binaires en retard par rapport aux binaires d'entraînement) de continuer à charger les modèles et d'éviter les interruptions dans la diffusion des modèles.

Versions GraphDef évolutives

Cette section explique comment utiliser ce mécanisme de gestion des versions pour apporter différents types de modifications au format GraphDef .

Ajouter une opération

Ajoutez la nouvelle opération aux consommateurs et aux producteurs en même temps, et ne modifiez aucune version GraphDef . Ce type de changement est automatiquement rétrocompatible et n'a pas d'impact sur le plan de compatibilité ascendante puisque les scripts producteurs existants n'utiliseront pas soudainement la nouvelle fonctionnalité.

Ajoutez une opération et changez les wrappers Python existants pour l'utiliser

  1. Implémentez une nouvelle fonctionnalité grand public et incrémentez la version GraphDef .
  2. S'il est possible de faire en sorte que les wrappers utilisent la nouvelle fonctionnalité uniquement dans des cas qui ne fonctionnaient pas auparavant, les wrappers peuvent être mis à jour maintenant.
  3. Modifiez les wrappers Python pour utiliser la nouvelle fonctionnalité. N'incrémentez pas min_consumer , car les modèles qui n'utilisent pas cette opération ne devraient pas se briser.

Supprimer ou restreindre la fonctionnalité d'une opération

  1. Corrigez tous les scripts du producteur (pas TensorFlow lui-même) pour ne pas utiliser l'opération ou la fonctionnalité interdite.
  2. Incrémentez la version GraphDef et implémentez une nouvelle fonctionnalité grand public qui interdit l'opération ou la fonctionnalité supprimée pour GraphDefs dans la nouvelle version et au-dessus. Si possible, faites en sorte que TensorFlow arrête de produire GraphDefs avec la fonctionnalité interdite. Pour ce faire, ajoutez le REGISTER_OP(...).Deprecated(deprecated_at_version, message) .
  3. Attendez une version majeure à des fins de compatibilité ascendante.
  4. Augmentez min_producer à la version GraphDef de (2) et supprimez complètement la fonctionnalité.

Modifier la fonctionnalité d'une opération

  1. Ajoutez une nouvelle opération similaire nommée SomethingV2 ou similaire et suivez le processus d'ajout et de changement des wrappers Python existants pour l'utiliser. Pour garantir la compatibilité ascendante, utilisez les vérifications suggérées dans compat.py lors de la modification des wrappers Python.
  2. Supprimez l'ancienne opération (ne peut avoir lieu qu'avec un changement de version majeur en raison de la compatibilité ascendante).
  3. Augmentez min_consumer pour exclure les consommateurs avec l'ancienne opération, ajoutez à nouveau l'ancienne opération comme alias pour SomethingV2 et suivez le processus pour changer les wrappers Python existants pour l'utiliser.
  4. Suivez le processus pour supprimer SomethingV2 .

Interdire une seule version grand public dangereuse

  1. Augmentez la version GraphDef et ajoutez la mauvaise version à bad_consumers pour tous les nouveaux GraphDef. Si possible, ajoutez à bad_consumers uniquement pour les GraphDefs qui contiennent une certaine opération ou similaire.
  2. Si les consommateurs existants ont la mauvaise version, supprimez-les dès que possible.