精华内容
下载资源
问答
  • 1.使用pytorch,使用全连接层,而不是用卷积层,要求有两层隐含层 2. 尽一切可能提高准确率,在这里训练集上达到99.9%以上
  • 详解DenseNet(密集连接的卷积网络)

    千次阅读 2020-12-31 16:12:04
    ResNet模型的核心是通过建立前面与后面之间的“短路连接”(shortcuts,skip connection),这有助于训练过程中梯度的反向传播,从而能训练出更深的CNN网络。今天我们要介绍的是 DenseNet(Densely connected con

    前言

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


    设计理念

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

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

    如果用公式表示的话,传统的网络在 l l l层的输出为:
    x l = H l ( x l − 1 ) x_l = H_l(x_{l-1}) xl=Hl(xl1)

    而对于ResNet,增加了来自上一层输入的identity函数:

    x l = H l ( x l − 1 ) + x l − 1 x_l = H_l(x_{l-1})+x_{l-1} xl=Hl(xl1)+xl1

    在DenseNet中,会连接前面所有层作为输入:

    x l = H l ( [ x 0 , x 1 , . . . , x l − 1 ] ) x_l = H_l([x_0,x_1,...,x_{l-1}]) xl=Hl([x0,x1,...,xl1])

    其中,上面的 H l ( ⋅ ) H_l(·) Hl()代表是非线性转化函数(non-liear transformation),它是一个组合操作,其可能包括一系列的BN(Batch Normalization),ReLU,Pooling及Conv操作。注意这里 l l l层与 l − 1 l-1 l1层之间可能实际上包含多个卷积层。

    DenseNet的前向过程如图所示,可以更直观地理解其密集连接方式,比如 h 3 h_3 h3 的输入不仅包括来自 h 2 h_2 h2 x 2 x_2 x2,还包括前面两层的 x 1 x_1 x1 x 2 x_2 x2 ,它们是在channel维度上连接在一起的。

    DenseNet的前向过程

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

    使用DenseBlock+Transition的DenseNet网络

    网络结构

    如前所示,DenseNet的网络结构主要由DenseBlockTransition组成,如图所示。下面具体介绍网络的具体实现细节。

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

    DenseBlock中的非线性转换结构

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

    使用bottleneck层的DenseBlock结构

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

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

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

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

    实验结果及讨论

    这里给出DenseNet在CIFAR-100和ImageNet数据集上与ResNet的对比结果,如下图所示。从图1中可以看到,只有0.8M的DenseNet-100性能已经超越ResNet-1001,并且后者参数大小为10.2M。而从图2中可以看出,同等参数大小时,DenseNet也优于ResNet网络。其它实验结果见原论文。

    在CIFAR-100数据集上ResNet vs DenseNet

    在ImageNet数据集上ResNet vs DenseNet

    综合来看,DenseNet的优势主要体现在以下几个方面:

    • 由于密集连接方式,DenseNet提升了梯度的反向传播,使得网络更容易训练。由于每层可以直达最后的误差信号,实现了隐式的“deep supervision”
    • 参数更小且计算更高效,这有点违反直觉,由于DenseNet是通过concat特征来实现短路连接,实现了特征重用,并且采用较小的growth rate,每个层所独有的特征图是比较小的;
    • 由于特征复用,最后的分类器使用了低级特征。

    要注意的一点是,如果实现方式不当的话,DenseNet可能耗费很多GPU显存,一种高效的实现如图所示,更多细节可以见这篇论文Memory-Efficient Implementation of DenseNets。不过我们下面使用Pytorch框架可以自动实现这种优化。

    DenseNet的更高效实现方式

    使用Pytorch实现DenseNet

    这里我们采用Pytorch框架来实现DenseNet,目前它已经支持Windows系统。对于DenseNet,Pytorch在torchvision.models模块里给出了官方实现,这个DenseNet版本是用于ImageNet数据集的DenseNet-BC模型,下面简单介绍实现过程。

    首先实现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)
            return torch.cat([x, new_features], 1)
    
    

    据此,实现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)
    

    此外,我们实现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))
    

    最后我们实现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
    

    选择不同网络参数,就可以实现不同深度的DenseNet,这里实现DenseNet-121网络,而且Pytorch提供了预训练好的网络参数:

    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
    

    下面,我们使用预训练好的网络对图片进行测试,这里给出top-5预测值:

    densenet = densenet121(pretrained=True)
    densenet.eval()
    
    img = Image.open("./images/cat.jpg")
    
    trans_ops = transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406],
                             std=[0.229, 0.224, 0.225])
    ])
    
    images = trans_ops(img).view(-1, 3, 224, 224)
    outputs = densenet(images)
    
    _, predictions = outputs.topk(5, dim=1)
    
    labels = list(map(lambda s: s.strip(), open("./data/imagenet/synset_words.txt").readlines()))
    for idx in predictions.numpy()[0]:
        print("Predicted labels:", labels[idx])
    

    给出的预测结果为:

    Predicted labels: n02123159 tiger cat
    Predicted labels: n02123045 tabby, tabby cat
    Predicted labels: n02127052 lynx, catamount
    Predicted labels: n02124075 Egyptian cat
    Predicted labels: n02119789 kit fox, Vulpes macrotis
    

    注:完整代码见xiaohu2015/DeepLearning_tutorials

    小结

    这篇文章详细介绍了DenseNet的设计理念以及网络结构,并给出了如何使用Pytorch来实现。值得注意的是,DenseNet在ResNet基础上前进了一步,相比ResNet具有一定的优势,但是其却并没有像ResNet那么出名(吃显存问题?深度不能太大?)。期待未来有更好的网络模型出现吧!


    参考文献

    1. DenseNet-CVPR-Slides.

    2. Densely Connected Convolutional Networks.

    本文是搬运,作者写的太好了。DenseNet:比ResNet更优的CNN模型。推荐一波,之前ResNet也是看的他的。

    展开全文
  • 密集连接的金字塔除雾网络(CVPR'2018) , [](CVPR'18) 我们提出了一种新的端到端单图像除雾方法,称为密集连接金字塔除雾网络(DCPDN),该方法可以共同学习透射图,大气光和除雾。 通过将大气散射模型直接嵌入...
  • 在判别网络结构中,采用6个卷积模块和一个全连接层对真伪图像进行甄别,采用对抗博弈的思想,提升重建图像的质量。实验结果表明,本文算法在视觉效果评估、峰值信噪比值、结构相似性值以及耗时等多方面指标上都有了很大...
  • 采用密集连接的网络结构,充分利用每网络提取的特征,减少网络推理时间;采用具有更大感受野的扩张块结构;使用扩张块结构和反卷积网络结构将浅层特征图和深层特征图进行信息融合,从而增强遥感图像中多尺度目标的检测...
  • 目录密集连接网络keras.layers.Inputkeras.models.Model多输入和多输出模型 密集连接网络 该Sequential模型可能是实现这种网络的更好选择,但它有助于从非常简单的事情开始。 图层实例可调用(在张量上),并...


    参考:RNN及LSTM: https://blog.csdn.net/zhaojc1995/article/details/80572098

    密集连接网络

    该Sequential模型可能是实现这种网络的更好选择,但它有助于从非常简单的事情开始。

    • 图层实例可调用(在张量上),并返回张量
    • 然后可以使用输入张量和输出张量来定义Model
    • 这种模型可以像Keras Sequential模型一样进行训练。
    from keras.layers import Input, Dense
    from keras.models import Model
    import keras
    import numpy as np
    from tensorflow.examples.tutorials.mnist import input_data
    import tensorflow as tf
    
    # 载入数据
    batch_sizes = 10000
    def loadData(filename):
        mnist = input_data.read_data_sets(filename, one_hot=True)
        mnist.train.cls = np.argmax(mnist.train.labels, axis=1)
        mnist.test.cls = np.argmax(mnist.test.labels, axis=1)
        mnist.validation.cls = np.argmax(mnist.validation.labels, axis=1)
        return mnist
    
    
    datas = loadData(r'C:\Users\Cs\Desktop\深度学习\tf_day011\datas\mnist')
    train_images, train_labels = datas.train.next_batch(batch_sizes)
    # 返回一个张量,这个输入数据不包括数据数量维度
    inputs = Input(shape=(784,))
    
    # 一个层实例可以在一个张量上调用,并返回一个张量
    x = Dense(64, activation='relu')(inputs)
    x = Dense(64, activation='relu')(x)
    predictions = Dense(10, activation='softmax')(x)
    
    # 创建一个包含输入层和三个密集层的模型
    model = Model(inputs=inputs, outputs=predictions)
    model.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    model.fit(train_images, train_labels)  # starts training
    # # 与上面功能相同
    # model = keras.Sequential()
    # model.add( Dense(64, activation='relu',input_shape=(784,)))
    # model.add( Dense(64, activation='relu'))
    # model.add( Dense(10, activation='softmax'))
    # model.compile(optimizer='rmsprop',
    #               loss='categorical_crossentropy',
    #               metrics=['accuracy'])
    # model.fit(train_images, train_labels,batch_size=500,epochs=30)  # starts training
    

    keras.layers.Input

    输入接口,返回一个可以使用的张量。
    使用功能API,可以轻松地重用经过训练的模型:通过在张量上调用,可以将任何模型视为一个层。请注意,通过调用模型,您不仅可以重用模型的体系结构,还可以重用其权重。
    示例:

    from keras.layers import Input,
    
    # 生成一个Nx 784的Tensor
    inputs = Input(shape=(784,))
    

    例如,这可以允许快速创建可以处理输入序列的模型。您可以将图像分类模型转换为视频分类模型,只需一行。

    from keras.layers import TimeDistributed
    # 20个时间步序列的输入张量,每个包含784维向量
    input_sequences = Input(shape=(20, 784))
    # 这将把前面的模型应用到输入序列中的每个时间步。前一个模型的输出是一个10路softmax,所以下面这个层的输出将是一个由20个大小为10的向量组成的序列。
    processed_sequences = TimeDistributed(model)(input_sequences)
    

    keras.models.Model

    功能和Sequential()差不多,都是生成模型的,不过上方式通过add增加图层,下方是设计了各图层之间的连接关系,然后再创建Model的时候使用最后一个图层
    示例:

    from keras.models import Model
    # inputs为keras.layers.Input实例,
    # predictions为连接图层,参考最上面的代码
    model = Model(inputs=inputs, outputs=predictions)
    model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['accuracy'])
    model.fit(data, labels)  # starts training
    

    多输入和多输出模型

    这是功能API的一个很好的用例:具有多个输入和输出的模型。功能API使操作大量交织在一起的数据流变得容易。

    让我们考虑以下模型。我们试图预测有多少转推和喜欢新闻标题将在Twitter上收到。模型的主要输入将是标题本身,作为一系列单词,但为了增加趣味,我们的模型还将具有辅助输入,接收额外数据,例如标题发布时的时间等。该模型还将通过两个损失函数进行监督。使用模型中较早的主要损失函数是深度模型的良好正则化机制。
    模型:
    在这里插入图片描述
    用功能API实现它。
    主要输入接收新闻标题本身,即一个整数序列(每个整数编码一个词)。 这些整数在 1 到 10,000 之间(10,000 个词的词汇表),且序列长度为 100 个词。

    from keras.layers import Input, Embedding, LSTM, Dense
    from keras.models import Model
    
    # 标题输入:表示接收100个整数序列,在1到10000之间。
    # 注意,我们可以通过传递一个“name”参数来命名任何层。
    main_input = Input(shape=(100,), dtype='int32', name='main_input')
    # 该嵌入层将输入序列编码为密集的512维向量序列。
    x = Embedding(output_dim=512, input_dim=10000, input_length=100)(main_input)
    
    # LSTM将把向量序列转换为包含关于整个序列的信息的单个向量
    lstm_out = LSTM(32)(x)
    

    在这里,我们插入辅助损失,使得即使在模型主损失很高的情况下,LSTM 层和 Embedding 层都能被平稳地训练。

    auxiliary_output = Dense(1, activation='sigmoid', name='aux_output')(lstm_out)
    

    此时,我们将辅助输入数据与 LSTM 层的输出连接起来,输入到模型中:

    auxiliary_input = Input(shape=(5,), name='aux_input')
    x = keras.layers.concatenate([lstm_out, auxiliary_input])
    
    # 堆叠多个全连接网络层
    x = Dense(64, activation='relu')(x)
    x = Dense(64, activation='relu')(x)
    x = Dense(64, activation='relu')(x)
    
    # 最后添加主要的逻辑回归层
    main_output = Dense(1, activation='sigmoid', name='main_output')(x)
    

    然后定义一个具有两个输入和两个输出的模型:

    model = Model(inputs=[main_input, auxiliary_input], outputs=[main_output, auxiliary_output])
    

    现在编译模型,并给辅助损失分配一个 0.2 的权重。如果要为不同的输出指定不同的 loss_weightsloss,可以使用列表或字典。 在这里,我们给 loss 参数传递单个损失函数,这个损失将用于所有的输出。

    model.compile(optimizer='rmsprop', loss='binary_crossentropy',
                  loss_weights=[1., 0.2])
    

    我们可以通过传递输入数组和目标数组的列表来训练模型:

    model.fit([headline_data, additional_data], [labels, labels],
              epochs=50, batch_size=32)
    

    由于输入和输出均被命名了(在定义时传递了一个 name参数),我们也可以通过以下方式编译模型:

    model.compile(optimizer='rmsprop',
                  loss={'main_output': 'binary_crossentropy', 'aux_output': 'binary_crossentropy'},
                  loss_weights={'main_output': 1., 'aux_output': 0.2})
    
    # 然后使用以下方式训练:
    model.fit({'main_input': headline_data, 'aux_input': additional_data},
              {'main_output': labels, 'aux_output': labels},
              epochs=50, batch_size=32)
    

    共享网络层

    函数式 API 的另一个用途是使用共享网络层的模型。我们来看看共享层。
    来考虑推特推文数据集。我们想要建立一个模型来分辨两条推文是否来自同一个人(例如,通过推文的相似性来对用户进行比较)。
    实现这个目标的一种方法是建立一个模型,将两条推文编码成两个向量,连接向量,然后添加逻辑回归层;这将输出两条推文来自同一作者的概率。模型将接收一对对正负表示的推特数据。
    由于这个问题是对称的,编码第一条推文的机制应该被完全重用来编码第二条推文。这里我们使用一个共享的 LSTM 层来编码推文。
    让我们使用函数式 API 来构建它。首先我们将一条推特转换为一个尺寸为 (140, 256) 的矩阵,即每条推特 140 字符,每个字符为 256 维的 one-hot 编码 (取 256 个常用字符)。

    import keras
    from keras.layers import Input, LSTM, Dense
    from keras.models import Model
    
    tweet_a = Input(shape=(140, 256))
    tweet_b = Input(shape=(140, 256))
    

    要在不同的输入上共享同一个层,只需实例化该层一次,然后根据需要传入你想要的输入即可:

    # 这一层可以输入一个矩阵,并返回一个 64 维的向量
    shared_lstm = LSTM(64)
    
    # 当我们重用相同的图层实例多次,图层的权重也会被重用 (它其实就是同一层)
    encoded_a = shared_lstm(tweet_a)
    encoded_b = shared_lstm(tweet_b)
    
    # 然后再连接两个向量:
    merged_vector = keras.layers.concatenate([encoded_a, encoded_b], axis=-1)
    
    # 再在上面添加一个逻辑回归层
    predictions = Dense(1, activation='sigmoid')(merged_vector)
    
    # 定义一个连接推特输入和预测的可训练的模型
    model = Model(inputs=[tweet_a, tweet_b], outputs=predictions)
    
    model.compile(optimizer='rmsprop',
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    model.fit([data_a, data_b], labels, epochs=10)
    

    让我们暂停一会,看看如何读取共享层的输出或输出尺寸。

    层「节点」的概念

    每当你在某个输入上调用一个层时,都将创建一个新的张量(层的输出),并且为该层添加一个「节点」,将输入张量连接到输出张量。当多次调用同一个图层时,该图层将拥有多个节点索引 (0, 1, 2…)。
    在之前版本的 Keras 中,可以通过 layer.get_output()来获得层实例的输出张量,或者通过 layer.output_shape来获取其输出形状。现在你依然可以这么做(除了 get_output()已经被 output属性替代)。但是如果一个层与多个输入连接呢?
    只要一个层只连接到一个输入,就不会有困惑,.output会返回层的唯一输出:

    a = Input(shape=(140, 256))
    lstm = LSTM(32)
    encoded_a = lstm(a)
    assert lstm.output == encoded_a
    

    但是如果该层有多个输入,那就会出现问题:

    a = Input(shape=(140, 256))
    b = Input(shape=(140, 256))
    
    lstm = LSTM(32)
    encoded_a = lstm(a)
    encoded_b = lstm(b)
    
    lstm.output
    >> AttributeError: Layer lstm_1 has multiple inbound nodes,
    hence the notion of "layer output" is ill-defined.
    Use `get_output_at(node_index)` instead.
    

    好吧,通过下面的方法可以解决:

    assert lstm.get_output_at(0) == encoded_a
    assert lstm.get_output_at(1) == encoded_b
    

    input_shapeoutput_shape这两个属性也是如此:只要该层只有一个节点,或者只要所有节点具有相同的输入/输出尺寸,那么「层输出/输入尺寸」的概念就被很好地定义,并且将由 layer.output_shape/ layer.input_shape返回。但是比如说,如果将一个 Conv2D 层先应用于尺寸为 (32,32,3) 的输入,再应用于尺寸为 (64, 64, 3) 的输入,那么这个层就会有多个输入/输出尺寸,你将不得不通过指定它们所属节点的索引来获取它们:

    a = Input(shape=(32, 32, 3))
    b = Input(shape=(64, 64, 3))
    
    conv = Conv2D(16, (3, 3), padding='same')
    conved_a = conv(a)
    
    # 到目前为止只有一个输入,以下可行:
    assert conv.input_shape == (None, 32, 32, 3)
    
    conved_b = conv(b)
    # 现在 `.input_shape` 属性不可行,但是这样可以:
    assert conv.get_input_shape_at(0) == (None, 32, 32, 3)
    assert conv.get_input_shape_at(1) == (None, 64, 64, 3)
    
    展开全文
  • 密集连接融合后组成的密集块结构使图像区域的上下文信息得到有效利用。激励模块将有价值的全局信息选择性放大并将无用特征加以抑制。图像重建部分中的多个1×1卷积层结构减小了前一的尺寸,在加速计算的同时减少了...
  • 对 n-1 层和 n 层而言,n-1 层的任意一个节点,都和第 n 层所有节点有连接(即第n层...符合这种特征的卷积网络层,被称为全连接层。像下面的中间层就是全连接方式 参考文章:卷积神经网络中的 “全连接层” ...

    对 n-1 层和 n 层而言,n-1 层的任意一个节点,都和第 n 层所有节点有连接(即第n层节点都和第n-1层节点相连接)。即第n层的每个节点在进行计算的时候,激活函数的输入是n-1层所有节点的加权。符合这种特征的卷积网络层,被称为全连接层。像下面的中间层就是全连接方式

    在这里插入图片描述

    参考文章1:卷积神经网络中的 “全连接层”

    参考文章2:全连接层

    展开全文
  • 主要是将SE模块融合到密集连接模块,并使用共享显存的方式减少显存的大小。
  • 但这些措施都有一个共性:都是在前一和后一中都建立一个短连接。比如,酱紫: 1.2 本文概要 1.2.1 模型结构预览 本文提出的densenet就更霸道了,为了确保网络中最大的信息流通,让每都与改之前的...

    image_1cs0pegkqocnqk61imqab7sjv6h.png-57.3kB


    @[t oc]

    1 简单介绍

    image_1crv3fp6h1281lqn1fc01irl17j719.png-56.5kB

    论文题目:Densely Connected Convolutional Networks
    发表机构:康奈尔大学,清华大学,Facebook AI
    发表时间:2018年1月
    论文代码:https://github.com/WangXiaoCao/attention-is-all-you-need-pytorch
    pytorch代码:https://github.com/WangXiaoCao/attention-is-all-you-need-pytorch

    1.1 背景介绍

    1.卷积神经网络CNN在计算机视觉物体识别上优势显著,典型的模型有:LeNet5, VGG, Highway Network, Residual Network.

    2.CNN越深则效果越好,但是,会面临梯度弥散的问题,经过层数越多,则前面的信息就会渐渐减弱和消散。

    3.目前已有很多措施去解决以上困境:
    (1)Highway Network,Residual Network通过前后两层的残差链接使信息尽量不丢失
    (2)Stochastic depth通过随机drop掉Resnet的一些层来缩短模型
    (3)FractalNets通过重复组合一些平行的层序列来保证深度的同时减轻这个问题。
    但这些措施都有一个共性:都是在前一层和后一层中都建立一个短连接。比如,酱紫:
    image_1crv7ht2oe0thm5lgm57c178n1m.png-19.7kB

    1.2 本文概要

    1.2.1 模型结构预览

    本文提出的densenet就更霸道了,为了确保网络中最大的信息流通,让每层都与改层之前的所有层都相连,即每层的输入,是前面所有层的输出的concat.(resnet用的是sum).整体结构是酱紫的:
    image_1crv7tocd1a5k87n1okb1a9o12mg23.png-58.4kB

    1.2.2 优点

    1.需要更少参数。

    2.使得信息(前向计算时)或梯度(后向计算时)在整个网络中的保持地更好,可以训练更深的模型。

    3.dense connection有正则化的效果,在较少训练集上减少过拟合。

    1.2.3 实验结果

    在4个benchmark datasets (CIFAR-10, CIFAR-100, SVHN, and
    ImageNet)上测试。
    大部分任务上都优于state of art.

    2 模型结构

    2.1 整体结构

    image_1crv9jqh11qpfn3e2vo3fuujf2g.png-66.2kB

    1.输入:图片
    2.经过feature block(图中的第一个convolution层,后面可以加一个pooling层,这里没有画出来)
    3.经过第一个dense block, 该Block中有n个dense layer,灰色圆圈表示,每个dense layer都是dense connection,即每一层的输入都是前面所有层的输出的拼接
    4.经过第一个transition block,由convolution和poolling组成
    5.经过第二个dense block
    6.经过第二个transition block
    7.经过第三个dense block
    8.经过classification block,由pooling,linear层组成,输出softmax的score
    9.经过prediction层,softmax分类
    10.输出:分类概率

    作者在4个数据集上进行测试,CIFAR-10, CIFAR-100, SVHN上构建的是以上3个dense block + 2个transition block;在ImageNet上构建的是4个dense block + 3个transition block。两者在参数的设置上略有不同,下文将以ImageNet上构建的densenet为例进行讲解。

    2.2 Feature Block

    Feature Block是输入层与第一个Dense Block之间的那一部分,上面结构图中只画了一个卷积,在ImageNet数据集上构建的densenet中其实后面还跟了一个poolling层。计算过程如下:

    输入:图片 (244 * 244 * 3)
    1.卷积层convolution计算:in_channel=3, out_channel=64,kernel_size=7,stride=2,padding=3,输出(122 * 122 * 64)
    2.batch normalization计算,输入与输出维度不变 (122 * 122 * 64)
    3.激活函数relu计算,输入与输出维度不变 (122 * 122 * 64)
    4.池化层poollig计算,kenel_size=3, stride=2,padding=1,输出(56 * 56 * 64)

        from torch.nn import Sequential, Conv2d, BatchNorm2d, ReLU, MaxPool2d
        
        class FeatureBlock(RichRepr, Sequential):
            def __init__(self, in_channels, out_channels):
                super(FeatureBlock, self).__init__()
        
                self.in_channels = in_channels
                self.out_channels = out_channels
        
                # add_module:在现有model中增添子module
                self.add_module('conv', Conv2d(in_channels, out_channels, kernel_size=7, stride=2, padding=3, bias=False)),
                self.add_module('norm', BatchNorm2d(out_channels)),
                self.add_module('relu', ReLU(inplace=True)),
                self.add_module('pool', MaxPool2d(kernel_size=3, stride=2, padding=1)),
    

    2.3 Dense Block 和 Dense Layer

    2.3.1 Dense Layer

    一个Dense Block中是由L层dense laryer组成,layer之间是dense connectivity。从下面这个公式上来体会什么是dense connectivity,第l层的输出是:
    image_1crvbi3r5qljcnisu51al91s742t.png-4.7kB
    H_l是该layer的计算函数,输入是x0到x_l-1的拼接,即模型的原始输出(x0)和前面每层的输出的拼接。这个拼接是channel维度上的拼接,即维度(56 * 56 * 64)的数据 和(56 * 56 * 32)的数据拼接成(56 * 56 * 96)的数据维度。

    而ResNet就不同了,是直接将前一层的输出加在该层的输出之上:
    image_1crvbmdhu7o242247417jh1vpi3a.png-3.9kB
    Dense Layer中函数H(·)的计算过程如下(括号中的数据维度是以第一个dense block的第一个dense layer为例的,整个模型的k值是预先设定的,本模型为k=32):

    输入:Feature Block的输出(56 * 56 * 64)或者是上一层dense layer的输出
    1.Batch Normalization, 输出(56 * 56 * 64)
    2.ReLU ,输出(56 * 56 * 64)
    3.Bottleneck,是可选的,为了减少 feature-maps的数量,过程如下3步
    -1x1 Convolution, kernel_size=1, channel = 4k, 则输出为(56 * 56 * 128)
    -Batch Normalization(56 * 56 * 128)
    -ReLU(56 * 56 * 128)
    4.Convolution, kernel_size=3, channel = k (56 * 56 * 32)
    5.Dropout,可选的,用于防止过拟合(56 * 56 * 32)

    from typing import Optional
    from torch.nn import Sequential, BatchNorm2d, ReLU, Conv2d, Dropout2d
    from .bottleneck import Bottleneck
    
    class DenseLayer(RichRepr, Sequential):
        r"""
        Dense Layer as described in [DenseNet](https://arxiv.org/abs/1608.06993)
        and implemented in https://github.com/liuzhuang13/DenseNet
    
        Consists of:
    
        - Batch Normalization
        - ReLU
        - (Bottleneck)
        - 3x3 Convolution
        - (Dropout)
        """
    
        def __init__(self, in_channels: int, out_channels: int,
                     bottleneck_ratio: Optional[int] = None, dropout: float = 0.0):
            super(DenseLayer, self).__init__()
    
            self.in_channels = in_channels
            self.out_channels = out_channels
    
            self.add_module('norm', BatchNorm2d(num_features=in_channels))
            self.add_module('relu', ReLU(inplace=True))
    
            if bottleneck_ratio is not None:
                self.add_module('bottleneck', Bottleneck(in_channels, bottleneck_ratio * out_channels))
                in_channels = bottleneck_ratio * out_channels
    
            self.add_module('conv', Conv2d(in_channels, out_channels, kernel_size=3, padding=1, bias=False))
    
            if dropout > 0:
                self.add_module('drop', Dropout2d(dropout, inplace=True))
    

    Bottleneck代码如下:

    from torch.nn import Sequential, Conv2d, BatchNorm2d, ReLU
    
    from ..utils import RichRepr
    
    
    class Bottleneck(RichRepr, Sequential):
        r"""
        A 1x1 convolutional layer, followed by Batch Normalization and ReLU
        """
    
        def __init__(self, in_channels: int, out_channels: int):
            super(Bottleneck, self).__init__()
    
            self.in_channels = in_channels
            self.out_channels = out_channels
    
            self.add_module('conv', Conv2d(in_channels, out_channels, kernel_size=1, bias=False))
            self.add_module('norm', BatchNorm2d(num_features=out_channels))
            self.add_module('relu', ReLU(inplace=True))
    

    2.3.2 Dense Block

    Dense Block有L层dense layer组成
    layer 0:输入(56 * 56 * 64)->输出(56 * 56 * 32)
    layer 1:输入(56 * 56 (32 * 1))->输出(56 * 56 * 32)
    layer 2:输入(56 * 56
    (32 * 2))->输出(56 * 56 * 32)

    layer L:输入(56 * 56 * (32 * L))->输出(56 * 56 * 32)

    注意,L层dense layer的输出都是不变的,而每层的输入channel数是增加的,因为如上所述,每层的输入是前面所有层的拼接。

    rom typing import Optional
    import torch
    from torch.nn import Module
    from .dense_layer import DenseLayer
    
    class DenseBlock(RichRepr, Module):
        r"""
        Dense Block as described in [DenseNet](https://arxiv.org/abs/1608.06993)
        and implemented in https://github.com/liuzhuang13/DenseNet
    
        - Consists of several DenseLayer (possibly using a Bottleneck and Dropout) with the same output shape
        - The first DenseLayer is fed with the block input
        - Each subsequent DenseLayer is fed with a tensor obtained by concatenating the input and the output
          of the previous DenseLayer on the channel axis
        - The block output is the concatenation of the output of every DenseLayer, and optionally the block input,
          so it will have a channel depth of (growth_rate * num_layers) or (growth_rate * num_layers + in_channels)
        """
    
        def __init__(self, in_channels: int, growth_rate: int, num_layers: int,
                     concat_input: bool = False, dense_layer_params: Optional[dict] = None):
            super(DenseBlock, self).__init__()
    
            self.concat_input = concat_input
            self.in_channels = in_channels
            self.growth_rate = growth_rate
            self.num_layers = num_layers
            self.out_channels = growth_rate * num_layers
            if self.concat_input:
                self.out_channels += self.in_channels
    
            if dense_layer_params is None:
                dense_layer_params = {}
    
            for i in range(num_layers):
                # 增添dense_layer:norm->relu->bottleneck->conv->dropout
                self.add_module(
                    f'layer_{i}',
                    DenseLayer(in_channels=in_channels + i * growth_rate, out_channels=growth_rate, **dense_layer_params)
                )
    
        def forward(self, block_input):
            layer_input = block_input
            # empty tensor (not initialized) + shape=(0,)
            layer_output = block_input.new_empty(0)
    
            all_outputs = [block_input] if self.concat_input else []
            for layer in self._modules.values():
                layer_input = torch.cat([layer_input, layer_output], dim=1)
                layer_output = layer(layer_input)
                all_outputs.append(layer_output)
    
            return torch.cat(all_outputs, dim=1)
    

    2.4 Transition Block

    Transition Block是在两个Dense Block之间的,由一个卷积+一个pooling组成(下面的数据维度以第一个transition block为例):

    输入:Dense Block的输出(56 * 56 * 32)
    1.Batch Normalization 输出(56 * 56 * 32)
    2.ReLU 输出(56 * 56 * 32)
    3.1x1 Convolution,kernel_size=1,此处可以根据预先设定的压缩系数(0-1之间)来压缩原来的channel数,以减小参数,输出(56 * 56 *(32 * compression))
    4.2x2 Average Pooling 输出(28 * 28 * (32 * compression))

    class Transition(RichRepr, Sequential):
        r"""
        Transition Block as described in [DenseNet](https://arxiv.org/abs/1608.06993)
        and implemented in https://github.com/liuzhuang13/DenseNet
    
        Consists of:
        - Batch Normalization
        - ReLU
        - 1x1 Convolution (with optional compression of the number of channels)
        - 2x2 Average Pooling
        """
    
        def __init__(self, in_channels, compression: float = 1.0):
            super(Transition, self).__init__()
            if not 0.0 < compression <= 1.0:
                raise ValueError(f'Compression must be in (0, 1] range, got {compression}')
    
            self.in_channels = in_channels
            # transition中可设置压缩系数,以减少输出channel
            self.out_channels = int(ceil(compression * in_channels))
    
            self.add_module('norm', BatchNorm2d(num_features=self.in_channels))
            self.add_module('relu', ReLU(inplace=True))
            self.add_module('conv', Conv2d(self.in_channels, self.out_channels, kernel_size=1, bias=False))
            self.add_module('pool', AvgPool2d(kernel_size=2, stride=2))
    

    2.5 循环Dense Block和Transition

    论文中,在ImageNet的数据集上,构建的densenet是由4个Dense Block,和3个Transition构成,按照上文讲述的过程,数据流的演变过程应该是:

    Dense Block1:输入(565664),输出(565632)
    Transition1:输入(565632),输出(282832)
    Dense Block2:输入(282832),输出(282832)
    Transition2:输入(282832),输出(141432)
    Dense Block3:输入(141432),输出(141432)
    Transition3:输入(141432),输出(7732)

    2.6 ClassificationBlock

    最后一步是ClassificationBlock,这一步将原来3维的数据拉平成一维,再接上全连接层,以准备做softmax。计算过程如下:

    输入:Transition3的输出(7 * 7 * 32)
    1.Batch Normalization, 输出(7 * 7 * 32)
    2.ReLU, 输出(7 * 7 * 32)
    3.poolling, kernel_size=7, stride=1,输出(1 * 1 * 32)
    4.flatten,将(1 * 1 * 32)铺平成(1 * 32)
    5.Linear全连接,输出(1*classes_num) classes_num为待分类的数目

    from torch.nn import Sequential, BatchNorm2d, ReLU, AvgPool2d, Linear
    from ..shared import Flatten
    
    class ClassificationBlock(RichRepr, Sequential):
        r"""
        Classification block for [DenseNet](https://arxiv.org/abs/1608.06993),
        takes in a 7x7 feature map and outputs logit scores for classification
        """
    
        def __init__(self, in_channels, output_classes):
            super(ClassificationBlock, self).__init__()
    
            self.in_channels = in_channels
            self.out_classes = output_classes
    
            self.add_module('norm', BatchNorm2d(num_features=in_channels))
            self.add_module('relu', ReLU(inplace=True))
            self.add_module('pool', AvgPool2d(kernel_size=7, stride=1))
            self.add_module('flatten', Flatten())
            self.add_module('linear', Linear(in_channels, output_classes))
    
    

    flaten代码如下:

    from torch.nn import Module
    
    class Flatten(Module):
        def forward(self, x):
            return x.view(x.size(0), -1)
    

    最后将以上输出进入softmax,预测每个类别的概率。

    logits = self(x)  //x是linear层的输出
    return F.softmax(logits)
    

    2.7 整合以上过程

    将以上所有过程都这个起来,构建一个完整的densenet模型,代码如下:

    from itertools import zip_longest
    from typing import Sequence, Union, Optional
    from torch.nn import Sequential, Conv2d, BatchNorm2d, Linear, init
    from torch.nn import functional as F
    from .classification_block import ClassificationBlock
    from .feature_block import FeatureBlock
    from .transition import Transition
    from ..shared import DenseBlock
    
    
    # 继承Sequential类
    class DenseNet(Sequential):
        def __init__(self,
                     in_channels: int = 3,
                     output_classes: int = 1000,
                     initial_num_features: int = 64,
                     dropout: float = 0.0,
    
                     dense_blocks_growth_rates: Union[int, Sequence[int]] = 32,
                     dense_blocks_bottleneck_ratios: Union[Optional[int], Sequence[Optional[int]]] = 4,
                     dense_blocks_num_layers: Union[int, Sequence[int]] = (6, 12, 24, 16),
                     transition_blocks_compression_factors: Union[float, Sequence[float]] = 0.5):
            """
            构建完成densenet模型
            :param in_channels: 输入的channel数目
            :param output_classes: 待分类别树
            :param initial_num_features: 进入第一个Block的feature map数目
            :param dropout: dropout的比率
            :param dense_blocks_growth_rates: k(block中的channel数)
            :param dense_blocks_bottleneck_ratios: (bottleneck的比率)
            :param dense_blocks_num_layers: densenet的block数目
            :param transition_blocks_compression_factors: 在transition层中的压缩系数(0-1之间)
            """
            super(DenseNet, self).__init__()
    
            # region Parameters handling
            self.in_channels = in_channels
            self.output_classes = output_classes
    
            # 扩展成4维:(10,10,10,10)
            if type(dense_blocks_growth_rates) == int:
                dense_blocks_growth_rates = (dense_blocks_growth_rates,) * 4
            if dense_blocks_bottleneck_ratios is None or type(dense_blocks_bottleneck_ratios) == int:
                dense_blocks_bottleneck_ratios = (dense_blocks_bottleneck_ratios,) * 4
            if type(dense_blocks_num_layers) == int:
                dense_blocks_num_layers = (dense_blocks_num_layers,) * 4
            if type(transition_blocks_compression_factors) == float:
                transition_blocks_compression_factors = (transition_blocks_compression_factors,) * 3
            # endregion
    
            # region First convolution
            # 1.第一个卷积:covn->norm->relu->pool
            features = FeatureBlock(in_channels, initial_num_features)
            current_channels = features.out_channels
            self.add_module('features', features)
            # endregion
    
            # region Dense Blocks and Transition layers
            # Dense Blocks 参数
            dense_blocks_params = [
                {
                    'growth_rate': gr,
                    'num_layers': nl,
                    'dense_layer_params': {
                        'dropout': dropout,
                        'bottleneck_ratio': br
                    }
                }
                for gr, nl, br in zip(dense_blocks_growth_rates, dense_blocks_num_layers, dense_blocks_bottleneck_ratios)
            ]
            # Transition layers 参数
            transition_blocks_params = [
                {
                    'compression': c
                }
                for c in transition_blocks_compression_factors
            ]
    
            block_pairs_params = zip_longest(dense_blocks_params, transition_blocks_params)
            for block_pair_idx, (dense_block_params, transition_block_params) in enumerate(block_pairs_params):
                block = DenseBlock(current_channels, **dense_block_params)
                current_channels = block.out_channels
                # 增添DenseBlock:dense_block->dense_block->...dense_block
                self.add_module(f'block_{block_pair_idx}', block)
    
                if transition_block_params is not None:
                    transition = Transition(current_channels, **transition_block_params)
                    current_channels = transition.out_channels
                    # 增加transition:covn->norm->relu->pool
                    self.add_module(f'trans_{block_pair_idx}', transition)
            # endregion
    
            # region Classification block
            # 添加最后的分类层:norm->relu->poll->flaten->linear
            self.add_module('classification', ClassificationBlock(current_channels, output_classes))
            # endregion
    
            # region Weight initialization
            for module in self.modules():
                if isinstance(module, Conv2d):
                    init.kaiming_normal_(module.weight)
                elif isinstance(module, BatchNorm2d):
                    module.reset_parameters()
                elif isinstance(module, Linear):
                    init.xavier_uniform_(module.weight)
                    init.constant_(module.bias, 0)
            # endregion
    
        def predict(self, x):
            logits = self(x)
            return F.softmax(logits)
    

    我们可以根据构建好的densenet模型,输入不同参数,得到自定义的densenet模型,论文中,作者分别尝试了如下深度的模型:
    区别在于dense_blocks_num_layers的设置,也就是每个dense block中的dense layer的数目。

    from .densenet import DenseNet
    
    class DenseNet121(DenseNet):
        def __init__(self, dropout: float = 0.0):
            super(DenseNet121, self).__init__(
                in_channels=3,
                output_classes=1000,
                initial_num_features=64,
                dropout=dropout,
                dense_blocks_growth_rates=32,
                dense_blocks_bottleneck_ratios=4,
                dense_blocks_num_layers=(6, 12, 24, 16),
                transition_blocks_compression_factors=0.5
            )
    
    
    class DenseNet169(DenseNet):
        def __init__(self, dropout: float = 0.0):
            super(DenseNet169, self).__init__(
                in_channels=3,
                output_classes=1000,
                initial_num_features=64,
                dropout=dropout,
                dense_blocks_growth_rates=32,
                dense_blocks_bottleneck_ratios=4,
                dense_blocks_num_layers=(6, 12, 32, 32),
                transition_blocks_compression_factors=0.5
            )
    
    
    class DenseNet201(DenseNet):
        def __init__(self, dropout: float = 0.0):
            super(DenseNet201, self).__init__(
                in_channels=3,
                output_classes=1000,
                initial_num_features=64,
                dropout=dropout,
                dense_blocks_growth_rates=32,
                dense_blocks_bottleneck_ratios=4,
                dense_blocks_num_layers=(6, 12, 48, 32),
                transition_blocks_compression_factors=0.5
            )
    
    
    class DenseNet161(DenseNet):
        def __init__(self, dropout: float = 0.0):
            super(DenseNet161, self).__init__(
                in_channels=3,
                output_classes=1000,
                initial_num_features=64,
                dropout=dropout,
                dense_blocks_growth_rates=48,
                dense_blocks_bottleneck_ratios=4,
                dense_blocks_num_layers=(6, 12, 36, 24),
                transition_blocks_compression_factors=0.5
            )
    
    
    

    3 实验与结果

    3.1 训练参数

    参数CIFAR和SVHN数据集上ImageNet数据
    优化方式梯度下降梯度下降
    batch size64256
    epoch300for CIFAR40 forSVHN90
    learning rateinitial learning rate is set to 0.1, and is divided by 10 at 50% and 75% of the total number of training epochsThe learning rate is set to 0.1 initially, and is lowered by 10 times at epoch 30 and 60
    weight decay10^-410^-4
    Nesterov momentum0.90.9
    drop rate0.20.2

    3.2 结果

    在CIFAR和SVHN数据集上的结果:
    image_1cs0mn3vbjqja0c1mb8b12vjc3n.png-231.5kB

    在Imagenet上的结果:
    image_1cs0msmmp3r9okd1qmi1cu518te44.png-121.9kB

    image_1cs0mtcs810jve0s1pve4h13vt4h.png-97.6kB


    文章代码来自:https://github.com/WangXiaoCao/attention-is-all-you-need-pytorch

    展开全文
  • 经过滤波后的图像进入两卷积层进行特征提取,在卷积层之后使用了5组密集连接模块来解决网络加深带来的梯度消失问题,密集连接模块之间通过过度来控制整个网络的宽度。实验结果表明,相比传统的图像隐写分析算法...
  • 利用具有自门激活功能的密集连接卷积网络进行叶分类
  • 第三章 基于密集连接卷积网络改进的目标分类算法 最近的研究表明,如果卷积网络包含接近输入的和接近输出的之间的较短连接,则卷积网络可以更深入,更精确和更有效地进行训练。在本章中,论文首先研究密集卷积...
  • 最近的工作表明,卷积网络如果在靠近输入的和靠近输出的之间包含较短的连接,就可以更深入,更准确,更有效地进行训练。我们认同这个观察结果,并引入密集卷积网络(DenseNet),该网络以前馈的方式将每一...
  • 密集连接卷积网络 摘要 最近的研究表明,如果卷积网络在接近输入和接近输出之间包含更短的连接,那么它在本质上可以更深入、更准确、更有效地进行训练。在本文中,我们接受了这一观察,并介绍了稠密卷积网络...
  • 针对这些问题,提出多维加权密集连接卷积神经网络模型实现对多光谱卫星云图的云检测。跨连接能够实现网络中所有之间的信息流,从而减少训练过程中的梯度消失导致收敛困难的问题。特征图之间连接的权值不同使得...
  • 针对大多数图像去雾算法模型参数估计准确性差及色彩失真等问题,提岀了一种端到端的密集连接扩张卷积神经网络。首先,通过使用多层密集连接结枃来増加网络的特征利用窣,避免网络加深时的梯度消失现象。其次,通过在...
  • 连接层与 softmax

    万次阅读 2017-04-05 10:58:26
    连接层一维一般常见的是这种一维的全连接层,下面这种图就很常见。全连接层,通俗的说就是前面一层的每个单元都与后面一层的相连接。如下图的绿色 Hidden 层,Hidden 层的每个单元都与 Input 层的所有单元相连接,...
  • 譬如你要读写几千万数据,非常密集的IO操作,那么你可以尝试一下开启少量的mysql连接(和cpu的核数相同)和开启大量的连接(成百上千),来做同样的事。你会发现,更少的连接数,会给你带来几百倍的性能提升。 ...
  • 连接层的实现

    千次阅读 2019-10-16 15:33:53
    下图中连线最密集的2个地方就是全连接层,这很明显的可以看出全连接层的参数的确很多。在前向计算过程,也就是一个线性的加权求和的过程,全连接层的每一个输出都可以看成前一层的每一个结点乘以一个权重系数W,最后...
  • 本文提出了一种密集连接的递归网络(DCRN),以权衡性能和复杂性。 我们通过去除批处理规范化(BN)并采用挤压和激发(SE)结构来引入增强的致密单元。 还采用了递归架构来控制深度网络的参数。 此外,提出了一种...
  • CVPR 2017最佳论文解读:密集连接卷积网络
  • 对于全连接层的理解 全连接层的推导

    万次阅读 多人点赞 2018-02-16 18:03:47
    连接层的前向计算下图中连线最密集的2个地方就是全连接层,这很明显的可以看出全连接层的参数的确很多。在前向计算过程,也就是一个线性的加权求和的过程,全连接层的每一个输出都可以看成前一层的每一个结点乘以...
  • -用pytorch的简单全连接层实现全连接层 class VGG(nn.Module): def __init__(self, features, num_classes=1000, init_weights=True): super(VGG, self).__init__() self.features = features self....
  • 连接层的前向计算下图中连线最密集的2个地方就是全连接层,这很明显的可以看出全连接层的参数的确很多。在前向计算过程,也就是一个线性的加权求和的过程,全连接层的每一个输出都可以看成前一层的每一个结点乘以...
  • 对于全连接层的理解

    万次阅读 多人点赞 2018-08-24 11:45:07
    下图中连线最密集的2个地方就是全连接层,这很明显的可以看出全连接层的参数的确很多。在前向计算过程,也就是一个线性的加权求和的过程,全连接层的每一个输出都可以看成前一层的每一个结点乘以一个权重系数W,最后...
  • 下图中连线最密集的2个地方就是全连接层,这很明显的可以看出全连接层的参数的确很多。在前向计算过程,也就是一个线性的加权求和的过程,全连接层的每一个输出都可以看成前一层的每一个结点乘以一个权重系数W,最后...
  • 它们都是密集连接的图卷积层,其中数( n & m )不同。 对于这两个任务,我们使用n = 6和m = 3 。 这些是超参数。 依存关系 该模型要求: Python3 CUDA(我们在CUDA 9.2上进行了测试) 安装 显卡 如果要在GPU...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 42,143
精华内容 16,857
关键字:

密集连接层