文章目录

  • 1. Eager Execution 简介
    • 1.1 eager execution 引入
    • 1.2 理解eager execution
    • 1.3 eager execution优缺点
  • 2. eager execution用法
    • 2.1 开启eager模式
    • 2.1 eager execution 和 numpy
  • 3. 动态控制流程
  • 4. 建模
  • 5. Eager训练
    • 5.1 梯度计算
    • 5.2 变量和优化
  • 6. 使用 python 对象来存储程序状态
    • 6.1 变量都是对象
    • 6.2 基于对象的保存
    • 6.3 Summaries 和 TensorBoard
  • 7. 自动微分
    • 7.1 动态模型
    • 7.2 计算梯度的方法
      • 7.2.1 tfe.gradients_function
      • 7.2.2 tfe.value_and_gradients_function
    • 7.3 定制梯度

1. Eager Execution 简介

1.1 eager execution 引入

"即时计算"模式,即eager 模式是在 TF 1.4 版本之后引入的,并在TF2.0+将eager模式便成为默认执行模式

1.2 理解eager execution

自己理解,eager 模式就是类似于 python 这样的命令式编程,写好程序之后,不需要编译,就可以直接运行了(其实是一边建图一边计算,不具有复用性),而且非常直观;而之前的静态图模式则类似于 c/c++ 的声明式编程。写好程序之后要先编译(搭建好静态计算图),然后才能运行。

1.3 eager execution优缺点

优点

  • eager 模式提供了更直观的接口,可以像写 python 代码一样写模型;
  • 更方便调试,这个应该是不言而喻的,如果同时调试过 python 和 c++ 就知道有多方便了;
  • 自然的控制流程,像编写 python 程序一样;

当然就像 python 一直被诟病的速度慢的问题以及不适合做大的工程的问题,eager 模式也具有类似的问题:

缺点

  • 速度问题:对于有很大计算量的模型,比如在 GPU 上训练 ResNet50,eager 模式和通过 graph 模式构造的模型没有太大的差异,但是这个差异却随着计算量减小而扩大(也就是说,如果模型越简单,通过 eager 模式构造的模型速度上要比通过 graph 构造的模型慢)
  • 分布式训练、性能优化以及线上部署:通过 graph 构造的模型在分布式训练、性能优化以及线上部署上有优势;

建议

eager 模式支持大多数的 TF 操作和 GPU 加速;TF 官方的一些例子可以参考:https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/eager/python/examples

基于此,官方给的建议是:同时写 eager 模式代码和 graph 模式代码,使用 eager 模式快速调试和 debug,然后利用 graph 模式在分布式训练方面的优势部署;

2. eager execution用法

如果 TF 版本在 1.4 以下,使用如下方式进行升级:

pip install --upgrade tensorflow

2.1 开启eager模式

import tensorflow as tf
tf.enable_eager_execution()tf.executing_eagerly()        # => Truex = [[2.]]
m = tf.matmul(x, x)
print("hello, {}".format(m))  # => "hello, [[4.]]"

eager 模式下,操作会立刻执行并返回实际值。在这里 tf.Tensor 对象会是一个实际值而不是 graph 模式下的 Tensor 结构(这个 Tensor 结构主要包含了三个属性:名字、维度和类型,而且只有运行 graph 的时候,Tensor 才会有真实的值);

2.1 eager execution 和 numpy

eager 模式下对 numpy 的支持很友好。具体有如下三个特性:

  • numpy 的操作可以接受 Tensor 作为参数;
  • TF 的数学操作会将 python 对象和 numpy 的 arrays 转换成 Tensor;
  • tf.Tensor.numpy 方法返回 numpy 的 ndarray;

直接看官方的例子即可:

a = tf.constant([[1, 2],[3, 4]])
print(a)
# => tf.Tensor([[1 2]
#               [3 4]], shape=(2, 2), dtype=int32)# Broadcasting support
b = tf.add(a, 1)
print(b)
# => tf.Tensor([[2 3]
#               [4 5]], shape=(2, 2), dtype=int32)# Operator overloading is supported
print(a * b)
# => tf.Tensor([[ 2  6]
#               [12 20]], shape=(2, 2), dtype=int32)# Use NumPy values
import numpy as npc = np.multiply(a, b)
print(c)
# => [[ 2  6]
#     [12 20]]# Obtain numpy value from a tensor:
print(a.numpy())
# => [[1 2]
#     [3 4]]

3. 动态控制流程

这是 eager 模式的主要特性,就是像写 python 代码一样写 TF 代码,而且可以随时通过 print 来进行调试;

一个 fizzbuzz 示例:

def fizzbuzz(max_num):counter = tf.constant(0)max_num = tf.convert_to_tensor(max_num)for num in range(max_num.numpy()):num = tf.constant(num)if int(num % 3) == 0 and int(num % 5) == 0:print('FizzBuzz')elif int(num % 3) == 0:print('Fizz')elif int(num % 5) == 0:print('Buzz')else:print(num)counter += 1return counter

4. 建模

模型一般由多层组成,你可以自定义层,也可以使用 tf.keras.layers 提供的 layers。或者继承 tf.keras.layers.Layer 基类来实现自己的 layer;

代码如下:

lass MySimpleLayer(tf.keras.layers.Layer):def __init__(self, output_units):super(MySimpleLayer, self).__init__()self.output_units = output_unitsdef build(self, input_shape):# 在第一次使用 layer 的时候才会调用 build 方法,因此定义在 build 下面的 input_shape 可以动态指定,当然,如果你知道具体的 layer 大小,也可以在 __init__ 方法中直接指定;self.kernel = self.add_variable("kernel", [input_shape[-1], self.output_units])def call(self, input):# Override call() instead of __call__ so we can perform some bookkeeping.return tf.matmul(input, self.kernel)

当然也可以使用 tf.keras.layers.Dense 和 tf.keras.Sequential 来组织模型:

model = tf.keras.Sequential([
tf.keras.layers.Dense(10, input_shape=(784,)), # must declare input shape
tf.keras.layers.Dense(10)
])

而且,你也可以使用 python 的类(继承 tf.keras.Model)配合 tf.keras.layers 建模;

class MNISTModel(tf.keras.Model):def __init__(self):super(MNISTModel, self).__init__()self.dense1 = tf.keras.layers.Dense(units=10)self.dense2 = tf.keras.layers.Dense(units=10)def call(self, input):"""Run the model."""result = self.dense1(input)result = self.dense2(result)result = self.dense2(result)  # reuse variables from dense2 layerreturn resultmodel = MNISTModel()

5. Eager训练

5.1 梯度计算

在 eager 模式中,可以使用 tf.GradientTape 来跟踪记录操作;Tape 是磁带的意思,因此可以这样理解,在前向计算的时候,相关操作会记录到 Tape 上,然后反向播放 Tape 即可计算梯度;一个特定的 tf.GradientTape 只能计算一个梯度,再一次调用就会报错;

简单的示例:

w = tf.Variable([[1.0]])
# 前向计算,得到 loss
with tf.GradientTape() as tape:loss = w * wgrad = tape.gradient(loss, w)
print(grad)  # => tf.Tensor([[ 2.]], shape=(1, 1), dtype=float32)

5.2 变量和优化

可以用类将模型封装,模型的参数作为类的参数

以3*x+2

class Model(tf.keras.Model):def __init__(self):super(Model, self).__init__()self.W = tf.Variable(3., name='weight')self.B = tf.Variable(2., name='bias')def call(self, inputs):return inputs * self.W + self.B

6. 使用 python 对象来存储程序状态

在 graph 模式中,程序状态(比如变量)是被存储在一个全局集合中,生命周期是由 tf.Session 管理的。eager 模式中,程序状态的生命周期是由其对应的 python 对象来决定的

6.1 变量都是对象

eager 模式下,直到引用该变量的最后一个对象被移除,变量才会被删除;

示例代码:

with tf.device("gpu:0"):v = tf.Variable(tf.random_normal([1000, 1000]))v = None  # v no longer takes up GPU memory

6.2 基于对象的保存

tf.train.Checkpoint 可以保存和恢复 tf.Variable,tf.keras.Model等;
参考文章:https://blog.csdn.net/weixin_44441131/article/details/121626669

6.3 Summaries 和 TensorBoard

tf.contrib.summary 兼容 eager execution 模式和 graph 模式

比如,每 100 步记录一下 summaries

global_step = tf.train.get_or_create_global_step()
writer = tf.contrib.summary.create_file_writer(logdir)
writer.set_as_default()for _ in range(iterations):global_step.assign_add(1)# Must include a record_summaries methodwith tf.contrib.summary.record_summaries_every_n_global_steps(100):# your model code goes heretf.contrib.summary.scalar('loss', loss)...

