1、resnet残差网络
(1)较深的网络比较浅的网络性能更差。 一个创新的想法:如果什么也没学到,那就比以前更糟:因此提出了identity map(也称为shortcut连接)。 H(x)= x + F(x),F(x)= H(x)-x,称为残差。
(2)ResNet的深度各不相同,从18层到34、50、101到非常深的152层。
(3)不同的快捷方式,如果不更改尺寸,则可以使用identity映射。 但是在实践中,尺寸更改因此会产生“瓶颈”。 (这在基线后记中很流行,因为它可以保存参数。)
残差单元:
跨层连接:要求输入x:feature map的shape与输出F(x):feature map 的shape一样。
可能存在的情况:
①输入x与输出F(x) 的shape一样直接相加
②输入x输出F(x) 的feature map数量及feature map尺寸不一样
如:输入x:[1, 64, 224, 224]输出F(x) :[1, 128, 112, 112]
需要对输入x通过卷积层各参数调整,确保与F(x)一致
相邻的x 与F(x)通道不一致,fp也相差一倍
import torch.nn as nn
import torch
#残差单元
class Block(nn.Module):
def __init__(self,inch,outch,stride):
super(Block, self).__init__()
self.con1=nn.Conv2d(inch,outch,3,stride,1)
self.con2=nn.Conv2d(outch,outch,3,1,1)
self.relu=nn.ReLU()
self.bn=nn.BatchNorm2d(outch)
if inch!=outch:
self.downsample=nn.Conv2d(inch,outch,1,stride)#输入与输出通道不一致,调整通道并通过步长调整特征图
else:
self.downsample=None
def forward(self,x):
pre=x
out=self.con1(x)
out=self.relu(out)
out=self.bn(out)
out=self.con2(out)
out = self.bn(out)
if self.downsample is not None:#
pre=self.downsample(x)
out+=pre#跨层连接相加:x+F(x)
out = self.relu(out)
return out
class mynet(nn.Module):
def __init__(self,Block):
super(mynet, self).__init__()
self.layer1=nn.Sequential(nn.Conv2d(3,64,3,1,1),
nn.BatchNorm2d(64),
nn.MaxPool2d(2))#64,224
self.layer2=self.layer(Block,64,64,3,1)
self.layer3 = self.layer(Block, 64, 128,4, 2)#连续有4个残差单元除了第一个要增加通道,后面保持与上个一样
self.layer4 = self.layer(Block, 128, 256, 6,2)
self.layer5 = self.layer(Block, 256, 512, 3, 2)
def layer(self,Block,inch,outch,blocknum,stride):
layers=[]
layers.append(Block(inch,outch,stride))#主要负责调整每个block的特征图及通道
for i in range(blocknum-1):
layers.append(Block(outch,outch,1))#普通的卷积操作并且通道一致
return nn.Sequential(*layers)#以列表形式放在序列化中
def forward(self,x):
x1=self.layer1(x)
print(x1.shape)
x2 = self.layer2(x1)
print(x2.shape)
x3 = self.layer3(x2)
print(x3.shape)
x4 = self.layer4(x3)
print(x4.shape)
x5 = self.layer5(x4)
print(x5.shape)
return x1,x2
x=torch.randn(1,3,448,448)
model=mynet(Block)
y1,y2=model(x)
# print(y1.shape,y2.shape)
2、Googlenet中inception单元
(1)除了增加网络深度之外(对于googlenet v1为22层),还会增加网络的宽度
(2)引入较小的内核,1 * 1卷积,减小尺寸并保存参数。 参数:AlexNet ~ 12 GoogLeNet, VGG ~ 3 AlexNet
(3)初始模块很容易添加或删除,它是模仿人的大脑以建立稀疏连接。
import torch
import torch.nn as nn
class inception(nn.Module):
def __init__(self,inch,outch):
super(inception, self).__init__()
self.con1=nn.Conv2d(inch,outch,1,1)
self.con2=nn.Conv2d(inch,outch,3,1,1)
self.con3=nn.Conv2d(inch,outch,5,1,2)
self.maxpool=nn.MaxPool2d(3,1,1)
def forward(self,x):
out1=self.con1(x)
out2=self.con2(x)
out3=self.con3(x)
out4=self.maxpool(x)
out=torch.cat((out1,out2,out3,out4),dim=1)#特征融合
return out
class mynet(nn.Module):
def __init__(self,inception):
super(mynet, self).__init__()
self.layer1=nn.Sequential(
nn.Conv2d(3, 64, 3, 1, 1),
nn.MaxPool2d(2)
)
self.layer2=inception(64,64)
def forward(self,x):
x=self.layer1(x)
x=self.layer2(x)
return x
x=torch.randn(1,3,448,448)
model=mynet(inception)
y=model(x)
print(y.shape)
3、Yolov3
①无yolo层的darknet53 主干网络backbone:
import torch
import torch.nn as nn
import torch.nn.functional as F
class ResidualBlock(nn.Module):
def __init__(self,inch,outch):
super(ResidualBlock, self).__init__()
self.conv1=nn.Sequential(nn.Conv2d(inch,outch,1,1),
nn.BatchNorm2d(outch),
nn.LeakyReLU())
self.conv2=nn.Sequential(nn.Conv2d(outch,inch,3,1,1),
nn.BatchNorm2d(inch),
nn.LeakyReLU())
def forward(self, x):
identity=x
out=self.conv1(x)
out=self.conv2(out)
out+=identity
return out
class Darknet53(nn.Module):
def __init__(self,ResidualBlock):
super(Darknet53, self).__init__()
self.firstblock=nn.Sequential(nn.Conv2d(3,32,3,1,1),
nn.BatchNorm2d(32),
nn.LeakyReLU()
)
self.conv1 = nn.Conv2d(32, 64, 3, 2, 1)
self.resblock1=self.block(ResidualBlock,32,64,1)
self.conv2 = nn.Conv2d(64, 128, 3, 2, 1)
self.resblock2 = self.block(ResidualBlock, 64, 128, 2)
self.conv3 = nn.Conv2d(128, 256, 3, 2, 1)
self.resblock3 = self.block(ResidualBlock, 128, 256, 8)
self.conv4 = nn.Conv2d(256, 512, 3, 2, 1)
self.resblock4 = self.block(ResidualBlock, 256, 512, 8)
self.conv5 = nn.Conv2d(512, 1024, 3, 2, 1)
self.resblock5 = self.block(ResidualBlock, 512, 1024, 4)
def block(self,ResidualBlock,inch, outch, numblock):
layers=[]
# layers.append(nn.Conv2d(inch,outch,3,2,1))
for i in range(numblock - 1):
layers.append(ResidualBlock(outch,inch))
return nn.Sequential(*layers)
def forward(self,x):
out=self.firstblock(x)
out=self.conv1(out)
out=self.resblock1(out)
out = self.conv2(out)
out = self.resblock2(out)
out = self.conv3(out)
fp_52 = self.resblock3(out)
out = self.conv4(fp_52)
fp_26 = self.resblock4(out)
out = self.conv5(fp_26)
fp_13 = self.resblock5(out)
return fp_52,fp_26,fp_13
inputs=torch.randn(1,3,416,416)
model=Darknet53(ResidualBlock)
sc1,sc2,sc3=model(inputs)
print(sc1.shape,sc2.shape,sc3.shape)
②含有YOLO层的网络
将输出调整为:(batch,3*(x,y,w,h,conf,cls1…cls20),fp,fp)
这里20类加上两个坐标点,宽高,置信度共25,fp为 feature map的大小。
import torch
import torch.nn as nn
import torch.nn.functional as F
class ResidualBlock(nn.Module):
def __init__(self,inch,outch):
super(ResidualBlock, self).__init__()
self.conv1=nn.Sequential(nn.Conv2d(inch,outch,1,1),
nn.BatchNorm2d(outch),
nn.LeakyReLU())
self.conv2=nn.Sequential(nn.Conv2d(outch,inch,3,1,1),
nn.BatchNorm2d(inch),
nn.LeakyReLU())
def forward(self, x):
identity=x
out=self.conv1(x)
out=self.conv2(out)
out+=identity
return out
class UpsampleLayer(nn.Module):
def __init__(self):
super(UpsampleLayer, self).__init__()
def forward(self, x):
return F.interpolate(x, scale_factor=2, mode='nearest')
class ConvolutionalSetLayer(nn.Module):
def __init__(self,inch,outch):
super(ConvolutionalSetLayer, self).__init__()
self.conv=nn.Sequential(
nn.Conv2d(inch, outch, 1, 1),
nn.Conv2d(outch, inch, 3, 1, 1),
nn.Conv2d(inch, outch, 1, 1),
nn.Conv2d(outch, inch, 3, 1, 1),
nn.Conv2d(inch, outch, 1, 1)
)
def forward(self,x):
return self.conv(x)
class Darknet53(nn.Module):
def __init__(self,ResidualBlock):
super(Darknet53, self).__init__()
self.firstblock=nn.Sequential(nn.Conv2d(3,32,3,1,1),
nn.BatchNorm2d(32),
nn.LeakyReLU()
)
self.conv1 = nn.Conv2d(32, 64, 3, 2, 1)
self.resblock1=self.block(ResidualBlock,32,64,1)
self.conv2 = nn.Conv2d(64, 128, 3, 2, 1)
self.resblock2 = self.block(ResidualBlock, 64, 128, 2)
self.conv3 = nn.Conv2d(128, 256, 3, 2, 1)
self.resblock3 = self.block(ResidualBlock, 128, 256, 8)
self.conv4 = nn.Conv2d(256, 512, 3, 2, 1)
self.resblock4 = self.block(ResidualBlock, 256, 512, 8)
self.conv5 = nn.Conv2d(512, 1024, 3, 2, 1)
self.resblock5 = self.block(ResidualBlock, 512, 1024, 4)
self.conset13=nn.Sequential(ConvolutionalSetLayer(1024,512))
self.conset26 = nn.Sequential(ConvolutionalSetLayer(768, 256))
self.conset52 = nn.Sequential(ConvolutionalSetLayer(384, 128))
self.yololy1=nn.Sequential(
nn.Conv2d(512, 1024, 3, 1, 1),
nn.BatchNorm2d(1024),
nn.LeakyReLU(),
nn.Conv2d(1024,75,1,1)
)
self.yololy2 = nn.Sequential(
nn.Conv2d(256, 512, 3, 1, 1),
nn.BatchNorm2d(512),
nn.LeakyReLU(),
nn.Conv2d(512, 75, 1, 1)
)
self.yololy3 = nn.Sequential(
nn.Conv2d(128, 256, 3, 1, 1),
nn.BatchNorm2d(256),
nn.LeakyReLU(),
nn.Conv2d(256, 75, 1, 1)
)
self.up1=nn.Sequential(
nn.Conv2d(512, 256, 1, 1),
UpsampleLayer()
)
self.up2 = nn.Sequential(
nn.Conv2d(256, 128,1, 1),
UpsampleLayer()
)
def block(self,ResidualBlock,inch, outch, numblock):
layers=[]
# layers.append(nn.Conv2d(inch,outch,3,2,1))
for i in range(numblock - 1):
layers.append(ResidualBlock(outch,inch))
return nn.Sequential(*layers)
def forward(self,x):
out=self.firstblock(x)
out=self.conv1(out)
out=self.resblock1(out)
out = self.conv2(out)
out = self.resblock2(out)
out = self.conv3(out)
fp_52 = self.resblock3(out)
out = self.conv4(fp_52)
fp_26 = self.resblock4(out)
out = self.conv5(fp_26)
fp_13 = self.resblock5(out)
convset13=self.conset13(fp_13)
yoloout1=self.yololy1(convset13)
up1=self.up1(convset13)
route1=torch.cat((up1,fp_26),1)
convset26=self.conset26(route1)
yoloout2=self.yololy2(convset26)
up2=self.up2(convset26)
route2=torch.cat((up2,fp_52),1)
convset52=self.conset52(route2)
yoloout3=self.yololy3(convset52)
return yoloout1,yoloout2,yoloout3
inputs=torch.randn(1,3,416,416)
model=Darknet53(ResidualBlock)
print(model)
sc1,sc2,sc3=model(inputs)
print(sc1.shape,sc2.shape,sc3.shape)
还有yolov4等网络结构,具体的见博客:传送门