resnet,inception等网络核心单元代码实现
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=Nonedef forward(self,x):pre=xout=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 outclass 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,224self.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,x2x=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 nnclass 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 outclass 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 xx=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=xout=self.conv1(x)out=self.conv2(out)out+=identityreturn outclass 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_13inputs=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=xout=self.conv1(x)out=self.conv2(out)out+=identityreturn 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等网络结构,具体的见博客:传送门