50
50
51
51
前面说到在图像领域,用传统的神经网络并不合适。我们知道,图像是由一个个像素点构成,每个像素点有三个通道,分别代表RGB颜色,那么,如果一个图像的尺寸是(28,28,1),即代表这个图像的是一个长宽均为28,channel为1的图像(channel也叫depth,此处1代表灰色图像)。如果使用全连接的网络结构,即,网络中的神经与与相邻层上的每个神经元均连接,那就意味着我们的网络有 `28 * 28 =784` 个神经元,hidden层采用了15个神经元,那么简单计算一下,我们需要的参数个数(w和b)就有: `784*15*10+15+10=117625` 个,这个参数太多了,随便进行一次反向传播计算量都是巨大的,从计算资源和调参的角度都不建议用传统的神经网络。(评论中有同学对这个参数计算不太理解,我简单说一下:图片是由像素点组成的,用矩阵表示的, `28*28` 的矩阵,肯定是没法直接放到神经元里的,我们得把它“拍平”,变成一个`28*28=784` 的一列向量,这一列向量和隐含层的15个神经元连接,就有 `784*15=11760` 个权重w,隐含层和最后的输出层的10个神经元连接,就有 `11760*10=117600` 个权重w,再加上隐含层的偏置项15个和输出层的偏置项10个,就是:117625个参数了)
52
52
53
- ![ ] ( /img/dl/CNN原理/853467-20171031123650574-11330636.png )
53
+ ![ ] ( ../.. /img/dl/CNN原理/853467-20171031123650574-11330636.png)
54
54
55
55
图1 三层神经网络识别手写数字
56
56
62
62
63
63
上文提到我们用传统的三层神经网络需要大量的参数,原因在于每个神经元都和相邻层的神经元相连接,但是思考一下,这种连接方式是必须的吗?全连接层的方式对于图像数据来说似乎显得不这么友好,因为图像本身具有“二维空间特征”,通俗点说就是局部特性。譬如我们看一张猫的图片,可能看到猫的眼镜或者嘴巴就知道这是张猫片,而不需要说每个部分都看完了才知道,啊,原来这个是猫啊。所以如果我们可以用某种方式对一张图片的某个典型特征识别,那么这张图片的类别也就知道了。这个时候就产生了卷积的概念。举个例子,现在有一个4* 4的图像,我们设计两个卷积核,看看运用卷积核后图片会变成什么样。
64
64
65
- ![ ] ( /img/dl/CNN原理/853467-20171104142033154-1330878114.png )
65
+ ![ ] ( ../.. /img/dl/CNN原理/853467-20171104142033154-1330878114.png)
66
66
67
67
图2 4* 4 image与两个2* 2的卷积核操作结果
68
68
@@ -532,7 +532,7 @@ class LayerHelper(object):
532
532
通过上一层2* 2的卷积核操作后,我们将原始图像由4* 4的尺寸变为了3* 3的一个新的图片。池化层的主要目的是通过降采样的方式,在不影响图像质量的情况下,压缩图片,减少参数。简单来说,假设现在设定池化层采用MaxPooling,大小为2* 2,步长为1,取每个窗口最大的数值重新,那么图片的尺寸就会由3* 3变为2* 2:(3-2)+1=2。从上例来看,会有如下变换:
533
533
534
534
535
- ![ ] ( /img/dl/CNN原理/853467-20171104142056685-2048616836.png )
535
+ ![ ] ( ../.. /img/dl/CNN原理/853467-20171104142056685-2048616836.png)
536
536
537
537
图3 Max Pooling结果
538
538
@@ -553,7 +553,7 @@ class LayerHelper(object):
553
553
554
554
所以到现在为止,我们的图片由4* 4,通过卷积层变为3* 3,再通过池化层变化2* 2,如果我们再添加层,那么图片岂不是会越变越小?这个时候我们就会引出“Zero Padding”(补零),它可以帮助我们保证每次经过卷积或池化输出后图片的大小不变,如,上述例子我们如果加入Zero Padding,再采用3* 3的卷积核,那么变换后的图片尺寸与原图片尺寸相同,如下图所示:
555
555
556
- ![ ] ( /img/dl/CNN原理/853467-20171031215017701-495180034.png )
556
+ ![ ] ( ../.. /img/dl/CNN原理/853467-20171031215017701-495180034.png)
557
557
558
558
图4 zero padding结果
559
559
@@ -565,7 +565,7 @@ class LayerHelper(object):
565
565
566
566
到这一步,其实我们的一个完整的“卷积部分”就算完成了,如果想要叠加层数,一般也是叠加“Conv-MaxPooing",通过不断的设计卷积核的尺寸,数量,提取更多的特征,最后识别不同类别的物体。做完Max Pooling后,我们就会把这些数据“拍平”,丢到Flatten层,然后把Flatten层的output放到full connected Layer里,采用softmax对其进行分类。
567
567
568
- ![ ] ( /img/dl/CNN原理/853467-20171104142200763-1912037434.png )
568
+ ![ ] ( ../.. /img/dl/CNN原理/853467-20171104142200763-1912037434.png)
569
569
570
570
图5 Flatten过程
571
571
@@ -586,7 +586,7 @@ class LayerHelper(object):
586
586
1.卷积核的尺寸不一定非得为正方形。长方形也可以,只不过通常情况下为正方形。如果要设置为长方形,那么首先得保证这层的输出形状是整数,不能是小数。如果你的图像是边长为 28 的正方形。那么卷积层的输出就满足 [ (28 - kernel_size)/ stride ] + 1 ,这个数值得是整数才行,否则没有物理意义。譬如,你算得一个边长为 3.6 的 feature map 是没有物理意义的。 pooling 层同理。FC 层的输出形状总是满足整数,其唯一的要求就是整个训练过程中 FC 层的输入得是定长的。如果你的图像不是正方形。那么在制作数据时,可以缩放到统一大小(非正方形),再使用非正方形的 kernel_size 来使得卷积层的输出依然是整数。总之,撇开网络结果设定的好坏不谈,其本质上就是在做算术应用题:如何使得各层的输出是整数。
587
587
588
588
589
- 2.由经验确定。通常情况下,靠近输入的卷积层,譬如第一层卷积层,会找出一些共性的特征,如手写数字识别中第一层我们设定卷积核个数为5个,一般是找出诸如"横线"、“竖线”、“斜线”等共性特征,我们称之为basic feature,经过max pooling后,在第二层卷积层,设定卷积核个数为20个,可以找出一些相对复杂的特征,如“横折”、“左半圆”、“右半圆”等特征,越往后,卷积核设定的数目越多,越能体现label的特征就越细致,就越容易分类出来,打个比方,如果你想分类出“0”的数字,你看到![ ] ( / img/dl/CNN原理/853467-20171031231438107-1902818098.png) 这个特征,能推测是什么数字呢?只有越往后,检测识别的特征越多,试过能识别![ ] ( /img/dl/CNN原理/853467-20171101085737623-1572944193.png ) 这几个特征,那么我就能够确定这个数字是“0”。
589
+ 2.由经验确定。通常情况下,靠近输入的卷积层,譬如第一层卷积层,会找出一些共性的特征,如手写数字识别中第一层我们设定卷积核个数为5个,一般是找出诸如"横线"、“竖线”、“斜线”等共性特征,我们称之为basic feature,经过max pooling后,在第二层卷积层,设定卷积核个数为20个,可以找出一些相对复杂的特征,如“横折”、“左半圆”、“右半圆”等特征,越往后,卷积核设定的数目越多,越能体现label的特征就越细致,就越容易分类出来,打个比方,如果你想分类出“0”的数字,你看到![ ] ( ../../ img/dl/CNN原理/853467-20171031231438107-1902818098.png) 这个特征,能推测是什么数字呢?只有越往后,检测识别的特征越多,试过能识别![ ] ( ../.. /img/dl/CNN原理/853467-20171101085737623-1572944193.png) 这几个特征,那么我就能够确定这个数字是“0”。
590
590
591
591
592
592
3.有stride_w和stride_h,后者表示的就是上下步长。如果用stride,则表示stride_h=stride_w=stride。
@@ -632,7 +632,7 @@ def convolutional_neural_network_org(img):
632
632
633
633
那么这个时候我考虑的问题是,既然上面我们已经了解了卷积核,改变卷积核的大小是否会对我的结果造成影响?增多卷积核的数目能够提高准确率?于是我做了个实验:
634
634
635
- ![ ] ( /img/dl/CNN原理/853467-20171031232805748-157396975.png )
635
+ ![ ] ( ../.. /img/dl/CNN原理/853467-20171031232805748-157396975.png)
636
636
637
637
* 第一次改进:仅改变第一层与第二层的卷积核数目的大小,其他保持不变。可以看到结果提升了0.06%
638
638
* 第二次改进:保持3* 3的卷积核大小,仅改变第二层的卷积核数目,其他保持不变,可以看到结果相较于原始参数提升了0.08%
0 commit comments