深度学习-第J4周:ResNet与DenseNet结合探索

 前言

上周文章中我们复现了DenseNet算法并与,本文将结合Resnet50算法模型进行初步的对比,我们将继续把DenseNet算法与Resnet50算法的特点结合,并构建一个新的模型框架

参考文章:第J3周/J3-1周:Densenet算法对比及多数据集对比(乳腺癌识别)_quant_day的博客-CSDN博客

首先我们再看一下Resnet50算法与DenseNet算法的结构图

Resnet50算法

 Resnet50主要通过IdentityBlock与ConvBlock两个过程提供逐层短路连接来加深网络

DenseNet算法的结构图

 DenseNet算法类似的,提供了DenseBlock与Transition过程来连接前面所有层跟下一层的密集连接

所以本文设计了一个既有密集连接又有逐层短路连接的算法方案

一、模型准备

第一步,我们先封装Resnet50与DenseNet算法,以便新的模型直接引用标准的模型框架

resnet50v2.py

# -*- coding:utf-8 -*-
import torch
from torchvision import datasets, transforms
import torch.nn as nn
import time
import numpy as np
import matplotlib.pyplot as plt

import torchsummary as summary

import os
from collections import OrderedDict

class IdentityBlock_V2(nn.Module):

    def __init__(self, in_channel, kl_size, filters):
        super(IdentityBlock_V2, self).__init__()
        
        filter1, filter2, filter3 = filters
        self.bn0 = nn.BatchNorm2d(num_features=in_channel)
        
        self.cov1 = nn.Conv2d(in_channels=in_channel, out_channels=filter1, kernel_size=1, stride=1, padding=0)
        self.bn1 = nn.BatchNorm2d(num_features=filter1)
        self.relu = nn.ReLU(inplace=True)
        self.zeropadding2d1 = nn.ZeroPad2d(1)
        
        self.cov2 = nn.Conv2d(in_channels=filter1, out_channels=filter2, kernel_size=kl_size, stride=1, padding=0)
        self.bn2 = nn.BatchNorm2d(num_features=filter2)
        
        self.cov3 = nn.Conv2d(in_channels=filter2, out_channels=filter3, kernel_size=1, stride=1, padding=0)
        self.bn3 = nn.BatchNorm2d(num_features=filter3)        

    def forward(self, x):
        
        identity = self.bn0(x)
        identity = self.relu(identity)
        
        identity = self.cov1(identity)
        identity = self.bn1(identity)
        identity = self.relu(identity)
        identity = self.zeropadding2d1(identity)  
        
        identity = self.cov2(identity)
        identity = self.bn2(identity)
        identity = self.relu(identity)        
        
        identity = self.cov3(identity)

        x = identity + x   
        x = self.relu(x)       
        
        return x

class ConvBlock_V2(nn.Module):

    def __init__(self, in_channel, kl_size, filters, stride_size=2, conv_shortcut=False):
        super(ConvBlock_V2, self).__init__()

        filter1, filter2, filter3 = filters
        
        self.bn0 = nn.BatchNorm2d(num_features=in_channel)
        
        self.cov1 = nn.Conv2d(in_channels=in_channel, out_channels=filter1, kernel_size=1, stride=stride_size, padding=0)
        self.bn1 = nn.BatchNorm2d(num_features=filter1)
        self.relu = nn.ReLU(inplace=True)
        self.zeropadding2d1 = nn.ZeroPad2d(1)
        
        self.cov2 = nn.Conv2d(in_channels=filter1, out_channels=filter2, kernel_size=kl_size, stride=1, padding=0)
        self.bn2 = nn.BatchNorm2d(num_features=filter2)
        
        self.cov3 = nn.Conv2d(in_channels=filter2, out_channels=filter3, kernel_size=1, stride=1, padding=0)
        self.bn3 = nn.BatchNorm2d(num_features=filter3)   
        
        self.conv_shortcut = conv_shortcut
        if self.conv_shortcut:
            self.short_cut = nn.Conv2d(in_channels=in_channel, out_channels=filter3, kernel_size=1, stride=stride_size, padding=0)
        else:
            self.short_cut = nn.MaxPool2d(kernel_size=1, stride=stride_size, padding=0)

    def forward(self, x):    
        
        identity = self.bn0(x)
        identity = self.relu(identity)
        short_cut = self.short_cut(identity)
		
        identity = self.cov1(identity)
        identity = self.bn1(identity)
        identity = self.relu(identity)    
        identity = self.zeropadding2d1(identity)    
        
        identity = self.cov2(identity)
        identity = self.bn2(identity)
        identity = self.relu(identity)        
        
        identity = self.cov3(identity)
        x = identity + short_cut
        x = self.relu(x)   
        
        return x

