目录
1 理论部分
卷积神经网络是主要做计算机视觉的网络,当然它不仅仅只能作用于图像,比如也可以应用于语音识别
我们首先清楚一点,计算机看到的图像和我们看到的图像是不一样的,我们可以看到图像中有三条狗,计算机看到的图像是一堆数,那么计算机想要得知这个图上的情况是得找到这一堆数的规律,然后推测出图上有三条狗
一个卷积神经网络大致由下面这几层构成,卷积层是提取特征,非线性层是激活函数,池化层的目的是简化特征,在一张图中我们得到了特征非常多,我们执行一个认识时(判定图片中是猫还是狗)往往不需要这么多特征,池化层减少部分特征,全连接层可以理解为输出层
卷积的运算方式可以看一下这个 24.卷积原理_potato123232的博客-CSDN博客
我们现在比如将边缘提取卷积算子应用一张图像
右侧的图就是提取边缘后的效果
在实际应用中,每一次的卷积核都不是固定的,卷积核在训练的过程中不断修正
1.1 卷积
1.1.1 主要参数
有这么三个参数
- ksize 卷积核大小
像下面这个卷积算子就是一个卷积核,大小为3*3
卷积核的大小一般我们选择3*3或5*5
- strides 跨度
像下面这个图,卷积核运算之后移动两格,这个跨度就是2,如果移动一个格就是1,跨度越大,我们卷积的结果就越小
- padding 边界填充
当我们图像不能正好进行完卷积核移动的时候,这个时候就用到填充了,由于填充的值我们不希望对结果产生影响,所以我们一般填充0,我们也可以选择不填充,如果不填充最后不能达到卷积核大小的图像区域会被跳过
1.1.2 Conv2D中的所有参数
在代码中使用卷积层处理图像使用Conv2D,我们看一下Conv2D的参数,不是所有的参数都常用,我就简单提一下
- filters
卷积核个数,这个和得到的特征图像个数相关
- kernel_size
卷积核大小
- strides
步长
- padding
填充
- data_format
数据格式
- dilation_rate
扩张率
- group
组
- activation
激活函数
- use_bias
是否使用偏置
- kernel_initializer
卷积核初始化
- bias_initalizer
偏置初始化
- bias_regularizer
偏置正则化
- activity_regularizer
输出正则化
- kernel_constraint
卷积核约束
- bias_constraint
偏置约束
1.2 池化
一般是使用最大池化或平均池化,在这个链接中有相应的介绍 24.卷积原理_potato123232的博客-CSDN博客
在代码中我们使用MaxPool2D(最大池化)或AveragePooling2D(平均池化)
它们的参数相同,有下面这么几个参数
- pool_size 池化核大小
- strides 步长
- padding 填充
- data_format 数据类型
1.3 卷积神经网络整体结构
我们可以看到第一步,从一张图像变成了三张图像,这个是卷积核的个数,如果有三个卷积核就得到三张特征图像,有5个卷积核就得到五张特征图像,我前面指的是灰度图像的情况,如果是彩色图像,本身就有三个通道,这三个通道也和特征图像的数量相关
下一步是让特征图像变小,之后一直重复卷积与池化的过程,之后我们就获取了若干个小的特征图像,然后我们将其做为x连到全连接层上,之后我们就可以得出y了
2 代码实现
我们使用CNN对fashion_mnist进行训练
2.1 导入库
导入库之后我们检测一下gpu版的tensorlofw是否可用,在处理图像时,我们需要gpu以达到更快的运算速度
- 对于fashion_mnist不用GPU影响也不大
2.2 加载数据集
2.3 数据处理
之前我们使用的是Flatten将图像变为28*28 = 784 个值的数组,之前那个是一维数据,现在我们要使用卷积神经网络,所以我们要增加数据的维度,我们看之前图像的shape,第一个维度60000是图片的个数,第二个维度28是图片的高,第三个维度28是图像的宽,我们现在要扩出第四个维度用于存放卷积结果(特征图像)个数
2.3.1 增加train_images维度
这里我们使用到了np.expand_dims(),这个方法是用来扩充维度用的,里面的参数是要扩充维度的对象与位置,我们使用-1,维度扩充在最后一位,如果输入0,那么代表维度扩充在第一位
2.3.2 增加test_images维度¶
2.4 建立模型
在卷积神经网络中,第一层我们基本都使用卷积层,在第一层中,我使用32个3*3大小的卷积核,输入数据为(28,28,1),激活函数为relu
第二层我们使用最大池化,此时我没有填写参数,使用的全部为默认参数,默认池化核大小为2*2
第三层我们使用64个3*3的卷积核,激活函数为relu,一般来讲我们在使用卷积神经网络中使用卷积核的个数都是越来越大,比如上一层我们用的是32个卷积核,这一层我们用64个卷积核,这里我们虽然用的还是(3,3)的卷积核,但是我们卷积的是池化后的特征图像(比原图像小),从某种意义上来讲,这一层虽然是(3,3)但放在原图中缺能以更宏观的视角找到图像的特征
第四层我们使用全局平均池化,之后我们链接全连接层dense输出10分类结果
- 卷积核个数我们一般使用2的n次方个
- 在这里我们没有输入padding这个参数,默认padding参数为valid,这个的意思是跳过大小未满足卷积的图像区域
- 我们现在建立的神经网络与之前建立的神经网络都不是最优的神经网络,只是为了更好的展示tensorflow中的API,如果我们要追求更好的预测结果,我们更多的使用Resnet,Alexnet这种有依据且已经验证过的神经网络
我们看一下这个模型
我们看第一层,首先通过一轮卷积,图像由原来的(28,28)变为了(26,26),原本第四维度的数值为1,现在变为了32(卷积核个数),我们再看后面的参数量320,这个320=3*3*32+32
然后进入池化层,默认池化核是(2,2)所以图像减小了一半,第四维数值不变
之后对池化后的图像卷积,图像再一次减小,然后第三维度变为了64(当前卷积核个数),卷积层的输出的第四维是永远和卷积核数量相同的,虽然形状与之前差不多,但是参数量从原来的320变为了18494,这里的18494=3*3*32*64+64
我们的dense层只能接受二维的数据,所以我们针对dense的要求有两种处理方式,一种是使用Flatten层,但这样会引入大量的参数,我们之前使用的模型为(28,28)的,当时使用了700多个参数,另一种就是使用global_average_pooling2d(对所有维度的图像做平均,我们在这里理解为把(11,11)的图像池化为1个值)
2.5 编译模型
2.6 训练模型
我们看一下训练中的值
我们将acc绘制出来看一下
蓝色是acc,橙色是val_acc,可能是由于epoch太多标签没显示出来
再将loss绘制出来看一下
蓝色是loss,橙色是val_loss
我们发现无论是从正确率还是损失来讲,这个模型现在呈现的状态都是过拟合状态,我们接下来简单优化一下模型
2.7 优化模型
我们现在把模型优化成这个样子
在过程中我们更改了padding,这个就是我们是否在乎图像边缘的数据了,如果在乎就用same,如果不在乎就使用默认的value就可以,由于我们之前没有添加padding,导致padding默认为value,所以会使图像在卷积过程中变小,如果我们添加padding为same,就会保持图像的大小,对于现在这个项目padding影响不大
看一下summary
可以看到Drouput前有481万个参数,相比之前的参数多了许多
下面再来看训练过程,由于网络的增大训练过程会比较漫长
最后再看两条曲线
- acc
- loss
虽然最终的效果(准确率与损失)一般,但是确实解决了过拟合的情况