深度学习第J3周:DenseNet算法实战与解析

Posted 牛大了2022

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度学习第J3周:DenseNet算法实战与解析相关的知识,希望对你有一定的参考价值。

目录

一、前言

二、设计理念

三、网络结构

四、与其他算法进行对比

五、使用Pytorch实现DenseNet121

六、使用Tensorflow实现DenseNet网络

1.DenseLayer

2.Block 

3.Transition

4.DenseNet

5.DenseNet121网络结构图


🍨 本文为[🔗365天深度学习训练营]内部限免文章(版权归 *K同学啊* 所有)
🍖 作者:[K同学啊]

数据集下载:百度网盘 请输入提取码(提取码:0mhm) 

📌 本周任务:
●1.请根据本文 Pytorch 代码,编写出相应的 TensorFlow 代码(建议使用上周的数据测试一下模型是否构建正确)
●2.了解并研究 DenseNet与ResNetV 的区别
●3.改进思路是否可以迁移到其他地方呢(自由探索,虽然不强求但是请认真对待这个哦)

一、前言

       在计算机视觉领域,卷积神经网络(CNN)已经成为最主流的方法,比如GoogLenet,VGG-16,Incepetion等模型。CNN史上的一个里程碑事件是ResNet模型的出现,ResNet可以训练出更深的CNN模型,从而实现更高的准确度。ResNet模型的核心是通过建立前面层与后面层之间的“短路连接”(shortcuts,skip connection),进而训练出更深的CNN网络。
       今天我们要介绍的是DenseNet模型,它的基本思路与ResNet一致,但是它建立的是前面所有层与后面层的密集连接(dense connection),它的名称也是由此而来。DenseNet的另一大特色是通过特征在channel上的连接来实现特征重用(feature reuse)。这些特点让DenseNet在参数和计算成本更少的情形下实现比ResNet更优的性能,DenseNet也因此斩获CVPR 2017的最佳论文奖。

 DenseNet论文

二、设计理念

相比ResNet,DenseNet提出了一个更激进的密集连接机制:即互相连接所有的层,具体来说就是每个层都会接受其前面所有层作为其额外的输入。
图1为ResNet网络的残差连接机制,作为对比,图2为DenseNet的密集连接机制。可以看到,ResNet是每个层与前面的某层(一般是2~4层)短路连接在一起,连接方式是通过元素相加。而在DenseNet中,每个层都会与前面所有层在channel维度上连接(concat)在一起(即元素叠加),并作为下一层的输入。
对于一个 L 层的网络,DenseNet共包含 L(L+1)/2​ 个连接,相比ResNet,这是一种密集连接。而且DenseNet是直接concat来自不同层的特征图,这可以实现特征重用,提升效率,这一特点是DenseNet与ResNet最主要的区别。

图1:ResNet网络的短路连接机制(其中+代表的是元素级相加操作)

图2:DenseNet网络的密集连接机制(其中c代表的是channel级连接操作)

而对于DesNet,则是采用跨通道concat的形式来连接,会连接前面所有层作为输入,输入和输出的公式是Xl​=Hl​(X0​,X1​,...,Xl−1​)。这里要注意所有的层的输入都来源于前面所有层在channel维度的concat,用一张动图体会一下:

三、网络结构

  CNN网络一般要经过Pooling或者stride>1的Conv来降低特征图的大小,而DenseNet的密集连接方式需要特征图大小保持一致。为了解决这个问题,DenseNet网络中使用DenseBlock+Transition的结构,其中DenseBlock是包含很多层的模块,每个层的特征图大小相同,层与层之间采用密集连接方式。而Transition层是连接两个相邻的DenseBlock,并且通过Pooling使特征图大小降低。图5给出了DenseNet的网路结构,它共包含4个DenseBlock,各个DenseBlock之间通过Transition层连接在一起。

 使用DenseBlock+Transition的DenseNet网络

