##### Copyright 2018 The TensorFlow Authors.
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

自动重写 TF 1.x 和 compat.v1 API 符号#

在 TensorFlow.org 上查看 在 Google Colab 运行 在 Github 上查看源代码 下载笔记本

TensorFlow 2.x 包含 TF 1.x 和 tf.compat.v1 API 的许多 API 更改,例如重新排序了参数,重命名了符号,更改了参数的默认值。手动执行所有这些修改可能很乏味,而且很容易出错。为了简化更改,尽可能让您无缝过渡到 TF 2.x,TensorFlow 团队创建了 tf_upgrade_v2 效用函数,帮助您将旧版代码转换至新的 API。

注:TensorFlow 1.13 和更高版本(包括所有 TF 2.0 构建)会自动安装 tf_upgrade_v2

典型的用法如下:

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

将现有 TensorFlow 1.x Python 脚本转换为 TensorFlow 2.x 脚本可以加快升级流程。

尽管许多 API 无法自动迁移,但转换脚本会自动执行许多机械 API 转换。它也无法使您的代码与 TF2 行为和 API 完全兼容。因此,这只是您迁移之旅的一部分。

兼容性模块#

某些 API 符号不能简单地通过使用字符串替换来升级。那些无法自动升级的符号将被映射到它们在 compat.v1 模块中的位置。此模块将 tf.foo 等 TF 1.x 符号替换为对应的 tf.compat.v1.foo 引用。如果您已经通过 import tensorflow.compat.v1 as tf 导入 TF 来使用 compat.v1 API,tf_upgrade_v2 脚本会尝试尽可能将这些用法转换为非兼容 API。请注意,尽管有些 compat.v1 API 与 TF2.x 行为兼容,但许多 API 不兼容。因此,建议尽快手动检查替换并将它们迁移到 tf.* 命名空间而不是 tf.compat.v1 命名空间中的新 API。

由于在 TensorFlow 2.x 模块弃用(例如,tf.flagstf.contrib),所以切换到 compat.v1 无法解决某些更改。升级此代码可能需要其他库(例如,absl.flags)或切换到 tensorflow/addons 中的软件包。

推荐的升级流程#

本指南的剩余部分将演示如何使用符号重写脚本。虽然此脚本易于使用,但我们仍强烈建议按照以下流程使用脚本:

  1. 单元测试:确保要升级的代码包含具有合理覆盖率的单元测试套件。这是 Python 代码,该语言并不会帮助您避免各种类型的错误。同时还要确保已升级所有依赖项,使其与 TensorFlow 2.x 兼容。

  2. 安装 TensorFlow 1.15:将 TensorFlow 升级到最新的 TensorFlow 1.x 版本(最低为 1.15 版本)。其中包括 tf.compat.v2 中的最终 TensorFlow 2.0 API。

  3. 使用 1.15 版本进行测试:确保此时可以通过单元测试。在升级过程中,您将反复进行测试,因此,从可以正常运行的代码开始非常重要。

  4. 运行升级脚本:对整个源代码树运行 tf_upgrade_v2(已包含测试)。这样可将代码升级为仅使用 TensorFlow 2.0 中提供的符号的格式。被弃用的符号将通过 tf.compat.v1 进行访问。最终需要人工检查这些升级,但不是现在。

  5. 使用 TensorFlow 1.15 运行转换的测试:代码在 TensorFlow 1.15 中应该仍可以正常运行。再次运行单元测试。测试在此时产生任何错误都意味着升级脚本存在错误。请通知我们

  6. 检查更新报告中的警告和错误:该脚本会编写一个对需要复查的转换或需要执行的人工操作进行解释的报告文件。例如:contrib 的所有剩余实例需要通过人工移除。请查阅 RFC 中的详细说明

  7. 安装 TensorFlow 2.x:此时切换到 TensorFlow 2.x 二进制文件应当是安全的,即使您正在运行旧版行为

  8. 使用 v1.disable_v2_behavior 进行测试:使用测试主函数中的 v1.disable_v2_behavior() 重新运行测试产生的结果应与在 1.15 下运行时产生的结果相同。

  9. 启用 V2 行为:现在,您的测试使用 TF2 二进制文件工作,现在可以开始迁移代码以避免 tf.estimator 并仅使用受支持的 TF2 行为(不停用 TF2 行为)。请参阅迁移指南以了解详情。

使用符号重写 tf_upgrade_v2 脚本#

安装#

首先,请确保已安装 TensorFlow 2.x。

import tensorflow as tf

print(tf.__version__)

克隆 tensorflow/modelss git 仓库,以便获得要测试的一些代码:

!git clone --branch r1.13.0 --depth 1 https://github.com/tensorflow/models

读取帮助#

安装 TensorFlow 时应该已安装该脚本。下面是内置帮助命令:

!tf_upgrade_v2 -h

TF1 代码示例#

下面是一个简单的 TensorFlow 1.0 脚本:

!head -n 65 models/samples/cookbook/regression/custom_regression.py | tail -n 10

对于安装的 TensorFlow 2.x,它不会运行:

!(cd models/samples/cookbook/regression && python custom_regression.py)

单个文件#

该脚本可以对单个 Python 文件运行:

!tf_upgrade_v2 \
  --infile models/samples/cookbook/regression/custom_regression.py \
  --outfile /tmp/custom_regression_v2.py

如果无法找到修正代码问题的方法,该脚本会打印错误消息。

目录树#

典型项目(包括下面的简单示例)会使用远不止一个文件。通常需要更新整个软件包,因此该脚本也可以对目录树运行:

# 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

注意关于 dataset.make_one_shot_iterator 函数的一条警告。

现在,对于 TensorFlow 2.x,该脚本已经可以发挥作用:

请注意,由于 TF 1.15 中包含 tf.compat.v1 模块,转换的脚本在 TensorFlow 1.15 中也可以运行。

!(cd regression_v2 && python custom_regression.py 2>&1) | tail

详细报告#

该脚本还会报告一个详细更改的列表。在本例中,它发现了一个可能不安全的转换,因此在文件顶部包含了一条警告:

!head -n 20 tree_report.txt

再次注意关于 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)
!tf_upgrade_v2 \
  --infile dropout.py \
  --outfile dropout_v2.py \
  --reportfile dropout_report.txt > /dev/null
!cat dropout_report.txt

以下是经过修改的文件内容,请注意脚本是如何通过添加参数名来处理移动和重命名的参数的:

!cat dropout_v2.py

更大的项目可能会包含一些错误。例如,转换 deeplab 模型:

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

它会生成输出文件:

!ls deeplab_v2

但是其中包含错误。该报告会帮助您找到确保代码可以正常运行所需要解决的错误。下面是前三个错误:

!cat deeplab_report.txt | grep -i models/research/deeplab | grep -i error | head -n 3

“安全”模式#

该转换脚本还有一种介入度相对较低的 SAFETY 模式。在此模式下,只需更改导入来使用 tensorflow.compat.v1 模块:

!cat dropout.py
!tf_upgrade_v2 --mode SAFETY --infile dropout.py --outfile dropout_v2_safe.py > /dev/null
!cat dropout_v2_safe.py

如您所见,这不会升级您的代码,但允许 TensorFlow 1 代码针对 TensorFlow 2 二进制文件运行。请注意,这并不意味着您的代码正在运行受支持的 TF 2.x 行为!

注意事项#

  • 在运行此脚本之前,不要手动更新代码的某些部分。尤其是,更改了参数顺序的函数(如 tf.math.argmaxtf.batch_to_space)会导致代码错误添加不正确映射现有代码匹配的关键字参数。

  • 该脚本假定使用 import tensorflow as tfimport tensorflow.compat.v1 as tf 导入 tensorflow

  • 该脚本不会更改参数顺序,但是会将关键字参数添加到本身已更改参数顺序的函数。

  • 请查阅 tf2up.ml,找到一款方便的工具来升级 GitHub 仓库中的 Jupyter 笔记本和 Python 文件。

要报告升级脚本错误或提出功能请求,请在 GitHub 上提交议题。