Réécrire automatiquement les symboles API TF 1.x et compat.v1

Voir sur TensorFlow.org Exécuter dans Google Colab Voir la source sur GitHub Télécharger le cahier

TensorFlow 2.x inclut de nombreuses modifications d'API par rapport aux API TF 1.x et tf.compat.v1 , telles que la réorganisation des arguments, le changement de nom des symboles et la modification des valeurs par défaut des paramètres. Effectuer manuellement toutes ces modifications serait fastidieux et sujet aux erreurs. Pour rationaliser les modifications et rendre votre transition vers TF 2.x aussi transparente que possible, l'équipe TensorFlow a créé l'utilitaire tf_upgrade_v2 pour faciliter la transition du code hérité vers la nouvelle API.

L'utilisation typique est la suivante :

tf_upgrade_v2 \
  --intree my_project/ \
  --outtree my_project_v2/ \
  --reportfile report.txt

Il accélérera votre processus de mise à niveau en convertissant les scripts Python TensorFlow 1.x existants en TensorFlow 2.x.

Le script de conversion automatise de nombreuses transformations d'API mécaniques, bien que de nombreuses API ne puissent pas être migrées automatiquement. Il n'est pas non plus en mesure de rendre votre code entièrement compatible avec les comportements et les API de TF2. Ce n'est donc qu'une partie de votre parcours migratoire.

Modules de compatibilité

Certains symboles API ne peuvent pas être mis à niveau simplement en utilisant un remplacement de chaîne. Ceux qui ne peuvent pas être automatiquement mis à niveau seront mappés à leurs emplacements dans le module compat.v1 . Ce module remplace les symboles TF 1.x comme tf.foo par la référence équivalente tf.compat.v1.foo . Si vous utilisez déjà des API compat.v1 en important TF via import tensorflow.compat.v1 as tf , le script tf_upgrade_v2 tentera de convertir ces utilisations en API non compatibles dans la mesure du possible. Notez que si certaines API compat.v1 sont compatibles avec les comportements TF2.x, beaucoup ne le sont pas. Nous vous recommandons donc de relire manuellement les remplacements et de les migrer vers de nouvelles API dans l'espace de noms tf.* au lieu de l'espace de noms tf.compat.v1 aussi rapidement que possible.

En raison des obsolescences du module TensorFlow 2.x (par exemple, tf.flags et tf.contrib ), certaines modifications ne peuvent pas être contournées en passant à compat.v1 . La mise à niveau de ce code peut nécessiter l'utilisation d'une bibliothèque supplémentaire (par exemple, absl.flags ) ou le passage à un package dans tensorflow/addons .

Le reste de ce guide montre comment utiliser le script de réécriture de symboles. Bien que le script soit facile à utiliser, il est fortement recommandé de l'utiliser dans le cadre du processus suivant :

  1. Test unitaire : assurez-vous que le code que vous mettez à niveau dispose d'une suite de tests unitaires avec une couverture raisonnable. Il s'agit de code Python, donc le langage ne vous protégera pas de nombreuses classes d'erreurs. Assurez-vous également que toute dépendance que vous avez a déjà été mise à niveau pour être compatible avec TensorFlow 2.x.

  2. Installez TensorFlow 1.15 : mettez à niveau votre TensorFlow vers la dernière version de TensorFlow 1.x, au moins 1.15. Cela inclut l'API finale de TensorFlow 2.0 dans tf.compat.v2 .

  3. Testez avec 1.15 : Assurez-vous que vos tests unitaires réussissent à ce stade. Vous les exécuterez à plusieurs reprises au fur et à mesure de la mise à niveau, il est donc important de commencer par le vert.

  4. Exécutez le script de mise à jour : Exécutez tf_upgrade_v2 sur l'ensemble de votre arbre source, tests inclus. Cela mettra à niveau votre code vers un format où il n'utilise que les symboles disponibles dans TensorFlow 2.0. Les symboles obsolètes seront accessibles avec tf.compat.v1 . Ceux-ci nécessiteront éventuellement une attention manuelle, mais pas immédiatement.

  5. Exécutez les tests convertis avec TensorFlow 1.15 : votre code devrait toujours fonctionner correctement dans TensorFlow 1.15. Exécutez à nouveau vos tests unitaires. Toute erreur dans vos tests ici signifie qu'il y a un bogue dans le script de mise à jour. Veuillez nous le faire savoir .

  6. Vérifiez le rapport de mise à niveau pour les avertissements et les erreurs : le script écrit un fichier de rapport qui explique toutes les conversions que vous devez revérifier ou toute action manuelle que vous devez entreprendre. Par exemple : toutes les instances restantes de contrib nécessiteront une action manuelle pour être supprimées. Veuillez consulter le RFC pour plus d'instructions .

  7. Installez TensorFlow 2.x : à ce stade, vous devriez pouvoir passer en toute sécurité aux fichiers binaires TensorFlow 2.x, même si vous utilisez des comportements hérités.

  8. Test avec v1.disable_v2_behavior : Ré-exécuter vos tests avec un v1.disable_v2_behavior() dans la fonction principale des tests devrait donner les mêmes résultats que l'exécution sous 1.15.

  9. Activer le comportement V2 : maintenant que vos tests fonctionnent avec les binaires TF2, vous pouvez maintenant commencer à migrer votre code pour éviter les tf.estimator et utiliser uniquement les comportements TF2 pris en charge (sans désactiver le comportement TF2). Consultez les guides de migration pour plus de détails.