在DenseBlock中,各个层的特征图大小一致,可以在channel维度上连接。DenseBlock中的非线性组合函数 H ( ⋅ )的是 BN + ReLU + 3x3 Conv 的结构,如图所示。另外值得注意的一点是,与ResNet不同,所有DenseBlock中各个层卷积之后均输入 k 个特征图,即得到的特征图的channel数为 k,或者说采用 k  个卷积核。k 在DenseNet称为growth rate,这是一个超参数。一般情况下使用较小的 k (比如12),就可以得到较佳的性能。假定输入层的特征图的channel数为 k 0,那么 l 层输入的channel数为 k 0 + k ( 1 , 2 , … , l − 1 ) ,因此随着层数增加,尽管 k 设定得较小,DenseBlock的输入会非常多,不过这是由于特征重用所造成的,每个层仅有 k  个特征是自己独有的。

 由于后面层的输入会非常大,DenseBlock内部可以采用bottleneck层来减少计算量,主要是原有的结构中增加1x1 Conv,如图7所示,即 BN + ReLU + 1x1 Conv + BN + ReLU + 3x3 Conv,称为DenseNet-B结构。其中1x1 Conv得到 4 k  个特征图,它起到的作用是降低特征数量,从而提升计算的效率。

对于Transition层,,它主要是连接两个相邻的DenseBlock,并且降低特征图大小。Transition层包括一个1x1的卷积和2x2的AvgPooling,结构为BN+ReLU+1x1Conv+2x2AvgPooling。另外,Transition层可以起到压缩模型的作用。假定层的上接DenseBlock得到的特征图channels数为m,Transition层可以产生【θm】个特征(通过卷积层),其中 是压缩系数θ∈(0,1](compression rate)。当 θ=1时,特征个数经过Transition层没有变化,即无压缩,而当压缩系数小于1时,这种结构称为DenseNet-C,文中使用θ=0.5。对于使用bottleneck层的DenseBlock结构和压缩系数小于1的Transition组合结构称为DenseNet-BC。

       对于ImageNet数据集,图片输入大小为224×224,网络结构采用包含4个DenseBlock的DenseNet-BC,其首先是一个stride=2的7x7卷积层,然后是一个stride=2的3x3 MaxPooling层,后面才进入DenseBlock。ImageNet数据集所采用的网络配置如表1所示:

四、与其他算法进行对比

ResNet与DenseNet的对比

五、使用Pytorch实现DenseNet121

这里我们采用了Pytorch的框架来实现DenseNet,首先实现DenseBlock中的内部结构,这里是BN+ReLU+1×1Conv+BN+ReLU+3×3Conv结构,最后也加入dropout层用于训练过程。

class _DenseLayer(nn.Module):
    def __init__(self, num_input_features, growth_rate, bn_size, drop_rate, efficient=False):
        super(_DenseLayer, self).__init__()
        self.add_module('norm1', nn.BatchNorm2d(num_input_features)),
        self.add_module('relu1', nn.ReLU(inplace=True)),
        self.add_module('conv1', nn.Conv2d(num_input_features, bn_size * growth_rate,
                        kernel_size=1, stride=1, bias=False)),
        self.add_module('norm2', nn.BatchNorm2d(bn_size * growth_rate)),
        self.add_module('relu2', nn.ReLU(inplace=True)),
        self.add_module('conv2', nn.Conv2d(bn_size * growth_rate, growth_rate,
                        kernel_size=3, stride=1, padding=1, bias=False)),
        self.drop_rate = drop_rate
        self.efficient = efficient
 
    def forward(self, *prev_features):
        bn_function = _bn_function_factory(self.norm1, self.relu1, self.conv1)
        if self.efficient and any(prev_feature.requires_grad for prev_feature in prev_features):
            bottleneck_output = cp.checkpoint(bn_function, *prev_features)
        else:
            bottleneck_output = bn_function(*prev_features)
        new_features = self.conv2(self.relu2(self.norm2(bottleneck_output)))
        if self.drop_rate > 0:
            new_features = F.dropout(new_features, p=self.drop_rate, training=self.training)
        return new_features

