迁移至 TensorFlow 1.0
TensorFlow 1.0 中 API 的改动不再完全向后兼容。因此,运行于 TensorFlow 0.n 版本的 TensorFlow 应用可能不能在 TensorFlow 1.0 版本中正常运行。在此版本中,我们对 API 进行了一些修改,确保了其内部一致性;在接下来的整个 1.N 版本周期中都不会进行任何断代式变更。
本指南将引导您了解新版 API 的主要变更,以及如何将您的程序自动升级至 TensorFlow 1.0。除了帮助您完成程序的修改之外,本指南也解释了我们为何要做出这些变更。
如何升级
如果您希望自动将代码迁移至 1.0 版本,可以尝试使用我们的 tf_upgrade.py
脚本。此脚本能处理大多数情况,但有时还是需要您进行手动修改。
您可以在我们的 GitHub 中获取此脚本。
如要将单个的 0.n 版 TensorFlow 源文件转换为 1.0 版本,请输入如下格式的命令:
$ python tf_upgrade.py --infile InputFile --outfile OutputFile
例如,以下命令会将一个名为 test.py
的 0.n 版 TensorFlow 程序转换为名为 test_1.0.py
的 1.0 版 TensorFlow 程序:
$ python tf_upgrade.py --infile test.py --outfile test_1.0.py
tf_upgrade.py
脚本还会生成一个名为 report.txt
的文件,记录了其在升级过程中做的所有修改,并给出了一些可能需要您手动修改的建议。
如要将整个目录的 0.n 版 TensorFlow 程序升级为 1.0 版本,请输入如下格式的命令:
$ python tf_upgrade.py --intree InputDir --outtree OutputDir
例如,以下命令会将 /home/user/cool
中的所有 0.n 版 TensorFlow 程序转换为 1.0 版并放入新建的 /home/user/cool_1.0
目录中:
$ python tf_upgrade.py --intree /home/user/cool --outtree /home/user/cool_1.0
限制
在使用脚本进行升级时,有几点注意事项。尤其是:
- 你需要手动修复所有
tf.reverse()
实例。
tf_upgrade.py
脚本也会在屏幕输出以及report.txt
文件中警告您关于tf.reverse()
的信息。 - 如果遇上一些需要重排序的参数,
tf_upgrade.py
将会试着最小化地格式化您的代码,但不能自动地改变实际的参数顺序。因此tf_upgrade.py
将使用关键字参数,让函数参数与顺序无关。 tf.get_variable_scope().reuse_variables()
之类的构造器将失效。我们建议删除它们用以下方法代替:with tf.variable_scope(tf.get_variable_scope(), reuse=True): ...
与
tf.pack
和tf.unpack
类似,我们将TensorArray.pack
以及TensorArray.unpack
重命名为TensorArray.stack
和TensorArray.unstack
。但是,TensorArray.pack
和TensorArray.unpack
并不直接关联tf
命名空间,因而无法通过词法直接检测出来,例如foo = tf.TensorArray(); foo.unpack()
。因此需要手动修改它们。
手动升级您的代码
您也可以不使用 tf_upgrade.py
,手动升级代码。本文档剩余部分提供了完整的 TensorFlow 1.0 非向后兼容变更列表。
变量(Variables)
现在 Variable 函数更具一致性,减少了误解。
tf.VARIABLES
- 需要重命名为
tf.GLOBAL_VARIABLES
- 需要重命名为
tf.all_variables
- 需要重命名为
tf.global_variables
- 需要重命名为
tf.initialize_all_variables
- 需要重命名为
tf.global_variables_initializer
- 需要重命名为
tf.initialize_local_variables
- 需要重命名为
tf.local_variables_initializer
- 需要重命名为
tf.initialize_variables
- 需要重命名为
tf.variables_initializer
- 需要重命名为
聚合函数
现在所有的聚合函数(Summary function)都被统一放置于 tf.summary
命名空间中。
tf.audio_summary
- 需要重命名为
tf.summary.audio
- 需要重命名为
tf.contrib.deprecated.histogram_summary
- 需要重命名为
tf.summary.histogram
- 需要重命名为
tf.contrib.deprecated.scalar_summary
- 需要重命名为
tf.summary.scalar
- 需要重命名为
tf.histogram_summary
- 需要重命名为
tf.summary.histogram
- 需要重命名为
tf.image_summary
- 需要重命名为
tf.summary.image
- 需要重命名为
tf.merge_all_summaries
- 需要重命名为
tf.summary.merge_all
- 需要重命名为
tf.merge_summary
- 需要重命名为
tf.summary.merge
- 需要重命名为
tf.scalar_summary
- 需要重命名为
tf.summary.scalar
- 需要重命名为
tf.train.SummaryWriter
- 需要重命名为
tf.summary.FileWriter
- 需要重命名为
数值差异
整数除法以及 tf.floordiv
将使用向下取整(floor)语义。这样就能使 np.divide
和 np.mod
的结果与 tf.divide
和 tf.mod
的结果保持一致。另外,我们修改了 tf.round
使用的取整算法,使其与 NumPy 保持一致。
tf.div
除法
tf.divide
的语义现在已经修改与 Python 语义保持一致,即 Python 3 中的/
符号以及 Python 2 future 模块的 division 将始终得到浮点数、//
将进行求整除法。此外,tf.div
将只进行求整除法。如需使用 C 语言强制截断风格的除法运算,可以使用tf.truncatediv
。请尽量将你的代码
tf.div
改为tf.divide
,它将遵循 Python 的语义。
tf.mod
- 求余
tf.mod
的语义现在已经修改与 Python 语义保持一致。另外,对于整数的运算将使用向下取整(floor)语义。如需使用 C 语言强制截断风格的求余运算,可以使用tf.truncatemod
。
- 求余
新版和旧版的除法操作对比总结如下表所示:
表达式 | TF 0.11 (py2) | TF 0.11 (py3) | TF 1.0 (py2) | TF 1.0 (py3) |
---|---|---|---|---|
tf.div(3,4) | 0 | 0 | 0 | 0 |
tf.div(-3,4) | 0 | 0 | -1 | -1 |
tf.mod(-3,4) | -3 | -3 | 1 | 1 |
-3/4 | 0 | -0.75 | -1 | -0.75 |
-3/4tf.divide(-3,4) | N/A | N/A | -0.75 | -1 |
新版和旧版的取整操作对比总结如下表所示:
输入 | Python | NumPy | C++ round() | TensorFlow 0.11(floor(x+.5)) | TensorFlow 1.0 |
---|---|---|---|---|---|
-3.5 | -4 | -4 | -4 | -3 | -4 |
-2.5 | -2 | -2 | -3 | -2 | -2 |
-1.5 | -2 | -2 | -2 | -1 | -2 |
-0.5 | 0 | 0 | -1 | 0 | 0 |
0.5 | 0 | 0 | 1 | 1 | 0 |
1.5 | 2 | 2 | 2 | 2 | 2 |
2.5 | 2 | 2 | 3 | 3 | 2 |
3.5 | 4 | 4 | 4 | 4 | 4 |
匹配 NumPy 命名
新版本对许多函数进行了重命名以匹配 NumPy。这么做旨在使得 NumPy 与 TensorFlow 之间的转换尽量简便。虽然我们已经排除了一些常见的不一致情况,但现在还有一些函数未能完全匹配。
tf.inv
- 需要重命名为
tf.reciprocal
- 这么做是为了防止其与 NumPy 的矩阵求逆函数
np.inv
混淆
- 需要重命名为
tf.list_diff
- 需要重命名为
tf.setdiff1d
- 需要重命名为
tf.listdiff
- 需要重命名为
tf.setdiff1d
- 需要重命名为
tf.mul
- 需要重命名为
tf.multiply
- 需要重命名为
tf.neg
- 需要重命名为
tf.negative
- 需要重命名为
tf.select
- 需要重命名为
tf.where
tf.where
现在与np.where
一样,需要传入 3 个或 1 个参数
- 需要重命名为
tf.sub
- 需要重命名为
tf.subtract
- 需要重命名为
匹配 NumPy 参数
一些 TensorFlow 1.0 方法的参数现在与 NumPy 的方法相匹配了。为了实现这一点,TensorFlow 1.0 对一些关键字参数进行了修改,并对一些参数进行了重排序。需要注意的是,TensorFlow 1.0 现在不再使用 dimension
而转为使用 axis
。TensorFlow 1.0 在修改张量的操作中将保持张量参数始终在第一位。(参见 tf.concat
的改动)。
tf.argmax
- 关键字参数
dimension
需要重命名为axis
- 关键字参数
tf.argmin
- 关键字参数
dimension
需要重命名为axis
- 关键字参数
tf.concat
- 关键字参数
concat_dim
需要重命名为axis
- 输入参数重排序为
tf.concat(values, axis, name='concat')
.
- 关键字参数
tf.count_nonzero
- 关键字参数
reduction_indices
需要重命名为axis
- 关键字参数
tf.expand_dims
- 关键字参数
dim
需要重命名为axis
- 关键字参数
tf.reduce_all
- 关键字参数
reduction_indices
需要重命名为axis
- 关键字参数
tf.reduce_any
- 关键字参数
reduction_indices
需要重命名为axis
- 关键字参数
tf.reduce_join
- 关键字参数
reduction_indices
需要重命名为axis
- 关键字参数
tf.reduce_logsumexp
- 关键字参数
reduction_indices
需要重命名为axis
- 关键字参数
tf.reduce_max
- 关键字参数
reduction_indices
需要重命名为axis
- 关键字参数
tf.reduce_mean
- 关键字参数
reduction_indices
需要重命名为axis
- 关键字参数
tf.reduce_min
- 关键字参数
reduction_indices
需要重命名为axis
- 关键字参数
tf.reduce_prod
- 关键字参数
reduction_indices
需要重命名为axis
- 关键字参数
tf.reduce_sum
- 关键字参数
reduction_indices
需要重命名为axis
- 关键字参数
tf.reverse
tf.reverse
之前需要传入 1 维bool
型张量用以控制维度的顺序调换,现在使用一组轴的索引进行控制。- 例如
tf.reverse(a, [True, False, True])
现在需改为tf.reverse(a, [0, 2])
tf.reverse_sequence
- 关键字参数
batch_dim
需要重命名为batch_axis
- 关键字参数
seq_dim
需要重命名为seq_axis
- 关键字参数
tf.sparse_concat
- 关键字参数
concat_dim
需要重命名为axis
- 关键字参数
tf.sparse_reduce_sum
- 关键字参数
reduction_axes
需要重命名为axis
- 关键字参数
tf.sparse_reduce_sum_sparse
- 关键字参数
reduction_axes
需要重命名为axis
- 关键字参数
tf.sparse_split
- 关键字参数
split_dim
需要重命名为axis
- 输入参数重排序为
tf.sparse_split(keyword_required=KeywordRequired(), sp_input=None, num_split=None, axis=None, name=None, split_dim=None)
.
- 关键字参数
tf.split
- 关键字参数
split_dim
需要重命名为axis
- 关键字参数
num_split
需要重命名为num_or_size_splits
- 输入参数重排序为
tf.split(value, num_or_size_splits, axis=0, num=None, name='split')
.
- 关键字参数
tf.squeeze
- 关键字参数
squeeze_dims
需要重命名为axis
- 关键字参数
tf.svd
- 输入参数重排序为
tf.svd(tensor, full_matrices=False, compute_uv=True, name=None)
.
- 输入参数重排序为
简化数学变换
批量版数学运算操作已被移除。现在非批量版的函数已经包含了批量运算的功能。例如,tf.complex_abs
的功能已迁移至 tf.abs
tf.batch_band_part
- 需要重命名为
tf.band_part
- 需要重命名为
tf.batch_cholesky
- 需要重命名为
tf.cholesky
- 需要重命名为
tf.batch_cholesky_solve
- 需要重命名为
tf.cholesky_solve
- 需要重命名为
tf.batch_fft
- 需要重命名为
tf.fft
- 需要重命名为
tf.batch_fft3d
- 需要重命名为
tf.fft3d
- 需要重命名为
tf.batch_ifft
- 需要重命名为
tf.ifft
- 需要重命名为
tf.batch_ifft2d
- 需要重命名为
tf.ifft2d
- 需要重命名为
tf.batch_ifft3d
- 需要重命名为
tf.ifft3d
- 需要重命名为
tf.batch_matmul
- 需要重命名为
tf.matmul
- 需要重命名为
tf.batch_matrix_determinant
- 需要重命名为
tf.matrix_determinant
- 需要重命名为
tf.batch_matrix_diag
- 需要重命名为
tf.matrix_diag
- 需要重命名为
tf.batch_matrix_inverse
- 需要重命名为
tf.matrix_inverse
- 需要重命名为
tf.batch_matrix_solve
- 需要重命名为
tf.matrix_solve
- 需要重命名为
tf.batch_matrix_solve_ls
- 需要重命名为
tf.matrix_solve_ls
- 需要重命名为
tf.batch_matrix_transpose
- 需要重命名为
tf.matrix_transpose
- 需要重命名为
tf.batch_matrix_triangular_solve
- 需要重命名为
tf.matrix_triangular_solve
- 需要重命名为
tf.batch_self_adjoint_eig
- 需要重命名为
tf.self_adjoint_eig
- 需要重命名为
tf.batch_self_adjoint_eigvals
- 需要重命名为
tf.self_adjoint_eigvals
- 需要重命名为
tf.batch_set_diag
- 需要重命名为
tf.set_diag
- 需要重命名为
tf.batch_svd
- 需要重命名为
tf.svd
- 需要重命名为
tf.complex_abs
- 需要重命名为
tf.abs
- 需要重命名为
其它改动
除上文所述的改动外,还有以下一些变化:
tf.image.per_image_whitening
- 需要重命名为
tf.image.per_image_standardization
- 需要重命名为
tf.nn.sigmoid_cross_entropy_with_logits
- 输入参数重排序为
tf.nn.sigmoid_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, name=None)
.
- 输入参数重排序为
tf.nn.softmax_cross_entropy_with_logits
- 输入参数重排序为
tf.nn.softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, dim=-1, name=None)
.
- 输入参数重排序为
tf.nn.sparse_softmax_cross_entropy_with_logits
- 输入参数重排序为
tf.nn.sparse_softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, name=None)
.
- 输入参数重排序为
tf.ones_initializer
- 需要修改成函数调用,例如
tf.ones_initializer()
- 需要修改成函数调用,例如
tf.pack
- 需要重命名为
tf.stack
- 需要重命名为
tf.round
tf.round
的语义现在与银行家舍入法(Banker's rounding)相同。
tf.unpack
- 需要重命名为
tf.unstack
- 需要重命名为
tf.zeros_initializer
- 需要修改成函数调用,例如
tf.zeros_initializer()
- 需要修改成函数调用,例如