Resnet梳理和复盘

整理:张一极 2020·0319·19:44

Resnet的跳层连接:

由于过深的网络无法训练的问题,作者将下一层的网络设置为F(x)+ x,不断的叠加之后,可以从第一层,一直堆叠到最后一层,都可以得到有效的训练。

image-20200319194518320

网络结构:

后面三个卷积层组成的网络块和前面最大的区别就是,使用了瓶颈层的结构,小卷积到大卷积再到小卷积,每个网络都是由4个块组成,每个块包含的卷积结构有所不同,但是有共同之处,例如前两个网络结构,18-layer和34-layer,都是由四个块(blocks)组成,每一个块的输入卷积和输出卷积完全一样,这样我们就可以定义一个通用的卷积组合,进行堆叠即可得到不同的网络结构。

image-20200319195015568

解析关于pytorch的实现:

首先写一个函数:

实现了一个通用的3x3的卷积块,我们用它来构筑3x3的卷积层,其中,bias不设置是因为我们后面有bn层,无需设置偏置去修改修复数据分布位移。

接着就是用这个生成卷积层的函数,去实现基础模块,也就是多个组合的卷积层。

就是这两个层,两个3x3的conv,output_channels = 64:

expansion是扩张系数,对应的构造函数,这时候不用在意构造了什么参数,我们之后慢慢写慢慢往上添加,首先是继承自己的这么一句话,super(BasicBlock,self). init(),接着定义一个输入的卷积层,用构筑好的conv3x3,需求参数就是输入通道数目和输出通道数目,接着使用一个归一化层,然后激活层,很标准的conv格式,接下来是第二层,一样标准的卷积格式,然后没有定义激活层是因为我们后面需要对两个block之间跳层相连,需要在激活层之前进行相加,而后再统一激活,故这里我们没有定义激活层,接下来的downsample是下采样的作用,为了保证跳层之间的维度相融,这时候回过头来,我们既然决定了在这里执行下采样,那么就必须在这里输入下采样函数,所以回到参数部分,加入一个downsample参数,然后我们还需要输入维度和输出维度,前向传播里面,一层一层写完以后,我们需要把激活层之前的输出和残差(输入)做一个叠加操作,这个就是Resnet的add,完整代码,如上。

接下来是函数主体部分,首先, 定义好输入通道,也就是64维的,在网络结构图可以看出,接着一个7x7的卷积,bn,然后relu激活层,接着一个pooling,开始定义第一个网络块,这时候的这个定义块函数,我单独解析一遍:

这个downsample函数,定义为一个序列函数,包含一个1x1的卷积和bn,用于改变矩阵的通道数目,至于if的条件,就是我们所说的,通道维度变化的时候,才需要改变通道数目去保证维度相融。

接着建立了一个list,先添加了第一层的参数,第一个块函数,输入通道由函数给定,输出函数也由我们Resnet类给定,至于为什么第一层要单独添加,是因为我们需要在之后把输入通道改成第一层的输出通道,而后是一个循环,循环到最后一个层添加完毕,返回这个list的所有层。

最后,开始搭建网络主体。

下面四行分别代表四大模块:

Resnet类的主体代码:

前向传播较为简单,一层对着一层写即可,最终卷积层之后flatten成全连接可以接受的维度,输出softmax压缩结果。

完整代码:

结果

image-20200319215459193Acc和loss抖动都很大,可能写的比较粗糙了,下次用更复杂的数据实验:

image-20200319215601406

image-20200319215527979

在加入一个策略,图片尺寸resize到较大尺寸之后,随机crop到某个固定尺寸:

有两个点左右的提升

image-20200321134842332

🏃