class Resnet50_Model_V2(nn.Module):
    def __init__(self, in_channel, N_classes):
        super(Resnet50_Model_V2, self).__init__()
        self.in_channels = in_channel
        # ============= 基础层
        # 方法1
        self.zeropadding2d_0 = nn.ZeroPad2d(3)
        self.cov0 = nn.Conv2d(self.in_channels, out_channels=64, kernel_size=7, stride=2)
        self.zeropadding2d_1 = nn.ZeroPad2d(1)
        self.maxpool0 = nn.MaxPool2d(kernel_size=3, stride=2, padding=0)
              
        self.layer1 = nn.Sequential(
            ConvBlock_V2(64, 3, [64, 64, 256], 1, 1),
            IdentityBlock_V2(256, 3, [64, 64, 256]),
            ConvBlock_V2(256, 3, [64, 64, 256], 2, 0),
            )
        
        self.layer2 = nn.Sequential(
            ConvBlock_V2(256, 3, [128, 128, 512], 1, 1),
            IdentityBlock_V2(512, 3, [128, 128, 512]),
            IdentityBlock_V2(512, 3, [128, 128, 512]),
            ConvBlock_V2(512, 3, [128, 128, 512], 2, 0),
            )

        self.layer3 = nn.Sequential(
            ConvBlock_V2(512, 3, [256, 256, 1024], 1, 1),
            IdentityBlock_V2(1024, 3, [256, 256, 1024]),
            IdentityBlock_V2(1024, 3, [256, 256, 1024]),
            IdentityBlock_V2(1024, 3, [256, 256, 1024]),
            IdentityBlock_V2(1024, 3, [256, 256, 1024]),
            ConvBlock_V2(1024, 3, [256, 256, 1024], 2, 0),
            )

        self.layer4 = nn.Sequential(
            ConvBlock_V2(1024, 3, [512, 512, 2048], 1, 1),
            IdentityBlock_V2(2048, 3, [512, 512, 2048]),
            IdentityBlock_V2(2048, 3, [512, 512, 2048]),
            )
        
        # 输出网络
        self.bn = nn.BatchNorm2d(num_features=2048)  
        self.relu = nn.ReLU(inplace=True)
        self.avgpool = nn.AvgPool2d((7, 7))
        # classfication layer
        # 7*7均值后2048个参数
        self.fc = nn.Sequential(nn.Linear(2048, N_classes),
                                nn.Softmax(dim=1))

    def basic_layer1(self, x):
        '''
        input:  x = tensor(3, 224, 224).unsqueeze(0)
         Layer (type)               Output Shape         Param #
      ================================================================
            Conv2d-1         [-1, 64, 112, 112]           9,408
       BatchNorm2d-2         [-1, 64, 112, 112]             128
              ReLU-3         [-1, 64, 112, 112]               0
         MaxPool2d-4           [-1, 64, 56, 56]               0
      ================================================================   
        '''
        x = self.zeropadding2d_0(x)
        x = self.cov0(x)
        x = self.zeropadding2d_1(x)
        x = self.maxpool0(x)
        
        return x

    def forward(self, x):
        
        x = self.forward1(x)
        
        return x
    
    def forward1(self, x):
        
        x = self.basic_layer1(x)
        
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        
        x = self.bn(x)
        x = self.relu(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.fc(x)

        return x

#%%
if __name__=='__main__':
 
    model = Resnet50_Model_V2()
    

DenseNet.py

# -*- coding:utf-8 -*-
import torch
from torchvision import datasets, transforms
import torch.nn as nn
import time
import numpy as np
import matplotlib.pyplot as plt
import torch.nn.functional as F 
import torchsummary as summary

import os
from collections import OrderedDict

class DenseLayer(nn.Sequential):
    def __init__(self, in_channel, growth_rate, bn_size, drop_rate):
       super(DenseLayer, self).__init__()

       self.out_channels1 = bn_size * growth_rate
       self.out_channels2 =  growth_rate
       
       self.add_module("norm1", nn.BatchNorm2d(num_features=in_channel))
       self.add_module("relu1", nn.ReLU(inplace=True))
       self.add_module("conv1",  nn.Conv2d(in_channels=in_channel, out_channels=self.out_channels1, kernel_size=1, stride=1, padding=0, bias=False))
       
       self.add_module("norm2", nn.BatchNorm2d(num_features=self.out_channels1))
       self.add_module("relu2", nn.ReLU(inplace=True))
       self.add_module("conv2", nn.Conv2d(in_channels=self.out_channels1, out_channels=self.out_channels2, kernel_size=3, stride=1, padding=1, bias=False))
       
       self.drop_rate = drop_rate
       
    def forward(self, x):    
       
       new_features = super(DenseLayer, self).forward(x)
       if self.drop_rate>0:
           new_features = F.dropout(new_features, p=self.drop_rate, training=self.training)
       return torch.cat([x, new_features], 1)

class DenseBlock(nn.Sequential):
     def __init__(self, num_layers, in_channel, growth_rate, bn_size, drop_rate):
        super(DenseBlock, self).__init__()
        for i in range(num_layers):
            layer = DenseLayer(in_channel+i*growth_rate, growth_rate, bn_size, drop_rate)
            self.add_module('DenseLayer%d' %(i+1), layer)

class Transition(nn.Sequential):
    
    def __init__(self, in_channel, out_channel):
       super(Transition, self).__init__()
       self.add_module("norm", nn.BatchNorm2d(num_features=in_channel))
       self.add_module("relu", nn.ReLU(inplace=True))
       self.add_module("conv",  nn.Conv2d(in_channels=in_channel, out_channels=out_channel, kernel_size=1, stride=1, padding=0, bias=False))
       self.add_module("pool", nn.AvgPool2d(2, stride=2))        

class DenseNet(nn.Module):
    def __init__(self, growth_rate = 32, block_config=(6, 12, 24, 16), num_init_features=64,
                 bn_size=4, compression_rate=0.5, drop_rate=0, num_classes=4):
        super(DenseNet, self).__init__()
        # basic_layer
        self.in_channels = 3
        self.basic_layer = nn.Sequential(
            nn.Conv2d(self.in_channels, out_channels=num_init_features, kernel_size=7, stride=2, padding=3, bias=False),
            nn.BatchNorm2d(num_features=num_init_features),
            nn.ReLU(inplace=False),
            nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
            )
        
        self.features = self.basic_layer
        # DenseBlock
        self.num_features = num_init_features
        for i, num_layers in enumerate(block_config):
            block = DenseBlock(num_layers, self.num_features, growth_rate, bn_size, drop_rate)
            self.features.add_module('DenseBlock%d' %(i+1), block)
            self.num_features += num_layers * growth_rate
            if i != (len(block_config) - 1):
                trans = Transition(self.num_features, int(self.num_features * compression_rate))
                self.features.add_module('Transition%d' %(i+1), trans)
                self.num_features = int(self.num_features * compression_rate)

        # final_layer
        self.features.add_module('norm_f', nn.BatchNorm2d(num_features=self.num_features))
        self.add_module("relu_f", nn.ReLU(inplace=True))
        # classfication layer
        self.classifier =  nn.Sequential(nn.Linear(self.num_features, num_classes),
                                nn.Softmax(dim=1))
        
        
        # param initialization
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight)

            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.bias, 0)
                nn.init.constant_(m.weight, 1)

            elif isinstance(m, nn.Linear):
                nn.init.constant_(m.bias, 0)

    def forward(self, x):   
        features = self.features(x)
        out = F.avg_pool2d(features, 7, stride=1).view(features.size(0), -1)
        out = self.classifier(out)
        return out
        
