VGG & ResNet


深度学习神经网络特征提取(五)

本文接续前文提到的主干特征提取网络,前文的网络构建主要是基于keras框架构建的,而在深度学习领域pytorch是当前最流行的框架,且深受顶会论文学者的喜爱。因此,在前文已经给出的keras代码的基础上,从这篇文章开始会针对前文网络重新用pytorch构建。

再次给出pytorch代码,还需要注意的是:不同于keraspytorch输入的shape=(3,224,224),通道数在前。关于网络的讲解部分,大家参考前期的文章VGGResnet

VGG16

class VGG16(nn.Module):
    def __init__(self,num_classes):
        super(VGG16,self).__init__()
        #input_shape(3,224,224)
        self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding =1,stride=1)
        self.relu1 = nn.ReLU()
        self.conv2 = nn.Conv2d(64,64,kernel_size=3,padding =1,stride=1)
        self.relu2 = nn.ReLU()
        self.maxpool1 = nn.MaxPool2d(kernel_size=2,stride = 2)

        self.conv3 = nn.Conv2d(64,128,kernel_size=3,padding =1,stride=1)
        self.relu3 = nn.ReLU()
        self.conv4 = nn.Conv2d(128,128,kernel_size=3,padding =1,stride=1)
        self.relu4 = nn.ReLU()
        self.maxpool2 = nn.MaxPool2d(kernel_size=2,stride=2)

        self.conv5 = nn.Conv2d(128,256,kernel_size=3,padding =1,stride=1)
        self.relu5 = nn.ReLU()
        self.conv6 = nn.Conv2d(256,256,kernel_size=3,padding =1,stride=1)
        self.relu6 = nn.ReLU()
        self.conv7 = nn.Conv2d(256,256,kernel_size=3,padding =1,stride=1)
        self.relu7 = nn.ReLU()
        self.maxpool3 = nn.MaxPool2d(kernel_size=2,stride=2)

        self.conv8 = nn.Conv2d(256,512,kernel_size=3,padding =1,stride=1)
        self.relu8 = nn.ReLU()
        self.conv9 = nn.Conv2d(512,512,kernel_size=3,padding =1,stride=1)
        self.relu9 = nn.ReLU()
        self.conv10 = nn.Conv2d(512,512,kernel_size=3,padding =1,stride=1)
        self.relu10 = nn.ReLU()
        self.maxpool4 = nn.MaxPool2d(kernel_size=2,stride = 2)

        self.conv11 = nn.Conv2d(512,512,kernel_size=3,padding =1,stride=1)
        self.relu11 = nn.ReLU()
        self.conv12 = nn.Conv2d(512,512,kernel_size=3,padding =1,stride=1)
        self.relu12 = nn.ReLU()
        self.conv13 = nn.Conv2d(512,512,kernel_size=3,padding =1,stride=1)
        self.relu13 = nn.ReLU()
        self.maxpool5 = nn.MaxPool2d(kernel_size=2,stride = 2)

        self.linear1 = nn.Linear(512*7*7,4096)
        self.relu14 = nn.ReLU()
        self.dropout1 = nn.Dropout(0.5)
        self.linear2= nn.Linear(4096,4096)
        self.relu15 = nn.ReLU()
        self.dropout2 = nn.Dropout(0.5)
        self.linear3= nn.Linear(4096,num_classes)
    def forward(self,x):
        x = self.conv1(x)
        x = self.relu1(x)
        x = self.conv2(x)
        x = self.relu2(x)
        x = self.maxpool1(x)
        x = self.conv3(x)
        x = self.relu3(x)
        x = self.conv4(x)
        x = self.relu4(x)
        x = self.maxpool2(x)

        x = self.conv5(x)
        x = self.relu5(x)
        x = self.conv6(x)
        x = self.relu6(x)
        x = self.conv7(x)
        x = self.relu7(x)
        x = self.maxpool3(x)

        x = self.conv8(x)
        x = self.relu8(x)
        x = self.conv9(x)
        x = self.relu9(x)
        x = self.conv10(x)
        x = self.relu10(x)
        x = self.maxpool4(x)

        x = self.conv11(x)
        x = self.relu11(x)
        x = self.conv12(x)
        x = self.relu12(x)
        x = self.conv13(x)
        x = self.relu13(x)
        x = self.maxpool5(x)

        x = x.view(x.size(0),x.size(1))
        x = self.linear1(x)
        x = self.relu14(x)
        x = self.dropout1(x)
        x = self.linear2(x)
        x = self.relu15(x)
        x = self.dropout2(x)
        x =self.linear3(x)
        return x

ResNet101

