精华内容
下载资源
问答
  • 卷积神经网络(CNN)之一维卷积、二维卷积、三维卷积详解 作者:szx_spark 由于计算机视觉的大红大紫,二维卷积的用处范围最广。因此本文首先介绍二维卷积,之后再介绍一维卷积与三维卷积的具体流程,并描述...

    卷积神经网络(CNN)之一维卷积、二维卷积、三维卷积详解

    作者:szx_spark
    由于计算机视觉的大红大紫,二维卷积的用处范围最广。因此本文首先介绍二维卷积,之后再介绍一维卷积与三维卷积的具体流程,并描述其各自的具体应用。

    1. 二维卷积

    1223117-20180212184502796-2124697190.png

    • 图中的输入的数据维度为14×1414×14,过滤器大小为5×55×5,二者做卷积,输出的数据维度为10×1010×10145+1=1014−5+1=10)。如果你对卷积维度的计算不清楚,可以参考我之前的博客吴恩达深度学习笔记(deeplearning.ai)之卷积神经网络(CNN)(上)

    • 上述内容没有引入channel的概念,也可以说channel的数量为1。如果将二维卷积中输入的channel的数量变为3,即输入的数据维度变为(14×14×314×14×3)。由于卷积操作中过滤器的channel数量必须与输入数据的channel数量相同,过滤器大小也变为5×5×35×5×3。在卷积的过程中,过滤器与数据在channel方向分别卷积,之后将卷积后的数值相加,即执行10×1010×10次3个数值相加的操作,最终输出的数据维度为10×1010×10

    • 以上都是在过滤器数量为1的情况下所进行的讨论。如果将过滤器的数量增加至16,即16个大小为10×10×310×10×3的过滤器,最终输出的数据维度就变为10×10×1610×10×16。可以理解为分别执行每个过滤器的卷积操作,最后将每个卷积的输出在第三个维度(channel 维度)上进行拼接。

    • 二维卷积常用于计算机视觉、图像处理领域。

    2. 一维卷积

    1223117-20180212193102531-761358003.png

    • 图中的输入的数据维度为8,过滤器的维度为5。与二维卷积类似,卷积后输出的数据维度为85+1=48−5+1=4

    • 如果过滤器数量仍为1,输入数据的channel数量变为16,即输入数据维度为8×168×16。这里channel的概念相当于自然语言处理中的embedding,而该输入数据代表8个单词,其中每个单词的词向量维度大小为16。在这种情况下,过滤器的维度由55变为5×165×16,最终输出的数据维度仍为44

    • 如果过滤器数量为nn,那么输出的数据维度就变为4×n4×n

    • 一维卷积常用于序列模型,自然语言处理领域。

    3. 三维卷积

    1223117-20180212194618921-376193862.png

    这里采用代数的方式对三维卷积进行介绍,具体思想与一维卷积、二维卷积相同。

    • 假设输入数据的大小为a1×a2×a3a1×a2×a3,channel数为cc,过滤器大小为ff,即过滤器维度为f×f×f×cf×f×f×c(一般不写channel的维度),过滤器数量为nn

    • 基于上述情况,三维卷积最终的输出为(a1f+1)×(a2f+1)×(a3f+1)×n(a1−f+1)×(a2−f+1)×(a3−f+1)×n。该公式对于一维卷积、二维卷积仍然有效,只有去掉不相干的输入数据维度就行。

    • 三维卷积常用于医学领域(CT影响),视频处理领域(检测动作及人物行为)。

    4
    1
    « 上一篇:吴恩达深度学习笔记(deeplearning.ai)之卷积神经网络(CNN)(下)
    » 下一篇:吴恩达深度学习笔记(deeplearning.ai)之循环神经网络(RNN)(一)
    posted @ 2018-02-12 19:55 szx_spark 阅读(33325) 评论(2) 编辑 收藏

    #1楼 2019-06-17 10:01 李莫愁  
    作者您好,感谢您的分享,内容很详细,很有帮助。
    在此纠正一个小错误,在1二维卷积中,第三条,当过滤器数量增加到16时,过滤器的大小应该时5*5*16。
    #2楼42814112019/6/17 10:02:55 2019-06-17 10:02 李莫愁  
    16个5*5*3

    转载于:https://www.cnblogs.com/SanguineBoy/p/11215308.html

    展开全文
  • .边缘检测 1.卷积是如何运算的? 对应位相乘,具体方法见另博文https://blog.csdn.net/qq_40243295/article/details/104391755 卷积运算: python中是conv_forward TensorFlow中是td.nn.conv2d kears中是...

    目录

    一.边缘检测

    1.1 卷积是如何运算的?

    1.2 为什么卷积可以做垂直边缘检测呢?卷积是如何工作的?

    1.3 如何区分垂直边缘是由深入浅,还是由浅入深的边缘?

    二.padding

    2.1 卷积中存在的缺点

    2.2 问题解决

    2.3 两个参数的含义

    三.步长strided

    3.1 输入和输出的维度

    3.2 cross-correlation VS. correlation (深度学习中的卷 vs. 数学中的卷积)

    四.立体卷积

             4.1 立体卷积的计算

    4.2 多个边缘检测器

    五.单层卷积网络

     5.1 如何构建卷积神经网络的卷积层?(卷积神经网络在某一次的工作原理)

    5.2 如何让卷积层从一层传播到下一层?

    5.3 卷积的标识

    六、池化层

    6.1 最大池化

             6.2 平均池化(不太常用)

    6.3 超级参数

    七、卷积神经网络示例

    7.1 示例的构建过程详述

    7.2 示例中激活值的形状,大小,参数数量

    八. 为什么使用卷积?

    8.1 参数共享

    8.2 稀疏连接


    一.边缘检测

    1.1 卷积是如何运算的?

    对应位相乘,具体方法见另一博文https://blog.csdn.net/qq_40243295/article/details/104391755

    卷积运算:

    python中是conv_forward

    TensorFlow中是td.nn.conv2d

    kears中是Conv2D

    1.2 为什么卷积可以做垂直边缘检测呢?卷积是如何工作的?

    如下图所示:

    左侧图:代表输入的6x6的灰度图,10表示白色,0表示灰色

    中间图:代表卷积核1、0、-1分别表示白、灰、黑(或者可用浅色,中间不考虑,深色像素来表达)

    右侧图:右侧图是通过卷积得到的结果,0、10分别代表灰、白;中间的白色就是检测出来的边缘。但是此时由于输入的图片大小是6x6的所以就会显得检测出来的边缘很宽,如果输入的图片是1000x1000的边缘就会很窄。

    1.3 如何区分垂直边缘是由深入浅,还是由浅入深的边缘?

    水平边缘检测

    如果将卷积核的9个元素为以下取值,就分别是sobel核与scharr核:

    如果将9个元素当做参数,然后进行反向传播算法,将输入图与卷积核进行得到理想的边缘检测,其目标就是理解这9个参数。相比较于这些单纯水平垂直的卷积核,这样的卷积核可以算出45°,75°,81°甚至是任意角度的边缘。所以通过将9个元素当做参数,通过数据反馈,让神经网络自动的去学习它所需的任何卷积核,并且在整幅图上运用此卷积核,依次检测任何的边缘。

    要讨论反向传播我们还需要学习一下内容padding和各种卷积的发展,其是卷积神经网络中卷积模块重要的组成部分

    二.padding

    2.1 卷积中存在的缺点

    已知输入像素(nxn),卷积核大小(f x f),可以得到卷积后的图像像素大小(n-f+1 x n-f+1),如图:

    由于卷积过程中的两个缺点的存在:

    1.原图每经过依次卷积之后,像素就会缩小,因此卷积很多次之后图像就会变得非常小。

    2.角落或边缘的像素点信息容易丢失。例如下图:左上角的像素点只被包括了一次,但是中间的像素点被包括了很多次,那么左上角的像素点的数据卷积后就很容易丢失。

    2.2 问题解决

    因此,我们需要在给原图卷积之前填充一层像素(用0填充),使卷积之后的图片与原图像素相同。

    例如原图为6x6,卷积核是3x3,则可以将原图扩充为8x8的(扩充后大小=n-f+1,其中n为原图大小,f为卷积核大小),因此输出还是6x6的图(8-3+1=6)

    另外一种表示:将边缘用p表示(扩充了一层此时p=1)。但是计算时,扩充一层就是上下共两行(就是2p),所以表达式是n+2p-f-1 x n+2p-f-1,这就是卷积之后输出的大小,解决了卷积之后图像缩小的问题。

    由n=n+2p-1解出p,

    p=(f-1)/2

    f是卷积层的大小(通常为奇数),n是原图的大小。

    6x6的原图中左上角的像素点,扩充后进行卷积,也可以影响好几个框,所以保留了像素点的值,解决了边缘信息易丢失的问题。

    2.3 两个参数的含义

    三.步长strided

    卷积中的步长是构建卷积神经网络的基本操作。

    3.1 输入和输出的维度

    其是由以下公式决定:

    参数:

    原图式:n x n

    卷积核: f x f 

    padding: p

    stride :s 此处s=2

    输出图像像素表达式:[(n+2p-f)/s +1] x [(n+2p-f)/s +1]

    如果计算出不是整数,则向下取整

    3.2 cross-correlation VS. correlation (深度学习中的卷 vs. 数学中的卷积)

    在数学中卷积运算要对原卷积核进行翻转再与原图进行计算。

    但从技术上来讲,我们不进行翻转。因此两者是有区分的

    省略旋转的原因是:旋转之后就会有(A*B)*C=A*(B*C)的性质,但对深度神经网络不重要,因此我们省略这个双重镜像操作以简化代码,并且神经网络也能正常工作。

     

    四.立体卷积

    4.1 立体卷积的计算

    灰度图的是6*6*1是一维的

    但是彩色图是6*6*3有三个通道数,因此是三维的。卷积核的通道数要与原图的通道数相同,因此卷积核也是三维的。

    但是卷积之后的图片是二维的。

    通道数channels,也叫三维立体图的深度

    左侧27个数与卷积核对于位置数相乘求和,得到卷积后的一个值,移动卷积核对于位的27个值对于相乘求和,以此类推..... 

    红色边缘检测:R设置为正常,G、B设置为全0

    任意颜色检测:R、G、B都设置为正常,具体如图:

    4.2 多个边缘检测器

    三维下,我们不仅仅想要垂直的边缘检测器,还想要同时检测水平,垂直的,或者45°,70°以及各个方向的边缘检测器,该如何实现?

    我们可以使用多个卷积核与原图卷积,然后将卷积后的图依次叠加起来,第一个在叠加图的最上面.....,如图所示:

    五.单层卷积网络

     5.1 如何构建卷积神经网络的卷积层?(卷积神经网络在某一次的工作原理)

    原图分别与各个卷积核卷积,最终各自形成一个卷积神经网络层,然后增加偏差(给卷积神经网络层的16个元素,每个都加同一个偏差),然后应用一个非线性激活函数ReLU,最终得到另一个4x4的矩阵。然后重复我们之前的操作,将这两个矩阵堆叠起来,就变成了一个4x4x2的的矩阵。

    5.2 如何让卷积层从一层传播到下一层?
     

    参数:

    最初的输入层为a[0],下一层为a[1],第一层的过滤器表示为w[1]

    1. 使用线性函数:a[0]w[1],卷积后的结果就是a[0]w[1],即原图与卷积核对应位相乘的结果。

    2. 再加上偏差b:变为w[1]a[0]+b,记为z[1],z[1]就是应用激活函数之前的值。

    3. 使用激活函数ReLU:g(z[1])就是应用激活函数之后的值,记为a[1],成为神经网络的下一层。

    z[1]=w[1]a[0]

    然后执行非线性激活函数得到a[1]=g(z[1])

    假设有10个过滤器(可以提取10个特征),每个是3x3x3,那么这一层有多少个参数呢?

    1个过滤器:3x3x3=27+一个偏差b=28个参数

    28x10个=280个参数

    注意:无论输入的图片是多大的,参数始终是280个

    5.3 卷积的标识

    f[l]:l层中过滤器的大小filter size

    p[l]:l层的padding

    s[l]:l层的步长stride

    l层的输入值:即上层的输出层,nh[l-1] x  nw[l-1] x nc[l-1](三个分别代表高、宽、通道数)

    l层的输出层:nh[l] x  nw[l] x nc[l]

    输出图片的大小:nh[l] = [(nh[l-1]+2p[l]-f[l])/s[l]]+1向下取整

    nw[l] = [(nw[l-1]+2p[l]-f[l])/s[l]]+1向下取整

     nc[l]=该层过滤器的数量,过滤器的通道数必须与输入的通道数保持一致

    过滤器大小:f[l] x f[l] x nc[l-1]

    应用偏差和非线性函数之后,l层的输出的激活值就是a[l],a[l]是一个三维体,即nh[l] x  nw[l] x nc[l]

    如果执行批量梯度下降,如果有m个例子,就是有m个激活值,A[l]=m x nh[l] x  nw[l] x nc[l]

    权重参数Weights:f[l] x f[l] x nc[l-1] x nc[l]

    偏差bias:每个过滤器都有一个偏差参数,1x1x1xnc[l]

     

    简单卷积网络示意:

    典型的卷积网络通常有三层:

    -Convolution (Conv)卷积层

    -Pooling(pool)池化层

    -Fully connected(FC)全连接层

    虽然仅适用卷积层也有可能构建出很好的神经网络,但大部分神经网络架构师依然会添加池化层和全连接层。

     

    六、池化层

    卷积网络除了卷积层也经常使用池化层,来缩减模型的大小,提高计算速度,同时提高所提取特征的鲁棒性。

    池化类型:最大池化,平均池化

    6.1 最大池化

    假如输入是一个4x4矩阵,执行最大池化输出的是一个2x2矩阵

    执行过程:把4x4输入拆分成不同的区域(图中用不同颜色标记4个区域),对于2x2的输出,输出的每个元素都是其对应颜色区域中的最大元素值。

    这就像应用了一个规模为2X2,步长为2的过滤器,这就是最大池化的超级参数。 

    数字大意味着可能提取了某些特定特征,左上象限具有这个特征,其可能是一个垂直边缘;右上象限并不存在这个特征。

    最大化操作的功能就是只要在任何一个象限内提取到某个特征,它就会保留在最大池化的输出里。最大化运算的实际作用就是如果在过滤器中提取到某个特征,那么就保留其最大值。如果没有提取到这个特征,其区域内最大值也是很小的,

    卷积层输出大小的公式,同样适用于池化层

    6.2 平均池化(不太常用)

     

    6.3 超级参数

    池化的超级参数包括过滤器的大小f和步长s,常用参数是f=2,s=2,其效果相当于高度和宽度缩减一半,其他参数就要看你使用的是最大池化还是平均池化。它有一组超级参数,但是并没有参数需要学习,一旦f和s确定,它就是一个固定运算。

    注意:池化过程中没有需要学习的参数,执行反向传播时,反向传播没有参数适用于最大池化;最大池化知识计算神经网络某一层的静态属性。

     

    七、卷积神经网络示例

    7.1 示例的构建过程详述

    识别RGB图中的数字,输入是32x32x3,第一层过滤器大小是5x5,步长是1,padding是0,过滤器个数是6个,那么输出是28x28x6,增加偏差,应用非线性函数后输出,将这一层标记为CONV1

    然后构建一个池化层,选择最大池化,参数f=2,s=2(表示层的高度和宽度会减少一半)因此变为了14x14,通道数量保持不变,最终输出的为14x14x6,将该输出标记为POOL1

    在文献中卷积的分类有两种,这与所谓层的划分存在一致性,一类卷积是一个卷积层和一个池化层一起作为一层,这就是神经网络的Layer1,另一类卷积是吧卷积层作为一层,而池化层单独作为一层,人们在计算神经网络有多少层,通常只是统计具有权值和参数的层。因为池化层没有权重和参数,只有一些超级参数,这里我们把CONV1和POOL1共同作为一个卷积,并标记为Layer1。

    此时Layer1的输出为14x14x6。

    再构建一个卷积层,过滤器大小是5x5,步长是1,有16个过滤器,最后输出的是10x10x16的矩阵,记为CONV2

    然后做最大池化,超级参数f=2,s=2,结果是5x5x16,记为POOL2

    CONV2与POOL2组成一个卷积,记为Layer2。

    5x5x16=400个元素,将POOL2平整化为一个大小为400的一维向量,将整平化的结果想象成一个神经元集合,然后利用这400个单元构建下一层,下一层含有个120个单元,这就是我们第一个全连接层,标记为FC3

    因为这400个单元与120个单元每一个相连接,这就是全连接层。这是一个标准的神经网络,它在120x400的维度上具有一个权重矩阵w[3],最后输出120个维度。

    然后我们对这120个单元再添加一个全连接层,假设FC4有84个单元,用这84个单元填充一个softmax单元,其有10个输出(功能是识别0—9的10个数字)。

    超级参数尽量采用文献中别人使用过的参数,这样效果比较好。

    另外一种模型是一个或多个卷积层后面跟随一个池化层,然后一个或多个卷积层后面再跟随一个池化层,然后后面再跟几个全连接层。最后是softmax,这是神经网络的另一种常见模式。

    7.2 示例中激活值的形状,大小,参数数量

    输入层:32x32x3=3072,输入层没有参数

    注意:

    (1)池化层和最大池化层没有参数,

    (2)卷积层的参数相对较少

    (3)大多数参数存在于神经网络的全连接层,随着神经网络的加深,激活值会逐渐变小,若激活值下降太快,也会影响网络性能。

     许多计算机视觉研究正在探索如何把这些基本模块(卷积层,池化层,全连接层)整合起来,构建高效的神经网络。

    5x5=25,25+偏移量1=26个参数,26x8=208

    5x5=25,25+偏移量1=26个参数,26x16=416

    全连接层:400x120+1=48001

    120x84+1=10081

    84x10+1=841

    八. 为什么使用卷积?

    与只使用连接层相比,卷积层的两个主要优势在于参数共享和稀疏连接,假设有一张32x32x3维度的照片,用6个5x5的过滤器,输出的维度为28x28x6,32x32x3=3072,28x28x6=4704,我们构建一个神经网络,其中一层含有3072个单元,下一层含有4074个单元,,两层中的每个神经元彼此相连,然后计算权重矩阵,它等于3072x4704越等于1400万。因此要训练的参数很多,如果图片更大,权重矩阵就会变得非常大。

    卷积层的参数数量:每个过滤器是5x5的,再加上偏差,因此每个过滤器有25+1=26个参数,一共6个过滤器,参数共计26x6=156个,参数数量还是很少的。

    卷积网络映射参数少有两个原因:参数分享与稀疏连接。

    8.1 参数共享

    特征检测如垂直检测,如果其适用于某一区域,则它也可能适用于图片的其他区域,换而言之,就是你用一个3

    x3的过滤器检测垂直边缘,那么图片左上角区域,以及旁边的各个区域都可以使用这个3x3的过滤器,每个特征检测器以及输出,都可以在输入图片的不同区域用使用相同的参数卷积,以便提取垂直边缘或其他特征。

    整张照片共享一个特征检测器。提取效果也很好

    8.2 稀疏连接

    例如输出矩阵中的的第一个元素0,它只依赖输入中左上角3x3的单元格,即此0只与36个输入特征中的9个相连接。

    神经网络可以通过参数分享,稀疏连接这两种机制减少参数。并且卷积神经网络善于捕捉平移不变。

     

    展开全文
  • 在看这两个函数之前,我们需要先了解一维卷积(conv1d)和二维卷积(conv2d),二维卷积是将一个特征图在width和height两个方向进行滑动窗口操作,对应位置进行相乘求和;而一维卷积则只是在width或者height方向上进行...

    作者:凌逆战

    地址:https://www.cnblogs.com/LXP-Never/p/10763804.html


    在看这两个函数之前,我们需要先了解一维卷积(conv1d)二维卷积(conv2d),二维卷积是将一个特征图在width和height两个方向进行滑动窗口操作,对应位置进行相乘求和;而一维卷积则只是在width或者height方向上进行滑动窗口并相乘求和。

    一维卷积:tf.layers.conv1d()

    一维卷积常用于序列数据,如自然语言处理领域。

    tf.layers.conv1d(
        inputs,
        filters,
        kernel_size,
        strides=1,
        padding='valid',
        data_format='channels_last',
        dilation_rate=1,
        activation=None,
        use_bias=True,
        kernel_initializer=None,
        bias_initializer=tf.zeros_initializer(),
        kernel_regularizer=None,
        bias_regularizer=None,
        activity_regularizer=None,
        kernel_constraint=None,
        bias_constraint=None,
        trainable=True,
        name=None,
        reuse=None
    )
    

    参数:[1]

    • inputs:张量数据输入,一般是[batch, width, length]
    • filters:整数,输出空间的维度,可以理解为卷积核(滤波器)的个数
    • kernel_size:单个整数或元组/列表,指定1D(一维,一行或者一列)卷积窗口的长度。
    • strides:单个整数或元组/列表,指定卷积的步长,默认为1
    • padding:"SAME" or "VALID" (不区分大小写)是否用0填充,
        • SAME用0填充;
        • VALID不使用0填充,舍去不匹配的多余项。
    • activation:激活函数
    • ues_bias:该层是否使用偏差
    • kernel_initializer:卷积核的初始化
    • bias_initializer:偏置向量的初始化器
    • kernel_regularizer:卷积核的正则化项
    • bias_regularizer:偏置的正则化项
    • activity_regularizer:输出的正则化函数
    • reuse:Boolean,是否使用相同名称重用前一层的权重
    • trainable:Boolean,如果True,将变量添加到图collection中
    • data_format:一个字符串,一个channels_last(默认)或channels_first。输入中维度的排序。
        • channels_last:对应于形状的输入(batch, length, channels)
        • channels_first:对应于形状输入(batch, channels, length)
    • name = 取一个名字

    返回值

      一维卷积后的张量,

    例子

    import tensorflow as tf 
    
    x = tf.get_variable(name="x", shape=[32, 512, 1024], initializer=tf.zeros_initializer)
    x = tf.layers.conv1d(
        x,
        filters=1,                    # 输出的第三个通道是1
        kernel_size=512,            # 不用管它是多大,都不影响输出的shape
        strides=1,
        padding='same',
        data_format='channels_last',
        dilation_rate=1,
        use_bias=True,
        bias_initializer=tf.zeros_initializer())
    
    print(x)            # Tensor("conv1d/BiasAdd:0", shape=(32, 512, 1), dtype=float32)
    

    解析

    1. 输入数据的维度为[batch, data_length, data_width]=[32, 512, 1024],一般输入数据input第一维为batch_size,此处为32,意味着有32个样本,第二维度和第三维度分别表示输入的长和宽(512,1024)
    2. 一维卷积核是二维的,也有长和宽,长为卷积核的数量kernel_size=512,因为卷积核的数量只有一个,所以宽为输入数据的宽度data_width=1024,所以一维卷积核的shape为[512,1024]
    3. filteres是卷积核的个数,即输出数据的第三维度。filteres=1,第三维度为1
    4. 所以卷积后的输出数据大小为[32, 512, 1]

    二维卷积:tf.layers.conv2d()

    二维卷积常用于计算机视觉、图像处理领域

    tf.layers.conv2d(
        inputs,
        filters,
        kernel_size,
        strides=(1, 1),
        padding='valid',
        data_format='channels_last',
        dilation_rate=(1, 1),
        activation=None,
        use_bias=True,
        kernel_initializer=None,
        bias_initializer=tf.zeros_initializer(),
        kernel_regularizer=None,
        bias_regularizer=None,
        activity_regularizer=None,
        kernel_constraint=None,
        bias_constraint=None,
        trainable=True,
        name=None,
        reuse=None
    )
    

    参数:[4]

    • inputs:张量输入。一般是[batch, width, length,channel]
    • filters:整数,输出空间的维度,可以理解为卷积核(滤波器)的个数
    • kernel_size:2个整数或元组/列表,指定2D卷积窗口的高度和宽度。可以是单个整数,以指定所有空间维度的相同值。
    • strides:2个整数或元组/列表,指定卷积沿高度和宽度方向的步幅。可以是单个整数,以指定所有空间维度的相同值。
    • padding:"SAME" or "VALID" (不区分大小写)是否用0填充,
        • SAME用0填充;
        • VALID不使用0填充,舍去不匹配的多余项。
    • data_format:字符串,"channels_last"(默认)或"channels_first"。输入中维度的排序。
        • channels_last:对应于具有形状的输入,(batch, height, width, channels)
        • channels_first:对应于具有形状的输入(batch, channels, height, width)
    • activation:激活函数
    • use_bias:Boolean, 该层是否使用偏差项
    • kernel_initializer:卷积核的初始化
    • bias_initializer:  偏置向量的初始化。如果为None,将使用默认初始值设定项
    • kernel_regularizer:卷积核的正则化项
    • bias_regularizer:  偏置矢量的正则化项
    • activity_regularizer:输出的正则化函数
    • trainable:Boolean,如果True,将变量添加到图collection中
    • name:图层的name
    • reuse:Boolean,是否使用相同名称重用前一层的权重

    返回:

      二维卷积后的张量

    例子:

    import tensorflow as tf 
    
    x = tf.get_variable(name="x", shape=[1, 3, 3, 5], initializer=tf.zeros_initializer)
    x = tf.layers.conv2d(
        x,
        filters=1,                    # 结果的第三个通道是1
        kernel_size=[1, 1],            # 不用管它是多大,都不影响输出的shape
        strides=[1, 1],
        padding='same',
        data_format='channels_last',
        use_bias=True,
        bias_initializer=tf.zeros_initializer())
    
    print(x)            # shape=(1, 3, 3, 1)
    

    解析:

    1. input输入是1张 3*3 大小的图片,图像通道数是5,输入shape=(batch, data_length, data_width, data_channel)
    2. kernel_size卷积核shape是 1*1,数量filters是1strides步长是[1,1],第一维和第二维分别为长度方向和宽度方向的步长 = 1。
    3. 最后输出的shape为[1,3,3,1] 的张量,即得到一个3*3的feature map(batch,长,宽,输出通道数)
    4. 长和宽只和strides有关,最后一个维度 = filters。

    卷积层中的输出大小计算

      设输入图片大小W,Filter大小F*F,步长为S,padding为P,输出图片的大小为N:

    $$N=\frac{W-F+2P}{S}+1$$

      向下取整后再加1。

    在Tensoflow中,Padding有2个选型,'SAME'和'VALID' ,下面举例说明差别:

    如果 Padding='SAME',输出尺寸为: W / S(向上取整)

    import tensorflow as tf
    
    input_image = tf.get_variable(shape=[64, 32, 32, 3], dtype=tf.float32, name="input", initializer=tf.zeros_initializer)
    conv0 = tf.layers.conv2d(input_image, 64, kernel_size=[3, 3], strides=[2, 2], padding='same')  # 32/2=16
    conv1 = tf.layers.conv2d(input_image, 64, kernel_size=[5, 5], strides=[2, 2], padding='same')  
    # kernel_szie不影响输出尺寸
    print(conv0)      # shape=(64, 16, 16, 64)
    print(conv1)      # shape=(64, 16, 16, 64)
    

    如果 Padding='VALID',输出尺寸为:(W - F + 1) / S

    import tensorflow as tf
    
    input_image = tf.get_variable(shape=[64, 32, 32, 3], dtype=tf.float32, name="input", initializer=tf.zeros_initializer)
    conv0 = tf.layers.conv2d(input_image, 64, kernel_size=[3, 3], strides=[2, 2], padding='valid')  # (32-3+1)/2=15
    conv1 = tf.layers.conv2d(input_image, 64, kernel_size=[5, 5], strides=[2, 2], padding='valid')  # (32-5+1)/2=14
    print(conv0)      # shape=(64, 15, 15, 64)
    print(conv1)      # shape=(64, 14, 14, 64)
    

     1x1卷积核的作用,加深一层网络,提取更深特征,数据变维,

    有效卷积(valid)、同维卷积(same)、完全卷积(full)

    a = [1 2 3 4 5]   原数组
    b = [8 7 6]    卷积核数组 kernel

    使用b作为卷积核对a数组做一维卷积运算的过程如下:

    原数组:   0  0  1  2  3  4  5  0  0
    卷积数组: 6  7  8
                6  7  8
                   6  7  8
                      6  7  8
                         6  7  8
                            6  7  8
                               6  7  8
    -------------------------------------
    结果:        44 65  86         有效卷积 (valid)
              23 44 65  86 59      同维卷积 (same)
          8   23 44 65  86 59 30   完全卷积 (full)
    

    参考文献:

    [1] tensorflow官方API tf.layers.conv1d

    [2] tf.layers.conv1d函数解析(一维卷积)

    [3] tf.layer.conv1d、conv2d、conv3d

    [4] tensorflow官方API tf.layers.conv2d

    import tensorflow as tf
    
    # case 2
    input = tf.Variable(tf.random_normal([1, 3, 3, 5]))
    filter = tf.Variable(tf.random_normal([1, 1, 5, 1]))
    op2 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')  # (1, 3, 3, 1)
    # case 3
    input = tf.Variable(tf.random_normal([1, 3, 3, 5]))
    filter = tf.Variable(tf.random_normal([3, 3, 5, 1]))
    op3 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')  # (1, 1, 1, 1)
    # case 4
    input = tf.Variable(tf.random_normal([1, 5, 5, 5]))
    filter = tf.Variable(tf.random_normal([3, 3, 5, 1]))
    op4 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')  # (1, 3, 3, 1)
    # case 5
    input = tf.Variable(tf.random_normal([1, 5, 5, 5]))
    filter = tf.Variable(tf.random_normal([3, 3, 5, 1]))
    op5 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')  # (1, 5, 5, 1)
    # case 6
    input = tf.Variable(tf.random_normal([1, 5, 5, 5]))
    filter = tf.Variable(tf.random_normal([3, 3, 5, 7]))
    op6 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')  # (1, 5, 5, 7)
    # case 7
    input = tf.Variable(tf.random_normal([1, 5, 5, 5]))
    filter = tf.Variable(tf.random_normal([3, 3, 5, 7]))
    op7 = tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')  # (1, 3, 3, 7)
    # case 8
    input = tf.Variable(tf.random_normal([10, 5, 5, 5]))
    filter = tf.Variable(tf.random_normal([3, 3, 5, 7]))
    op8 = tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')  # (10, 3, 3, 7)
    
    init = tf.global_variables_initializer()
    with tf.Session() as sess:
        sess.run(init)
        print("case 2")
        print(sess.run(op2).shape)  # (1, 3, 3, 1)
        print("case 3")
        print(sess.run(op3).shape)  # (1, 1, 1, 1)
        print("case 4")
        print(sess.run(op4).shape)  # (1, 3, 3, 1)
        print("case 5")
        print(sess.run(op5).shape)  # (1, 5, 5, 1)
        print("case 6")
        print(sess.run(op6).shape)  # (1, 5, 5, 7)
        print("case 7")
        print(sess.run(op7).shape)  # (1, 3, 3, 7)
        print("case 8")
        print(sess.run(op8).shape)  # (10, 3, 3, 7)
    
    View Code
    展开全文
  • 卷积神经网络详解

    千次阅读 2017-09-24 17:44:16
    卷积 我们在 2 上说话。有两个 的函数 f(x, y) 和 g(x, y) 。所谓 f 和 g 的卷积就是个新的 的函数 c(x, y) 。通过下式得到: 这式子的含义是:遍览从负无穷到正无穷的全部 s 和 t 值,把 g 在 (x-...

    一、卷积

    我们在 2 维上说话。有两个 \mathcal{R}^2\rightarrow \mathcal{R}的函数 f(x, y) 和 g(x, y) 。所谓 f 和 g 的卷积就是一个新的 \mathcal{R}^2\rightarrow \mathcal{R}的函数 c(x, y) 。通过下式得到:


    c(x,y)=\int_{-\infty}^{\infty} \int_{-\infty}^{\infty}f(s,t)\times g(x-s,y-t) \ ds \ dt

    这式子的含义是:遍览从负无穷到正无穷的全部 s 和 t 值,把 g 在 (x-s, y-t) 上的值乘以 f 在 (s, t) 上的值之后再“加和”到一起(积分意义上),得到 c 在 (x, y) 上的值。说白了卷积就是一种“加权求和”:以 f 为权,以 (x, y) 为中心,把 g 距离中心 (-s, -t) 位置上的值乘上 f 在 (s, t) 的值,最后加到一起。把卷积公式写成离散形式就更清楚了:

    C(x,y)=\sum_{t=-\infty}^{\infty}\sum_{s=-\infty}^{\infty}F(s,t)\times G(x-s,y-t) \ \Delta s \ \Delta t=\sum_{t=-\infty}^{\infty}\sum_{s=-\infty}^{\infty}F(s,t)\times G(x-s,y-t)

    第二个等号成立是因为在这里我们每隔单位长度 1 一采样,\Delta s\Delta t都是 1 。可以令 G 表示一幅 100 x 100 大小的灰度图像。G(x, y) 取值 [0,255] 区间内的整数,是图像在 (x, y) 的灰度值。x 和 y 坐标取 [0, 99] ,其它位置上 G 值全取 0 。令 F 在 s 和 t 取 {-1, 0, 1} 的位置为特定值,其他位置全取 0 。F 可以看作是一个 3 x 3 的网格。如图 1.1


    <img src="https://pic3.zhimg.com/v2-8eedb4e4e9d168e8bf792db30434755e_b.png" data-rawwidth="612" data-rawheight="387" class="origin_image zh-lightbox-thumb" width="612" data-original="https://pic3.zhimg.com/v2-8eedb4e4e9d168e8bf792db30434755e_r.png">

    图 1.1



    图 1.1 中 G 每个小格子里的值就是图像在 (x, y) 的灰度值。F 每个小格子里的值就是 F 在 (s, t) 的取值。

    <img src="https://pic4.zhimg.com/v2-5c62242d21e0d6caed39f143bca88553_b.jpg" data-rawwidth="640" data-rawheight="480" class="origin_image zh-lightbox-thumb" width="640" data-original="https://pic4.zhimg.com/v2-5c62242d21e0d6caed39f143bca88553_r.jpg">


    图 1.2

    如图 1.2 所示,将 F 的中心 (0, 0) 对准 G 的 (6, 6) 。把 F 和 G 对应的 9 个位置上各自的值相乘,再将 9 个乘积加在一起,就得到了卷积值 C(6, 6) 。对 G 的每一个位置求 C 值,就得到了一幅新的图像。其中注意三点:

    1. F 是上下左右翻转后再与 G 对准的。因为卷积公式中 F(s, t) 乘上的是 G(x-s, y-t) 。比如 F(-1, -1) 乘上的是 G(7, 7) ;
    2. 如果 F 的所有值之和不等于 1.0,则 C 值有可能不落在 [0, 255] 区间内,那就不是一个合法的图像灰度值。所以如果需要让结果是一幅图像,就得将 F 归一化——令它的所有位置之和等于 1.0 ;
    3. 对于 G 边缘上的点,有可能它的周围位置超出了图像边缘。此时可以把图像边缘之外的值当做 0 。或者只计算其周围都不超边缘的点的 C 。这样计算出来的图像就比原图像小一些。在上例中是小了一圈,如果 F 覆盖范围更大,那么小的圈数更多。

    上述操作其实就是对数字图像进行离散卷积操作,又叫滤波。F 称作卷积核滤波器。不同的滤波器起不同的作用。想象一下,如果 F 的大小是 3 x 3 ,每个格子里的值都是 1/9 。那么滤波就相当于对原图像每一个点计算它周围 3 x 3 范围内 9 个图像点的灰度平均值。这应该是一种模糊。看看效果。

    <img src="https://pic1.zhimg.com/v2-25799d873bc79a8f4d8d9bd2093c0d4c_b.png" data-rawwidth="1216" data-rawheight="386" class="origin_image zh-lightbox-thumb" width="1216" data-original="https://pic1.zhimg.com/v2-25799d873bc79a8f4d8d9bd2093c0d4c_r.png">

    图 1.3

    左图是 lena 灰度原图。中图用 3 x 3 值都为 1/9 的滤波器去滤,得到一个轻微模糊的图像。模糊程度不高是因为滤波器覆盖范围小。右图选取了 9 x 9 值为 1/81 的滤波器,模糊效果就较明显了。滤波器还有许多其他用处。例如下面这个滤波器:

    +----+----+----+
    | -1 |  0 |  1 |
    +----+----+----+
    | -2 |  0 |  2 |
    +----+----+----+
    | -1 |  0 |  1 |
    +----+----+----+
    

    注意该滤波器没有归一化(和不是 1.0 ),故滤出来的值可能不在 [0, 255] 之内。通过减去最小值、除以最大/最小值之差、再乘以 255 并取整,把结果值归一到 [0, 255] 之内,使之成为一幅灰度图像。现在尝试用它来滤 lena 图。


    <img src="https://pic1.zhimg.com/v2-a49e747d5f31e0fd84fc5d49c2a8e870_b.png" data-rawwidth="960" data-rawheight="550" class="origin_image zh-lightbox-thumb" width="960" data-original="https://pic1.zhimg.com/v2-a49e747d5f31e0fd84fc5d49c2a8e870_r.png">

    图 1.4

    该滤波器把图像的边缘检测出来了。它就是 Sobel 算子。边缘检测、图像模糊等等都是人们设计出来的、有专门用途的滤波器。如果搞一个 9 x 9 的随机滤波器,会是什么效果呢?


    <img src="https://pic4.zhimg.com/v2-17235016286dd0a7522a271501adc8cf_b.png" data-rawwidth="1033" data-rawheight="545" class="origin_image zh-lightbox-thumb" width="1033" data-original="https://pic4.zhimg.com/v2-17235016286dd0a7522a271501adc8cf_r.png">

    图 1.5

    如上图,效果也类似于模糊。因为把一个像素点的值用它周围 9 x 9 范围的值随机加权求和,相当于“捣浆糊”。但可以看出模糊得并不润滑。

    这时我们不禁要想,如果不是由人来设计一个滤波器,而是从一个随机滤波器开始,根据某种目标、用某种方法去逐渐调整它,直到它接近我们想要的样子,可行么?这就是卷积神经网络(Convolutional Neural Network, CNN)的思想了。可调整的滤波器是 CNN 的“卷积”那部分;如何调整滤波器则是 CNN 的“神经网络”那部分。



    二、神经网络

    人工神经网络(Neural Network, NN)作为一个计算模型,其历史甚至要早于计算机。 W.S. McCulloch 和 W. Pitts 在四十年代就提出了人工神经元模型。但是单个人工神经元甚至无法计算异或。多个人工神经元连接成网络就可以克服无法计算异或的问题。但是对于这样的网络——多层感知机网络,当时的人们没有发现训练它的方法。人工智能领域的巨擘马文.明斯基认为这个计算模型是没有前途的。直到 7、80 年代,人们发现了训练多层感知机网络的反向传播算法(BP)。BP 的本质是梯度下降算法。多层感知机网络梯度的计算乍看十分繁琐,实则有规律。


    人工神经元就是用一个数学模型简单模拟神经细胞。神经细胞有多个树突和一个伸长的轴突。一个神经元的轴突连接到其他神经元的树突,并向其传导神经脉冲。神经元会根据来自它的若干树突的信号决定是否从其轴突向其他神经元发出神经脉冲。

    <img src="https://pic4.zhimg.com/v2-0ad559470849c1d895a1da8ed88ad89f_b.jpg" data-rawwidth="424" data-rawheight="235" class="origin_image zh-lightbox-thumb" width="424" data-original="https://pic4.zhimg.com/v2-0ad559470849c1d895a1da8ed88ad89f_r.jpg">

    图 2.1

    一个人工神经元就是对生物神经元的数学建模(下文中“神经元”就指人工神经元,“神经网络”就指人工神经网络)。见图 2.2 。

    <img src="https://pic2.zhimg.com/v2-6327a2edb2305783031d79a178b885ad_b.jpg" data-rawwidth="197" data-rawheight="136" class="content_image" width="197">

    图 2.2

    p_{1} ,p_{2} , \ ... \ ,p_{n}是神经元的输入。a 是神经元的输出。神经元将输入p_{1} ,p_{2} , \ ... \ , p_{n}加权求和后再加上偏置值 b ,最后再施加一个函数 f ,即:

    a=f(n)=f \left( \sum_{i=1}^{n}{p_iw_i}+b \right) = f \left( \begin{array}{ccc} (w_1,w_2 \cdots w_n) \end{array} \left( \begin{array}{ccc} p_1 \\ p_2 \\ \vdots \\ p_n\end{array} \right)+b \right) = f \left( \mathcal{W}^T\mathcal{P}+b\right)


    上式最后是这个式子的向量形式。P 是输入向量,W 是权值向量,b 是偏置值标量 。f 称为激活函数( Activation Function )。激活函数可以采用多种形式。图 2.3 展示了一些常用的激活函数。


    <img src="https://pic3.zhimg.com/v2-ddfddf84fd98fa6be6c0af332fd1425e_b.png" data-rawwidth="1000" data-rawheight="1000" class="origin_image zh-lightbox-thumb" width="1000" data-original="https://pic3.zhimg.com/v2-ddfddf84fd98fa6be6c0af332fd1425e_r.png">

    图 2.3

    这是单个神经元的定义。神经网络就是把许多这样的神经元连接成一个网络:一个神经元的输出作为另一个神经元的输入。神经网络可以有多种多样的拓扑结构。其中最简单的就是“多层全连接前向神经网络”。它的输入连接到网络第一层的每个神经元。前一层的每个神经元的输出连接到下一层每个神经元的输入。最后一层神经元的输出就是整个神经网络的输出。

    图 2.4 是一个三层神经网络。它接受 10 个输入,也就是一个 10 元向量。第一层和第二层各有 12 个神经元。最后一层有 6 个神经元,就是说这个神经网络输出一个 6 元向量。神经网络最后一层称为输出层,中间的层称为隐藏层。

    <img src="https://pic2.zhimg.com/v2-432b807d4485f0c2d78071371b78d1ad_b.jpg" data-rawwidth="660" data-rawheight="645" class="origin_image zh-lightbox-thumb" width="660" data-original="https://pic2.zhimg.com/v2-432b807d4485f0c2d78071371b78d1ad_r.jpg">

    图 2.4

    整个神经网络的计算可以用矩阵式给出。我们给出神经网络单层的式子。每层的神经元个数不一样,输入/输出维度也就不一样,计算式中的矩阵和向量的行列数也就不一样,但形式是一致的。假设我们考虑的这一层是第 i 层。它接受 m 个输入,拥有 n 个神经元( n 个输出),那么这一层的计算如下式所示:

    \mathcal{O}^i=\left(\begin{array}{ccc} o_1^{i} \\ \vdots \\ o_n^{i} \end{array}\right)=f\left(\left(\begin{array}{ccc} w_{11}^i & \cdots & w_{1m}^i\\ \vdots & \ddots & \vdots\\ w_{n1}^i & \cdots & w_{nm} ^i \end{array}\right) \left(\begin{array}{ccc} o_1^{i-1} \\ \vdots \\ o_m^{i-1} \end{array}\right) +\left(\begin{array}{ccc} b_1^{i} \\ \vdots \\ b_n^{i} \end{array}\right)\right)

    上标 i 表示第 i 层。 \mathcal{O}^i是输出向量,n 元,因为第 i 层有 n 个神经元。第 i 层的输入,即第 i-1 层的输出,是 m 元向量。权值矩阵 W 是 n x m 矩阵:n 个神经元,每个神经元有 m 个权值。W 乘以第 i - 1 层输出的 m 向量,得到一个 n 向量,加上 n 元偏置向量 b ,再对结果的每一个元素施以激活函数 f ,最终得到第 i 层的 n 元输出向量。

    若不嫌繁琐,可以将第 i - 1 层的输出也展开,最终能写出一个巨大的式子。它就是整个全连接前向神经网络的计算式。可以看出整个神经网络其实就是一个向量到向量的函数。至于它是什么函数,就取决于网络拓扑结构和每一个神经元的权值和偏置值。如果随机给出权值和偏置值,那么这个神经网络是无用的。我们想要的是有用的神经网络。它应该表现出我们想要的行为。

    要达到这个目的,首先准备一个从目标函数采样的包含若干“输入-输出对”的集合——训练集。把训练集的输入送给神经网络,得到的输出肯定不是正确的输出。因为一开始这个神经网络的行为是随机的。

    把一个训练样本输入给神经网络,计算输出与目标输出的(向量)差的模平方(自己与自己的内积)。再把全部 n 个样本的差的模平方求平均,得到 e :

    e=\frac{1}{2n} \sum_{i=1}^{n} ||o_i^{real}-o_i^{output}||^2

    e 称为均方误差 mse 。全部输出向量和目标输出向量之间的距离(差的模)越小,则 e 越小。e 越小则神经网络的行为与想要的行为越接近。

    目标是使 e 变小。在这里 e 可以看做是全体权值和偏置值的一个函数。这就成为了一个无约束优化问题。如果能找到一个全局最小点,e 值在可接受的范围内,就可以认为这个神经网络训练好了。它能够很好地拟合目标函数。这里待优化的函数也可以是 mse 外的其他函数,统称 Cost Function,都可以用 e 表示。

    经典的神经网络的训练算法是反向传播算法(Back Propagation, BP)。BP 算法属于优化理论中的梯度下降法(Gradient Descend)。将误差 e 作为全部权值和全部偏置值的函数。算法的目的是在自变量空间内找到 e 的全局极小点。

    首先随机初始化全体权值和全体偏置值,之后在自变量空间中沿误差函数 e 在该点的梯度方向的反方向前进一个步长。梯度的反方向上函数方向导数最小,函数值下降最快。步长称为学习速率(Learning Rate, LR)。如此反复迭代,最终(至少是期望)解运动到误差曲面的全局最小点(请参考专栏文章:神经网络之梯度下降与反向传播(上))。


    图 2.5 是用 matlab 训练一个极简单的神经网络。它只有单输入单输出。输入层有两个神经元,输出层有一个神经元。整个网络有 4 个权值加 3 个偏置。图中展示了固定其他权值,只把第一层第一个神经元的权值w_{(1,1)}^1和偏置b_1^1做自变量时候的 e 曲面,以及随着算法迭代,解的运动轨迹。

    <img src="https://pic1.zhimg.com/v2-813599ed434b3feaf8ef75fa92f45e70_b.jpg" data-rawwidth="499" data-rawheight="477" class="origin_image zh-lightbox-thumb" width="499" data-original="https://pic1.zhimg.com/v2-813599ed434b3feaf8ef75fa92f45e70_r.jpg">


    图 2.5

    最终算法没有收敛到全局最优解(红 +)。但是解已经运动到了一个峡谷的底部。由于底部过于平缓,解“走不动”了。所得解比最优也差不到哪去。

    对于一个稍复杂的神经网络,e 对权值和偏置值的函数是一个复杂的函数。求梯度需要计算 e 对每一个权值和偏置值的偏导数。所幸的是求偏导的公式不会因为这个权值或偏置值距离输出层越远而越复杂。对于每个神经元可以计算一个值 delta ,称“局部误差”或“灵敏度”。得到了每个神经元的 delta 就很容易计算 e 对任何一个权值或偏执值的偏导数。


    计算某神经元的 delta 用到该神经元激活函数的导函数,对于输出层用到输出与目标输出的差;对于隐藏层用到下一层各神经元的 delta 。每个神经元将其 delta 传递给前一层的各神经元。前一层的各神经元收集后一层的神经元的 delta 计算自己的 delta 。这就是“反向传播”名称的由来——“局部误差”或“灵敏度” delta 沿着反向向前传,逐层计算所有权值和偏置值的偏导数,最终得到梯度。详细推导可参考书籍[1]第八章、[2]第十一章、[3]第四章、[4]第三章或[5]第十一章(或参考专栏文章:神经网络之梯度下降与反向传播(下))。

    梯度下降法有很多变体。通过调整学习速率 LR 可以提高收敛速度;通过增加冲量可以避免陷入局部最优点以及减少震荡。还可以每一次不计算全部样本的 e ,而是随机取一部分样本,根据它们的 e 更新权值。梯度下降是基于误差函数的一阶性质。还有其他方法基于二阶性质进行优化,比如牛顿法等等。优化作为一门应用数学学科是机器学习的一个重要理论基础,在理论和实现上均有众多结论和方法。参考[1]。




    三、卷积神经网络

    现在把卷积滤波器和神经网络两个思想结合起来。卷积滤波器无非就是一套权值。而神经网络也可以有(除全连接外的)其它拓扑结构。可以构造如图 3.1 所示意的神经网络。

    <img src="https://pic4.zhimg.com/v2-32dfed0f256a990d59d1ca5860dd0a3b_b.jpg" data-rawwidth="480" data-rawheight="501" class="origin_image zh-lightbox-thumb" width="480" data-original="https://pic4.zhimg.com/v2-32dfed0f256a990d59d1ca5860dd0a3b_r.jpg">

    图 3.1

    该神经网络接受 n x n 个输入,产生 n x n 个输出。图中左边的平面包含 n x n 个格子,每个格子中是一个 [0, 255] 的整数值。它就是输入图像,也是这个神经网络的输入。右边的平面也是 n x n 个格子,每个格子是一个神经元。每个神经元连接到输入上它对应位置周围 3 x 3 范围内的值。每个连接有一个权值。所有神经元都如此连接(图中只画了一个,出了输入图像边缘的连接就认为连接到常数 0 )。右边层的每个神经元将与它连接的 3 x 3 个输入的值乘上连接权重并加和,得到该神经元的输出。n x n 个神经元的输出就是该神经网络的输出。

    这个神经网络有两点与全连接神经网络不同。首先它不是全连接的。右层的神经元并非连接上全部输入,而是只连接了一部分。这里的一部分就是输入图像的一个局部区域。我们常听说 CNN 能够把握图像局部特征就是这个意思。这样一来权值少了很多,因为连接少了。权值其实还更少,因为每一个神经元的 9 个权值都是和其他神经元共享的。全部 n x n 个神经元都用这共同的一组 9 个权值,并且不要偏置值。那么这个神经网络其实一共只有 9 个参数需要调整。

    看了第一节的同学们都看出来了,这个神经网络所进行的计算不就是一个卷积滤波器么?只不过卷积核的参数未定,需要我们去训练——它是一个“可训练滤波器”。这个神经网络其实就是一个只有一个卷积层、且该卷积层只有一个滤波器(通道)的 CNN 。


    试着用 Sobel 算子滤出来的图片作为目标值去训练这个神经网络。给神经网络的输入是灰度 lena 图,目标输出是经过 Sobel 算子滤波的 lena 图,见图 1.4 。这唯一的一对输入输出图片就构成了训练集。神经网络权值随机初始化,训练 2000 轮。如图 3.7 。


    <img src="https://pic3.zhimg.com/v2-eed01c490ceeefc3a19663c635fe3ec6_b.jpg" data-rawwidth="825" data-rawheight="622" class="origin_image zh-lightbox-thumb" width="825" data-original="https://pic3.zhimg.com/v2-eed01c490ceeefc3a19663c635fe3ec6_r.jpg">

    图 3.2



    从左上到右下依次为:初始随机滤波器输出、每个 200 轮训练后的滤波器输出( 10 幅)、最后一幅是 Sobel 算子的输出,也就是用作训练的目标图像。可以看到经过最初 200 轮后,神经网络的输出就已经和 Sobel 算子的输出看不出什么差别了。后面那些轮的输出基本一样。输入与输出的均方误差 mse 随着训练轮次的变化。如图 3.3 。


    <img src="https://pic2.zhimg.com/v2-90f9bb1494105cf270a33bb9a8189de9_b.jpg" data-rawwidth="640" data-rawheight="480" class="origin_image zh-lightbox-thumb" width="640" data-original="https://pic2.zhimg.com/v2-90f9bb1494105cf270a33bb9a8189de9_r.jpg">

    图 3.3



    1500 轮过后,mse 基本就是 0 了。训练完成后网络的权值是:

    +-------+--------+--------+
    | 1.29  |  0.04  |  -1.31 |
    +-------+--------+--------+
    | 1.43  |  0.01  |  -1.45 |
    +-------+--------+--------+
    | 1.34  |  -0.07 |  -1.28 |
    +-------+--------+--------+
    

    与 Sobel 算子比较一下:

    +----+----+----+
    | -1 |  0 |  1 |
    +----+----+----+
    | -2 |  0 |  2 |
    +----+----+----+
    | -1 |  0 |  1 |
    +----+----+----+
    

    注意训练出来的滤波器负数列在右侧而不是左侧。因为计算卷积是把滤波器上下左右翻转反着扣上去的。这并不重要,本质是相同的。关键是一正列、一负列,中间零值列。非零值列三个值之比近似 1:2:1 。我们得到的就是一个近似的 Sobel 算子。我们以训练神经网络的方式把一个随机滤波器训练成了 Sobel 算子。这就是优化的魔力(代码见本文最后)。

    在 CNN 中,这样的滤波器层叫做卷积层。一个卷积层可以有多个滤波器,每一个叫做一个 channel 。图像是二维信号。信号也可以是其他维度的,比如一维、三维乃至更高维度。那么滤波器相应的也有各种维度。回到二维图像的例子,实际上一个卷积层面对的是多个 channel 的 “一摞” 二维图像。比如一幅 100 x 100 大小的彩色图就会有 RGB 三个 channel ,其数据维度是 3 x 100 x 100 。那么直接连接彩色图像输入的卷积层面对的是 3 x 100 x 100 的数据,这时它的滤波器是 3 维度,第一维等于输入 channel 数(这里是 3)。第 2、3 维度是指定的滤波器大小,例如 5 x 5 。卷积层把输入的多 channel 的一摞二维图像用三维滤波器滤出一幅二维图像。假如这层有 32 个滤波器,那么这层输出 32 个 channel ,每个 channel 是一个二维图像。

    激活函数构成 CNN 的一种层——激活层,这样的层没有可训练的参数。它为输入施加激活函数,例如 Sigmoid 、Tanh 等。


    还有一种层叫做 Pooling 层(池化层)。它也没有参数,起到降维的作用。将输入切分成不重叠的一些 n x n 区域。每一个区域就包含 n x n 个值。从这 n x n 个值计算出一个值。计算方法可以是求平均、取最大等等。假设 n = 2,那么 4 个输入变成一个输出。输出图像就是输入图像的 1/4 大小。若把 2 维的层展平成一维向量,后面可再连接一个全连接前向神经网络。

    通过把这些组件进行组合就得到了一个 CNN 。它直接以原始图像为输入,以最终的回归或分类问题的结论为输出,内部兼有滤波图像处理和函数拟合,所有参数放在一起训练。这就是卷积神经网络。



    四、举个栗子

    手写数字识别。数据集中一共有 42000 个 28 x 28 的手写数字灰度图片。十个数字( 0~9 )的样本数量大致相等。为减少训练时间,随机抽取其中 10000 个。图 4.1 展示其中一部分。

    <img src="https://pic4.zhimg.com/v2-a42b31aa4937c0893489f7f2d51b04e7_b.png" data-rawwidth="800" data-rawheight="550" class="origin_image zh-lightbox-thumb" width="800" data-original="https://pic4.zhimg.com/v2-a42b31aa4937c0893489f7f2d51b04e7_r.png">

    图 4.1



    将样本集合的 75% 用作训练,剩下的 25% 用作测试。构造一个结构如图 4.2 的 CNN 。

    <img src="https://pic4.zhimg.com/v2-1140147561b6764e36691d2fbd894eef_b.png" data-rawwidth="568" data-rawheight="1043" class="origin_image zh-lightbox-thumb" width="568" data-original="https://pic4.zhimg.com/v2-1140147561b6764e36691d2fbd894eef_r.png">


    图 4.2



    该 CNN 共有 9 层(不包括输入层)。它接受 784 元向量作为输入,就是一幅 28 x 28 的灰度图片。并没有将图片先变形成 28 x 28 再输入,因为在 CNN 的第一层放了一个 reshape 层。该层负责将 784 元的输入向量变形成 1 x 28 x 28 的阵列。最开始那个 1 x 表示只有一个通道 ,因为这是灰度图像。如果是彩色图像,就有 RGB 三个通道 。

    接下来放一个卷积层。它包含 32 个 3 x 3 的滤波器,所以它的输出维度是 32 x 28 x 28 。32 个滤波器搞出来 32 幅图像(通道),每个都是 28 x 28 大小。后续一个 2 x 2 的取平均值 Pooling 层把维度减小一半:32 x 14 x 14 。


    接着是第二个卷积层。它包含 64 个 32 x 3 x 3 的滤波器。它的输出维度是 64 x 14 x 14 。注意该卷积层的输入是 32 个 channel ,每个 14 x 14 大小。可以看作 32 x 14 x 14 的一个 3 维输入。该层的滤波器是 32 x 3 x 3 的一个 3 维滤波器。该层的输出维度是 64 x 14 x 14 。后面再续一个 2 x 2 的取平均值 Pooling 层,输出维度:64 x 7 x 7 。


    接着是一个展平层,没有运算也没有参数,只变化一下数据形状:把 64 x 7 x 7 展平成了 3136 元向量。该 3136 元向量送给后面一个三层的全连接神经网络。该网络的结构是 1000 x 1000 x 10 。两个隐藏层各有 1000 个神经元,最后的输出层有 10 个神经元,代表 10 个数字。假如第六个输出为 1 ,其余输出为 0 ,就表示网络判定这个手写数字为 “5”(数字 “0” 占第一个输出,所以 “5” 占第六个输出)。数字 “5” 就编码成了:

    \left( \begin{array}{ccc} 0\\0\\0\\0\\0\\1\\0\\0\\0\\0 \end{array}\right)

    训练集和测试集的数字标签都这么编码( one-hot 编码)。

    全连接神经网络的隐藏层的激活函数采用 Sigmoid ,输出层的激活函数采用 Linear 。误差函数采用均方误差 mse 。优化算法采用随机梯度下降 SGD 。SGD 是梯度下降的一个变体。它并不是用全体样本计算 e 的梯度,而是每次迭代使用随机选择的一部分样本来计算。学习速率 LR 初始为 0.01 ,每次迭代以 1e-6 的比例衰减。以 0.9 为参数设置冲量。训练过程持续 10 轮( epoch )。注意这里 10 轮不是指当前解在解空间只运动 10 步。一轮是指全部 7500 个训练样本都送进网络迭代一次。每次权值更新以 32 个样本为一个 batch 提交给算法。

    图 4.3 展示了随着训练进行,mse 以及分类正确率( accuracy )的变化情况( 横坐标取了 log )。

    <img src="https://pic3.zhimg.com/v2-3bd1b581609ab43ab1ca250198e7eafe_b.png" data-rawwidth="640" data-rawheight="480" class="origin_image zh-lightbox-thumb" width="640" data-original="https://pic3.zhimg.com/v2-3bd1b581609ab43ab1ca250198e7eafe_r.png">


    图 4.3



    该 CNN 在测试集上的正确率( accuracy )是 96.12%,各数字的准确率( precision ) / 召回率( recall )/ f1-score 如下:


                precision    recall  f1-score   support
    
              0       0.96      0.98      0.97       252
              1       0.99      0.99      0.99       281
              2       0.98      0.94      0.96       240
              3       0.97      0.95      0.96       258
              4       0.96      0.92      0.94       239
              5       0.98      0.95      0.97       219
              6       0.96      0.99      0.97       273
              7       0.97      0.97      0.97       259
              8       0.92      0.96      0.94       231
              9       0.91      0.97      0.94       248
    
    avg / total       0.96      0.96      0.96      2500
    


    训练完成神经网络后,最有趣的是将其内部权值以某种方式展现出来。看着那些神秘的、不明所以的连接强度最后竟产生表观上有意义的行为,不由让我们联想起大脑中的神经元连接竟构成了我们的记忆、人格、情感 ... 引人遐思。

    在 CNN 上就更适合做这种事情。因为卷积层训练出来的是滤波器。用这些滤波器把输入图像滤一滤,看看 CNN 到底“看到”了什么。图 4.4 是该 CNN 第一卷积层对一个手写数字 “5” 的 32 个输出。

    <img src="https://pic4.zhimg.com/v2-b53c7213146bfd6c7a56c8001ac79533_b.png" data-rawwidth="640" data-rawheight="480" class="origin_image zh-lightbox-thumb" width="640" data-original="https://pic4.zhimg.com/v2-b53c7213146bfd6c7a56c8001ac79533_r.png">

    图 4.4



    接下来看一看第二卷积层输出的 64 幅图像。


    <img src="https://pic1.zhimg.com/v2-e41769699c595e816dca9a36cb021274_b.png" data-rawwidth="640" data-rawheight="480" class="origin_image zh-lightbox-thumb" width="640" data-original="https://pic1.zhimg.com/v2-e41769699c595e816dca9a36cb021274_r.png">

    图 4.5


    这些就是 CNN 经两步滤波后“看到”的信息。现在将展平层的 3136 元输出呈现出来。呈现方式是:“0”~“9” 十个数字各取 100 个(共 1000 个),将对每一个样本的输出作为一行,得到一副 1000 x 3136 大小的图像,根据数值用伪彩色呈现出来。如图 4.6 。


    <img src="https://pic3.zhimg.com/v2-0bb59e1fdc1975cf801820680b199272_b.png" data-rawwidth="1130" data-rawheight="570" class="origin_image zh-lightbox-thumb" width="1130" data-original="https://pic3.zhimg.com/v2-0bb59e1fdc1975cf801820680b199272_r.png">

    图 4.6



    是否能从中看到 10 个条带,每个条带对应同一个数字的 100 个样本?再把两个全连接层的输出以同样的方式显示出来,是两个 1000 x 1000 的伪彩色图。如图 4.7 。


    <img src="https://pic1.zhimg.com/v2-5a93f71cbef5a27ff5f489f525a98d54_b.png" data-rawwidth="903" data-rawheight="563" class="origin_image zh-lightbox-thumb" width="903" data-original="https://pic1.zhimg.com/v2-5a93f71cbef5a27ff5f489f525a98d54_r.png">

    图 4.7



    经过各卷积层、采样层和全连接层,信息表示的抽象程度逐层提高。CNN 就这样“认出”了手写数字。多层的 CNN 逐层提高了“逻辑深度”,这就是 “Deep Learning” 的含义。

    最后把代码附上。CNN 实现使用的是 keras 库。数据集来自 kaggle :这里

    import pandas as pd
    from keras.models import Sequential
    from keras.layers import Dense, Flatten, Reshape, AveragePooling2D, Convolution2D, Activation
    from keras.utils.np_utils import to_categorical
    from keras.utils.visualize_util import plot
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import classification_report, accuracy_score, confusion_matrix
    from keras.callbacks import Callback
    from keras.optimizers import SGD
    
    
    class LossHistory(Callback):
        def __init__(self):
            Callback.__init__(self)
            self.losses = []
            self.accuracies = []
    
        def on_train_begin(self, logs=None):
            pass
    
        def on_batch_end(self, batch, logs=None):
            self.losses.append(logs.get('loss'))
            self.accuracies.append(logs.get('acc'))
    
    
    history = LossHistory()
    
    data = pd.read_csv("train.csv")
    data = data.sample(n=10000, replace=False)
    digits = data[data.columns.values[1:]].values
    labels = data.label.values
    
    train_digits, test_digits, train_labels, test_labels = train_test_split(digits, labels)
    
    train_labels_one_hot = to_categorical(train_labels)
    test_labels_one_hot = to_categorical(test_labels)
    
    model = Sequential()
    model.add(Reshape(target_shape=(1, 28, 28), input_shape=(784,)))
    model.add(
        Convolution2D(nb_filter=32, nb_row=3, nb_col=3, dim_ordering="th", border_mode="same", bias=False, init="uniform"))
    model.add(AveragePooling2D(pool_size=(2, 2), dim_ordering="th"))
    model.add(
        Convolution2D(nb_filter=64, nb_row=3, nb_col=3, dim_ordering="th", border_mode="same", bias=False, init="uniform"))
    model.add(AveragePooling2D(pool_size=(2, 2), dim_ordering="th"))
    model.add(Flatten())
    model.add(Dense(output_dim=1000, activation="sigmoid"))
    model.add(Dense(output_dim=1000, activation="sigmoid"))
    model.add(Dense(output_dim=10, activation="linear"))
    
    with open("digits_model.json", "w") as f:
        f.write(model.to_json())
    
    plot(model, to_file="digits_model.png", show_shapes=True)
    
    opt = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
    model.compile(loss="mse", optimizer=opt, metrics=["accuracy"])
    
    model.fit(train_digits, train_labels_one_hot, batch_size=32, nb_epoch=10, callbacks=[history])
    
    model.save_weights("digits_model_weights.hdf5")
    
    predict_labels = model.predict_classes(test_digits)
    
    print(classification_report(test_labels, predict_labels))
    print(accuracy_score(test_labels, predict_labels))
    print(confusion_matrix(test_labels, predict_labels))
    



    用 lena 图训练 sobel 算子的代码:

    from keras.models import Sequential
    from keras.layers import Convolution2D
    from keras.callbacks import Callback
    from PIL import Image
    import numpy as np
    from scipy.ndimage.filters import convolve
    
    
    class LossHistory(Callback):
        def __init__(self):
            Callback.__init__(self)
            self.losses = []
    
        def on_train_begin(self, logs=None):
            pass
    
        def on_batch_end(self, batch, logs=None):
            self.losses.append(logs.get('loss'))
    
    
    lena = np.array(Image.open("lena.png").convert("L"))
    lena_sobel = np.zeros(lena.shape)
    
    # sobel 算子。
    sobel = np.array([
        [-1, 0, 1],
        [-2, 0, 2],
        [-1, 0, 1]
    ])
    
    # 计算卷积:用 sobel 算子滤波。结果保存在 lena_sobel 中。
    convolve(input=lena, output=lena_sobel, weights=sobel, mode="constant", cval=1.0)
    
    # 将像素值调整到 [0,255] 区间并保存 sobel 算子滤波后的 lena 图。
    lena_tmp = np.uint8((lena_sobel - lena_sobel.min()) * 255 / (lena_sobel.max() - lena_sobel.min()))
    Image.fromarray(lena_tmp).save("lena_sobel.png")
    
    # 将原始 lena 图和 sobel 滤波 lena 图转换成 (1, 1, width, height) 尺寸。第一个 1 表示训练集只有一个样本。第二个 1 表示样本只有一个 channel 。
    X = lena.reshape((1, 1) + lena.shape)
    Y = lena_sobel.reshape((1, 1) + lena_sobel.shape)
    
    # 建一个神经网络模型。
    model = Sequential()
    
    # 只添加一个卷积层。卷积层只有一个滤波器。滤波器尺寸 3x3 。输入维度顺序是 "th" 表示 (channel, width, height) 。输入尺寸是 (channel, width, height) 。不要偏执置。
    model.add(
        Convolution2D(nb_filter=1, nb_row=3, nb_col=3, dim_ordering="th", input_shape=X.shape[1:], border_mode="same",
                      bias=False, init="uniform"))
    
    # 代价函数取 mse 。优化算法取 rmsprop 。
    model.compile(loss="mse", optimizer="rmsprop", metrics=["accuracy"])
    
    history = LossHistory()
    
    # 训练 10 轮,每轮保存一下当前网络输出图像。
    for i in np.arange(0, 10):
        lena_tmp = model.predict(X).reshape(lena.shape)
        lena_tmp = np.uint8((lena_tmp - lena_tmp.min()) * 255 / (lena_tmp.max() - lena_tmp.min()))
        Image.fromarray(lena_tmp).save("lena_sobel_stage_{:d}.png".format(i))
        print("lena_sobel_stage_{:d}.png saved".format(i))
    
        model.fit(X, Y, batch_size=1, nb_epoch=200, verbose=1, callbacks=[history])
        print("Epoch {:d}".format(i + 1))
    
    lena_tmp = model.predict(X).reshape(lena.shape)
    lena_tmp = np.uint8((lena_tmp - lena_tmp.min()) * 255 / (lena_tmp.max() - lena_tmp.min()))
    Image.fromarray(lena_tmp).save("lena_sobel_stage_final.png")
    
    
    
    
    
    
    附上出处https://zhuanlan.zhihu.com/p/25249694。
    
    展开全文
  • 卷积神经网络VGG16详解

    千次阅读 2019-01-06 16:03:30
    2、卷积核设置为3*3*3,通过第一层卷积,变成一个一维数组。 3、下一层为64的卷积层,然后进行池化 4、然后再根据图上的D神经网络进行操作。 5.最后将其转化为4096个神经元的全连接层共有三层,前两层为4096,...
  • 1、卷积神经网络(CNN)张量(图像)的尺寸和参数计算(深度学习) 2、卷积神经网络(3)卷积计算流程 3、卷积神经网络(CNN)之一维卷积、二维卷积、三维卷积详解 4、卷积神经网络的通道数与卷积核数的关系。 ...
  • 文章目录卷积是什么卷积神经网络介绍卷积层--提取局部图片特征扩充--padding,保持卷积后图片的长和宽保持不变池化层---降低维度,降低模型复杂度和计算量全连接层--输出结果二、TensorFlow2代码实现1....
  •  大家可能会疑惑,对于同个分类任务,我们可以用机器学习的算法来做,为什么要用神经网络呢?大家回顾一下,个分类任务,我们在用机器学习算法来做时,首先要明确feature和label,然后把这个数据"灌"...
  • 卷积神经网络(CNN )详解(复习) 1.区别 卷积神经网络和传统神经网络区别 传统神经网络输入是一个向量,一维数据。 卷积神经网络输入的是三维长方体矩阵,HW3,高度 * 宽度 * 3通道,或者行数 * 列数 * 3通道。 ...
  • 卷积神经网络主要由以下5种结构组成: 1. 输入层。 输入层是整个神经网络的输入,在处理图像的卷积神经网络中,它一般代表了一张图片的像素矩阵。比如在下图中,最左侧的三矩阵就可以代表 张图片。其种三...
  • 卷积神经网络CNN

    2019-03-30 15:16:05
    --CNN的输入层的输入格式保留了数据本身的结构,与全连接神经网络一维向量不同 --对于8*8像素的黑白(灰度)图片,CNN的输入是一个8*8的二维神经元 --对于64*64像素RGB彩色图片,CNN的输入层是一个64*64*3的三维...
  • AI 卷积神经网络 CNN

    2019-05-24 18:46:06
    先放放吧,暂时也没有空去仔细写写,就把找到的东西放放。 CNN详解 CNN初探 - FANG_YANG - 博客园 输入层:二向量 基本模块 最容易理解的对卷积(convolution)的解释 - bitcarmanlee的博客 - CSDN博客 ...
  • caffe中卷积计算详解

    千次阅读 2016-11-25 18:41:10
    卷积是卷积神经网络的重要组成部分,消耗整个网络中大量计算资源,理解卷积计算过程,对优化网络结构和简化网络模型非常重要。  正常卷积的实现如下图所示:   非常重要的是:卷积核其实和特征图一样,是...
  • LeNet网络详解

    2021-03-02 17:49:20
    LeNet-5是个较简单的卷积神经网络。下图显示了其结构:输入的二图像,先经过两次卷积层到池化层,再经过全连接层,最后使用softmax分类作为输出层。 LeNet-5 这个网络虽然很小,但是它包含了深度学习的基本...
  • CNN入门详解及TensorFlow实现源码–深度学习笔记卷积神经网络1、简介卷积神经网络种前馈神经网络,它的人工神经元可以响应部分覆盖范围内的周围单元,对于大型图像处理有出色表现。卷积神经网络个或多...
  • LeNet-5出自论文Gradient-Based Learning Applied to Document Recognition,是种用于手写体字符识别的非常高效的卷积神经网络。 LeNet-5是个较简单的卷积神经网络。下图显示了其结构:输入的二图像,先经过...
  • 卷积函数是卷积神经网络(CNN)非常核心和重要的函数,在搭建CNN时经常会用到,因此较为详细和深入的理解卷积函数具有十分重要的意义。tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=...
  • 卷积函数是卷积神经网络(CNN)非常核心和重要的函数,在搭建CNN时经常会用到,因此较为详细和深入的理解卷积函数具有十分重要的意义。1、tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, ...
  • 神经网络模型详讲(14)

    千次阅读 2019-03-18 14:03:54
    、简介 ... ...LeNet-5是个较简单的卷积神经网络。下图显示了其结构:输入的二图像,先经过两次卷积层到池化层,再经过全连接层,最后使用softmax分类作为输出层。关于CNN参见:https://blo...
  • 卷积神经网络中还有个非常重要的结构:过滤器,它作用于层与层之间(卷积层与池化层),决定了怎样对数据进行卷积和池化。下面先直观理解下卷积和池化二维卷积即滤波器的每个格子与滤波器选中数据的格子相乘三维卷积...
  • 该层对二输入进行滑动窗卷积,当使用该层作为第层时,应提供input_shape参数。例如input_shape = (128,128,3)代表128*128的彩色RGB图像(data_format=‘channels_last’) keras.layers.convolutional.Conv2D...

空空如也

空空如也

1 2 3
收藏数 48
精华内容 19
关键字:

一维卷积神经网络详解