卷积神经网络实现

ResNet网络实现

ResNet网络在图像分类算是经典之作,2015 ILSVRC分类竞赛中遥遥领先,一个简单的 shortcut connection解决了网络随深度加深而衰退的问题。这论文值得我多啃几遍,没直接迁移keras模块中网络结构,一步步Debug瞅瞅网络,整一个图像3分类。

【程序喵笔记】Resnet实现分类

数据处理

1.数据库分割

  • 原始数据: 猫-1000张, 狗-1000张, 熊猫-1000张

  • 目标数据:训练集-1800, 验证集- 600, 测试集- 600.每个数据集不同类别各在一个目录下.

    【程序喵笔记】Resnet实现分类

步骤

  • 所有数据目录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实现分类

网络模型

ResNet(残差网络)原理

  • 卷积神经网络遇到的问题:按道理加深网络层数可以提取更深入的信息,但是实际上加深网络会使得网络衰退,就是网络层数增加,错误增加,退化问题。

    【程序喵笔记】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.

    【程序喵笔记】Resnet实现分类

    • 这样的好处就是,如果极端而言,右边的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实现分类

    比较可以看出来,同样网络构造,ResNet中34层要比18层优秀。不仅如此。18层虽然结果相似,但是ResNet更快收敛。

ResNet模型实现

ResNet_50为例

【程序喵笔记】Resnet实现分类

整体构架

包括三个主要部分:预处理、conv_x层(彩色部分),和最后全连接层。每个conv_x层是由几个Res block组成。

【程序喵笔记】Resnet实现分类

预处理

预处理就是一个7*7卷积,步长为2,特征图尺寸减半,加BN,Relu**和一个最大池化。

【程序喵笔记】Resnet实现分类

conv_x层

conv_x层由几个Res_block组成, 不同层的block数目不同,但是结构都相似。主要由3个卷积构成,1*1卷积层负责减少然后增加/恢复维度,3 *3的卷积就是特征提取了。卷积和Relu之间有Batch Normalization(BN),最后一个卷积在相加之后才加**函数Relu。

【程序喵笔记】Resnet实现分类

有可能x和F(x)维度不一样,所以每个卷积conv_x层中的block_1和剩余的block处理有些不同,以conv2_x为例,见右侧虚线,只表示卷积层,BN和Relu省略。

【程序喵笔记】Resnet实现分类

  • block_1

    分左右两路,最后两路相加。

    【程序喵笔记】Resnet实现分类

    • 左边经过三个卷积,第二个卷积中有一个/1, 就是步长为1(特征图尺度不变,还是55*55),因为前面池化已经特征图缩小一倍,这里就不缩放了。其他conv_x层都会在此处 /2(特征图尺度减半)。

    • 右边进行一个1*1的卷积的原因是让左右两侧特征图的维度一致,可以相加。

  • 后续的block

    由于后续卷积左边的特征图尺度和维度都不变化,所以并不需要右侧变换,直接和原始相加即可。

    【程序喵笔记】Resnet实现分类

全连接层

经过4个conv_x之后,再加入7*7池化层,提取得到2048特征,最后连接全连接层。原文没有加dropout,我数据集很小,图像像素低,分3类,并没加7 *7 池化,多增加了一层全连接层,并增加了dropout,防止过拟合。

【程序喵笔记】Resnet实现分类

定义损失和优化器

损失采用 SparseCategoricalCrossentropy,优化选用最陡梯度下降法,学习率这个参数啊,原文是随着训练次数降低学习率,我只是简单粗暴的随便设置了一下。

训练和测试

Demo一下,图像输入是32*32的,跑了10个epoch,数据也不是很多,最后验证集准确率凑乎70%多。在测试集上看来,就这个像素,我看着都挺费劲,蓝色为正确的,红色为错误的。

【程序喵笔记】Resnet实现分类

【程序喵笔记】Resnet实现分类

【程序喵笔记】Resnet实现分类

【程序喵笔记】Resnet实现分类

相关文章:

  • 2021-09-28
  • 2021-05-14
  • 2021-06-23
  • 2021-11-18
  • 2021-12-25
  • 2021-09-19
猜你喜欢
  • 2021-10-08
  • 2022-12-23
  • 2021-09-08
  • 2022-12-23
  • 2021-07-14
  • 2021-06-22
相关资源
相似解决方案