Автоматическое обновление кода до TensorFlow 2

Смотрите на TensorFlow.org Запустите в Google Colab Изучайте код на GitHub Скачайте ноутбук

TensorFlow 2.0 включает много изменений API, таких как изменение порядка аргументов, переименование символов и изменение значений по умолчанию для параметров. Ручное исправление всех этих модификаций утомительно и подвержено ошибкам. Чтобы упростить изменения и сделать ваш переход на TF 2.0 как можно более плавным, команда TensorFlow создала утилиту tf_upgrade_v2, помогающую перейти от legacy кода к новому API.

Примечание: tf_upgrade_v2 устанавливается автоматически для TensorFlow 1.13 и более поздних версий (включая все сборки TF 2.0).

Типичное использование выглядит так:

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

Это ускорит процесс обновления за счет конвертации существующих скриптов TensorFlow 1.x Python в TensorFlow 2.0.

Скрипт конвертации максимально автоматизирует процесс, но все еще существуют синтаксические и стилистические изменения, которые не могут быть выполнены скриптом.

Модули совместимости

Некоторые символы API не могут быть обновлены просто с использованием замены строк. Чтобы гарантировать поддержку вашего кода в TensorFlow 2.0, скрипт обновления включает в себя модуль compat.v1. Этот модуль заменяет символы TF 1.x, такие как tf.foo, на эквивалентную ссылкуtf.compat.v1.foo. Хотя модуль совместимости хорош, мы рекомендуем вам вручную вычитать замены и перенести их на новые API в пространстве имен tf. * вместо пространства имен tf.compat.v1 как можно быстрее.

Из-за депрекации модулей TensorFlow 2.x (например, tf.flags иtf.contrib) некоторые изменения не могут быть обойдены путем переключения на compat.v1. Обновление этого кода может потребовать использования дополнительной библиотеки (например, absl.flags) или переключения на пакет в tenorflow / addons.

Рекомендуемый процесс обновления

Оставшаяся часть руководства демонстрирует использование скрипта обновления. Хоть скрипт обновления прост в использовании, очень рекомендуем вам использовать скрипт как часть следующего процесса:

  1. ** Модульное тестирование **: убедитесь, что в обновляемом коде имеется набор модульных тестов с разумным охватом. Это код Python, поэтому язык не защитит вас от многих классов ошибок. Также убедитесь, что все ваши зависимости были обновлены до совместимых с TensorFlow 2.0.

  2. Установите TensorFlow 1.14: Обновите ваш TensorFlow до последней версии TensorFlow 1.x, как минимум 1.14. Она включает финальный API TensorFlow 2.0 в tf.compat.v2.

  3. Протестируйте с 1.14: Убедитесь, что ваши модульные тесты проходят на этом этапе. Вы будете повторно запускать их в процессе обновления поэтому важно начать с зеленого цвета.

  4. Запустите скрипт обновления: Запустите tf_upgrade_v2 на всем дереве исходного кода включая тесты. Это обновит ваш код до формата в котором он использует только символы доступные в TensorFlow 2.0. Устаревшие символы будут доступны с tf.compat.v1. Это впоследствии потребует ручного внимания, но не сразу.

  5. Запустите ковертированные тесты с TensorFlow 1.14: Ваш код должен все еще запускаться правильно в TensorFlow 1.14. Запустите снова модульные тесты. Любая ошибка в ваших тестах на этом этапе значит, что в скрипте обновления есть ошибка. Сообщите нам пожалуйста об этом.

  6. Проверьте отчет обновления на наличие предупреждений и ошибок: Скрипт пишет файл отчета объясняющий все конвертации которые вам нужно перепроверить, или все действия которые нужно совершить вручную. Например: Любые оставшиеся экземпляры contrib требуют ручного удаления. Пожалуйста, обратитесь к RFC для получения дополнительных инструкций.

  7. Установите TensorFlow 2.0: В этом месте переключение на TensorFlow 2.0 должно быть безопасно.

  8. Протестируйте с v1.disable_v2_behavior: Перезапустите ваши тесты с v1.disable_v2_behavior () в основной функции тестов результаты должны быть те же, что и при запуске под 1.14.

  9. Включите V2 Behavior: Сейчас, когда ваши тесты работают с использованием API v2, вы можете начать смотреть включение v2 behavior. В зависимости от того, как написан ваш код, это может потребовать некоторых изменений. См. Руководство по миграции для деталей.

Использование скрипта обновления

Установка

Перед началом убедитесь, что TensorlFlow 2.0 установлен.

try:
  import tensorflow.compat.v2 as tf
except Exception:
  pass

tf.enable_v2_behavior()

print(tf.__version__)
2.3.0

