卷积CNN简介

作者: DonkeyJason | 来源:发表于2018-07-21 09:37 被阅读0次

    1.颜色

    计算机处理灰度图片更好
    RGB---->RGB/3
    

    2.统计不变性

    共享权重
    

    3.卷积神经网络

    image.png

    直观感受

    让我们对卷积神经网络如何工作形成更好直观感受。我们先看下人怎样识别图片,然后再看 CNNs 如何用一个近似的方法来识别图片。

    比如说,我们想把下面这张图片识别为金毛巡回犬。


    image.png

    人类是怎么做的呢?

    一种做法是我们识别狗的特定部位,例如鼻子,眼睛,毛发。我们把图片分成小片,识别小片,然后把这些结合在一起,得到一个狗的概念。

    这种情况下,我们可以把图片分成下列组合:

    • 一个鼻子
    • 两只眼睛
    • 金色毛发

    如下图所示:


    image.png

    狗的眼睛

    image.png

    狗的鼻子

    image.png

    狗的毛发

    再进一步

    再进一步来说,我们如何确定鼻子在哪呢?一个金毛巡回犬的鼻子可以看出是一个椭圆形,有两个黑洞在里面。因此,一种辨别巡回犬鼻子的方法是把它分割更小的区域,寻找黑洞(鼻孔)和椭圆的曲线。如下所示:

    image.png

    用来确定鼻子的曲线

    image.png

    用来确定鼻子的鼻孔

    广义上来说,这就是 CNN 的学习方式。它学习识别基本的直线,曲线,然后是形状,点块,然后是图片中更复杂的物体。最终 CNN 分类器把这些大的,复杂的物体综合起来识别图片。

    在我们的例子中,层级关系是:

    • 简单的形状,如椭圆,暗色圆圈
    • 复杂的物体(简单形状的组合),例如眼睛,鼻子,毛发
    • 狗的整体(复杂物体的组合)

    有了深度学习,我们不需要设定 CNN 来识别特定的特征。相反,CNN 通过正向和反向传播,自己学习识别上述物体。

    尽管我们从来没有让 CNN 寻找特定的特征信息,但是它识别图片的能力却好的惊人!

    尽管我们从来没有让 CNN 寻找特定的特征信息,但是它识别图片的能力却好的惊人!

    image.png

    CNN 可能有几层网络,每个层可能捕获对象抽象层次中的不同级别。第一层是抽象层次的最底级,CNN 一般把图片中的较小的部分识别成简单的形状,例如水平、竖直的直线,简单的色块。下一层将会上升到更高的抽象层次,一般会识别更复杂的概念,例如形状(线的组合),以此类推直至最终识别整个物体,例如狗。

    再次强调,CNN 是自主学习。我们不需要告诉 CNN 去寻找任何直线、曲线、鼻子、毛发等等。CNN 从训练集中学习并发现金毛巡回犬值得寻找的特征。

    这是个不错的开始!希望你对 CNNs 如何工作有了直观的了解。

    接下来我们看看实现的细节。

    4.分解一张图片

    CNN 的第一步是把图片分成小块。我们通过选取一个给定宽度和高度的滤波器来实现这一步。

    滤波器会照在图片的小块 patch (图像区块)上。这些 patch 的大小与滤波器一样大。


    image.png
    CNN用滤波器来把图片分割成更小的patch,patch的大小跟滤波器大小相同
    

    我们可以在水平反方向,或者竖直方向滑动滤波器对图片的不同部分进行聚焦。

    滤波器滑动的间隔被称为stide(步长)。这是可以调节的一个超参数。增大stride值后,会减少每层总patch量,因此也减少了模型大小。通过这也会降低图像精度。

    让我们看一个看一个例子,在这个放大的狗的图片中,我们从红框开始,我们滤波器的高度和宽度决定了这个正方形的大小。

    image.png

    然后我们向右把方块移动一个给定的步长(这里是2),得到另一块 patch。

    image.png
    我们把方块像右移动两个像素,得到另一个patch
    

    这里最重要的是我们把相邻的像素聚在一起,把他们视作一个集合。

    在普通非卷积的神经网络中,我们忽略了这种临近性。在普通网络中,我们把输入图片中的每一个像素与下一层的神经元相连。图片中相邻像素在一起是有原因的,并且有着特殊意义,但普通网络没有有效利用好这些信息。

    要利用这种临近结构,我们的 CNN 就要学习如何分类临近模式,例如图片中的形状和物体。
    滤波器深度 Filter Depth

    通常都会有多余一个滤波器,不同滤波器提取一个 patch 的不同特性。例如,一个滤波器寻找特定颜色,另一个寻找特定物体的特定形状。卷积层滤波器的数量被称为滤波器深度。

    image.png
    上述例子中,一个patch与下一个层的神经网络相连接
    

    每个 patch 连接多少神经元?

    这取决于滤波器的深度,如果深度是 k,我们把每个 patch 与下一层的 k 个神经元相连。这样下一层的高度就是 k,如下图所示。实际操作中,k是一个我们可以调节的超参数,大多数的 CNNs 倾向于选择相同的起始值。

    image.png
    滤波器的深度为k,与下一层的k个神经元相连接
    

    为什么我们把一个 patch 与下一层的多个神经元相连呢?一个神经元不够好吗?

    多个神经元的作用在于,一个 patch 可以有多个有意义的,可供提取的特点。

    例如,一个 patch 可能包括白牙,金色的须,红舌头的一部分。在这种情况下,我们需要一个深度至少为3的滤波器,一个识别牙,一个识别须,一个识别舌头。

    image.png
    这只狗的patch有很多有意思的特征需要提取。包括牙,旭以及粉红色的舌头
    

    一个 patch 连接有多个神经元可以保证我们的 CNNs 学会提取任何它觉得重要的特征。

    记住,CNN 并没有被规定寻找特定特征。与之相反,它自我学习什么特征值得注意。

    特征图像大小

    image.png

    )

    参数共享

    image.png
    在CNN的一层中的patch中共享权重W,无论猫在图片的哪个位置都可以找到 
    

    当我们试图识别一个猫的图片的时候,我们并不在意猫出现在哪个位置。无论是左上角,右下角,它在你眼里都是一只猫。我们希望 CNNs 能够无差别的识别,这如何做到呢?

    如我们之前所见,一个给定的 patch 的分类,是由 patch 对应的权重和偏置项决定的。

    如果我们想让左上角的猫与右下角的猫以同样的方式被识别,他们的权重和偏置项需要一样,这样他们才能以同一种方法识别。

    这正是我们在 CNNs 中做的。一个给定输出层学到的权重和偏置项会共享在输入层所有的 patch 里。注意,当我们增大滤波器的深度的时候,我们需要学习的权重和偏置项的数量也会增加,因为权重并没有共享在所有输出的 channel 里。

    共享参数还有一个额外的好处。如果我们不在所有的 patch 里用相同的权重,我们必须对每一个 patch 和它对应的隐藏层神经元学习新的参数。这不利于规模化,特别对于高清图片。因此,共享权重不仅帮我们平移不变,还给我们一个更小,可以规模化的模型。
    Padding

    image.png
    一个5x5的网络附带一个3x3的滤波器。
    

    假设现在有一个 5x5 网格 (如上图所示) 和一个尺寸为 3x3 stride值为 1 的滤波器(filter)。 下一层的 width 和 height 是多少呢? 如图中所示,在水平和竖直方向都可以在3个不同的位置放置 patch, 下一层的维度即为 3x3 。下一层宽和高的尺寸就会按此规则缩放。

    在理想状态下,我们可以在层间保持相同的宽度和高度,以便继续添加图层,保持网络的一致性,而不用担心维度的缩小。如何实现这一构想?其中一种简单的办法是,在 5x5 原始图片的外层包裹一圈 0 ,如下图所示。

    image.png
    为了0 padding的相同网格。
    

    这将会把原始图片扩展到 7x7。 现在我们知道如何让下一层图片的尺寸维持在 5x5,保持维度的一致性。
    维度

    综合目前所学的知识,我们应该如何计算 CNN 中每一层神经元的数量呢?

    输入层(input layer)维度值为W, 滤波器(filter)的维度值为 F (height * width * depth), stride 的数值为 S, padding 的数值为 P, 下一层的维度值可用如下公式表示: (W−F+2P)/S+1。

    我们可以通过每一层神经元的维度信息,得知模型的规模,并了解到我们设定的 filter size 和 stride 如何影响整个神经网络的尺寸。

    卷积输出维度练习

    • 介绍

    接下来的几个练习将检测你对 CNNs 维度的理解,理解维度可以帮你在模型大小和模型质量上,做精确的权衡。你将会了解,一些参数对模型大小的影响会远大于另外一些。

    设置
    H = height, W = width, D = depth

    我们有一个输入维度是 32x32x3 (HxWxD)
    20个维度为 8x8x3 (HxWxD) 的滤波器
    高和宽的stride(步长)都为 2。(S)
    padding 大小为1 (P)
    计算新的高度和宽度的公式是:

    new_height = (input_height - filter_height + 2 * P)/S + 1
    new_width = (input_width - filter_width + 2 * P)/S + 1
    

    卷积层输出维度

    输出的维度(shape)是什么?

    答案写成 HxWxD 的形式。假设你认为新的高度是 9,新的宽度是 9,新的深度是 5,则在答案框中输入 9x9x5。
    答案
    答案是 14x14x20

    代入公式可以得到下列结果:

    (32 - 8 + 2 * 1)/2 + 1 = 14
    (32 - 8 + 2 * 1)/2 + 1 = 14
    

    新的深度与滤波器的数量相同,都是 20。
    对应如下代码:

    input = tf.placeholder(tf.float32, (None, 32, 32, 3))
    filter_weights = tf.Variable(tf.truncated_normal((8, 8, 3, 20))) # (height, width, input_depth, output_depth)
    filter_bias = tf.Variable(tf.zeros(20))
    strides = [1, 2, 2, 1] # (batch, height, width, depth)
    padding = 'VALID'
    conv = tf.nn.conv2d(input, filter_weights, strides, padding) + filter_bias
    

    注意,这里的conv 输出的是 [1, 13, 13, 20]。这是对应 batch size 的 4D 大小,重要的是它不是 [1, 14, 14, 20]。这是因为 TensorFlow 的 padding 算法与上面的并不完全相同。一个可替换方案是把 padding 从 'VALID' 改为'SAME',这样得到的结果是 [1, 16, 16, 20]。如果你想了解 TensorFlow 中的 padding 如何工作,可以看这个文档。

    总之,TensorFlow 使用如下等式计算 SAME 、PADDING

    SAME Padding, 输出的高和宽,计算如下:

    out_height = ceil(float(in_height) / float(strides1))
    
    out_width = ceil(float(in_width) / float(strides[2]))
    

    VALID Padding, 输出的高和宽,计算如下:

    out_height = ceil(float(in_height - filter_height + 1) / float(strides1))
    
    out_width = ceil(float(in_width - filter_width + 1) / float(strides[2]))
    

    参数的数量

    我们要计算卷积层的参数的数量,在此将使用上一个练习的答案!

    能够计算神经网络里面的参数数量很有用,因为我们想控制神经网络使用的内存空间。

    设置

    H = height, W = width, D = depth

    • 输入数据,维度为 32x32x3 (HxWxD)
    • 20个滤波器,维度为 8x8x3 (HxWxD)
    • stride(步长)高和宽的都为 2 (S)
    • padding 大小为1 (P)

    输出层

    • 14x14x20 (HxWxD)
      提示

    没有参数共享,每个输出层的神经元必须连接到滤波器的每个神经元。此外,每个输出层的神经元必须连接到一个偏置神经元。

    答案
    总共有756560个参数。这非常多!这是我们的计算方法:

    (8 * 8 * 3 + 1) * (14 * 14 * 20) = 756560
    

    8 * 8 * 3 是权值数量,加上 1 作为 bias。因为每一个权值都与输出的每一部分相连。所以我们把这两个数相乘得到最后答案。

    参数共享

    如果输出层的每个神经元与其它同样通道的神经元共享参数,现在我们想让你来计算卷积层的参数数量。

    这是实际卷积层(tf.nn.conv2d())使用的参数数量。

    设置

    H = height, W = width, D = depth

    • 我们有一个输入维度是 32x32x3 (HxWxD)

    • 20个维度为 8x8x3 (HxWxD) 的滤波器

    • 高和宽的stride(步长)都为 2。(S)

    • padding 大小为1 (P)
      输出层

    • 14x14x20 (HxWxD)
      提示

    有了参数共享,每个输出通道的神经元与相同通道的其它神经元共享权值。参数的数量与滤波器神经元的数量相同,加上偏置,再乘以输出层的通道数。
    卷积层参数

    卷积层参数 2
    有了参数共享后,卷积层有多少参数?
    

    答案

    总计有 3860 个参数。是之前的196分之一。是这样计算的:

    (8 * 8 * 3 + 1) * 20 = 3840 + 20 = 3860
    

    3840 个权值与 20 个偏置。这与之前练习的答案类似,区别就是20,而不是 (14 * 14 * 20)。记住,有了权值共享,一整个深度切片,我们用同一个滤波器。所以我们可以拿掉14 * 14只留下20。

    CNNs 可视化

    让我们看一个 CNN 的例子,了解它如何运作。

    我们看到的训练 ImageNet 的 CNN 例子,来自 Zeiler 和 Fergus 的论文 。在下图中(同样取自此论文),我们会看到网络中的每一层侦测到什么,看到每一层如何侦测更复杂的概念。

    第一层

    image.png
    网络第一层被激活的样例。有简单的对角线(左上)和绿色色块(中下) 
    

    图片来自 Matthew Zeiler 和 Rob Fergus 的 deep visualization toolbox,让我们可以可视化地看到 CNN 每一层的关注的点是什么。

    上述格子中的每一个图片都代表一个激活神经元的图案。换句话说,这些是第一层认出的图案。左上角的图有一条-45度的直线,上方中间的图有一个+45度的直线。如下所示:

    image.png
    可以看到第一层识别出的-45度的直线
    
    image.png
    CNN的第一层还是别出了+45度的直线
    

    让我们看下引发这些示例图片的图片。下面的都引发了-45度的直线,尽管他们有不同的颜色,渐变和图案。

    image.png

    所以 CNN 的第一层很清楚的选择了非常简单的形状、图案,例如直线和色块。

    第二层

    image.png
    CNN 第二层的可视化。可以发现它注意到更复杂的概念例如圈,条纹。左边的图表示这一次 CNN 的激活状况(或者说它“看到”了什么),右边是引起这些状况的原始图片。
    

    CNN 的第二层捕捉了一些复杂的概念。

    如上图所示,CNN 的第二层认出了圈(第二行第二栏),条纹(第一行第二栏)和长方形(右下角)。

    CNN 是自己学着做这些事情的。 我们并没有设定让更深的网络层聚焦于更复杂的事物上。只要把训练数据输入 CNN,自然就会发生这样的事情。

    第三层

    image.png
    CNN 第三层的可视化图。左边的网格表示 CNN 的激活(或者说它“看到”了什么)。右边是相对应的原始图片。
    

    第三层捕捉了第二层特征的复杂组合。包括格子,蜂窝状(左上),轮子(第二行第二列)甚至脸(第三行第三列)。

    第五层

    image.png
    CNN 第五层,也是最后一层的可视化。左边的灰色网格表示 CNN 的激活(或者说它“看到”了什么)。右边是相对应的原始图片。
    

    我们跳过了第四层(这一层同样遵循这个规律),直接跳到 CNN 的第五层,也是最后一层。

    最后一层选取了我们最关心的,可用作分类的概念,例如狗的脸,鸟的脸,自行车。

    回到 TensorFlow
    我们对卷积神经网络的高层次讨论就此告一段落。

    接下来你要在 TensorFlow 里面构建这些网络。

    相关文章

      网友评论

        本文标题:卷积CNN简介

        本文链接:https://www.haomeiwen.com/subject/jdncmftx.html