TensorFlow 2 在几个方面与 TF1.x 存在根本区别。您仍然可以像这样对 TF2 二进制安装运行未修改的 TF1.x 代码(除了 contrib)
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
但是,这不是运行 TF2 行为和 API,并且可能无法与为 TF2 编写的代码一起正常工作。如果您没有使用 TF2 行为运行,则实际上是在 TF2 安装之上运行 TF1.x。阅读TF1 与 TF2 行为指南,详细了解 TF2 与 TF1.x 的区别。
本指南概述了将您的 TF1.x 代码迁移到 TF2 的过程。这使您能够利用新的和未来的功能改进,并使您的代码更简单、更高效且更易于维护。
如果您使用的是tf.keras
的高级 API 并且仅使用model.fit
进行训练,那么您的代码应该或多或少与 TF2 完全兼容,除了以下注意事项
TF2 迁移过程
在迁移之前,请阅读指南,了解 TF1.x 和 TF2 之间的行为和 API 差异。
- 运行自动化脚本将您的一些 TF1.x API 用法转换为
tf.compat.v1
。 - 删除旧的
tf.contrib
符号(检查TF Addons 和TF-Slim)。 - 使您的 TF1.x 模型前向传递在启用急切执行的 TF2 中运行。
- 将您的 TF1.x 代码升级为 TF2 等效的训练循环和保存/加载模型。
- (可选)将您的 TF2 兼容
tf.compat.v1
API 迁移到惯用的 TF2 API。
以下部分将详细介绍上述步骤。
运行符号转换脚本
这将执行对您的代码符号进行重写的初始步骤,以针对 TF 2.x 二进制文件运行,但不会使您的代码成为 TF 2.x 的惯用代码,也不会自动使您的代码与 TF2 行为兼容。
您的代码很可能仍然会使用tf.compat.v1
端点来访问占位符、会话、集合和其他 TF1.x 风格的功能。
阅读指南,详细了解使用符号转换脚本的最佳实践。
删除tf.contrib
的使用
tf.contrib
模块已停止使用,其几个子模块已集成到核心 TF2 API 中。其他子模块现在已分离到其他项目中,例如TF IO 和TF Addons。
大量较旧的 TF1.x 代码使用Slim 库,该库与 TF1.x 一起打包为tf.contrib.layers
。将 Slim 代码迁移到 TF2 时,请将 Slim API 用法切换到指向tf-slim pip 包。然后,阅读模型映射指南,了解如何转换 Slim 代码。
或者,如果您使用 Slim 预训练模型,您可以考虑尝试使用 Keras 从tf.keras.applications
或TF Hub 导出的 TF2 SavedModel
(从原始 Slim 代码导出)。
使 TF1.x 模型前向传递在启用 TF2 行为的情况下运行
跟踪变量和损失
TF2 中的急切执行不支持tf.Graph
基于集合的 API。这会影响您构建和跟踪变量的方式。
对于新的 TF2 代码,您应该使用 tf.Variable
而不是 v1.get_variable
,并使用 Python 对象来收集和跟踪变量,而不是 tf.compat.v1.variable_scope
。通常情况下,这将是以下之一:
使用 Layer
、Module
或 Model
对象的 .variables
和 .trainable_variables
属性来聚合变量列表(例如 tf.Graph.get_collection(tf.GraphKeys.VARIABLES)
)。
Layer
和 Model
类实现了其他几个属性,消除了对全局集合的需要。它们的 .losses
属性可以替代使用 tf.GraphKeys.LOSSES
集合。
阅读 模型映射指南,了解有关使用 TF2 代码建模垫片将现有的基于 get_variable
和 variable_scope
的代码嵌入到 Layers
、Models
和 Modules
中的更多信息。这将允许您在启用急切执行的情况下执行前向传递,而无需进行重大重写。
适应其他行为变化
如果 模型映射指南 本身不足以使您的模型前向传递运行,则可能需要进行其他更详细的行为更改,请参阅有关 TF1.x 与 TF2 行为 的指南,了解其他行为更改以及如何适应它们。还可以查看 通过子类化创建新的层和模型指南 以获取详细信息。
验证您的结果
请参阅 模型验证指南,了解有关如何(数值上)验证您的模型在启用急切执行时是否行为正确的简单工具和指南。您可能会发现这与 模型映射指南 结合使用时特别有用。
升级训练、评估和导入/导出代码
使用 v1.Session
样式的 tf.estimator.Estimator
和其他基于集合的方法构建的 TF1.x 训练循环与 TF2 的新行为不兼容。您必须迁移所有 TF1.x 训练代码,因为将其与 TF2 代码结合使用会导致意外行为。
您可以从几种策略中选择一种来执行此操作。
最高级别的做法是使用 tf.keras
。Keras 中的高级函数管理了许多低级细节,如果您自己编写训练循环,这些细节可能很容易被忽略。例如,它们会自动收集正则化损失,并在调用模型时设置 training=True
参数。
参考 Estimator 迁移指南,了解如何迁移 tf.estimator.Estimator
代码以使用 普通 和 自定义 tf.keras
训练循环。
自定义训练循环可以让您更精细地控制模型,例如跟踪各个层的权重。阅读有关 从头开始构建训练循环 的指南,了解如何使用 tf.GradientTape
来检索模型权重并使用它们来更新模型。
将 TF1.x 优化器转换为 Keras 优化器
tf.compat.v1.train
中的优化器,例如 Adam 优化器 和 梯度下降优化器,在 tf.keras.optimizers
中有等效项。
下表总结了如何将这些旧版优化器转换为其 Keras 等效项。您可以直接用 TF2 版本替换 TF1.x 版本,除非需要其他步骤(例如 更新默认学习率)。
请注意,转换优化器 可能会使旧检查点不兼容。
TF1.x | TF2 | 其他步骤 |
---|---|---|
`tf.v1.train.GradientDescentOptimizer` | tf.keras.optimizers.SGD |
无 |
`tf.v1.train.MomentumOptimizer` | tf.keras.optimizers.SGD |
包含 `momentum` 参数 |
`tf.v1.train.AdamOptimizer` | tf.keras.optimizers.Adam |
将 `beta1` 和 `beta2` 参数重命名为 `beta_1` 和 `beta_2` |
`tf.v1.train.RMSPropOptimizer` | tf.keras.optimizers.RMSprop |
将 `decay` 参数重命名为 `rho` |
`tf.v1.train.AdadeltaOptimizer` | tf.keras.optimizers.Adadelta |
无 |
`tf.v1.train.AdagradOptimizer` | tf.keras.optimizers.Adagrad |
无 |
`tf.v1.train.FtrlOptimizer` | tf.keras.optimizers.Ftrl |
删除 `accum_name` 和 `linear_name` 参数 |
`tf.contrib.AdamaxOptimizer` | tf.keras.optimizers.Adamax |
将 `beta1` 和 `beta2` 参数重命名为 `beta_1` 和 `beta_2` |
`tf.contrib.Nadam` | tf.keras.optimizers.Nadam |
将 `beta1` 和 `beta2` 参数重命名为 `beta_1` 和 `beta_2` |
升级数据输入管道
有许多方法可以将数据馈送到 tf.keras
模型。它们将接受 Python 生成器和 Numpy 数组作为输入。
将数据馈送到模型的推荐方法是使用 tf.data
包,其中包含用于操作数据的集合的高性能类。属于 tf.data
的 dataset
高效、表达能力强,并且与 TF2 集成良好。
它们可以直接传递给 tf.keras.Model.fit
方法。
model.fit(dataset, epochs=5)
它们可以直接在标准 Python 中进行迭代
for example_batch, label_batch in dataset:
break
如果您仍在使用 tf.queue
,这些现在仅作为数据结构支持,而不是作为输入管道。
您还应该迁移所有使用 tf.feature_columns
的特征预处理代码。阅读 迁移指南 以获取更多详细信息。
保存和加载模型
TF2 使用基于对象的检查点。阅读 检查点迁移指南,了解有关从基于名称的 TF1.x 检查点迁移的更多信息。还可以阅读 TensorFlow 核心文档中的 检查点指南。
保存的模型没有明显的兼容性问题。阅读 SavedModel
指南,了解有关将 TF1.x 中的 SavedModel
迁移到 TF2 的更多信息。一般来说,
- TF1.x 保存的模型在 TF2 中有效。
- 如果所有操作都受支持,则 TF2 保存的模型在 TF1.x 中有效。
还可以参考 GraphDef
部分 在 SavedModel
迁移指南中,了解有关使用 Graph.pb
和 Graph.pbtxt
对象的更多信息。
(可选)从 tf.compat.v1
符号迁移
tf.compat.v1
模块包含完整的 TF1.x API,具有其原始语义。
即使在遵循上述步骤并最终获得与所有 TF2 行为完全兼容的代码后,也可能存在许多对 compat.v1
api 的引用,这些引用恰好与 TF2 兼容。您应该避免在编写的任何新代码中使用这些旧版 compat.v1
api,尽管它们将继续对您已经编写的代码有效。
但是,您可以选择将现有用法迁移到非旧版 TF2 API。各个 compat.v1
符号的文档字符串通常会解释如何将它们迁移到非旧版 TF2 API。此外,模型映射指南中有关增量迁移到惯用 TF2 API 的部分 也可以帮助您完成此操作。
资源和进一步阅读
如前所述,将所有 TF1.x 代码迁移到 TF2 是一个好习惯。阅读 TensorFlow 指南中 迁移到 TF2 部分 中的指南以了解更多信息。