实现DenseBlock模块,内部是密集连接方式(输入特征数线性增长):

class _DenseBlock(nn.Module):
    def __init__(self, num_layers, num_input_features, bn_size, growth_rate, drop_rate, efficient=False):
        super(_DenseBlock, self).__init__()
        for i in range(num_layers):
            layer = _DenseLayer(
                num_input_features + i * growth_rate,
                growth_rate=growth_rate,
                bn_size=bn_size,
                drop_rate=drop_rate,
                efficient=efficient,
            )
            self.add_module('denselayer%d' % (i + 1), layer)
 
    def forward(self, init_features):
        features = [init_features]
        for name, layer in self.named_children():
            new_features = layer(*features)
            features.append(new_features)
        return torch.cat(features, 1)

实现Transition层,它主要是一个卷积层和一个池化层:

class _Transition(nn.Sequential):
    def __init__(self, num_input_features, num_output_features):
        super(_Transition, self).__init__()
        self.add_module('norm', nn.BatchNorm2d(num_input_features))
        self.add_module('relu', nn.ReLU(inplace=True))
        self.add_module('conv', nn.Conv2d(num_input_features, num_output_features,
                                          kernel_size=1, stride=1, bias=False))
        self.add_module('pool', nn.AvgPool2d(kernel_size=2, stride=2))
 
 

实现DenseNet网络: 

class DenseNet(nn.Module):
    r"""Densenet-BC model class, based on
    `"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`
    Args:
        growth_rate (int) - how many filters to add each layer (`k` in paper)
        block_config (list of 3 or 4 ints) - how many layers in each pooling block
        num_init_features (int) - the number of filters to learn in the first convolution layer
        bn_size (int) - multiplicative factor for number of bottle neck layers
            (i.e. bn_size * k features in the bottleneck layer)
        drop_rate (float) - dropout rate after each dense layer
        num_classes (int) - number of classification classes
        small_inputs (bool) - set to True if images are 32x32. Otherwise assumes images are larger.
        efficient (bool) - set to True to use checkpointing. Much more memory efficient, but slower.
    """
    def __init__(self, growth_rate=12, block_config=(16, 16, 16), compression=0.5,
                 num_init_features=24, bn_size=4, drop_rate=0,
                 num_classes=10, small_inputs=True, efficient=False):
 
        super(DenseNet, self).__init__()
        assert 0 < compression <= 1, 'compression of densenet should be between 0 and 1'
 
        # First convolution
        if small_inputs:
            self.features = nn.Sequential(OrderedDict([
                ('conv0', nn.Conv2d(3, num_init_features, kernel_size=3, stride=1, padding=1, bias=False)),
            ]))
        else:
            self.features = nn.Sequential(OrderedDict([
                ('conv0', nn.Conv2d(3, num_init_features, kernel_size=7, stride=2, padding=3, bias=False)),
            ]))
            self.features.add_module('norm0', nn.BatchNorm2d(num_init_features))
            self.features.add_module('relu0', nn.ReLU(inplace=True))
            self.features.add_module('pool0', nn.MaxPool2d(kernel_size=3, stride=2, padding=1,
                                                           ceil_mode=False))
 
        # Each denseblock
        num_features = num_init_features
        for i, num_layers in enumerate(block_config):
            block = _DenseBlock(
                num_layers=num_layers,
                num_input_features=num_features,
                bn_size=bn_size,
                growth_rate=growth_rate,
                drop_rate=drop_rate,
                efficient=efficient,
            )
            self.features.add_module('denseblock%d' % (i + 1), block)
            num_features = num_features + num_layers * growth_rate
            if i != len(block_config) - 1:
                trans = _Transition(num_input_features=num_features,
                                    num_output_features=int(num_features * compression))
                self.features.add_module('transition%d' % (i + 1), trans)
                num_features = int(num_features * compression)
 
        # Final batch norm
        self.features.add_module('norm_final', nn.BatchNorm2d(num_features))
 
        # Linear layer
        self.classifier = nn.Linear(num_features, num_classes)
 
        # Initialization
        for name, param in self.named_parameters():
            if 'conv' in name and 'weight' in name:
                n = param.size(0) * param.size(2) * param.size(3)
                param.data.normal_().mul_(math.sqrt(2. / n))
            elif 'norm' in name and 'weight' in name:
                param.data.fill_(1)
            elif 'norm' in name and 'bias' in name:
                param.data.fill_(0)
            elif 'classifier' in name and 'bias' in name:
                param.data.fill_(0)
 
    def forward(self, x):
        features = self.features(x)
        out = F.relu(features, inplace=True)
        out = F.adaptive_avg_pool2d(out, (1, 1))
        out = torch.flatten(out, 1)
        out = self.classifier(out)
        return out

