提交 0f0467c3 编写于 作者: W wizardforcel

2020-09-14 15:06:02

上级 13c6421d
......@@ -22,7 +22,7 @@
# 第 3 章
本章将介绍使用深度学习进行的图像分类,以及为什么CNN会干扰我们现在进行计算机视觉的方式。 本章的参考是:
本章将介绍使用深度学习进行的图像分类,以及为什么 CNN 会干扰我们现在进行计算机视觉的方式。 本章的参考是:
* [Learning Multiple Layers of Features from Tiny Images](https://www.cs.toronto.edu/~kriz/learning-features-2009-TR.pdf), Alex Krizhevsky, 2009
* 可以在这里找到关于图像表示技术的出色回顾:*Computer Vision: Algorithms and Applications*, Richard Szeliski, 2010
......
......@@ -180,7 +180,7 @@ R-CNN 与 FastRCNN 的比较表明,后者在训练时快约 10 倍,而在测
RPN 的工作是预测我们称为锚点的对象(本质上只是一个边界框)是否包含对象或仅是背景,然后完善此边界框的位置。
基本上,RPN 通过在最后一个 CNN 特征图上滑动一个小窗口(3 x 3)来做到这一点(同一特征图 Fast R-CNN 从中获得建议)。 对于每个滑动窗口中心,我们创建 *k* 固定锚框,并将这些框分类为是否包含对象:
基本上,RPN 通过在最后一个 CNN 特征图上滑动一个小窗口(`3 x 3`)来做到这一点(同一特征图 Fast R-CNN 从中获得建议)。 对于每个滑动窗口中心,我们创建`k`固定锚框,并将这些框分类为是否包含对象:
![](img/7c57ffe8-af41-47a0-b295-5aeb633e866f.png)
......@@ -204,15 +204,15 @@ RoI 层的输入将是建议和最后的卷积层激活。 例如,考虑以下
# 从传统的 CNN 转换为完全卷积网络
对于有效的对象检测器而言,非常重要的一点是提高卷积,从而提高计算的重用性​​。 为此,我们将所有 FC 层转换为 CONV 层,如下图所示。
对于有效的对象检测器而言,非常重要的一点是提高卷积,从而提高计算的重用性​​。 为此,我们将所有 FC 层转换为卷积层,如下图所示。
以这种方式实现我们的网络的目的是,他们可以使用比其最初设计的图像更大的图像作为输入,同时共享计算以使其效率更高。 将所有 FC 层都转换为 CONV 层的这种类型的网络的名称称为完全卷积网络(FCN)。
以这种方式实现我们的网络的目的是,他们可以使用比其最初设计的图像更大的图像作为输入,同时共享计算以使其效率更高。 将所有 FC 层都转换为卷积层的这种类型的网络的名称称为完全卷积网络(FCN)。
将 FC 层转换为 CONV 层的基本技术是使用与输入空间尺寸一样大的内核大小,并使用过滤器数来匹配 FC 层上的输出数。 在此示例中,我们期望输入图像为 14x14x3
将 FC 层转换为卷积层的基本技术是使用与输入空间尺寸一样大的内核大小,并使用过滤器数来匹配 FC 层上的输出数。 在此示例中,我们期望输入图像为`14x14x3`
![](img/dd1a5963-27dc-4ede-b0a9-4671fdf0a655.jpg)
以我们为例,用 100 x 100 的输入补丁训练一个全卷积网络,并用 2,000 x 2,000 的输入图像进行测试,结果将是在 2000 x 2000 图像上运行 100 x 100 的滑动窗口 。 当使用较大的输入体积(如本例中所示)时,FCN 的输出将是一个体积,其中每个单元格对应于原始输入图像上 100x100 窗口补丁的一张幻灯片。
以我们为例,用`100 x 100`的输入补丁训练一个全卷积网络,并用`2,000 x 2,000`的输入图像进行测试,结果将是在`2000 x 2000`图像上运行`100 x 100`的滑动窗口 。 当使用较大的输入体积(如本例中所示)时,FCN 的输出将是一个体积,其中每个单元格对应于原始输入图像上`100x100`窗口补丁的一张幻灯片。
现在,每次我们使用比原始训练输入大的输入图像时,效果都将像我们实际上在整个图像上滑动分类器,但计算量却减少了。 通过这种方式,我们通过 CNN 的前向传递一步一步地使滑动窗口卷积:
......@@ -224,7 +224,7 @@ RoI 层的输入将是建议和最后的卷积层激活。 例如,考虑以下
YOLO 网络的主要思想是在不使用任何滑动窗口的情况下优化输入图像中各个位置的预测计算。为实现此目的,网络以大小为`N x N`单元格的网格形式输出特征图。
每个单元格都有`B * 5 + C`条目。 其中`B`是每个单元格的边界框的数量,C 是类概率的数量,而 5 是每个边界框的元素(x,y:边界框相对于其所在单元格的中心点坐标, `w`是相对于原始图像的边界框的宽度, `h`是相对于原始图像的边界框的高度,置信度:边界框中对象存在的可能性)。
每个单元格都有`B * 5 + C`条目。 其中`B`是每个单元格的边界框的数量,`C`是类概率的数量,而 5 是每个边界框的元素(`x, y`:边界框相对于其所在单元格的中心点坐标, `w`是相对于原始图像的边界框的宽度, `h`是相对于原始图像的边界框的高度,置信度:边界框中对象存在的可能性)。
我们将置信度得分定义为:
......@@ -234,11 +234,11 @@ YOLO 网络的主要思想是在不使用任何滑动窗口的情况下优化输
请注意,网格的每个单元格都负责预测固定数量的边界框。
下图描述了作为 YOLO 网络输出的单元格条目的样子,它预测了形状的张量(N,N,B * 5 + C)。 网络的最后一个 conv 层将输出与栅格尺寸相同大小的要素图。
下图描述了作为 YOLO 网络输出的单元格条目的样子,它预测了形状的张量`(N, N, B * 5 + C)`。 网络的最后一个卷积层将输出与栅格尺寸相同大小的要素图。
![](img/c0865621-4388-4c74-80d1-33cfc363f626.png)
中心坐标以及边界框的高度和宽度在[0,1]之间进行归一化。 下图显示了如何计算这些坐标的示例:
中心坐标以及边界框的高度和宽度在`[0, 1]`之间进行归一化。 下图显示了如何计算这些坐标的示例:
![](img/71f35c09-6130-40da-91af-468ba0a6d69f.png)
......@@ -254,7 +254,7 @@ YOLO 网络的主要思想是在不使用任何滑动窗口的情况下优化输
# 创建用于 Yolo 对象检测的训练集
为了创建 YOLO 的训练集,将与 YOLO 网络的输出特征图预测相同大小的网格放置在每个训练输入图像上。 对于网格中的每个像元,我们创建一个目标向量 Y,其长度为 B * 5 + C(即与上一节中的输出特征图网格像元大小相同)。
为了创建 YOLO 的训练集,将与 YOLO 网络的输出特征图预测相同大小的网格放置在每个训练输入图像上。 对于网格中的每个像元,我们创建一个目标向量`Y`,其长度为`B * 5 + C`(即与上一节中的输出特征图网格像元大小相同)。
让我们以训练图像为例,看看如何为图像上的网格中的单元创建目标向量:
......@@ -266,7 +266,7 @@ YOLO 网络的主要思想是在不使用任何滑动窗口的情况下优化输
第一个条目是类别`P[c]`存在的置信度得分,对于没有对象的单元格中的两个锚定框,该得分均为 0。 其余值将*无关*。 单元格编号 8 有一个对象,并且对象的边界框具有较高的 IOU。
对于大小为 NxM 的输入训练图像,训练后从 ConvNet 输出的目标向量的最终体积将为 3x3x16(在此玩具示例中)
对于大小为`NxM`的输入训练图像,训练后从卷积网络输出的目标向量的最终体积将为`3x3x16`(在此玩具示例中)
数据集中每个图像的标签信息将仅包括对象的中心坐标及其边界框。 实施代码以使其与网络的输出向量相匹配是您的责任; 这些任务包括以下所列的任务:
......@@ -280,7 +280,7 @@ YOLO 网络的主要思想是在不使用任何滑动窗口的情况下优化输
![](img/e0d3c104-c2bd-41f8-a3f7-7ad0d63c1e6c.png)
我们还需要定义一个条件类别概率; 给定对象 P(class | Pr)的存在,我们想要这样做是因为我们不希望损失函数在单元格上没有对象的情况下惩罚错误的类预测。 该网络仅预测每个单元格的一组类别概率,而不考虑框数`B`
我们还需要定义一个条件类别概率; 给定对象`P(class | Pr)`的存在,我们想要这样做是因为我们不希望损失函数在单元格上没有对象的情况下惩罚错误的类预测。 该网络仅预测每个单元格的一组类别概率,而不考虑框数`B`
# 评估检测(并口交集)
......@@ -384,9 +384,9 @@ def tf_iou_vectorized(self, box_vec_1, box_vec_2):
实际上,您的模型通常会返回同一对象的多个检测窗口。 为了解决这个问题,我们使用一种称为非最大抑制的算法。 该算法使用“IoU 和对象的存在”作为启发式过滤这些多个框。 运作方式如下:
1. 丢弃所有包含物体的可能性低的框(pc <0.6
2. 选择最有可能出现物体的盒子(标签上的 pc
3. 丢弃与所选框高度重叠的所有框(IoU> 0.5
1. 丢弃所有包含物体的可能性低的框(`pc < 0.6`
2. 选择最有可能出现物体的盒子(标签上的`pc`
3. 丢弃与所选框高度重叠的所有框(`IoU > 0.5`
4. 重复步骤 2 和 3,直到所有检测都被放弃或选择为止
我们将在检测器的预测时间上使用非最大抑制:
......@@ -411,7 +411,7 @@ Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image
![](img/a6b0764f-f0af-4fd1-bbc3-00fd2958c7fc.png)
请注意,`...`条目表示即使对于没有对象的单元格,预测向量中也会有一些随机值。 但是,在单元格 8 中,x,y,h,w 的预测值有望接近准确。
请注意,`...`条目表示即使对于没有对象的单元格,预测向量中也会有一些随机值。 但是,在单元格 8 中,`x, y, h, w`的预测值有望接近准确。
在最后阶段,我们可以使用非最大值抑制算法过滤每个像元中的多个预测边界框。
......@@ -421,9 +421,9 @@ Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image
![](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
同样,`1[ij]^noobj`正好相反。
......@@ -434,7 +434,7 @@ Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image
第一部分计算与预测的边界框位置坐标`(x, y)`相关的损耗。 `(x_hat, y_hat)`是训练集中真实情况数据的边界框坐标。
`λ[coord] = 5.0`表示一个常数,当有错误时,该常数将给予更多的补偿。 B 是边界框的数量。 `S^2`是网格中的单元数。
`λ[coord] = 5.0`表示一个常数,当有错误时,该常数将给予更多的补偿。 `B`是边界框的数量。 `S^2`是网格中的单元数。
使用类似的公式来处理边界框的宽度/高度
......@@ -468,7 +468,7 @@ Tensorflow 已经具有实现非最大值抑制算法的功能,称为`tf.image
![](img/aea81ee0-d79f-4213-9343-be0e90e8c96e.png)
在实践中的实践中,您将尝试矢量化这种损失并避免 for 循环并提高性能,这对于 Tensorflow 之类的库尤其如此。
在实践中的实践中,您将尝试矢量化这种损失并避免`for`循环并提高性能,这对于 Tensorflow 之类的库尤其如此。
这是 YOLO 损失的 TensorFlow 实现:
......@@ -552,13 +552,13 @@ def loss_layer(self, predicts, labels, scope='loss_layer'):
需要解决的其他一些实现细节是:
* 最终的采样层(Deconv)需要具有与分类一样多的过滤器,并且您的标签“颜色”需要与最后一层中的索引匹配,否则在训练过程中可能会遇到 NaN 问题
* 最终的采样层(Deconv)需要具有与分类一样多的过滤器,并且您的标签“颜色”需要与最后一层中的索引匹配,否则在训练过程中可能会遇到 NaN 问题
* 我们需要一个 Argmax 层来选择输出张量上概率最大的像素(仅在预测时间内)
* 我们的损失需要考虑输出张量上的所有像素
# 最大分拆
取消池操作用于恢复最大池操作的效果。 这个想法只是充当上采样器。 此操作已在一些较早的论文上使用,并且不再使用,因为您还需要 CONV 层来修补(低通滤波器)上采样的结果:
取消池操作用于恢复最大池操作的效果。 这个想法只是充当上采样器。 此操作已在一些较早的论文上使用,并且不再使用,因为您还需要卷积层来修补(低通滤波器)上采样的结果:
![](img/f32f83c1-2c6a-462c-b053-811239923262.png)
......@@ -574,7 +574,7 @@ def loss_layer(self, predicts, labels, scope='loss_layer'):
![](img/8cc1410a-dc11-4f64-9d0f-8a25950c7cdd.png)
在 Tensorflow 中,我们可以访问`tf.layers`中的转置卷积。 下面的示例将采用一个空间大小为 14 x 14 的输入,并使其通过`conv2d_transpose`层,其中输出空间大小为 28 x 28
在 Tensorflow 中,我们可以访问`tf.layers`中的转置卷积。 下面的示例将采用一个空间大小为`14 x 14`的输入,并使其通过`conv2d_transpose`层,其中输出空间大小为`28 x 28`
```py
# input_im has spatial dimensions 14x14 in this example
......@@ -630,7 +630,7 @@ with tf.name_scope("SPATIAL_SOFTMAX"):
这种知道图像中有多少个对象实例的能力也使该问题类似于对象检测。 但是,对象检测产生的对象边界要粗糙得多,这意味着被遮挡的对象更容易被遗漏,实例分割不会发生这种情况。
# 面具 R-CNN
# Mask R-CNN
Mask R-CNN 是一种最近的网络体系结构,通过提供简单,灵活的模型体系结构可以使此问题更易于解决。 该架构于 2017 年发布,旨在扩展更快的 R-CNN 的功能:
......
......@@ -9,20 +9,20 @@
* 如何提高参数效率
* 如何在 TensorFlow 中实现 VGG 网络
* 如何在 TensorFlow 中实现 Inception 网络
* 如何在 TensorFlow 中实施残网络
* 如何在 TensorFlow 中实施残网络
* 如何实现对移动设备更友好的体系结构
# 替代大卷积
在开始之前,我们将首先学习可以减少模型使用的参数数量的技术。 首先,这很重要,因为它可以提高网络的泛化能力,因为使用该模型中存在的参数数量将需要较少的训练数据。 其次,较少的参数意味着更高的硬件效率,因为将需要更少的内存。
在这里,我们将从解释减少模型参数的重要技术入手,将几个小卷积级联在一起。 在下图中,我们有两个 3x3 卷积层。 如果回头看图右侧的第二层,可以看到第二层中的一个神经元具有 3x3 的感受域:
在这里,我们将从解释减少模型参数的重要技术入手,将几个小卷积级联在一起。 在下图中,我们有两个`3x3`卷积层。 如果回头看图右侧的第二层,可以看到第二层中的一个神经元具有`3x3`的感受域:
![](img/5eaf2681-cfa7-4907-b95f-c6204b5c4721.png)
当我们说“感受野”时,是指它可以从上一层看到的区域。 在此示例中,需要一个 3x3 区域来创建一个输出,因此需要一个 3x3 的感受域。
当我们说“感受野”时,是指它可以从上一层看到的区域。 在此示例中,需要一个`3x3`区域来创建一个输出,因此需要一个`3x3`的感受域。
回溯到另一层,该 3x3 区域的每个元素在输入端也具有 3x3 感受域。 因此,如果我们将所有这 9 个元素的接受场组合在一起,那么我们可以看到在输入上创建的总接受场大小为 5x5
回溯到另一层,该`3x3`区域的每个元素在输入端也具有`3x3`感受域。 因此,如果我们将所有这 9 个元素的接受场组合在一起,那么我们可以看到在输入上创建的总接受场大小为`5x5`
因此,用简单的话来说,将较小的卷积级联在一起可以获得与使用较大卷积相同的感受域。 这意味着我们可以用级联的小卷积代替大卷积。
......@@ -30,13 +30,13 @@
![](img/b41b8fa0-33ef-41f1-bf8e-7b9d3a4ede88.png)
在上图中,我们用三个 3x3 卷积替换了一个 7x7 卷积。 让我们自己计算一下,以减少使用的参数。
在上图中,我们用三个`3x3`卷积替换了一个`7x7`卷积。 让我们自己计算一下,以减少使用的参数。
想象一下,在形状为 WxHxC 的输入体积上使用 C 滤波器进行 7x7 大小的卷积。 我们可以计算过滤器中的权数,如下所示:
想象一下,在形状为`WxHxC`的输入体积上使用`C`滤波器进行`7x7`大小的卷积。 我们可以计算过滤器中的权数,如下所示:
![](img/65e0fde3-6ba1-4588-93b6-a945414cdfef.png)
现在,相反,如果我们层叠三个 3x3 卷积(代之以 7x7 卷积),我们可以如下计算其权重数:
现在,相反,如果我们层叠三个`3x3`卷积(代之以`7x7`卷积),我们可以如下计算其权重数:
![](img/6f819b52-e9db-4868-b320-cbbeb722b935.png)
......@@ -44,17 +44,17 @@
还要注意,在这三个卷积层的每一个之间,我们放置了 ReLu 激活。 与仅使用单个大卷积层相比,这样做会给模型带来更多的非线性。 增加的深度(和非线性)是一件好事,因为这意味着网络可以将更多的概念组合在一起,并提高其学习能力!
大多数新的成功模型的趋势是用许多级联在一起的较小卷积(通常为 3x3 大小)替换所有大型滤波器。 如前所述,这样做有两个巨大的好处。 它不仅减少了参数的数量,而且还增加了网络中非线性的深度和数量,这对于增加其学习能力是一件好事。
大多数新的成功模型的趋势是用许多级联在一起的较小卷积(通常为`3x3`大小)替换所有大型滤波器。 如前所述,这样做有两个巨大的好处。 它不仅减少了参数的数量,而且还增加了网络中非线性的深度和数量,这对于增加其学习能力是一件好事。
# 替代 3x3 卷积
# 替代`3x3`卷积
也可以通过称为瓶颈的机制来简化 3x3 卷积。 与早期相似,这将具有正常 3x3 卷积的相同表示,但参数更少,非线性更多。
也可以通过称为瓶颈的机制来简化`3x3`卷积。 与早期相似,这将具有正常`3x3`卷积的相同表示,但参数更少,非线性更多。
瓶颈通过使用以下 C 滤镜替换 3x3 卷积层而起作用:
瓶颈通过使用以下`C`滤镜替换`3x3`卷积层而起作用:
* 具有 C / 2 滤波器的 1x1 卷积
* 具有 C / 2 滤波器的 3x3 卷积
* C 滤镜的 1x1 卷积
* 带有`C / 2`滤波器的`1x1`卷积
* 带有`C / 2`滤波器的`3x3`卷积
*`C`滤镜的`1x1`卷积
这里给出一个实际的例子:
......@@ -64,7 +64,7 @@
![](img/d3fa1a7c-dbd1-47c7-bd95-9df99f61b68b.png)
这比仅使用 3x3 卷积层时得到的参数要少:
这比仅使用`3x3`卷积层时得到的参数要少:
![](img/2b7ce629-e563-477b-9552-cf8a85339dfb.png)
......@@ -74,15 +74,15 @@
VGGNet 由牛津大学的**视觉几何组****VGG**)创建,是真正引入堆叠更多层的想法的首批架构之一。 虽然 AlexNet 最初以其七层出现时被认为很深,但与 VGG 和其他现代体系结构相比,这现在已经很小了。
与只有 11x11 的 AlexNet 相比,VGGNet 仅使用空间大小为 3x3 的非常小的滤镜。 这些 3x3 卷积滤波器经常散布在 2x2 最大池化层中。
与只有`11x11`的 AlexNet 相比,VGGNet 仅使用空间大小为`3x3`的非常小的滤镜。 这些`3x3`卷积滤波器经常散布在`2x2`最大池化层中。
使用如此小的滤波器意味着可见像素的邻域也非常小。 最初,这可能给人的印象是,本地信息是模型所考虑的全部内容。 但是,有趣的是,通过依次堆叠小型滤波器,它提供了与单个大型滤波器相同的“感受域”。 例如,堆叠三批 3x3 滤镜将具有与一个 7x7 滤镜相同的感受域。
使用如此小的滤波器意味着可见像素的邻域也非常小。 最初,这可能给人的印象是,本地信息是模型所考虑的全部内容。 但是,有趣的是,通过依次堆叠小型滤波器,它提供了与单个大型滤波器相同的“感受域”。 例如,堆叠三批`3x3`滤镜将具有与一个`7x7`滤镜相同的感受域。
堆叠过滤器的这种洞察力带来了能够拥有更深的结构(我们通常会看到更好的结构)的优点,该结构保留了相同的感受域大小,同时还减少了参数数量。 本章后面将进一步探讨这个想法。
# 建筑
接下来,我们将看到 VGGNet 的体系结构,特别是包含 16 层的 VGG-16 风味。 所有卷积层都有空间大小为 3x3 的滤镜,并且随着我们深入网络,卷积层中滤镜的数量从 64 个增加到 512 个。
接下来,我们将看到 VGGNet 的体系结构,特别是包含 16 层的 VGG-16 风格。 所有卷积层都有空间大小为`3x3`的滤镜,并且随着我们深入网络,卷积层中滤镜的数量从 64 个增加到 512 个。
堆叠两个或三个卷积层然后合并的简单模块化设计使网络的大小易于增加或减小。 结果,VGG 成功创建并测试了具有 11、13 和 19 层的版本:
......@@ -206,7 +206,7 @@ VGG 最酷的功能之一是,由于其在 conv 层中的内核较小,因此
事实证明,VGG 模型可以在许多任务中很好地工作,并且由于其简单的体系结构,它是开始尝试或适应问题需求的理想模型。 但是,它确实有以下问题需要注意:
* 通过仅使用 3x3 层,尤其是在第一层,计算量不适用于移动解决方案
* 通过仅使用`3x3`层,尤其是在第一层,计算量不适用于移动解决方案
* 如前几章所述,由于逐渐消失的梯度问题,甚至更深的 VGG 结构也无法正常工作
* 原始设计中大量的 FC 层在参数方面是过大的,这不仅减慢了模型的速度,而且更容易出现过拟合的问题
* 使用许多池化层,目前认为这不是好的设计
......@@ -229,25 +229,25 @@ GoogLeNet 具有 22 层,参数几乎比 AlexNet 少 12 倍。 因此,除了
基本上,初始块的想法是使用所有可用的内核大小和操作来覆盖尽可能多的信息,并让反向传播根据您的数据决定使用什么。 在上图中看到的唯一问题是计算成本,因此该图在实践中会有所不同。
考虑我们之前看到的 5x5 分支,让我们检查一下它的计算成本:
考虑我们之前看到的`5x5`分支,让我们检查一下它的计算成本:
![](img/b9e05229-a800-45dc-b675-4fad355b3c54.png)
![](img/564ae665-af37-4088-8ab8-2975d8c16ec8.png)
现在,考虑以下更改; 我们添加一个 1x1 CONV 来将 5x5 CONV 输入深度从 192 转换为 16:
现在,考虑以下更改; 我们添加一个`1x1`卷积来将`5x5`卷积输入深度从 192 转换为 16:
![](img/8cc4d625-1193-4cd4-a91f-55adc41c642a.png)
![](img/a0d5631a-32bc-4136-ac2a-a12452ce341c.png)
如果您观察到,现在计算效率提高了 10 倍。 1x1 层会挤压大量深度(瓶颈),然后发送到 5x5 CONV 层。
如果您观察到,现在计算效率提高了 10 倍。 `1x1`层会挤压大量深度(瓶颈),然后发送到`5x5`卷积层。
考虑到这一瓶颈变化,真正的初始层要复杂一些:
![](img/ca3da890-3a5d-4c96-8320-af7cbc197cfd.png)
此外,在某些实现中,您可能会注意到有人试图在初始代码块中使用 Batchnorm 或 Dropout
此外,在某些实现中,您可能会注意到有人试图在初始代码块中使用批量规范化或丢弃法
Googlenet 将只是许多级联的启动块。 在这段代码中,我们展示了如何创建一个起始块:
......@@ -299,9 +299,9 @@ def inception_block_a(x, name='inception_a'):
GoogLeNet 的主要优点是,它比 VGG 更为准确,同时使用的参数更少,计算能力也更低。 主要的缺点仍然是,如果我们开始堆叠很多初始层,梯度将消失,而且整个网络具有多个分支和多个损耗的设计相当复杂。
# 残网络
# 残网络
在前面的部分中,已经证明了网络的深度是有助于提高准确性的关键因素(请参见 VGG)。 TensorFlow 中的第 3 章“图像分类”中也显示,可以通过正确的权重初始化和批处理归一化来缓解深度网络中梯度消失或爆炸的问题。 但是,这是否意味着我们添加的层越多,我们得到的系统就越准确? 亚洲研究机构 Microsoft 的《用于图像识别的深度残差学习》的作者发现,只要网络深度达到 30 层,准确性就会达到饱和。 为了解决此问题,他们引入了一个称为残差块的新层块,该块将上一层的输出添加到下一层的输出中(请参见下图)。 Residual Net 或 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)
......@@ -311,9 +311,9 @@ GoogLeNet 的主要优点是,它比 VGG 更为准确,同时使用的参数
![](img/2a75b154-8239-4fce-968d-441d25d69a27.png)
其中`g`是非线性激活函数,例如 ReLu 和`F(x) = W[l] g(W[l-1] x)`,即两层堆叠卷积。 ReLu 函数可以在添加 x 之前或之后添加。 剩余的块应由 2 层或更多层组成,因为一层的块没有明显的好处。
其中`g`是非线性激活函数,例如 ReLu 和`F(x) = W[l] g(W[l-1] x)`,即两层堆叠卷积。 ReLu 函数可以在添加`x`之前或之后添加。 剩余的块应由 2 层或更多层组成,因为一层的块没有明显的好处。
为了理解该概念背后的直觉,我们假设我们有一个经过训练的浅层 CNN,其更深的对应层具有与浅层 CNN 相同的层,并且在它们之间随机插入了一些层。 为了拥有一个与浅层模型至少具有相似性能的深层模型,附加层必须近似标识函数。 但是,要学习具有 CONV 层堆栈的标识函数比将残差函数推为零要困难得多。 换句话说,如果单位函数是最优解,则很容易实现`F(x)`,因此很容易实现`H(x) = x`
为了理解该概念背后的直觉,我们假设我们有一个经过训练的浅层 CNN,其更深的对应层具有与浅层 CNN 相同的层,并且在它们之间随机插入了一些层。 为了拥有一个与浅层模型至少具有相似性能的深层模型,附加层必须近似标识函数。 但是,要学习具有卷积层堆栈的标识函数比将残差函数推为零要困难得多。 换句话说,如果单位函数是最优解,则很容易实现`F(x)`,因此很容易实现`H(x) = x`
另一种思考的方式是,在训练期间,特定的层不仅会从上一层学习一个概念,还会从它之前的其他层学习一个概念。 这比只从上一层学习概念要好。
......@@ -382,7 +382,7 @@ for group_i, group in enumerate(groups):
我们将以一个新的 CNN 系列结束本章,该系列不仅具有较高的准确性,而且更轻巧,并且在移动设备上的运行速度更快。
由 Google 创建的 MobileNet 的关键功能是它使用了不同的“三明治”形式的卷积块。 它不是通常的(`CONV``BATCH_NORM,RELU`),而是将 3x3 卷积拆分为 3x3 深度卷积,然后是 1x1 点向卷积。他们称此块为深度可分离卷积。
由 Google 创建的 MobileNet 的关键功能是它使用了不同的“三明治”形式的卷积块。 它不是通常的(`CONV``BATCH_NORM,RELU`),而是将`3x3`卷积拆分为`3x3`深度卷积,然后是`1x1`点向卷积。他们称此块为深度可分离卷积。
这种分解可以减少计算量和模型大小:
......@@ -390,20 +390,20 @@ for group_i, group in enumerate(groups):
# 深度可分离卷积
这个新的卷积块(`tf.layers.separable_conv2d`)由两个主要部分组成:深度卷积层,然后是 1x1 点式卷积层。 该块与普通卷积有以下几种不同:
这个新的卷积块(`tf.layers.separable_conv2d`)由两个主要部分组成:深度卷积层,然后是`1x1`点式卷积层。 该块与普通卷积有以下几种不同:
* 在正常卷积层中,每个滤波器 F 将同时应用于输入通道上的所有通道(F 应用于每个通道然后求和)
* 这个新的卷积 F 分别应用于每个通道,并且结果被级联到某个中间张量(多少由深度倍数 DM 参数控制)
* 在正常卷积层中,每个滤波器`F`将同时应用于输入通道上的所有通道(`F`应用于每个通道然后求和)
* 这个新的卷积`F`分别应用于每个通道,并且结果被级联到某个中间张量(多少由深度倍数`DM`参数控制)
相对于标准卷积,深度卷积非常有效。 但是,它仅过滤输入通道,并且不将它们组合以创建新功能。
现在,将使用 1x1 转换层将深度输出张量映射到某些所需的输出通道深度,该转换层将在通常在标准卷积层中发生的通道之间进行混合。 区别在于 DM 参数可用于丢弃一些信息。 同样,1x1 转换仅用于调整音量大小。
现在,将使用`1x1`转换层将深度输出张量映射到某些所需的输出通道深度,该转换层将在通常在标准卷积层中发生的通道之间进行混合。 区别在于`DM`参数可用于丢弃一些信息。 同样,`1x1`转换仅用于调整音量大小。
# 控制参数
MobileNets 使用两个超参数来帮助控制精度和速度之间的折衷,从而使网络适合您要定位的任何设备。 这两个超参数如下:
* **宽度倍增器**:通过统一减少整个网络中使用的滤波器数量,控制深度 CONV 精度
* **宽度倍增器**:通过统一减少整个网络中使用的滤波器数量,控制深度卷积精度
* **分辨率倍增器**:只需将输入图像缩小到不同大小
# 有关 MobileNets 的更多信息
......@@ -414,6 +414,6 @@ MobileNets 使用两个超参数来帮助控制精度和速度之间的折衷,
# 摘要
在本章中,我们向您介绍了各种卷积神经网络设计,这些设计已经证明了它们的有效性,因此被广泛使用。 我们首先介绍牛津大学 VGG 的 VGGNet 模型。 接下来,在最终讨论微软的 Residual Net 之前,我们先使用 Google 的 GoogLeNet。 此外,我们还向您展示了一种更高级的新型卷积,该模型在名为 MobileNet 的模型设计中具有特色。 在整个过程中,我们讨论了使每个网络如此出色的不同属性和设计选择,例如跳过连接,堆叠小型过滤器或启动模块。 最后,给出了代码,向您展示了如何在 TensorFlow 中写出这些网络。
在本章中,我们向您介绍了各种卷积神经网络设计,这些设计已经证明了它们的有效性,因此被广泛使用。 我们首先介绍牛津大学 VGG 的 VGGNet 模型。 接下来,在最终讨论微软的残差网络之前,我们先使用 Google 的 GoogLeNet。 此外,我们还向您展示了一种更高级的新型卷积,该模型在名为 MobileNet 的模型设计中具有特色。 在整个过程中,我们讨论了使每个网络如此出色的不同属性和设计选择,例如跳过连接,堆叠小型过滤器或启动模块。 最后,给出了代码,向您展示了如何在 TensorFlow 中写出这些网络。
在下一章中,我们将讨论一种称为生成模型的新型模型,该模型将使我们能够生成数据。
\ No newline at end of file
......@@ -342,16 +342,16 @@ GAN 的一些实际用法如下:
* 使用鉴别器网络权重作为不同任务的初始化,类似于我们对自编码器可以执行的操作
* 使用生成器网络创建新图像,可能会扩大您的数据集,就像我们可以使用经过训练的 VAE 解码器一样
* 将鉴别器用作损失函数(对于图像,可能优于 L1 / L2),并且也可以在 VAE 中使用
* 将鉴别器用作损失函数(对于图像,可能优于 L1/L2),并且也可以在 VAE 中使用
* 通过将生成的数据与标记的数据混合来进行半监督学习
现在我们将向您展示如何在 TensorFlow 中实现非常简单的 GAN。 一旦经过训练,我们的 GAN 的生成器部分就可以用于根据 100 个长随机噪声矢量创建 MNIST 手写数字。 让我们开始吧!
# 鉴别器
我们需要做的第一件事就是创建我们的区分网络。 为此,我们将几个全连接层堆叠在一起。 鉴别器将 784 个长度向量作为输入,这是我们的 28x28 MNIST 图像变平。 每个图像的输出将只是一个数字,这是鉴别者对该图像为真实图像的信心程度的分数。 我们使用 Leaky ReLu 作为激活功能,以防止 ReLu 单元死亡。
我们需要做的第一件事就是创建我们的区分网络。 为此,我们将几个全连接层堆叠在一起。 鉴别器将 784 个长度向量作为输入,这是我们的`28x28` MNIST 图像变平。 每个图像的输出将只是一个数字,这是鉴别者对该图像为真实图像的信心程度的分数。 我们使用 Leaky ReLu 作为激活功能,以防止 ReLu 单元死亡。
我们返回原始 logit,因为损失函数将为我们应用 S 型激活函数,以确保鉴别器输出在 0 到 1 之间:
我们返回原始对率,因为损失函数将为我们应用 Sigmoid 激活函数,以确保鉴别器输出在 0 到 1 之间:
```py
def discriminator(x):
......@@ -364,7 +364,7 @@ def discriminator(x):
# 发电机
现在我们创建发电机网络。 生成器的工作是将随机噪声的矢量作为输入,并从中生成输出图像。 在此示例中,我们再次使用全连接层,这些层最后将产生 784 个长向量的输出,我们可以对其进行整形以获得 28x28 的图像:
现在我们创建发电机网络。 生成器的工作是将随机噪声的矢量作为输入,并从中生成输出图像。 在此示例中,我们再次使用全连接层,这些层最后将产生 784 个长向量的输出,我们可以对其进行整形以获得`28x28`的图像:
```py
def generator(z):
......@@ -375,7 +375,7 @@ def generator(z):
return img
```
我们在输出上使用 tanh 激活来将生成的图像限制在-1 到 1 的范围内。
我们在输出上使用 tanh 激活来将生成的图像限制在 -1 到 1 的范围内。
现在已经定义了模型,我们可以看看 GAN 训练所需的损失函数。
......@@ -385,7 +385,7 @@ def generator(z):
![](img/1d24b043-c4b8-42f0-8f9c-8f2c7db22ec3.png)
在这里,D 是我们的判别器,G 是我们的生成器,z 是输入到生成器的随机矢量,x 是真实图像。 尽管我们在此处给出了 GAN 损失的总和,但实际上更容易分别考虑这两种优化。
在这里,`D`是我们的判别器,`G`是我们的生成器,`z`是输入到生成器的随机矢量,`x`是真实图像。 尽管我们在此处给出了 GAN 损失的总和,但实际上更容易分别考虑这两种优化。
为了训练 GAN,我们将在鉴别器和生成器之间交替进行梯度步骤更新。 在更新判别器时,我们要尝试使**最大化**判别器做出**正确选择**的概率。 在更新生成器时,我们想尝试使**最小化**鉴别器做出**正确选择**的可能性。
......@@ -559,7 +559,7 @@ def generator(z):
* 对于鉴别器:再次使用泄漏的 relu,不要使用最大池。 仅使用跨步卷积或平均池。
* 对于生成器:在最后一层使用 relu 和 tanh。
* 通常,最佳实践是在生成器和鉴别器上都使用 batchnorm 层。 它们将始终设置为训练模式。
* 通常,最佳实践是在生成器和鉴别器上都使用批量规范化层。 它们将始终设置为训练模式。
* 有时,人们运行生成器优化器的次数是运行鉴别器优化器的两倍。
这是一个简单的 DCGAN 在生成人脸图像时可以达到的质量的示例:
......@@ -597,7 +597,7 @@ BEGAN 的主要思想是在鉴别器上使用自编码器,这将有其自身
BEGAN 的一些优点如下:
* 高分辨率(128x128)人脸生成(2017 最新技术)。
* 高分辨率(`128x128`)人脸生成(2017 最新技术)。
* 提供一种衡量收敛的方法。
* 即使没有批处理规范和辍学也有良好的结果。
* 超参数可控制世代多样性与质量。 更高的质量也意味着更多的模式崩溃。
......@@ -646,7 +646,7 @@ GAN 当前最大的问题是,它们很难训练。 幸运的是,有一些技
这可能是您在训练 GAN 时遇到的第一个问题。 当生成器找到一组特定的输入来欺骗鉴别器时,就会发生模式崩溃,并且它会继续利用这种故障情况并将潜伏`Z`空间中的许多值折叠为相同的值。
解决此问题的一种方法是使用“迷你批处理功能”或“展开 GANs”,或者完全停止训练,然后在生成器开始创建非常狭窄的输出分布时重新开始:
解决此问题的一种方法是使用“小批量功能”或“展开 GANs”,或者完全停止训练,然后在生成器开始创建非常狭窄的输出分布时重新开始:
![](img/febfacea-0ff5-4ee3-9fec-729292f70e27.jpg)
......@@ -656,7 +656,7 @@ GAN 当前最大的问题是,它们很难训练。 幸运的是,有一些技
在这里,我们将介绍一些在训练 GAN 时使生活更轻松的技术:
* 归一化-1/1 之间的输入
* 归一化输入到 -1/1 之间
* 使用 BatchNorm
* 使用 Leaky Relu(判别器)
* 在发电机输出上使用 Relu(发电机),tanh
......
......@@ -58,7 +58,7 @@
# 没有解码器的自编码器
包含两个卷积层和一个完全连接层的编码器(不带解码器部分的自编码器)如下所示。 父自编码器在 MNIST 数据集上进行了训练。 因此,网络将大小为 28x28x1 的图像作为输入,并在潜在空间将其编码为 10 维矢量,每个类别一维:
包含两个卷积层和一个完全连接层的编码器(不带解码器部分的自编码器)如下所示。 父自编码器在 MNIST 数据集上进行了训练。 因此,网络将大小为`28x28x1`的图像作为输入,并在潜在空间将其编码为 10 维矢量,每个类别一维:
```py
# Only half of the autoencoder changed for classification
......@@ -133,7 +133,7 @@ list_fc_linear = [v for v in tf.global_variables() if "fc" in v.name or "output"
<tf.Variable 'logits/bias:0' shape=(10,) dtype=float32_ref>]
```
将定义图的图层分为卷积和完全连接两个列表后,您将使用`tf.Train.Saver`加载所需的权重。 首先,我们需要创建一个 saver 对象,将要从检查点加载的变量列表作为输入,如下所示:
将定义图的图层分为卷积和完全连接两个列表后,您将使用`tf.Train.Saver`加载所需的权重。 首先,我们需要创建一个保存器对象,将要从检查点加载的变量列表作为输入,如下所示:
```py
# Define the saver object to load only the conv variables
......@@ -167,7 +167,7 @@ train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss, var_list=list_
# 完整资料
在此示例中,我们将从 MNIST 卷积自编码器示例中加载权重。 我们将仅恢复编码器部分的权重,冻结 CONV 层,并训练 FC 层以执行数字分类:
在此示例中,我们将从 MNIST 卷积自编码器示例中加载权重。 我们将仅恢复编码器部分的权重,冻结卷积层,并训练 FC 层以执行数字分类:
```py
import tensorflow as tf
......
......@@ -15,7 +15,7 @@
为了构建机器学习系统,建议从一个新的小项目开始并逐步改进它:
1. 查找与您类似的问题并下载代码(并测试模型以检查结果)
2. 根据需要找到扩展计算的方法(即 AWS / Google Cloud)
2. 根据需要找到扩展计算的方法(即 AWS/Google Cloud)
3. 从较小的数据集开始,以避免浪费时间等待一个纪元
4. 从简单的架构开始
5. 使用可视化/调试(例如,TensorBoard)
......@@ -40,7 +40,7 @@
为了获得高性能的神经网络,将数据集正确划分为训练集,开发集和测试集非常重要。 它有助于更​​快地迭代。 另外,它允许更有效地测量算法的偏差和方差,以便我们可以选择有效方式进行改进的方法。
在以前的时代,我们拥有较小的数据集(例如最多 10,000 个示例)和简单的分类器,我们会将数据集拆分为训练和测试集。 通常将训练集分成较小的集,以使用称为交叉验证的技术来训练分类器。 优良作法是按 60/20/20 的比例拆分数据集(即 60% 的训练数据,20% 的开发数据,20% 的测试数据)。 但是,大数据的现代时代已经改变了这一经验法则。 如果我们有 1,000,000 个示例,则拆分比例已更改为 98/1/1(即 98% 的训练数据,1% 的 dev 数据,1% 的测试数据)。
在以前的时代,我们拥有较小的数据集(例如最多 10,000 个示例)和简单的分类器,我们会将数据集拆分为训练和测试集。 通常将训练集分成较小的集,以使用称为交叉验证的技术来训练分类器。 优良作法是按 60/20/20 的比例拆分数据集(即 60% 的训练数据,20% 的开发数据,20% 的测试数据)。 但是,大数据的现代时代已经改变了这一经验法则。 如果我们有 1,000,000 个示例,则拆分比例已更改为 98/1/1(即 98% 的训练数据,1% 的开发数据,1% 的测试数据)。
随着我们拥有更多的数据,开发和测试集的比例将变小。
......@@ -48,7 +48,7 @@
# 开发和测试集不匹配
除了拆分数据之外,数据的分布还对神经网络的性能产生巨大影响。 应用深度学习中的大多数问题来自开发人员和测试集数据分布的不匹配。 我们需要记住,开发和测试数据应该来自类似的分发。 例如,如果我们以如下方式收集和分割人员检测数据,即从网页上收集人员的训练图像,而使用移动电话收集测试集图像,则会出现分布不匹配的情况。 这里的问题是,在训练模型时,我们会根据其在 dev 数据上的性能来微调网络的参数和体系结构,如果 dev 数据与训练数据相似且与测试数据不同,则与训练集相比 dev 数据中存在很高的偏差。 在开发集上获得良好的评估结果并不一定意味着该模型可以很好地推广。 在这种情况下,对分布完全不同的集合进行测试可能会导致不良结果。 这是浪费时间和精力。 解决方案是首先合并开发集和测试集,随机将它们洗牌,最后将洗过的数据再次拆分为开发集和测试集。 这有助于在将机器学习算法成功训练到最终应用程序方面取得更快的进展。
除了拆分数据之外,数据的分布还对神经网络的性能产生巨大影响。 应用深度学习中的大多数问题来自开发人员和测试集数据分布的不匹配。 我们需要记住,开发和测试数据应该来自类似的分发。 例如,如果我们以如下方式收集和分割人员检测数据,即从网页上收集人员的训练图像,而使用移动电话收集测试集图像,则会出现分布不匹配的情况。 这里的问题是,在训练模型时,我们会根据其在开发数据上的性能来微调网络的参数和体系结构,如果开发数据与训练数据相似且与测试数据不同,则与训练集相比开发数据中存在很高的偏差。 在开发集上获得良好的评估结果并不一定意味着该模型可以很好地推广。 在这种情况下,对分布完全不同的集合进行测试可能会导致不良结果。 这是浪费时间和精力。 解决方案是首先合并开发集和测试集,随机将它们洗牌,最后将洗过的数据再次拆分为开发集和测试集。 这有助于在将机器学习算法成功训练到最终应用程序方面取得更快的进展。
# 何时更改开发/测试集
......@@ -64,11 +64,11 @@
![](img/00d0d711-3009-4542-bb6e-3988f1007b50.png)
最好的方法是根据上图将其拆分。 分配 1 被拆分为训练集,其一部分用作开发集。 在这里,我们称其为“训练开发集”(因为开发集与火车集具有相同的分布)。 分布 1 主要用于训练,因为它是一个大型数据集。 发行版 2 分为测试集和开发集,它们与发行版 1 中的任一集无关。这里要强调的一点是,测试和开发集应来自同一发行版,并且属于我们实际上关心的应用程序,即目标应用程序。 开发集和测试集通常是小的数据集,因为它们的目的是给出模型/算法的无偏性能估计。
最好的方法是根据上图将其拆分。 分布 1 被拆分为训练集,其一部分用作开发集。 在这里,我们称其为“训练开发集”(因为开发集与火车集具有相同的分布)。 分布 1 主要用于训练,因为它是一个大型数据集。 分布 2 分为测试集和开发集,它们与分布 1 中的任一集无关。这里要强调的一点是,测试和开发集应来自同一发行版,并且属于我们实际上关心的应用程序,即目标应用程序。 开发集和测试集通常是小的数据集,因为它们的目的是给出模型/算法的无偏性能估计。
模型在不同数据集分区上的误差差异,以及查看人为误差可为我们提供诊断偏见和方差问题的见解
下表显示了当左列中的集合之间存在误差时,应如何诊断。 N.B. 人为水平误差是此分析的基准,它为比较模型提供了基准。
下表显示了当左列中的集合之间存在误差时,应如何诊断。 注意,人为水平误差是此分析的基准,它为比较模型提供了基准。
![](img/43b92390-d3d8-4104-a0e8-0b0e03958557.png)
......@@ -81,7 +81,7 @@
| 人为/最佳误差 | 1% |
| 训练误差 | 15% |
与人员水平的表现相比,训练误差较大,这意味着该模型甚至无法拟合数据。 训练有素,因此欠拟合/高偏见。 但是,当我们在这种情况下查看 dev 错误时,它可以很好地概括,因此不会丢失所有内容。
与人员水平的表现相比,训练误差较大,这意味着该模型甚至无法拟合数据。 训练有素,因此欠拟合/高偏见。 但是,当我们在这种情况下查看开发误差时,它可以很好地概括,因此不会丢失所有内容。
* 高方差/过拟合
......@@ -164,11 +164,11 @@ Tensorflow 已经具有其损失功能,并内置了加权选项:
* `tf.losses.sparse_softmax_cross_entropy(labels=label, logits=logits, weights=weights)`
* `Tf.nn.weighted_cross_entropy_with_logits`
例如,如果您尝试对 A,B,C 三个类别进行分类,其中 A 为 10%,B 为 45%,C 为 45%,则可以将`tf.losses.sparse_softmax_cross_entropy`用于以下权重:[1.0、0.3, 0.3]
例如,如果您尝试对 A,B,C 三个类别进行分类,其中 A 为 10%,B 为 45%,C 为 45%,则可以将`tf.losses.sparse_softmax_cross_entropy`用于以下权重:`[1.0, 0.3, 0.3]`
# 评估指标
在为模型选择评估指标时,我们还需要小心。 假设对于狗/非狗分类问题,我们有两种算法的准确度分别为 98% 和 96%。 乍一看,这些算法看起来都具有相似的性能。 让我们记住,分类准确度定义为做出的正确预测数除以做出的预测总数。 换句话说,True Positive(TP)和 True Negative(TN)预测数除以预测总数。 但是,可能出现的情况是,随着狗图像的出现,我们还会得到大量被错误分类为狗的背景或类似外观的物体,通常称为误报(FP)。 另一个不良行为可能是许多狗图像被错误分类为负片或假阴性(FN)。 显然,根据定义,分类准确性不能捕获误报或误报的概念。 因此,需要更好的评估指标。
在为模型选择评估指标时,我们还需要小心。 假设对于狗/非狗分类问题,我们有两种算法的准确度分别为 98% 和 96%。 乍一看,这些算法看起来都具有相似的性能。 让我们记住,分类准确度定义为做出的正确预测数除以做出的预测总数。 换句话说,真阳性(TP)和真阴性(TN)预测数除以预测总数。 但是,可能出现的情况是,随着狗图像的出现,我们还会得到大量被错误分类为狗的背景或类似外观的物体,通常称为假阳性(FP)。 另一个不良行为可能是许多狗图像被错误分类为负面或假阴性(FN)。 显然,根据定义,分类准确性不能捕获误报或误报的概念。 因此,需要更好的评估指标。
第一步,我们将构建一个混淆矩阵,该矩阵总结最后显示的段落:
......@@ -191,17 +191,37 @@ Tensorflow 已经具有其损失功能,并内置了加权选项:
| 预测为负 | 75(FN) | 188(TN) | 263 |
| | 85 | 201 | 286 |
精度:(TP + TN)/(TP + TN + FP + FN)= 198/286 = 0.69 TPR:TP /(TP + FN)= 10/85 = 0.11 FPR:FP /(FP + TN)= 13 / 201 = 0.06 PPV:TP /(TP + FP)= 10/23 = 0.43 NPV:TN /(TN + FN)= 188/263 = 0.71
```py
ACC: (TP + TN) / (TP + TN + FP + FN) = 198/286 = 0.69
TPR: TP / (TP + FN) = 10/85 = 0.11
FPR: FP / (FP + TN) = 13 / 201 = 0.06
PPV: TP / (TP + FP) = 10/23 = 0.43
NPV: TN / (TN + FN) = 188/263 = 0.71
```
范例 2:
| | 正 | 负 | |
| --- | --- | --- | --- |
| 预测为 | 0(TP) | 0(FP) | 0 |
| 预测为 | 0(TP) | 0(FP) | 0 |
| 预测为负 | 85(FN) | 201(TN) | 286 |
| | 85 | 201 | 286 |
精度:(TP + TN)/(TP + TN + FP + FN)= 201/286 = 0.70 TPR:TP /(TP + FN)= 0/85 = 0 FPR:FP /(FP + TN)= 0 / 201 = 0 PPV:TP /(TP + FP)= 0/0 = 0 NPV:TN /(TN + FN)= 201/286 = 0.70
```py
ACC: (TP + TN) / (TP + TN + FP + FN) = 201/286 = 0.70
TPR: TP / (TP + FN) = 0/85 = 0
FPR: FP / (FP + TN) = 0 / 201 = 0
PPV: TP / (TP + FP) = 0/0 = 0
NPV: TN / (TN + FN) = 201/286 = 0.70
```
在第一个示例中,我们可以得到 69% 的正确精度,但是在第二个示例中,通过仅对每个示例进行预测,我们实际上将我们的精度提高到 70% ! 显然,仅预测所有事物为负类的模型并不是一个很好的模型,这就是我们所说的准确性悖论。 简单来说,“准确性悖论”说,即使模型可能具有更高的准确性,但实际上可能并不是更好的模型。
......@@ -217,7 +237,17 @@ Tensorflow 已经具有其损失功能,并内置了加权选项:
| 测试结果阴性 | 1(FN) | 98,901(TN) | 98,902 |
| 总数 | 100 | 99,900 | 100,000 |
精度:(TP + TN)/(TP + TN + FP + FN)= 0.99 TPR:TP /(TP + FN)= 0.99 FPR:FP /(FP + TN)= 0.01 PPV:TP /(TP + FP) = 0.09 净现值:TN /(TN + FN)= 0.99
```py
ACC: (TP + TN) / (TP + TN + FP + FN) = 0.99
TPR: TP / (TP + FN) = 0.99
FPR: FP / (FP + TN) = 0.01
PPV: TP / (TP + FP) = 0.09
NPV: TN / (TN + FN) = 0.99
```
此处的测试似乎表现不错,因为准确性为 99%。 但是,如果您被诊断出患有癌症,这并不意味着您患该病的可能性为 99%。 应该注意的是,在 1098 个测试阳性的患者中,只有 99 个患有该疾病。 这意味着,如果您获得了阳性测试,那么对于准确度高达 99% 的测试,您实际患病的可能性仅为 9%。
......@@ -253,7 +283,7 @@ Tensorflow 已经具有其损失功能,并内置了加权选项:
使用设计模式来解决一些软件设计问题也是一种常见的做法。 python 中最简单,最有用的设计模式之一就是单例模式。 当您只想将一个类的实例强制仅用于一个对象时,可以使用它,因此,即使您在项目中的多个不同位置多次实例化该类,也将引用同一个对象。 在我们的情况下,如果我们要求 TensorFlow 创建具有相同名称的多个节点或图形,则会引发错误。 因此,我们在创建图形时使用单例模式,以避免生成两次。
在下面的示例中,我们总结了一个简单的分类模型,同时还确保不会多次构建图形(也称为 Singleton 模式)。
在下面的示例中,我们总结了一个简单的分类模型,同时还确保不会多次构建图形(也称为单例模式)。
注意`__new__`类方法的定义。 在 Python 中,当我们创建一个类的新实例时,将调用`__new__`
......@@ -315,14 +345,14 @@ class CAE_CNN_Encoder(object):
以下几点基于我们在训练神经网络方面的经验以及该领域研究人员认为的当前最佳实践。 希望如果您需要从头开始设计自己的 CNN 架构,他们将为您提供帮助。 但是,在尝试设计自己的 CNN 之前,您应该查看其他现成的体系结构以从中学习,并检查它们是否已经为您完成了工作。
1. 使用内核大小为 3x3 的卷积层。 就参数和计算而言,较大的内核更昂贵。 最重要的是,如我们在前面的章节中所看到的,您可以堆叠卷积层以产生更大的感受域,并受益于更多的非线性激活。
1. 使用内核大小为`3x3`的卷积层。 就参数和计算而言,较大的内核更昂贵。 最重要的是,如我们在前面的章节中所看到的,您可以堆叠卷积层以产生更大的感受域,并受益于更多的非线性激活。
2. 第一层卷积通常应至少具有 32 个过滤器。 这样,更深的层不受第一层提取的特征数量的限制。
3. 尽可能避免使用池化层。 相反,请使用步长为 2 的卷积层。这将像池化那样对输入进行下采样,但它不会像池化那样丢弃宝贵的信息。 同样,使用跨步卷积就像将 conv 和合并在一层中一样。
3. 尽可能避免使用池化层。 相反,请使用步长为 2 的卷积层。这将像池化那样对输入进行下采样,但它不会像池化那样丢弃宝贵的信息。 同样,使用跨步卷积就像将卷积和合并在一层中一样。
4. 减小要素地图的空间大小时,应增加使用的过滤器数量,以免丢失过多信息。 在深度网络中,请避免在第一层中过快减小空间大小。
5. 请遵循本章中有关从小规模开始网络设计,然后逐渐增加复杂性的建议,以避免出现过大的问题。
6. 使用 batchnorm。 确实有助于训练您的网络!
6. 使用批量规范化。 确实有助于训练您的网络!
7. 随着您对网络的深入了解,逐渐减小要素地图的空间大小。
8. 最小化 FC 层的数量(在最后一层之前使用 dropout)。 仅在最终需要连接某些标量特征时才使用 FC。 (您甚至可以通过在输入通道上进行编码来避免这种情况)
8. 最小化 FC 层的数量(在最后一层之前使用丢弃)。 仅在最终需要连接某些标量特征时才使用 FC。 (您甚至可以通过在输入通道上进行编码来避免这种情况)
9. 如果您需要较大的感受域(物体大小接近总图像大小的检测或分类),请尝试对每层使用具有指数膨胀因子的膨胀卷积。 这样,您将在保持少量参数的同时非常迅速地扩大接收范围。
10. 如果网络变深并且训练损失没有减少,请考虑使用剩余连接。
......
......@@ -36,7 +36,7 @@
# 制作 TFRecord
在开始之前,让我们分解一下 TFRecord 的工作方式。 打开 TFRecord 文件进行写入后,创建一个称为 Example 的内容。 这只是一个协议缓冲区,我们将使用它填充要保存在其中的所有数据。 在示例中,我们将数据存储在 Feature 中。 功能是描述示例中数据的一种方式。 功能可以是以下三种类型之一:字节列表,浮点列表或 int64 列表。 将所有数据放入功能部件并将它们写入示例缓冲区后,我们会将整个协议缓冲区序列化为字符串,然后将其写入 TFRecord 文件。
在开始之前,让我们分解一下 TFRecord 的工作方式。 打开 TFRecord 文件进行写入后,创建一个称为`Example`的内容。 这只是一个协议缓冲区,我们将使用它填充要保存在其中的所有数据。 在示例中,我们将数据存储在`Feature`中。 功能是描述示例中数据的一种方式。 功能可以是以下三种类型之一:字节列表,浮点列表或`int64`列表。 将所有数据放入功能部件并将它们写入示例缓冲区后,我们会将整个协议缓冲区序列化为字符串,然后将其写入 TFRecord 文件。
让我们看看这在实践中如何工作。 我们将继续使用前面的图像分类示例,并创建一个 TFRecord 来存储相关数据。
......@@ -70,7 +70,7 @@ for index in range(len(labels)):
必须使用`tf.train.BytesList``tf.train.Int64List``tf.train.FloatList`将进入`tf.train.Feature`的数据转换为期望的正确类型。
接下来,我们创建一个`tf.train.Example`协议缓冲区并将功能传递给它。 最后,我们将 Example 序列化为字符串并将其写入 TFRecord 文件。 一旦遍历了整个图像阵列,就必须记住关闭文件进行写入。
接下来,我们创建一个`tf.train.Example`协议缓冲区并将功能传递给它。 最后,我们将`Example`序列化为字符串并将其写入 TFRecord 文件。 一旦遍历了整个图像阵列,就必须记住关闭文件进行写入。
# 存储编码图像
......@@ -130,7 +130,7 @@ train_dataset = train_dataset.map(decode_tfrec, num_parallel_calls=4)
默认情况下,您在数据集上调用的任何地图转换都仅作用于数据集的单个元素,并且将按顺序处理元素。 要加快速度并使用所有 CPU 功能,最简单的方法是将`num_parallel_calls`参数设置为可用的 CPU 内核数。 这样,我们就不会浪费任何可用的 CPU 能力。 但是,警告您不要将其设置为高于可用内核的数量,因为由于调度效率低下,这实际上可能会降低性能。
您想要对数据进行的任何转换(例如数据扩充)也可以编写为函数,然后像以前一样传递给 map 方法,以将其应用于数据集。 例如,请注意以下代码:
您想要对数据进行的任何转换(例如数据扩充)也可以编写为函数,然后像以前一样传递给`map`方法,以将其应用于数据集。 例如,请注意以下代码:
```py
train_dataset = train_dataset.map(decode_tfrec, num_parallel_calls=4) # Decode tfrecord.
......@@ -198,7 +198,7 @@ with tf.Session() as sess:
在本节中,您将学习如何在 TensorFlow 中分配计算; 强调如何做到这一点的重要性如下:
* 并行运行更多实验(即,找到超参数,例如 gridsearch
* 并行运行更多实验(即,找到超参数,例如网格搜索
* 在多个 GPU(在多个服务器上)上分配模型训练,以减少训练时间
一个著名的用例是,Facebook 发布了一篇论文,该论文能够在 1 小时(而不是几周)内训练 ImageNet。 基本上,它在 256 个 GPU 上的 ImageNet 上训练了 ResNet-50,该 GPU 分​​布在 32 台服务器上,批量大小为 8,192 张图像。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册