【翻译】Sklearn与TensorFlow机器学习实用指南 —— 第12章 卷积神经网络(下)
Python爱好者社区专栏作者
GitHub:https://github.com/apachecn/hands_on_Ml_with_Sklearn_and_TF
前文传送门:
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— Chapter 0.前言
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第1章 机器学习概览(上)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第1章 机器学习概览(下)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第2章 一个完整的机器学习项目(上)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第2章 一个完整的机器学习项目(中)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第2章 一个完整的机器学习项目(中二)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第2章 一个完整的机器学习项目(下)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第3章 分类(上)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第3章 分类(中)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第3章 分类(下)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第4章( 上) 训练模型
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第4章( 中) 训练模型
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第4章( 下) 训练模型
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第5章( 上)支持向量机
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第5章( 中)支持向量机
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第5章( 中)支持向量机
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第5章( 下)支持向量机
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第6章 决策树
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第7章 集成学习和随机森林(上)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第7章 集成学习和随机森林 (中)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第7章 集成学习和随机森林 (下)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第8章 降维(上)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第8章 降维(下)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第9章 (上)启动并运行TensorFlow
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第9章 (中)启动并运行TensorFlow
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第9章 (下)启动并运行TensorFlow
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第10章 人工神经网络介绍(上)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第10章 人工神经网络介绍(中)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第10章 人工神经网络介绍(下)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第11章 训练深层神经网络(上)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第11章 训练深层神经网络(中)
【翻译】Sklearn 与 TensorFlow 机器学习实用指南 —— 第11章 训练深层神经网络(下)
【翻译】Sklearn与TensorFlow机器学习实用指南 —— 第12章 卷积神经网络(上)
TensorFlow 实现
from sklearn.datasets import load_sample_image
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
if __name__ == '__main__':
# Load sample images
china = load_sample_image("china.jpg")
flower = load_sample_image("flower.jpg")
dataset = np.array([china, flower], dtype=np.float32)
batch_size, height, width, channels = dataset.shape
# Create 2 filters
filters = np.zeros(shape=(7, 7, channels, 2), dtype=np.float32)
filters[:, 3, :, 0] = 1 # vertical line
filters[3, :, :, 1] = 1 # horizontal line
# Create a graph with input X plus a convolutional layer applying the 2 filters
X = tf.placeholder(tf.float32, shape=(None, height, width, channels))
convolution = tf.nn.conv2d(X, filters, strides=[1,2,2,1], padding="SAME")
with tf.Session() as sess:
output = sess.run(convolution, feed_dict={X: dataset})
plt.imshow(output[0, :, :, 1], cmap="gray") # plot 1st image's 2nd feature map
plt.show()
大部分代码是不言而喻的,但conv2d()
这一行值得解释一下:
X
是输入小批次(4D 张量,如前所述)卷积核是应用的一组卷积核(也是一个 4D 张量,如前所述)。
步幅是一个四元素的一维数组,其中两个中间的值是垂直和水平的步幅(
sh
和sw
)。 第一个和最后一个元素现在必须等于 1。他们可能有一天会被用来指定批量步长(跳过一些实例)和频道步幅(跳过上一层的特征映射或通道)。padding
必须是"VALID"
或"SAME"
:如果设置为
"VALID"
,卷积层不使用零填充,并且可能会忽略输入图像底部和右侧的某些行和列,具体取决于步幅,如图 13-7 所示(为简单起见, 这里只显示水平尺寸,当然,垂直尺寸也适用相同的逻辑)如果设置为
"SAME"
,则卷积层在必要时使用零填充。 在这种情况下,输出神经元的数量等于输入神经元的数量除以该步幅,向上舍入(在这个例子中,ceil(13/5)= 3
)。 然后在输入周围尽可能均匀地添加零。
不幸的是,卷积图层有很多超参数:你必须选择卷积核的数量,高度和宽度,步幅和填充类型。 与往常一样,您可以使用交叉验证来查找正确的超参数值,但这非常耗时。 稍后我们将讨论常见的 CNN 体系结构,以便让您了解超参数值在实践中的最佳工作方式。
内存需求
CNN 的另一个问题是卷积层需要大量的 RAM,特别是在训练期间,因为反向传播需要在正向传递期间计算的所有中间值。
例如,考虑具有5×5
卷积核的卷积层,输出 200 个尺寸为150×100
的特征映射,步长为 1,使用SAME
填充。 如果输入是150×100
RGB 图像(三个通道),则参数的数量是(5×5×3 + 1)×200 = 15,200
(+1
对应于偏置项),这跟全连接层比较是相当小的。(具有150×100
神经元的全连接层,每个连接到所有150×100×3
输入,将具有150 ^ 2×100 ^ 2×3 = 675,000,000
个参数!)然而,200 个特征映射中的每一个包含150×100
个神经元,并且这些神经元中的每一个都需要计算其5×5×3 = 75
个输入的权重和:总共 2.25 亿次浮点乘法。不像全连接层那么糟糕,但仍然是计算密集型的。 而且,如果使用 32 位浮点数来表示特征映射,则卷积层的输出将占用 RAM 的200×150×100×32 = 9600万
位(大约 11.4MB)。 这只是一个例子! 如果训练批次包含 100 个实例,则该层将占用超过 1 GB 的 RAM!
在推理过程中(即对新实例进行预测时),一旦下一层计算完毕,一层所占用的 RAM 就可以被释放,因此只需要两个连续层所需的 RAM 数量。 但是在训练期间,在正向传递期间计算的所有内容都需要被保留用于反向传递,所以所需的 RAM 量(至少)是所有层所需的 RAM 总量。
如果由于内存不足错误导致训练崩溃,则可以尝试减少小批量大小。 或者,您可以尝试使用步幅降低维度,或者删除几个图层。 或者你可以尝试使用 16 位浮点数而不是 32 位浮点数。 或者你可以在多个设备上分发 CNN。
池化层
一旦你理解了卷积层是如何工作的,池化层很容易掌握。 他们的目标是对输入图像进行二次抽样(即收缩)以减少计算负担,内存使用量和参数数量(从而限制过度拟合的风险)。 减少输入图像的大小也使得神经网络容忍一点点的图像变换(位置不变)。
就像在卷积图层中一样,池化层中的每个神经元都连接到前一层中有限数量的神经元的输出,位于一个小的矩形感受野内。 您必须像以前一样定义其大小,跨度和填充类型。 但是,汇集的神经元没有权重; 它所做的只是使用聚合函数(如最大值或平均值)来聚合输入。 图 13-8 显示了最大池层,这是最常见的池化类型。 在这个例子中,我们使用一个2×2的核,步幅为 2,没有填充。 请注意,只有每个核中的最大输入值才会进入下一层。 其他输入被丢弃。
这显然是一个非常具有破坏性的层:即使只有一个2×2
的核和 2 的步幅,输出在两个方向上都会减小两倍(所以它的面积将减少四倍),一下减少了 75% 的输入值
池化层通常独立于每个输入通道工作,因此输出深度与输入深度相同。 接下来可以看到,在这种情况下,图像的空间维度(高度和宽度)保持不变,但是通道数目可以减少。
在 TensorFlow 中实现一个最大池层是非常容易的。 以下代码使用2×2
核创建最大池化层,步幅为2,没有填充,然后将其应用于数据集中的所有图像:
import numpy as np
from sklearn.datasets import load_sample_image
import tensorflow as tf
import matplotlib.pyplot as plt
china = load_sample_image("china.jpg")
flower = load_sample_image("flower.jpg")
dataset = np.array([china, flower], dtype=np.float32)
batch_size, height, width, channels = dataset.shape
# Create 2 filters
filters = np.zeros(shape=(7, 7, channels, 2), dtype=np.float32)
filters[:, 3, :, 0] = 1 # vertical line
filters[3, :, :, 1] = 1 # horizontal line
X = tf.placeholder(tf.float32, shape=(None, height, width, channels))
max_pool = tf.nn.max_pool(X, ksize=[1,2,2,1], strides=[1,2,2,1],padding="VALID")
with tf.Session() as sess:
output = sess.run(max_pool, feed_dict={X: dataset})
plt.imshow(output[0].astype(np.uint8)) # plot the output for the 1st image
plt.show()
ksize
参数包含沿输入张量的所有四维的核形状:[min-batch, height, width, channels]
。 TensorFlow 目前不支持在多个实例上合并,因此ksize
的第一个元素必须等于 1。此外,它不支持在空间维度(高度和宽度)和深度维度上合并,因此ksize[1]
和ksize[2]
都必须等于 1,否则ksize[3]
必须等于 1。
要创建一个平均池化层,只需使用avg_pool()
函数而不是max_pool()
。
现在你知道所有的构建模块来创建一个卷积神经网络。 我们来看看如何组装它们。
CNN 架构
典型的 CNN 体系结构有一些卷积层(每一个通常跟着一个 ReLU 层),然后是一个池化层,然后是另外几个卷积层(+ ReLU),然后是另一个池化层,等等。 随着网络的进展,图像变得越来越小,但是由于卷积层的缘故,图像通常也会越来越深(即更多的特征映射)(见图 13-9)。 在堆栈的顶部,添加由几个全连接层(+ ReLU)组成的常规前馈神经网络,并且最终层输出预测(例如,输出估计类别概率的 softmax 层)。
一个常见的错误是使用太大的卷积核。 通常可以通过将两个3×3
内核堆叠在一起来获得与9×9
内核相同的效果,计算量更少。
多年来,这种基础架构的变体已经被开发出来,导致了该领域的惊人进步。 这种进步的一个很好的衡量标准是比赛中的错误率,比如 ILSVRC ImageNet 的挑战。 在这个比赛中,图像分类的五大误差率在五年内从 26% 下降到仅仅 3% 左右。 前五位错误率是系统前5位预测未包含正确答案的测试图像的数量。 图像很大(256 像素),有 1000 个类,其中一些非常微妙(尝试区分 120 个狗的品种)。 查看获奖作品的演变是了解 CNN 如何工作的好方法。
我们先来看看经典的 LeNet-5 架构(1998 年),然后是 ILSVRC 挑战赛的三名获胜者 AlexNet(2012),GoogLeNet(2014)和 ResNet(2015)。
其他视觉任务在其他视觉任务中,如物体检测和定位以及图像分割,也取得了惊人的进展。 在物体检测和定位中,神经网络通常输出图像中各种物体周围的一系列边界框。 例如,参 见Maxine Oquab 等人的 2015 年论文,该论文为每个客体类别输出热图,或者 Russell Stewart 等人的 2015 年论文,该论文结合使用 CNN 来检测人脸,并使用递归神经网络来输出 围绕它们的一系列边界框。 在图像分割中,网络输出图像(通常与输入大小相同),其中每个像素指示相应输入像素所属的对象的类别。 例如,查看 Evan Shelhamer 等人的 2016 年论文。
LeNet-5
LeNet-5 架构也许是最广为人知的 CNN 架构。 如前所述,它是由 Yann LeCun 于 1998 年创建的,广泛用于手写数字识别(MNIST)。 它由表 13-1 所示的层组成。
有一些额外的细节要注意:
MNIST 图像是
28×28
像素,但是它们被零填充到32×32
像素,并且在被输入到网络之前被归一化。 网络的其余部分不使用任何填充,这就是为什么随着图像在网络中的进展,大小不断缩小。平均池化层比平常稍微复杂一些:每个神经元计算输入的平均值,然后将结果乘以一个可学习的系数(每个特征映射一个),并添加一个可学习的偏差项(每个特征映射一个),然后最后应用激活函数。
C3 图中的大多数神经元仅在三个或四个 S2 图(而不是全部六个 S2 图)中连接到神经元。有关详细信息,请参阅原始论文中的表 1。
输出层有点特殊:每个神经元不是计算输入和权向量的点积,而是输出其输入向量和其权向量之间的欧几里德距离的平方。 每个输出测量图像属于特定数字类别的多少。 交叉熵损失函数现在是首选,因为它更多地惩罚不好的预测,产生更大的梯度,从而更快地收敛。
Yann LeCun 的网站(“LENET”部分)展示了 LeNet-5 分类数字的很好的演示。
AlexNet
AlexNet CNN 架构赢得了 2012 年的 ImageNet ILSVRC 挑战赛:它达到了 17% 的 top-5 的错误率,而第二名错误率只有 26%! 它由 Alex Krizhevsky(因此而得名),Ilya Sutskever 和 Geoffrey Hinton 开发。 它与 LeNet-5 非常相似,只是更大更深,它是第一个将卷积层直接堆叠在一起,而不是在每个卷积层顶部堆叠一个池化层。 表 13-2 介绍了这种架构。
为了减少过拟合,作者使用了前面章节中讨论的两种正则化技术:首先他们在训练期间将丢失率(dropout 率为 50%)应用于层 F8 和 F9 的输出。其次,他们通过随机对训练图像进行各种偏移,水平翻转和改变照明条件来进行数据增强。
AlexNet 还在层 C1 和 C3 的 ReLU 步骤之后立即使用竞争标准化步骤,称为局部响应标准化(local response normalization)。 这种标准化形式使得在相同的位置的神经元被最强烈的激活但是在相邻的特征映射中抑制神经元(在生物神经元中观察到了这种竞争激活)。 这鼓励不同的特征映射特殊化,迫使它们分开,并让他们探索更广泛的特征,最终提升泛化能力。 公式 13-2 显示了如何应用 LRN。
是位于特征映射i
的神经元的标准化输出,在某行u
和列v
(注意,在这个等式中我们只考虑位于这个行和列的神经元,所以u
和v
没有显示)。
例如,如果r = 2
且神经元具有强激活,则将抑制位于其上下的特征映射中的神经元的激活。
在 AlexNet 中,超参数设置如下:r = 2
,α= 0.00002
,β= 0.75
,k = 1
。这个步骤可以使用 TensorFlow 的local_response_normalization()
操作来实现。
AlexNet 的一个名为 ZF Net 的变体由 Matthew Zeiler 和 Rob Fergus 开发,赢得了 2013 年 ILSVRC 的挑战。 它基本上是 AlexNet 的一些调整的超参数(特征映射的数量,内核大小,步幅等)。
GoogLeNet
GoogLeNet 架构是由 Christian Szegedy 等人开发的。 来自 Google Research,通过低于 7% 的 top-5 错误率,赢得了 ILSVRC 2014 的挑战赛。 这个伟大的表现很大程度上因为它比以前的 CNN 网络更深(见图 13-11)。 这是通过称为初始模块(inception modules)的子网络实现的,这使得 GoogLeNet 比以前的架构更有效地使用参数:实际上,GoogLeNet 的参数比 AlexNet 少了 10 倍(约 600 万而不是 6000 万)。
初始模块的架构如图 13-10 所示。 符号3×3 + 2(S)
表示该层使用3×3
内核,步幅 2 和SAME
填充。 输入信号首先被复制并馈送到四个不同的层。 所有卷积层都使用 ReLU 激活功能。 请注意,第二组卷积层使用不同的内核大小(1×1
,3×3
和5×5
),允许它们以不同的比例捕获图案。
还要注意,每一层都使用了跨度为1和SAME填充的(即使是最大的池化层),所以它们的输出全都具有与其输入相同的高度和宽度。这使得将所有输出在最后的深度连接层(depth
concat layer)上沿着深度方向堆叠成为可能(即,堆叠来自所有四个顶部卷积层的特征映射)。这个连接层可以在 TensorFlow
中使用concat()
操作实现,其中axis = 3
(轴 3 是深度)。
您可能想知道为什么初始模块具有1×1
内核的卷积层。 当然这些图层不能捕获任何功能,因为他们一次只能看一个像素? 实际上,这些层次有两个目的:
首先,它们被配置为输出比输入少得多的特征映射,所以它们作为瓶颈层,意味着它们降低了维度。 在3×3
和5×5
卷积之前,这是特别有用的,因为这些在计算上是非常耗费内存的层。
其次,每一个卷积层对([1 × 1, 3 × 3]
和[1 × 1, 5 × 5]
表现地像一个强大的卷积层,可以捕捉到更多的复杂的模式。事实上,这一对卷积层不是在图像上扫过一个简单的线性分类器(就像单个卷积层一样),而是在图像上扫描一个双层神经网络。
简而言之,您可以将整个初始模块视为类固醇卷积层,能够输出捕捉各种尺度复杂模式的特征映射。
每个卷积层的卷积核的数量是一个超参数。 不幸的是,这意味着你有六个超参数来调整你添加的每个初始层。
现在让我们来看看 GoogLeNet CNN 的架构(见图 13-11)。 它非常深,我们不得不将它分成三列,但是 GoogLeNet 实际上是一列,包括九个初始模块(带有旋转顶端的框),每个模块实际上包含三层。每个卷积层和池化层输出的特征映射的数量显示在内核大小前。 初始模块中的六个数字表示模块中每个卷积层输出的特征映射的数量(与图 13-10 中的顺序相同)。 请注意,所有的卷积层都使用 ReLU 激活函数。
让我们来过一遍这个网络:
前两层将图像的高度和宽度除以 4(使其面积除以 16),以减少计算负担。
然后,局部响应标准化层确保前面的层学习各种各样的功能(如前所述)
接下来是两个卷积层,其中第一个像瓶颈层一样。 正如前面所解释的,你可以把这一对看作是一个单一的更智能的卷积层。
再次,局部响应标准化层确保了先前的层捕捉各种各样的模式。
接下来,最大池化层将图像高度和宽度减少 2,再次加快计算速度。
然后是九个初始模块的堆叠,与几个最大池层交织,以降低维度并加速网络。
接下来,平均池化层使用具有
VALID
填充的特征映射的大小的内核,输出1×1
特征映射:这种令人惊讶的策略被称为全局平均池化。 它有效地强制以前的图层产生特征映射,这些特征映射实际上是每个目标类的置信图(因为其他类型的功能将被平均步骤破坏)。 这样在 CNN 的顶部就不必有有几个全连接层(如 AlexNet),大大减少了网络中的参数数量,并减少了了过度拟合的风险。最后一层是不言自明的:正则化 drop out,然后是具有 softmax 激活函数的完全连接层来输出估计类的概率。
这个图略有简化:原来的 GoogLeNet 架构还包括两个插在第三和第六个初始模块之上的辅助分类器。
它们都由一个平均池层,一个卷积层,两个全连接层和一个 softmax 激活层组成。 在训练期间,他们的损失(缩小了 70%)加在了整体损失上。
目标是解决消失梯度问题,正则化网络。 但是,结果显示其效果相对小。
ResNet
最后是,2015 年 ILSVRC 挑战赛的赢家 Kaiming He 等人开发的 Residual Network(或 ResNet),该网络的 top-5 误率低到惊人的 3.6%,它使用了一个非常深的 CNN,由 152 层组成。 能够训练如此深的网络的关键是使用跳过连接(skip connection,也称为快捷连接):一个层的输入信号也被添加到位于下一层的输出。 让我们看看为什么这是有用的。
当训练一个神经网络时,目标是使其模拟一个目标函数h(x)
。 如果将输入x添加到网络的输出中(即添加跳过连接),那么网络将被迫模拟f(x)= h(x) - x
而不是h(x)
。 这被称为残留学习(见图 13-12)。
当你初始化一个普通的神经网络时,它的权重接近于零,所以网络只输出接近零的值。 如果添加跳过连接,则生成的网络只输出其输入的副本; 换句话说,它最初对身份函数进行建模。 如果目标函数与身份函数非常接近(常常是这种情况),这将大大加快训练速度。
而且,如果添加了许多跳转连接,即使几个层还没有开始学习,网络也可以开始进行(见图 13-13)。 由于跳过连接,信号可以很容易地通过整个网络。 深度剩余网络可以看作是一堆剩余单位,其中每个剩余单位是一个有跳过连接的小型神经网络。
现在让我们看看 ResNet 的架构(见图 13-14)。 这实际上是令人惊讶的简单。 它的开始和结束与GoogLeNet完全一样(除了没有 dropout 层),而在两者之间只是一堆很简单的残余单位。 每个残差单元由两个卷积层组成,使用3×3
的内核和保存空间维度(步幅 1,SAME
填充),批量归一化(BN)和 ReLU 激活。
需要注意的是特征映射的数量每隔几个残差单位会加倍,同时它们的高度和宽度减半(使用步幅 2 卷积层)。
发生这种情况时,输入不能直接添加到剩余单元的输出中,因为它们不具有相同的形状(例如,此问题影响图 13-14 中的虚线箭头表示的跳过连接)。
为了解决这个问题,输入通过一个1×1
卷积层,步长2和正确数量的输出特征映射(见图 13-15)。
ResNet-34 是具有 34 个层(仅计算卷积层和完全连接层)的 ResNet,包含 3 个剩余单元输出 64 个特征映射,4 个剩余单元输出 128 个特征映射,6 个剩余单元输出 256 个特征映射,3 个剩余单元输出 512 个特征映射。
ResNet-152 更深,使用稍微不同的剩余单位。 他们使用三个卷积层,而不是两个 256 个特征映射的3×3
的卷积层,它们使用三个卷积层:第一个卷积层只有 64 个特征映射(少 4 倍),这是一个瓶颈层(已经讨论过) ,然后是具有 64 个特征映射的3×3
层,最后是具有 256 个特征映射(4×64
)的另一个1×1
卷积层,以恢复原始深度。ResNet-152 包含三个这样的剩余单位,输出 256 个特征映射,然后是 8 个剩余单位,输出 512 个特征映射,高达 36 个剩余单位,输出 1024 个特征映射,最后是 3 个剩余单位,输出 2048 个特征映射。
正如你所看到的,这个领域正在迅速发展,每年都会有各种各样的架构出现。 一个明显的趋势是 CNN 越来越深入。 他们也越来越轻量,需要越来越少的参数。 目前,ResNet 架构既是最强大的,也是最简单的,所以它现在应该是你应该使用的,但是每年都要继续关注 ILSVRC 的挑战。 2016 年获奖者是来自中国的 Trimps-Soushen 团队,他们的出错率惊人的缩减到 2.99%。 为了达到这个目标,他们训练了以前模型的组合,并将它们合并为一个整体。 根据任务的不同,降低的错误率可能会或可能不值得额外的复杂性。
还有其他一些架构可供您参考,特别是 VGGNet(2014 年 ILSVRC 挑战赛的亚军)和 Inception-v4(将 GooLeNet 和 ResNet 的思想融合在一起,实现了接近 3% 的 top-5 误差 ImageNet 分类率)。
实施我们刚刚讨论的各种CNN架构真的没什么特别的。 我们之前看到如何构建所有的独立构建模块,所以现在您只需要组装它们来创建所需的构架。 我们将在即将开始的练习中构建 ResNet-34,您将在 Jupyter 笔记本中找到完整的工作代码。
TensorFlow 卷积操作
TensorFlow 还提供了一些其他类型的卷积层:
conv1d()
为 1D 输入创建一个卷积层。 例如,在自然语言处理中这是有用的,其中句子可以表示为一维单词阵列,并且接受场覆盖一些邻近单词。conv3d()
创建一个 3D 输入的卷积层,如 3D PET 扫描。atrous_conv2d()
创建了一个 atrous 卷积层(“àtrous”是法语“with holes”)。 这相当于使用具有通过插入行和列(即,孔)而扩大的卷积核的普通卷积层。 例如,等于[[1,2,3]]
的1×3
卷积核可以以4的扩张率扩张,导致扩张的卷积核[[1,0,0,0,2,0,0,0,3]]
。 这使得卷积层在没有计算价格的情况下具有更大的局部感受野,并且不使用额外的参数。conv2d_transpose()
创建了一个转置卷积层,有时称为去卷积层,它对图像进行上采样(这个名称是非常具有误导性的,因为这个层并不执行去卷积,这是一个定义良好的数学运算(卷积的逆)) 。这是通过在输入之间插入零来实现的,所以你可以把它看作是一个使用分数步长的普通卷积层。例如,在图像分割中,上采样是有用的:在典型的CNN中,特征映射越来越小当通过网络时,所以如果你想输出一个与输入大小相同的图像,你需要一个上采样层。depthwise_conv2d()
创建一个深度卷积层,将每个卷积核独立应用于每个单独的输入通道。 因此,如果有fn
卷积核和fn'
输入通道,那么这将输出fn×fn'
特征映射。separable_conv2d()
创建一个可分离的卷积层,首先像深度卷积层一样工作,然后将1×1
卷积层应用于结果特征映射。 这使得可以将卷积核应用于任意的输入通道组。
Python爱好者社区历史文章大合集:
Python爱好者社区历史文章列表(每周append更新一次)
关注后在公众号内回复“课程”即可获取:
小编的Python入门免费视频课程!!!
【最新免费微课】小编的Python快速上手matplotlib可视化库!!!
崔老师爬虫实战案例免费学习视频。
陈老师数据分析报告制作免费学习视频。
玩转大数据分析!Spark2.X+Python 精华实战课程免费学习视频。