六、使用Tensorflow实现DenseNet网络

1.DenseLayer

class  DenseLayer(Model):
    def __init__(self,bottleneck_size,growth_rate):
        super().__init__()
        self.filters=growth_rate
        self.bottleneck_size=bottleneck_size
        self.b1=BatchNormalization()
        self.a1=Activation('relu')
        self.c1=Conv2D(filters=self.bottleneck_size,kernel_size=(1,1),strides=1)
        self.b2=BatchNormalization()
        self.a2=Activation('relu')
        self.c2=Conv2D(filters=32,kernel_size=(3,3),strides=1,padding='same')
    def call(self,*x):
        x=tf.concat(x,2)
        x=self.b1(x)
        x=self.a1(x)
        x=self.c1(x)
        x=self.b2(x)
        x=self.a2(x)
        y=self.c2(x)    
        return y

2.Block 

class DenseBlock(Model):
    def __init__(self,Dense_layers_num,growth_rate):#Dense_layers_num每个denseblock中的denselayer数,growth
        super().__init__()
        self.Dense_layers_num=Dense_layers_num
        self.Dense_layers=[]
        bottleneck_size=4*growth_rate
        for i in range(Dense_layers_num):
            layer=DenseLayer(bottleneck_size,growth_rate)
            self.Dense_layers.append(layer)
    def call(self,input):
        x=[input]
        for layer in self.Dense_layers:
            output=layer(*x)
            x.append(output)
        y=tf.concat(x,2)
        return y

3.Transition

class Transition(Model):
    def __init__(self,filters):
        super().__init__()
        self.b=BatchNormalization()
        self.a=Activation('relu')
        self.c=Conv2D(filters=filters,kernel_size=(1,1),strides=1)
        self.p=AveragePooling2D(pool_size=(2,2),strides=2)
        
    def call(self,x):
        x=self.b(x)
        x=self.a(x)
        x=self.c(x)
        y=self.p(x)
        return y 

4.DenseNet

class DenseNet(Model):
    def __init__(self,block_list=[6,12,24,16],compression_rate=0.5,filters=64):
        super().__init__()
        growth_rate=32
        self.padding=ZeroPadding2D(((1,2),(1,2)))
        self.c1=Conv2D(filters=filters,kernel_size=(7,7),strides=2,padding='valid')
        self.b1=BatchNormalization()
        self.a1=Activation('relu')
        self.p1=MaxPooling2D(pool_size=(3,3),strides=2,padding='same')
        self.blocks=tf.keras.models.Sequential()
        input_channel=filters
        for i,layers_in_block in enumerate(block_list):
            if i<3 :
                self.blocks.add(DenseBlock(layers_in_block,growth_rate))
                block_out_channels=input_channel+layers_in_block*growth_rate
                self.blocks.add(Transition(filters=block_out_channels*0.5))
            if i==3:
                self.blocks.add(DenseBlock(Dense_layers_num=layers_in_block,growth_rate=growth_rate))
        self.p2=GlobalAveragePooling2D()
        self.d2=Dense(1000,activation='softmax') 
    def call(self,x):
        x=self.padding(x)
        x=self.c1(x)
        x=self.b1(x)
        x=self.a1(x)
        x=self.p1(x)
        x=self.blocks(x)
        x=self.p2(x)
        y=self.d2(x)
        return y

