卷积神经网络(CNN)

一、非线性激活函数

  多层的线性网络和单层的线性网络没有区别,线性模型能够解决的问题也是有限的。

  可在此网站观察模拟:Tinker With a Neural Network Right Here in Your Browser.

                               

  使用线性激活函数和不使用激活函数、直接使用Logistic回归没有区别,无论神经网络有多少层,输出都是输入的线性组合,与没有隐藏层效果相当,也就是最原始的感知机。

二、卷积神经网络的引入

  为啥不使用多层的神经网络去处理图像?

  参数太多,千万上亿级别,神经网络的参数更新需要大量的计算,也很难达到好的效果。

  卷积神经网络的引入,减少了网络参数的数量,达到更好的效果。

1、感受野

  概念

     在卷积神经网络中,感受野(Receptive Field)的定义是卷积神经网络每一层输出的特征图(feature map)上的像素点在输入图片上映射的区域大小。再通俗点的解释是,特征图上的一个点对应输入图上的区域,如图所示。

    某一层feature map(特性图)中某个位置的特征向量,是由前面某一层固定区域的输入计算出来的,那这个区域就是这个位置的感受野。

    感受野区域之外图像区域的像素不会影响feature map层的特征向量。

                                    

  作用

  • 一般task要求感受野越大越好,如图像分类中最后卷积层的感受野要大于输入图像,网络深度越深感受野越大性能越好
  • 密集预测task要求输出像素的感受野足够的大,确保做出决策时没有忽略重要信息,一般也是越深越好
  • 目标检测task中设置anchor要严格对应感受野,anchor太大或偏离感受野都会严重影响检测性能

2、边缘检测

   为了能够更少的参数,检测出更多的信息,基于上面的感受野的思想,通常神经网络需要检测出物体最明显的垂直和水平边缘来区分物体。

 三、卷积神经网络结构

组成部分:一个或多个卷积层、池化层以及全连接层等组成

                  

其中包含了几个主要结构

  • 卷积层(Convolutions)
  • 池化层(Subsampling)
  • 全连接层(Full connection)
  • 激活函数

1、卷积层

  • 目的:卷积运算的目的是提取输入的不同特征,某些卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网路能从低级特征中迭代提取更复杂的特征。
  • 参数:缺点:
    • size:卷积核/过滤器大小,选择有1 * 1, 3 * 3, 5 * 5(为什么是奇数个)
    • padding:零填充,Valid 与Same
    • stride:步长,通常默认为1
    • 图像变小
    • 边缘信息丢失
  • 计算公式padding-零填充
  • 零填充:在图片像素的最外层加上若干层0值,若一层,记做p =1。

    为什么增加的是0?

    因为0在权重乘积和运算中对最终结果不造成影响,也就避免了图片增加了额外的干扰信息。

  • Valid and Same卷积

    • valid:不填充
    • same:输出大小与原图大小一致

想一想卷积核大小为啥要奇数层嘞?联想一下padding后输出与原大小一致,怎么计算

增加步长的影响因素之后,计算一下卷积核大小

 

  多通道卷积 

  特征图只有一个

    

 

   多卷积核

卷积层充当特征提取的角色,但是并没有减少图片的特征数量,在最后的全连接层依然面临大量的参数,所以需要池化层进行特征数量的减少

2、池化层

   降低了后续网络层的输入维度,缩减模型大小,提高计算速度;

  提高了Feature Map的鲁棒性,防止过拟合;

池化层主要对卷积层学习到的特征图进行亚采样(subsampling)处理,主要由两种

  • 最大池化:Max Pooling,取窗口内的最大值作为输出
  • 平均池化:Avg Pooling,取窗口内的所有值的均值作为输出

 通用:feature 为2*2,步长step为2

                                                            

3、全连接层

   卷积层+激活层+池化层可以看成是CNN的特征学习/特征提取层,而学习到的特征(Feature Map)最终应用于模型任务(分类、回归):

  • 先对所有 Feature Map 进行扁平化(flatten, 即 reshape 成 1 x N 向量)
  • 再接一个或多个全连接层,进行模型学习

 

