最早可追溯到TensorFlow1.10版本,那时TensorFlow由于强大的深度学习计算能力被众多的深度学习从业人员使用和称道。但是盛名之下还是有一些小的缺点让人诟病,例如程序编写的困难、代码格式和其他深度学习框架有较大差异、运行时占用资源较多等。
TensorFlow开发组为了解决这些问题,在TensorFlow1.10版本中就引入了一种新的程序运行机制—TensorFlow Eager Execution(动态图机制)。其目的是为了解决所有程序开发人员使用TensorFlow作为深度学习框架时学习坡度不是很友善的问题,同时也是为了增加程序编写的便利性。结果一经推出就大受好评,使得很多原先使用别的机器学习框架的程序编写人员、机器学习爱好者投入TensorFlow的怀抱中。
TensorFlow Eager Execution是一个命令式的编程环境,不是建立图而是立即运算求值:运算返回具体值,替换了以前那种先构建运算图然后执行的机制,使得使用TensorFlow和调试模型变得简单,而且减少了多余的模板化、公式化的操作。根据指南,可以在交互式Python的解释器中运行各种样例程序。
动态图机制是一个灵活的机器学习平台,用于研究和实验,它提供了以下功能:
TensorFlow的开发团队曾表示,Eager Execution的主要优点如下:
Eager Execution的调用非常简单,直接使用如下代码即可:
import tensorflow as tf
这是因为在TensorFlow 2.0中,Eager Execution是默认开启的,所以直接引入TensorFlow即可。
在TensorFlow 1.x版本中,Eager Execution需要手动开启,代码如下:
这些代码是在1.x版本中开启Eager Execution的方法,首先在第1行中导入TensorFlow,然后在第2行和第3行中开启Eager模式,使之可以在本段代码中使用。
除此之外,如果安装了TensorFlow 2.0或者以后版本,对于在1.x版本下编写的代码可能会产生一些问题,因此需要重新开启TensorFlow 1.x的运行模式,在导入TensorFlow的时候修改代码:
import tensorflow.compat.v1 as tf tf.disable_v2_behavior()
导入TensorFlow 1.x版本同时禁用2.0版本。
Eager Execution有一个非常有意思并作为宣传点的功能,就是允许用户在不创建图(Graph)的情况下使用TensorFlow代码。代码段如下:
【程序2-1】
import tensorflow as tf data = tf.constant([1,2]) print(data)
这段代码默认启动了Eager模式,再使用TensorFlow读入一个序列后将其打印输出,结果如下:
可以看到,打印输出了读入数据后的Tensor数据格式,即具体数值为[1,2],维度大小为2,数据类型为int32。
如果此时需要将它的具体内容打印出来,则可以改成如下程序。
【程序2-2】
import tensorflow as tf data = tf.constant([1,2]) print(data.numpy())
该程序运行的结果如下:
可以看到,此时由于加上了数据自带的numpy()函数,Tensor数据被转化为常用的NumPy数据格式,即常数格式。
这里顺带提一下,使用传统的TensorFlow编写模式可修改代码为如下程序。
【程序2-3】
import tensorflow.compat.v1 as tf tf.disable_v2_behavior() data = tf.constant([1,2]) print(data)
该程序运行的结果如下:
可以看到,此时数据被读入到图中而非被直接计算,因此打印出的结果并没有具体数据。具体数据的计算请读者自行完成。
传统的TensorFlow 1.x数据的读取是采用占位符的形式,首先将数据读取到内存中,之后建立整体的TensorFlow图,在运行图以后将数据读取并显示。
TensorFlow 2.0简化了数据的读取,类似NumPy的数据迭代风格,只使用TensorFlow中自带的Dataset API即可完成数据的迭代。
import numpy as np arr_list = np.arange(0,100) shape = arr_list.shape
上述代码使用NumPy生成数据,产生了100个由0到99的数据并存储在arr_list中。
dataset = tf.data.Dataset.from_tensor_slices(arr_list) dataset_iterator = dataset.shuffle(shape[0]).batch(10)
这里首先使用Dataset.from_tensor_slices读取数据,之后使用shuffle函数打乱顺序,最终将数据以10个为一批进行输出。
创建计算模型是数据处理的关键。这里为了简化起见创建了一个非常简单的模型,即使用TensorFlow将输入的数据乘以0.1并输出,代码如下:
def model(xs): # ... 编写一些函数 outputs = tf.multiply(xs,0.1) return outputs
model内是一个简单函数的实现,有兴趣的读者可以添加更多的内容。
在Eager模式中,Dataset API可以自动生成一个新的迭代器,将数据迭代出来。代码如下:
for it in dataset_iterator: logits = model(it) print(logits)
这样就构造了一个完整的使用Eager模型进行简单数据计算的模型,全部代码如下:
【程序2-4】
import tensorflow as tf import numpy as np arr_list = np.arange(0,100).astype(np.float32) shape = arr_list.shape dataset = tf.data.Dataset.from_tensor_slices(arr_list) dataset_iterator = dataset.shuffle(shape[0]).batch(10) def model(xs): # ... 编写一些函数 outputs = tf.multiply(xs,0.1) return outputs for it in dataset_iterator: logits = model(it) print(logits)
该程序的运行结果如图2.2所示。
图2.2 程序2-4的运行结果
打印输出的结果显然不符合在程序中既定的模型,即将数列中的数乘以0.1并显示,而这里的输出数据却都是0。
究其原因是在NumPy数据生成的时候是以int32格式作为数据的基本生成格式,因此Eager在进行计算时无法隐式地将数据转化成float类型,从而造成计算失败。
解决的办法也很方便,将数据生成代码改成为如下形式即可:
arr_list = np.arange(0,100).astype(np.float32)
具体内容请读者自行完成。