Copyright 2018 The TensorFlow Authors.
Eager Execution
TensorFlow 的 Eager Execution 是一种命令式编程环境,可立即评估运算,无需构建计算图:运算会返回具体的值,而非构建供稍后运行的计算图。这样能使您轻松入门 TensorFlow 并调试模型,同时也减少了样板代码。要跟随本指南进行学习,请在交互式 python
解释器中运行以下代码示例。
Eager Execution 是用于研究和实验的灵活机器学习平台,具备以下特性:
直观的界面 - 自然地组织代码结构并使用 Python 数据结构。快速迭代小模型和小数据。
更方便的调试功能 - 直接调用运算以检查正在运行的模型并测试更改。使用标准 Python 调试工具立即报告错误。
自然的控制流 - 使用 Python 而非计算图控制流,简化了动态模型的规范。
Eager Execution 支持大部分 TensorFlow 运算和 GPU 加速。
注:启用 Eager Execution 后可能会增加某些模型的开销。我们正在持续改进其性能,如果您遇到问题,请提交错误报告并分享您的基准。
设置和基本用法
在 Tensorflow 2.0 中,默认启用 Eager Execution。
现在您可以运行 TensorFlow 运算,结果将立即返回:
启用 Eager Execution 会改变 TensorFlow 运算的行为方式 - 现在它们会立即评估并将值返回给 Python。tf.Tensor
对象会引用具体值,而非指向计算图中节点的符号句柄。由于无需构建计算图并稍后在会话中运行,可以轻松使用 print()
或调试程序检查结果。评估、输出和检查张量值不会中断计算梯度的流程。
Eager Execution 可以很好地配合 NumPy 使用。NumPy 运算接受 tf.Tensor
参数。TensorFlow tf.math
运算会将 Python 对象和 NumPy 数组转换为 tf.Tensor
对象。tf.Tensor.numpy
方法会以 NumPy ndarray
的形式返回该对象的值。
动态控制流
Eager Execution 的一个主要优势是,在执行模型时,主机语言的所有功能均可用。因此,编写 fizzbuzz 之类的代码会很容易:
这段代码具有依赖于张量值的条件语句并会在运行时输出这些值。
Eager 训练
训练模型
以下示例创建了一个多层模型,该模型会对标准 MNIST 手写数字进行分类。示例演示了在 Eager Execution 环境中构建可训练计算图的优化器和层 API。
即使没有训练,也可以在 Eager Execution 中调用模型并检查输出:
虽然 Keras 模型有内置训练循环(使用 fit
方法),但有时您需要进行更多自定义。下面是一个使用 Eager Execution 实现训练循环的示例:
注:请在 tf.debugging
中使用断言函数检查条件是否成立。这在 Eager Execution 和计算图执行中均有效。
变量和优化器
tf.Variable
对象会存储在训练期间访问的可变、类似于 tf.Tensor
的值,以更简单地实现自动微分。
变量的集合及其运算方法可以封装到层或模型中。有关详细信息,请参阅自定义 Keras 层和模型。层和模型之间的主要区别在于模型添加了如下方法:Model.fit
、Model.evaluate
和 Model.save
。
例如,上面的自动微分示例可以改写为:
下一步:
创建模型。
损失函数对模型参数的导数。
基于导数的变量更新策略。
注:变量将一直存在,直至删除对 Python 对象的最后一个引用,并删除该变量。
基于对象的保存
tf.keras.Model
包括一个方便的 save_weights
方法,您可以通过该方法轻松创建检查点:
您可以使用 tf.train.Checkpoint
完全控制此过程。
本部分是检查点训练指南的缩略版。
要保存和加载模型,tf.train.Checkpoint
会存储对象的内部状态,而无需隐藏变量。要记录 model
、optimizer
和全局步骤的状态,请将它们传递到 tf.train.Checkpoint
:
注:在许多训练循环中,会在调用 tf.train.Checkpoint.restore
后创建变量。这些变量将在创建后立即恢复,并且可以使用断言来确保检查点已完全加载。有关详细信息,请参阅检查点训练指南。
面向对象的指标
tf.keras.metrics
会被存储为对象。可以通过将新数据传递给可调用对象来更新指标,并使用 tf.keras.metrics.result
方法检索结果,例如:
摘要和 TensorBoard
TensorBoard 是一种可视化工具,用于了解、调试和优化模型训练过程。它使用在执行程序时编写的摘要事件。
您可以在 Eager Execution 中使用 tf.summary
记录变量摘要。例如,要每 100 个训练步骤记录一次 loss
的摘要,请运行以下代码:
自定义梯度
自定义梯度是重写梯度的一种简单方法。在前向函数中,定义相对于输入、输出或中间结果的梯度。例如,下面是在后向传递中裁剪梯度范数的一种简单方法:
自定义梯度通常用来为运算序列提供数值稳定的梯度:
在此例中,log1pexp
函数可以通过自定义梯度进行分析简化。下面的实现重用了在前向传递期间计算的 tf.exp(x)
值,通过消除冗余计算使其变得更加高效:
性能
在 Eager Execution 期间,计算会自动分流到 GPU。如果想控制计算运行的位置,可将其放在 tf.device('/gpu:0')
块(或 CPU 等效块)中:
可以将 tf.Tensor
对象复制到不同设备来执行其运算:
基准
对于计算量繁重的模型(如在 GPU 上训练的 ResNet50),Eager Execution 性能与 tf.function
执行相当。但是对于计算量较小的模型来说,这种性能差距会越来越大,并且在为有大量小运算的模型优化热代码路径方面,其性能还有待提升。
使用函数
虽然 Eager Execution 增强了开发和调试的交互性,但 TensorFlow 1.x 样式的计算图执行在分布式训练、性能优化和生产部署方面具有优势。为了弥补这一差距,TensorFlow 2.0 通过 tf.function
API 引入了 function
。有关详细信息,请参阅 tf.function 指南。