文章目录
前言
这次飞桨的论文复现的作业是要求去将pytorch的resnet50模型来用paddle来实现,因为我以前根本没有接触过pytorch,所以这里面实现起来还是有点困难的,然后我们这里就开始实现吧!
基础
这里面给了一个pytorch的链接:https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py
但是我有点看不懂,我先去了解一下resnet50的模型结构是什么样的?我看了半天只是懂了点皮毛,然后我们一会结合代码实际看看!
然后这里面说是要对比最后两者的权重啥的,那个我torch的我直接去使用了一下别人已经得到的权重吧,然后将它的权重和我用paddle去实现的权重做一个对比。
resnet50网络结构
这里我们来看一下resnet50的网络结构:
参考:https://zhuanlan.zhihu.com/p/353235794
从这个图上我们可以看到主要是分成了5个步骤,这里输入的图片格式为:(3,224,224),然后第一层的话是一个7x7的卷积核,个数为64个,这个就是可以代表我们可以去提取特征的数目,然后卷积的步长为2,然后得到的是(3,112,1112)大小的形式,这里可能有人会问了,这是怎么得到的,卷积的计算过程是什么呢?那这里我们先来回顾一下卷积神经网络的基础
参考:https://www.paddlepaddle.org.cn/tutorials/projectdetail/1516119
卷积神经网络基础
在应用卷积之前是怎么做的呢?是将数据变成一维的进行计算,这里可以借鉴我以前的手写数字识别的文章,数据的大小就是WXH,但是这种方法有很多的弊端:空间信息丢失和当图片过大的话,数据就会呈平方式的增长,那样的话会导致参数过大引起过拟合。而使用卷积的话就不会,因为输入的还是原来的形式不用变成一维的,然后就是卷积核也不会受到图片的大小的影响
卷积
这里我们先看一下卷积的运算过程,看下面这张图:
这里先要去看卷积核就是中间的那个,然后在左面去对应,之后对应相乘相加得到结果
从这个图中我们可以看到,最后得到的形式与卷积核的大小一致,但是加了填充和步幅就不一定了
然后我们来看看下一步:
就是这样,相当于一个滑动的窗口在滑动,每滑动一次做一次卷积。
这里我们会发现通过卷积的时候输出的形式会变小,为了防止这种事情的发生我们这里可以去使用填充来解决,先看一下特征图的计算过程:
然后我们看下什么叫做填充:
填充
这里的话我们再计算一下:比如用4X4的输入与3X3的卷积进行计算,特征图是4-3+1=2
但是我们用1的填充后,输入变成了6X6,然后在计算一下特征图,为6-3+1=4,这样就不改变形式了
最后我们给出一个通用的公式,这样不用去计算填充后的输入,只要用原输入就可以啦
我们重新计算一下:4+2-3+1=4,ph指的是填充
之后我们看一下步幅:
步幅
这个是最好理解的,就是滑动的间隔的像素点:
然后的话有了步幅,那么得到的特征图的大小就有不一样了,这里我们给出最后的公式:
我们来计算一下:(4+0-2)/2 +1 =2
上面的内容可能我们了解的比较多,但是接下来的感受野可能就不是了解的很清楚了
感受野
感受野理解起来并不是很难,因为我们在输入图像经历卷积的时候,每个卷积核大小的面积区域就会得到一个点,那个那个原图像的区域就是特征图的对应的点的感受野,根据网络结构的加深,感受野会越来越大。
批量操作
这里面输出多少个特征图是由N决定的,特征图的通道数是由卷积核的数目决定的!已上面的图为例:N=2,所以最后也会生成2个特征图,然后卷积核为2,所以特征图通道数也为2
API介绍
这里主要用到下面这个API:
如果是图像处理就要2D,如果是视频处理就要用3D,然后说说这里面的参数,第一个是输入图像的通道数,比如说RGB图像就是3,然后是输出的通道数,上面我们也说了,就是卷积核的数目,接下来是卷积核的大小,然后是步长,填充
池化
介绍完了卷积,我们来说说池化!下面看一下这个图:
当我们得到特征图后,可以用一个值来代替一个区域的值,常用的是平均值池化和最大值池化,这样就可以减少特征图的大小从而减小计算量,然后我们看一下计算过程:
(4+0-2)/2 +1 = 2 大体上和我们上面的卷积计算过程差不多
在卷积神经网络中通常会用到2X2的池化窗口,并且步幅也为2,这时的话,输出特征图大小是原来特征图大小的一半
Relu激活函数
在以前的时候用sigmoid会多一点,但是因为会出现梯度消失的情况,所以现在多用Relu函数
批归一化(Batch Normalization)
这个也叫做BN层, 在ResNet中也是应用到了,其目的是对神经网络中间层的输出进行标准化处理,使得中间层的输出更加稳定。我们一般会对数据去使用归一化但是随着网络结构的深入,数据对后面的层影响就不那么大了,所以我们也要对中间层的输出也做归一化处理,这样有很多好处:可以加快收敛,使用更大的学习率去学习,最重要的可以抑制过拟合
丢弃法Dropout
这也是一种抑制过拟合的方法:
这里面丢弃的是随机的!
学到这里差不多了,我们来继续上面的去看ResNet的网络结构!
再看ResNet网络结构
党部整除的时候:卷积向下取整,池化向上取整。
我们来说下过程,第一层的话是(224-7)/2 +1= 109呀,为什么这上面写的是112呀,为啥呀?气死我了,弄了半个点才弄明白是因为这里面有一个3的填充,然后我们计算一下:(224-7+6)/2 + 1=112.5 = 112,合理了,哈哈。然后接下来是一个最大池化,我们计算一下:(112+0-3)/2+1=55.5=56,合理,这回会算了,然后到这步我们的特征图的形状为(64,56,56)。然后下面我们结合代码去做
paddle代码实现
这里先说一下1X1卷积核的重要性,它不是为了改变特征图的大小而是为了改变特征图的维度,通过使用改变卷积核的数目来改变维度的大小。
然后像下面这种结构我们也称为瓶颈结构:
因为输入的维度是256,先通过1X1的卷积核,将维度变成64,然后进行3x3的卷积操作,之后在经历1X1的卷积来增加维度为256,这样大大减少了计算的参数。我们在来看一下示意图: