如何调整一个不收敛的卷积神经网络 公开课

看了深度学习卷积神经网络,有很多疑问?_人工智能吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:48,105贴子:
看了深度学习卷积神经网络,有很多疑问?收藏
1。看了深度学习卷积神经网络,觉得相当震撼,但还是对细节不太了解。只是大概知道: 利用滤波器(卷积核)对局部感受区域,进行卷积运算,从而得到该局部的特征。2。还有高级特征可以通过稀疏编码,用基(低级特征)的线性组合来表示。3。SIFT是局部特征表示的一个理论。现在问题是:我已经学习了眼睛这个特征,我怎么用更低级的特征来表示?找到用低级特征基来表示眼睛,那我在另外一幅画中,怎么利用这个分割眼睛特征?
美国人工智能专业,出国留学优选天道,51个哈佛,71个耶鲁,986个哥大,录取战绩业内领先.美国人工智能专业录取条件解析,天道资深留学专家为你量身定做美国理科专业名校之路!
流行学习有些答案。降维后可以提取一些特征。
哈哈 确实还差个流形
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或机器学习教程 十五-细解卷积神经网络 - 推酷
机器学习教程 十五-细解卷积神经网络
深度学习首先要讲的就是卷积神经网络,因为卷积神经网络沿用了之前讲过的多层神经网络的具体算法,同时在图像识别领域得到了非常好的效果。本节介绍它的数学原理和一些应用中的问题解决方案,最后通过公式讲解样本训练的方法
请尊重原创,转载请注明来源网站以及原始链接地址
再次引用上一篇里的内容《
卷积英文是convolution(英文含义是:盘绕、弯曲、错综复杂),数学表达是:
上面连续的情形如果不好理解,可以转成离散的来理解,其实就相当于两个多项式相乘,如:(x*x+3*x+2)(2*x+5),计算他的方法是两个多项式的系数分别交叉相乘,最后相加。用一句话概括就是:多项式相乘,相当于系数向量的卷积。
如果再不好理解,我们可以通俗点来讲:卷积就相当于在一定范围内做平移并求平均值。比如说回声可以理解为原始声音的卷积结果,因为回声是原始声音经过很多物体反射回来声音揉在一起。再比如说回声可以理解为把信号分解成无穷多的冲击信号,然后再进行冲击响应的叠加。再比如说把一张图像做卷积运算,并把计算结果替换原来的像素点,可以实现一种特殊的模糊,这种模糊其实是一种新的特征提取,提取的特征就是图像的纹路。总之卷积就是先打乱,再叠加。
下面我们在看上面的积分公式,需要注意的是这里是对τ积分,不是对x积分。也就是说对于固定的x,找到x附近的所有变量,求两个函数的乘积,并求和。
卷积神经网络
英文简称CNN,大家并不陌生,因为你可能见过DNN(深度神经网络)、RNN(循环神经网络)。CNN主要应用领域是图像处理,它本质上是一个分类器。
卷积神经网络为什么这么深得人心呢?因为在卷积神经网络的第一层就是特征提取层,也就是不需要我们自己做特征提取的工作,而是直接把原始图像作为输入,这带来了很大的便利,归根结底还是归功于卷积运算的神奇。
那么第一层是怎么利用卷积运算做特征提取的呢?我们还是通过图像处理的例子来说明。参考生物学的视觉结构,当人眼观察一个事物的时候,并不是每个视神经细胞感知所有看到的“像素”,而是一个神经细胞负责一小块视野,也就是说假设看到的全部视野是1000像素,而神经细胞有10个,那么一个神经细胞就负责比1000/10得到的平均值大一圈的范围,也就是200像素,一个细胞负责200个像素,10个细胞一共是2000个像素,大于1000个像素,说明有重叠。这和上面卷积运算的原理很像。用一张图来表示如下:
什么是卷积核
先看下面这张图,这是计算5*5矩阵中间的3*3部分的卷积值
绿色部分是一个5*5的矩阵,标橙的部分说明正在进行卷积计算,&1表示算上这个单元的值,&0表示不计算,这样得出的结果1&1+1&0+1&1+0&0+1&1+1&0+0&1+0&0+1&1=4,这样计算出了第一个元素的卷积
我们继续让这个橙色部分移动并计算,最终会得到如下结果:
那么这里的橙色(标记&1或&0)的矩阵(一般都是奇数行奇数列)就叫做卷积核,即
卷积计算实际上是一种对图像元素的矩阵变换,是提取图像特征的方法,多种卷积核可以提取多种特征。每一种卷积核生成的图像都叫做一个通道,这回也就理解了photoshop中“通道”的概念了吧
一个卷积核覆盖的原始图像的范围(上面就是5*5矩阵范围)叫做感受野(receptive field),这个概念来自于生物学
请尊重原创,转载请注明来源网站以及原始链接地址
利用一次卷积运算(哪怕是多个卷积核)提取的特征往往是局部的,难以提取出比较全局的特征,因此需要在一层卷积基础上继续做卷积计算 ,这也就是多层卷积,例如下面这个示意图:
这实际上有四层卷积、三层池化、加上一层全连接,经过这些计算后得出的特征再利用常规的机器学习分类算法(如soft-max)做分类训练。上面这个过程是一个真实的人脸识别的卷积神经网络。
上面讲到了池化,池化是一种降维的方法。按照卷积计算得出的特征向量维度大的惊人,不但会带来非常大的计算量,而且容易出现过拟合,解决过拟合的办法就是让模型尽量“泛化”,也就是再“模糊”一点,那么一种方法就是把图像中局部区域的特征做一个平滑压缩处理,这源于局部图像一些特征的相似性(即局部相关性原理)。
具体做法就是对卷积计算得出的特征在局部范围内算出一个平均值(或者取最大值、或者取随机采样值)作为特征值,那么这个局部范围(假如是10*10),就被压缩成了1*1,压缩了100倍,这样虽然更“模糊”了,但是也更“泛化”了。通过取平均值来池化叫做平均池化,通过取最大值来池化叫做最大池化。
卷积神经网络训练过程
上面讲解了卷积神经网络的原理,那么既然是深度学习,要学习的参数在哪里呢?
上面我们讲的卷积核中的因子(&1或&0)其实就是需要学习的参数,也就是卷积核矩阵元素的值就是参数值。一个特征如果有9个值,1000个特征就有900个值,再加上多个层,需要学习的参数还是比较多的。
和多层神经网络(见我的另外一篇文章《
》)一样,为了方便用链式求导法则更新参数,我们设计sigmoid函数作为激活函数,我们同时也发现卷积计算实际上就是多层神经网络中的Wx矩阵乘法,同时要加上一个偏执变量b,那么前向传到的计算过程就是:
如果有更多层,计算方法相同
因为是有监督学习,所以模型计算出的y'和观察值y之间的偏差用于更新模型参数,反向传导的计算方法参考《
》中的反向传导算法:
参数更新公式是:
偏导计算公式是:
其中a的计算公式是:
残差δ的计算公式是:
上面是输出层残差的推导公式和计算方法,下面是隐藏层残差的推导公式和计算方法
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致卷积神经网络在自然语言处理的应用
发表于 12:22|
来源WildML|
作者Denny Britz
摘要:CNN作为当今绝大多数计算机视觉系统的核心技术,在图像分类领域做出了巨大贡献。本文从计算机视觉的用例开始,介绍CNN及其在自然语言处理中的优势和发挥的作用。
当我们听到卷积神经网络(Convolutional&Neural&Network,&CNNs)时,往往会联想到计算机视觉。CNNs在图像分类领域做出了巨大贡献,也是当今绝大多数计算机视觉系统的核心技术,从Facebook的图像自动标签到自动驾驶汽车都在使用。最近我们开始在自然语言处理(Natural&Language&Processing)领域应用CNNs,并取得了一些引人注目的成果。我将在本文中归纳什么是CNNs,怎样将它们应用于NLP。CNNs背后的直觉知识在计算机视觉的用例里更容易被理解,因此我就先从那里开始,然后慢慢过渡到自然语言处理。什么是卷积运算?对我来说,最容易的理解方式就是把卷积想象成作用于矩阵的一个滑动窗口函数。这么说有些拗口,但是用动画显示就很直观了。3x3的滤波器做卷积运算。图片来源:把左侧的矩阵想象成一幅黑白图像。每一个元素对应一个像素点,0表示黑点,1表示白点(灰度图的像素值一般是0~255)。移动窗口又称作核、滤波器或是特征检测器。这里我们使用3x3的滤波器,将滤波器与矩阵对应的部分逐元素相乘,然后求和。我们平移窗口,使其扫过矩阵的所有像素,对整幅图像做卷积运算。你也许有些疑惑,刚才的操作究竟会有什么效果呢。我们就来看几个直观的例子。用邻近点像素值的均值替换其原值,实现图像模糊的效果:& & & & & &&用邻近点像素值与自身的差值替换其原值,实现边缘检测的效果:(为了直观地来理解,想想图像中平滑的那些部分,那些像素点与周围像素的颜色几乎一致:求和的结果趋近于0,相当于黑色。如果有一条明显的边缘线,比如黑白分界线,那么像素值的差值将会很大,相当于白色)&&里还有一些其它的例子。想要深入了解卷积运算的原理,我推荐阅读Chris&Olah写的。什么是卷积神经网络?现在你明白了什么是卷积运算了吧。那CNNs又是什么呢?CNNs本质上就是多层卷积运算,外加对每层的输出用非线性激活函数做转换,比如用和。在传统的前馈神经网络中,我们把每个输入神经元与下一层的输出神经元相连接。这种方式也被称作是全连接层,或者仿射层。在CNNs中我们不这样做,而是用输入层的卷积结果来计算输出。这相当于是局部连接,每块局部的输入区域与输出的一个神经元相连接。对每一层应用不同的滤波器,往往是如上图所示成百上千个,然后汇总它们的结果。这里也涉及到池化层(降采样),我会在后文做解释。在训练阶段,CNN基于你想完成的任务自动学习滤波器的权重值。举个例子,在图像分类问题中,第一层CNN模型或许能学会从原始像素点检测到一些边缘线条,然后根据边缘线条在第二层检测出一些简单的形状,然后基于这些形状检测出更高级的特征,比如脸部轮廓等。最后一层是利用这些高级特征的一个分类器。这种计算方式有两点值得我们注意:位置不变性和组合性。比如说你想对图片中是否包含大象做分类。因为滤波器是在全图范围内平移,所以并不用关心大象究竟在图片的什么位置。事实上,池化也有助于平移、旋转和缩放的不变性,它对克服缩放因素的效果尤其好。第二个关键因素是(局部)组合性。每个滤波器对一小块局部区域的低级特征组合形成更高级的特征表示。这也是CNNs对计算机视觉作用巨大的原因。我们可以很直观地理解,线条由像素点构成,基本形状又由线条构成,更复杂的物体又源自基本的形状。那么,如何将它们用于NLP呢?NLP任务的输入不再是像素点了,大多数情况下是以矩阵表示的句子或者文档。矩阵的每一行对应于一个分词元素,一般是一个单词,也可以是一个字符。也就是说每一行是表示一个单词的向量。通常,这些向量都是word&embeddings(一种底维度表示)的形式,如和,但是也可以用one-hot向量的形式,也即根据词在词表中的索引。若是用100维的词向量表示一句10个单词的句子,我们将得到一个10x100维的矩阵作为输入。这个矩阵相当于是一幅“图像”。在计算机视觉的例子里,我们的滤波器每次只对图像的一小块区域运算,但在处理自然语言时滤波器通常覆盖上下几行(几个词)。因此,滤波器的宽度也就和输入矩阵的宽度相等了。尽管高度,或者区域大小可以随意调整,但一般滑动窗口的覆盖范围是2~5行。综上所述,处理自然语言的卷积神经网络结构是这样的(花几分钟时间理解这张图片,以及维度是如何变化的。你可以先暂时忽略池化操作,我们在稍后会解释它):用于句子分类器的卷积神经网络(CNN)结构示意图。这里我们对滤波器设置了三种尺寸:2、3和4行,每种尺寸各有两种滤波器。每个滤波器对句子矩阵做卷积运算,得到(不同程度的)特征字典。然后对每个特征字典做最大值池化,也就是只记录每个特征字典的最大值。这样,就由六个字典生成了一串单变量特征向量(univariate&feature&vector),然后这六个特征拼接形成一个特征向量,传给网络的倒数第二层。最后的softmax层以这个特征向量作为输入,用其来对句子做分类;我们假设这里是二分类问题,因此得到两个可能的输出状态。来源:Zhang,&Y.,&&&Wallace,&B.&(2015).&A&Sensitivity&Analysis&of&(and&Practitioners’&Guide&to)&Convolutional&Neural&Networks&for&Sentence&Classification.计算机视觉完美的直观感受这里还存在吗?位置不变性和局部组合性对图像来说很直观,但对NLP却并非如此。你也许会很在意一个词在句子中出现的位置。相邻的像素点很有可能是相关联的(都是物体的同一部分),但单词并不总是如此。在很多种语言里,短语之间会被许多其它词所隔离。同样,组合性也不见得明显。单词显然是以某些方式组合的,比如形容词修饰名词,但若是想理解更高级特征真正要表达的含义是什么,并不像计算机视觉那么明显了。由此看来,卷积神经网络似乎并不适合用来处理NLP任务。(Recurrent&Neural&Network)更直观一些。它们模仿我们人类处理语言的方式(至少是我们自己所认为的方式):从左到右的顺序阅读。庆幸的是,这并不意味着CNNs没有效果。。实际上CNNs对NLP问题的效果非常理想。正如(Bag&of&Words&model),它明显是基于错误假设的过于简化模型,但这不影响它多年来一直被作为NLP的标准方法,并且取得了不错的效果。CNNs的主要特点在于速度快。非常的快。卷积运算是计算机图像的核心部分,在GPU级别的硬件层实现。相比于,CNNs表征方式的效率也更胜一筹。由于词典庞大,任何超过3-grams的计算开销就会非常的大。即使Google也最多不超过5-grams。卷积滤波器能自动学习好的表示方式,不需要用整个词表来表征。那么用尺寸大于5行的滤波器完全合情合理了。我个人认为许多在第一层学到的滤波器扑捉到的特征与n-grams非常相似(但不局限),但是以更紧凑的方式表征。CNN的超参数在解释如何将CNNs用于NLP任务之前,先来看一下构建CNN网络时需要面临的几个选择。希望这能帮助你更好地理解相关文献。窄卷积&vs&宽卷积在上文中解释卷积运算的时候,我忽略了如何使用滤波器的一个小细节。在矩阵的中部使用3x3的滤波器没有问题,在矩阵的边缘该怎么办呢?左上角的元素没有顶部和左侧相邻的元素,该如何滤波呢?解决的办法是采用补零法(zero-padding)。所有落在矩阵范围之外的元素值都默认为0。这样就可以对输入矩阵的每一个元素做滤波了,输出一个同样大小或是更大的矩阵。补零法又被称为是宽卷积,不使用补零的方法则被称为窄卷积。1D的例子如图所示:窄卷积&vs&宽卷积。滤波器长度为5,输入长度为7。来源:A&Convolutional&Neural&Network&for&Modelling&Sentences&(2014)当滤波器长度相对输入向量的长度较大时,你会发现宽卷积很有用,或者说很有必要。在上图中,窄卷积输出的长度是&(7-5)+1=3,宽卷积输出的长度是(7+2*4-5)+1=11。一般形式为步长卷积运算的另一个超参数是步长,即每一次滤波器平移的距离。上面所有例子中的步长都是1,相邻两个滤波器有重叠。步长越大,则用到的滤波器越少,输出的值也越少。下图来自斯坦福的,分别是步长为1和2的情况:卷积步长。左侧:步长为1,右侧:步长为2。来源:&在文献中我们常常见到的步长是1,但选择更大的步长会让模型更接近于,其结构就像是一棵树。池化层卷积神经网络的一个重要概念就是池化层,一般是在卷积层之后。池化层对输入做降采样。常用的池化做法是对每个滤波器的输出求最大值。我们并不需要对整个矩阵都做池化,可以只对某个窗口区间做池化。例如,下图所示的是2x2窗口的最大值池化(在NLP里,我们通常对整个输出做池化,每个滤波器只有一个输出值):CNN的最大池化。来源:&为什么要池化呢?有许多原因。&池化的特点之一就是它输出一个固定大小的矩阵,这对分类问题很有必要。例如,如果你用了1000个滤波器,并对每个输出使用最大池化,那么无论滤波器的尺寸是多大,也无论输入数据的维度如何变化,你都将得到一个1000维的输出。这让你可以应用不同长度的句子和不同大小的滤波器,但总是得到一个相同维度的输出结果,传入下一层的分类器。池化还能降低输出结果的维度,(理想情况下)却能保留显著的特征。你可以认为每个滤波器都是检测一种特定的特征,例如,检测句子是否包含诸如“not&amazing”等否定意思。如果这个短语在句子中的某个位置出现,那么对应位置的滤波器的输出值将会非常大,而在其它位置的输出值非常小。通过采用取最大值的方式,能将某个特征是否出现在句子中的信息保留下来,但是无法确定它究竟在句子的哪个位置出现。这个信息出现的位置真的很重要吗?确实是的,它有点类似于一组n-grams模型的行为。尽管丢失了关于位置的全局信息(在句子中的大致位置),但是滤波器捕捉到的局部信息却被保留下来了,比如“not&amazing”和“amazing&not”的意思就大相径庭。在图像识别领域,池化还能提供平移和旋转不变性。若对某个区域做了池化,即使图像平移/旋转几个像素,得到的输出值也基本一样,因为每次最大值运算得到的结果总是一样的。通道我们需要了解的最后一个概念是通道。通道即是输入数据的不同“视角”。比如说,做图像识别时一般会用到RGB通道(红绿蓝)。你可以对每个通道做卷积运算,赋予相同或不同的权值。你也同样可以把NLP想象成有许多个通道:把不同类的词向量表征(例如和)看做是独立的通道,或是把不同语言版本的同一句话看作是一个通道。卷积神经网络在自然语言处理的应用我们接下来看看卷积神经网络模型在自然语言处理领域的实际应用。我试图去概括一些研究成果。希望至少能够涵盖大部分主流的成果,难免也会遗漏其它一些有意思的应用(请在评论区提醒我)。最适合CNNs的莫过于分类任务,如语义分析、垃圾邮件检测和话题分类。卷积运算和池化会丢失局部区域某些单词的顺序信息,因此纯CNN的结构框架不太适用于PoS&Tagging和Entity&Extraction等顺序标签任务(也不是不可能,你可以尝试输入位置相关的特征)。文献[1&在不同的分类数据集上评估CNN模型,主要是基于语义分析和话题分类任务。CNN模型在各个数据集上的表现非常出色,甚至有个别刷新了目前最好的结果。令人惊讶的是,这篇文章采用的网络结构非常简单,但效果相当棒。输入层是一个表示句子的矩阵,每一行是word2vec词向量。接着是由若干个滤波器组成的卷积层,然后是最大池化层,最后是softmax分类器。该论文也尝试了两种不同形式的通道,分别是静态和动态词向量,其中一个通道在训练时动态调整而另一个不变。文献[2]中提到了一个类似的结构,但更复杂一些。文献[6]在网络中又额外添加了一个层,用于语义聚类。Kim,&Y.&(2014).&卷积神经网络用来语句分类文献[4]从原始数据训练CNN模型,不需要预训练得到word2vec或GloVe等词向量表征。它直接对one-hot向量进行卷积运算。作者对输入数据采用了节省空间的类似词袋表征方式,以减少网络需要学习的参数个数。在文献[5]中作者用了CNN学习得到的非监督式“region&embedding”来扩展模型,预测文字区域的上下文内容。这些论文中提到的方法对处理长文本(比如影评)非常有效,但对短文本(比如推特)的效果还不清楚。凭我的直觉,对短文本使用预训练的词向量应该能比长文本取得更好的效果。搭建一个CNN模型结构需要选择许多个超参数,我在上文中已经提到了一些:输入表征(word2vec,&GloVe,&one-hot),卷积滤波器的数量和尺寸,池化策略(最大值、平均值),以及激活函数(ReLU,&tanh)。文献[7]通过多次重复实验,比较了不同超参数对CNN模型结构在性能和稳定性方面的影响。如果你想自己实现一个CNN用于文本分类,可以借鉴该论文的结果。其主要的结论有最大池化效果总是好于平均池化;选择理想的滤波器尺寸很重要,但也根据任务而定需;正则化在NLP任务中的作用并不明显。需要注意的一点是该研究所用文本集里的文本长度都相近,因此若是要处理不同长度的文本,上述结论可能不具有指导意义。文献[8]探索了CNNs在关系挖掘和关系分类任务中的应用。除了词向量表征之外,作者还把词与词的相对位置作为卷积层的输入值。这个模型假设了所有文本元素的位置已知,每个输入样本只包含一种关系。文献[9]和文献[10]使用的模型类似。来自微软研究院的文献[11]和&[12]介绍了CNNs在NLP的另一种有趣的应用方式。这两篇论文介绍了如何学习将句子表示成包含语义的结构,它能被用来做信息检索。论文中给出的例子是基于用户当前的阅读内容,为其推荐其它感兴趣的文档。句子的表征是基于搜索引擎的日志数据训练得到的。大多数CNN模型以这样或是那样的训练方式来学习单词和句子的词向量表征,它是训练过程的一部分。并不是所有论文都关注这一步训练过程,也并不在乎学到的表征意义有多大。文献[13]介绍了用CNN模型对Facebook的日志打标签。这些学到的词向量随后又被成功应用于另一个任务&——&基于点击日志给用户推荐感兴趣的文章。字符层面的CNNs模型至此,所有的模型表征都是在单词的层面上。另外有一些团队则研究如何将CNNs模型直接用于字符。文献[14]学到了字符层面的向量表征,将它们与预训练的词向量结合,用来给语音打标签。文献[15]和[16]研究了直接用CNNs模型直接从字符学习,而不必预训练词向量了。值得注意的是,作者使用了一个相对较深的网络结构,共有9层,用来完成语义分析和文本分类任务。结果显示,用字符级输入直接在大规模数据集(百万级)上学习的效果非常好,但用简单模型在小数据集(十万级)上的学习效果一般。文献[17]是关于字符级卷积运算在语言建模方面的应用,将字符级CNN模型的输出作为LSTM模型每一步的输入。同一个模型用于不同的语言。令人惊讶的是,上面所有论文几乎都是发表于近两年。显然CNNs模型在NLP领域已经有了出色的表现,新成果和顶级系统还在层出不穷地出现。若有疑问或是反馈,请在评论区留言。谢谢阅读!&参考文献&[1]&&[2]&&[3]&&[4]&&[5]&&[6]&&[7]&&[8]&[9]&&[10]&&[11]&&[12][13][14]&[15]&[16]&[17]&原文链接:(译者/赵屹华&审核/刘翔宇、朱正贵 责编/周建丁 原创/翻译投稿请联系:,微信号:jianding_zhou)译者简介:,计算广告工程师@搜狗,前生物医学工程师,关注推荐算法、机器学习领域。将于-12日在北京隆重举办。在主会之外,会议还设立了16大分论坛,包含数据库、深度学习、推荐系统、安全等6大技术论坛,金融、制造业、交通旅游、互联网、医疗健康、教育等7大应用论坛和3大热点议题论坛,。&
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章Deep Learning(182)
& & & &本文的所有代码均可在&&找到,欢迎点星星。
& & & & 注.CNN的这份代码非常慢,基本上没有实际使用的可能,所以我只是发出来,代表我还是实践过而已
& & & & & &CNN这个模型实在是有些年份了,最近随着深度学习的兴起又开始焕发青春了,把imagenet测试的准确度提高了非常多,一个是Alex的工作,然后最近好像又有突破性的成果,可惜这些我都没看过,主要是imagenet的数据太大了,我根本没有可能跑得动,所以学习的积极性有些打折扣。不说那么多,还是先实现一个最基础的CNN再说吧:
& & & & &好吧,基本是根据的结构按照&&来写的,大家可以先看这里的代码讲解:
& & & & &本来是想根据Notes那篇文章来写的,只是最后发现如果给subsampling层加上sigmoid之后整个结构就不收敛了~~~,我用numeric_grad_check检测发现梯度计算也是对的,不明所以~~~这份代码我也上传了(),不过下面的代码最后就只能改成稍简化版的,貌似通常情况下CNN的pooling(subsampling)层也是没有sigmoid的,先这样吧,这个东西理解起来简单还是写了我两个下午……伤……
& & & 代码:&
from __future__ import division
import numpy as np
import scipy as sp
from scipy.signal import convolve as conv
from dml.tool import sigmoid,expand,showimage
from numpy import rot90
'''
this algorithm have refered to the DeepLearnToolBox(/rasmusbergpalm/DeepLearnToolbox)
also:[1]:&Notes on Convolutional Neural Networks& Jake Bouvrie 2006 - How to implement CNNs
I want to implement as [1] described,where the subsampling layer have sigmoid function
but finally it does not converge,but I can pass the gradcheck!!
(this version is dml/CNN/cnn.py.old ,if you can figure out what is wrong in the code,PLEASE LET ME KNOW)
at last I changed code back to simple version,delete the sigmoid in 's' layer
ps:this code in python is too slow!don't use it do anything except reading.
'''
class LayerC:
def __init__(self,types='i',out=0,scale=0,kernelsize=0):
self.types=types
self.a=None
self.b=None
self.d=None
if (types=='i'):
elif (types=='c'):
self.out=out
self.kernelsize=kernelsize
self.k=None
elif (types=='s'):
self.scale=scale
self.Beta={}
self.dBeta={}
class CNNC:
def __init__(self,X,y,layers,opts):
self.X=np.array(X)
self.y=np.array(y)
self.layers=layers
self.opts=opts
inputmap = 1
mapsize = np.array(self.X[0].shape)
for i in range(len(self.layers)):
if self.layers[i].types=='s':
mapsize = mapsize / self.layers[i].scale
assert np.sum(np.floor(mapsize)== mapsize)==mapsize.size
self.layers[i].b={}
self.layers[i].db={}
for j in range(inputmap):
self.layers[i].b.setdefault(j,0)
self.layers[i].db.setdefault(j,0)
self.layers[i].Beta.setdefault(j,1)
self.layers[i].dBeta.setdefault(j,0.0)
if self.layers[i].types=='c':
mapsize = mapsize - self.layers[i].kernelsize + 1
fan_out = self.layers[i].out*self.layers[i].kernelsize**2
self.layers[i].k={}
self.layers[i].dk={}
self.layers[i].b={}
self.layers[i].db={}
for j in range(self.layers[i].out):
fan_in = inputmap*self.layers[i].kernelsize**2
for t in range(inputmap):
self.layers[i].k.setdefault(t,{})
self.layers[i].k[t].setdefault(j)
self.layers[i].k[t][j]=(np.random.rand(self.layers[i].kernelsize,self.layers[i].kernelsize)-
0.5)*2*np.sqrt(6/(fan_out+fan_in))
self.layers[i].dk.setdefault(t,{})
self.layers[i].dk[t].setdefault(j)
self.layers[i].dk[t][j]=np.zeros(self.layers[i].k[t][j].shape)
self.layers[i].b.setdefault(j,0)
self.layers[i].db.setdefault(j,0)
inputmap=self.layers[i].out
if self.layers[i].types=='i':
fvnum = np.prod(mapsize)*
onum = self.y.shape[0];
self.ffb=np.zeros((onum,1))
self.ffW=(np.random.rand(onum, fvnum)-0.5)*2*np.sqrt(6/(onum+fvnum))
def cnnff(self,x):
self.layers[0].a={}
self.layers[0].a.setdefault(0)
self.layers[0].a[0]=x.copy()
inputmap=1
n=len(self.layers)
for l in range(1,n):
if self.layers[l].types=='s':
for j in range(inputmap):
temp=np.ones((self.layers[l].scale,self.layers[l].scale))/(self.layers[l].scale**2)
z=conv(self.layers[l-1].a[j],np.array([temp]), 'valid')
z=np.array(z)[:,::self.layers[l].scale,::self.layers[l].scale]
if self.layers[l].a==None:
self.layers[l].a={}
self.layers[l].a.setdefault(j)
self.layers[l].a[j] =z
if self.layers[l].types=='c':
if self.layers[l].a==None:
self.layers[l].a={}
for j in range(self.layers[l].out): #for each outmaps
z = np.zeros(self.layers[l-1].a[0].shape - np.array([0,self.layers[l].kernelsize-1,self.layers[l].kernelsize-1]))
for i in range(inputmap):
#cumulate from inputmaps
z+=conv(self.layers[l-1].a[i],np.array([self.layers[l].k[i][j]]),'valid')
self.layers[l].a.setdefault(j)
self.layers[l].a[j]=sigmoid(z+self.layers[l].b[j])
inputmap = self.layers[l].out
self.fv=None
for j in range(len(self.layers[n-1].a)):
sa=self.layers[n-1].a[j].shape
p=self.layers[n-1].a[j].reshape(sa[0],sa[1]*sa[2]).copy()
if (self.fv==None):
self.fv=np.concatenate((self.fv,p),axis=1)
self.fv=self.fv.transpose()
self.o=sigmoid(np.dot(self.ffW,self.fv) + self.ffb)
def cnnbp(self,y):
n=len(self.layers)
self.e=self.o-y
self.L=0.5*np.sum(self.e**2)/self.e.shape[1]
self.od=self.e*(self.o*(1-self.o))
self.fvd=np.dot(self.ffW.transpose(),self.od)
if self.layers[n-1].types=='c':
self.fvd=self.fvd*(self.fv*(1-self.fv))
sa=self.layers[n-1].a[0].shape
fvnum=sa[1]*sa[2]
for j in range(len(self.layers[n-1].a)):
if self.layers[n-1].d==None:
self.layers[n-1].d={}
self.layers[n-1].d.setdefault(j)
self.layers[n-1].d[j]=self.fvd[(j*fvnum):((j+1)*fvnum),:].transpose().reshape(sa[0],sa[1],sa[2])
for l in range(n-2,-1,-1):
if self.layers[l].types=='c':
for j in range(len(self.layers[l].a)):
if self.layers[l].d==None:
self.layers[l].d={}
self.layers[l].d.setdefault(j)
self.layers[l].d[j]=self.layers[l].a[j]*(1-self.layers[l].a[j])*
np.kron(self.layers[l+1].d[j],np.ones(( self.layers[l+1].scale,self.layers[l+1].scale))/(self.layers[l+1].scale**2))
elif self.layers[l].types=='s':
for j in range(len(self.layers[l].a)):
if self.layers[l].d==None:
self.layers[l].d={}
self.layers[l].d.setdefault(j)
z=np.zeros(self.layers[l].a[0].shape)
for i in range(len(self.layers[l+1].a)):
rotated=np.array([rot90(self.layers[l+1].k[j][i],2)])
z=z+conv(self.layers[l+1].d[i],rotated,'full')
self.layers[l].d[j]=z
for l in range(1,n):
m=self.layers[l].d[0].shape[0]
if self.layers[l].types=='c':
for j in range(len(self.layers[l].a)):
for i in range(len(self.layers[l-1].a)):
#self.layers[l].dk[i][j]=rot90(conv(self.layers[l-1].a[i],rot90(self.layers[l].d[j],2),'valid'),2)
self.layers[l].dk[i][j]=self.layers[l].dk[i][j]*0
for t in range(self.layers[l].d[0].shape[0]):
self.layers[l].dk[i][j]+=rot90(conv(self.layers[l-1].a[i][t],rot90(self.layers[l].d[j][t],2),'valid'),2)
self.layers[l].dk[i][j]=self.layers[l].dk[i][j]/m
self.layers[l].db[j]=np.sum(self.layers[l].d[j])/m
self.dffW=np.dot(self.od,self.fv.transpose())/self.od.shape[1]
self.dffb = np.mean(self.od,1).reshape(self.ffb.shape);
def cnnapplygrads(self,alpha=0.1):
n=len(self.layers)
for l in range(1,n):
if self.layers[l].types=='c':
for j in range(len(self.layers[l].a)):
for i in range(len(self.layers[l-1].a)):
self.layers[l].k[i][j]-=alpha*self.layers[l].dk[i][j]
self.layers[l].b[j]-=alpha*self.layers[l].db[j]
self.ffW-=alpha*self.dffW
self.ffb-=alpha*self.dffb
def train(self):
m=self.X.shape[0]
batchsize=self.opts['batchsize']
numbatches = m/batchsize
print numbatches
self.rL = []
for i in range(self.opts['numepochs']):
print 'the %d -th epoch is running'% (i+1)
kk=np.random.permutation(m)
for j in range(numbatches):
print 'the %d -th batch is running , totally
%d batchs'% ((j+1),numbatches)
batch_x=self.X[kk[(j)*batchsize:(j+1)*batchsize],:,:].copy()
batch_y=self.y[:,kk[(j)*batchsize:(j+1)*batchsize]].copy()
nff(batch_x)
nbp(batch_y)
napplygrads(alpha=self.opts['alpha'])
if len(self.rL)==0:
self.rL.append(self.L)
p=self.rL[len(self.rL)-1]
self.rL.append(p*0.99+0.1*self.L)
print self.L
def gradcheck(self,test_x,test_y):
#github上有这部分代码
def test(self,test_x,test_y):
nff(np.array(test_x))
p=self.o.argmax(axis=0)
bad= np.sum(p!=np.array(test_y).argmax(axis=0))
print p,np.array(test_y).argmax(axis=0)
print np.array(test_y).shape[1]
er=bad/np.array(test_y).shape[1]
def pred(self,test_x):
nff(np.array(test_x))
p=self.o.argmax(axis=0)
& & 因为python跑这个实在是太慢了,主要原因我觉得是convolution函数(我用的scipy.signal.convolve)比matlab里慢太多了,所以跑MNIST以50为一个patch跑SGD一轮要二三十分钟,所以建议不要使用这份代码,你可以去用DeepLearnToolbox比这都快……
& 使用代码来测试:
& & & & &&
layers=[LayerC('i'),
LayerC('c',out=6,kernelsize=5),
LayerC('s',scale=2),
LayerC('c',out=12,kernelsize=5),
LayerC('s',scale=2)]
opts['batchsize']=40
opts['numepochs']=1
opts['alpha']=1
a=CNNC(X,groundTruth,layers,opts)
#a.gradcheck(test_x[1:3,:,:],test_groundTruth[:,1:3])
a.test(test_x,test_groundTruth)
& 这是一轮的结果,89.99%的准确度,应该还是正常的: &
& & & & & & & &
from:&/?p=6350
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1361753次
积分:22592
积分:22592
排名:第240名
原创:427篇
转载:3135篇
评论:175条
(99)(222)(17)(127)(159)(189)(317)(382)(479)(217)(348)(477)(286)(113)(8)(1)(72)(11)(10)(21)(11)
----------coding----------
----------MLCV----------
----------IT笔试面试----------
----------大数据云计算----------
----------Math----------

我要回帖

更多关于 卷积神经网络 的文章

 

随机推荐