精华内容
下载资源
问答
  • 十四、卷积神经网络(1):介绍卷积神经网络

    千次阅读 多人点赞 2017-09-30 12:10:32
    本篇博客介绍在图像分类中常常使用的卷积神经网络。首先由原始的全连接神经网络忽略了图像的空间结构入手,引出了具有空间结构的卷积神经网络;之后介绍卷积神经网络中的三个基本概念,即局部感受野、权值共享和池化...

    本篇博客主要内容参考图书《神经网络与深度学习》,李航博士的《统计学习方法》National Taiwan University (NTU)李宏毅老师的《Machine Learning》的课程,在下文中如果不正确的地方请积极指出。
    如果喜欢请点赞,欢迎评论留言 ! o( ̄▽ ̄)ブ

    欢迎大家在评论区多多留言互动~~~~

    1. 为什么要使用卷积神经网络

      在之前的手写数字分类的例子中,是直接使用全连接神经网络的进行图像分类的。但是仔细推敲,使用全连接层的网络来分类图像是很奇怪的,因为这样的一个网络架构不考虑图像的空间结构。所以一个很直接的考虑就是引入图像的一种空间关系来构建神经网络,也就是这里要介绍的卷积神经网络(CNN)。
      正是由于考虑了空间结构,所以卷积神经网络可以更快的训练,从而获得一个深度的、多层的神经网络,并可以在图像分类上获得较好的结果。

    2. CNN 中的基本概念

      在这里我们将介绍 CNN 中的主要的三个概念,即:局部感受野(local receptive fields),共享权重(shared weights),和池化(pooling)。

    2.1 局部感受野

      对于输入的图像,在这里并不会像之前的全连接神经网络一样按行排列成一个长的向量,而是仍然保持其原有的样子,如下所示


    图1. 卷积神经网络的输入神经元排列方式

    如图1所示为卷积神经网络的输入神经元排列方式,实际上因为输入神经元与像素是一一对应的关系,所以也可以看作是输入的图像。在这里我们不会把每个输入像素连接到每个隐藏神经元。相反,我们只是把输入图像进行小的、局部区域的连接。说的确切一点,第一个隐藏层中的每个神经元会连接到一个输入神经元的一个小区域(例如一5×5个的区域,对应于25个输入像素)。所以对于一个特定的隐藏神经元,我们可能有看起来像图2的连接:


    图2. 卷积神经网络的输入层于隐层的连接方式

    这个输入图像的区域被称为隐藏神经元的局部感受野,它是输入像素上的一个小窗口。每个连接学习一个权重。而隐藏神经元同时也学习一个总的偏置。你可以把这个特定的隐藏神经元看作是在学习分析它的局部感受野。

      我们然后在整个输入图像上交叉移动局部感受野。对于每个局部感受野,在第一个隐藏层中有一个不同的隐藏层神经元。为了正确说明,让我们从左上角开始一个局部感受野:

    然后我们往右一个像素(即一个神经元)移动局部感受野,连接到第二个隐藏神经元:

    如此重复,构建起第一个隐藏层。注意如果我们有一个 28×28 的输入图像,5×5 的局部感受野,那么隐藏层中就会有 24×24 个神经元。在这里每次移动的过程是一个像素,即步长为1,有的时候步长也可以是2。

    2.2 共享权重和偏置

      按照上面的说明过程,对于每一个给定的局部感受野有一个对应的隐层的神经元,比如一个5×5的感受野所对应的隐层的神经元应该具有25个权值和1个偏置。而通过上面的分析可以知道,隐层中共有 24×24 个神经元,所以共有25×24×24 个权值和 24×24 个偏置,但是在卷积神经网络中却不是这样的,因为这样的计算量过大。在这里,对 24×24 个隐藏神经元中的每一个使用相同的权重和偏置,也就是说共用一个 5×5 的权值和 1 个偏置。
      这意味着第一个隐藏层的所有神经元检测完全相同的特征,只是在输入图像的不同位置,这一点与图像处理中的卷积的概念是一致的,我猜测这就它叫卷积神经网络的原因吧。把权重和偏置设想成隐藏神经元可以挑选的东西,例如,在一个特定的局部感受野的垂直边缘。这种能力在图像的其它位置也很可能是有用的。因此,在图像中应用相同的特征检测器是非常有用的。用稍微更抽象的术语,卷积网络能很好地适应图像的平移不变性:例如稍稍移动一幅猫的图像,它仍然是一幅猫的图像。
      因为这个原因,我们有时候把从输入层到隐藏层的映射称为一个特征映射。我们把定义特征映射的权重称为共享权重。我们把以这种方式定义特征映射的偏置称为共享偏置。共享权重和偏置经常被称为一个卷积核或者滤波器
      目前我描述的网络结构只能检测一种局部特征的类型。为了完成图像识别我们需要超过一个的特征映射,所以一个完整的卷积层由几个不同的特征映射组成,如下图所示

    在这个例子中,每个特征映射定义为一个 5×5 共享权重和单个共享偏置的集合。其结果是网络能够检测3种不同的特征,每个特征都在整个图像中可检测。在实际使用的过程中可以使用更过的卷积核。

      共享权重和偏置的一个很大的优点是,它大大减少了参与的卷积网络的参数。

    2.3 池化层

      池化层通常紧接着在卷积层之后使用,简化从卷积层输出的信息。一种常见的池化方法为最大池化方法,它简单地输出其 2×2 输入区域的最大激活值,具体如图6所示


    图6. 最大池化的过程

    注意既然从卷积层有 24×24 个神经元输出,池化后我们得到 12×12 个神经元。同样的对于每一个卷积层的输出都可以进行池化。我们可以把最大值池化看作一种网络询问是否有一个给定的特征在一个图像区域中的哪个地方被发现的方式。然后它扔掉确切的位置信息。直观上,一旦一个特征被发现,它的确切位置并不如它相对于其它特征的大概位置重要。一个很大的好处是,这样可以有很多被更少地混合的特征,所以这有助于减少在以后的层所需的参数的数目。最大值混合并不是用于混合的仅有的技术,另一个常用的方法是L2 混合(L2 pooling)。

    3. 卷积神经网络的总体过程


    图6. 卷积神经网络总体过程

    这个网络从 28×28 个输入神经元开始,这些神经元用于对 MNIST 图像的像素强度进行编码。接着的是一个卷积层,使用一个 5× 5局部感受野和 3 个特征映射。其结果是一个3×24×24 隐藏特征神经元层。下一步是一个最大值池化层,应用于 2×2 区域,遍及3个特征映射,结果是一个 3×12×12 隐藏特征神经元层。网络中最后连接的层是一个全连接层。更确切地说,这一层将最大值池化层的每一个神经元连接到每一个输出神经元,和我们之前章节中使用的相同。

    4. 卷积神经网络的反向传播过程

      我们确实需要对反向传播程序做些修改。原因是我们之前的反向传播的推导是针对全连接层的网络。幸运的是,针对卷积和最大值混合层的推导是简单的。在一个具有全连接层的网络中,反向传播的核心方程是(BP1)–(BP4)。假设我们有这样一个网络,它包含有一个卷积层,一个最大值混合层,和一个全连接的输出层,正如上面讨论的那样。
      具体过程留一个坑,日后来填。

    展开全文
  • 解析卷积神经网络

    2018-08-16 22:22:44
    络,向读者剖析了卷积神经网络的基本部件与工作机理,更重要的是系统性的 介绍了深度卷积神经网络在实践应用方面的细节配置与工程经验。笔者希望本 书“小而精”,避免像某些国外相关书籍一样浅尝辄止的“大而空”。
  • 卷积神经网络.pdf

    2019-06-05 17:29:46
    卷积神经网络(高清版,详细介绍卷积神经网络原理,可编辑内容
  • 卷积神经网络

    千次阅读 多人点赞 2018-04-18 18:47:38
    本文尝试对卷积神经网络(convolutional neural network ,CNN)做一个总结,主要包括以下几部分内容 1、卷积神经网络的动机和基本精神 2、卷积神经网络的原理 3、卷积神经网络的参数和数据的维度 4、使用python...

    本文尝试对卷积神经网络(convolutional neural network ,CNN)做一个总结,主要包括以下几部分内容

    1、卷积神经网络的动机和基本精神

    2、卷积神经网络的原理

    3、卷积神经网络的参数和数据的维度

    4、使用python实现卷积神经网络

    5、经典卷积神经网络

    6、卷积神经网络在NLP中的应用

    7、卷积神经网络实例

    卷积神经网络的动机和基本精神

    卷积神经网络(CNN)最初是为解决图像识别问题设计的,图像数据如果展开成一维,采用全连接神经网络,参数量将会非常大,根据VC理论,很难保证训练误差与泛化误差足够接近,因此非常容易产生过拟合。

    因此,需要根据具体的问题,设定算法偏好来降低模型复杂度(设定先验),提升泛化能力。

    图像数据与其他数据相比,具有以下特点:

    1、图像数据可能又成千上万个像素点,但如果我们希望检查某些小的有意义的特征,比如,如果我们希望检测图像中的鸟嘴,我们并不需要了解整个图像数据,事实上只需要图中红框内很小的一块区域的信息。—-局部连接
    这里写图片描述

    2、相同的特征可能出现在图像的不同区域,如下图所示,鸟嘴特征可能出现在图像的不同区域,因此,可以采用相同的参数取侦查。—-参数共享

    这里写图片描述

    3、将图像数据降采样,大部分时候不会影响我们对图像的理解。
    这里写图片描述

    基于图像数据的前两个特性,提出卷积层,基于图像数据的第三个特点,为了提升效率和减少参数的考虑,提出池化层。为了实现分类或者其他任务,一般还需要全连接层连接到输出,因此一般卷积神经网络主要一下包括三个组件:

    卷积层:实现局部连接和参数共享机制

    池化层 :实现降采样

    全连接层 :用于最终进行分类或其他任务

    卷积层主要执行特征提取工作,后面的全连接层对特征进行组合匹配,并进行分类或其他任务,卷积神经网络将训练与特征提取两个任务同时执行,使其提取的特征更加有效,避免复杂的特征工程工作。接下来尝试说明卷积操作与特征提取的关系,然后再来介绍卷积神经网络。

    卷积与特征提取

    为了说明卷积与特征提取的关系,首先引入卷积积分和傅立叶变换

    傅立叶变换F(ω)=Γ[f(t)]=tallf(t)ejωtdt

    卷积积分f1(t)f2(t)=τallf1(τ)f2(tτ)dτ

    那么则有F(f1(t)f2(t))=tallτall[f1(τ)f2(tτ)dτ]ejωtdt=τallf1(τ)[tallf2(tτ)ejωtdt]dτ=F1(ω)F2(ω)

    上述公式即为时域卷积定理 :(对于二维信号也是一样的),两个信号时间域的卷积为频率域的乘积。

    因此我们可以将卷积与特征提取的工作转换到频率域理解,在频域中,频率越大说明原始信号变化速度越快;频率越小说明原始信号越平缓。因此,频率的大小反应了信号的变化快慢。因此高频分量解释信号的突变部分,而低频分量决定信号的整体形象。对于图像而言,高频分量在某些情况下指图像边缘信息,低频分量代表图像的轮廓信息。因此如果我们要做边缘检测,可以设计一个高通滤波器,将输入信号与该滤波器进行卷积操作,根据上面推导的卷积定理,卷积操作后的结果都为高频分量,即实现边缘检测,当然,我们也可以设计更复杂的滤波器,进行其他特征提取,比如我们可以通过傅立叶算子,提取形状特征,直接通过傅立叶系数获取纹理特征等。

    下面是一些图像的纹理特征,在时间域(左)频率域(右)的不同表现,使用这些算子与输入信号进行卷积操作,即可实现特征提取。

    img

    img

    同一个网络中,卷积层和池化层可以连续重复多次,每一层的卷积层可以有多个不同的卷积核,用于侦查图像中不同的特征,图像由一些基本特征(点,边)构成,因此只要提供足够数量的卷积核,就可以提取各种方向的边和各种形态的点,可以让卷积层抽取丰富而有效的高级特征,每一个卷积核得到的图像就是一类特征的映射,不管图片尺寸如何,由于局部连接参数共享机制,需要训练的权重只跟卷积核的大小和卷积个数相关,我们可以只使用非常少的参数量处理任意大小的图片,每一个卷积核都很小,只提取简单的特征,但可以通过更深的网络组合成更高阶的特征,多层抽象的卷积神经网络表达能力更强,效率更高,相比只使用很少的隐藏层提取高阶特征,可以节省参数,减弱过拟合风险;池化操作的降采样,大大降低存储和计算压力,同时,由于池化操作保留最显著的特征,因此,可以有效提升模型容忍畸变的能力,提高泛化能力。

    Lecun认为:可训练参数的卷积层是一种用少量参数在图像多个位置提取相似特征的有效方式,可以充分利用图像的空间相关性,直接使用像素点则利用不到这些信息

    卷积网络从输入到输出,应该让图片尺寸越来越小,输出同道数逐渐增加,让空间结构简化,将空间信息转化为高阶抽象的特征信息。

    卷积神经网络的成功可以理解为其先验假设与图像处理任务的高度吻合,也要意识到池化操作虽然有许多好处,但其只保留最显著特征,很可能丢失其他次重要的特征。可能这些信息也是非常重要的。

    卷积神经网络(CNN)最初是为解决图像识别问题设计的,现在也可以应用时间序列信号,比如音频信号或文本数据等。

    卷积神经网络原理

    二维卷积运算S(i,j)=(IK)(i,j)=mnI(im)(jn)K(m,n),卷积运算中将核进行了翻转(输入的索引在增大,但是核的索引在减小),将核翻转的唯一目的是实现可交换性,但可交换性在神经网络中不是一个非常中要的性质,因此为了简单,卷积神经网络实际上实现了

    互相关函数S(i,j)=(IK)(i,j)=mnI(i+m)(j+n)K(m,n)

    互相关函数与特征提取 :互相关是信号分析中的概念,表示两个时间序列之间的相关程度,越相关,操作之后,输出值也越大,意味神经元的激活。如果我们将卷积核视为某种特征提取器,如果数据数据中包含与卷积核相似的特征,那么输入数据与卷积核进行卷操作后的输出会很大,因此反过来,如果卷积操作之后神经元被激活,意味着提取到了该特征。

    ​ 理解互相关函数与特征提取的另一个思路是相关定理,上一节通过卷积定理说明了卷积操作与特征提取的关系,事实上互相关也可以采用相同的形式,即相关定理:两信号的互相关函数的傅立叶变换等于其中一个的傅立叶变换乘上另一信号的傅立叶变换的共轭,虽然存在共轭,但是由于参数是学习得到的,这并不影响我们对利用卷积进行特征提取的理解。

    下图说明了卷积的具体操作,filter在图像内滑动,并与滑动到的区域内数据进行元素相乘,并加上偏置(图中未画出),右边区域显示了卷积神经网络与全连接网络的关系,我们可以把卷积神经网络理解为对全连接网络施加了非常强的先验假设:

    1、隐藏层中神经元只与其上一层范围的空间区域(感受域)内神经元相连,感受域之外的权值均为零 –局部相连

    2、隐藏层中每一个独立图像内部神经元参数相同–参数共享

    需要说明的是,虽然卷积层连接只发生在局部空间区域内,但处在更深的层中神经元可以间接的链接到大部分或全部的输入
    这里写图片描述
    这里写图片描述

    真实数据中图片一般都是多通道的(RGB)(多个卷积核也会生成多通道的图像),因此,执行卷积操作的卷积核一定要与输入图片的通道数一致。
    这里写图片描述

    为了提取输入层中的不同特征,需要多个卷积核,每个卷积核与输入进行卷积操作后,在输出层生成一个独立的图像,因此,卷积核数等于输出层的通道数。
    这里写图片描述

    下图说明了池化层的具体操作,在定义的范围内,统计最大值,并作为池化层的输出,没有需要学习的参数,一般采取最大池化,保留最显著特征,平均池化容易引起模糊效应。
    这里写图片描述

    池化操作中,多通道,多卷积核的操作与卷积层类似,这里就不再赘述。

    将经过多层卷积层和池化层后的数据,展平输出到全连接网络,用于分类或其他任务。
    这里写图片描述

    卷积中的参数与维度

    主要参数:

    卷积核大小 :f*f

    卷积步长 :s

    padding : valid,same

    如下图所示,卷积核为黄色filter,其大小为3*3,stride 表示卷积核移动的步长,stride=1 表示卷积核每次移动1格,stride=2表示每次移动两格。
    这里写图片描述

    如下图所示,如果直接执行卷积操作(valid),那么每次执行卷积后,图像都会变小,核越大,减小的越快,无法构建很深的卷积网络。因此,为了保证图像大小,一般会在边界做padding(same)(事实上也是为了保证边界信息向深层传播)。
    这里写图片描述

    假设卷积之前图像大小为nl1nl1,channel 为cl1,stride 为1,核大小为flfl,为了保证卷积的执行,卷积核的通道数应为cl1,因此卷积的维度为flflcl1,卷积核个数为cl

    如果padding为valid(有效),那么执行卷积之后的图像维度为:(nl1fl+1)(nl1fl+1)cl

    如果padding为same,那么执行卷积之后图像的维度为nl1nl1cl,为了保证输出维度,padding 步长应该为:fl12,通常情况下fl取奇数。

    如果stride不为1,那么就无法保证输入输出图像的维度相同,那么此时输出的维度为nl1+2plflsl+1nl1+2plflsl+1cl, 表示向下取整。

    与全连接网络一样,卷积操作还需要添加偏置,并进行非线性激活输出。

    下图是一个简单的卷积的例子,nl1=6,cl1=3,fl=3,cl=2,stride=1,padding选择valid,那么输出图像的维度就为(63+1)(63+1)2=442

    这里写图片描述

    下图是参数维度的一个说明:
    这里写图片描述

    池化层没有需要学习的参数,也不需要padding,维度信息为nHfs+1nWfs+1c

    下图是一个一个卷积神经网络的例子。输入维度为32323,经过两个(卷积层和池化层),最终输出为5516,(图像从宽短,逐渐变得细长)。然后展开成一维网络,并连接到全连接网络。
    这里写图片描述

    卷积神经网络的训练采用梯度下降法。

    使用python 实现卷积神经网络

    整体框架如下所示:
    这里写图片描述

    为了实现卷积网络,需要构建卷积层和池化层:

    卷积层主要包括以下几个模块:

    1、zero padding

    2、convolve window:(实现单个卷积核与图像一小块区域相乘相加,并添加偏置操作)

    3、convolution forward

    4、convolution backward

    池化层主要包括以下几个模块:

    1、pooling forward

    2、Creat mask

    3、Distribute value

    (2,3 用于反向传播时的梯度向前传播)

    4、pooling backward

    首先实现卷积层
    这里写图片描述

    def zero_pad(X, pad):
    """
    Pad with zeros all images of the dataset X. The padding is applied to the height and width of an image, 
    as illustrated in Figure 1.
    
    Argument:
    X -- python numpy array of shape (m, n_H, n_W, n_C) representing a batch of m images
    pad -- integer, amount of padding around each image on vertical and horizontal dimensions
    
    Returns:
    X_pad -- padded image of shape (m, n_H + 2*pad, n_W + 2*pad, n_C)
    """
    
    ### START CODE HERE ### (≈ 1 line)
    X_pad = np.pad(X,((0,0),(pad,pad),(pad,pad),(0,0)),'constant')
    #X: 待填充numpy数组,(before,after)表示对于维度填充个数,constant 表示填充方式,默认constant填充0
    #zero_pad 中只在n_H,n_W 维度上填充,其他维度不填充
    ### END CODE HERE ###
    
    return X_pad
    

    这里写图片描述

    def conv_single_step(a_slice_prev, W, b):
    
    """
    Apply one filter defined by parameters W on a single slice (a_slice_prev) of the output activation 
    of the previous layer.
    
    Arguments:
    a_slice_prev -- slice of input data of shape (f, f, n_C_prev)
    W -- Weight parameters contained in a window - matrix of shape (f, f, n_C_prev)
    b -- Bias parameters contained in a window - matrix of shape (1, 1, 1)
    
    Returns:
    Z -- a scalar value, result of convolving the sliding window (W, b) on a slice x of the input data
    """
    
    ### START CODE HERE ### (≈ 2 lines of code)
    # Element-wise product between a_slice and W. Add bias.
    s = np.multiply(a_slice_prev,W)
    
    # Sum over all entries of the volume s
    Z = np.sum(s)
    # Add bias b to Z. Cast b to a float() so that Z results in a scalar value.
    Z = np.squeeze(np.add(Z,b))
    #去掉维度信息,输出标量值
    ### END CODE HERE ###
    
    return Z
    

    这里写图片描述

    nH=nHprevf+2padstride+1

    nW=nWprevf+2padstride+1

    nC 滤波器个数

    def conv_forward(A_prev, W, b, hparameters):
    """
    Implements the forward propagation for a convolution function
    
    Arguments:
    A_prev -- output activations of the previous layer, numpy array of shape (m, n_H_prev, n_W_prev, n_C_prev)
    W -- Weights, numpy array of shape (f, f, n_C_prev, n_C)
    b -- Biases, numpy array of shape (1, 1, 1, n_C)
    hparameters -- python dictionary containing "stride" and "pad"
    
    Returns:
    Z -- conv output, numpy array of shape (m, n_H, n_W, n_C)
    cache -- cache of values needed for the conv_backward() function
    """
    
    ### START CODE HERE ###
    # Retrieve dimensions from A_prev's shape (≈1 line)  
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    
    # Retrieve dimensions from W's shape (≈1 line)
    (f, f, n_C_prev, n_C) = W.shape
    
    # Retrieve information from "hparameters" (≈2 lines)
    stride = hparameters['stride']
    pad = hparameters['pad']
    
    # Compute the dimensions of the CONV output volume using the formula given above. Hint: use #int() to floor. (≈2 lines)
    n_H = np.floor_divide(n_H_prev - f + 2 * pad  , stride) + 1
    n_W = np.floor_divide(n_W_prev - f + 2 * pad  , stride) + 1
    
    # Initialize the output volume Z with zeros. (≈1 line)
    Z = np.zeros((m,n_H,n_W,n_C))
    
    # Create A_prev_pad by padding A_prev
    A_prev_pad = zero_pad(A_prev,pad)
    
    for i in range(m):                               # loop over the batch of training examples
        a_prev_pad = A_prev_pad[i]                               # Select ith training example's #padded activation
        for h in range(n_H):                           # loop over vertical axis of the output #volume
            for w in range(n_W):                       # loop over horizontal axis of the output #volume
                for c in range(n_C):                   # loop over channels (= #filters) of the #output volume
    
                    # Find the corners of the current "slice" (≈4 lines)
                    vert_start = h * stride
                    vert_end = h * stride + f
                    horiz_start = w * stride
                    horiz_end = w * stride + f
    
                    # Use the corners to define the (3D) slice of a_prev_pad (See Hint above the #cell). (≈1 line)
                    a_slice_prev = a_prev_pad[vert_start:vert_end,horiz_start:horiz_end,:]
    
                    # Convolve the (3D) slice with the correct filter W and bias b, to get back one output neuron. (≈1 line)
                    Z[i, h, w, c] = conv_single_step(a_slice_prev,W[:,:,:,c],b[:,:,:,c])
    
    ### END CODE HERE ###
    
    # Making sure your output shape is correct
    assert(Z.shape == (m, n_H, n_W, n_C))
    
    # Save information in "cache" for the backprop
    cache = (A_prev, W, b, hparameters)
    
    return Z, cache
    

    接下来实现池化层
    这里写图片描述

    这里写图片描述

    def pool_forward(A_prev, hparameters, mode = "max"):
    """
    Implements the forward pass of the pooling layer
    
    Arguments:
    A_prev -- Input data, numpy array of shape (m, n_H_prev, n_W_prev, n_C_prev)
    hparameters -- python dictionary containing "f" and "stride"
    mode -- the pooling mode you would like to use, defined as a string ("max" or "average")
    
    Returns:
    A -- output of the pool layer, a numpy array of shape (m, n_H, n_W, n_C)
    cache -- cache used in the backward pass of the pooling layer, contains the input and hparameters 
    """
    
    # Retrieve dimensions from the input shape
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    
    # Retrieve hyperparameters from "hparameters"
    f = hparameters["f"]
    stride = hparameters["stride"]
    
    # Define the dimensions of the output
    n_H = np.floor_divide(n_H_prev - f  , stride) + 1
    n_W = np.floor_divide(n_W_prev - f   , stride) + 1
    n_C = n_C_prev
    
    # Initialize output matrix A
    A = np.zeros((m, n_H, n_W, n_C))              
    
    ### START CODE HERE ###
    for i in range(m):                         # loop over the training examples
        for h in range(n_H):                     # loop on the vertical axis of the output volume
            for w in range(n_W):                 # loop on the horizontal axis of the output volume
                for c in range (n_C):            # loop over the channels of the output volume
    
                    # Find the corners of the current "slice" (≈4 lines)
                    vert_start = h * stride
                    vert_end = h * stride + f
                    horiz_start = w * stride
                    horiz_end = w * stride + f
    
                    # Use the corners to define the current slice on the ith training example of #A_prev, channel c. (≈1 line)
                    a_prev_slice = A_prev[i,vert_start:vert_end,horiz_start:horiz_end,c]
    
                    # Compute the pooling operation on the slice. Use an if statment to #differentiate the modes. Use np.max/np.mean.
                    if mode == "max":
                        A[i, h, w, c] = np.max(a_prev_slice)
                    elif mode == "average":
                        A[i, h, w, c] = np.mean(a_prev_slice)
    
    ### END CODE HERE ###
    
    # Store the input and hparameters in "cache" for pool_backward()
    cache = (A_prev, hparameters)
    
    # Making sure your output shape is correct
    assert(A.shape == (m, n_H, n_W, n_C))
    
    return A, cache
    

    卷积网络的反向传播

    前向传播

    Z[i,h,w,c]=Aprepad[i,hstride:hstride+f,wstride:wstride+f,:]W[:,:,:,c]+b[:,:,:,c]

    因此反向传播中:

    dAprepad[i,hstride:hstride+f,wstride:wstride+f,:]=c=1nCdZ[i,h,w,c]W[:,:,:,c]

    dW[:,:,:,c]=i=1mh=1nHw=1nWdZ[i,h,w,c]Aprepad[i,hstride:hstride+f,wstride:wstride+f,:]

    db[:,:,:,c]=i=1mh=1nHw=1nWdZ[i,h,w,c]

    def conv_backward(dZ, cache):
    """
    Implement the backward propagation for a convolution function
    
    Arguments:
    dZ -- gradient of the cost with respect to the output of the conv layer (Z), numpy array of shape (m, n_H, n_W, n_C)
    cache -- cache of values needed for the conv_backward(), output of conv_forward()
    
    Returns:
    dA_prev -- gradient of the cost with respect to the input of the conv layer (A_prev),
               numpy array of shape (m, n_H_prev, n_W_prev, n_C_prev)
    dW -- gradient of the cost with respect to the weights of the conv layer (W)
          numpy array of shape (f, f, n_C_prev, n_C)
    db -- gradient of the cost with respect to the biases of the conv layer (b)
          numpy array of shape (1, 1, 1, n_C)
    """
    
    ### START CODE HERE ###
    # Retrieve information from "cache"
    (A_prev, W, b, hparameters) = cache
    
    # Retrieve dimensions from A_prev's shape
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    
    # Retrieve dimensions from W's shape
    (f, f, n_C_prev, n_C) = W.shape
    
    # Retrieve information from "hparameters"
    stride = hparameters['stride']
    pad = hparameters['pad']
    
    # Retrieve dimensions from dZ's shape
    (m, n_H, n_W, n_C) = dZ.shape
    
    # Initialize dA_prev, dW, db with the correct shapes
    dA_prev = np.zeros_like(A_prev)                          
    dW = np.zeros_like(W)
    db = np.zeros_like(b)
    
    # Pad A_prev and dA_prev
    A_prev_pad = zero_pad(A_prev,stride)
    dA_prev_pad = zero_pad(dA_prev,stride)
    
    for i in range(m):                       # loop over the training examples
    
        # select ith training example from A_prev_pad and dA_prev_pad
        a_prev_pad = A_prev_pad[i,:,:,:]
        da_prev_pad = dA_prev_pad[i,:,:,:]
    
        for h in range(n_H):                   # loop over vertical axis of the output volume
            for w in range(n_W):               # loop over horizontal axis of the output volume
                for c in range(n_C):           # loop over the channels of the output volume
    
                    # Find the corners of the current "slice"
                    vert_start = h * stride
                    vert_end = h * stride + f
                    horiz_start = w * stride
                    horiz_end = w * stride + f
    
                    # Use the corners to define the slice from a_prev_pad
                    a_slice = a_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :]
    
                    # Update gradients for the window and the filter's parameters using the code #formulas given above
                    da_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :] += W[:,:,:,c] * dZ[i, h, w, c]
                    dW[:,:,:,c] +=  a_slice * dZ[i,h,w,c]
                    db[:,:,:,c] +=  dZ[i,h,w,c]
    
        # Set the ith training example's dA_prev to the unpaded da_prev_pad (Hint: use X[pad:-pad, #pad:-pad, :])
        dA_prev[i, :, :, :] = dA_prev_pad[i,pad:-pad,pad:-pad,:]
        #保持与前一个A维度一致
    ### END CODE HERE ###
    
    # Making sure your output shape is correct
    assert(dA_prev.shape == (m, n_H_prev, n_W_prev, n_C_prev))
    
    return dA_prev, dW, db
    

    pooling的反向传播

    maxpooling 反向传播 :

    A[i,h,w,c]=np.max(Aprev[i,hstride:hstride+f,wstride:wstride+f,c])

    A[i,h,w,c] 只与(Aprev[i,vertstart:vertend,horizstart:horizend,c])的最大值有关,

    因此,只将梯度传给其最大项即可,

    建立mask,(Aprev[i,vertstart:vertend,horizstart:horizend,c])维度为ff,mask维度也为ff

    使mask中(Aprev[i,vertstart:vertend,horizstart:horizend,c])最大项对应的项为1,其余项为0,

    反向传播:dAprev[i,vertstart:vertend,horizstart:horizend,c])=maskdA[i,h,w,c]

    averagepooling 反向传播 :

    A[i,h,w,c](Aprev[i,vertstart:vertend,horizstart:horizend,c])的平均,因此

    dAprev[i,vertstart:vertend,horizstart:horizend,c])=dA[i,h,w,c]/(ff)

    当f与stride不同时,dAprev[i,vertstart:vertend,horizstart:horizend,c]) 会与多个dA[i,h,w,c]有关,因此,需要全部加起来。

    def create_mask_from_window(x):
    """
    Creates a mask from an input matrix x, to identify the max entry of x.
    
    Arguments:
    x -- Array of shape (f, f)
    
    Returns:
    mask -- Array of the same shape as window, contains a True at the position corresponding to the max entry of x.
    """
    
    ### START CODE HERE ### (≈1 line)
    mask = (x == np.max(x))
    ### END CODE HERE ###
    
    return mask
    
    
    def distribute_value(dz, shape):
    """
    Distributes the input value in the matrix of dimension shape
    
    Arguments:
    dz -- input scalar
    shape -- the shape (n_H, n_W) of the output matrix for which we want to distribute the value of dz
    
    Returns:
    a -- Array of size (n_H, n_W) for which we distributed the value of dz
    """
    
    ### START CODE HERE ###
    # Retrieve dimensions from shape (≈1 line)
    (n_H, n_W) = shape
    
    # Compute the value to distribute on the matrix (≈1 line)
    average = 1.0 / (n_H*n_W)
    
    # Create a matrix where every entry is the "average" value (≈1 line)
    a = dz * np.full((n_H,n_W),average)
    ### END CODE HERE ###
    
    return a
    
    
    def pool_backward(dA, cache, mode = "max"):
    """
    Implements the backward pass of the pooling layer
    
    Arguments:
    dA -- gradient of cost with respect to the output of the pooling layer, same shape as A
    cache -- cache output from the forward pass of the pooling layer, contains the layer's input and hparameters 
    mode -- the pooling mode you would like to use, defined as a string ("max" or "average")
    
    Returns:
    dA_prev -- gradient of cost with respect to the input of the pooling layer, same shape as A_prev
    """
    
    ### START CODE HERE ###
    
    # Retrieve information from cache (≈1 line)
    (A_prev, hparameters) = cache
    
    # Retrieve hyperparameters from "hparameters" (≈2 lines)
    stride = hparameters['stride']
    f = hparameters['f']
    
    # Retrieve dimensions from A_prev's shape and dA's shape (≈2 lines)
    m, n_H_prev, n_W_prev, n_C_prev = A_prev.shape
    m, n_H, n_W, n_C = dA.shape
    # Initialize dA_prev with zeros (≈1 line)
    dA_prev = np.zeros_like(A_prev)
    for i in range(m):                       # loop over the training examples
    
        # select training example from A_prev (≈1 line)
        a_prev = A_prev[i,:,:,:]
    
        for h in range(n_H):                   # loop on the vertical axis
            for w in range(n_W):               # loop on the horizontal axis
                for c in range(n_C):           # loop over the channels (depth)
    
                    # Find the corners of the current "slice" (≈4 lines)
                    vert_start = h * stride
                    vert_end = h * stride + f
                    horiz_start = w *stride 
                    horiz_end = w * stride + f
    
                    # Compute the backward propagation in both modes.
                    if mode == "max":
    
                        # Use the corners and "c" to define the current slice from a_prev (≈1 line)
                        a_prev_slice = a_prev[vert_start:vert_end,horiz_start:horiz_end,c]
                        # Create the mask from a_prev_slice (≈1 line)
                        mask = create_mask_from_window(a_prev_slice)
                        # Set dA_prev to be dA_prev + (the mask multiplied by the correct entry of #dA) (≈1 line)
                        dA_prev[i, vert_start: vert_end, horiz_start: horiz_end, c] += np.multiply(dA[i,h,w,c],mask)
    
                    elif mode == "average":
    
                        # Get the value a from dA (≈1 line)
                        da = dA[i,h,w,c]
                        # Define the shape of the filter as fxf (≈1 line)
                        shape = (f,f)
                        # Distribute it to get the correct slice of dA_prev. i.e. Add the distributed value of da. (≈1 line)
                        dA_prev[i, vert_start: vert_end, horiz_start: horiz_end, c] += distribute_value(da,shape)
    
    ### END CODE ###
    
    # Making sure your output shape is correct
    assert(dA_prev.shape == A_prev.shape)
    
    return dA_prev
    

    经典卷积神经网络

    前边几节介绍了卷积神经网络的基本构件,但如何将这些组件组合起来,形成有效的卷积神经网络依然是一个非常开放的问题,一方面学习经典的,被证实确实有效的神经网络,理解其中的精神,可以非常有效的帮助构建自己的神经网络。另一方面,理解这些网络,并直接将经典的神经网络迁移到自己的应用中,也是一个非常有效的方法。

    因此,下文尝试说明一些经典的卷积神经网络,说明其网络架构,网络设计的思想并尝试用tensorflow和keras实现相关网络。主要包括以下几个网络。

    AlexNet

    VGGNet

    ResNet

    Google Inception Net

    AlexNet :

    AlexNet 是Hinton的学生Alex Krizhevsky 提出的卷积神经网络模型,
    包含5个卷积层和三个全连接层

    在ILSVRC数据集上可达到16.4%的错误率,有6000万的参数,

    AlexNet 确立了深度学习在计算机视觉的统治地位,同时也推动了深度学习在语音识别,自然语言处理,强化学习等领域的拓展,开启了深度学习的时代。

    特点:

    (1)成功使用relu 作为CNN激活函数,成功解决sigmoid梯度消失问题
    (2)训练时使用dropout随机忽略一部分神经元,避免过拟合,主要用在全连接层
    (3)CNN中使用重叠的最大池化,避免平均池化的模糊化效果,使步长比池化核小,这样有覆盖,提升的特征的丰富性
    (4)提出了LRN层,对局部神经元的活动创建竞争机制,使得其中响应比较大的值相对更大,增强模型的泛化能力(不在使用)
    (5)数据增强,截取,翻转等,数据量显著增多,避免过拟合,对RGB图像做PCA,并对主成分增加标准差为0.1的高斯扰动,进一步降低误差率。

    (76)使用CUDA加速卷积神经网络的训练,利用GPU强大的并行计算能力,加速训练

    网络架构如下图所示:

    输入图片尺寸:2272273,

    第一个卷积核尺寸为1111,步长为4,有96个卷积核,

    LRN层(应用不多 )

    33的最大池化层,步长为2

    55的卷积层,步长为1,卷积核数为256

    接3个3*3卷积层,步长为1,padding=same,卷积核数分别为384,384,256

    33的最大池化层,步长为2

    flatten为9216维,接入全连接层,并最终使用softmax输出
    这里写图片描述

    VGGNet:

    是牛津大学计算机视觉组(Visual Geometry Group)和 Google Deepmind 公司研究员一起研发的深度卷积神经网络,探索了卷积神经网络的深度与其性能之间的关系,通过反复堆叠33的小型卷积核和22的最大池化层,VGG构筑了16-19层的卷积神经网络,拓展性很强,泛化性能非常好,VGGNet依然被经常用来提取图像特征,可以作为非常好的初始化权重.

    CONV =3*3 filters,s=1,padding=same

    MAX-POOL =2*2,S=2

    2014在ILSVRC上的准确率达到7.0 %

    VGGNet拥有5段卷积,每一段内有2-3个卷积层,同时每段尾部都会连接一个最大池化层,用来缩小尺寸,每段内卷积数量一样,越往后越多64-128-256-512-512,其中出现多个完全一样的33的卷积层堆叠在一起,两个33卷积核相当于一个55卷积核,3个33卷积核相当于一个77卷积核,感受野相同,但是可以省掉将近一半的参数量,而且3个串联的33的卷积层,比一个77的卷积层有更多的非线性变换(前者可以有3个激活函数),使得CNN特征学习能力更强。

    VGGNet 参数量巨大,约1.38亿,但网络结构非常一致。

    训练时叶采用Multi-Scale 的方法做数据增强,将原始图片缩放到不同尺寸S,然后再随机裁取224*224图片,增加数据量

    重要观点:

    (1) LRN层作用不大
    (2)越深的网络效果越好
    (3)大一些的卷积核可以学习更大的空间特征

    图像缩小比例和信道增加的比例是有规律的

    VGGNet模型虽然比AlexNet多,但反而只需要较少的迭代次数就可以收敛。
    这里写图片描述

    使用tensorflow实现VGGNet:

    定义卷积操作:

    def conv_op(input_op,name,kh,kw,n_out,dh,dw,p) :

    #kh,kw分别为kernel的高和宽,dh和dw分布为步长的高和宽,
    # input:输入tenser  n_out:卷积核数量(输出的同道数),p:参数列表
    n_in = input_op.get_shape()[-1].value
    with tf.name_scope(name) as scope:
        kernel = tf.get_variable(name=scope+'w',
                                 shape=[kh,kw,n_in,n_out],
                                 dtype=tf.float32,
                                 initializer=tf.contrib.layers.xavier_initializer_conv2d())
        conv = tf.nn.conv2d(input_op,kernel,strides=[1,dh,dw,1],padding='SAME')
        bias_init_val =tf.constant(0.0,shape=[n_out],dtype=tf.float32)
        biases = tf.Variable(bias_init_val,trainable=True,name='b')
        activation = tf.nn.relu(tf.nn.bias_add(conv,biases))
        p +=[kernel,biases]
        return activation
    

    def fc_op(input_op,name,n_out,p):

    n_in = input_op.get_shape()[-1].value
    with tf.name_scope(name) as scope:
        kernel = tf.get_variable(name=scope+'w',
                                 shape=[n_in,n_out],
                                 dtype=tf.float32,
                                 initializer=tf.contrib.layers.xavier_initializer())
        biases = tf.Variable(tf.constant(0.1,shape=[n_out],dtype=tf.float32),name='b')
        activation = tf.nn.relu_layer(input_op,kernel,biases,name=scope)
        p +=[kernel,biases]
        return activation
    

    定义网络

    def inference_op(input_op,keep_prob):

    p = []
    
    #第一段
    conv1_1 = conv_op(input_op,name='conv1_1',kh=3,kw=3,n_out=64,dh=1,dw=1,p=p)
    conv1_2 = conv_op(conv1_1,name='conv1_2',kh=3,kw=3,n_out=64,dh=1,dw=1,p=p)
    pool1 = mpool_op(conv1_2,name='pool1',kh=2,kw=2,dh=2,dw=2)
    
    #第二段
    conv2_1 = conv_op(pool1,name='conv2_1',kh=3,kw=3,n_out=128,dh=1,dw=1,p=p)
    conv2_2 = conv_op(conv2_1,name='conv2_2',kh=3,kw=3,n_out=128,dh=1,dw=1,p=p)
    pool2 = mpool_op(conv2_2,name='pool2',kh=2,kw=2,dh=2,dw=2)
    #第三段
    
    conv3_1 = conv_op(pool2,name='conv3_1',kh=3,kw=3,n_out=256,dh=1,dw=1,p=p)
    conv3_2 = conv_op(conv3_1,name='conv3_2',kh=3,kw=3,n_out=256,dh=1,dw=1,p=p)
    conv3_3 = conv_op(conv3_2,name='conv3_3',kh=3,kw=3,n_out=256,dh=1,dw=1,p=p)
    pool3 = mpool_op(conv3_3,name='pool3',kh=2,kw=2,dh=2,dw=2)
    
    #第四段
    conv4_1 = conv_op(pool3,name='conv4_1',kh=3,kw=3,n_out=512,dh=1,dw=1,p=p)
    conv4_2 = conv_op(conv4_1,name='conv4_2',kh=3,kw=3,n_out=512,dh=1,dw=1,p=p)
    conv4_3 = conv_op(conv4_2,name='conv4_3',kh=3,kw=3,n_out=512,dh=1,dw=1,p=p)
    pool4 = mpool_op(conv4_3,name='pool4',kh=2,kw=2,dh=2,dw=2)
    
    #第四段
    conv5_1 = conv_op(pool4,name='conv5_1',kh=3,kw=3,n_out=512,dh=1,dw=1,p=p)
    conv5_2 = conv_op(conv5_1,name='conv5_2',kh=3,kw=3,n_out=512,dh=1,dw=1,p=p)
    conv5_3 = conv_op(conv5_2,name='conv5_3',kh=3,kw=3,n_out=512,dh=1,dw=1,p=p)
    pool5 = mpool_op(conv5_3,name='pool5',kh=2,kw=2,dh=2,dw=2)
    
    shp = pool5.get_shape()
    flattened_shape = shp[1].value * shp[2].value*shp[3].value
    resh1 = tf.reshape(pool5,[-1,flattened_shape],name='resh1')
    
    fc6 = fc_op(resh1,name='fc6',n_out=4096,p=p)
    fc6_drop = tf.nn.dropout(fc6,keep_prob,name='fc6_drop')
    
    fc7 = fc_op(fc6_drop,name='fc7',n_out=4096,p=p)
    fc7_drop = tf.nn.dropout(fc7,keep_prob,name='fc7_drop')
    
    fc8 = fc_op(fc7_drop,name='fc8',n_out=1000,p=p)
    softmax = tf.nn.softmax(fc8)
    predictions = tf.argmax(softmax,1)
    return predictions,softmax,fc8,p
    

    ResNet

    ResNet(Residual Neural Network)是由微软研究院Kaiming He等4名华人提出,通过使用Residual Unit 成功训练152层的神经网络,取得了3.57%的top-5错误率。参数量却比VGGNet低,可以极快的加速超深神经网络的训练,模型准确率也大幅提升。

    ResNet可以算是深度学习中一个里程碑式的突破,真正意义上解决了极深神经网络的训练问题。

    加深网络的深度,可以使网络表示更复杂的模型,可以在更多的水平上进行特征抽象和抽取,但极深网络存在比较严重的长期依赖问题 :前向传播过程中由于信息丢失和损耗等问题,很难保证信息传递的完整性,反向传播时,则由于梯度消失等问题,梯度很难有效向前传播,优化非常困难。因此出现Degradation问题 ,即训练误差随着深度的增加会先降低,继续增加深度,训练误差反而增大的问题。

    ResNet 采用了 skip connection 的思想,直接将输入信息绕道输出,前向传播时,使得后层信息直接获得输入信息,保证信息的完整,反向传播时,梯度直接从深层传到浅层,可以有效缓解梯度消失的问题,使得优化变得容易。

    总结来说就是:ResNet使得信息可以传出去,梯度可以传回来

    吴恩达在课程中的解释主要集中在训练难度和效率 上:如果在一个神经网络中,添加一个skip connection,

    如果激活函数为ReLU,则al+2=acti(zl+2+al)=acti(Wl+2al+1+bl+2+al),只要Wl+2,bl+2为0,那么

    al+2=al,因此全等映射很容易通过学习得到,因此通过skip connection的方式增加网络的深度,并不会增加训练的难度,可以保证网络的性能不会受到影响,可以有效解决Degradation的问题,如果增加的层可以学到一些有意义的信息,就会比全等表现的更好。

    事实上,使用ResNet结构后,可以发现层数不断增加导致的训练集上的误差增大的现象被消除了,随着深度的增加,测试集上的表现也变得更好。
    这里写图片描述

    skip connection :
    这里写图片描述

    zl+1=Wl+1al+bl+1

    al+1=acti(zl+1)

    zl+2=Wl+2al+1+bl+2

    al+2=acti(zl+2+al)

    ship connection 可以有不同的深度,也可以有不用的残差结构 。
    这里写图片描述
    这里写图片描述

    上式最后一项,要执行zl+2al的元素相加,因此,需要保证两项维度一致,如果维度一致,直接相加即可,如果维度不一致,则需要对al进行某些运算,即:

    al+2=acti(zl+2+Wsal),其网络结构如下图所示。
    这里写图片描述

    使用keras建立 ResNet,网络结构如下图所示:
    这里写图片描述

    The details of this ResNet-50 model are:

    • Zero-padding pads the input with a pad of (3,3)

    • Stage 1:

      • The 2D Convolution has 64 filters of shape (7,7) and uses a stride of (2,2). Its name is “conv1”.
      • BatchNorm is applied to the channels axis of the input.
      • MaxPooling uses a (3,3) window and a (2,2) stride.
    • Stage 2:

      • The convolutional block uses three set of filters of size [64,64,256], “f” is 3, “s” is 1 and the block is “a”.
      • The 2 identity blocks use three set of filters of size [64,64,256], “f” is 3 and the blocks are “b” and “c”.
    • Stage 3:

      • The convolutional block uses three set of filters of size [128,128,512], “f” is 3, “s” is 2 and the block is “a”.
      • The 3 identity blocks use three set of filters of size [128,128,512], “f” is 3 and the blocks are “b”, “c” and “d”.
    • Stage 4:

      • The convolutional block uses three set of filters of size [256, 256, 1024], “f” is 3, “s” is 2 and the block is “a”.
      • The 5 identity blocks use three set of filters of size [256, 256, 1024], “f” is 3 and the blocks are “b”, “c”, “d”, “e” and “f”.
    • Stage 5:

      • The convolutional block uses three set of filters of size [512, 512, 2048], “f” is 3, “s” is 2 and the block is “a”.
      • The 2 identity blocks use three set of filters of size [256, 256, 2048], “f” is 3 and the blocks are “b” and “c”.
    • The 2D Average Pooling uses a window of shape (2,2) and its name is “avg_pool”.

    • The flatten doesn’t have any hyperparameters or name.

    • The Fully Connected (Dense) layer reduces its input to the number of classes using a softmax activation. Its name should be 'fc' + str(classes).

      图中 identity blocks 为上图跳过3层的全等层,convolutional block 为figure 所示的结构。

      首先定义identty blocks(3层skip connection),即:al+3=acti(Zl+3+al):

      第一和第三个为步长为1的11卷积,不会改变数据维度,第二个卷积步长为1,padding为same,因此也不会改变数据维度,保证Zl+3yal维度一致。

      def identity_block(X, f, filters, stage, block):

      “””
      Implementation of the identity block as defined in Figure 4

      Arguments:
      X – input tensor of shape (m, n_H_prev, n_W_prev, n_C_prev)
      f – integer, specifying the shape of the middle CONV’s window for the main path
      filters – python list of integers, defining the number of filters in the CONV layers of the main path
      stage – integer, used to name the layers, depending on their position in the network
      block – string/character, used to name the layers, depending on their position in the network

      Returns:
      X – output of the identity block, tensor of shape (n_H, n_W, n_C)
      “”“

      # defining name basis
      conv_name_base = ‘res’ + str(stage) + block + ‘_branch’
      bn_name_base = ‘bn’ + str(stage) + block + ‘_branch’

      # Retrieve Filters
      F1, F2, F3 = filters

      # Save the input value. You’ll need this later to add back to the main path.
      X_shortcut = X

      # First component of main path
      X = Conv2D(filters = F1, kernel_size = (1, 1), strides = (1,1), padding = ‘valid’, name = conv_name_base + ‘2a’, kernel_initializer = glorot_uniform(seed=0))(X)
      X = BatchNormalization(axis = 3, name = bn_name_base + ‘2a’)(X)
      X = Activation(‘relu’)(X)

      ### START CODE HERE ###

      # Second component of main path (≈3 lines)
      X = Conv2D(filters = F2, kernel_size = (f, f), strides = (1,1), padding = ‘same’, name = conv_name_base + ‘2b’, kernel_initializer = glorot_uniform(seed=0))(X)
      X = BatchNormalization(axis=3, name = bn_name_base + ‘2b’)(X)
      X = Activation(‘relu’)(X)

      # Third component of main path (≈2 lines)
      X = Conv2D(filters = F3, kernel_size = (1, 1), strides = (1,1), padding = ‘valid’, name = conv_name_base + ‘2c’, kernel_initializer = glorot_uniform(seed=0))(X)
      X = BatchNormalization(axis=3, name = bn_name_base + ‘2c’)(X)

      # Final step: Add shortcut value to main path, and pass it through a RELU activation (≈2 lines)
      X = layers.add([X, X_shortcut])
      X = Activation(‘relu’)(X)

      ### END CODE HERE ###

      return X
      接下来 定义 convolutional block,即:al+3=acti(Zl+3+Wsal)

      X的第一个卷积与X_short_cut 卷积维度一致,X的第二个和三个卷积,不会改变数据维度,最终可以保证Zl+3Wsal的维度一致。

    def convolutional_block(X, f, filters, stage, block, s = 2):

    """
    Implementation of the convolutional block as defined in Figure 4
    
    Arguments:
    X -- input tensor of shape (m, n_H_prev, n_W_prev, n_C_prev)
    f -- integer, specifying the shape of the middle CONV's window for the main path
    filters -- python list of integers, defining the number of filters in the CONV layers of the main path
    stage -- integer, used to name the layers, depending on their position in the network
    block -- string/character, used to name the layers, depending on their position in the network
    s -- Integer, specifying the stride to be used
    
    Returns:
    X -- output of the convolutional block, tensor of shape (n_H, n_W, n_C)
    """
    
    # defining name basis
    conv_name_base = 'res' + str(stage) + block + '_branch'
    bn_name_base = 'bn' + str(stage) + block + '_branch'
    
    # Retrieve Filters
    F1, F2, F3 = filters
    
    # Save the input value
    X_shortcut = X
    
    
    ##### MAIN PATH #####
    # First component of main path 
    X = Conv2D(F1, (1, 1), strides = (s,s), name = conv_name_base + '2a', padding='valid', kernel_initializer = glorot_uniform(seed=0))(X)
    X = BatchNormalization(axis = 3, name = bn_name_base + '2a')(X)
    X = Activation('relu')(X)
    
    ### START CODE HERE ###
    
    # Second component of main path (≈3 lines)
    X = Conv2D(F2, (f, f), strides = (1, 1), name = conv_name_base + '2b',padding='same', kernel_initializer = glorot_uniform(seed=0))(X)
    X = BatchNormalization(axis = 3, name = bn_name_base + '2b')(X)
    X = Activation('relu')(X)
    
    # Third component of main path (≈2 lines)
    X = Conv2D(F3, (1, 1), strides = (1, 1), name = conv_name_base + '2c',padding='valid', kernel_initializer = glorot_uniform(seed=0))(X)
    X = BatchNormalization(axis = 3, name = bn_name_base + '2c')(X)
    
    ##### SHORTCUT PATH #### (≈2 lines)
    X_shortcut = Conv2D(F3, (1, 1), strides = (s, s), name = conv_name_base + '1',padding='valid', kernel_initializer = glorot_uniform(seed=0))(X_shortcut)
    X_shortcut = BatchNormalization(axis = 3, name = bn_name_base + '1')(X_shortcut)
    
    # Final step: Add shortcut value to main path, and pass it through a RELU activation (≈2 lines)
    X = layers.add([X, X_shortcut])
    X = Activation('relu')(X)
    
    ### END CODE HERE ###
    
    return X
    

    接下来实现完整的50层的ResNet。

    def ResNet50(input_shape = (64, 64, 3), classes = 6):

    """
    Implementation of the popular ResNet50 the following architecture:
    CONV2D -> BATCHNORM -> RELU -> MAXPOOL -> CONVBLOCK -> IDBLOCK*2 -> CONVBLOCK -> IDBLOCK*3
    -> CONVBLOCK -> IDBLOCK*5 -> CONVBLOCK -> IDBLOCK*2 -> AVGPOOL -> TOPLAYER
    Arguments:
    input_shape -- shape of the images of the dataset
    classes -- integer, number of classes
    
    Returns:
    model -- a Model() instance in Keras
    """
    # Define the input as a tensor with shape input_shape
    X_input = Input(shape=input_shape)
    # Zero-Padding
    X = ZeroPadding2D(padding=(3,3))(X_input)
    # Stage 1
    X = Conv2D(filters=64,kernel_size=(7,7),strides=(2,2),name='conv1')(X)
    X = BatchNormalization(axis=3,name='bn1')(X)
    X = Activation('relu')(X)
    X = MaxPooling2D(pool_size=(3,3),strides=(2,2))(X)
    # Stage 2
    X =convolutional_block(X,f=3,filters=[64,64,256],stage=2,block='a',s=1)
    X =identity_block(X,f=3,filters=[64,64,256],stage=2,block='b')
    X =identity_block(X,f=3,filters=[64,64,256],stage=2,block='c')
    ### START CODE HERE ###
    # Stage 3 (≈4 lines)
    # The convolutional block uses three set of filters of size [128,128,512], "f" is 3, "s" is 2 and the block is "a".
    # The 3 identity blocks use three set of filters of size [128,128,512], "f" is 3 and the blocks are "b", "c" and "d".
    X =convolutional_block(X,f=3,filters=[128,128,512],stage=3,block='a')
    X = identity_block(X,f=3,filters=[128,128,512],stage=3,block='b')
    X = identity_block(X,f=3,filters=[128,128,512],stage=3,block='c')
    X = identity_block(X,f=3,filters=[128,128,512],stage=3,block='d')
    # Stage 4 (≈6 lines)
    # The convolutional block uses three set of filters of size [256, 256, 1024], "f" is 3, "s" is 2 and the block is "a".
    # The 5 identity blocks use three set of filters of size [256, 256, 1024], "f" is 3 and the blocks are "b", "c", "d", "e" and "f".
    X =convolutional_block(X,f=3,filters=[256,256,1024],stage=4, block='a')
    X = identity_block(X,f=3,filters=[256,256,1024],stage=4,block='b')
    X = identity_block(X,f=3,filters=[256,256,1024],stage=4,block='c')
    X = identity_block(X,f=3,filters=[256,256,1024],stage=4,block='d')
    X = identity_block(X,f=3,filters=[256,256,1024],stage=4,block='e')
    X = identity_block(X,f=3,filters=[256,256,1024],stage=4,block='f')
    # Stage 5 (≈3 lines)
    # The convolutional block uses three set of filters of size [512, 512, 2048], "f" is 3, "s" is 2 and the block is "a".
    # The 2 identity blocks use three set of filters of size [256, 256, 2048], "f" is 3 and the blocks are "b" and "c".
    X =convolutional_block(X,f=3,filters=[512,512,2048],stage=5,block='a')
    X = identity_block(X,f=3,filters=[512,512,2048],stage=5,block='b')
    X = identity_block(X,f=3,filters=[512,512,2048],stage=5,block='c') 
    # filters should be [256, 256, 2048], but it fail to be graded. Use [512, 512, 2048] to pass the grading
    # AVGPOOL (≈1 line). Use "X = AveragePooling2D(...)(X)"
    # The 2D Average Pooling uses a window of shape (2,2) and its name is "avg_pool".
    X = AveragePooling2D(pool_size=(2,2),name='avg_pool')(X)
    X = Flatten()(X)
    X = Dense(classes,activation='softmax',name='fc'+ str(classes))(X)
    ### END CODE HERE ###
    # output layer
    model = Model(inputs = X_input, outputs = X, name='ResNet50')
    # Create model
    return model
    

    Google Inception Net

    Google Inception Net 首次出现在ILSVRC 2014的比赛中,并以较大优势取得了第一名,top-5错误率为6.67%。Inception V1 有22层,但计算量只有15亿次浮点运算,参数量只有500万。

    Inception可以很深但参数量却只有500万,主要有两个原因:

    1、去除全连接层,用平均池化层替代(减少过拟合,加速训练)

    2、Inception Net 网络架构设计精巧,提高了参数的利用率。

    人类神经元的连接时稀疏的,因此研究者认为大型神经网络的链接方式也应该是稀疏的,稀疏结构可以有效减少参数量,减弱过拟合(卷积神经网络本身就是全连接网络的稀疏结构)。Inception Net 的主要目标就是找到最优的稀疏结构单元(Inception Module)。

    一个“好”的稀疏结构,应该把相关性高的一簇神经元连接在一起,在普通数据集中,可能需要对神经元节点进行聚类,但图像数据中,天然的就是邻近区域数据相关性最高,极端情况,同一个空间位置,不同的通道内的特征相关性最高,而11的卷积就是同一空间,不同通道内的特征组合在一起的有效工具。另外33,55区域,不同同道间的数据相关性也很强,因此也可以被连接在一起(使用33,55)卷积,这样做,也可以提供更多的多样性,提升泛化能力。事实上当直接使用一个33,或55网络时,参数量可能非常大,使用11的卷积压缩通道数,然后再使用3355的卷积可以非常显著的减少参数量。因此,首先介绍11卷积网络。

    11的卷积 又被称为Net in Net

    对图像进行11的卷积就是用11的卷积核与图像中每一个空间位置(同一个height和weight位置)不同道之通间的数据进行元素相乘相加,然后加上偏置,经过非线性激活函数。如下图所示,11卷积相当于对图像每个位置不同同道之间的特征,建立全连接网络(不同空间位置共享同一组参数),因此11的卷积也被称作Net in Net
    这里写图片描述

    卷积神经网络每一个通道代表某一类特征,11卷积将不同同道之间的特征组织起来 ,提高了网络的表达能力。

    另一方面,11网络可以对输出通道进行改变,将输出同道减小并接一个较大的卷积,可以显著减少参数量。
    这里写图片描述

    这里写图片描述

    假设我们的目标是将一个2828192的输入数据,通过55的卷积,得到一个282832的输出。

    直接使用55卷积,

    需要的参数量为5519232=153600,

    每一层前向传播(反向传播相同)需要的计算量为(55192)(282832)=1.2e8(输出位置每个点需要的乘法运算为55192,共282832个输入)

    采用11卷积先执行通道降维,然后通过55卷积,同样可以得到282832的输出

    需要的参数量为:1119216+551632=15872

    每一层前向传播(反向传播相同)需要的计算量为
    11192282816+5516282832=1.2e7

    对比可以看到,需要的参数量和计算量都下降了10倍,可以有效压制过拟合并提升计算效率。

    11卷积可以组合不同同道的特征,并进行非线性输出,可以提高参数的表达能力,因此,虽然参数量下降很多,但只要卷积个数不太少,模型的表达能力不会有明显的下降。

    Inception Module

    上节阐述了11卷积,下面使用11卷积来构建Inception Module(Inception Net 就是将多个Inception Module连接在一起)。基本的Inception Module的结构如下图所示:
    这里写图片描述

    如上图所示,Inception Module包含4个分支,第一个分支为一个11的卷积,第二个分支为先11进行通道降维,然后接一个33卷积,第三个分支为先11进行通道降维,然后接一个55卷积,最后一个分支先为一个maxpool,然后使用一个11卷积进行通道降维到与其他输出一致,最终将4个分支的输出在通道维度上进行聚合。

    Inception Module的精神是让网络自己去捕捉不同尺度的特征,或者说让网络自己去学习需要什么样的卷积,采取哪些类型卷积的融合,而不用人为去设计卷积核的类型。显著增加网络对不同尺度特征的适应性,可以捕捉到不同大小的特征。
    这里写图片描述

    如上图所示,Inception Net 就是将堆叠多个Inception Module,我们希望靠后的Inception Module可以捕捉更高阶的抽象特征,因此靠后的Inception Module需要捕获面积更大的特征,因此越靠后3355卷积应该更多。

    Inception Net 有22层,除了最后一层的输出,其中间节点的分类效果也很好,因此Inception Net 也将中间某一层节点进行分类输出(给予一个比较小的权重),添加到最终分类结果中,相当于堆模型做了集成,同时给网络增加了反向传播的梯度信号,提升泛化性能,假设网络训练。

    Google Inception Net是一个大家族,包含Inception V1,Inception V2,Inception V3,Inception V4.

    Inception V2 学习了VGG,连续使用两个33网络替代一个55网络,感受野相同,但减少参数量,并增加了非线性。并提出了Batch Normlization(在<深度学习的优化>一文中有详细论述,这里就不再说明)
    这里写图片描述

    Inception V3 网络主要有两方面改造:

    1、引入Factorization into small convolution的思想,将一个较大的二维卷积拆成两个较小的一维卷积,比如77卷积拆成1771的卷积,一方面可以节省大量参数,减轻过拟合,另外增加了一层非线性扩展模型的表达能力。论文中指出,这种非对称的卷积结构拆分,其结果比对称的拆分几个相同的小卷积核效果更明显,可以处理更多,更丰富的空间特征,增加特征多样性。
    这里写图片描述

    2、Inception 还在分支中使用了分支,可以提取不同抽象程度的高阶特征,可以丰富网络的表达能力。

    Inception V4 主要结合了ResNet。

    卷积神经网络在NLP中的应用

    NLP中大量任务都是序列数据,采用循环神经网络,尤其Attention + Bidirectional LSTM 可以NLP中的大部分任务,但循环神经网络也有一些问题。

    1、RNN 无法单独捕捉没有前缀上下文的短语

    2、最终的向量中最后一个单词影响更大

    ​3、需要执行softmax

    解决上述问题的一个解决方案是采用递归神经网络,但递归神经网络需要事先提供解析树,因此,可以考虑使用卷积神经网络。

    接下来介绍如何使用卷积神经网络解决文本分类问题。

    CNN分类任务

    卷积神经网络应用于文本分类模型,需要解决两个主要问题:

    1、如何解决文本序列长度不一致的问题

    2、如何捕获不同长度的短语

    CNN的核心思想 :计算相邻的n-gram词组合起来,而不管它到底是不是真正的短语。
    这里写图片描述

    模型的架构
    这里写图片描述

    每个单词使用一个k维的向量表示(可以使用wor2vec 或者Glove训练的参数进行初始化),序列长度为n,从而将序列使用n*k维的矩阵表示。

    为了完整的表述单词,卷积核横向长度一定为k,为了捕获不同长度的短语结构,卷积核纵向长度h需要多种不同参数(h=1对应捕获unigram,h=2,对应捕获bigram,h=3对应捕获trigram…),卷积核个数可以为任意多个。为了不丢失重要的短语,卷积步长取1,由于我们不搭建深层CNN,因此序列可以补零,也可以不补零(为了叙述方便,这里假设只在末尾补零),对于维度为hk的卷积核与长度为n 的文本的文本序列进行卷积操作,得到nh+1的向量c=[c1,c2...cnh+1]。可以看到,同一个卷积核与不同长度的文本序列进行卷积操作,得到的向量的维度不一致。解决这个问题的关键是在卷积层后再接一个池化层,从而得到一个标量c^=max(c),采用最大池化与在图像领域中的思想一致,即捕捉到最显著的特征。然后将池化后的所有标量concat到一起,这样,不管输入的文本序列为多少,输出的维度都只与卷积核个数有关。然后将拼接后的向量输出到全连接层,进而进行分类任务,具体操作如下:

    z=[c^1,c^2....c^m]

    y=softmax(Wsz+b)

    为了提升泛化性能,可以采用dropout机制:y=softmax(Wszr+b),r为dropout 的 mask。

    通过池化操作,可以有效解决,文本序列长度不一致的问题

    通过选取不同大小的卷积核可以有效捕获不同长度的短语向量

    另外,有一个关于词向量的技巧。如果任由梯度流入词向量,则词向量会根据分类任务目标而移动,丢失语义上泛化的相似性。解决办法是用两份相同的词向量,称作两个通道(channel)。一个通道可变,一个通道固定。将两个通道的卷积结果输入到max-pool中 (模型架构中两个输入就表示两个通道,这样可以同时获得两个方面的信息:1、word2vec训练出的相语义,语法相似度,2、该问题的目标)。

    CNN扩展

    可以选取不同的卷积核长度,卷积核的个数,padding方式,池化方法等,也可以堆叠多层的CNN,总之,可以有多种扩展方式,这里就不在过多说明。
    hankcs.com 2017-07-04 下午2.09.13.png

    CNN 应用:机器翻译

    第一个神经网络机器翻译模型吧,用CNN做encoder,RNN做decoder:

    hankcs.com 2017-07-04 下午2.10.23.png

    卷积网络实例

    下面的实例来自吴恩达深度学习工程师课程 卷积神经网络 第一周的作业,使用卷积神经网络实现一个分类任务,使用tensorflow实现。

    问题描述:如下图所示,输入为用手演示的0-5数字的图像数据,标签为0-5数字

    img

    1、load数据集并将图像进行归一化处理(这一步在图像处理中常常是必要的,不希望特征太大),然后将标签改为one-hot vector。

    X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()
    X_train = X_train_orig/255.
    X_test = X_test_orig/255.
    Y_train = convert_to_one_hot(Y_train_orig, 6).T
    Y_test = convert_to_one_hot(Y_test_orig, 6).T
    

    2、创建 placeholders

    def create_placeholders(n_H0, n_W0, n_C0, n_y):
        """
        Creates the placeholders for the tensorflow session.
    
        Arguments:
        n_H0 -- scalar, height of an input image
        n_W0 -- scalar, width of an input image
        n_C0 -- scalar, number of channels of the input
        n_y -- scalar, number of classes
    
        Returns:
        X -- placeholder for the data input, of shape [None, n_H0, n_W0, n_C0] and dtype "float"
        Y -- placeholder for the input labels, of shape [None, n_y] and dtype "float"
        """
    
        ### START CODE HERE ### (≈2 lines)
        X = tf.placeholder(dtype=tf.float32,shape=[None,n_H0,n_W0,n_C0],name='X')
        Y = tf.placeholder(dtype=tf.float32,shape=[None,n_y],name='Y')
        ### END CODE HERE ###
    
        return X, Y
    

    3、初始化参数

    def initialize_parameters():
        """
        Initializes weight parameters to build a neural network with tensorflow. The shapes are:
                            W1 : [4, 4, 3, 8]
                            W2 : [2, 2, 8, 16]
        Returns:
        parameters -- a dictionary of tensors containing W1, W2
        """
    
        tf.set_random_seed(1)                              # so that your "random" numbers match ours
    
        ### START CODE HERE ### (approx. 2 lines of code)
        W1 = tf.get_variable(name='W1',shape=[4,4,3,8],dtype=tf.float32,initializer=tf.contrib.layers.xavier_initializer(seed=0))
        W2 = tf.get_variable(name='W2',shape=[2,2,8,16],dtype=tf.float32,initializer=tf.contrib.layers.xavier_initializer(seed=0))
        ### END CODE HERE ###
    
        parameters = {"W1": W1,
                      "W2": W2}
    
        return parameters
    

    4、定义前向传播(深度学习框架中只需要定义前向传播过程)

    网络架构如下:

     - Conv2D: stride 1, padding is "SAME"
     - ReLU
     - Max pool: Use an 8 by 8 filter size and an 8 by 8 stride, padding is "SAME"
     - Conv2D: stride 1, padding is "SAME"
     - ReLU
     - Max pool: Use a 4 by 4 filter size and a 4 by 4 stride, padding is "SAME"
     - Flatten the previous output.
     - FULLYCONNECTED (FC) layer
    def forward_propagation(X, parameters):
        """
        Implements the forward propagation for the model:
        CONV2D -> RELU -> MAXPOOL -> CONV2D -> RELU -> MAXPOOL -> FLATTEN -> FULLYCONNECTED
    
        Arguments:
        X -- input dataset placeholder, of shape (input size, number of examples)
        parameters -- python dictionary containing your parameters "W1", "W2"
                      the shapes are given in initialize_parameters
    
        Returns:
        Z3 -- the output of the last LINEAR unit
        """
    
        # Retrieve the parameters from the dictionary "parameters" 
        W1 = parameters['W1']
        W2 = parameters['W2']
    
        ### START CODE HERE ###
        # CONV2D: stride of 1, padding 'SAME'
        Z1 = tf.nn.conv2d(X,W1, strides = (1,1,1,1), padding = 'SAME')
        # RELU
        A1 = tf.nn.relu(Z1)
        # MAXPOOL: window 8x8, sride 8, padding 'SAME'
        P1 = tf.nn.max_pool(A1, ksize = (1,8,8,1), strides = (1,8,8,1),padding='SAME')
        # CONV2D: filters W2, stride 1, padding 'SAME'
        Z2 = tf.nn.conv2d(P1,W2,strides=(1,1,1,1),padding='SAME')
        # RELU
        A2 = tf.nn.relu(Z2)
        # MAXPOOL: window 4x4, stride 4, padding 'SAME'
        P2 = tf.nn.max_pool(A2, ksize = (1,4,4,1), strides = (1,4,4,1),padding='SAME')
        # FLATTEN
        P2 = tf.contrib.layers.flatten(P2)
        # FULLY-CONNECTED without non-linear activation function (not not call softmax).
        # 6 neurons in output layer. Hint: one of the arguments should be "activation_fn=None" 
        Z3 = tf.contrib.layers.fully_connected(P2, 6,activation_fn=None)
        ### END CODE HERE ###  
    
        return Z3
    

    5、定义损失函数,分类问题使用cross_entropy

    def compute_cost(Z3, Y):
        """
        Computes the cost
    
        Arguments:
        Z3 -- output of forward propagation (output of the last LINEAR unit), of shape (6, number of examples)
        Y -- "true" labels vector placeholder, same shape as Z3
    
        Returns:
        cost - Tensor of the cost function
        """
    
        ### START CODE HERE ### (1 line of code)
        cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=Z3,labels=Y))
        ### END CODE HERE ###
    
        return cost
    

    6、建立模型,主要包括以下几部分:

    • create placeholders
    • initialize parameters
    • forward propagate
    • compute the cost
    • create an optimizer

      def model(X_train, Y_train, X_test, Y_test, learning_rate = 0.009,
      num_epochs = 100, minibatch_size = 64, print_cost = True):
      “””
      Implements a three-layer ConvNet in Tensorflow:
      CONV2D -> RELU -> MAXPOOL -> CONV2D -> RELU -> MAXPOOL -> FLATTEN -> FULLYCONNECTED

      Arguments:
      X_train -- training set, of shape (None, 64, 64, 3)
      Y_train -- test set, of shape (None, n_y = 6)
      X_test -- training set, of shape (None, 64, 64, 3)
      Y_test -- test set, of shape (None, n_y = 6)
      learning_rate -- learning rate of the optimization
      num_epochs -- number of epochs of the optimization loop
      minibatch_size -- size of a minibatch
      print_cost -- True to print the cost every 100 epochs
      
      Returns:
      train_accuracy -- real number, accuracy on the train set (X_train)
      test_accuracy -- real number, testing accuracy on the test set (X_test)
      parameters -- parameters learnt by the model. They can then be used to predict.
      """
      
      ops.reset_default_graph()                         # to be able to rerun the model without overwriting tf variables
      tf.set_random_seed(1)                             # to keep results consistent (tensorflow seed)
      seed = 3                                          # to keep results consistent (numpy seed)
      (m, n_H0, n_W0, n_C0) = X_train.shape             
      n_y = Y_train.shape[1]                            
      costs = []                                        # To keep track of the cost
      
      # Create Placeholders of the correct shape
      ### START CODE HERE ### (1 line)
      X, Y = create_placeholders(n_H0, n_W0, n_C0, n_y)
      ### END CODE HERE ###
      
      # Initialize parameters
      ### START CODE HERE ### (1 line)
      parameters = initialize_parameters()
      ### END CODE HERE ###
      
      # Forward propagation: Build the forward propagation in the tensorflow graph
      ### START CODE HERE ### (1 line)
      Z3 = forward_propagation(X,parameters)
      ### END CODE HERE ###
      
      # Cost function: Add cost function to tensorflow graph
      ### START CODE HERE ### (1 line)
      cost = compute_cost(Z3,Y)
      ### END CODE HERE ###
      
      # Backpropagation: Define the tensorflow optimizer. Use an AdamOptimizer that minimizes the cost.
      ### START CODE HERE ### (1 line)
      optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)
      ### END CODE HERE ###
      
      # Initialize all the variables globally
      init = tf.global_variables_initializer()
      
      # Start the session to compute the tensorflow graph
      with tf.Session() as sess:
      
          # Run the initialization
          sess.run(init)
      
          # Do the training loop
          for epoch in range(num_epochs):
      
              minibatch_cost = 0.
              num_minibatches = int(m / minibatch_size) # number of minibatches of size minibatch_size in the train set
              seed = seed + 1
              minibatches = random_mini_batches(X_train, Y_train, minibatch_size, seed)
      
              for minibatch in minibatches:
      
                  # Select a minibatch
                  (minibatch_X, minibatch_Y) = minibatch
                  # IMPORTANT: The line that runs the graph on a minibatch.
                  # Run the session to execute the optimizer and the cost, the feedict should contain a minibatch for (X,Y).
                  ### START CODE HERE ### (1 line)
                  _ , temp_cost = sess.run([optimizer,cost],feed_dict={X:minibatch_X,Y:minibatch_Y})
                  ### END CODE HERE ###
      
                  minibatch_cost += temp_cost / num_minibatches
      
      
              # Print the cost every epoch
              if print_cost == True and epoch % 5 == 0:
                  print ("Cost after epoch %i: %f" % (epoch, minibatch_cost))
              if print_cost == True and epoch % 1 == 0:
                  costs.append(minibatch_cost)
      
      
          # plot the cost
          plt.plot(np.squeeze(costs))
          plt.ylabel('cost')
          plt.xlabel('iterations (per tens)')
          plt.title("Learning rate =" + str(learning_rate))
          plt.show()
      
          # Calculate the correct predictions
          predict_op = tf.argmax(Z3, 1)
          correct_prediction = tf.equal(predict_op, tf.argmax(Y, 1))
      
          # Calculate accuracy on the test set
          accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
          print(accuracy)
          train_accuracy = accuracy.eval({X: X_train, Y: Y_train})
          test_accuracy = accuracy.eval({X: X_test, Y: Y_test})
          print("Train Accuracy:", train_accuracy)
          print("Test Accuracy:", test_accuracy)
      
          return train_accuracy, test_accuracy, parameters
      

      7、对模型进行训练

      , , parameters = model(X_train, Y_train, X_test, Y_test)

    img

    损失函数如下:训练集准确率为94%,测试集准确率为82%,存在比较明显的过拟合。

    相关课程

    吴恩达 深度学习工程师 卷积神经网络

    台湾大学 李宏毅 机器学习,深度学习 卷积神经网络

    斯坦福 CS224n:Natural Language Processing with Deep Learning ,Convolutional Neural Networks

    相关书籍

    lan Goodfellow ,Yoshua Bengio ,Aaron Courville 深度学习,卷积神经网络

    黄文坚 唐源 TensorFlow实战

    姜建国等 信号与系统分析基础

    展开全文
  • 卷积神经网络 情绪识别Nendoroids are a brand of action figures owned by the Good Smile Company. They are usually short in size or chibi-sized and cover a lot of characters from all sorts of mediums ...

    卷积神经网络 情绪识别

    Nendoroids are a brand of action figures owned by the Good Smile Company. They are usually short in size or chibi-sized and cover a lot of characters from all sorts of mediums such as movies, games TV shows, animations, books, etc. They are very popular among the anime and manga fandom due to most of their figures being based on most popular anime/manga/light novels. They consist of around 30–40 movable parts and some of them are known to be hand-made to this day.

    黏土人是Good Smile Company旗下的动作人物品牌。 它们通常身材矮小或赤壁大小,并且涵盖了来自电影,游戏电视节目,动画,书籍等各种媒介的许多角色。由于它们的大多数,它们在动漫和漫画迷中非常受欢迎这些数字是根据最受欢迎的动漫/漫画/轻小说创作的。 它们由大约30–40个可移动部件组成,其中有些至今仍是手工制作的。

    If you want to know more about their production, I recommend watching this 30 min video of how they are made.

    如果您想了解更多有关其生产的信息,建议您观看这30分钟的视频,了解它们的制作方法。

    In this blog, we’re going to classify pics of Nendoroids with other action figure brands such as Figmas, Gunplas, etc. using deep learning. I’ll try my best to explain these concepts in layman terms. The reason for doing so is that making an image classification project using cats, dogs, fruits doesn’t sound so exciting.

    在本博客中,我们将使用深度学习将黏土人的图片与其他动作人物品牌(例如Figmas,Gunplas等)进行分类。 我将尽力用外行术语解释这些概念。 这样做的原因是,使用猫,狗,水果进行图像分类项目听起来并不那么令人兴奋。

    创建图像数据集 (Creating an image dataset)

    Collecting the images was sort of easy. I downloaded (manually or through a script or software) the Nendoroid and Non-Nendoroid images from Google Images, Pinterest, and online stores that sell these figures and place them into their respective folders (Nendoroid and non-Nendoroids). There’s no set amount for the number of images in a dataset, but the rule of thumb is around a total of 1000 images.

    收集图像很容易。 我从Google图片,Pinterest和在线商店下载了(手动或通过脚本或软件)黏土人和非黏人人的图像,这些图像出售这些人物并将它们放置在各自的文件夹中(黏土人和非黏土人)。 数据集中的图像数量没有固定的数量,但是经验法则是总共约1000张图像。

    One thing that I had to keep in mind is that the images only contained one or 2 figures and are facing the camera.

    我要记住的一件事是,图像仅包含一个或两个数字,并且都面向相机。

    For labeling, I renamed the file names in both folder to something like nendo_(insert number) and nonendo_(insert number) using the Python OS library.

    为了进行标记,我使用Python OS库将两个文件夹中的文件名都重命名为nendo_(插入编号)和nonendo_(插入编号)。

    A much better way to label the images is using an annotator like Pidgeon (https://github.com/agermanidis/pigeon) thanks to this blog on collecting images for the dataset.

    更好的标记图像的方法是使用像Pidgeon( https://github.com/agermanidis/pigeon )这样的注释器,这要归功于此博客为数据集收集图像。

    Here are some examples of Nendoroids. They have a very miniature build that is more expressive and their poses can be customized.

    这是黏土人的一些例子。 他们的身材非常小巧,更具表现力,可以自定义姿势。

    Image for post
    Photo by Tengyart on Unsplash
    TengyartUnsplash拍摄的照片
    Image for post
    Photo by Daniel Lee on Unsplash
    Daniel LeeUnsplash拍摄的照片

    Here are other examples of action figures that are not Nendoroids like Gunplas (owned by Bandai Hobby Center) and Figmas (which are also owned by the Good Smile Company).

    这里还有一些其他非黏土人的动作模型,例如Gunplas(由Bandai Hobby Center拥有)和Figmas(也由Good Smile Company拥有)。

    Image for post
    Daily Choice on Daily Choice on UnsplashUnsplash拍摄
    Image for post
    Photo by Ryan Yao on Unsplash
    Ryan Yao Unsplash

    图像的组成 (Components of an image)

    Before we get into preprocessing the data, we need to understand what an image consists of. A digital image consists of pixels that are arranged in a given length and width.

    在进行数据预处理之前,我们需要了解图像由什么组成。 数字图像由以给定的长度和宽度排列的像素组成。

    An example of this would be an image of a resolution of 1920 x 1080. This contains 816,000 pixels, where the pixels are arranged within the length of 1920 pixels horizontally and 1080 pixels vertically.

    例如,分辨率为1920 x 1080的图像。它包含816,000像素,其中这些像素在水平1920像素和垂直1080像素的长度内排列。

    Every pixel contains a value. For grayscaled images, those values range between 0(black) to 255(white) and each of them represent the different shades of the 2 colors.

    每个像素都包含一个值。 对于灰度图像,这些值的范围在0(黑色)到255(白色)之间,并且每个值代表两种颜色的不同阴影。

    What gives the color to an image is the RGB (Red, Green, Blue) channels. These channels consist of their own pixel value from 0 to 255, each representing a different shade of that color channel. The pixel value of that color image is a vector of all the 3-pixel values from each channel.

    使图像具有颜色的是RGB(红色,绿色,蓝色)通道。 这些通道由自己的像素值(从0到255)组成,每个像素值代表该颜色通道的不同阴影。 该彩色图像的像素值是每个通道中所有3像素值的向量。

    预处理图像 (Preprocessing the images)

    For preprocessing our data, there are 3 steps to be followed :

    要预处理我们的数据,需要遵循3个步骤:

    1. Read our image and convert it to greyscale. This is because we are more focused on the structures of the figures and not the color.

      阅读我们的图像并将其转换为灰度。 这是因为我们更专注于图形的结构,而不是颜色。
    2. Resize it to a certain resolution because all the images must have a uniform resolution size.

      将其调整为某个分辨率,因为所有图像都必须具有统一的分辨率大小。
    3. Convert the image to an n-dimensional array and flatten it to a 1-dimensional array.

      将图像转换为n维数组并将其展平为1维数组。

    Do that for both image classes, append the labels and we have our dataset to feed the model with.

    对两个图像类都执行此操作,然后附加标签,我们就有了数据集来填充模型。

    os.chdir("Insert file link to dataset")files = os.listdir()data = []for i in files:
    #Read and convert the images to greyscale
    ig = cv2.imread(os.path.join(os.getcwd(),i),cv2.IMREAD_GRAYSCALE)
    #Resize the image to a uniform dimension
    new_ig = cv2.resize(ig,dsize=(img_size,img_size))
    #append converted data to label
    data.append([new_ig,'Nendoroid'])

    Now to split our dataset into training, validation, and testing datasets.

    现在将我们的数据集分为训练,验证和测试数据集。

    x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=42)x_train,x_val,y_train,y_val = train_test_split(x_train,y_train,test_size=0.2,random_state=42)

    First thing is to normalize our images by dividing it with the value 255, which is the highest number that represents a shade of color from 0–255. The reason for doing so is that improve our Convolutional Neural Network during classification since the values will be at a range between 0–1.

    第一件事是通过将图像除以值255(这是代表从0到255的阴影)的最高数字来规范化图像。 这样做的原因是在分类过程中改进了卷积神经网络,因为该值将在0–1之间。

    x_train = np.array(x_train)/255
    x_test = np.array(x_test)/255
    x_val = np.array(x_val)/255

    Next is to resize them back to their image size and send it as input to the Convolutional Neural Network.

    接下来是将其调整为图像大小,并将其作为输入发送到卷积神经网络。

    x_train = x_train.reshape(-1,img_size,img_size,1)
    y_train = np.array(y_train)x_test = x_test.reshape(-1,img_size,img_size,1)
    y_test = np.array(y_test)x_val = x_val.reshape(-1,img_size,img_size,1)
    y_val = np.array(y_val)

    卷积神经网络 (Convolutional Neural Network)

    To put it simply, the convolutional neural network (CNN) involves breaking down the images into the smallest representation, before it is sent as input to the neural networks. How it breaks down the image? It goes like this.

    简单地说,卷积神经网络(CNN)涉及在将图像作为输入发送到神经网络之前,将图像分解为最小的表示形式。 它如何分解图像? 就像这样

    Step 1: A matrix of a given dimension aka a kernel goes through the image step by step from up to down, left to right, and multiplies. The result is a value that represents that kernel at that position. This is known as a convolution.

    第1步 :给定维度(又称内核)的矩阵从上到下,从左到右逐步相乘并相乘。 结果是一个值,该值表示该位置的内核。 这被称为卷积。

    Image for post
    Convolution process
    卷积过程

    How many steps it needs to take is determined by a value called stride.

    它需要采取多少步骤由一个称为跨度的值决定。

    Step 2: That convoluted matrix then gets broken down even further through a process called pooling, which is similar to convolution but it returns a matrix containing the max or average value of that kernel in the pooling phase.

    步骤2 :然后,通过称为池化的过程进一步分解了卷积矩阵,该过程类似于卷积,但是它返回了一个包含在池化阶段该内核的最大值或平均值的矩阵。

    Image for post
    Pooling process
    合并过程

    Step 3: This goes on until it returns the smallest possible image dimensions.

    步骤3 :继续进行直到返回最小的图像尺寸。

    How does CNN find out any patterns and classify the images?

    CNN如何找出任何图案并对图像进行分类?

    In the convolution layer, there exists filters, which are a bunch of weights as a vector. During the training of the model, it multiplies with the output of the convolution layer and as it goes through all the images, the weights keep on changing. When the model predicts an image, if the image has a very similar pattern to one of the images in the training dataset, those weights return high values.

    在卷积层中,存在过滤器,这些过滤器是一堆权重作为矢量。 在训练模型期间,它与卷积层的输出相乘,并且在遍历所有图像时,权重不断变化。 当模型预测图像时,如果图像具有与训练数据集中的图像非常相似的图案,则这些权重将返回高值。

    建立卷积神经网络 (Building the Convolutional Neural Network)

    Now it’s time to build the Convolutional Neural Network using Keras via Tensorflow. Start by calling the Sequential() method to stack our layers and then add the convolutional layer (Conv2D) with a given number of nodes and the size of the kernel to use. After that add a max-pooling layer of given kernel size and keep on doing this until the dimension of the images through the layers are near zero or one. Once that’s done, the images are flattened to a 1-dimensional array and it goes through the dense neural network at the last stages.

    现在是时候通过Tensorflow使用Keras构建卷积神经网络了。 首先调用Sequential()方法来堆叠我们的层,然后添加具有给定节点数和要使用的内核大小的卷积层(Conv2D)。 之后,添加给定内核大小的最大池化层,并继续执行此操作,直到通过层的图像尺寸接近零或一。 一旦完成,图像将被展平为一维数组,并在最后阶段通过密集的神经网络。

    cnn = Sequential()
    cnn.add(Conv2D(32,(3,3),activation='relu',input_shape=(img_size,img_size,1)))
    cnn.add(MaxPooling2D((2,2)))
    cnn.add(Dropout(0.1))
    cnn.add(Conv2D(64,(3,3),activation='relu'))
    cnn.add(MaxPooling2D((2,2)))
    cnn.add(Dropout(0.1))
    cnn.add(Conv2D(64,(3,3),activation='relu'))
    cnn.add(MaxPooling2D((2,2)))
    cnn.add(Dropout(0.1))
    cnn.add(Conv2D(64,(3,3),activation='relu'))
    cnn.add(MaxPooling2D((2,2)))
    cnn.add(Dropout(0.1))
    cnn.add(Conv2D(128,(3,3),activation='relu'))
    cnn.add(MaxPooling2D((2,2)))
    cnn.add(Dropout(0.1))
    cnn.add(Conv2D(128,(3,3),activation='relu'))
    cnn.add(MaxPooling2D((2,2)))
    cnn.add(Dropout(0.1))
    cnn.add(Flatten())
    cnn.add(Dense(128,activation='relu'))
    cnn.add(Dropout(0.1))
    cnn.add(Dense(1,activation='sigmoid'))

    Activation functions are what convert the output of one node to be sent as input to the corresponding node. Except for the last layer, the ReLu activation function is used since it takes fewer resources and it doesn’t fall victim to the ‘vanishing gradient’ problem, unlike the Sigmoid function.

    激活函数将转换一个节点的输出作为输入发送到相应节点的功能。 除了最后一层之外,还使用了ReLu激活功能,因为它占用的资源更少,并且与Sigmoid函数不同,它不会成为“消失梯度”问题的受害者。

    The last layer has ‘Sigmoid’ as the activation function and it outputs a value between 0 to 1.

    最后一层具有“ Sigmoid”作为激活函数,它输出0到1之间的值。

    Dropouts are added to lessen the chances of overfitting the model. Here’s a visual representation of the Dropout process.

    添加了辍学以减少过拟合模型的机会。 这是Dropout流程的直观表示。

    Image for post
    Meme representation of Dropouts in Neural Networks made by me
    我所做的神经网络中辍学的模因表示

    For compiling the neural network, the optimizer (which changes the weights and biases in the Neural Network at a given learning rate) chosen is the RMSprop, the loss function is binary cross-entropy because we have only 2 classes to classify from. The Convolutional Neural Network is trained for about 35 rounds or epochs, with the validation data used to make sure that it isn’t ‘memorizing’ anything and can classify unseen data well.

    为了编译神经网络,选择的优化器(以给定的学习速率改变神经网络中的权重和偏差)是RMSprop,损失函数是二进制交叉熵,因为我们只有2个类可以进行分类。 卷积神经网络经过约35轮或每个纪元的训练,其验证数据可确保其不会“记住”任何东西,并且可以很好地对看不见的数据进行分类。

    cnn.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['accuracy'])history = cnn.fit(x_train,y_train,epochs=35,validation_data=(x_val,y_val))

    Comparing the accuracy values of both the training and validation data for 20 epochs and the test data accuracy, there seems to be overfitting. This can be changed through trial and error by changing the learning rate, dropout value, removing layers, etc. but I’ll stop it from here.

    比较20个时期的训练和验证数据的准确性值与测试数据的准确性,似乎存在过度拟合的问题。 可以通过更改学习率,辍学值,删除图层等来通过反复试验来更改此设置,但我将从此处停止。

    Image for post
    Comparing between training and validation data accuracy
    培训和验证数据准确性之间的比较

    Looking at the confusion matrix for the test data, the model did its job of classifying the test data quite well, albeit some false negatives.

    通过查看测试数据的混淆矩阵,该模型可以很好地对测试数据进行分类,尽管存在一些假阴性。

    Image for post
    Confusion matrix of test dataset
    测试数据集的混淆矩阵

    关键时刻 (The moment of truth)

    Now for the moment of truth. It’s time to use our classifier against images outside of the dataset we used. What’s a classifier if it doesn’t classify anything outside of the used dataset ?. There are 40 images (20 Nendoroid and non-Nendoroid images) in this set and we’re going to see how well it was able to classify our images.

    现在是关键时刻。 现在该对我们所使用的数据集之外的图像使用分类器了。 如果未对使用的数据集以外的任何内容进行分类,则该分类器是什么? 此集合中有40张图像(20个Nendoroid和非Nendoroid图像),我们将看到它对图像的分类效果如何。

    Like before, we preprocess the images and then use the model.predict_classes() function to predict the class for each image.

    和之前一样,我们对图像进行预处理,然后使用model.predict_classes()函数预测每个图像的类。

    Looking at the accuracy and the confusion matrix, there are a lot less false positives and false negatives found, so I’d say it did its job.

    从准确性和混淆矩阵的角度来看,发现的误报和误报要少得多,所以我想说它确实能做到。

    Image for post
    Confusion matrix of images in the Test data folder
    测试数据文件夹中图像的混淆矩阵

    Here are some of the images classified correctly and not correctly classified (0 indicates it’s not a Nendoroid and 1 indicates it is a Nendoroid).

    以下是一些正确分类和未正确分类的图像(0表示不是黏土人,1表示是黏土人)。

    Image for post
    Images correctly classified as non-Nendoroids
    正确分类为非黏土人的图像
    Image for post
    Images correctly classified as a Nendoroid
    正确分类为黏土人的图像
    Image for post
    Images incorrectly classified as either Nendoroids or non-Nendoroids
    图像错误地分类为黏土人或非黏土人

    结论 (Conclusion)

    In short, we were able to make a classifier that was able to differentiate and classify between Nendoroids and Non-Nendoroid images using a Convolutional Neural Network. Even though this could have been done better with some slight tuning and modifications, we now know that it was effective in doing so.

    简而言之,我们能够使用卷积神经网络进行分类,从而能够对黏土人和非黏土人图像进行区分和分类。 即使通过一些微调和修改可以更好地做到这一点,我们现在知道这样做是有效的。

    Overall, this was a fun experiment to learn about image preprocessing and classification as well as the inner workings of the Convolutional Neural Network. Here’s a reward for going through all of this.

    总体而言,这是一个有趣的实验,旨在了解图像预处理和分类以及卷积神经网络的内部工作原理。 这是对所有这些过程的奖励。

    If you like the Nendoroids, Gunplas, and figmas in this article and want to buy for yourself, you can go to their official sites to buy them.

    如果您喜欢本文中的Nendoroids,Gunplas和figmas并希望自己购买,可以前往其官方网站购买。

    If you like this article, please share it with others. I’ll be grateful if you do so. Feel free to give feedback about this and the notebook for this project will be on my Github page.

    如果您喜欢这篇文章,请与他人分享。 如果您愿意,我将不胜感激。 随时提供有关此项目的反馈,该项目的笔记本将在我的Github页面上。

    翻译自: https://towardsdatascience.com/identifying-nendoroids-using-convolutional-neural-networks-80aa08291aef

    卷积神经网络 情绪识别

    展开全文
  • 本篇博客主要介绍了卷积神经网络的结构,并解释了使用这种结构的好处及原理,并总体分析了一个好的卷积神经网络都需要哪些部分。

    本篇博客主要内容参考图书《神经网络与深度学习》,李航博士的《统计学习方法》National Taiwan University (NTU)李宏毅老师的《Machine Learning》的课程,在下文中如果不正确的地方请积极指出。
    如果喜欢请点赞,欢迎评论留言 ! o( ̄▽ ̄)ブ

    欢迎大家在评论区多多留言互动~~~~

    1. 卷积神经网络的结构

      一个在实际使用中具有较好的效果的卷积神经网络的结构应该是如下所描述的。


    图1. 卷积神经网络的结构

    (1)数据增强(拓展训练数据):这部分作用主要是防止模型过拟合。当然当训练数据足够多的时候可以不使用这一部,因为数据量已经足够了。
    (2)输入层:这部分卷积形式所对应的输入层,从图1 中左侧第一个正方形(28×28)所代表的部分,注意这里不是全连接神经网络那种的将图片展开成向量的形式,而是任然保留原有图片的形式。
    (3)卷积层:在这里我们将卷积与池化放在一起看作是一个整体,即卷积层。在实际的卷积神经网络中不仅仅有着之前介绍的一个卷积层,可能有着数个,甚至十几个卷积层,这样往往会得到更好的效果。可是这个从实际的意义上应该如何考虑呢?第一个卷积层的输出可以看作是原始输入图像中特定的局部特征的存在(或不存在),因此可以看作是原始输入图像的一个版本。这个版本是经过抽象和凝缩过的,但是仍然有大量的空间结构。所以第二层相当于再这个新版本的图像上考察他是否存在或者不存在某些特征。另外还有一个问题就是,对于第二个卷积层,其输入已经不是像第一个卷积层那样仅仅具有一个输入了,而具有多个输入。所以对于第二个卷积层某一个卷积滤波器,他是使用该滤波器对前面那一层的所有输出运算,不过仍然是限制于他的局部感受野内的。而池化的具体方法,除了最大池化,还有均值池化,L2池化等等。
    (4)全连接层:和之前的神经网络一样,可以是一层也可以是两层
    (5)Dropout:使用Dropout之后可以使更多的神经元也让可以防止神经网络过拟合,并且可以加快神经网络的训练速度,缩短迭代次数。值得注意的是Dropout仅仅用于全连接层,而不用于卷积层,主要原因在于共享权重意味着卷积滤波器被强制从整个图像中学习,这使他们不太可能去选择在训练数据中的局部特质,即卷积层有相当大的先天的对于过度拟合的抵抗。
    (6)输出层:分类问题常用 softmax。

      除了上述部分还有其他需要选择的内容:
    (1)激活函数:最开始我们介绍的 S 激活函数,由于使用它会使得使得神经网络的训练速度减慢(即更容易产生输出饱和,进而加剧了梯度消失现象);之后可以采用tanh函数,该函数因为是奇函数,所以具有负值部分,在一定程度上改善了 S 激活函数的缺点;但是在现在的实际使用中往往更多的使用ReLU函数,使用这种函数的好处在于这种函数由于其求导简单,会使得训练的速度加快;同时许多实验也表明其具有更高的正确率。对于这种优点,除了可以归功到求导形式简单之外,有的生物学家认为这种单边信号很符合生物学的特点。
    (2)使用一个组合的网络:一个简单的进一步提高性能的方法是创建几个神经网络,然后让它们投票来决定最好的分类。例如,假设我们使用上述的方式训练了 5 个不同的神经网络,每个达到了接近于 99.6% 的准确率。尽管网络都会有相似的准确率,他们很可能因为不同的随机初始化产生不同的错误。在这 5 个网络中进行一次投票来取得一个优于单个网络的分类,似乎是合理的。
    (3)使用GPU:相同的神经网络,使用GPU训练和使用CPU训练的速度明显是不同的。使用GPU具有更快的速度,所以我们常常将停止迭代的误差设的要比CPU版本的要低,所以往往会获得更好的效果。
    (4)权重初始化。可以使用各种改进的随机高斯分布的初始化方式,但是一般不建议用原始的随机高斯分布。

    展开全文
  • 这两天突然发现,不管是书籍还是竞赛里的卷积神经网络模型都没有讲解说为什么这样设置层数?比如先有两个卷积层,再有一个池化层,最后有一个全连接层,选择这些层的层数是根据什么原理的呢?这件事引起了我的好奇。...
  • 卷积神经网络(Convolutional Neural Network)简称CNN,CNN是所有深度学习课程、书籍必教的模型,CNN在影像识别方面的为例特别强大,许多影像识别的模型也都是以CNN的架构为基础去做延伸。另...
  • 卷积神经网络pdf讲义超详细
  • 卷积神经网络(CNN)的快速入门做的笔记,简洁可参考。 一、卷积神经网络(CNN) 二、LeNet(推进深度学习最早的卷积神经网络之一) 1、卷积操作 2、非线性简介(ReLU)(激活函数) 3、池化操作 4、全连接层 ...
  • 卷积神经网络记录(一)基础知识整理

    万次阅读 多人点赞 2018-11-17 20:23:25
    卷积神经网络记录 最近一段时间在学习卷积神经网络的知识,看了很多博客和资料之后,决定自己写一篇记录一下学习地知识,巩固一下所学。 1.卷积神经网络与全连接神经网络的异同 首先来看卷积神经网络之前的网络的...
  • 大嘴巴漫谈数据挖掘和解析卷积神经网络书籍,用来收藏。
  • 一文搞定卷积神经网络——从原理到应用

    万次阅读 多人点赞 2019-01-07 19:40:20
    卷积神经网络基本单元3.1 卷积(Convolution)3.2 填充(Padding)和步长(Stride)3.3 完整的卷积过程3.4 池化(Pooling)3.5 激活函数4. 卷积神经网络的前向传播过程5. 卷积神经网络的反向传播过程5.1 卷积层的...
  • 学习目标 1.计算机视觉 2.边缘检测示例 3.其他边缘检测 4.Padding 5.卷积步长 strided convolution 6.Convolutions over Volume 7.单层式卷积网络one Layer of a Convolution...10.卷积神经网络示例(CNN Example) ...
  • 造就机器能够获得在这些视觉方面取得优异性能可能是源于一种特定类型的神经网络——卷积神经网络(CNN)。如果你是一个深度学习爱好者,你可能早已听说过这种神经网络,并且可能已经使用一些深度学习框架比如caffe、...
  • CNN卷积神经网络详解

    2018-08-05 15:59:02
    CNN神经网络入门书籍,想要入门神经网络,学习基础知识的不可错误
  • 卷积神经网络入门

    2017-11-22 13:02:27
    卷积神经网络(Convolutional neural networks)。听起来就像是生物加数学在再计算机科学为佐料做成的一个狂野的组合,但这些网络却是计算机视觉领域极富有影响力的一部分创新。2012年是神经网络大放异彩的第一年,...
  • 关于深度学习, 图像处理.卷积神经网络的大量参考论文文献.
  • 《解析卷积神经网络》学习笔记

    千次阅读 2018-05-05 19:21:32
    本文主要分享一下自己读吴秀参的《解析卷积神经网络》的一些心得,这是一本偏实用的深度学习工具书,内容侧重深度卷积神经网络的基础知识和实践应用。这本书主要剖析了卷积神经网络的基本部件与工作机理,并且系统性...
  • 1、卷积神经网络(ConvolutionNeural Network,CNN) 19世纪60年代科学家最早提出感受野(ReceptiveField)。当时通过对猫视觉皮层细胞研究,科学家发现每一个视觉神经元只会处理一小块区域的视觉图像,即感受野。20...
  • 卷积神经网络(Convolutional Neural Network, CNN) 卷积神经网络(Convolutional Neural Network, CNN)是受生物学上感受野机制的启发而提出的。卷积神经网络一般是由卷积层、池化层和全连接层交叉堆叠而成的前馈神经...
  • 最近几天一直在学习卷积神经网络原理,感觉还是挺难理解的,本篇博文结合网上的资料和手头上的深度学习的书籍,对卷积神经网络(CNN)的基本结构和核心思想做了一下整理。望与各位道友交流学习,不足之处还望批评...
  • 文章目录卷积神经网络前向及反向传播过程数学解析1、卷积神经网络初印象2、卷积神经网络性质3、前向传播3.1、卷积层层级间传递3.2、池化操作3.3、卷积层到全连接层传递4、卷积神经网络的反向传播过程4.1、全连接层...
  • Torch7下搭建卷积神经网络框架

    千次阅读 2016-12-05 21:58:26
    之前的博文,如一文读懂卷积神经网络(CNN)、多层网络与反向传播算法详解、感知机详解、卷积神经网络详解等已经比较详细的讲述了神经网络以及卷积神经网络的知识。本篇博文主要讲述在Torch7中神经网络如何建立以及...
  • 卷积神经网络基础

    2020-10-14 11:49:48
    卷积神经网络近年来在图像识别,NLP处理上风头无两。本章节主要讲CNN在图像识别上的应用。 一、输入数据 1、输入结果 第一章使用全连接层也能实现图像的分类,改种方法把输入数据压缩成向量,例如一个28*28像素的...
  • 卷积神经网络 本文参考《TensorFlow2深度学习》 背景知识 1、深度学习的深度是指网络的层数较深,一般有5层以上。1~4层神经网络称为浅层神经网络。浅层神经网络不能很好的提取数据的高层特征,表达能力一般,很快被...
  • 卷积神经网络CNN进行图像分类
  • 一、什么是卷积神经网络 卷积神经网络(Convolutional Neural Network,CNN)又叫卷积网络(Convolutional Network),是一种专门用来处理具有类似网格结构的数据的神经网络。卷积神经网络一词中的卷积是一种特殊的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,782
精华内容 2,312
关键字:

关于卷积神经网络的书籍