model=DenseNet()
print(model)

5.DenseNet121网络结构图

 

365天深度学习训练营-第J1周:ResNet-50算法实战与解析

目录

 一、前言

二、论文分析

三、残差网络(ResNet)介绍

1、残差网络解决了什么

2、ResNet-50介绍

 四、构造ResNet-50模型

1、Tensorflow代码

2、Pytorch代码


 一、前言

● 难度:夯实基础⭐⭐
● 语言:Python3、Pytorch3
● 时间:2月5日-2月10日
🍺要求:

1.根据本文的Tensorflow代码,编写Pytorch代码
2.了解残差网络
3.是否可以将残差模块融合到C3中

二、论文分析

论文:Deep Residual Learning for Image Recognition

问题的提出:

随着网络层数的增加,更深的网络具有更大的训练误差,从而导致测试误差。

所以提出了一个问题:对叠层数越多是不是训练网络效果越好呢?

这种问题的阻碍是梯度消失或者爆炸,而这种我们的解决办法是:初始化归一和中间层归一化

随着网络深度的增加,精度变得饱和,然后迅速退化,但是这种退化不是由于过度拟合引起的,这也就成为了模型训练退化问题。像适当深度的模型添加更多层会导致更高的训练误差。解决这种误差是这篇论文的主要目的。

解决方案一:添加的层是身份映射,其他层是从学习中较浅的模型复制,但是现有的解释器很难做

解决方案二:引入深度残差学习框架来解决这种退化问题。

将所需的基础映射表示为H(x)

让堆叠的非线性层适合F(x):= H(x)- x的另一个映射。

原始映射为F(x)+ x。 

通过快捷连接来实现身份验证。

实验证明:

1)极深的残差网络易于优化,但是当深度增加时,对应的“普通”网络(简单地堆叠层)显示出更高的训练误差;

2)深层残差网络可以通过大大增加深度来轻松享受准确性的提高,所产生的结果比以前的网络要好得多。

Deep Residual Learning 

残差学习:

       将H(x)视为由一些堆叠层(不一定是整个网络)拟合的基础映射,其中x表示这些层中第一层的输入。如果假设多个非线性层可以渐近逼近复杂函数,那么就可以假设它们可以渐近逼近残差函数,即H(x)-x(假设输入和输出为尺寸相同)。因此,没有让堆叠的层近似为H(x),而是明确地让这些层近似为残差函数F(x):= H(x)-x。因此,原始函数变为F(x)+ x。尽管两种形式都应能够渐近地逼近所需的功能(如假设),但学习的难易程度可能有所不同。

简单来讲:

整个模块除了正常的卷积层输出外,还有一个分支把输入直接连在输出上,该分支输出和卷积的输出做算数相加得到了最终的输出,这种残差结构人为的制造了恒等映射,即F(x)分支中所有参数都是0,H(x)就是一个恒等映射,这样就能让整个结构朝着恒等映射的方向去收敛,确保最终的错误率不会因为深度的变大而越来越差。

假设我们现在已经有了一个N层的网络,现在在尾部加上K个残差模块(M层),

如果说这K个残差会造成网络过深,那么这K个残差模块会向恒等映射方向发展(参数为0),进而解决了网络过深问题

网络框架

实验结果

 可以明显看到在用ResNet之后,随着网络深度的增加,网络的训练效果更好。

三、残差网络(ResNet)介绍

1、残差网络解决了什么

残差网络是为了解决神经网络隐藏层过多时,而引起的网络退化问题。退化(degradation)问题是指:当网络隐藏层变多时,网络的准确度达到饱和然后急剧退化,而且这个退化不是由于过拟合引起的。

