TensorFlow 和 Keras 入门:过去 (TF1) 现在 (TF2)
Posted
技术标签:
【中文标题】TensorFlow 和 Keras 入门:过去 (TF1) 现在 (TF2)【英文标题】:Primer on TensorFlow and Keras: The past (TF1) the present (TF2) 【发布时间】:2020-03-25 12:11:36 【问题描述】:这个问题的目的是要求提供一个最基本的指南,以帮助人们快速了解 TensorFlow 1 和 TensorFlow 2。我觉得没有一个连贯的指南来解释 TF1 和 TF2 之间的差异,而 TF 有经历了重大修订并迅速发展。
我说的时候供参考,
v1 或 TF1 - 我指的是 TF 1.15.0 v2 或 TF2 - 我指的是 TF 2.0.0我的问题是,
TF1/TF2 是如何工作的?它们的主要区别是什么?
TF1 和 TF2 中有哪些不同的数据类型/数据结构?
什么是 Keras 以及它如何适应所有这些? Keras 提供了哪些不同的 API 来实现深度学习模型?你能提供每个例子吗?
在使用 TF 和 Keras 时,我需要注意哪些经常出现的警告/错误?
TF1 和 TF2 的性能差异
【问题讨论】:
您似乎在使用 SO,就好像它是一个论坛,但它不是,它是一个问答网站。这里有什么问题? 嗨@MatiasValdenegro,感谢您的评论,我希望在这里提供一个答案,我想看看我是否是TensorFlow初学者(遵循guide)。问题是在底部列出的要点。这些问题似乎难以掌握/混淆(根据我的经验和 SO 问题)。但是,如果您看到可以改进以使其更适合的任何内容,我很乐意编辑/更改任何需要的内容。 不错的文章;作为提示,请尝试将这些问答框架作为问答 - 原始帖子应包含一个问题或一些待解决的问题 .这样,没有人会抱怨——这只是使用系统的一个技巧。例如,我可以轻松地将this question 写成“这篇文章是为了向您展示如何在 Keras 中可视化内容”——但这很可能会被扔进垃圾桶。 【参考方案1】:TF1/TF2 是如何工作的?以及他们的区别
TF1
TF1 遵循一种称为先定义后运行的执行方式。这与运行时定义相反,例如 Python 执行风格。但是,这是什么意思?定义然后运行意味着,仅仅因为你调用/定义了一些它没有执行的东西。您必须明确执行您定义的内容。
TF 有一个 Graph 的概念。首先,您定义所有需要的计算(例如,神经网络的所有层计算、损失计算和最小化损失的优化器 - 这些表示为 ops 或 operations )。在定义计算/数据流图之后,您可以使用 Session 执行其中的一些部分。让我们看一个简单的例子。
# Graph generation
tf_a = tf.placeholder(dtype=tf.float32)
tf_b = tf.placeholder(dtype=tf.float32)
tf_c = tf.add(tf_a, tf.math.multiply(tf_b, 2.0))
# Execution
with tf.Session() as sess:
c = sess.run(tf_c, feed_dict=tf_a: 5.0, tf_b: 2.0)
print(c)
计算图(也称为数据流图)如下所示。
tf_a tf_b tf.constant(2.0)
\ \ /
\ tf.math.multiply
\ /
tf.add
|
tf_c
类比:想想你在做蛋糕。你从网上下载食谱。然后你开始按照步骤实际制作蛋糕。配方就是图表,而制作蛋糕的过程就是 Session 所做的事情(即图表的执行)。
TF2
TF2 遵循立即执行样式或逐个运行定义。你调用/定义一些东西,它就会被执行。让我们看一个例子。
a = tf.constant(5.0)
b = tf.constant(3.0)
c = tf_a + (tf_b * 2.0)
print(c.numpy())
哇!与 TF1 示例相比,它看起来非常干净。一切看起来都像 Pythonic。
类比:现在假设您在动手做蛋糕工作坊。正如教练解释的那样,你正在做蛋糕。教练会立即解释每一步的结果是什么。因此,与前面的示例不同,您不必等到烤好蛋糕后再查看是否正确(这是对您无法调试代码的事实的引用)。但是你会得到关于你的表现的即时反馈(你知道这意味着什么)。
这是否意味着 TF2 不构建图表?惊恐发作
嗯,是的,不是的。关于eager execution 和AutoGraph 函数,您应该了解TF2 中的两个功能。
提示:确切地说,TF1 也有急切执行(默认关闭),可以使用
tf.enable_eager_execution()
启用。 TF2 默认开启了 eager_execution。
急切执行
Eager execution 可以立即执行Tensor
s 和Operation
s。这就是您在 TF2 示例中观察到的情况。但另一方面是它不构建图表。因此,例如,您使用急切执行来实现和运行神经网络,它会非常慢(因为神经网络一遍又一遍地执行非常重复的任务(前向计算 - 损失计算 - 后向传递))。
自动图表
这就是 AutoGraph 功能的用武之地。 AutoGraph 是我在 TF2 中最喜欢的功能之一。这样做的目的是,如果您在函数中执行“TensorFlow”,它会分析函数并为您构建图表(大吃一惊)。因此,例如,您执行以下操作。 TensorFlow 构建图表。
@tf.function
def do_silly_computation(x, y):
a = tf.constant(x)
b = tf.constant(y)
c = tf_a + (tf_b * 2.0)
return c
print(do_silly_computation(5.0, 3.0).numpy())
因此,您需要做的就是定义一个函数,该函数接受必要的输入并返回正确的输出。最重要的是添加 @tf.function
装饰器,因为这是 TensorFlow AutoGraph 分析给定函数的触发器。
警告:AutoGraph 不是灵丹妙药,不能天真地使用。 AutoGraph 也有各种limitations。
TF1 和 TF2 的区别
TF1 需要tf.Session()
对象来执行图形,而 TF2 不需要
在 TF1 中,未引用的变量不是由 Python GC 收集的,但在 TF2 中是
TF1 不会促进代码模块化,因为您需要在开始计算之前定义完整的图形。但是,鼓励使用 AutoGraph 功能代码模块化
TF1 和 TF2 中有哪些不同的数据类型?
您已经看到了很多主要的数据类型。但是您可能对他们的工作和行为方式有疑问。好吧,本节就是关于这些的。
TF1 数据类型/数据结构
tf.placeholder
:这就是您向计算图提供输入的方式。顾名思义,它没有附加值。相反,您在运行时提供一个值。 tf_a
和 tf_b
就是这些例子。把它想象成一个空盒子。你可以根据需要在里面装满水/沙子/蓬松的泰迪熊。
tf.Variable
:这是你用来定义神经网络参数的。与占位符不同,变量是用一些值初始化的。但它们的价值也可以随着时间而改变。这就是反向传播期间神经网络参数发生的情况。
tf.Operation
:操作是您可以对占位符、张量和变量执行的各种转换。例如tf.add()
和tf.mul()
是操作。这些操作返回一个张量(大部分时间)。如果您想证明不返回张量的操作,请检查this。
tf.Tensor
:这类似于变量,因为它具有初始值。但是,一旦它们被定义,它们的值就不能改变(即它们是不可变的)。例如,上例中的tf_c
是tf.Tensor
。
TF2 数据类型/数据结构
tf.Variable
tf.Tensor
tf.Operation
就行为而言,从 TF1 到 TF2 的数据类型没有太大变化。唯一的主要区别是,tf.placeholders
消失了。你也可以看看full list of data types。
什么是 Keras,它如何适应所有这些?
Keras 曾经是一个单独的库,提供主要用于深度学习模型的组件(例如层和模型)的高级实现。但是自从 TensorFlow 的更高版本之后,Keras 被集成到了 TensorFlow 中。
正如我所解释的,如果您要使用准 TensorFlow,Keras 隐藏了许多您必须处理的不必要的复杂问题。 Keras 为实现 NN 提供了两个主要的东西 Layer
对象和 Model
对象。 Keras 还有两个最常见的模型 API,可让您开发模型:Sequential API 和 Functional API。让我们通过一个简单的示例来看看 Keras 和 TensorFlow 的不同之处。让我们构建一个简单的 CNN。
提示:Keras 让您可以更轻松地实现使用 TF 可以实现的目标。但是 Keras 也提供了 TF 中还不强大的功能(例如text processing 功能)。
height=64
width = 64
n_channels = 3
n_outputs = 10
Keras(顺序 API)示例
model = Sequential()
model.add(Conv2D(filters=32, kernel_size=(2,2),
activation='relu',input_shape=(height, width, n_channels)))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=64, kernel_size=(2,2), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(n_outputs, activation='softmax'))
model.compile(loss='binary_crossentropy', optimizer='adam')
model.summary()
优点
直接实现简单的模型
缺点
不能用于实现复杂模型(例如具有多个输入的模型)
Keras(函数式 API)示例
inp = Input(shape=(height, width, n_channels))
out = Conv2D(filters=32, kernel_size=(2,2), activation='relu',input_shape=(height, width, n_channels))(inp)
out = MaxPooling2D(pool_size=(2,2))(out)
out = Conv2D(filters=64, kernel_size=(2,2), activation='relu')(out)
out = MaxPooling2D(pool_size=(2,2))(out)
out = Flatten()(out)
out = Dense(n_outputs, activation='softmax')(out)
model = Model(inputs=inp, outputs=out)
model.compile(loss='binary_crossentropy', optimizer='adam')
model.summary()
优点
可用于实现涉及多个输入和输出的复杂模型
缺点
需要非常了解输入输出的形状以及每一层的输入预期
TF1 示例
# Input
tf_in = tf.placeholder(shape=[None, height, width, n_channels], dtype=tf.float32)
# 1st conv and max pool
conv1 = tf.Variable(tf.initializers.glorot_uniform()([2,2,3,32]))
tf_out = tf.nn.conv2d(tf_in, filters=conv1, strides=[1,1,1,1], padding='SAME') # 64,64
tf_out = tf.nn.max_pool2d(tf_out, ksize=[2,2], strides=[1,2,2,1], padding='SAME') # 32,32
# 2nd conv and max pool
conv2 = tf.Variable(tf.initializers.glorot_uniform()([2,2,32,64]))
tf_out = tf.nn.conv2d(tf_out, filters=conv2, strides=[1,1,1,1], padding='SAME') # 32, 32
tf_out = tf.nn.max_pool2d(tf_out, ksize=[2,2], strides=[1,2,2,1], padding='SAME') # 16, 16
tf_out = tf.reshape(tf_out, [-1, 16*16*64])
# Dense layer
dense = conv1 = tf.Variable(tf.initializers.glorot_uniform()([16*16*64, n_outputs]))
tf_out = tf.matmul(tf_out, dense)
优点
非常适合涉及非典型操作的前沿研究(例如动态改变层的大小)
缺点
可读性差
注意事项和注意事项
在这里,我将列出您在使用 TF 时需要注意的几件事(根据我的经验)。
TF1 - 忘记提供所有依赖占位符来计算结果
tf_a = tf.placeholder(dtype=tf.float32)
tf_b = tf.placeholder(dtype=tf.float32)
tf_c = tf.add(tf_a, tf.math.multiply(tf_b, 2.0))
with tf.Session() as sess:
c = sess.run(tf_c, feed_dict=tf_a: 5.0)
print(c)
InvalidArgumentError:您必须使用 dtype float 为占位符张量“Placeholder_8”提供一个值 [[node Placeholder_8(定义在/usr/local/lib/python3.6/dist-packages/tensorflow_core/python/framework/ops.py:1748)]]
您在此处收到错误的原因是,您没有向tf_b
提供值。因此,请确保将值提供给 all 依赖占位符以计算结果。
TF1 - 小心数据类型
tf_a = tf.placeholder(dtype=tf.int32)
tf_b = tf.placeholder(dtype=tf.float32)
tf_c = tf.add(tf_a, tf.math.multiply(tf_b, 2.0))
with tf.Session() as sess:
c = sess.run(tf_c, feed_dict=tf_a: 5, tf_b: 2.0)
print(c)
TypeError: 'Add' Op 的输入 'y' 的 float32 类型与参数 'x' 的 int32 类型不匹配。
你能发现错误吗?这是因为在将数据类型传递给操作时必须匹配数据类型。否则,使用tf.cast()
操作将您的数据类型转换为兼容的数据类型。
Keras - 了解每个层期望的输入形状
model = Sequential()
model.add(Conv2D(filters=32, kernel_size=(2,2),
activation='relu',input_shape=(height, width)))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=64, kernel_size=(2,2), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(n_outputs, activation='softmax'))
model.compile(loss='binary_crossentropy', optimizer='adam')
ValueError: 层 conv2d_8 的输入 0 与层不兼容:预期 ndim=4,发现 ndim=3。收到的完整形状:[None, 64, 64]
在这里,您定义了一个输入形状[None, height, width]
(当您添加批处理维度时)。但是Conv2D
需要一个 4D 输入 [None, height, width, n_channels]
。因此,您会收到上述错误。一些通常被误解/容易出错的层是,
Conv2D
层 - 需要 4D 输入 [None, height, width, n_channels]
。要更详细地了解卷积层/操作,请查看answer
LSTM
层 - 需要 3D 输入 [None, timesteps, n_dim]
ConvLSTM2D
层 - 期望 5D 输入 [None, timesteps, height, width, n_channels]
Concatenate
层 - 除了轴之外,所有其他维度上连接的数据都需要相同
Keras - 在fit()
期间输入错误的输入/输出形状
height=64
width = 64
n_channels = 3
n_outputs = 10
Xtrain = np.random.normal(size=(500, height, width, 1))
Ytrain = np.random.choice([0,1], size=(500, n_outputs))
# Build the model
# fit network
model.fit(Xtrain, Ytrain, epochs=10, batch_size=32, verbose=0)
ValueError: 检查输入时出错:预期 conv2d_9_input 的形状为 (64, 64, 3) 但得到的数组的形状为 (64, 64, 1)
你应该知道这个。当我们应该提供 [batch size, height, width, 3]
输入时,我们正在提供形状为 [batch size, height, width, 1]
的输入。
TF1 和 TF2 的性能差异
这已经在讨论here。所以我不会重复其中的内容。
我希望我可以谈论但不能谈论的事情
我留下了一些进一步阅读的链接。
tf.data.Dataset
tf.RaggedTensor
【讨论】:
以上是关于TensorFlow 和 Keras 入门:过去 (TF1) 现在 (TF2)的主要内容,如果未能解决你的问题,请参考以下文章
TensorFlow2.0教程-Keras 快速入门:用于构建和训练深度学习模型的高阶 API
TensorFlow2 入门指南 | 11 Keras 与 tf.keras 总体框架介绍
TensorFlow2 入门指南 | 10 Keras 与 tf.keras 总体框架介绍