1,为什么提出ResNet网络?
在不断加深的神经网络的深度时,会出现退化的问题,即准确率会先上升然后达到饱和,再持续增加深度后其准确率下降了。这不是由于过拟合导致的,因为这不仅导致训练集上误差增大,测试集上误差也增大。原因是随着网络越来越深,训练变得越来越难,网络的优化变得越来越难。理论上,层度越深的网络其学习到语义信息越丰富,提取的特征效果会越好;但是,实际上,由于深度增加导致网络难以训练,产生网络退出问题,其效果还没有浅层网络的好。而残差网络的出现解决了这个问题。
2,残差网络的创新点
文章的基本思想是:在理想化的深层神经网络中,如果后面的网络层是恒等映射(残差块),那么随着残差块的增加(深度增加)至少网络的效果不会比浅层的差。
(1)引入了残差结构,设想残差映射比起普通的堆叠层的映射更容易优化
(2)使用了zero padding和1x1投影的方式解决了分辨率和深度不一样的特征图相加的问题。
3,残差结构
残差是指实际观察值和估计值之间的差,残差块的输入为x,拟合的输出为H(x),如果我们直接把输入x直接传到输出作为观测结果,那么需要学习的残差就是F(x)=H(x)-x.
残差块的计算方式:
残差块的输出:
残差块的优化目标:预测输出H(x)=x,即输出H(x)与x的差别;使残差F(x)=H(x)-x,尽量使F(x)为0
残差为什么更容易实现优化:
一般网络实现恒等映射的方式是拟合一个函数使H(x)=x,但是直接拟合这个恒等隐式难度很大。而引入残差后,它将拟合函数H(x)=x转化为F(x)=H(x)-x形式,通过在残差块中加入batchnorm normalization等方式,可以使网络更为容易实现F(x)=0,从而实现H(x)=x,即实现了恒等映射。
同时,引入残差块后也使映射对输出变化更敏感。设是加入skip连接前的网络映射,是加入skip连接后的网络映射。对于输入x=5,设此时H1(5)=5.1,H2(5)=F(5)+5=5.1,即F(5)=0.1.当输出变为5.2时,H1(x)由5.1变为5.2,F(x)由0.1变为0.2,明显后者输出变化对权重调整作用大,效果更好。残差的思想是去掉相同主体部分,突出微小部分的变化。
4.ResNet网络结构
左边是我们之前提到的残差块,右边则是瓶颈结构了。之所以称为瓶颈结构,因为它两端深度(channel)大,中间小,就像是一个瓶口的颈部。
那为什么要提出这种结构呢?其实主要是解决在更加深的残差网络101或者152中,参数数目的问题。我们从resnet34中看到,特征图的厚度是逐渐加深的,在resnent34中最后几层卷积是512的厚度,那到了resnet152,岂不是上万的厚度,带来的参数数目是巨大的。所以我们看右边的图,输入先经过一个1x1的卷积核降维,将一个256维的输入降到了64维,再使用3x3的卷积提特征,再用1x1的卷积核升维。这样就到了减少参数数目的目的。
本文中用pytorch实现上述表格中Resnet18的结构:
整个网络结构的搭建如下:先构建残差块(BasicBlock),然后在搭建ResNet18网络,网络中有4个layer,每个layer有两个basicblock。其图示结构可以参考以下链接:
https://zhuanlan.zhihu.com/p/163577599
import torch
import torch.nn as nn
import torch.nn.functional as F
#BasicBlock块构建
class BasicBlock(nn.Module):
expansion=1
def __init__(self,inplanes,planes,stride):
super(BasicBlock,self).__init__()
self.s=stride
self.conv1=nn.Conv2d(inplanes,planes,kernel_size=3,stride=stride,padding=1,bias=False)
self.bn1=nn.BatchNorm2d(planes)
self.conv2=nn.Conv2d(planes,planes,kernel_size=3,stride=1,padding=1,bias=False)
self.bn2=nn.BatchNorm2d(planes)
self.shortcut=nn.Sequential()
if stride!=1 or inplanes!=self.expansion*planes:
self.shortcut=nn.Sequential(nn.Conv2d(inplanes,planes*self.expansion,kernel_size=1,stride=stride,bias=False),
nn.BatchNorm2d(planes*self.expansion))
def forward(self,x):
out = F.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
cut=self.shortcut(x)
out += self.shortcut(x)
out = F.relu(out)
return out
#ResNet18g构建
class ResNet(nn.Module):
def __init__(self,block,num_block):
super(ResNet,self).__init__()
self.in_planes=64
self.conv1=nn.Conv2d(3,64,kernel_size=7,stride=2,padding=3,bias=False)
self.bn1=nn.BatchNorm2d(64)
self.layer1=self._make_layer(block,64,num_block[0],stride=1)
self.layer2=self._make_layer(block,128,num_block[1],stride=2)
self.layer3=self._make_layer(block,256,num_block[2],stride=2)
self.layer4=self._make_layer(block,512,num_block[3],stride=2)
self.fc=nn.Linear(512*block.expansion,10)
def _make_layer(self,block,planes,numblock,stride):
strides=[stride]+[1]*(numblock-1)
layers=[]
for stride in strides:
layers.append(block(self.in_planes,planes,stride))
self.in_planes=block.expansion*planes
return nn.Sequential(*layers)#*返回迭代的元素
def forward(self,x):
out=F.relu(self.bn1(self.conv1(x)))
out=F.max_pool2d(out,[3,3],stride=2,padding=1)
out=self.layer1(out)
out=self.layer2(out)
out=self.layer3(out)
out=self.layer4(out)
out=F.avg_pool2d(out,4)#1*512*512
out=out.view(out.size(0),-1)
out=self.fc(out)
return out
网络调用:
net=ResNet(BasicBlock,[2,2,2,2])
input=torch.randn(1,3,224,224)
#input=torch.randn(1,64,56,56)
y=net(input)
print(y)
结果:
torch.Size([1, 512])
tensor([[ 0.0466, -0.3549, -0.7361, -0.0907, -0.6479, 0.3554, -0.0383, 0.3438,
-0.3191, 0.0304]], grad_fn=<AddmmBackward>)
残差的深层含义,引入他人博客的
设F为一个残差单元,x是上一个残差单元的输出,代表提取的特征,残差单元的输出为F(x)+x。要知道反向传播是损失函数代表的空间中往更优的方向走。每一次迭代理论上说参数应该更新为满足优化损失函数的数值。我们就当做这个设想成立。现在设想残差单元的输出F(x)+x这个特征比x要差,那么反向传播时,F中的参数该往什么方向上更新呢,当然是往数值更小的方向更新,尽量使得F(X)为0或者近似0。因为这样能保证F(x)+x至少不会比x更差。如果F(x)为0了,或者近似0,说明当前残差单元进行了恒等映射,所得到的特征和上一个单元的特征一样,那么可以说当前单元得到的特征至少不会比上一层的特征差。又因为残差又不可能为0,其数值是往优化损失函数的方向上更新的,所以特征会越来越好。
原文链接:https://blog.csdn.net/qq_34914551/article/details/88088182
残差的应用:
在许多其他论文中看到过引用残差的思想,例如在图像或者点云去噪中,通过网络学习到噪音的分布,然后在将网络输入减去学习到的噪音分布从而学习到原始的图像。即,把原始的噪音图像看作为,n表示噪音分布,P^表示无噪音图像。通过残差学习加噪之后的图像与原始图像之间的差的分布。
参考: