跨境派

跨境派

跨境派,专注跨境行业新闻资讯、跨境电商知识分享!

当前位置:首页 > 卖家故事 > DenseNet(密集连接的卷积网络)

DenseNet(密集连接的卷积网络)

时间:2024-04-29 13:20:17 来源:网络cs 作者:纳雷武 栏目:卖家故事 阅读:

标签: 网络  密集  连接 
阅读本书更多章节>>>>

这里写目录标题

前言1. DenseNet网络2.设计理念2.1 Resnet2.2 DenseNet2.3 密集连接的实现 3. DenseNet的实现3.1 Dense Block的实现3.2 Transition Layer的实现3.3 DenseNet网络3.4 DenseNet-121网络 4. 测试

前言

DenseNet是指Densely connected convolutional networks(密集卷积网络)。它的优点主要包括有效缓解梯度消失、特征传递更加有效、计算量更小、参数量更小、性能比ResNet更好。它的缺点主要是较大的内存占用。

1. DenseNet网络

DenseNet网络与Resnet、GoogleNet类似,都是为了解决深层网络梯度消失问题的网络。

Resnet从深度方向出发,通过建立前面层与后面层之间的“短路连接”或“捷径”,从而能训练出更深的CNN网络。GoogleNet从宽度方向出发,通过Inception(利用不同大小的卷积核实现不同尺度的感知,最后进行融合来得到图像更好的表征)。DenseNet从特征入手,通过对前面所有层与后面层的密集连接,来极致利用训练过程中的所有特征,进而达到更好的效果和减少参数。

2.设计理念

为了详细对比Resnet与DenseNet的区别,分别介绍Resnet网络和DenseNet网络。

2.1 Resnet

](https://img-blog.csdnimg.cn/6a2acedac29f4b44a95dc8e7d6e96ab4.png

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

在Resnet网络中,通过一个残差连接将输入部分内容与卷积后的内容结合在一起。如果卷积层因为层数过深而不起作用,这不会影响最终的结果。哪一层卷积层起作用就调用哪一层卷积层,从而避免了层数过深的问题。这也是残差结构所带来的优势所在。

2.2 DenseNet

在这里插入图片描述

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

在DenseNet中,一个更激进的密集连接机制被设计用来充分利用特征。简单来说就是每一层的特征都被保存下来,在后面的每次卷积操作中用到。因此,每一层的网络结构都用到了前面的所有信息(包括卷积操作前和卷积操作后的信息)。

注意:在Resnet网络结构中,网路的残差连接是+操作。即:两个数据规模是相同的,得到的数据跟前面的数据规模也是相同的。而DenseNet网络中,是合并操作。即:在channel维度上连接在一起(这里各个层的特征图大小是相同的)。

2.3 密集连接的实现

首先实现DenseBlock中的内部结构,这里是BN+ReLU+1x1 Conv+BN+ReLU+3x3 Conv结构,最后也加入dropout层以用于训练过程。

class _DenseLayer(nn.Sequential):    """Basic unit of DenseBlock (using bottleneck layer) """    def __init__(self, num_input_features, growth_rate, bn_size, drop_rate):        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    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)        #通过torch.cat操作将前面的数据合并在一起         #类似如:第一次操作:[x, features]         #      第二次操作:[x, features_1] 其中,此时的x为[x, features]         return torch.cat([x, new_features], 1)

3. DenseNet的实现

DenseNet的网络结构如图所示。可以发现,该网络主要有Dense Block和Transition Layer两个部分组成。
DenseNet共在三个图像分类数据集(CIFAR,SVHN和ImageNet)上进行测试。对于前两个数据集,其输入图片大小为 32 × 32 ,所使用的DenseNet在进入第一个DenseBlock之前,首先进行进行一次3x3卷积(stride=1),卷积核数为16(对于DenseNet-BC为 2 k )。DenseNet共包含三个DenseBlock,各个模块的特征图大小分别为 32 × 32, 16 × 16 和 8 × 8 ,每个DenseBlock里面的层数相同。最后的DenseBlock之后是一个global AvgPooling层,然后送入一个softmax分类器。注意,在DenseNet中,所有的3x3卷积均采用padding=1的方式以保证特征图大小维持不变。对于基本的DenseNet,使用如下三种网络配置:{ L = 40 , k = 12 },{ L = 100 , k = 12 },{ L = 40 , k = 24 } 。而对于DenseNet-BC结构,使用如下三种网络配置:{ L = 100 , k = 12 } , { L = 250 , k = 24 } ,{ L = 190 , k = 40 } 。这里的 L 指的是网络总层数(网络深度),一般情况下,我们只把带有训练参数的层算入其中,而像Pooling这样的无参数层不纳入统计中,此外BN层尽管包含参数但是也不单独统计,而是可以计入它所附属的卷积层。对于普通的L = 40 , k = 12 网络,除去第一个卷积层、2个Transition中卷积层以及最后的Linear层,共剩余36层,均分到三个DenseBlock可知每个DenseBlock包含12层。其它的网络配置同样可以算出各个DenseBlock所含层数。