class Conv_block(nn.Module):
    def __init__(self,input_channel,filters,stride=2):
        super(Conv_block,self).__init__()
        self.conv1 = nn.Conv2d(input_channel,filters[0],kernel_size=1,stride = stride,bias=True)
        self.batch1 = nn.BatchNorm2d(filters[0])
        self.relu1 = nn.ReLU()

        self.conv2 = nn.Conv2d(filters[0],filters[1],kernel_size=3,stride=1,padding =1,bias =True)
        self.batch2 = nn.BatchNorm2d(filters[1])
        self.relu2 = nn.ReLU()

        self.conv3 = nn.Conv2d(filters[1],filters[2],kernel_size=1,stride=1,bias =True)
        self.batch3 = nn.BatchNorm2d(filters[2])

        self.conv4 = nn.Conv2d(input_channel,filters[2],kernel_size=1,stride=stride,bias =True)
        self.batch4 = nn.BatchNorm2d(filters[2])

        self.relu3 = nn.ReLU()
    def forward(self,x):
        shortcut = x
        x = self.conv1(x)
        x = self.batch1(x)
        x = self.relu1(x)
        x = self.conv2(x)
        x = self.batch2(x)
        x = self.relu2(x)
        x = self.conv3(x)
        x = self.batch3(x)
        shortcut = self.conv4(shortcut)
        shortcut = self.batch4(shortcut)
        x +=shortcut
        x = self.relu3(x)
        return x
class Identity_block(nn.Module):
    def __init__(self,input_channel,filters):
        super(Identity_block,self).__init__()
        self.conv1 = nn.Conv2d(input_channel,filters[0],kernel_size=1,stride=1,bias=True)
        self.batch1 = nn.BatchNorm2d(filters[0])
        self.relu1 = nn.ReLU()

        self.conv2 = nn.Conv2d(filters[0],filters[1],kernel_size=3,padding=1,stride=1,bias=True)
        self.batch2 = nn.BatchNorm2d(filters[1])
        self.relu2 = nn.ReLU()

        self.conv3 = nn.Conv2d(filters[1],filters[2],kernel_size=1,stride=1,bias=True)
        self.batch3 = nn.BatchNorm2d(filters[2])

        self.relu3 = nn.ReLU()

    def forward(self,x):
        shortcut = x
        x = self.conv1(x)
        x = self.batch1(x)
        x = self.relu1(x)
        x = self.conv2(x)
        x = self.batch2(x)
        x = self.relu2(x)
        x = self.conv3(x)
        x = self.batch3(x)
        x +=shortcut
        x = self.relu3(x)
        return x
class ResNet101(nn.Module):
    def __init__(self,num_classes):
        super(ResNet101,self).__init__()
        self.model1 = nn.Sequential(
            nn.Conv2d(3,64,kernel_size=7,padding=3,stride=2,bias=True),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3,stride=2,padding=1)

        )
        self.model2 = nn.Sequential(
            Conv_block(64,[64,64,256],stride=1),
            Identity_block(256,[64,64,256]),
            Identity_block(256,[64,64,256])
        )
        self.model3 = nn.Sequential(
            Conv_block(256,[128,128,512]),
            Identity_block(512,[128,128,512]),
            Identity_block(512,[128,128,512]),
            Identity_block(512,[128,128,512])
        )

        self.conv1 = Conv_block(512,[256,256,1024])
        self.loop_identity = Identity_block(1024,[256,256,1024])
        self.model4 = nn.Sequential(
            Conv_block(1024,[512,512,2048]),
            Identity_block(2048,[512,512,2048]),
            Identity_block(2048,[512,512,2048])
        )

        self.avgpool = nn.AdaptiveMaxPool2d(1)
        self.model5 = nn.Sequential(
            nn.Linear(2048,1024),
            nn.Dropout(0.5),
            nn.ReLU(),
            nn.Linear(1024,num_classes)
        )
    def forward(self,x):
        c1 = x = self.model1(x)
        c2 = x = self.model2(x)
        c3 = x = self.model3(x)
        x = self.conv1(x)
        for i in range(22):
            x = self.loop_identity(x)
        c4 = x
        c5 = x = self.model4(x)
        x = self.avgpool(x)
        x = x.view(x.size(0),x.size(1))
        x = self.model5(x)
        return c1,c2,c3,c4,c5,x

针对重新构建的代码,读者可自行对照前文的代码,感受不同框架之间的差异和优缺点。
为了方便读者自行测试代码,一下给出一些简易的测试代码,有助于读者了解输出输入的方式

net = ResNet101(num_classes=10) # net = VGG16(num_classes=10)
input = torch.randn(1,3,224,224)
out = net(input)
print(net)
print(out[4].shape)

文章作者: Fanrencli
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Fanrencli !
  目录