四、CIFAR案例

1、模型设计

  • 进行模型编写

    • 两层卷积层+两个神经网络层
    • 网络设计
    • 输入:[None,32*32*3] --> [None,32,32,3]
  • 第一层

    • 卷积:32个filter、大小5*5、strides=1、padding="SAME"  ----->    [None, 32, 32, 32]
    • 激活:Relu           ----->    [None, 32, 32, 32]
    • 池化:大小2x2、strides2          ----->    [None, 16, 16, 32]
  • 第二层
    • 卷积:64个filter、大小5*5、strides=1、padding="SAME"          ----->    [None, 16, 16, 64]
    • 激活:Relu         ----->    [None, 16, 16, 64]
    • 池化:大小2x2、strides2         ----->    [None, 8, 8, 64]
  • 全连接层
    • 第一层神经网络:1024
      •  [None, 8, 8, 64] --> [None,8*8*64] * 权重:[8*8*64,1024],+偏置:[1024]   ---------------> [None,1024]
    • 最后一层全连接层:100(等于类别数)
      • [None,1024]* 权重:[1024,100],+偏置:[100]   -------------> [None,100]

2、完整代码

 1 from tensorflow.python.keras.datasets import cifar100
 2 from tensorflow.python import keras
 3 import tensorflow as tf
 4 
 5 
 6 class CNNMnist(object):
 7 
 8     # 构建模型
 9     model = keras.models.Sequential([
10         # 卷积层1,32个filter、大小5*5、strides=1、padding="SAME"
11         keras.layers.Conv2D(32, kernel_size=5, strides=1, padding="same", data_format="channels_last", activation=tf.nn.relu),
12         # 池化层1,大小2x2、strides2
13         keras.layers.MaxPool2D(pool_size=2, strides=2, padding="same"),
14         # 卷积层2, 64个filter、大小5*5、strides=1、padding="SAME"
15         keras.layers.Conv2D(64, kernel_size=5, strides=1, padding='same', data_format='channels_last', activation=tf.nn.relu),
16         # 池化层, 大小2x2、strides2
17         keras.layers.MaxPool2D(pool_size=2, strides=2, padding="same"),
18         # 全连接层,神经网络
19         keras.layers.Flatten(),
20         # [None, 8, 8, 64] --> [None,8*8*64] * 权重:[8*8*64,1024],+偏置:[1024]   ---------------> [None,1024]
21         keras.layers.Dense(1024, activation=tf.nn.relu),
22         # [None,1024]* 权重:[1024,100],+偏置:[100]   -------------> [None,100]
23         keras.layers.Dense(100, activation=tf.nn.softmax)
24     ])
25 
26 
27     def __init__(self):
28         # 获取数据集
29         (self.x_train, self.y_train), (self.x_test, self.y_test) = cifar100.load_data()
30         # 进行数据归一化
31         self.x_train = self.x_train / 255.0
32         self.x_test = self.x_test / 255.0
33 
34     def compile(self):
35         CNNMnist.model.compile(optimizer=keras.optimizers.Adam(),
36                                loss=keras.losses.sparse_categorical_crossentropy,
37                                metrics=['accuracy'])
38         return None
39 
40     def fit(self):
41         CNNMnist.model.fit(self.x_train, self.y_train, epochs=1, batch_size=32)
42         return None
43 
44     def evaluate(self):
45         test_loss, test_acc = CNNMnist.model.evaluate(self.x_test, self.y_test)
46         print(test_loss, test_acc)
47         return None
48 
49 
50 if __name__ == '__main__':
51     cnn = CNNMnist()
52     cnn.compile()
53     cnn.fit()
View Code

 

 

 

 参考

posted @ 2021-12-03 09:49  luyizhou  阅读(754)  评论(0)    收藏  举报