卷积神经网络实现
ResNet网络实现
ResNet网络在图像分类算是经典之作,2015 ILSVRC分类竞赛中遥遥领先,一个简单的 shortcut connection解决了网络随深度加深而衰退的问题。这论文值得我多啃几遍,没直接迁移keras模块中网络结构,一步步Debug瞅瞅网络,整一个图像3分类。
数据处理
1.数据库分割
-
原始数据: 猫-1000张, 狗-1000张, 熊猫-1000张
-
目标数据:训练集-1800, 验证集- 600, 测试集- 600.每个数据集不同类别各在一个目录下.
步骤
- 所有数据目录
all_file_paths=[[..类别0目录..],[..类别1目录..],[..类别2目录..]], 类别标签index_label_dict=[0,1,2] - 训练目录
train_file_path=[[0,..0目录(数目为0中训练数目)..],[1,..1目录..],[2,..2目录..]],运用random.shuffle打乱数据顺序 -
__copy_files复制按照格式
2.数据生成器
- 训练集,验证集,测试集分别做,操作相同
- 导入目录和标签,数据目录
all_image_path,数据标签all_image_label(0,1,2数字格式) 一一对应。 - 制作成tensor格式,图像
image_dataset运用.map操作把图像载入预处理处理,label也变为tensor格式label_dataset;把标签和图像zip到一起dataset = tf.data.Dataset.zip((image_dataset, label_dataset))。 - 制作
batch格式,对于训练集需要 打乱shuffle,注意:需要指定buffer_size设为训练样本数即可。
网络模型
ResNet(残差网络)原理
-
卷积神经网络遇到的问题:按道理加深网络层数可以提取更深入的信息,但是实际上加深网络会使得网络衰退,就是网络层数增加,错误增加,退化问题。
-
解决方案:
In this paper, we address the degradation problem by introducing a deep residual learning framework. Instead of hoping each few stacked layers directly fit a desired underlying mapping, we explicitly let these layers fit a residual mapping.
说人话,就是原先网络新加的层F(x)是直接和下一层H(x)连接的。现在让F(x)=H(x)-x,那么H(x)=F(x)+x.
-
这样的好处就是,如果极端而言,右边的x(identity mapping)很优秀了,那么F(x)很容易就变为0,这样也就相当于这层特征提取的太差,就把他扔了,下一层继续提取(但实际不会这么极端)。直接把x拿过来这跟线就是shortcut connection,不会增加网络额外的参数和复杂度,并且不会变为0。
-
这里的F(x)必须是两层或者更多层的网络,如果是单层那么又等价为线性层。如果F(x)和x维度一致,可以直接相加的;如果不一致对x进行一个维度变换,文章提出两种方案,一是直接加0,二是用1*1的卷积卷一下来增加维度(二效果更好)。
-
卷积设置和VGG一样,大多是3*3卷积,遵循两个原则::(i)对于相同的输出特征图尺寸,各层有相同数量的滤波器; (ii)如果将特征图的大小(尺寸)减半(用步长为2的卷积进行下采样),则过滤器的数量将增加一倍,以保持每一层的时间复杂度。卷积之后,Relu**之前,增加Batch Normalization(BN)防止梯度消失。
比较可以看出来,同样网络构造,ResNet中34层要比18层优秀。不仅如此。18层虽然结果相似,但是ResNet更快收敛。
-
ResNet模型实现
ResNet_50为例
整体构架
包括三个主要部分:预处理、conv_x层(彩色部分),和最后全连接层。每个conv_x层是由几个Res block组成。
预处理
预处理就是一个7*7卷积,步长为2,特征图尺寸减半,加BN,Relu**和一个最大池化。
conv_x层
conv_x层由几个Res_block组成, 不同层的block数目不同,但是结构都相似。主要由3个卷积构成,1*1卷积层负责减少然后增加/恢复维度,3 *3的卷积就是特征提取了。卷积和Relu之间有Batch Normalization(BN),最后一个卷积在相加之后才加**函数Relu。
有可能x和F(x)维度不一样,所以每个卷积conv_x层中的block_1和剩余的block处理有些不同,以conv2_x为例,见右侧虚线,只表示卷积层,BN和Relu省略。
-
block_1
分左右两路,最后两路相加。
-
左边经过三个卷积,第二个卷积中有一个/1, 就是步长为1(特征图尺度不变,还是55*55),因为前面池化已经特征图缩小一倍,这里就不缩放了。其他conv_x层都会在此处 /2(特征图尺度减半)。
-
右边进行一个1*1的卷积的原因是让左右两侧特征图的维度一致,可以相加。
-
-
后续的block
由于后续卷积左边的特征图尺度和维度都不变化,所以并不需要右侧变换,直接和原始相加即可。
全连接层
经过4个conv_x之后,再加入7*7池化层,提取得到2048特征,最后连接全连接层。原文没有加dropout,我数据集很小,图像像素低,分3类,并没加7 *7 池化,多增加了一层全连接层,并增加了dropout,防止过拟合。
定义损失和优化器
损失采用 SparseCategoricalCrossentropy,优化选用最陡梯度下降法,学习率这个参数啊,原文是随着训练次数降低学习率,我只是简单粗暴的随便设置了一下。
训练和测试
Demo一下,图像输入是32*32的,跑了10个epoch,数据也不是很多,最后验证集准确率凑乎70%多。在测试集上看来,就这个像素,我看着都挺费劲,蓝色为正确的,红色为错误的。