基本介绍:
CNN里面最重要的构建单元就是卷积层。卷积层是局部连接,卷积是参数共享(一个卷积核去扫描整个图像)
经过每层卷积层得到的结果我们叫做Feature map(特征图)。
神经元在第一个卷积层不是连接输入图片的每个像素,知识链接他们感受野的像素,以此类推第二个卷积层的每一个神经元仅连接位于第一个卷积层的小方块的神经元。
图像维介绍度:
一个图像有三个维度(h,w,c)== (高,宽 ,通道),那么,有时候我们也叫c这个维度叫做深度,对于多个图像就再加一个维度图像个数(m,h,w,c)
黑白图像有一个通道,彩色图像三个通道。所以对于黑白图像(m,h,w,1),彩色图像(m,h,w,3)
卷积的计算
假设有一个5*5的图像,使用一个3*3的filter卷积核进行卷积,想得到一个3*3的Feature map
我们用3*3的卷积核进行扫描(这里扫面计算机可以同时并行计算)。当卷积核扫描第一个位置的时候,卷积核的数字和原图像的位置的数字进行相乘再相加然后再加上一个截距项得到Feature map第一个位置的数字。扫描可以设置步长。
卷积层是局部连接,可以使得w参数比全连接变少。
对于三通道图片,三个通道分别对应的是R,G,B(有时候也可能是4通道,透明度我们一般不会用到,如果我们读出来是(h,w,4)那么我们就要用切片获取前面三个通道。)
那么对应的卷积核也应该是三通道的,卷积核的每个通道卷积核去扫描相应原图通道的像素点。
(假如原图像是彩色图像是三通道,那么卷积核也要设置三通道)当然卷积核高和宽可以人为的改变。
卷积核的个数我们可以去人为设置,有几个卷积核,最终就有几个输出结果。卷积核大小一般是1*1,3*3,5*5。
每一个卷积核生成一个Feature map
我们需要设置的超参数:num_filters,kernel_size(3*3*3)
对于上面的三通道的原图,我们使用两个卷积核,每个卷积核也必须是三通道。
那么两个卷积核要求的参数总共就是num_filters*(kernel_h+kernel_w*kernel_c+1)
2*3*3*3+2=56
那么第一个feature map的第一个数字6就是每一个通道扫描相乘相加后的结果再相加再加上一个截距项。
最终feature map有几个数字,就有几个输出节点。(也可以通过这种方式降维)
stride步长
最终生成的Feature map大小取决于卷积核设置的步长。同样大小的图像和卷积核设置不一样的步长,生成的feature map大小不一样
padding模式
VAILD:不使用zero padding,如果不进行填充,那么卷积核再扫描的时候,如果向左或者向右进行扫描,扫描的时候有空白,那么卷积核就会对这次扫描不进行计算,那么有可能会忽略图片右侧或底下。
那么如果图片本身右侧或者底下跟图片想表达的内容没有关系,那么可以用VAILD进行忽略。
SAME:必要的时候会去zero pedding,然后用步长是1的卷积核进行扫描,用same模式的时候是给图像周边添加一圈0,这样在扫描的时候会把每一个像素点都看得很重要。
用same添加一圈0后,第一次扫描就把原图像最周边的像素点作为中心点,依次扫描下去,这样的话整个图像每一个像素点都看得很重要。
填充多少圈0?kernel_size-图像大小/步长的余数
生成多大的feature map? 用图像大小/步长结果向上取整。例如步长是2,原图高宽是5,那么ceil(5/2)=3
same步长是1*1是最常用的。
当我们进行卷积的时候,用same模式用的比较多。
特征图大小计算方式
池化Pooling
池化是接在卷积层后面。
池化的作用是将采样,一般我们卷积层之间会有一层池化层,这层池化的目的是进行降采样,通过降采样使得下一层卷积的计算量减少。
池化核:池化和一般是2*2大小,步长为2,里面没有权重值,只是将池化圈住的数值取最大或者取平均,假如有四个格,那么就只会取出一个,长和宽两倍小,面积四倍小,丢掉百分之七十五的值。
池化也有Valde和Same,那么池化主要用Valde模式。
池化不同于卷积,卷积会将每个通道计算后的结果再汇总,但是池化对于每个通道不会进行汇总,对于每个通道单独进行计算。
# 卷积层
tf.keras.layers.Conv2D(filters, kernel_size, strides=(1, 1),
padding='vaild', activation=None)
# 池化层
tf.keras.layers.MaxPool2D(pool_size=(2, 2), strides=None, padding='vaild')
tf.keras.layers.AvgPool2D(pool_size=(2, 2), strides=None, padding='same')
CNN架构
一个卷积层后跟Relu层,然后再跟池化层,在跟卷积层后跟Relu层,然后再跟池化层,通过网络传递让图片越来越小,也越来越深。
池化会减少参数。
输入图片先经过卷积层(有图片可以看出图片大小没有变,所以这里的卷积层是步长1*1的SAME模式,那么生成了5个feature map,那么卷积层是有5个卷积核)
在卷积后会接Relu.
经过卷积和Relu后,还要经过池化层(这里池化层面积大概是原来图片的四分之一,所以用的VALID模式,步长是2*2,池化核也是2*2)
再跟卷积层(SAME模式,卷积核数量增加)
在卷积后会接Relu.
再跟池化(VALID模式,步长是2*2,池化核也是2*2)
以此类推...
最后一个四位数组,将四维数组reshape成一个二维数组(m,h,w,c)==(m,h*w*c)
再跟两个全连接层
最后经过softmax输出。
经过两层池化后,最后的图片是原来的四分之一。
所以经过两层池化长宽是
如果是经过5层池化长宽是原来的
总结:
卷积层:提取图像特征
池化层:降维,防止过拟合
全连接层:输出结果
在CNN架构里,统计层数包含卷积层和全连接曾,不包含池化层。
代码示例:
import tensorflow as tf
from tensorflow.keras.datasets import mnist
# 导入数据
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 数据处理,做维度调整
train_images = tf.reshape(x_train, (x_train.shape[0], x_train.shape[1], x_train.shape[2], 1))
test_images = tf.reshape(x_test, (x_test.shape[0], x_test.shape[1], x_test.shape[2], 1 ))
# 模型构建
net = tf.keras.models.Sequential([
# 卷积层 6个5*5的卷积核 sigmoid激活函数
tf.keras.layers.Conv2D(filters=6, kernel_size=5, activation="sigmoid", input_shape=(28, 28, 1)),
# 池化层(最大池化)
tf.keras.layers.MaxPool2D(pool_size=2, strides=2),
# 卷积层 16 5*5 sigmoid
tf.keras.layers.Conv2D(filters=16, kernel_size=5, activation="sigmoid"),
# 池化层 (最大池化)
tf.keras.layers.MaxPool2D(pool_size=2, strides=2),
# 接全连接层之间将数据抻平
tf.keras.layers.Flatten(),
# 全连接层
tf.keras.layers.Dense(120, activation="sigmoid"),
# 全连接层
tf.keras.layers.Dense(84, activation="sigmoid"),
# 输出层
tf.keras.layers.Dense(10, activation="softmax")
])
print(net.summary())
# 模型编译
net.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.9),
loss=tf.keras.losses.sparse_categorical_crossentropy,
metrics=["accuracy"])
# 训练模型
net.fit(train_images, y_train, epochs=5, batch_size=128, verbose=1)
# 模型评估
print("模型评估分数")
net.evaluate(test_images, y_test, verbose=1)