在这里插入图片描述

ImageNet数据集上所采用的DenseNet结构

3.1 Dense Block的实现

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

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

class _DenseBlock(nn.Sequential):    """DenseBlock"""    def __init__(self, num_layers, num_input_features, bn_size, growth_rate, drop_rate):        super(_DenseBlock, self).__init__()        for i in range(num_layers):            layer = _DenseLayer(num_input_features+i*growth_rate, growth_rate, bn_size,                                drop_rate)            self.add_module("denselayer%d" % (i+1,), layer)

3.2 Transition Layer的实现

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

class _Transition(nn.Sequential):    """Transition layer between two adjacent DenseBlock"""    def __init__(self, num_input_feature, num_output_features):        super(_Transition, self).__init__()        self.add_module("norm", nn.BatchNorm2d(num_input_feature))        self.add_module("relu", nn.ReLU(inplace=True))        self.add_module("conv", nn.Conv2d(num_input_feature, num_output_features,                                          kernel_size=1, stride=1, bias=False))        self.add_module("pool", nn.AvgPool2d(2, stride=2))

3.3 DenseNet网络

class DenseNet(nn.Module):    "DenseNet-BC model"    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=1000):        """        :param growth_rate: (int) number of filters used in DenseLayer, `k` in the paper        :param block_config: (list of 4 ints) number of layers in each DenseBlock        :param num_init_features: (int) number of filters in the first Conv2d        :param bn_size: (int) the factor using in the bottleneck layer        :param compression_rate: (float) the compression rate used in Transition Layer        :param drop_rate: (float) the drop rate after each DenseLayer        :param num_classes: (int) number of classes for classification        """        super(DenseNet, self).__init__()        # first Conv2d        self.features = nn.Sequential(OrderedDict([            ("conv0", nn.Conv2d(3, num_init_features, kernel_size=7, stride=2, padding=3, bias=False)),            ("norm0", nn.BatchNorm2d(num_init_features)),            ("relu0", nn.ReLU(inplace=True)),            ("pool0", nn.MaxPool2d(3, stride=2, padding=1))        ]))        # DenseBlock        num_features = num_init_features        for i, num_layers in enumerate(block_config):            block = _DenseBlock(num_layers, num_features, bn_size, growth_rate, drop_rate)            self.features.add_module("denseblock%d" % (i + 1), block)            num_features += num_layers*growth_rate            if i != len(block_config) - 1:                transition = _Transition(num_features, int(num_features*compression_rate))                self.features.add_module("transition%d" % (i + 1), transition)                num_features = int(num_features * compression_rate)        # final bn+ReLU        self.features.add_module("norm5", nn.BatchNorm2d(num_features))        self.features.add_module("relu5", nn.ReLU(inplace=True))        # classification layer        self.classifier = nn.Linear(num_features, num_classes)        # params 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

3.4 DenseNet-121网络

这里实现了DenseNet-121网络,且可以通过设置是否预训练来加载Pytorch模型中的DenseNet-121模型。

def densenet121(pretrained=False, **kwargs):    """DenseNet121"""    model = DenseNet(num_init_features=64, growth_rate=32, block_config=(6, 12, 24, 16),                     **kwargs)    if pretrained:        # '.'s are no longer allowed in module names, but pervious _DenseLayer        # has keys 'norm.1', 'relu.1', 'conv.1', 'norm.2', 'relu.2', 'conv.2'.        # They are also in the checkpoints in model_urls. This pattern is used        # to find such keys.        pattern = re.compile(            r'^(.*denselayer\d+\.(?:norm|relu|conv))\.((?:[12])\.(?:weight|bias|running_mean|running_var))$')        state_dict = model_zoo.load_url(model_urls['densenet121'])        for key in list(state_dict.keys()):            res = pattern.match(key)            if res:                new_key = res.group(1) + res.group(2)                state_dict[new_key] = state_dict[key]                del state_dict[key]        model.load_state_dict(state_dict)    return model

4. 测试

最后,我们使用一个简单的代码来对模型进行测试。
注意:输入必须是224,224的图片,如果不是的话模型参数需要进行调整。

model = densenet121()x = torch.rand(size=(1,3,224,224))print(model(x).shape)

阅读本书更多章节>>>>

本文链接:https://www.kjpai.cn/gushi/2024-04-29/163469.html,文章来源:网络cs,作者:纳雷武,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。

文章评论