7. 自动微分

7.1 动态模型

tf.GradientTape 可以用在动态模型中,下面的示例是:backtracking line search 算法,看起来就像普通的 numpy 代码,但是这里包含了梯度计算和自动微分:

def line_search_step(fn, init_x, rate=1.0):with tf.GradientTape() as tape:# Variables are automatically recorded, but manually watch a tensortape.watch(init_x)value = fn(init_x)grad = tape.gradient(value, init_x)grad_norm = tf.reduce_sum(grad * grad)init_value = valuewhile value > init_value - rate * grad_norm:x = init_x - rate * gradvalue = fn(x)rate /= 2.0return x, value

7.2 计算梯度的方法

除了 tf.GradientTape 方法之外,还有一些其他的自动微分的方法。如果直接计算数学公式的梯度(数学公式中只有 Tensor,没有 tf.Variables),那么这些方法会很有用;

7.2.1 tfe.gradients_function

  • 输入是一个函数;
  • 输出该函数的梯度函数(其实就是一个求导后的函数),给定输入这个梯度函数会自动计算梯度,返回的是一个 list,其中的每一个元素是输入参数对应的梯度;

注:这里说的有点绕,还是直接看代码吧:

def square(x):return tf.multiply(x, x)grad = tfe.gradients_function(square)square(3.)  # => 9.0
grad(3.)    # => [6.0]def square2(x, y):return tf.multiply(x, x) + tf.multiply(y, y)grad = tfe.gradients_function(square2)
square2(3., 2.) # => 13
grad(3., 2.)    # => 6, 4# The second-order derivative of square:
gradgrad = tfe.gradients_function(lambda x: grad(x)[0])
gradgrad(3.)  # => [2.0]# The third-order derivative is None:
gradgradgrad = tfe.gradients_function(lambda x: gradgrad(x)[0])
gradgradgrad(3.)  # => [None]# With flow control:
def abs(x):return x if x > 0. else -xgrad = tfe.gradients_function(abs)grad(3.)   # => [1.0]
grad(-3.)  # => [-1.0]

7.2.2 tfe.value_and_gradients_function

梯度函数输出的时候会带上 value(输入函数计算出来的),示例代码如下:

def square(x, y):return tf.multiply(x, x) + tf.multiply(y, y)grad = tfe.value_and_gradients_function(square)
print(square(3., 2.))
print(grad(3., 2.))

示例输出:

tf.Tensor(13.0, shape=(), dtype=float32)
(<tf.Tensor: id=13, shape=(), dtype=float32, numpy=13.0>, [<tf.Tensor: id=19, shape=(), dtype=float32, numpy=6.0>, <tf.Tensor: id=20, shape=(), dtype=float32, numpy=4.0>])

7.3 定制梯度

@tf.custom_gradient 方式可以对梯度进行一下定制,通常的用法是提供一个更平滑的梯度(防止梯度爆炸),比如约束梯度的 l2 范数;
代码示例:

@tf.custom_gradient
def clip_gradient_by_norm(x, norm):y = tf.identity(x)def grad_fn(dresult):return [tf.clip_by_norm(dresult, norm), None]return y, grad_fn

上面这种方式会因为数值计算的不稳定性导致结果为 nan,通过定制梯度可以解决这种问题

@tf.custom_gradient
def log1pexp(x):e = tf.exp(x)def grad(dy):# 梯度规约return dy * (1 - 1 / (1 + e))return tf.log(1 + e), gradgrad_log1pexp = tfe.gradients_function(log1pexp)# As before, the gradient computation works fine at x = 0.
grad_log1pexp(0.)  # => [0.5]# And the gradient computation also works at x = 100.
grad_log1pexp(100.)  # => [1.0]

更多性能、和graph模式一起工作参考https://zhuanlan.zhihu.com/p/47201474

