提交 676b8f6d 编写于 作者: W wizardforcel

2020-09-15 13:57:49

上级 0f0467c3
...@@ -48,7 +48,7 @@ TensorFlow 在最新版本的 Ubuntu 和 Windows 上受支持。 Windows 上的 ...@@ -48,7 +48,7 @@ TensorFlow 在最新版本的 Ubuntu 和 Windows 上受支持。 Windows 上的
TensorFlow 的优势之一是它允许您编写可以直接在 GPU 上运行的代码。 除了少数例外,TensorFlow 中的几乎所有主要操作都可以在 GPU 上运行以加快其执行速度。 我们将看到,这对于训练本书稍后描述的大型卷积神经网络将至关重要。 TensorFlow 的优势之一是它允许您编写可以直接在 GPU 上运行的代码。 除了少数例外,TensorFlow 中的几乎所有主要操作都可以在 GPU 上运行以加快其执行速度。 我们将看到,这对于训练本书稍后描述的大型卷积神经网络将至关重要。
# 康达环境 # Conda 环境
使用 PIP 可能是上手最快的方法,但是我发现最方便的方法是使用 conda 环境。 使用 PIP 可能是上手最快的方法,但是我发现最方便的方法是使用 conda 环境。
...@@ -155,7 +155,7 @@ API 堆栈的最后一层是 TensorFlow 提供的最高抽象层,这称为估 ...@@ -155,7 +155,7 @@ API 堆栈的最后一层是 TensorFlow 提供的最高抽象层,这称为估
本书将重点介绍如何使用低级 API 以及图层,数据集和指标 API 来构建,训练和评估自己的 ML 模型。 我们相信,通过使用这些较低级别的 API,读者将对 TensorFlow 的幕后工作方式有更深入的了解,并有能力更好地应对可能需要使用这些较低级别 API 的各种未来问题。 本书将重点介绍如何使用低级 API 以及图层,数据集和指标 API 来构建,训练和评估自己的 ML 模型。 我们相信,通过使用这些较低级别的 API,读者将对 TensorFlow 的幕后工作方式有更深入的了解,并有能力更好地应对可能需要使用这些较低级别 API 的各种未来问题。
# 急执行 # 急执行
在撰写本文时,Google 刚刚将急切的执行 API 引入了 TensorFlow。 急切执行是 TensorFlow 对另一个名为 PyTorch 的深度学习库的回答。 它允许您绕过通常的 TensorFlow 工作方式,在这种方式下,您必须首先定义计算图,然后执行该图以获得结果。 这称为静态图计算。 相反,现在您可以使用急切执行创建在运行程序时动态定义的所谓动态图。 使用 TensorFlow 时,这允许使用更传统的命令式编程方式。 不幸的是,急切的执行仍在开发中,缺少某些功能,因此在本书中不作介绍。 可以在 TensorFlow 网站上找到有关急切执行的更多信息。 在撰写本文时,Google 刚刚将急切的执行 API 引入了 TensorFlow。 急切执行是 TensorFlow 对另一个名为 PyTorch 的深度学习库的回答。 它允许您绕过通常的 TensorFlow 工作方式,在这种方式下,您必须首先定义计算图,然后执行该图以获得结果。 这称为静态图计算。 相反,现在您可以使用急切执行创建在运行程序时动态定义的所谓动态图。 使用 TensorFlow 时,这允许使用更传统的命令式编程方式。 不幸的是,急切的执行仍在开发中,缺少某些功能,因此在本书中不作介绍。 可以在 TensorFlow 网站上找到有关急切执行的更多信息。
...@@ -199,7 +199,7 @@ test_labels = shuffled_labels[105:] ...@@ -199,7 +199,7 @@ test_labels = shuffled_labels[105:]
接下来,我们重新整理数据集; 这一点很重要,因此,当我们将其分为训练集和测试集时,我们在这两个集之间平均分配,并且最终不会在一组集中获得所有一种类型的数据。 接下来,我们重新整理数据集; 这一点很重要,因此,当我们将其分为训练集和测试集时,我们在这两个集之间平均分配,并且最终不会在一组集中获得所有一种类型的数据。
# 一热载体 # 单热向量
改组后,我们对数据标签进行一些预处理。 随数据集加载的标签只是一个 150 长度的整数向量,表示每个数据点所属的目标类,在这种情况下为 1、2 或 3。 在创建机器学习模型时,我们希望将标签转换为一种新的形式,通过执行一种称为“单热编码”的方式可以更轻松地使用它。 改组后,我们对数据标签进行一些预处理。 随数据集加载的标签只是一个 150 长度的整数向量,表示每个数据点所属的目标类,在这种情况下为 1、2 或 3。 在创建机器学习模型时,我们希望将标签转换为一种新的形式,通过执行一种称为“单热编码”的方式可以更轻松地使用它。
...@@ -233,7 +233,7 @@ test_labels = shuffled_labels[105:] ...@@ -233,7 +233,7 @@ test_labels = shuffled_labels[105:]
![](img/e32b3460-ee85-420f-8eac-61314d7678c4.png) ![](img/e32b3460-ee85-420f-8eac-61314d7678c4.png)
# 变 # 变
我们如何在 TensorFlow 代码中全部写出来? 让我们开始创建权重和偏见。 在 TensorFlow 中,如果我们想创建一些可以被我们的代码操纵的张量,那么我们需要使用 TensorFlow 变量。 TensorFlow 变量是`tf.Variable`类的实例。 `tf.Variable`类表示`tf.Tensor`对象,可以通过在其上运行 TensorFlow 操作来更改其值。 变量是类似于张量的对象,因此它们可以以与张量相同的方式传递,并且可以与张量一起使用的任何操作都可以与变量一起使用。 我们如何在 TensorFlow 代码中全部写出来? 让我们开始创建权重和偏见。 在 TensorFlow 中,如果我们想创建一些可以被我们的代码操纵的张量,那么我们需要使用 TensorFlow 变量。 TensorFlow 变量是`tf.Variable`类的实例。 `tf.Variable`类表示`tf.Tensor`对象,可以通过在其上运行 TensorFlow 操作来更改其值。 变量是类似于张量的对象,因此它们可以以与张量相同的方式传递,并且可以与张量一起使用的任何操作都可以与变量一起使用。
...@@ -245,7 +245,7 @@ test_labels = shuffled_labels[105:] ...@@ -245,7 +245,7 @@ test_labels = shuffled_labels[105:]
my_variable = tf.get_variable(name= "my_variable", initializer=tf.constant([21, 25])) my_variable = tf.get_variable(name= "my_variable", initializer=tf.constant([21, 25]))
``` ```
# 作方式 # 作方式
在图中有变量很好,但我们也想对它们做点什么。 我们可以使用 TensorFlow 操作来操作我们的变量。 在图中有变量很好,但我们也想对它们做点什么。 我们可以使用 TensorFlow 操作来操作我们的变量。
...@@ -316,7 +316,7 @@ initializer = tf.global_variables_initializer() ...@@ -316,7 +316,7 @@ initializer = tf.global_variables_initializer()
要训​​练我们的模型,我们必须定义一些称为损失函数的函数。 损失函数将告诉我们我们的模型目前做得如何好坏。 要训​​练我们的模型,我们必须定义一些称为损失函数的函数。 损失函数将告诉我们我们的模型目前做得如何好坏。
损失可在`tf.losses`模块中找到。 对于此模型,我们将使用铰链损耗。 铰链损耗是创建**支持向量机****SVM**)时使用的损耗函数。 铰链损失严重惩罚了错误的预测。 对于一个给定的示例`(x[i], y[i])`,其中`x[i]`是数据点的特征向量,`y[i]`是其标记,其铰链损耗如下: 损失可在`tf.losses`模块中找到。 对于此模型,我们将使用铰链损失。 铰链损失是创建**支持向量机****SVM**)时使用的损失函数。 铰链损失严重惩罚了错误的预测。 对于一个给定的示例`(x[i], y[i])`,其中`x[i]`是数据点的特征向量,`y[i]`是其标记,其铰链损失如下:
![](img/18f2de01-7b99-4a9d-a016-fd44db07e0b5.png) ![](img/18f2de01-7b99-4a9d-a016-fd44db07e0b5.png)
...@@ -330,7 +330,7 @@ initializer = tf.global_variables_initializer() ...@@ -330,7 +330,7 @@ initializer = tf.global_variables_initializer()
这个概念实际上是非常直观的,因为如果我们的权重和偏见得到了正确的训练,那么所产生的三个得分中的最高得分就可以自信地表明输入示例所属的正确类别。 这个概念实际上是非常直观的,因为如果我们的权重和偏见得到了正确的训练,那么所产生的三个得分中的最高得分就可以自信地表明输入示例所属的正确类别。
由于在训练期间,我们会一次输入许多训练示例,因此,我们将获得多个需要平均的损失。 因此,需要最小化的总损方程如下: 由于在训练期间,我们会一次输入许多训练示例,因此,我们将获得多个需要平均的损失。 因此,需要最小化的总损方程如下:
![](img/5a3e2008-78d9-46de-b9a2-52e4d5d540d2.png) ![](img/5a3e2008-78d9-46de-b9a2-52e4d5d540d2.png)
...@@ -346,7 +346,7 @@ loss = tf.reduce_mean(tf.losses.hinge_loss(logits=model_out, labels=y)) ...@@ -346,7 +346,7 @@ loss = tf.reduce_mean(tf.losses.hinge_loss(logits=model_out, labels=y))
# 优化 # 优化
现在我们定义了要使用的损失函数; 我们可以使用这个损失函数来训练我们的模型。 如前面的方程式所示,损函数是权重和偏差的函数。 因此,我们要做的就是详尽地搜索权重和偏差的空间,并查看哪种组合最大程度地减少了损失。 当我们具有一维或二维权向量时,此过程可能还可以,但是当权向量空间太大时,我们需要一个更有效的解决方案。 为此,我们将使用一种名为**梯度下降**的优化技术。 现在我们定义了要使用的损失函数; 我们可以使用这个损失函数来训练我们的模型。 如前面的方程式所示,损函数是权重和偏差的函数。 因此,我们要做的就是详尽地搜索权重和偏差的空间,并查看哪种组合最大程度地减少了损失。 当我们具有一维或二维权向量时,此过程可能还可以,但是当权向量空间太大时,我们需要一个更有效的解决方案。 为此,我们将使用一种名为**梯度下降**的优化技术。
通过使用损失函数和演算,梯度下降法可以看到如何调整模型权重和偏差的值,以使损失值减小。 这是一个迭代过程,需要多次迭代才能针对我们的训练数据对权重和偏差的值进行适当调整。 这个想法是,通过相对于目标函数`ᐁ[w]L(w)`的梯度的相反方向更新参数,可以最小化由权重`w`参数化的损失函数`L`。 权重和偏差的更新功能如下所示: 通过使用损失函数和演算,梯度下降法可以看到如何调整模型权重和偏差的值,以使损失值减小。 这是一个迭代过程,需要多次迭代才能针对我们的训练数据对权重和偏差的值进行适当调整。 这个想法是,通过相对于目标函数`ᐁ[w]L(w)`的梯度的相反方向更新参数,可以最小化由权重`w`参数化的损失函数`L`。 权重和偏差的更新功能如下所示:
...@@ -368,7 +368,7 @@ TensorFlow 的好处在于,它使用其内置的优化器(称为**自动微 ...@@ -368,7 +368,7 @@ TensorFlow 的好处在于,它使用其内置的优化器(称为**自动微
我们可以在`tf.train`模块中找到优化程序类。 现在,我们将使用`GradientDescentOptimizer`类,它只是基本的梯度下降优化算法。 创建优化器时,我们必须提供学习率。 学习速率的值是`hyperparameter`,用户必须通过反复试验和实验来对其进行调整。 0.5 的值应该可以很好地解决此问题。 我们可以在`tf.train`模块中找到优化程序类。 现在,我们将使用`GradientDescentOptimizer`类,它只是基本的梯度下降优化算法。 创建优化器时,我们必须提供学习率。 学习速率的值是`hyperparameter`,用户必须通过反复试验和实验来对其进行调整。 0.5 的值应该可以很好地解决此问题。
优化器节点具有一种称为`minimize`的方法。 在您提供的损失函数上调用此方法会做两件事。 首先,针对您的整个图形计算与该损有关的梯度。 其次,这些梯度用于更新所有相关变量。 优化器节点具有一种称为`minimize`的方法。 在您提供的损失函数上调用此方法会做两件事。 首先,针对您的整个图形计算与该损有关的梯度。 其次,这些梯度用于更新所有相关变量。
创建我们的优化器节点将如下所示: 创建我们的优化器节点将如下所示:
...@@ -396,7 +396,7 @@ correct_prediction = tf.equal(tf.argmax(model_out,1), tf.argmax(y,1)) ...@@ -396,7 +396,7 @@ correct_prediction = tf.equal(tf.argmax(model_out,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
``` ```
# 会 # 会
现在,我们已经构造了计算图的所有部分。 我们需要做的最后一件事是创建一个`tf.Session`并运行我们的图形。 TensorFlow 会话是一种将用 Python 编写的 TensorFlow 程序与为 TensorFlow 供电的 C++ 运行时连接的一种方式。 该会话还使 TensorFlow 可以访问本地或远程计算机上存在的设备,例如 CPU 和 GPU。 另外,该会话将缓存有关构造图的信息,因此可以有效地多次运行计算。 现在,我们已经构造了计算图的所有部分。 我们需要做的最后一件事是创建一个`tf.Session`并运行我们的图形。 TensorFlow 会话是一种将用 Python 编写的 TensorFlow 程序与为 TensorFlow 供电的 C++ 运行时连接的一种方式。 该会话还使 TensorFlow 可以访问本地或远程计算机上存在的设备,例如 CPU 和 GPU。 另外,该会话将缓存有关构造图的信息,因此可以有效地多次运行计算。
...@@ -434,7 +434,7 @@ with tf.Session() as sess: ...@@ -434,7 +434,7 @@ with tf.Session() as sess:
运行 1000 次迭代后,我们使用另一个`session.run`调用来获取精度节点的输出。 我们执行两次,一次输入我们的训练数据以获取训练集的准确性,一次输入我们保留的测试数据以获取测试集的准确性。 您应该从`0.977778`中打印出测试精度,这意味着我们的模型可以正确分类 45 个测试集中的 44 个,一点也不差! 运行 1000 次迭代后,我们使用另一个`session.run`调用来获取精度节点的输出。 我们执行两次,一次输入我们的训练数据以获取训练集的准确性,一次输入我们保留的测试数据以获取测试集的准确性。 您应该从`0.977778`中打印出测试精度,这意味着我们的模型可以正确分类 45 个测试集中的 44 个,一点也不差!
# 摘要 # 总结
在本章中,我们已经说明了使用 TensorFlow 进行编程的方式以及如何为使用 TensorFlow 设置工作环境。 我们还研究了如何使用 TensorFlow 对鸢尾花朵进行分类来构建,训练和评估自己的线性模型。 在此过程中,我们简要介绍了损失函数和梯度下降优化器。 在本章中,我们已经说明了使用 TensorFlow 进行编程的方式以及如何为使用 TensorFlow 设置工作环境。 我们还研究了如何使用 TensorFlow 对鸢尾花朵进行分类来构建,训练和评估自己的线性模型。 在此过程中,我们简要介绍了损失函数和梯度下降优化器。
......
...@@ -103,21 +103,21 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要( ...@@ -103,21 +103,21 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要(
一层以上的神经网络是非线性假设的示例,在该模型中,模型可以学习比线性分类器更复杂的关系。 实际上,它们实际上是通用逼近器,能够逼近任何连续函数。 一层以上的神经网络是非线性假设的示例,在该模型中,模型可以学习比线性分类器更复杂的关系。 实际上,它们实际上是通用逼近器,能够逼近任何连续函数。
# 激活功能 # 激活函数
为了使 ANN 模型能够解决更复杂的问题,我们需要在神经元点积之后添加一个非线性块。 然后,如果将这些非线性层级联起来,它将使网络将不同的概念组合在一起,从而使复杂的问题更易于解决。 为了使 ANN 模型能够解决更复杂的问题,我们需要在神经元点积之后添加一个非线性块。 然后,如果将这些非线性层级联起来,它将使网络将不同的概念组合在一起,从而使复杂的问题更易于解决。
在神经元中使用非线性激活非常重要。 如果我们不使用非线性激活函数,那么无论我们层叠了多少层,我们都只会拥有行为类似于线性模型的东西。 这是因为线性函数的任何线性组合都会分解为线性函数。 在神经元中使用非线性激活非常重要。 如果我们不使用非线性激活函数,那么无论我们层叠了多少层,我们都只会拥有行为类似于线性模型的东西。 这是因为线性函数的任何线性组合都会分解为线性函数。
我们的神经元可以使用多种不同的激活功能,此处显示了一些; 唯一重要的是函数是非线性的。 每个激活功能都有其自身的优点和缺点。 我们的神经元可以使用多种不同的激活函数,此处显示了一些; 唯一重要的是函数是非线性的。 每个激活函数都有其自身的优点和缺点。
历史上,神经网络选择的激活函数是 Sigmoid 和 *TanH*。 但是,这些功能对于可靠地训练神经网络不利,因为它们具有不希望的特性,即它们的值在任一端都饱和。 这将导致这些点处的梯度为零,我们将在后面找到,并且在训练神经网络时不是一件好事。 历史上,神经网络选择的激活函数是 Sigmoid 和 *TanH*。 但是,这些功能对于可靠地训练神经网络不利,因为它们具有不希望的特性,即它们的值在任一端都饱和。 这将导致这些点处的梯度为零,我们将在后面找到,并且在训练神经网络时不是一件好事。
![](img/11ef12ae-e5d9-458a-a00a-3be49a15fbb1.png) ![](img/11ef12ae-e5d9-458a-a00a-3be49a15fbb1.png)
结果,更流行的激活功能之一是 ReLU 激活或**整流线性单元**。 ReLU 只是`max(x, 0)`,输入和 0 之间的最大运算。 它具有理想的特性,即梯度(至少在一端)不会变为零,这极大地有助于神经网络训练的收敛速度。 结果,更流行的激活函数之一是 ReLU 激活或**整流线性单元**。 ReLU 只是`max(x, 0)`,输入和 0 之间的最大运算。 它具有理想的特性,即梯度(至少在一端)不会变为零,这极大地有助于神经网络训练的收敛速度。
该激活功能用于帮助训练深层的 CNN 之后,变得越来越流行。 它的简单性和有效性使其成为通常使用的激活功能 该激活函数用于帮助训练深层的 CNN 之后,变得越来越流行。 它的简单性和有效性使其成为通常使用的激活函数
# XOR 问题 # XOR 问题
...@@ -143,12 +143,12 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要( ...@@ -143,12 +143,12 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要(
当我们说网络学习时,所发生的就是网络参数被更新,网络应该能够为训练数据集中的每个 X 输出正确的 Y。 期望的是,在对网络进行训练之后,它将能够针对训练期间未看到的新输入进行概括并表现良好。 但是,为了做到这一点,您必须有一个足够具有代表性的数据集,以捕获要输出的内容。 例如,如果要分类汽车,则需要具有不同类型,颜色,照度等的数据集。 当我们说网络学习时,所发生的就是网络参数被更新,网络应该能够为训练数据集中的每个 X 输出正确的 Y。 期望的是,在对网络进行训练之后,它将能够针对训练期间未看到的新输入进行概括并表现良好。 但是,为了做到这一点,您必须有一个足够具有代表性的数据集,以捕获要输出的内容。 例如,如果要分类汽车,则需要具有不同类型,颜色,照度等的数据集。
通常,当我们没有足够的数据或者我们的模型不够复杂以至于无法捕获数据的复杂性时,就会出现训练机器学习模型的一个常见错误。 这些错误可能导致过拟合和拟合不足的问题。 在以后的章节中,您将学习如何在实践中处理这些问题。 通常,当我们没有足够的数据或者我们的模型不够复杂以至于无法捕获数据的复杂性时,就会出现训练机器学习模型的一个常见错误。 这些错误可能导致过拟合和欠拟合的问题。 在以后的章节中,您将学习如何在实践中处理这些问题。
在训练期间,*以两种不同的模式执行网络* 在训练期间,*以两种不同的模式执行网络*
* **正向传播**:我们通过网络向前工作,为数据集中的当前给定输入生成输出结果。 然后评估损失函数,该函数告诉我们网络在预测正确输出方面的表现如何。 * **正向传播**:我们通过网络向前工作,为数据集中的当前给定输入生成输出结果。 然后评估损失函数,该函数告诉我们网络在预测正确输出方面的表现如何。
* **反向传播**:我们通过网络进行反向计算,计算每个权重对产生网络电流损的影响。 * **反向传播**:我们通过网络进行反向计算,计算每个权重对产生网络电流损的影响。
此图显示了训练时网络运行的两种不同方式。 此图显示了训练时网络运行的两种不同方式。
...@@ -156,7 +156,7 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要( ...@@ -156,7 +156,7 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要(
当前,使神经网络“学习”的主力军是与基于梯度的优化器(例如梯度下降)结合的反向传播算法。 当前,使神经网络“学习”的主力军是与基于梯度的优化器(例如梯度下降)结合的反向传播算法。
反向传播用于计算梯度,该梯度告诉我们每个权重对产生电流损有什么影响。 找到梯度后,可以使用诸如梯度下降之类的优化技术来更新权重,以使损失函数的值最小化。 反向传播用于计算梯度,该梯度告诉我们每个权重对产生电流损有什么影响。 找到梯度后,可以使用诸如梯度下降之类的优化技术来更新权重,以使损失函数的值最小化。
谨在最后一句话:TensorFlow,PyTorch,Caffe 或 CNTK 之类的 ML 库将提供反向传播,优化器以及表示和训练神经网络所需的所有其他功能,而无需您自己重写所有这些代码。 谨在最后一句话:TensorFlow,PyTorch,Caffe 或 CNTK 之类的 ML 库将提供反向传播,优化器以及表示和训练神经网络所需的所有其他功能,而无需您自己重写所有这些代码。
...@@ -174,7 +174,7 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要( ...@@ -174,7 +174,7 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要(
![](img/d3436da8-9781-4459-bed0-8921e134236c.png) ![](img/d3436da8-9781-4459-bed0-8921e134236c.png)
# 分批 # 批量
对于大型数据集而言,将整个数据集存储在内存中以训练网络的想法,例如第 1 章,“TensorFlow 简介和设置”中的示例。 人们在实践中所做的是,在训练期间,他们将数据集分成小块,称为迷你批次(通常称为批次)。 然后,依次将每个微型批次装入并馈送到网络,在网络中将计算反向传播和梯度下降算法,然后更新权重。 然后,对每个小批量重复此操作,直到您完全浏览了数据集。 对于大型数据集而言,将整个数据集存储在内存中以训练网络的想法,例如第 1 章,“TensorFlow 简介和设置”中的示例。 人们在实践中所做的是,在训练期间,他们将数据集分成小块,称为迷你批次(通常称为批次)。 然后,依次将每个微型批次装入并馈送到网络,在网络中将计算反向传播和梯度下降算法,然后更新权重。 然后,对每个小批量重复此操作,直到您完全浏览了数据集。
...@@ -188,7 +188,7 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要( ...@@ -188,7 +188,7 @@ ML 的新型深度学习方法具有的最酷的功能是,它们不需要(
在训练阶段,我们需要使用当前的权重正确预测训练集; 此过程包括评估我们的训练集输入 *X* ,并与所需的输出 *Y* 进行比较。 需要某种机制来量化(返回标量数)我们当前的权重在正确预测我们所需的输出方面有多好。 该机制称为**损失函数** 在训练阶段,我们需要使用当前的权重正确预测训练集; 此过程包括评估我们的训练集输入 *X* ,并与所需的输出 *Y* 进行比较。 需要某种机制来量化(返回标量数)我们当前的权重在正确预测我们所需的输出方面有多好。 该机制称为**损失函数**
反向传播算法应返回每个参数相对于损失函数的导数。 这意味着我们将发现更改每个参数将如何影响损函数的值。 然后,优化算法的工作就是最小化损失函数,换句话说,就是在训练时减小训练误差。 反向传播算法应返回每个参数相对于损失函数的导数。 这意味着我们将发现更改每个参数将如何影响损函数的值。 然后,优化算法的工作就是最小化损失函数,换句话说,就是在训练时减小训练误差。
一个重要方面是为工作选择合适的损失函数。 一些最常见的损失函数及其用途是在此处给出的: 一个重要方面是为工作选择合适的损失函数。 一些最常见的损失函数及其用途是在此处给出的:
...@@ -212,7 +212,7 @@ TensorFlow 的以下代码行也显示了这一点,因为损失仅需要标签 ...@@ -212,7 +212,7 @@ TensorFlow 的以下代码行也显示了这一点,因为损失仅需要标签
loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits) loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)
``` ```
您可能会注意到第三个箭头也连接到损失功能。 这与名为正则化的东西有关,将在第 3 章“TensorFlow 中的图像分类”中进行探讨; 因此,现在您可以放心地忽略它。 您可能会注意到第三个箭头也连接到损失函数。 这与名为正则化的东西有关,将在第 3 章“TensorFlow 中的图像分类”中进行探讨; 因此,现在您可以放心地忽略它。
# 优化器及其超参数 # 优化器及其超参数
...@@ -246,7 +246,7 @@ TensorFlow 的所有不同优化器都可以在`tf.train`类中找到。 例如 ...@@ -246,7 +246,7 @@ TensorFlow 的所有不同优化器都可以在`tf.train`类中找到。 例如
但是,如果您没有时间执行此操作,那么下一个最佳方法是首先尝试将 Adam 用作优化器,因为它通常在很少调整的情况下效果很好。 然后,如果有时间,请尝试使用 Momentum SGD; 这将需要更多的参数调整,例如学习率,但是如果调整得很好,通常会产生非常好的结果。 但是,如果您没有时间执行此操作,那么下一个最佳方法是首先尝试将 Adam 用作优化器,因为它通常在很少调整的情况下效果很好。 然后,如果有时间,请尝试使用 Momentum SGD; 这将需要更多的参数调整,例如学习率,但是如果调整得很好,通常会产生非常好的结果。
# 拟合不足与拟合过度 # 欠拟合与过拟合
在设计用于解决特定问题的神经网络时,我们可能有很多活动部件,并且必须同时处理许多事情,例如: 在设计用于解决特定问题的神经网络时,我们可能有很多活动部件,并且必须同时处理许多事情,例如:
...@@ -266,9 +266,9 @@ TensorFlow 的所有不同优化器都可以在`tf.train`类中找到。 例如 ...@@ -266,9 +266,9 @@ TensorFlow 的所有不同优化器都可以在`tf.train`类中找到。 例如
* 获取更多数据 * 获取更多数据
* 当检测到测试数据的错误开始增长时停止(提前停止) * 当检测到测试数据的错误开始增长时停止(提前停止)
* 尽可能简单地开始模型设计,并且仅在检测到拟合不足时才增加复杂性 * 尽可能简单地开始模型设计,并且仅在检测到欠拟合时才增加复杂性
# 功能缩放 # 特征缩放
为了简化优化程序算法的工作,在训练和测试之前,有一些技术可以并且应该应用到您的数据中。 为了简化优化程序算法的工作,在训练和测试之前,有一些技术可以并且应该应用到您的数据中。
...@@ -353,7 +353,7 @@ for step in range(10000): ...@@ -353,7 +353,7 @@ for step in range(10000):
writer.add_summary(summary, step) writer.add_summary(summary, step)
``` ```
如果运行此脚本,则应该期望获得以下损图。 我们可以看到损失已经为零,这表明模型已经过训练并解决了问题。 您可以重复此实验,但现在只有一层致密层; 正如我们所说,您应该注意到该模型无法解决问题 如果运行此脚本,则应该期望获得以下损图。 我们可以看到损失已经为零,这表明模型已经过训练并解决了问题。 您可以重复此实验,但现在只有一层致密层; 正如我们所说,您应该注意到该模型无法解决问题
![](img/75567914-f4cf-459e-9955-ab4c20c97299.png) ![](img/75567914-f4cf-459e-9955-ab4c20c97299.png)
...@@ -483,7 +483,7 @@ out_height = ceil(float(in_height) / float(strides[1])) ...@@ -483,7 +483,7 @@ out_height = ceil(float(in_height) / float(strides[1]))
这证明了这两种层类型之间参数的数量级差异。 这证明了这两种层类型之间参数的数量级差异。
# 计算操作数 # 计算操作数
现在,我们对计算特定卷积层的计算成本感兴趣。 如果您想了解如何实现有效的网络结构(例如在移动设备中速度是关键时),则此步骤很重要。 另一个原因是要查看在硬件中实现特定层需要多少个乘法器。 现代 CNN 架构中的卷积层最多可负责模型中所有计算的 90%! 现在,我们对计算特定卷积层的计算成本感兴趣。 如果您想了解如何实现有效的网络结构(例如在移动设备中速度是关键时),则此步骤很重要。 另一个原因是要查看在硬件中实现特定层需要多少个乘法器。 现代 CNN 架构中的卷积层最多可负责模型中所有计算的 90%!
...@@ -502,7 +502,7 @@ MAC 的数量可以计算为: ...@@ -502,7 +502,7 @@ MAC 的数量可以计算为:
#MAC = [F * F * C * (H + 2 * P-FS + 1) * (W + 2 * P-FS + 1) * M] * B #MAC = [F * F * C * (H + 2 * P-FS + 1) * (W + 2 * P-FS + 1) * M] * B
``` ```
例如,让我们考虑一个具有输入`224 x 224 x 3`,批处理大小为 1,内核为`3x3`、64 个过滤器,跨度为 1 和填充 1 的转换层: 例如,让我们考虑一个具有输入`224 x 224 x 3`,批大小为 1,内核为`3x3`、64 个过滤器,跨度为 1 和填充 1 的转换层:
```py ```py
#MAC = 3 * 3 * (224 + 2-31 + 1) * (224 + 2-31 + 1) * 3 * 64 * 1 = 9,462,528 #MAC = 3 * 3 * (224 + 2-31 + 1) * (224 + 2-31 + 1) * 3 * 64 * 1 = 9,462,528
...@@ -564,7 +564,7 @@ tf.layers.max_pooling2d(inputs=some_input_layer, pool_size=[2, 2], strides=2) ...@@ -564,7 +564,7 @@ tf.layers.max_pooling2d(inputs=some_input_layer, pool_size=[2, 2], strides=2)
![](img/88fb04f4-1cdb-45d7-8ecb-5b38bc80215e.png) ![](img/88fb04f4-1cdb-45d7-8ecb-5b38bc80215e.png)
# 计算感受 # 计算感受
感受域是特定卷积窗口“看到”其输入张量的程度。 感受域是特定卷积窗口“看到”其输入张量的程度。
...@@ -700,7 +700,7 @@ for i in range(2000): ...@@ -700,7 +700,7 @@ for i in range(2000):
print("Test Accuracy:",sess.run(accuracy, feed_dict={x_: mnist.test.images, y_: mnist.test.labels, is_training: False})) print("Test Accuracy:",sess.run(accuracy, feed_dict={x_: mnist.test.images, y_: mnist.test.labels, is_training: False}))
``` ```
# 张量板 # TensorBoard
TensorBoard 是 TensorFlow 随附的基于 Web 的实用程序,可让您可视化构造的 TensorFlow 图。 最重要的是,它使您能够跟踪大量的统计数据或变量,这些数据或变量可能对训练模型很重要。 您可能希望跟踪的此类变量的示例包括训练损失,测试集准确性或学习率。 前面我们看到,我们可以使用张量板可视化损失函数的值。 TensorBoard 是 TensorFlow 随附的基于 Web 的实用程序,可让您可视化构造的 TensorFlow 图。 最重要的是,它使您能够跟踪大量的统计数据或变量,这些数据或变量可能对训练模型很重要。 您可能希望跟踪的此类变量的示例包括训练损失,测试集准确性或学习率。 前面我们看到,我们可以使用张量板可视化损失函数的值。
...@@ -748,7 +748,7 @@ with tf.Session() as sess: ...@@ -748,7 +748,7 @@ with tf.Session() as sess:
* **膨胀卷积(Atrous Convolution)**:它们具有称为膨胀率的额外参数,可让您以相同的计算成本获得更大的视野(例如`3x3`卷积可以和`5x5`卷积具有相同的视野) * **膨胀卷积(Atrous Convolution)**:它们具有称为膨胀率的额外参数,可让您以相同的计算成本获得更大的视野(例如`3x3`卷积可以和`5x5`卷积具有相同的视野)
* **转置卷积(Deconvolutions)**:通常用于 CNN 自编码器和语义分割问题 * **转置卷积(Deconvolutions)**:通常用于 CNN 自编码器和语义分割问题
# 摘要 # 总结
在本章中,我们向您介绍了机器学习和人工智能。 我们研究了什么是人工神经网络以及如何对其进行训练。 在此之后,我们研究了 CNN 及其主要组成部分。 我们介绍了如何使用 TensorFlow 训练您自己的 CNN 以识别数字。 最后,我们对 Tensorboard 进行了介绍,并了解了如何在 TensorFlow 中训练模型时如何使用它来帮助可视化重要的统计数据。 在本章中,我们向您介绍了机器学习和人工智能。 我们研究了什么是人工神经网络以及如何对其进行训练。 在此之后,我们研究了 CNN 及其主要组成部分。 我们介绍了如何使用 TensorFlow 训练您自己的 CNN 以识别数字。 最后,我们对 Tensorboard 进行了介绍,并了解了如何在 TensorFlow 中训练模型时如何使用它来帮助可视化重要的统计数据。
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
图像分类模型的关键部分是其 CNN 层。 这些层将负责从图像数据中提取特征。 这些 CNN 图层的输出将是一个特征向量,就像以前一样,我们可以将其用作所选分类器的输入。 对于许多 CNN 模型,分类器将只是连接到我们 CNN 输出的完全连接层。 如第 1 章,“TensorFlow 简介和设置”中所示,我们的线性分类器只是一个全连接层; 除了层的大小和输入会有所不同之外,这里就是这种情况。 图像分类模型的关键部分是其 CNN 层。 这些层将负责从图像数据中提取特征。 这些 CNN 图层的输出将是一个特征向量,就像以前一样,我们可以将其用作所选分类器的输入。 对于许多 CNN 模型,分类器将只是连接到我们 CNN 输出的完全连接层。 如第 1 章,“TensorFlow 简介和设置”中所示,我们的线性分类器只是一个全连接层; 除了层的大小和输入会有所不同之外,这里就是这种情况。
重要的是要注意,分类或回归问题(例如本地化)(或其他使用图像的其他问题)所使用的 CNN 架构在本质上是相同的。 唯一真正的不同是,在 CNN 层完成特征提取之后会发生什么。 例如,一个差异可能是用于不同任务的损失函数,如下图所示: 重要的是要注意,分类或回归问题(例如定位)(或其他使用图像的其他问题)所使用的 CNN 架构在本质上是相同的。 唯一真正的不同是,在 CNN 层完成特征提取之后会发生什么。 例如,一个差异可能是用于不同任务的损失函数,如下图所示:
![](img/55354505-d9ef-4239-9e38-332e7c1e3cd7.jpg) ![](img/55354505-d9ef-4239-9e38-332e7c1e3cd7.jpg)
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
这在直觉上是正确的,因为当`y=1`时,我们要最小化`L(y, y_hat) = - log(y_hat)`,需要最大化`y_hat`;当`y=0`时,我们要最小化`L(y, y_hat) = - log(1 - y_hat)`,需要最小化`y_hat` 这在直觉上是正确的,因为当`y=1`时,我们要最小化`L(y, y_hat) = - log(y_hat)`,需要最大化`y_hat`;当`y=0`时,我们要最小化`L(y, y_hat) = - log(1 - y_hat)`,需要最小化`y_hat`
在 TensorFlow 中,可以在`tf.losses`模块中找到二进制交叉熵损失。 知道我们模型的原始输出`y_hat`的名称是`logits`很有用。 在将其传递给交叉熵损失之前,我们需要对其应用 **Sigmoid** 函数,以便我们的输出在 0 到 1 之间缩放。TensorFlow 实际上将所有这些步骤组合为一个操作,如下面的代码。 TensorFlow 还将为我们平均分批处理损失。 在 TensorFlow 中,可以在`tf.losses`模块中找到二进制交叉熵损失。 知道我们模型的原始输出`y_hat`的名称是`logits`很有用。 在将其传递给交叉熵损失之前,我们需要对其应用 **Sigmoid** 函数,以便我们的输出在 0 到 1 之间缩放。TensorFlow 实际上将所有这些步骤组合为一个操作,如下面的代码。 TensorFlow 还将为我们平均分批损失。
```py ```py
loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=labels_in, logits=model_prediction) loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=labels_in, logits=model_prediction)
...@@ -83,7 +83,7 @@ loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=labels_in, logits=mode ...@@ -83,7 +83,7 @@ loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=labels_in, logits=mode
![](img/b53e5bab-5f7a-4cf0-b749-92b36255f365.png) ![](img/b53e5bab-5f7a-4cf0-b749-92b36255f365.png)
在此,`y^(k)`为 0 或 1,表示类别标签`k`是否是用于预测`y_hat^(k)`的正确分类。 要使用此损,我们首先需要向模型中最终 FC 层的输出`y_hat`添加 softmax 激活。 交叉熵与 softmax 的组合如下所示: 在此,`y^(k)`为 0 或 1,表示类别标签`k`是否是用于预测`y_hat^(k)`的正确分类。 要使用此损,我们首先需要向模型中最终 FC 层的输出`y_hat`添加 softmax 激活。 交叉熵与 softmax 的组合如下所示:
![](img/208109f6-4aed-4f92-bbfc-eb093331aadd.png) ![](img/208109f6-4aed-4f92-bbfc-eb093331aadd.png)
...@@ -99,7 +99,7 @@ loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=model_logit ...@@ -99,7 +99,7 @@ loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=model_logit
# 训练/测试数据集拆分 # 训练/测试数据集拆分
暂时请注意,我们需要将数据集分为两组:训练和测试。 正如第 1 章,“TensorFlow 简介和设置”中所述,这是因为我们需要以某种方式检查模型是否能够从其自身的训练样本中进行概括(是否能够正确识别训练中从未见过的图像)。 如果我们的模型不能做到这一点,对我们来说就没有太大用处。 暂时请注意,我们需要将数据集分为两组:训练和测试。 正如第 1 章,“TensorFlow 简介和设置”中所述,这是因为我们需要以某种方式检查模型是否能够从其自身的训练样本中进行泛化(是否能够正确识别训练中从未见过的图像)。 如果我们的模型不能做到这一点,对我们来说就没有太大用处。
还有一些其他要记住的重要点: 还有一些其他要记住的重要点:
...@@ -120,7 +120,7 @@ Pascal **视觉对象类**(**VOC**)挑战成立于 2005 年。每年组织 ...@@ -120,7 +120,7 @@ Pascal **视觉对象类**(**VOC**)挑战成立于 2005 年。每年组织
随着更复杂的分类方法的出现,前面的数据集是不够的,以下几节中介绍的 ImageNet 数据集和 CIFAR 数据集成为分类测试的新标准。 随着更复杂的分类方法的出现,前面的数据集是不够的,以下几节中介绍的 ImageNet 数据集和 CIFAR 数据集成为分类测试的新标准。
# 影像网 # ImageNet
ImageNet 数据集由 Alex Berg(哥伦比亚大学),Jia Deng(普林斯顿大学)和 Lii-Fei Li(斯坦福大学)在 2010 年共同创建,旨在进行大规模视觉识别的测试比赛, *PASCAL 可视对象类挑战*,2010 年。数据集是代表 WordNet 内容的图像的集合。 WordNet 是英语的词汇数据库。 它以分层结构将英语单词分成称为**同义词集**的同义词集。 以下屏幕截图显示了名词的 WordNet 结构。 括号中的数字是子树中的同义词集的数量。 ImageNet 数据集由 Alex Berg(哥伦比亚大学),Jia Deng(普林斯顿大学)和 Lii-Fei Li(斯坦福大学)在 2010 年共同创建,旨在进行大规模视觉识别的测试比赛, *PASCAL 可视对象类挑战*,2010 年。数据集是代表 WordNet 内容的图像的集合。 WordNet 是英语的词汇数据库。 它以分层结构将英语单词分成称为**同义词集**的同义词集。 以下屏幕截图显示了名词的 WordNet 结构。 括号中的数字是子树中的同义词集的数量。
...@@ -213,7 +213,7 @@ from tf.keras.datasets import cifar100 ...@@ -213,7 +213,7 @@ from tf.keras.datasets import cifar100
(x_train, y_train), (x_test, y_test) = cifar100.load_data(label_mode='fine') (x_train, y_train), (x_test, y_test) = cifar100.load_data(label_mode='fine')
``` ```
# 使用 TensorFlow 进行图像分类 # 将 TensorFlow 用于图像分类
在本节中,我们将向您展示如何实现相对简单的 CNN 架构。 我们还将研究如何训练它对 CIFAR-10 数据集进行分类。 在本节中,我们将向您展示如何实现相对简单的 CNN 架构。 我们还将研究如何训练它对 CIFAR-10 数据集进行分类。
...@@ -335,7 +335,7 @@ def build_graph(self): ...@@ -335,7 +335,7 @@ def build_graph(self):
定义模型和损失函数后,我们需要指定将用于最小化损失的优化函数。 我们在这里选择的优化函数是 Adam 优化器,它在名称范围*优化器*中定义。 定义模型和损失函数后,我们需要指定将用于最小化损失的优化函数。 我们在这里选择的优化函数是 Adam 优化器,它在名称范围*优化器*中定义。
# 学习率安排 # 学习率调度
在上一章中,我们简要提到了在训练过程中保持恒定的学习率可能会出现的问题。 随着我们模型的开始学习,我们的初始学习率很可能会变得太大而无法继续学习。 梯度下降更新将开始超出或绕过我们的最小值; 结果,损失函数的值不会降低。 为了解决这个问题,我们可以不时降低学习率的值。 这个过程称为学习率调度,有几种流行的方法。 在上一章中,我们简要提到了在训练过程中保持恒定的学习率可能会出现的问题。 随着我们模型的开始学习,我们的初始学习率很可能会变得太大而无法继续学习。 梯度下降更新将开始超出或绕过我们的最小值; 结果,损失函数的值不会降低。 为了解决这个问题,我们可以不时降低学习率的值。 这个过程称为学习率调度,有几种流行的方法。
...@@ -532,7 +532,7 @@ decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps) ...@@ -532,7 +532,7 @@ decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps)
现在,我们可能倾向于认为将所有权重设置为零将实现最大的对称性。 但是,这实际上是一个非常糟糕的主意,并且我们的模型永远不会学到任何东西。 这是因为当您进行前向通过时,每个神经元都会产生相同的结果。 因此,在反向传播步骤中,所有权重将以相同的方式更新。 这意味着模型永远无法学习丰富的功能,因此请不要像这样初始化。 现在,我们可能倾向于认为将所有权重设置为零将实现最大的对称性。 但是,这实际上是一个非常糟糕的主意,并且我们的模型永远不会学到任何东西。 这是因为当您进行前向通过时,每个神经元都会产生相同的结果。 因此,在反向传播步骤中,所有权重将以相同的方式更新。 这意味着模型永远无法学习丰富的功能,因此请不要像这样初始化。
# 用平均零分布初始化 # 用均值为零的分布初始化
一个更好的主意是使用所有以零为中心的较小随机值初始化权重。 为此,我们可以使用均值为零和单位方差为零的正态分布的随机值,然后将其按某个较小的值进行缩放,例如 0.01。 一个更好的主意是使用所有以零为中心的较小随机值初始化权重。 为此,我们可以使用均值为零和单位方差为零的正态分布的随机值,然后将其按某个较小的值进行缩放,例如 0.01。
...@@ -558,7 +558,7 @@ decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps) ...@@ -558,7 +558,7 @@ decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps)
![](img/b802c1b0-4ed0-4d2f-87c4-57fd4027e470.png) ![](img/b802c1b0-4ed0-4d2f-87c4-57fd4027e470.png)
我们还可以从零均值和前面的方差的正态分布中采样权重。 对于 ReLu 激活功能,He 等人证明了这一点。 方差应该改为: 我们还可以从零均值和前面的方差的正态分布中采样权重。 对于 ReLu 激活函数,He 等人证明了这一点。 方差应该改为:
![](img/f093a9d2-6556-437c-b66d-541edccd858f.png) ![](img/f093a9d2-6556-437c-b66d-541edccd858f.png)
...@@ -576,9 +576,9 @@ kernel_initializer=tf.truncated_normal_initializer(stddev=0.01), ...@@ -576,9 +576,9 @@ kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),
bias_initializer=tf.zeros_initializer()) bias_initializer=tf.zeros_initializer())
``` ```
# 通过规范化来提高概括性 # 通过规范化来提高泛化能力
到目前为止,在本章中,我们已经看到了如何使用 TensorFlow 训练卷积神经网络来完成图像分类任务。 训练完模型后,我们将其遍历测试集,并从一开始就将其存储起来,以查看其在从未见过的数据上的性能如何。 在测试集上评估模型的过程向我们表明了在部署模型时模型将泛化的程度。 能够很好地概括的模型显然是理想的属性,因为它可以在许多情况下使用。 到目前为止,在本章中,我们已经看到了如何使用 TensorFlow 训练卷积神经网络来完成图像分类任务。 训练完模型后,我们将其遍历测试集,并从一开始就将其存储起来,以查看其在从未见过的数据上的性能如何。 在测试集上评估模型的过程向我们表明了在部署模型时模型将泛化的程度。 能够很好地泛化的模型显然是理想的属性,因为它可以在许多情况下使用。
我们使用的 CNN 架构是可以提高模型泛化能力的方法之一。 要记住的一种简单技术是从设计模型开始就尽可能简单地使用很少的图层或滤镜。 由于非常小的模型很可能无法适应您的数据,因此您可以慢慢增加复杂性,直到不再发生适应不足的情况为止。 如果您以这种方式设计模型,则将限制过拟合的可能性,因为您不允许自己拥有的模型对于数据集而言过大。 我们使用的 CNN 架构是可以提高模型泛化能力的方法之一。 要记住的一种简单技术是从设计模型开始就尽可能简单地使用很少的图层或滤镜。 由于非常小的模型很可能无法适应您的数据,因此您可以慢慢增加复杂性,直到不再发生适应不足的情况为止。 如果您以这种方式设计模型,则将限制过拟合的可能性,因为您不允许自己拥有的模型对于数据集而言过大。
...@@ -671,19 +671,19 @@ fc1 = tf.layers.dense(fc1, 1024) ...@@ -671,19 +671,19 @@ fc1 = tf.layers.dense(fc1, 1024)
fc1 = tf.layers.dropout(fc1, rate=dropout, training=is_training) fc1 = tf.layers.dropout(fc1, rate=dropout, training=is_training)
``` ```
# 批处理规范层 # 批规范层
之前,我们已经完成了权重的初始化工作,以使梯度下降优化器的工作更加轻松。 但是,好处仅在训练的早期阶段才能看到,并不能保证在后期阶段有所改善。 那就是我们转向另一个称为批处理规范层的伟大发明的地方。 在 CNN 模型中使用批处理规范层产生的效果与第 2 章,“深度学习和卷积神经网络”中看到的输入标准化大致相同。 现在唯一的区别是,这将在模型中所有卷积层和完全连接层的输出处发生。 之前,我们已经完成了权重的初始化工作,以使梯度下降优化器的工作更加轻松。 但是,好处仅在训练的早期阶段才能看到,并不能保证在后期阶段有所改善。 那就是我们转向另一个称为批量规范层的伟大发明的地方。 在 CNN 模型中使用批量规范层产生的效果与第 2 章,“深度学习和卷积神经网络”中看到的输入标准化大致相同。 现在唯一的区别是,这将在模型中所有卷积层和完全连接层的输出处发生。
处理规范层通常将附加到每个完全连接或卷积层的末端,但是在激活功能之前,它将对层输出进行规范化,如下图所示。 它通过获取图层输出(一批激活)并减去批次平均值并除以批次标准差来执行此操作,因此图层输出具有零均值和单位标准差。 请注意,在激活函数之前或之后放置批量规范化是一个引起激烈争论的话题,但是两者都应该起作用。 量规范层通常将附加到每个完全连接或卷积层的末端,但是在激活函数之前,它将对层输出进行规范化,如下图所示。 它通过获取图层输出(一批激活)并减去批次平均值并除以批次标准差来执行此操作,因此图层输出具有零均值和单位标准差。 请注意,在激活函数之前或之后放置批量规范化是一个引起激烈争论的话题,但是两者都应该起作用。
![](img/3e1365ac-328e-48f0-8077-920bb837324e.png) ![](img/3e1365ac-328e-48f0-8077-920bb837324e.png)
进行此标准化之后,批处理规范层还具有两个可学习的参数,这些参数将按比例缩放标准化的激活并将其转移到模型认为最有助于其学习的内容。 整个过程通过消除消失的梯度问题来帮助训练。 反过来,这又允许模型在训练时使用更高的学习率,因此可以减少迭代次数。 进行此标准化之后,批规范层还具有两个可学习的参数,这些参数将按比例缩放标准化的激活并将其转移到模型认为最有助于其学习的内容。 整个过程通过消除消失的梯度问题来帮助训练。 反过来,这又允许模型在训练时使用更高的学习率,因此可以减少迭代次数。
在训练过程中,记录平均值和标准差值的移动平均值。 然后在测试时使用这些值,而不是计算批次统计信息。 在训练过程中,记录平均值和标准差值的移动平均值。 然后在测试时使用这些值,而不是计算批次统计信息。
处理规范层的一些优点如下: 规范层的一些优点如下:
* 改善梯度流动,允许训练更深层的网络(解决消失的梯度问题) * 改善梯度流动,允许训练更深层的网络(解决消失的梯度问题)
* 允许更高的学习率,使训练更快 * 允许更高的学习率,使训练更快
...@@ -691,7 +691,7 @@ fc1 = tf.layers.dropout(fc1, rate=dropout, training=is_training) ...@@ -691,7 +691,7 @@ fc1 = tf.layers.dropout(fc1, rate=dropout, training=is_training)
* 给您的模型某种正则化效果 * 给您的模型某种正则化效果
* 使得可以使用饱和非线性,例如 Sigmoid * 使得可以使用饱和非线性,例如 Sigmoid
对于更多的数学读者,可以在批处理规范论文《批处理规范化:通过减少内部协变量偏移来加速深层网络训练》中找到更为正式的定义,这是一篇写得很好的论文,易于理解和解释。 更详细的概念。 如果假设我们有一个仅具有全连接层的简单神经网络,则正如我们在第 1 章,“TensorFlow 简介和设置”中所看到的,每一层的激活将是`s = f(x; W, b) = W · x + b`表格。 对于更多的数学读者,可以在批量规范论文《批量规范化:通过减少内部协变量偏移来加速深层网络训练》中找到更为正式的定义,这是一篇写得很好的论文,易于理解和解释。 更详细的概念。 如果假设我们有一个仅具有全连接层的简单神经网络,则正如我们在第 1 章,“TensorFlow 简介和设置”中所看到的,每一层的激活将是`s = f(x; W, b) = W · x + b`表格。
假设`g(·)`是非线性的,例如 Sigmoid 或 ReLU,然后将批量归一化`BN(·)`直接应用于每个单元,例如: 假设`g(·)`是非线性的,例如 Sigmoid 或 ReLU,然后将批量归一化`BN(·)`直接应用于每个单元,例如:
...@@ -709,7 +709,7 @@ fc1 = tf.layers.dropout(fc1, rate=dropout, training=is_training) ...@@ -709,7 +709,7 @@ fc1 = tf.layers.dropout(fc1, rate=dropout, training=is_training)
其中`γ``β`是可学习的参数,它们将缩放并移动您的标准化激活。 网络可以使用这些参数来决定是否需要标准化以及需要多少标准化。 这是正确的,因为如果我们设置`β = μ``γ = √(δ^s + ε)`,则设置`s[i]^(BN) = s[i]` 其中`γ``β`是可学习的参数,它们将缩放并移动您的标准化激活。 网络可以使用这些参数来决定是否需要标准化以及需要多少标准化。 这是正确的,因为如果我们设置`β = μ``γ = √(δ^s + ε)`,则设置`s[i]^(BN) = s[i]`
最后,这是一个如何在本章开始的分类示例代码中使用批处理规范层的示例。 在这种情况下,我们将批量规范化层放在卷积层之后和激活函数之前: 最后,这是一个如何在本章开始的分类示例代码中使用批规范层的示例。 在这种情况下,我们将批量规范化层放在卷积层之后和激活函数之前:
```py ```py
conv3 = tf.layers.conv2d(inputs=pool2, filters=32, kernel_size=[5, 5],padding="same", activation=None) conv3 = tf.layers.conv2d(inputs=pool2, filters=32, kernel_size=[5, 5],padding="same", activation=None)
...@@ -718,7 +718,7 @@ conv3_bn_relu = tf.nn.relu(conv3_bn) ...@@ -718,7 +718,7 @@ conv3_bn_relu = tf.nn.relu(conv3_bn)
pool3 = tf.layers.max_pooling2d(inputs=conv3_bn_relu, pool_size=[2, 2], strides=2) pool3 = tf.layers.max_pooling2d(inputs=conv3_bn_relu, pool_size=[2, 2], strides=2)
``` ```
# 摘要 # 总结
在本章中,我们了解了 CNN 模型的构建方式,包括使用哪些损失函数。 我们研究了 CIFAR 和互联网数据集,并了解了如何训练 CNN 来对 CIFAR10 数据集进行分类。 为此,我们被引入了 TensorFlow 数据 API,这使加载和转换数据的任务变得更加容易。 最后,我们讨论了通过谈论初始化和正则化的不同方法来提高训练模型的质量的方法。 在本章中,我们了解了 CNN 模型的构建方式,包括使用哪些损失函数。 我们研究了 CIFAR 和互联网数据集,并了解了如何训练 CNN 来对 CIFAR10 数据集进行分类。 为此,我们被引入了 TensorFlow 数据 API,这使加载和转换数据的任务变得更加容易。 最后,我们讨论了通过谈论初始化和正则化的不同方法来提高训练模型的质量的方法。
......
...@@ -4,21 +4,21 @@ ...@@ -4,21 +4,21 @@
为了解决这个更具挑战性的问题,需要进行对象检测和分割。 这些是计算机视觉领域,直到最近仍然非常具有挑战性。 然而,将卷积神经网络应用于这些问题近年来引起了很多关注,因此,在大多数情况下,现在可以考虑解决这些问题。 在本章中,我们将看到 CNN 如何很好地解决这些困难的任务。 为了解决这个更具挑战性的问题,需要进行对象检测和分割。 这些是计算机视觉领域,直到最近仍然非常具有挑战性。 然而,将卷积神经网络应用于这些问题近年来引起了很多关注,因此,在大多数情况下,现在可以考虑解决这些问题。 在本章中,我们将看到 CNN 如何很好地解决这些困难的任务。
下图显示了不同解决方案分段,本地化,检测和实例分段之间的区别: 下图显示了不同解决方案分段,定位,检测和实例分段之间的区别:
![](img/6fcfed2a-e8e5-4678-8b77-f062f301eb31.png) ![](img/6fcfed2a-e8e5-4678-8b77-f062f301eb31.png)
在开始讨论对象检测之前,我们需要了解另一个重要概念-本地化。 它是改善分类和启用检测的关键构建块。 我们将看到这三个概念彼此密切相关,这是因为我们从图像分类到具有定位的分类,最后是对象检测。 在开始讨论对象检测之前,我们需要了解另一个重要概念-定位。 它是改善分类和启用检测的关键构建块。 我们将看到这三个概念彼此密切相关,这是因为我们从图像分类到具有定位的分类,最后是对象检测。
在本章中,我们将学习以下有趣的主题: 在本章中,我们将学习以下有趣的主题:
* 图像分类与本地化 * 图像分类与定位
* 物体检测 * 物体检测
* 语义分割 * 语义分割
* 实例细分 * 实例细分
* 如何构建卷积神经网络来执行所有这些任务 * 如何构建卷积神经网络来执行所有这些任务
# 图像分类与本地化 # 图像分类与定位
在上一章学习了图像分类之后,我们现在知道对图像进行分类时,我们只是试图在该图像内输出对象的类标签。 通常,为了简化任务,图像中将只有一个对象。 在上一章学习了图像分类之后,我们现在知道对图像进行分类时,我们只是试图在该图像内输出对象的类标签。 通常,为了简化任务,图像中将只有一个对象。
...@@ -26,9 +26,9 @@ ...@@ -26,9 +26,9 @@
当我们建立一个负责预测类别标签以及感兴趣对象周围的边界框的模型时,称为带有局部化的**图像分类** 当我们建立一个负责预测类别标签以及感兴趣对象周围的边界框的模型时,称为带有局部化的**图像分类**
# 本地化为回归 # 作为回归的定位
可以使用与我们在第 3 章, “TensorFlow 中的图像分类”中了解的网络架构相似的网络架构来实现本地化 可以使用与我们在第 3 章, “TensorFlow 中的图像分类”中了解的网络架构相似的网络架构来实现定位
除了预测类标签外,我们还将输出一个标志,指示对象的存在以及对象边界框的坐标。 边界框坐标通常是四个数字,分别代表左上角的`x``y`坐标,以及框的高度和宽度。 除了预测类标签外,我们还将输出一个标志,指示对象的存在以及对象边界框的坐标。 边界框坐标通常是四个数字,分别代表左上角的`x``y`坐标,以及框的高度和宽度。
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
1. 我们将输入图像输入到 CNN。 1. 我们将输入图像输入到 CNN。
2. CNN 产生一个特征向量,该特征向量被馈送到三个不同的 FC 层。 这些不同的 FC 层(或负责人)中的每一个都将负责预测不同的事物:对象存在,对象位置或对象类。 2. CNN 产生一个特征向量,该特征向量被馈送到三个不同的 FC 层。 这些不同的 FC 层(或负责人)中的每一个都将负责预测不同的事物:对象存在,对象位置或对象类。
3. 训练中使用了三种不同的损:每个头部一个。 3. 训练中使用了三种不同的损:每个头部一个。
4. 计算当前训练批次的比率,以权衡给定物体的存在对分类和位置损失的影响。 例如,如果批次中只有 10% 的物体图像,那么这些损失将乘以 0.1。 4. 计算当前训练批次的比率,以权衡给定物体的存在对分类和位置损失的影响。 例如,如果批次中只有 10% 的物体图像,那么这些损失将乘以 0.1。
提醒一下:输出数字(即 4 个边界框坐标)称为**回归** 提醒一下:输出数字(即 4 个边界框坐标)称为**回归**
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
![](img/6a08d3d3-b216-46bf-9d8a-6ca5e8c715ff.png) ![](img/6a08d3d3-b216-46bf-9d8a-6ca5e8c715ff.png)
从图中可以清楚地看到三个全连接层,每个层都输出不同的损(状态,类和框)。 使用的损失是逻辑回归/对数损失,交叉熵/ softmax 损失和 Huber 损失。 胡贝尔损失是我们从未见过的损失。 这是用于回归的损失,是 L1 和 L2 损失的一种组合。 从图中可以清楚地看到三个全连接层,每个层都输出不同的损(状态,类和框)。 使用的损失是逻辑回归/对数损失,交叉熵/ softmax 损失和 Huber 损失。 胡贝尔损失是我们从未见过的损失。 这是用于回归的损失,是 L1 和 L2 损失的一种组合。
局部化的回归损失给出了图像中对象的真实情况边界框坐标与模型预测的边界框坐标之间的某种相似度度量。 我们在这里使用 Huber 损失,但是可以使用各种不同的损失函数,例如 L2,L1 或平滑 L1 损失。 局部化的回归损失给出了图像中对象的真实情况边界框坐标与模型预测的边界框坐标之间的某种相似度度量。 我们在这里使用 Huber 损失,但是可以使用各种不同的损失函数,例如 L2,L1 或平滑 L1 损失。
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
![](img/23f8f2a5-2aef-4ef5-a0ab-b25718aa8330.png) ![](img/23f8f2a5-2aef-4ef5-a0ab-b25718aa8330.png)
# TensorFlow 实 # TensorFlow 实
现在,我们将介绍如何在 TensorFlow 中实现这种模型。 它与分类模型极为相似,不同之处在于,我们在末尾有多个输出层而不是只有一个,并且每个层都有自己的损失函数: 现在,我们将介绍如何在 TensorFlow 中实现这种模型。 它与分类模型极为相似,不同之处在于,我们在末尾有多个输出层而不是只有一个,并且每个层都有自己的损失函数:
...@@ -118,7 +118,7 @@ def build_graph(self): ...@@ -118,7 +118,7 @@ def build_graph(self):
self.__session.run(init) self.__session.run(init)
``` ```
# 本地化的其他应用 # 定位的其他应用
使用 CNN 在图像中输出兴趣点坐标的想法可以扩展到许多其他应用程序。 其中一些包括人体姿势估计(《DeepPose:通过深度神经网络进行人体姿势估计》),如下所示: 使用 CNN 在图像中输出兴趣点坐标的想法可以扩展到许多其他应用程序。 其中一些包括人体姿势估计(《DeepPose:通过深度神经网络进行人体姿势估计》),如下所示:
...@@ -130,7 +130,7 @@ def build_graph(self): ...@@ -130,7 +130,7 @@ def build_graph(self):
![](img/aba4ce64-8355-48f9-ac0f-d5273a05bb1c.png) ![](img/aba4ce64-8355-48f9-ac0f-d5273a05bb1c.png)
# 对象检测作为分类–滑动窗口 # 作为分类的对象检测 – 滑动窗口
对象检测与定位是一个不同的问题,因为我们可以在图像中包含数量可变的对象。 因此,如果我们将检测视为像定位一样简单的回归问题,处理可变数量的输出将变得非常棘手。 因此,我们将检测视为分类问题。 对象检测与定位是一个不同的问题,因为我们可以在图像中包含数量可变的对象。 因此,如果我们将检测视为像定位一样简单的回归问题,处理可变数量的输出将变得非常棘手。 因此,我们将检测视为分类问题。
...@@ -156,9 +156,9 @@ def build_graph(self): ...@@ -156,9 +156,9 @@ def build_graph(self):
# 问题 # 问题
R-CNN 在计算上仍然很昂贵,因为您必须对大约 2,000 个单独的区域提案运行 CNN。 结果,训练和测试都非常慢。 CNN 分类器依赖于通过选择性搜索进行检测而生成的固定数量的矩形候选窗口。 这种方法并不是最快的方法,而且由于无法从训练数据中了解提案区域,因此它们可能不是针对任务的最佳选择。 R-CNN 在计算上仍然很昂贵,因为您必须对大约 2,000 个单独的区域候选运行 CNN。 结果,训练和测试都非常慢。 CNN 分类器依赖于通过选择性搜索进行检测而生成的固定数量的矩形候选窗口。 这种方法并不是最快的方法,而且由于无法从训练数据中了解候选区域,因此它们可能不是针对任务的最佳选择。
# 快速 R-CNN # Fast R-CNN
2015 年,提出了快速 R-CNN 来解决 R-CNN 的速度问题。 在此方法中,主要的变化是我们在管道中获取投标区域的位置。 首先,我们通过 CNN 运行整个输入图像,而不是从输入图像中直接获取它们,并提取靠近网络末端的生成的特征图。 接下来,再次使用区域提议方法,以与 R-CNN 类似的方式从该特征图中提取候选区域。 2015 年,提出了快速 R-CNN 来解决 R-CNN 的速度问题。 在此方法中,主要的变化是我们在管道中获取投标区域的位置。 首先,我们通过 CNN 运行整个输入图像,而不是从输入图像中直接获取它们,并提取靠近网络末端的生成的特征图。 接下来,再次使用区域提议方法,以与 R-CNN 类似的方式从该特征图中提取候选区域。
...@@ -168,15 +168,15 @@ R-CNN 在计算上仍然很昂贵,因为您必须对大约 2,000 个单独的 ...@@ -168,15 +168,15 @@ R-CNN 在计算上仍然很昂贵,因为您必须对大约 2,000 个单独的
R-CNN 与 FastRCNN 的比较表明,后者在训练时快约 10 倍,而在测试时快约 150 倍(使用 VGG 架构作为主要 CNN 时)。 R-CNN 与 FastRCNN 的比较表明,后者在训练时快约 10 倍,而在测试时快约 150 倍(使用 VGG 架构作为主要 CNN 时)。
# 更快的 R-CNN # Faster R-CNN
这项技术在 2015 年 Fast R-CNN 之后不久提出,解决了使用外部区域建议方法的需求,并消除了与之相关的计算成本。 这项技术在 2015 年 Fast R-CNN 之后不久提出,解决了使用外部区域建议方法的需求,并消除了与之相关的计算成本。
该算法的主要区别在于,不是使用外部算法(例如选择性搜索)来创建提案,而是使用称为**区域候选网络****RPN**)的子网为我们学习并提出建议。 在此屏幕快照中显示: 该算法的主要区别在于,不是使用外部算法(例如选择性搜索)来创建候选,而是使用称为**区域候选网络****RPN**)的子网为我们学习并提出建议。 在此屏幕快照中显示:
![](img/126d2b47-420b-482c-a03f-a43408f3fd04.jpg) ![](img/126d2b47-420b-482c-a03f-a43408f3fd04.jpg)
# 区域提案 # 区域候选
RPN 的工作是预测我们称为锚点的对象(本质上只是一个边界框)是否包含对象或仅是背景,然后完善此边界框的位置。 RPN 的工作是预测我们称为锚点的对象(本质上只是一个边界框)是否包含对象或仅是背景,然后完善此边界框的位置。
...@@ -186,7 +186,7 @@ RPN 的工作是预测我们称为锚点的对象(本质上只是一个边界 ...@@ -186,7 +186,7 @@ RPN 的工作是预测我们称为锚点的对象(本质上只是一个边界
在内部,在训练过程中,我们选择 IoU 最大的锚定边界框和真实情况边界框进行反向传播。 在内部,在训练过程中,我们选择 IoU 最大的锚定边界框和真实情况边界框进行反向传播。
# RoI 汇聚 # RoI 池化
RoI 池层只是最大池的一种,池的大小取决于输入的大小。 这样做可以确保输出始终具有相同的大小。 使用该层是因为全连接层始终期望输入大小相同,但是 FC 层的输入区域可能具有不同的大小。 RoI 池层只是最大池的一种,池的大小取决于输入的大小。 这样做可以确保输出始终具有相同的大小。 使用该层是因为全连接层始终期望输入大小相同,但是 FC 层的输入区域可能具有不同的大小。
...@@ -202,7 +202,7 @@ RoI 层的输入将是建议和最后的卷积层激活。 例如,考虑以下 ...@@ -202,7 +202,7 @@ RoI 层的输入将是建议和最后的卷积层激活。 例如,考虑以下
| 加速 | 1 倍 | 25 倍 | 250 倍 | | 加速 | 1 倍 | 25 倍 | 250 倍 |
| 准确性 | 66% | 66.9% | 66.9% | | 准确性 | 66% | 66.9% | 66.9% |
# 从传统的 CNN 转换为完全卷积网络 # 将传统的 CNN 转换为全卷积网络
对于有效的对象检测器而言,非常重要的一点是提高卷积,从而提高计算的重用性​​。 为此,我们将所有 FC 层转换为卷积层,如下图所示。 对于有效的对象检测器而言,非常重要的一点是提高卷积,从而提高计算的重用性​​。 为此,我们将所有 FC 层转换为卷积层,如下图所示。
...@@ -218,7 +218,7 @@ RoI 层的输入将是建议和最后的卷积层激活。 例如,考虑以下 ...@@ -218,7 +218,7 @@ RoI 层的输入将是建议和最后的卷积层激活。 例如,考虑以下
![](img/df71541c-cdad-4bda-ae6e-5c8062047d8d.png) ![](img/df71541c-cdad-4bda-ae6e-5c8062047d8d.png)
# 单发检测器您只看一次 # 单发检测器您只看一次
在本节中,我们将继续介绍一种稍有不同的对象检测器,称为单发检测器。 单发检测器尝试将对象检测伪装为回归问题。 此类别下的主要架构之一是 YOLO 架构(您只看一次),我们现在将对其进行详细介绍。 在本节中,我们将继续介绍一种稍有不同的对象检测器,称为单发检测器。 单发检测器尝试将对象检测伪装为回归问题。 此类别下的主要架构之一是 YOLO 架构(您只看一次),我们现在将对其进行详细介绍。
...@@ -268,7 +268,7 @@ YOLO 网络的主要思想是在不使用任何滑动窗口的情况下优化输 ...@@ -268,7 +268,7 @@ YOLO 网络的主要思想是在不使用任何滑动窗口的情况下优化输
对于大小为`NxM`的输入训练图像,训练后从卷积网络输出的目标向量的最终体积将为`3x3x16`(在此玩具示例中) 对于大小为`NxM`的输入训练图像,训练后从卷积网络输出的目标向量的最终体积将为`3x3x16`(在此玩具示例中)
数据集中每个图像的标签信息将仅包括对象的中心坐标及其边界框。 实代码以使其与网络的输出向量相匹配是您的责任; 这些任务包括以下所列的任务: 数据集中每个图像的标签信息将仅包括对象的中心坐标及其边界框。 实代码以使其与网络的输出向量相匹配是您的责任; 这些任务包括以下所列的任务:
1. 将每个中心点的图像空间转换为网格空间 1. 将每个中心点的图像空间转换为网格空间
2. 将图像空间上的边界框尺寸转换为网格空间尺寸 2. 将图像空间上的边界框尺寸转换为网格空间尺寸
...@@ -282,9 +282,9 @@ YOLO 网络的主要思想是在不使用任何滑动窗口的情况下优化输 ...@@ -282,9 +282,9 @@ YOLO 网络的主要思想是在不使用任何滑动窗口的情况下优化输
我们还需要定义一个条件类别概率; 给定对象`P(class | Pr)`的存在,我们想要这样做是因为我们不希望损失函数在单元格上没有对象的情况下惩罚错误的类预测。 该网络仅预测每个单元格的一组类别概率,而不考虑框数`B` 我们还需要定义一个条件类别概率; 给定对象`P(class | Pr)`的存在,我们想要这样做是因为我们不希望损失函数在单元格上没有对象的情况下惩罚错误的类预测。 该网络仅预测每个单元格的一组类别概率,而不考虑框数`B`
# 评估检测(并口交集 # 评估检测(交并比
在继续进行之前,我们需要知道如何衡量我们的模型是否正确检测到物体。 为此,我们计算会返回一个数字的联合交叉点(IoU),根据某个参考(真实情况)告诉我们检测的效果如何。 IoU 的计算方法是:将检测和地面真理框彼此重叠的区域除以检测和地面真理框所覆盖的总面积: 在继续进行之前,我们需要知道如何衡量我们的模型是否正确检测到物体。 为此,我们计算会返回一个数字的交并比(IoU),根据某个参考(真实情况)告诉我们检测的效果如何。 IoU 的计算方法是:将检测和地面真理框彼此重叠的区域除以检测和地面真理框所覆盖的总面积:
![](img/8a083f5a-2925-4206-abc5-7cdfc4a3ba0b.png) ![](img/8a083f5a-2925-4206-abc5-7cdfc4a3ba0b.png)
...@@ -395,7 +395,7 @@ def tf_iou_vectorized(self, box_vec_1, box_vec_2): ...@@ -395,7 +395,7 @@ def tf_iou_vectorized(self, box_vec_1, box_vec_2):
Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image.non_max_suppression` Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image.non_max_suppression`
# 锚 # 锚
锚框预定义的模板框,具有一定的高宽比。 这些在 YOLO 中用于帮助检测单个网格单元中的多个对象。 我们根据可以检测到的物体类型的大致几何形状定义盒子的形状。 锚框预定义的模板框,具有一定的高宽比。 这些在 YOLO 中用于帮助检测单个网格单元中的多个对象。 我们根据可以检测到的物体类型的大致几何形状定义盒子的形状。
...@@ -415,13 +415,13 @@ Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image ...@@ -415,13 +415,13 @@ Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image
在最后阶段,我们可以使用非最大值抑制算法过滤每个像元中的多个预测边界框。 在最后阶段,我们可以使用非最大值抑制算法过滤每个像元中的多个预测边界框。
# 检测器损耗功能(YOLO 损耗 # 检测器损失函数(YOLO 损失
作为定位器,YOLO 损失函数分为三个部分:负责查找边界框坐标,边界框分数预测和类分数预测的部分。 它们都是均方误差损失,并由预测和真实情况情况之间的一些标量元参数或 IoU 得分进行调制: 作为定位器,YOLO 损失函数分为三个部分:负责查找边界框坐标,边界框分数预测和类分数预测的部分。 它们都是均方误差损失,并由预测和真实情况情况之间的一些标量元参数或 IoU 得分进行调制:
![](img/7b0edf3c-b27d-4d1a-952d-ad10176656fd.png) ![](img/7b0edf3c-b27d-4d1a-952d-ad10176656fd.png)
成员`1[ij]^obj`成员用于基于特定单元`i, j`上对象的存在来调制损 成员`1[ij]^obj`成员用于基于特定单元`i, j`上对象的存在来调制损
* 如果在网格单元格`i`和第`i`个边界框中具有最高 IoU 的对象存在:1 * 如果在网格单元格`i`和第`i`个边界框中具有最高 IoU 的对象存在:1
* 否则:0 * 否则:0
...@@ -432,7 +432,7 @@ Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image ...@@ -432,7 +432,7 @@ Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image
![](img/957dd494-38eb-4b48-9961-30a36494c0dd.png) ![](img/957dd494-38eb-4b48-9961-30a36494c0dd.png)
第一部分计算与预测的边界框位置坐标`(x, y)`相关的损`(x_hat, y_hat)`是训练集中真实情况数据的边界框坐标。 第一部分计算与预测的边界框位置坐标`(x, y)`相关的损`(x_hat, y_hat)`是训练集中真实情况数据的边界框坐标。
`λ[coord] = 5.0`表示一个常数,当有错误时,该常数将给予更多的补偿。 `B`是边界框的数量。 `S^2`是网格中的单元数。 `λ[coord] = 5.0`表示一个常数,当有错误时,该常数将给予更多的补偿。 `B`是边界框的数量。 `S^2`是网格中的单元数。
...@@ -556,7 +556,7 @@ def loss_layer(self, predicts, labels, scope='loss_layer'): ...@@ -556,7 +556,7 @@ def loss_layer(self, predicts, labels, scope='loss_layer'):
* 我们需要一个 Argmax 层来选择输出张量上概率最大的像素(仅在预测时间内) * 我们需要一个 Argmax 层来选择输出张量上概率最大的像素(仅在预测时间内)
* 我们的损失需要考虑输出张量上的所有像素 * 我们的损失需要考虑输出张量上的所有像素
# 最大分 # 最大分
取消池操作用于恢复最大池操作的效果。 这个想法只是充当上采样器。 此操作已在一些较早的论文上使用,并且不再使用,因为您还需要卷积层来修补(低通滤波器)上采样的结果: 取消池操作用于恢复最大池操作的效果。 这个想法只是充当上采样器。 此操作已在一些较早的论文上使用,并且不再使用,因为您还需要卷积层来修补(低通滤波器)上采样的结果:
...@@ -616,7 +616,7 @@ with tf.name_scope("SPATIAL_SOFTMAX"): ...@@ -616,7 +616,7 @@ with tf.name_scope("SPATIAL_SOFTMAX"):
![](img/752b45a8-16ce-48eb-99b7-a1ca80b40d40.png) ![](img/752b45a8-16ce-48eb-99b7-a1ca80b40d40.png)
# 实例细分 # 实例分割
实例分割是我们在本章中要讨论的最后一件事。 在许多方面,可以将其视为对象检测和语义分段的融合。 但是,与这两个问题相比,这绝对是难度增加。 实例分割是我们在本章中要讨论的最后一件事。 在许多方面,可以将其视为对象检测和语义分段的融合。 但是,与这两个问题相比,这绝对是难度增加。
...@@ -638,7 +638,7 @@ Mask R-CNN 是一种最近的网络体系结构,通过提供简单,灵活的 ...@@ -638,7 +638,7 @@ Mask R-CNN 是一种最近的网络体系结构,通过提供简单,灵活的
它采用现有的更快的 R-CNN 模型,并尝试通过向模型中添加一个分支来解决实例分割问题,该分支负责预测与分类和边界框回归头平行的对象蒙版。 在发布时,该架构被证明是有效的,并且在所有 COCO 挑战中均获得了最高荣誉。 它采用现有的更快的 R-CNN 模型,并尝试通过向模型中添加一个分支来解决实例分割问题,该分支负责预测与分类和边界框回归头平行的对象蒙版。 在发布时,该架构被证明是有效的,并且在所有 COCO 挑战中均获得了最高荣誉。
# 摘要 # 总结
在本章中,我们学习了对象定位,检测和分段的基础知识。 我们还讨论了与这些主题相关的最著名的算法。 在本章中,我们学习了对象定位,检测和分段的基础知识。 我们还讨论了与这些主题相关的最著名的算法。
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* 如何提高参数效率 * 如何提高参数效率
* 如何在 TensorFlow 中实现 VGG 网络 * 如何在 TensorFlow 中实现 VGG 网络
* 如何在 TensorFlow 中实现 Inception 网络 * 如何在 TensorFlow 中实现 Inception 网络
* 如何在 TensorFlow 中实残差网络 * 如何在 TensorFlow 中实残差网络
* 如何实现对移动设备更友好的体系结构 * 如何实现对移动设备更友好的体系结构
# 替代大卷积 # 替代大卷积
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
![](img/5eaf2681-cfa7-4907-b95f-c6204b5c4721.png) ![](img/5eaf2681-cfa7-4907-b95f-c6204b5c4721.png)
当我们说“感受”时,是指它可以从上一层看到的区域。 在此示例中,需要一个`3x3`区域来创建一个输出,因此需要一个`3x3`的感受域。 当我们说“感受”时,是指它可以从上一层看到的区域。 在此示例中,需要一个`3x3`区域来创建一个输出,因此需要一个`3x3`的感受域。
回溯到另一层,该`3x3`区域的每个元素在输入端也具有`3x3`感受域。 因此,如果我们将所有这 9 个元素的接受场组合在一起,那么我们可以看到在输入上创建的总接受场大小为`5x5` 回溯到另一层,该`3x3`区域的每个元素在输入端也具有`3x3`感受域。 因此,如果我们将所有这 9 个元素的接受场组合在一起,那么我们可以看到在输入上创建的总接受场大小为`5x5`
...@@ -108,7 +108,7 @@ VGG 最酷的功能之一是,由于其在 conv 层中的内核较小,因此 ...@@ -108,7 +108,7 @@ VGG 最酷的功能之一是,由于其在 conv 层中的内核较小,因此
到那时为止,这是所有参数的六倍以上! 到那时为止,这是所有参数的六倍以上!
如前所述,您需要在训练数据集中使用大量样本来消耗模型参数,因此最好避免过度使用全连接层来避免参数爆炸。 幸运的是,人们发现,如果最后只有一层而不是三层,那么 VGGNet 的工作原理几乎相同。 因此,删除这些全连接层会从模型中删除大量参数,而不会大大降低性能。 因此,如果您决定实 VGGNet,我们建议您也这样做。 如前所述,您需要在训练数据集中使用大量样本来消耗模型参数,因此最好避免过度使用全连接层来避免参数爆炸。 幸运的是,人们发现,如果最后只有一层而不是三层,那么 VGGNet 的工作原理几乎相同。 因此,删除这些全连接层会从模型中删除大量参数,而不会大大降低性能。 因此,如果您决定实 VGGNet,我们建议您也这样做。
# 码 # 码
...@@ -202,7 +202,7 @@ VGG 最酷的功能之一是,由于其在 conv 层中的内核较小,因此 ...@@ -202,7 +202,7 @@ VGG 最酷的功能之一是,由于其在 conv 层中的内核较小,因此
# 关于 VGG 的更多信息 # 关于 VGG 的更多信息
2014 年,VGG 在 Imagenet 分类挑战中获得第二名,在 Imagenet 本地化挑战中获得第一名。 正如我们所看到的,VGGNet 的设计选择是堆叠许多小的卷积层,从而可以实现更深的结构,同时具有更少的参数(如果我们删除了不必要的全连接层),则性能更好。 这种设计选择在创建强大而高效的网络方面非常有效,以至于几乎所有现代体系结构都复制了这种想法,并且很少(如果有的话)使用大型过滤器。 2014 年,VGG 在 Imagenet 分类挑战中获得第二名,在 Imagenet 定位挑战中获得第一名。 正如我们所看到的,VGGNet 的设计选择是堆叠许多小的卷积层,从而可以实现更深的结构,同时具有更少的参数(如果我们删除了不必要的全连接层),则性能更好。 这种设计选择在创建强大而高效的网络方面非常有效,以至于几乎所有现代体系结构都复制了这种想法,并且很少(如果有的话)使用大型过滤器。
事实证明,VGG 模型可以在许多任务中很好地工作,并且由于其简单的体系结构,它是开始尝试或适应问题需求的理想模型。 但是,它确实有以下问题需要注意: 事实证明,VGG 模型可以在许多任务中很好地工作,并且由于其简单的体系结构,它是开始尝试或适应问题需求的理想模型。 但是,它确实有以下问题需要注意:
...@@ -297,11 +297,11 @@ def inception_block_a(x, name='inception_a'): ...@@ -297,11 +297,11 @@ def inception_block_a(x, name='inception_a'):
# 有关 GoogLeNet 的更多信息 # 有关 GoogLeNet 的更多信息
GoogLeNet 的主要优点是,它比 VGG 更为准确,同时使用的参数更少,计算能力也更低。 主要的缺点仍然是,如果我们开始堆叠很多初始层,梯度将消失,而且整个网络具有多个分支和多个损的设计相当复杂。 GoogLeNet 的主要优点是,它比 VGG 更为准确,同时使用的参数更少,计算能力也更低。 主要的缺点仍然是,如果我们开始堆叠很多初始层,梯度将消失,而且整个网络具有多个分支和多个损的设计相当复杂。
# 残差网络 # 残差网络
在前面的部分中,已经证明了网络的深度是有助于提高准确性的关键因素(请参见 VGG)。 TensorFlow 中的第 3 章“图像分类”中也显示,可以通过正确的权重初始化和批处理归一化来缓解深度网络中梯度消失或爆炸的问题。 但是,这是否意味着我们添加的层越多,我们得到的系统就越准确? 亚洲研究机构 Microsoft 的《用于图像识别的深度残差学习》的作者发现,只要网络深度达到 30 层,准确性就会达到饱和。 为了解决此问题,他们引入了一个称为残差块的新层块,该块将上一层的输出添加到下一层的输出中(请参见下图)。 残差网络或 ResNet 在非常深的网络(甚至超过 100 层!)中都显示了出色的结果,例如 152 层的 ResNet 赢得了 2015 LRVC 图像识别挑战,其前 5 个测试错误为 3.57。 事实证明,诸如 ResNets 之类的更深层网络要比包括 Inception 模块(例如 GoogLeNet)在内的更广泛的网络更好地工作。 在前面的部分中,已经证明了网络的深度是有助于提高准确性的关键因素(请参见 VGG)。 TensorFlow 中的第 3 章“图像分类”中也显示,可以通过正确的权重初始化和批归一化来缓解深度网络中梯度消失或爆炸的问题。 但是,这是否意味着我们添加的层越多,我们得到的系统就越准确? 亚洲研究机构 Microsoft 的《用于图像识别的深度残差学习》的作者发现,只要网络深度达到 30 层,准确性就会达到饱和。 为了解决此问题,他们引入了一个称为残差块的新层块,该块将上一层的输出添加到下一层的输出中(请参见下图)。 残差网络或 ResNet 在非常深的网络(甚至超过 100 层!)中都显示了出色的结果,例如 152 层的 ResNet 赢得了 2015 LRVC 图像识别挑战,其前 5 个测试错误为 3.57。 事实证明,诸如 ResNets 之类的更深层网络要比包括 Inception 模块(例如 GoogLeNet)在内的更广泛的网络更好地工作。
![](img/d8ad63df-15dd-4d20-b918-a3f18767a9c8.png) ![](img/d8ad63df-15dd-4d20-b918-a3f18767a9c8.png)
...@@ -412,7 +412,7 @@ MobileNets 使用两个超参数来帮助控制精度和速度之间的折衷, ...@@ -412,7 +412,7 @@ MobileNets 使用两个超参数来帮助控制精度和速度之间的折衷,
但是,目前尚无良好(快速)的深度卷积实现可在 GPU 上运行。 结果,训练可能会比使用正常的卷积运算慢。 但是,此网络目前真正发挥作用的地方是小型 CPU 设计,提高的效率更加明显。 但是,目前尚无良好(快速)的深度卷积实现可在 GPU 上运行。 结果,训练可能会比使用正常的卷积运算慢。 但是,此网络目前真正发挥作用的地方是小型 CPU 设计,提高的效率更加明显。
# 摘要 # 总结
在本章中,我们向您介绍了各种卷积神经网络设计,这些设计已经证明了它们的有效性,因此被广泛使用。 我们首先介绍牛津大学 VGG 的 VGGNet 模型。 接下来,在最终讨论微软的残差网络之前,我们先使用 Google 的 GoogLeNet。 此外,我们还向您展示了一种更高级的新型卷积,该模型在名为 MobileNet 的模型设计中具有特色。 在整个过程中,我们讨论了使每个网络如此出色的不同属性和设计选择,例如跳过连接,堆叠小型过滤器或启动模块。 最后,给出了代码,向您展示了如何在 TensorFlow 中写出这些网络。 在本章中,我们向您介绍了各种卷积神经网络设计,这些设计已经证明了它们的有效性,因此被广泛使用。 我们首先介绍牛津大学 VGG 的 VGGNet 模型。 接下来,在最终讨论微软的残差网络之前,我们先使用 Google 的 GoogLeNet。 此外,我们还向您展示了一种更高级的新型卷积,该模型在名为 MobileNet 的模型设计中具有特色。 在整个过程中,我们讨论了使每个网络如此出色的不同属性和设计选择,例如跳过连接,堆叠小型过滤器或启动模块。 最后,给出了代码,向您展示了如何在 TensorFlow 中写出这些网络。
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* 汽车编码器 * 汽车编码器
* 变分自编码器 * 变分自编码器
* 生成对抗网络 * 生成对抗网络
*各种生成模型以生成手写数字 *各种生成模型以生成手写数字
# 为什么要生成模型 # 为什么要生成模型
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
![](img/460f5473-9a64-4f05-8479-e9f9f36b5eb4.png) ![](img/460f5473-9a64-4f05-8479-e9f9f36b5eb4.png)
对于任何自编码器,损失函数都会引导编码器和解码器重建输入。 使用的常见损耗是自编码器的输出与网络输入之间的 L2 损耗。 我们现在应该问自己一个问题:“使用 L2 损失比较图像是一个好主意吗?”。 如果您拍摄以下图像,即使它们看起来截然不同,它们实际上彼此之间的距离`L2`也相同: 对于任何自编码器,损失函数都会引导编码器和解码器重建输入。 使用的常见损失是自编码器的输出与网络输入之间的 L2 损失。 我们现在应该问自己一个问题:“使用 L2 损失比较图像是一个好主意吗?”。 如果您拍摄以下图像,即使它们看起来截然不同,它们实际上彼此之间的距离`L2`也相同:
![](img/1d80926b-a372-459a-8c13-ab3f74dd6fc5.png) ![](img/1d80926b-a372-459a-8c13-ab3f74dd6fc5.png)
...@@ -139,11 +139,11 @@ with tf.name_scope("Solver"): ...@@ -139,11 +139,11 @@ with tf.name_scope("Solver"):
![](img/ce4aa377-1bf4-483a-ab86-23ab2b9dc716.jpg) ![](img/ce4aa377-1bf4-483a-ab86-23ab2b9dc716.jpg)
# VAE 损失功能 # VAE 损失函数
在 VAE 中,损失函数由两部分组成: 在 VAE 中,损失函数由两部分组成:
* **生成损失**:此损失将模型输出与模型输入进行比较。 这可能是我们在自编码器中使用的损耗,例如 L2 损耗 * **生成损失**:此损失将模型输出与模型输入进行比较。 这可能是我们在自编码器中使用的损失,例如 L2 损失
* **潜在损失**:此损失将潜在向量与零均值,单位方差高斯分布进行比较。 我们在这里使用的损失将是 KL 散度损失。 如果 VAE 开始产生不是来自所需分布的潜在向量,则该损失项将对 VAE 造成不利影响。 * **潜在损失**:此损失将潜在向量与零均值,单位方差高斯分布进行比较。 我们在这里使用的损失将是 KL 散度损失。 如果 VAE 开始产生不是来自所需分布的潜在向量,则该损失项将对 VAE 造成不利影响。
以下屏幕截图显示了 VAE 的损失,它是生成损失和潜在空间损失的组合: 以下屏幕截图显示了 VAE 的损失,它是生成损失和潜在空间损失的组合:
...@@ -154,7 +154,7 @@ with tf.name_scope("Solver"): ...@@ -154,7 +154,7 @@ with tf.name_scope("Solver"):
KL 散度损失将产生一个数字,该数字指示两个分布彼此之间的接近程度。 KL 散度损失将产生一个数字,该数字指示两个分布彼此之间的接近程度。
两个分布之间的距离越近,损就越低。 在下图中,蓝色分布正在尝试对绿色分布进行建模。 随着蓝色分布越来越接近绿色分布,KL 散度损失将接近于零。 两个分布之间的距离越近,损就越低。 在下图中,蓝色分布正在尝试对绿色分布进行建模。 随着蓝色分布越来越接近绿色分布,KL 散度损失将接近于零。
![](img/3f81672f-26ea-446b-97b4-2b6119614be7.png) ![](img/3f81672f-26ea-446b-97b4-2b6119614be7.png)
...@@ -331,7 +331,7 @@ class VAE_CNN_GEN(object): ...@@ -331,7 +331,7 @@ class VAE_CNN_GEN(object):
![](img/98fcbf21-46e3-45f0-8a2d-a7004af773c3.png) ![](img/98fcbf21-46e3-45f0-8a2d-a7004af773c3.png)
鉴别器和发生器都将具有自己的损耗函数,但是它们的损耗都相互依赖。 鉴别器和发生器都将具有自己的损失函数,但是它们的损失都相互依赖。
让我们总结一下 GAN 模型的两个主要模块或网络: 让我们总结一下 GAN 模型的两个主要模块或网络:
...@@ -349,7 +349,7 @@ GAN 的一些实际用法如下: ...@@ -349,7 +349,7 @@ GAN 的一些实际用法如下:
# 鉴别器 # 鉴别器
我们需要做的第一件事就是创建我们的区分网络。 为此,我们将几个全连接层堆叠在一起。 鉴别器将 784 个长度向量作为输入,这是我们的`28x28` MNIST 图像变平。 每个图像的输出将只是一个数字,这是鉴别者对该图像为真实图像的信心程度的分数。 我们使用 Leaky ReLu 作为激活功能,以防止 ReLu 单元死亡。 我们需要做的第一件事就是创建我们的区分网络。 为此,我们将几个全连接层堆叠在一起。 鉴别器将 784 个长度向量作为输入,这是我们的`28x28` MNIST 图像变平。 每个图像的输出将只是一个数字,这是鉴别者对该图像为真实图像的信心程度的分数。 我们使用 Leaky ReLu 作为激活函数,以防止 ReLu 单元死亡。
我们返回原始对率,因为损失函数将为我们应用 Sigmoid 激活函数,以确保鉴别器输出在 0 到 1 之间: 我们返回原始对率,因为损失函数将为我们应用 Sigmoid 激活函数,以确保鉴别器输出在 0 到 1 之间:
...@@ -381,7 +381,7 @@ def generator(z): ...@@ -381,7 +381,7 @@ def generator(z):
# GAN 损失函数 # GAN 损失函数
如前所述,鉴别器和生成器都有自己的损函数,这些函数取决于彼此网络的输出。 我们可以将 GAN 视为在鉴别器和生成器之间玩 minimax 游戏,如下所示: 如前所述,鉴别器和生成器都有自己的损函数,这些函数取决于彼此网络的输出。 我们可以将 GAN 视为在鉴别器和生成器之间玩 minimax 游戏,如下所示:
![](img/1d24b043-c4b8-42f0-8f9c-8f2c7db22ec3.png) ![](img/1d24b043-c4b8-42f0-8f9c-8f2c7db22ec3.png)
...@@ -397,7 +397,7 @@ def generator(z): ...@@ -397,7 +397,7 @@ def generator(z):
![](img/82987b0d-594f-4f08-9c76-436c0ec89fbc.png) ![](img/82987b0d-594f-4f08-9c76-436c0ec89fbc.png)
# 发电机损 # 发电机损
生成器想要欺骗鉴别器,换句话说,使鉴别器输出`q`用于生成的图像`G(z)`。 发生器损失只是施加到发生器结果的鉴别器输出的二项式交叉熵损失的负值。 请注意,由于生成器始终尝试生成“真实”图像,因此交叉熵损失可简化为: 生成器想要欺骗鉴别器,换句话说,使鉴别器输出`q`用于生成的图像`G(z)`。 发生器损失只是施加到发生器结果的鉴别器输出的二项式交叉熵损失的负值。 请注意,由于生成器始终尝试生成“真实”图像,因此交叉熵损失可简化为:
...@@ -452,7 +452,7 @@ def gan_loss(logits_real, logits_fake): ...@@ -452,7 +452,7 @@ def gan_loss(logits_real, logits_fake):
return discriminator_loss , generator_loss return discriminator_loss , generator_loss
``` ```
您可能已经注意到,不可能同时最大化鉴别器损耗和发生器损耗。 这就是 GAN 的优点,因为在训练时,该模型有望达到某种平衡,在这种情况下,生成器必须生成真正高质量的图像,以欺骗鉴别器。 您可能已经注意到,不可能同时最大化鉴别器损失和发生器损失。 这就是 GAN 的优点,因为在训练时,该模型有望达到某种平衡,在这种情况下,生成器必须生成真正高质量的图像,以欺骗鉴别器。
TensorFlow 仅允许其优化器最小化而不是最大化。 结果,我们实际上采用了前面所述的损失函数的负值,这意味着我们从最大化损失变为最小化损失。 不过,我们无需执行任何其他操作,因为`tf.nn.sigmoid_cross_entropy_with_logits()`会为我们解决此问题。 TensorFlow 仅允许其优化器最小化而不是最大化。 结果,我们实际上采用了前面所述的损失函数的负值,这意味着我们从最大化损失变为最小化损失。 不过,我们无需执行任何其他操作,因为`tf.nn.sigmoid_cross_entropy_with_logits()`会为我们解决此问题。
...@@ -599,7 +599,7 @@ BEGAN 的一些优点如下: ...@@ -599,7 +599,7 @@ BEGAN 的一些优点如下:
* 高分辨率(`128x128`)人脸生成(2017 最新技术)。 * 高分辨率(`128x128`)人脸生成(2017 最新技术)。
* 提供一种衡量收敛的方法。 * 提供一种衡量收敛的方法。
* 即使没有批处理规范和辍学也有良好的结果。 * 即使没有批规范和辍学也有良好的结果。
* 超参数可控制世代多样性与质量。 更高的质量也意味着更多的模式崩溃。 * 超参数可控制世代多样性与质量。 更高的质量也意味着更多的模式崩溃。
* 不需要两个单独的优化器。 * 不需要两个单独的优化器。
...@@ -629,16 +629,16 @@ GAN 当前最大的问题是,它们很难训练。 幸运的是,有一些技 ...@@ -629,16 +629,16 @@ GAN 当前最大的问题是,它们很难训练。 幸运的是,有一些技
# 损失可解释性 # 损失可解释性
训练 GAN 时的问题之一是,生成器损耗和鉴别器损耗的值都没有明显的影响。 这不像训练分类器,只是等待损失下降以查看模型是否在训练。 训练 GAN 时的问题之一是,生成器损失和鉴别器损失的值都没有明显的影响。 这不像训练分类器,只是等待损失下降以查看模型是否在训练。
对于 GAN,损失值的下降并不一定意味着该模型正在训练中: 对于 GAN,损失值的下降并不一定意味着该模型正在训练中:
![](img/c8fb861d-7d21-463d-bf33-1b1398362b00.jpg) ![](img/c8fb861d-7d21-463d-bf33-1b1398362b00.jpg)
通过许多人的实验和研究,以下是有关如何使用 GAN 损值的一些提示: 通过许多人的实验和研究,以下是有关如何使用 GAN 损值的一些提示:
* 您不希望鉴别器的损失下降得很快,因为它将无法向生成器提供反馈以改善它。 * 您不希望鉴别器的损失下降得很快,因为它将无法向生成器提供反馈以改善它。
* 如果发电机损迅速下降,则意味着它发现了一个鉴别器弱点,并一次又一次地利用了这一弱点。 如果发生这种情况,则称为**模式折叠** * 如果发电机损迅速下降,则意味着它发现了一个鉴别器弱点,并一次又一次地利用了这一弱点。 如果发生这种情况,则称为**模式折叠**
损失实际上仅对查看训练中是否出现问题有好处。 因此,没有很好的方法知道训练已经收敛。 通常,最好的办法是继续查看发电机的输出。 确保输出看起来与您的期望接近,并且输出种类丰富。 损失实际上仅对查看训练中是否出现问题有好处。 因此,没有很好的方法知道训练已经收敛。 通常,最好的办法是继续查看发电机的输出。 确保输出看起来与您的期望接近,并且输出种类丰富。
...@@ -679,7 +679,7 @@ GAN 当前最大的问题是,它们很难训练。 幸运的是,有一些技 ...@@ -679,7 +679,7 @@ GAN 当前最大的问题是,它们很难训练。 幸运的是,有一些技
![](img/375e4e8f-7e97-4d2a-b8f1-b197a83021a2.jpg) ![](img/375e4e8f-7e97-4d2a-b8f1-b197a83021a2.jpg)
# 摘要 # 总结
在本章中,我们了解了生成模型及其与判别模型的不同之处。 我们还讨论了各种自编码器,包括深度,变体和卷积。 此外,我们了解了一种新型的生成模型,称为生成对抗网络(GAN)。 在了解了所有这些生成模型之后,我们看到了如何在 TensorFlow 中自己训练它们以生成手写数字,并看到了它们可以产生的不同质量的图像。 在本章中,我们了解了生成模型及其与判别模型的不同之处。 我们还讨论了各种自编码器,包括深度,变体和卷积。 此外,我们了解了一种新型的生成模型,称为生成对抗网络(GAN)。 在了解了所有这些生成模型之后,我们看到了如何在 TensorFlow 中自己训练它们以生成手写数字,并看到了它们可以产生的不同质量的图像。
......
...@@ -246,8 +246,8 @@ for epoch in range(num_epoch): ...@@ -246,8 +246,8 @@ for epoch in range(num_epoch):
saver.save(sess, os.path.join(SAVE_FOLDER, "model.ckpt"), epoch) saver.save(sess, os.path.join(SAVE_FOLDER, "model.ckpt"), epoch)
``` ```
# 摘要 # 总结
在本章中,我们学习了如何,何时以及为什么使用迁移学习。 这被认为是一个非常强大的工具,因为它使我们能够使用从其他领域学到的功能来以较少的数据很好地概括。 我们看了一些示例,现在应该清楚如何在自己的任务中实迁移学习。 在本章中,我们学习了如何,何时以及为什么使用迁移学习。 这被认为是一个非常强大的工具,因为它使我们能够使用从其他领域学到的功能来以较少的数据很好地概括。 我们看了一些示例,现在应该清楚如何在自己的任务中实迁移学习。
在下一章中,我们将看到如何组织我们的数据以及如何扩展 CNN 架构,以构建准确而实用的机器学习系统。 在下一章中,我们将看到如何组织我们的数据以及如何扩展 CNN 架构,以构建准确而实用的机器学习系统。
\ No newline at end of file
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
# 偏差和方差 # 偏差和方差
如第 2 章,“深度学习和卷积神经网络”中所讨论的,方差和偏差分别表示过拟合和欠拟合。 我们可以使用训练集,开发集和测试集错误来诊断“拟合不足”和“过拟合”的问题。 如第 2 章,“深度学习和卷积神经网络”中所讨论的,方差和偏差分别表示过拟合和欠拟合。 我们可以使用训练集,开发集和测试集错误来诊断“欠拟合”和“过拟合”的问题。
考虑以下场景,其中我们的数据来自两个不同的分布,分别称为分布 1 和分布 2。分布 2 表示我们关心的目标应用程序。 问题是,我们如何在这种分布上定义训练,开发和测试集。 考虑以下场景,其中我们的数据来自两个不同的分布,分别称为分布 1 和分布 2。分布 2 表示我们关心的目标应用程序。 问题是,我们如何在这种分布上定义训练,开发和测试集。
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
下表可以更好地说明这一点。 在这些示例中,我们假设在所有情况下的最佳/人为错误均最小,即 1%。 通常,深度学习模型的准确性与人类相似,因此将其作为比较可帮助您找到良好的架构。 下表可以更好地说明这一点。 在这些示例中,我们假设在所有情况下的最佳/人为错误均最小,即 1%。 通常,深度学习模型的准确性与人类相似,因此将其作为比较可帮助您找到良好的架构。
* 高偏差/拟合不足 * 高偏差/欠拟合
| | | | | |
| --- | --- | | --- | --- |
...@@ -159,7 +159,7 @@ ML 基本配方 ...@@ -159,7 +159,7 @@ ML 基本配方
我们还可以处理不平衡类,并通过将损失权重包括在内来处理不平衡数据的分类问题。 这种惩罚或权重迫使模型更多地关注少数群体(样本较少的类别)。 在前面的章节中讨论过的惩罚型 SVM 和焦点损失检测器算法就是这样的例子。 我们还可以处理不平衡类,并通过将损失权重包括在内来处理不平衡数据的分类问题。 这种惩罚或权重迫使模型更多地关注少数群体(样本较少的类别)。 在前面的章节中讨论过的惩罚型 SVM 和焦点损失检测器算法就是这样的例子。
Tensorflow 已经具有其损失功能,并内置了加权选项: Tensorflow 已经具有其损失函数,并内置了加权选项:
* `tf.losses.sparse_softmax_cross_entropy(labels=label, logits=logits, weights=weights)` * `tf.losses.sparse_softmax_cross_entropy(labels=label, logits=logits, weights=weights)`
* `Tf.nn.weighted_cross_entropy_with_logits` * `Tf.nn.weighted_cross_entropy_with_logits`
...@@ -360,7 +360,7 @@ class CAE_CNN_Encoder(object): ...@@ -360,7 +360,7 @@ class CAE_CNN_Encoder(object):
请记住,CNN 的训练和设计是一门经验丰富的科学,因此请始终注意,被视为最佳实践的内容会迅速发生变化。 请记住,CNN 的训练和设计是一门经验丰富的科学,因此请始终注意,被视为最佳实践的内容会迅速发生变化。
# 摘要 # 总结
在本章中,我们了解到遵循最佳实践将对作为机器学习工程师的日常活动有所帮助。 我们已经看到了如何准备数据集并将其拆分为子集,以促进对网络的正确训练和微调。 此外,我们还研究了执行有意义的测试,其中获得的结果代表了将模型部署到目标应用程序时所看到的结果。 涉及的另一个主题是对数据的过拟合和不足,以及为了解决这些问题而应遵循的最佳实践。 此外,解决了数据集不平衡的问题,我们已经看到了一个简单的示例,该示例可能在哪里找到(疾病诊断)。 为了解决这个问题,建议收集更多的数据,扩充数据集并选择不平衡数据集不变的评估指标。 最后,展示了如何构造代码以使其更具可读性和重用性。 在本章中,我们了解到遵循最佳实践将对作为机器学习工程师的日常活动有所帮助。 我们已经看到了如何准备数据集并将其拆分为子集,以促进对网络的正确训练和微调。 此外,我们还研究了执行有意义的测试,其中获得的结果代表了将模型部署到目标应用程序时所看到的结果。 涉及的另一个主题是对数据的过拟合和不足,以及为了解决这些问题而应遵循的最佳实践。 此外,解决了数据集不平衡的问题,我们已经看到了一个简单的示例,该示例可能在哪里找到(疾病诊断)。 为了解决这个问题,建议收集更多的数据,扩充数据集并选择不平衡数据集不变的评估指标。 最后,展示了如何构造代码以使其更具可读性和重用性。
......
...@@ -138,9 +138,9 @@ train_dataset = train_dataset.map(decode_tfrec, num_parallel_calls=4) # Decode ...@@ -138,9 +138,9 @@ train_dataset = train_dataset.map(decode_tfrec, num_parallel_calls=4) # Decode
num_parallel_calls=4) # Augment data. num_parallel_calls=4) # Augment data.
``` ```
# 批处理 # 批
您希望在管道末尾做的最后一件事是生成一批准备发送到 GPU 进行训练的数据。 这可以通过批处理方法简单地完成,并传入所需的批处理大小: 您希望在管道末尾做的最后一件事是生成一批准备发送到 GPU 进行训练的数据。 这可以通过批量方法简单地完成,并传入所需的批量大小:
```py ```py
train_dataset = train_dataset.batch(128) # Take a batch of 128 from the dataset. train_dataset = train_dataset.batch(128) # Take a batch of 128 from the dataset.
...@@ -152,7 +152,7 @@ train_dataset = train_dataset.batch(128) # Take a batch of 128 from the dataset ...@@ -152,7 +152,7 @@ train_dataset = train_dataset.batch(128) # Take a batch of 128 from the dataset
我们能够建立有效数据管道的另一种方法是始终准备好一批数据准备发送到 GPU。 理想情况下,在训练模型时,我们希望 GPU 的使用率始终保持在 100%。 这样,我们可以最大程度地利用昂贵的硬件,该硬件可以在训练时有效地计算前进和后退的传球次数。 我们能够建立有效数据管道的另一种方法是始终准备好一批数据准备发送到 GPU。 理想情况下,在训练模型时,我们希望 GPU 的使用率始终保持在 100%。 这样,我们可以最大程度地利用昂贵的硬件,该硬件可以在训练时有效地计算前进和后退的传球次数。
为此,我们需要 CPU 加载并准备一批图像,以准备在向前和向后传递模型的过程中传递给 GPU。 幸运的是,在收集批处理之后,我们可以使用简单的预取转换轻松完成此操作,如下所示: 为此,我们需要 CPU 加载并准备一批图像,以准备在向前和向后传递模型的过程中传递给 GPU。 幸运的是,在收集批之后,我们可以使用简单的预取转换轻松完成此操作,如下所示:
```py ```py
train_dataset= train_dataset.batch(128).prefetch(1) train_dataset= train_dataset.batch(128).prefetch(1)
...@@ -160,7 +160,7 @@ train_dataset= train_dataset.batch(128).prefetch(1) ...@@ -160,7 +160,7 @@ train_dataset= train_dataset.batch(128).prefetch(1)
使用预取将确保我们的数据管道在进行训练时为我们准备一整批数据,准备将其加载到 GPU 中以进行下一次迭代。 这样做可以确保我们的管道在等待一批批次收集之前不会减慢速度,并且如果获取批次所需的时间少于模型的前后传递时间,那么我们的管道将尽可能高效。 使用预取将确保我们的数据管道在进行训练时为我们准备一整批数据,准备将其加载到 GPU 中以进行下一次迭代。 这样做可以确保我们的管道在等待一批批次收集之前不会减慢速度,并且如果获取批次所需的时间少于模型的前后传递时间,那么我们的管道将尽可能高效。
要清楚的是,此处使用`prefetch(1)`表示我们`prefetch`整批数据。 这就是为什么我们将批处理作为流水线的最后一步,并在此处使用预取功能,因为这样做最有效。 要清楚的是,此处使用`prefetch(1)`表示我们`prefetch`整批数据。 这就是为什么我们将批作为流水线的最后一步,并在此处使用预取功能,因为这样做最有效。
# 追踪图形 # 追踪图形
...@@ -430,7 +430,7 @@ SageMaker 提供了一种在云中训练/部署机器学习模型的简便方法 ...@@ -430,7 +430,7 @@ SageMaker 提供了一种在云中训练/部署机器学习模型的简便方法
![](img/5a8a5836-b47a-4691-afff-476fa5e867c8.png) ![](img/5a8a5836-b47a-4691-afff-476fa5e867c8.png)
# 摘要 # 总结
在本章中,您学习了如何处理数据集太大而无法由普通台式计算机处理的数据。 我们看到了如何在多个 GPU 和机器之间训练 TensorFlow 模型,最后,我们研究了用于存储数据并将其有效地馈送到模型的最佳实践。 在本章中,您学习了如何处理数据集太大而无法由普通台式计算机处理的数据。 我们看到了如何在多个 GPU 和机器之间训练 TensorFlow 模型,最后,我们研究了用于存储数据并将其有效地馈送到模型的最佳实践。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册