拓展:深度神经网络的"两朵乌云"

  • 梯度弥散/爆炸

简单来讲就是网络太深了,会导致模型训练难以收敛。这个问题可以被标准初始化和中间层正规化的方法有效控制。

  • 网络退化

随着网络深度增加,网络的表现先是逐渐增加至饱和,然后迅速下降,这个退化不是由过拟合引起的。

2、ResNet-50介绍

ResNet-50有两个基本的块,分别名为Conv BlockIdentity Block

Conv Block结构:

Identity Block结构:

ResNet-50总体结构:

 四、构造ResNet-50模型

1、Tensorflow代码

def identity_block(input_ten,kernel_size,filters):
    filters1,filters2,filters3 = filters
    
    x = Conv2D(filters1,(1,1))(input_ten)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    
    x = Conv2D(filters2,kernel_size,padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    
    x = Conv2D(filters3,(1,1))(x)
    x = BatchNormalization()(x)
    
    x = layers.add([x,input_ten])
    x = Activation('relu')(x)
    return x
def conv_block(input_ten,kernel_size,filters,strides=(2,2)):
    filters1,filters2,filters3 = filters
    x = Conv2D(filters1,(1,1),strides=strides)(input_ten)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    
    x = Conv2D(filters2,kernel_size,padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    
    x = Conv2D(filters3,(1,1))(x)
    x = BatchNormalization()(x)
    
    shortcut = Conv2D(filters3,(1,1),strides=strides)(input_ten)
    shortcut = BatchNormalization()(shortcut)
    
    x = layers.add([x,shortcut])
    x = Activation('relu')(x)
    return x
def ResNet50(nb_class,input_shape):
    input_ten = Input(shape=input_shape)
    x = ZeroPadding2D((3,3))(input_ten)
    
    x = Conv2D(64,(7,7),strides=(2,2))(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = MaxPooling2D((3,3),strides=(2,2))(x)
    
    x =     conv_block(x,3,[64,64,256],strides=(1,1))
    x = identity_block(x,3,[64,64,256])
    x = identity_block(x,3,[64,64,256])
    
    x =     conv_block(x,3,[128,128,512])
    x = identity_block(x,3,[128,128,512])
    x = identity_block(x,3,[128,128,512])
    x = identity_block(x,3,[128,128,512])
    
    x =     conv_block(x,3,[256,256,1024])
    x = identity_block(x,3,[256,256,1024])
    x = identity_block(x,3,[256,256,1024])
    x = identity_block(x,3,[256,256,1024])
    x = identity_block(x,3,[256,256,1024])
    x = identity_block(x,3,[256,256,1024])
    
    x =     conv_block(x,3,[512,512,2048])
    x = identity_block(x,3,[512,512,2048])
    x = identity_block(x,3,[512,512,2048])
    
    x = AveragePooling2D((7,7))(x)
    x = tf.keras.layers.Flatten()(x)
    
    output_ten = Dense(nb_class,activation='softmax')(x)
    model = Model(input_ten,output_ten)
	model.load_weights("resnet50_weights_tf_dim_ordering_tf_kernels.h5")
    return model
model_ResNet50 = ResNet50(24,(img_height,img_width,3))
model_ResNet50.summary()

2、Pytorch代码

from torch import nn


class ConvBlock(nn.Module):
    def __init__(self, in_channel, kernel_size, filters, stride):
        super(ConvBlock, self).__init__()
        filter1, filter2, filter3 = filters
        self.stage = nn.Sequential(
            nn.Conv2d(in_channel, filter1, 1, stride=stride, padding=0, bias=False),
            nn.BatchNorm2d(filter1),
            nn.RuLU(True),
            nn.Conv2d(filter1, filter2, kernel_size, stride=1, padding=True, bias=False),
            nn.BatchNorm2d(filter2),
            nn.RuLU(True),
            nn.Conv2d(filter2, filter3, 1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(filter3),
        )
        self.shortcut_1 = nn.Conv2d(in_channel, filter3, 1, stride=stride, padding=0, bias=False)
        self.batch_1 = nn.BatchNorm2d(filter3)
        self.relu_1 = nn.ReLU(True)

        def forward(self, x):
            x_shortcut = self.shortcut_1(x)
            x_shortcut = self.batch_1(x_shortcut)
            x = self.stage(x)
            x = x + x_shortcut
            x = self.relu_1(x)
            return x


class IndentityBlock(nn.Module):
    def __init__(self, in_channel, kernel_size, filters):
        super(IndentityBlock, self).__init__()
        filter1, filter2, filter3 = filters
        self.stage = nn.Sequential(
            nn.Conv2d(in_channel, filter1, 1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(filter1),
            nn.RuLU(True),
            nn.Conv2d(filter1, filter2, kernel_size, padding=True, bias=False),
            nn.BatchNorm2d(filter1),
            nn.RuLU(True),
            nn.Conv2d(filter2, filter3, 1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(filter3),
        )
        self.relu_1=nn.ReLU(True)

        def forward(self, x):
            x_shortcut = x
            x = self.stage(x)
            x = x + x_shortcut
            x = self.relu_1(x)
            return x


class ResModel(nn.Module):
    def __init__(self, n_class):
        super(ResModel, self).__init__()
        self.stage1 = nn.Sequential(
            nn.Conv2d(3, 64, 7, stride=2, padding=3, bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU(True),
            nn.MaxPool2d(3, 2, padding=1),
        )
        self.stage2 = nn.Sequential(
            ConvBlock(64, f=3, filters=[64, 64, 256], s=2),
            IndentityBlock(256, 3, [64, 64, 256]),
            IndentityBlock(256, 3, [64, 64, 256]),
        )
        self.stage3 = nn.Sequential(
            ConvBlock(256, f=3, filters=[128, 128, 512], s=3),
            IndentityBlock(512, 3, [128, 128, 512]),
            IndentityBlock(512, 3, [128, 128, 512]),
            IndentityBlock(512, 3, [128, 128, 512]),
        )
        self.stage4 = nn.Sequential(
            ConvBlock(512, f=3, filters=[256, 256, 1024], s=4),
            IndentityBlock(1024, 3, [256, 256, 1024]),
            IndentityBlock(1024, 3, [256, 256, 1024]),
            IndentityBlock(1024, 3, [256, 256, 1024]),
            IndentityBlock(1024, 3, [256, 256, 1024]),
            IndentityBlock(1024, 3, [256, 256, 1024]),
        )
        self.stage5 = nn.Sequential(
            ConvBlock(1024, f=3, filters=[512, 512, 2048], s=5),
            IndentityBlock(2048, 3, [512, 512, 2048]),
            IndentityBlock(2048, 3, [512, 512, 2048]),
        )
        self.pool = nn.AvgPool2d(7, 7, padding=1)
        self.fc = nn.Sequential(
            nn.Linear(8192, n_class)
        )

    def forward(self, X):
        out = self.stage1(X)
        out = self.stage2(out)
        out = self.stage3(out)
        out = self.stage4(out)
        out = self.stage5(out)
        out = self.pool(out)
        out = out.view(out.size(0), 8192)
        out = self.fc(out)
        return out

以上是关于深度学习第J3周:DenseNet算法实战与解析的主要内容,如果未能解决你的问题,请参考以下文章

TensorFlow2深度学习实战:SSD目标检测算法源码解析

TensorFlow2深度学习实战:SSD目标检测算法源码解析

TensorFlow2 深度学习实战(十四):YOLOv4目标检测算法解析

TensorFlow2 深度学习实战(十四):YOLOv4目标检测算法解析

Pytorch实战 | 第P3周:天气识别

Pytorch实战 | 第P3周:天气识别