Utilisation du script de réécriture de tf_upgrade_v2

Installer

Avant de commencer, assurez-vous que TensorFlow 2.x est installé.

import tensorflow as tf

print(tf.__version__)
2.6.0

Clonez le référentiel git tensorflow/models afin d'avoir du code à tester :

git clone --branch r1.13.0 --depth 1 https://github.com/tensorflow/models
Cloning into 'models'...
remote: Enumerating objects: 2927, done.[K
remote: Counting objects: 100% (2927/2927), done.[K
remote: Compressing objects: 100% (2428/2428), done.[K
remote: Total 2927 (delta 504), reused 2113 (delta 424), pack-reused 0[K
Receiving objects: 100% (2927/2927), 369.04 MiB | 27.58 MiB/s, done.
Resolving deltas: 100% (504/504), done.
Checking out files: 100% (2768/2768), done.

Lire l'aide

Le script doit être installé avec TensorFlow. Voici l'aide intégrée :

tf_upgrade_v2 -h
usage: tf_upgrade_v2 [-h] [--infile INPUT_FILE] [--outfile OUTPUT_FILE]
                     [--intree INPUT_TREE] [--outtree OUTPUT_TREE]
                     [--copyotherfiles COPY_OTHER_FILES] [--inplace]
                     [--no_import_rename] [--no_upgrade_compat_v1_import]
                     [--reportfile REPORT_FILENAME] [--mode {DEFAULT,SAFETY}]
                     [--print_all]

Convert a TensorFlow Python file from 1.x to 2.0

Simple usage:
  tf_upgrade_v2.py --infile foo.py --outfile bar.py
  tf_upgrade_v2.py --infile foo.ipynb --outfile bar.ipynb
  tf_upgrade_v2.py --intree ~/code/old --outtree ~/code/new

optional arguments:
  -h, --help            show this help message and exit
  --infile INPUT_FILE   If converting a single file, the name of the file to
                        convert
  --outfile OUTPUT_FILE
                        If converting a single file, the output filename.
  --intree INPUT_TREE   If converting a whole tree of files, the directory to
                        read from (relative or absolute).
  --outtree OUTPUT_TREE
                        If converting a whole tree of files, the output
                        directory (relative or absolute).
  --copyotherfiles COPY_OTHER_FILES
                        If converting a whole tree of files, whether to copy
                        the other files.
  --inplace             If converting a set of files, whether to allow the
                        conversion to be performed on the input files.
  --no_import_rename    Not to rename import to compat.v2 explicitly.
  --no_upgrade_compat_v1_import
                        If specified, don't upgrade explicit imports of
                        `tensorflow.compat.v1 as tf` to the v2 APIs.
                        Otherwise, explicit imports of the form
                        `tensorflow.compat.v1 as tf` will be upgraded.
  --reportfile REPORT_FILENAME
                        The name of the file where the report log is
                        stored.(default: report.txt)
  --mode {DEFAULT,SAFETY}
                        Upgrade script mode. Supported modes: DEFAULT: Perform
                        only straightforward conversions to upgrade to 2.0. In
                        more difficult cases, switch to use compat.v1. SAFETY:
                        Keep 1.* code intact and import compat.v1 module.
  --print_all           Print full log to stdout instead of just printing
                        errors

Exemple de code TF1

Voici un simple script TensorFlow 1.0 :

head -n 65 models/samples/cookbook/regression/custom_regression.py | tail -n 10
# Calculate loss using mean squared error
  average_loss = tf.losses.mean_squared_error(labels, predictions)

  # Pre-made estimators use the total_loss instead of the average,
  # so report total_loss for compatibility.
  batch_size = tf.shape(labels)[0]
  total_loss = tf.to_float(batch_size) * average_loss

  if mode == tf.estimator.ModeKeys.TRAIN:
    optimizer = params.get("optimizer", tf.train.AdamOptimizer)

Lorsque TensorFlow 2.x est installé, il ne s'exécute pas :

(cd models/samples/cookbook/regression && python custom_regression.py)
Traceback (most recent call last):
  File "custom_regression.py", line 162, in <module>
    tf.logging.set_verbosity(tf.logging.INFO)
AttributeError: module 'tensorflow' has no attribute 'logging'

Un seul fichier

Le script peut être exécuté sur un seul fichier Python :

!tf_upgrade_v2 \
  --infile models/samples/cookbook/regression/custom_regression.py \
  --outfile /tmp/custom_regression_v2.py
INFO line 38:8: Renamed 'tf.feature_column.input_layer' to 'tf.compat.v1.feature_column.input_layer'
INFO line 43:10: Renamed 'tf.layers.dense' to 'tf.compat.v1.layers.dense'
INFO line 46:17: Renamed 'tf.layers.dense' to 'tf.compat.v1.layers.dense'
INFO line 57:17: tf.losses.mean_squared_error requires manual check. tf.losses have been replaced with object oriented versions in TF 2.0 and after. The loss function calls have been converted to compat.v1 for backward compatibility. Please update these calls to the TF 2.0 versions.
INFO line 57:17: Renamed 'tf.losses.mean_squared_error' to 'tf.compat.v1.losses.mean_squared_error'
INFO line 61:15: Added keywords to args of function 'tf.shape'
INFO line 62:15: Changed tf.to_float call to tf.cast(..., dtype=tf.float32).
INFO line 65:40: Renamed 'tf.train.AdamOptimizer' to 'tf.compat.v1.train.AdamOptimizer'
INFO line 68:39: Renamed 'tf.train.get_global_step' to 'tf.compat.v1.train.get_global_step'
INFO line 83:9: tf.metrics.root_mean_squared_error requires manual check. tf.metrics have been replaced with object oriented versions in TF 2.0 and after. The metric function calls have been converted to compat.v1 for backward compatibility. Please update these calls to the TF 2.0 versions.
INFO line 83:9: Renamed 'tf.metrics.root_mean_squared_error' to 'tf.compat.v1.metrics.root_mean_squared_error'
INFO line 142:23: Renamed 'tf.train.AdamOptimizer' to 'tf.compat.v1.train.AdamOptimizer'
INFO line 162:2: Renamed 'tf.logging.set_verbosity' to 'tf.compat.v1.logging.set_verbosity'
INFO line 162:27: Renamed 'tf.logging.INFO' to 'tf.compat.v1.logging.INFO'
INFO line 163:2: Renamed 'tf.app.run' to 'tf.compat.v1.app.run'
TensorFlow 2.0 Upgrade Script
-----------------------------
Converted 1 files
Detected 0 issues that require attention
--------------------------------------------------------------------------------


Make sure to read the detailed log 'report.txt'

Le script affichera des erreurs s'il ne trouve pas de correctif pour le code.

Arborescence des répertoires

Les projets typiques, y compris cet exemple simple, utiliseront bien plus d'un fichier. Vous souhaitez généralement mettre à jour un package entier, de sorte que le script peut également être exécuté sur une arborescence de répertoires :

# update the .py files and copy all the other files to the outtree
!tf_upgrade_v2 \
    --intree models/samples/cookbook/regression/ \
    --outtree regression_v2/ \
    --reportfile tree_report.txt
INFO line 82:10: tf.estimator.LinearRegressor: Default value of loss_reduction has been changed to SUM_OVER_BATCH_SIZE; inserting old default value tf.keras.losses.Reduction.SUM.

INFO line 105:2: Renamed 'tf.logging.set_verbosity' to 'tf.compat.v1.logging.set_verbosity'
INFO line 105:27: Renamed 'tf.logging.INFO' to 'tf.compat.v1.logging.INFO'
INFO line 106:2: Renamed 'tf.app.run' to 'tf.compat.v1.app.run'
INFO line 38:8: Renamed 'tf.feature_column.input_layer' to 'tf.compat.v1.feature_column.input_layer'
INFO line 43:10: Renamed 'tf.layers.dense' to 'tf.compat.v1.layers.dense'
INFO line 46:17: Renamed 'tf.layers.dense' to 'tf.compat.v1.layers.dense'
INFO line 57:17: tf.losses.mean_squared_error requires manual check. tf.losses have been replaced with object oriented versions in TF 2.0 and after. The loss function calls have been converted to compat.v1 for backward compatibility. Please update these calls to the TF 2.0 versions.
INFO line 57:17: Renamed 'tf.losses.mean_squared_error' to 'tf.compat.v1.losses.mean_squared_error'
INFO line 61:15: Added keywords to args of function 'tf.shape'
INFO line 62:15: Changed tf.to_float call to tf.cast(..., dtype=tf.float32).
INFO line 65:40: Renamed 'tf.train.AdamOptimizer' to 'tf.compat.v1.train.AdamOptimizer'
INFO line 68:39: Renamed 'tf.train.get_global_step' to 'tf.compat.v1.train.get_global_step'
INFO line 83:9: tf.metrics.root_mean_squared_error requires manual check. tf.metrics have been replaced with object oriented versions in TF 2.0 and after. The metric function calls have been converted to compat.v1 for backward compatibility. Please update these calls to the TF 2.0 versions.
INFO line 83:9: Renamed 'tf.metrics.root_mean_squared_error' to 'tf.compat.v1.metrics.root_mean_squared_error'
INFO line 142:23: Renamed 'tf.train.AdamOptimizer' to 'tf.compat.v1.train.AdamOptimizer'
INFO line 162:2: Renamed 'tf.logging.set_verbosity' to 'tf.compat.v1.logging.set_verbosity'
INFO line 162:27: Renamed 'tf.logging.INFO' to 'tf.compat.v1.logging.INFO'
INFO line 163:2: Renamed 'tf.app.run' to 'tf.compat.v1.app.run'
INFO line 58:10: tf.estimator.LinearRegressor: Default value of loss_reduction has been changed to SUM_OVER_BATCH_SIZE; inserting old default value tf.keras.losses.Reduction.SUM.

INFO line 101:2: Renamed 'tf.logging.set_verbosity' to 'tf.compat.v1.logging.set_verbosity'
INFO line 101:27: Renamed 'tf.logging.INFO' to 'tf.compat.v1.logging.INFO'
INFO line 102:2: Renamed 'tf.app.run' to 'tf.compat.v1.app.run'
INFO line 72:10: tf.estimator.DNNRegressor: Default value of loss_reduction has been changed to SUM_OVER_BATCH_SIZE; inserting old default value tf.keras.losses.Reduction.SUM.

INFO line 96:2: Renamed 'tf.logging.set_verbosity' to 'tf.compat.v1.logging.set_verbosity'
INFO line 96:27: Renamed 'tf.logging.INFO' to 'tf.compat.v1.logging.INFO'
INFO line 97:2: Renamed 'tf.app.run' to 'tf.compat.v1.app.run'
WARNING line 125:15: Changing dataset.make_one_shot_iterator() to tf.compat.v1.data.make_one_shot_iterator(dataset). Please check this transformation.

INFO line 40:7: Renamed 'tf.test.mock' to 'tf.compat.v1.test.mock'
TensorFlow 2.0 Upgrade Script
-----------------------------
Converted 7 files
Detected 1 issues that require attention
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
File: models/samples/cookbook/regression/automobile_data.py
--------------------------------------------------------------------------------
models/samples/cookbook/regression/automobile_data.py:125:15: WARNING: Changing dataset.make_one_shot_iterator() to tf.compat.v1.data.make_one_shot_iterator(dataset). Please check this transformation.



Make sure to read the detailed log 'tree_report.txt'

Notez le seul avertissement concernant la fonction dataset.make_one_shot_iterator .

Désormais, le script fonctionne avec TensorFlow 2.x :

Notez que le module tf.compat.v1 étant inclus dans TF 1.15, le script converti s'exécutera également dans TensorFlow 1.15.

(cd regression_v2 && python custom_regression.py 2>&1) | tail
I0922 22:16:42.778216 140254758430528 estimator.py:2074] Saving dict for global step 1000: global_step = 1000, loss = 651.5428, rmse = 3.684265
INFO:tensorflow:Saving 'checkpoint_path' summary for global step 1000: /tmp/tmpk2_4r192/model.ckpt-1000
I0922 22:16:42.817190 140254758430528 estimator.py:2135] Saving 'checkpoint_path' summary for global step 1000: /tmp/tmpk2_4r192/model.ckpt-1000
Tensor("IteratorGetNext:25", shape=(None,), dtype=float64, device=/device:CPU:0)
Tensor("Squeeze:0", shape=(None,), dtype=float32)

********************************************************************************

RMS error for the test set: $3684

Rapport détaillé

Le script rapporte également une liste de modifications détaillées. Dans cet exemple, il a trouvé une transformation potentiellement dangereuse et a inclus un avertissement en haut du fichier :

head -n 20 tree_report.txt
TensorFlow 2.0 Upgrade Script
-----------------------------
Converted 7 files
Detected 1 issues that require attention
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
File: models/samples/cookbook/regression/automobile_data.py
--------------------------------------------------------------------------------
models/samples/cookbook/regression/automobile_data.py:125:15: WARNING: Changing dataset.make_one_shot_iterator() to tf.compat.v1.data.make_one_shot_iterator(dataset). Please check this transformation.

================================================================================
Detailed log follows:

================================================================================
================================================================================
Input tree: 'models/samples/cookbook/regression/'
================================================================================
--------------------------------------------------------------------------------
Processing file 'models/samples/cookbook/regression/__init__.py'
 outputting to 'regression_v2/__init__.py'

Notez à nouveau le seul avertissement concernant la Dataset.make_one_shot_iterator function .

Dans d'autres cas, la sortie expliquera le raisonnement pour les modifications non triviales :

%%writefile dropout.py
import tensorflow as tf

d = tf.nn.dropout(tf.range(10), 0.2)
z = tf.zeros_like(d, optimize=False)
Writing dropout.py
!tf_upgrade_v2 \
  --infile dropout.py \
  --outfile dropout_v2.py \
  --reportfile dropout_report.txt > /dev/null
cat dropout_report.txt
TensorFlow 2.0 Upgrade Script
-----------------------------
Converted 1 files
Detected 0 issues that require attention
--------------------------------------------------------------------------------
================================================================================
Detailed log follows:

================================================================================
--------------------------------------------------------------------------------
Processing file 'dropout.py'
 outputting to 'dropout_v2.py'
--------------------------------------------------------------------------------

3:4: INFO: Changing keep_prob arg of tf.nn.dropout to rate, and recomputing value.

4:4: INFO: Renaming tf.zeros_like to tf.compat.v1.zeros_like because argument optimize is present. tf.zeros_like no longer takes an optimize argument, and behaves as if optimize=True. This call site specifies something other than optimize=True, so it was converted to compat.v1.
--------------------------------------------------------------------------------

Voici le contenu du fichier modifié, notez comment le script ajoute des noms d'arguments pour gérer les arguments déplacés et renommés :

cat dropout_v2.py
import tensorflow as tf

d = tf.nn.dropout(tf.range(10), rate=1 - (0.2))
z = tf.compat.v1.zeros_like(d, optimize=False)

Un projet plus important peut contenir quelques erreurs. Par exemple, convertissez le modèle deeplab :

!tf_upgrade_v2 \
    --intree models/research/deeplab \
    --outtree deeplab_v2 \
    --reportfile deeplab_report.txt > /dev/null

Il a produit les fichiers de sortie :

ls deeplab_v2
README.md   datasets        input_preprocess.py        train.py
__init__.py deeplab_demo.ipynb  local_test.sh          utils
common.py   eval.py         local_test_mobilenetv2.sh  vis.py
common_test.py  export_model.py     model.py
core        g3doc           model_test.py

Mais il y a eu des erreurs. Le rapport vous aidera à identifier ce que vous devez corriger avant que cela ne soit exécuté. Voici les trois premières erreurs :

cat deeplab_report.txt | grep -i models/research/deeplab | grep -i error | head -n 3
models/research/deeplab/eval.py:28:7: ERROR: Using member tf.contrib.slim in deprecated module tf.contrib. tf.contrib.slim cannot be converted automatically. tf.contrib will not be distributed with TensorFlow 2.0, please consider an alternative in non-contrib TensorFlow, a community-maintained repository such as tensorflow/addons, or fork the required code.
models/research/deeplab/eval.py:146:8: ERROR: Using member tf.contrib.metrics.aggregate_metric_map in deprecated module tf.contrib. tf.contrib.metrics.aggregate_metric_map cannot be converted automatically. tf.contrib will not be distributed with TensorFlow 2.0, please consider an alternative in non-contrib TensorFlow, a community-maintained repository such as tensorflow/addons, or fork the required code.
models/research/deeplab/export_model.py:25:7: ERROR: Using member tf.contrib.slim in deprecated module tf.contrib. tf.contrib.slim cannot be converted automatically. tf.contrib will not be distributed with TensorFlow 2.0, please consider an alternative in non-contrib TensorFlow, a community-maintained repository such as tensorflow/addons, or fork the required code.

Mode "Sécurité"

Le script de conversion dispose également d'un mode SAFETY moins invasif qui modifie simplement les importations pour utiliser le module tensorflow.compat.v1 :

cat dropout.py
import tensorflow as tf

d = tf.nn.dropout(tf.range(10), 0.2)
z = tf.zeros_like(d, optimize=False)
tf_upgrade_v2 --mode SAFETY --infile dropout.py --outfile dropout_v2_safe.py > /dev/null
cat dropout_v2_safe.py
import tensorflow.compat.v1 as tf

d = tf.nn.dropout(tf.range(10), 0.2)
z = tf.zeros_like(d, optimize=False)

Comme vous pouvez le voir, cela ne met pas à niveau votre code, mais permet au code TensorFlow 1 de s'exécuter sur les binaires TensorFlow 2. Notez que cela ne signifie pas que votre code exécute des comportements TF 2.x pris en charge !

Mises en garde

  • Ne mettez pas à jour des parties de votre code manuellement avant d'exécuter ce script. En particulier, les fonctions qui ont eu des arguments réordonnés comme tf.argmax ou tf.batch_to_space font que le script ajoute de manière incorrecte des arguments de mots clés qui ne correspondent pas à votre code existant.

  • Le script suppose que tensorflow est importé à l'aide import tensorflow as tf , ou import tensorflow.compat.v1 as tf .

  • Ce script ne réorganise pas les arguments. Au lieu de cela, le script ajoute des arguments de mots clés aux fonctions dont les arguments sont réorganisés.

  • Consultez tf2up.ml pour un outil pratique pour mettre à niveau les blocs-notes Jupyter et les fichiers Python dans un référentiel GitHub.

Pour signaler des bogues de script de mise à niveau ou faire des demandes de fonctionnalités, veuillez signaler un problème sur GitHub .