【TF2】Eager Execution机制相关推荐

  1. 【深度学习】村通网之——谈谈Tensorflow Eager Execution机制之新特性示例(二)

    文章目录 前言 直接使用operation进行卷积操作 自动计算梯度(导数) 计算所有参数的梯度 计算所有变量的梯度 使用Python程序流程控制模型流程 自动优化 前言 本文是[深度学习]村通网之- ...

  2. 【深度学习】村通网之——谈谈Tensorflow Eager Execution机制之静态图和动态图的区别(一)

    文章目录 前言 介绍 搭建静态图 搭建动态图 前言 随着TensorFlow 1.4 Eager Execution的出现,TensorFlow的使用出现了革命性的变化. 介绍 我很早就听说过这样一句 ...

  3. 独家 | TensorFlow 2.0将把Eager Execution变为默认执行模式,你该转向动态计算图了...

    机器之心报道 作者:邱陆陆 8 月中旬,谷歌大脑成员 Martin Wicke 在一封公开邮件中宣布,新版本开源框架--TensorFlow 2.0 预览版将在年底之前正式发布.今日,在上海谷歌开发者 ...

  4. tensorflow教程 学习笔记 之 Eager execution 急切执行

    链接:https://tensorflow.juejin.im/get_started/ 学习它主要为了解决yunyang tensorflow-yolov-3GPU多线程调用的问题 文章目录 坑1 ...

  5. TensorFlow推出命令式、可定义的运行接口Eager Execution

    安妮 编译自 Google Research Blog 量子位 出品 | 公众号 QbitAI 今天凌晨,谷歌宣布推出TensorFlow的eager execution.这是一个命令式的.可定义的运 ...

  6. Tensorflow学习——Eager Execution

    Eager Execution 目录 1.设置和基本用法 2.动态控制流 3.构建模型 4.Eager训练 计算梯度 训练模型 变量和优化器 5.在Eager Execution期间将对象用于状态 变 ...

  7. RuntimeError: iter() is only supported inside of tf.function or when eager execution is enabled.

    这是由于程序中用到了动态图机制,允许不创建静态图的情况下执行程序,对于 Tensorflow 2.0 以下的版本,需要在 import tensorflow 后,调用 tf.enable_eager_ ...

  8. 在tensorflow2.0下遇到1.x版本中占位符不兼容问题 tf.placeholder() is not compatible with eager execution的解决方法

    1 在代码中添加这样一句: tf.compat.v1.disable_eager_execution() 2  在代码中所有用 placeholder的地方修改为 tf.compat.v1.place ...

  9. RuntimeError: __iter__() is only supported inside of tf.function or when eager execution is enabled.

    使用tensorflow1.5.1出现如下报错: 根据其他博客的报错分析添加链接描述,由于我所用的tensorflow为1.5.1版本,在import tensorflow as tf后添加tf.en ...

最新文章

  1. IDEA快速入门(Mac版)
  2. 饿了么监控平台的架构设计与演进历程
  3. git创建本地分支、提交到远程分支
  4. Foundatio - .Net Core用于构建分布式应用程序的可插拔基础块
  5. 2020.7.20-每日进步
  6. bzoj 3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(状压+BFS)
  7. C语言中指针数组和数组指针
  8. 软件技术专业-就业提示(一、实施工程师)
  9. smart 3D 使用教程 笔记
  10. 记录:SpringBoot 开发之集成微信公众号支付
  11. Windows上免费轻量好用的软件(不定期更新)
  12. 三、Linux 教程-基础命令(181~完)
  13. 商标起名禁区,看了少走弯路
  14. 使用Python遍历文件夹下文件寻找关键词
  15. Java容器类 Collection (set list queue)和map
  16. 攻防世界之Miscellaneous-300
  17. 字符串解压缩类库(zip、GZIP、QuickLz、snappy、lzf、jzlib)性能对比
  18. 遥感影像匀色镶嵌分幅处理
  19. Wordpress 所有 hook 钩子
  20. python生成html报告

热门文章

  1. oracle的ofs,WINDOWS+MSCS+ORACLE+OFS
  2. oracle的 listagg() WITHIN GROUP () 函数使用
  3. Ubuntu上打开windows共享文件夹进行读写操作的命令
  4. 无法加载DLL:找不到指定模块 问题解决办法
  5. 5.23 通过自定义筛选查找指定城市的指定工作人员 [原创Excel教程]
  6. 基于Xlinx的时序分析与约束(1)----什么是时序分析?什么是时序约束?什么又是时序收敛?
  7. php 项目反应理论,科学网—好文 | 纽约石溪大学:机器学习中基于项目反应理论的集成学习 - 陈培颖的博文...
  8. SVG 图标制作指南
  9. 微商分销系统哪家好,要怎么做?
  10. 第四章USB数据流模型