TensorFlow 2.0 新增变化特性

image

文章内容由实验楼提供 Jupyter Notebook 线上实验环境


TensorFlow 2.0 版本现已推出,相对于 1.x 版本在很多地方都有较大的变动。文章中,我们将了解并学习 TensorFlow 2.0 的一些新的特征,同时熟悉一些常用的新 API 方法。

学习此课程的前提是已了解并使用过 TensorFlow 1.x。

TensorFlow 2.0 安装

2019 年初,TensorFlow 官方推出了 2.0 预览版本,也意味着 TensorFlow 即将从 1.x 过度到 2.x 时代。

image

根据 TensorFlow 显示,2.0 版本将专注于简洁性和易用性的改善,主要升级方向包括:

  • 使用 Keras 和 Eager Execution 轻松构建模型。
  • 在任意平台上实现稳健的生产环境模型部署。
  • 为研究提供强大的实验工具。
  • 通过清理废弃的 API 和减少重复来简化 API。

接下来,我们就通过实际的例子,来看看 TensorFlow 2.0 到底有哪些改进和变化。

目前,TensorFlow 2.0 仅有预览版,你需要通过 pip install tf-nightly-2.0-preview 进行安装。线上环境中,我们需要先卸载老版本,然后再安装 TensorFlow 2.0。

pip uninstall tensorflow -y  # 卸载 TensorFlow 1.x
pip install tf-nightly-2.0-preview  # 安装 TensorFlow 2.0

接下来,加载 TensorFlow 并查看版本号,看是否已经为 2.x。

import tensorflow as tf

tf.__version__
'2.0.0-dev20190401'

Eager Execution

TensorFlow 2.0 带来的最大改变之一是将 1.x 的 Graph Execution(图与会话机制)更改为 Eager Execution(动态图机制)。在 1.x 版本中,低级别 TensorFlow API 首先需要定义数据流图,然后再创建 TensorFlow 会话,这一点在 2.0 中被完全舍弃。

TensorFlow 2.0 中的 Eager Execution 是一种命令式编程环境,可立即评估操作,无需构建图:操作会返回具体的值,而不是构建以后再运行的计算图。实际上,Eager Execution 在 1.x 的后期版本中也存在,但需要单独执行 tf.enable_eager_execution() 进行手动启用。不过,2.0 版本的 TensorFlow 默认采用了 Eager Execution,无法关闭并回到 1.x 的 Graph Execution 模式中。

下面,我们来演示 Eager Execution 带来的变化。

1.x 版本中,如果我们新建一个张量 tf.Variable([[1, 2], [3, 4]]) 并执行输出,那么只能看到这个张量的形状和属性,并不能直接输出其数值。结果如下:

<tf.Variable 'Variable:0' shape=(2, 2) dtype=int32_ref>

如今,Eager Execution 模式下则可以直接输出张量的数值了,并以 NumPy 数组方式呈现。

c = tf.Variable([[1, 2], [3, 4]])
c
<tf.Variable 'Variable:0' shape=(2, 2) dtype=int32, numpy=
array([[1, 2],
       [3, 4]], dtype=int32)>

你还可以直接通过 .numpy() 输出张量的 NumPy 数组。Eager Execution 适合与 NumPy 一起使用。NumPy 操作接受 tf.Tensor 参数。TensorFlow 数学运算将 Python 对象和 NumPy 数组转换为 tf.Tensor 对象。tf.Tensor.numpy 方法返回对象的值作为 NumPy ndarray。

c.numpy()
array([[1, 2],
       [3, 4]], dtype=int32)

Eager Execution 带来的好处是不再需要手动管理图和会话。例如,现在使用示例张量进行数学计算,可以像 Python 一样直接相加。

c + c  # 加法计算
<tf.Tensor: id=14, shape=(2, 2), dtype=int32, numpy=
array([[2, 4],
       [6, 8]], dtype=int32)>

而在 1.x 版本中,我们需要初始化全局变量 → 建立会话 → 执行计算,最终才能打印出张量的运算结果。

init_op = tf.global_variables_initializer()  # 初始化全局变量
with tf.Session() as sess:  # 启动会话
    sess.run(init_op)
    print(sess.run(c + c))  # 执行计算

Eager Execution 带来的好处显而易见,其进一步降低了 TensorFlow 的入门门槛。之前,因为图与会话的模式,让很多人在入门时都很纳闷。除此之外,得益于自动微分的使用,在 Eager Execution 期间,可以使用 tf.GradientTape 这类跟踪操作以便稍后计算梯度。

w = tf.Variable([[1.0]])  # 新建张量

with tf.GradientTape() as tape:  # 追踪梯度
    loss = w * w

grad = tape.gradient(loss, w)  # 计算梯度
grad
<tf.Tensor: id=31, shape=(1, 1), dtype=float32, numpy=array([[2.]], dtype=float32)>

tf.GradientTape 会像磁带一样记录下计算图中的梯度信息,然后使用 .gradient 即可回溯计算出任意梯度,这对于使用 TensorFlow 低阶 API 构建神经网络时更新参数非常重要。

Eager Execution 的好处很多,但带来的问题也是很明显的,尤其是对于已经熟练使用 TensorFlow 的工程师而言简直是噩梦。

如今,TensorFlow 的默认执行模式为 Eager Execution,这就意味着之前基于 Graph Execution 构建的代码将完全无法使用,因为 2.0 中已经没有了相应的 API。例如,先前构建神经网络计算图时,都习惯于使用 tf.placeholder 占位符张量,等最终执行时再传入数据。Eager Execution 模式下,tf.placeholder 已无存在必要,所以此 API 已被移除。

所以,随着 TensorFlow 2.0 默认引入 Eager Execution 机制,也就意味着原 1.x 低阶 API 构建图的方法后续已无法使用。

TensorFlow Keras

TensorFlow 1.x 中,我们可以通过 tf.layers 高阶层封装开快速搭建神经网络。如果,2.0 已完全移除了 tf.layers 模块,转而引入了 tf.keras

如果你熟悉 Keras 的使用,那么 tf.keras 用起来就得心应手了,因为其基本和单独发行版本一致,子模块结构也几乎完全一样。除此之外,原 tf.contrib 也已经在 2.0 版本中被移除。

其他变化

TensorFlow 2.0 带来的更多变化,请详细阅读 。除此之外,官方也已经更新

为了便于开发者将 TensorFlow 1.x 代码转移到 TensorFlow 2.0 中执行,官方给出了一个 。根据我的测试,此脚本仅仅是将一些在 TensorFlow 2.0 中被删除的 API 使用过度模块 tensorflow.compat.v1 下方的方法给替代,同时原来建立会话相关的代码并无法自动转换为 Eager Execution 模式。

所以,如果想要把 TensorFlow 1.x 代码转移到 TensorFlow 2.0 中,还是需要花费一定的时间进行重构。

系列文章