Склонируйте git репозиторий tensorflow/models чтобы у вас был какой-нибудь код для проверки:

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% (2449/2449), done.[K
remote: Total 2927 (delta 509), reused 2036 (delta 403), pack-reused 0[K
Receiving objects: 100% (2927/2927), 369.04 MiB | 14.82 MiB/s, done.
Resolving deltas: 100% (509/509), done.
Checking out files: 100% (2768/2768), done.

Прочитайте help

Скрипт должен быть установлен с TensorFlow. Здесь встроенная помощь:

tf_upgrade_v2 -h
2020-08-01 00:24:20.618247: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
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

Пример кода TF1

Здесь простой скрипт 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)

С установленным TensorFlow 2.0 он не запускается:

(cd models/samples/cookbook/regression && python custom_regression.py)
2020-08-01 00:24:22.626858: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
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'

Отдельный файл

Скрипт обновления может быть запущен на отдельном файле Python:

!tf_upgrade_v2 \
  --infile models/samples/cookbook/regression/custom_regression.py \
  --outfile /tmp/custom_regression_v2.py
2020-08-01 00:24:24.541353: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
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'


Скрипт выведет ошибки если не сможет найти исправления для кода.

Дерево каталогов

Типичные проекты, включая этот простой пример, используют более одного файла. Обычно хочется обновить весь пакет, поэтому скрипт может быть также запущен на дереве каталогов:

# обновить файлы .py и скопировать остальные файлы в outtree
!tf_upgrade_v2 \
    --intree models/samples/cookbook/regression/ \
    --outtree regression_v2/ \
    --reportfile tree_report.txt
2020-08-01 00:24:26.470009: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
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 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 40:7: Renamed 'tf.test.mock' to 'tf.compat.v1.test.mock'
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 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'
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'
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'


Обратите внимание на одно замечание по поводу функции dataset.make_one_shot_iterator.

Сейчас скрипт работает с TensorFlow 2.0:

Обратите внимание, что из-за модуля tf.compat.v1, сконвертированный скрипт также будет запускаться в TensorFlow 1.14.

(cd regression_v2 && python custom_regression.py 2>&1) | tail
    data = raw_dataframe()
  File "/tmpfs/src/temp/site/ru/guide/regression_v2/automobile_data.py", line 67, in raw_dataframe
    dtype=COLUMN_TYPES, na_values="?")
  File "/home/kbuilder/.local/lib/python3.6/site-packages/pandas/io/parsers.py", line 686, in read_csv
    return _read(filepath_or_buffer, kwds)
  File "/home/kbuilder/.local/lib/python3.6/site-packages/pandas/io/parsers.py", line 449, in _read
    _validate_names(kwds.get("names", None))
  File "/home/kbuilder/.local/lib/python3.6/site-packages/pandas/io/parsers.py", line 417, in _validate_names
    raise ValueError("Names should be an ordered collection.")
ValueError: Names should be an ordered collection.

Детальный отчет

Скрипт также публикует подробный список изменений. В этом примере он нашел одну возможно небезопасную трансформацию и добавил предупреждение в начало файла:

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/linear_regression.py'
 outputting to 'regression_v2/linear_regression.py'

Обратите внимание вновь на одно замечание о Dataset.make_one_shot_iterator function.

В остальных случаях результат объяснит причину для нетривиальных изменений:

%%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
2020-08-01 00:24:31.315751: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1

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.
--------------------------------------------------------------------------------


Вот измененное содержимое файла, обратите внимание, как скрипт добавляет имена аргументов для работы с перемещенными и переименованными аргументами:

cat dropout_v2.py
import tensorflow as tf

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

Больший проект может содержать мало ошибок. Например, конвертируеме модель deeplab:

!tf_upgrade_v2 \
    --intree models/research/deeplab \
    --outtree deeplab_v2 \
    --reportfile deeplab_report.txt > /dev/null
2020-08-01 00:24:33.478066: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1

Это сгенерировало выходные файлы:

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

Но там были ошибки. Отчет поможет вам точно определить, что нужно исправить, прежде чем запускать скрипт. Вот первые три ошибки:

cat deeplab_report.txt | grep -i models/research/deeplab | grep -i error | head -n 3
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.
models/research/deeplab/train.py:29: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/vis.py:31: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.

"Безопасный" режим

У скрипт конвертации есть также менее инвазивный БЕЗОПАСНЫЙ режим который просто меняет импорты для использования модуля 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
2020-08-01 00:24:37.332505: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1

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)

Как вы можете видеть это не обновляет ваш код, но позволяет TensorFlow 1 коду запускаться в TensorFlow 2

Предостережения

  • Не обновляйте части вашего кода вручную перед запуском скрипта. В частности, функции с переупорядоченными аргументами, такие как tf.argmax илиtf.batch_to_space, вынудят скрипт неправильно добавить аргументы ключевых слов, что запутает ваш существующий код.

  • Скрипт предполагает, что tensorflow импортирован с использованием import tensorflow as tf.

  • Скрипт не переупорядочивает аргументы. Вместо этого скрипт добавляет ключевые слова аргументов к функциям у которых аргументы поменяли порядок.

  • Проверьте tf2up.ml для подходящего инструмента обновления ноутбуков Jupyter и файлов Python в репозитории GitHub.

Чтобы сообщить об ошибках в скрипте обновления или отправить запрос на добавление функции, отправьте сообщение об ошибке на GitHub. И если вы тестируете TensorFlow 2.0, мы хотим знать об этом! Вступайте в сообщество тестирования TF 2.0 и отправляйте вопросы и обсуждения на testing@tensorflow.org.