def densenet121(pretrained=False, **kwargs):

    model = DenseNet(growth_rate = 32, block_config=(6, 12, 24, 16), num_init_features=64)

    if pretrained:
        summary.summary(model, (3, 224, 224))

    return model

#%%
if __name__=='__main__':
 
    model = DenseNet(growth_rate = 32, block_config=(6, 12, 24, 16), num_init_features=64, bn_size=4, compression_rate=0.5, drop_rate=0, num_classes=4)
    
 

二、引用标准模型

from resnet50v2 import *
from DenseNet import *

通过上面两步,我们将resnet50v2的IdentityBlock_V2与ConvBlock_V2引入,及DenseNet的DenseBlock与Transition引入,通过这四个block组合新的网络框架

简单的,我们在DenseNet的密集连接后加一条resnet50v2的短路连接

实现如下:

class DenseNet_Resnet(nn.Module):
    def __init__(self, growth_rate = 32, block_config=(6, 12, 24, 16), num_init_features=64,
                 bn_size=4, compression_rate=0.5, drop_rate=0, num_classes=4):
        super(DenseNet_Resnet, self).__init__()
        # basic_layer
        self.in_channels = 3
        self.basic_layer = nn.Sequential(
            nn.Conv2d(self.in_channels, out_channels=num_init_features, kernel_size=7, stride=2, padding=3, bias=False),
            nn.BatchNorm2d(num_features=num_init_features),
            nn.ReLU(inplace=False),
            nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
            )
        
        self.features = self.basic_layer
        # DenseBlock
        self.num_features = num_init_features
        for i, num_layers in enumerate(block_config):
            block = DenseBlock(num_layers, self.num_features, growth_rate, bn_size, drop_rate)
            self.features.add_module('DenseBlock%d' %(i+1), block)
            self.num_features += num_layers * growth_rate
            if i != (len(block_config) - 1):
                trans = Transition(self.num_features, int(self.num_features * compression_rate))
                self.features.add_module('Transition%d' %(i+1), trans)
                self.num_features = int(self.num_features * compression_rate)
            
            # Resnet50_V2
            Resnet_ConvBlock_V2 = ConvBlock_V2(self.num_features, 3, [int(self.num_features/2), int(self.num_features/2), self.num_features * 2], 1, 1)
            self.features.add_module('ConvBlock_V2%d' %(i+1), Resnet_ConvBlock_V2)
            self.num_features = self.num_features * 2

        # final_layer
        self.features.add_module('norm_f', nn.BatchNorm2d(num_features=self.num_features))
        self.add_module("relu_f", nn.ReLU(inplace=True))
        # classfication layer
        self.classifier =  nn.Sequential(nn.Linear(self.num_features, num_classes),
                                nn.Softmax(dim=1))
        
        
        # param initialization
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight)

            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.bias, 0)
                nn.init.constant_(m.weight, 1)

            elif isinstance(m, nn.Linear):
                nn.init.constant_(m.bias, 0)

    def forward(self, x):   
        features = self.features(x)
        out = F.avg_pool2d(features, 7, stride=1).view(features.size(0), -1)
        out = self.classifier(out)
        return out

不难看出,主要区别是在每层DenseBlock与Transition后都添加了一步ConvBlock_V2

Resnet_ConvBlock_V2 = ConvBlock_V2(self.num_features, 3, [int(self.num_features/2), int(self.num_features/2), self.num_features * 2], 1, 1)
self.features.add_module('ConvBlock_V2%d' %(i+1), Resnet_ConvBlock_V2)
self.num_features = self.num_features * 2

新模型的打印,参数增加了不少

三、运行结果

 

 对比第J3周/J3-1周:Densenet算法对比及多数据集对比(乳腺癌识别)_quant_day的博客-CSDN博客

的结果

DenseNet_Resnet模型有一个精度提升的过程,大概提升到20层左右,精度不再提升,相对于DenseNet模型一层epochs就到达最大精度会更好一些

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值