经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用

这篇具有很好参考价值的文章主要介绍了经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用

1 DenseNet的简述

  1. DenseNet不是通过更深或者更宽的结构,而是通过特征重用来提升网络的学习能力。

  2. ResNet 的思想是:创建从“靠近输入的层” 到 “靠近输出的层” 的直连。而DenseNet 做得更为彻底:将所有层以前馈的形式相连,这种网络因此称作DenseNet

  3. DenseNet 具有以下的优点:

    • 缓解梯度消失的问题。因为每层都可以直接从损失函数中获取梯度、从原始输入中获取信息,从而易于训练。
    • 密集连接还具有正则化的效应,缓解了小训练集任务的过拟合。
    • 鼓励特征重用。网络将不同层学到的 feature map 进行组合。
    • 大幅度减少参数数量。因为每层的卷积核尺寸都比较小,输出通道数较少 (由增长率决定)。
  4. DenseNet 具有比传统卷积网络更少的参数,因为它不需要重新学习多余的feature map

    • 传统的前馈神经网络可以视作在层与层之间传递状态的算法,每一层接收前一层的状态,然后将新的状态传递给下一层。

      这会改变状态,但是也传递了需要保留的信息。

    • ResNet 通过恒等映射来直接传递需要保留的信息,因此层之间只需要传递状态的变化

    • DenseNet 会将所有层的状态 全部保存到集体知识中,同时每一层增加很少数量的feture map 到网络的集体知识中

  5. DenseNet 的层很窄(即:feature map 的通道数很小),如:每一层的输出只有 12 个通道。

  6. 在跨层连接上,不同于ResNet中将输⼊与输出相加,稠密连接网络(DenseNet)在通道维上连结输⼊与输出。DenseNet的主要构建模块是稠密块和过渡层。在构建DenseNet时,我们需要通过添加过渡层来控制网络的维数,从⽽再次减少通道的数量。

  7. 虽然 DenseNet 的计算效率较高、参数相对较少,但是DenseNet 对内存不友好。可以考虑通过共享内存,解决这个问题。

  8. 论文下载地址: https://arxiv.org/pdf/1608.06993.pdf

1.1 稠密块(dense block)

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用,# 深度学习,神经网络,人工智能,深度学习

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用,# 深度学习,神经网络,人工智能,深度学习

ResNet和DenseNet的关键区别在于,DenseNet输出是连接(下图中的[ , ] 表示),而不是如ResNet的简单相加。

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用,# 深度学习,神经网络,人工智能,深度学习

DenseNet这个名字由变量之间的“稠密连接”⽽得来,最后⼀层与之前的所有层紧密相连。

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用,# 深度学习,神经网络,人工智能,深度学习

注意:当 feature map 的尺寸改变时,无法沿着通道方向进行拼接。此时将网络划分为多个DenseNet 块,每块内部的 feature map尺寸相同,块之间的feature map 尺寸不同。

1.1.1 增长率

  1. DenseNet 块中,每层的 H(即BN-ReLU-Conv) 输出的feature map 通道数都相同,都是k个。 k是一个重要的超参数,称作网络的增长率。

    第 l 层的输入【特征图】的通道数为: k 0 + k ( l − 1 ) 。其中 k 0 为输入层的通道数。 第l层的输入【特征图】 的通道数为:k_0 + k(l-1) 。其中k_0为输入层的通道数。 l层的输入【特征图】的通道数为:k0+k(l1)。其中k0为输入层的通道数。

  2. DenseNet 不同于现有网络的一个重要地方是:DenseNet 的网络很窄,即输出的 feature map 通道数较小,如:k = 12 。

    • 一个很小的增长率就能够获得不错的效果。一种解释是:DenseNet 块的每层都可以访问块内的所有早前层输出的feature map,这些feature map 可以视作DenseNet 块的全局状态。每层输出的feature map 都将被添加到块的这个全局状态中,该全局状态可以理解为网络块的【集体知识】,由块内所有层共享。增长率决定了新增特征占全局状态的比例。

    • 因此feature map 无需逐层复制(因为它是全局共享),这也是DenseNet 与传统网络结构不同的地方。这有助于整个网络的特征重用,并产生更紧凑的模型。

1.1.2 非线性变换

  • H可以是包含了 Batch Normalization(BN) 、ReLU 单元、池化或者卷积等操作的复合函数。

  • 论文中的结构为:先执行BN ,再执行ReLU,最后接一个3 x 3 的卷积,即:BN-ReLU-Conv(3x3)

  • pytorch实现如下

import torch.nn as nn
import torch


'''
DenseNet使⽤了ResNet改良版的“批量规范化、激活和卷积”架构

    卷积块:BN-ReLU-Conv
'''
def conv_block(input_channels, num_channels):

    return nn.Sequential(
                  nn.BatchNorm2d(input_channels),
                  nn.ReLU(),
                  nn.Conv2d(input_channels, num_channels, kernel_size=3, padding=1)
         )

1.1.3 bottleneck

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用,# 深度学习,神经网络,人工智能,深度学习

1.1.4 pytorch实现稠密块

import torch.nn as nn
import torch


'''
DenseNet使⽤了ResNet改良版的“批量规范化、激活和卷积”架构

    卷积块:BN-ReLU-Conv
'''
def conv_block(input_channels, num_channels):

    return nn.Sequential(
                  nn.BatchNorm2d(input_channels),
                  nn.ReLU(),
                  nn.Conv2d(input_channels, num_channels, kernel_size=3, padding=1)
         )



'''
⼀个稠密块由多个卷积块组成,每个卷积块使⽤相同数量的输出通道。

然⽽,在前向传播中,我们将每个卷积块的输⼊和输出在通道维上连结。
'''
class DenseBlock(nn.Module):
    def __init__(self, num_convs, input_channels, num_channels):
        super(DenseBlock, self).__init__()

        layer = []
        for i in range(num_convs):
            layer.append(
                conv_block(num_channels * i + input_channels, num_channels)     # 一个稠密块由多个卷积块组成
            )
        self.net = nn.Sequential(*layer)


    def forward(self, X):
        for blk in self.net:
            Y = blk(X)
            # 连接通道维度上每个块的输⼊和输出
            X = torch.cat((X, Y), dim=1)
        return X

if __name__ == '__main__':
    '''
    1、稠密块 dense block
    我们定义⼀个有2个输出通道数为10的DenseBlock。
    使⽤通道数为3的输⼊时,我们会得到通道数为3 + 2 × 10 = 23的输出。
    卷积块的通道数控制了输出通道数相对于输⼊通道数的增⻓,因此也被称为增⻓率(growth rate)。
    '''
    blk = DenseBlock(2, 3, 10)
    # X经过第一个卷积块后变为(4, 10, 8, 8),然后和原始X(4, 3, 8, 8)进行在维度1进行拼接,X变成(4, 13, 8, 8)
    # 然后输入到第二个卷积块,第二个卷积块将channels由(10+3)变为10,因此输出Y(4, 10, 8, 8)
    # 然后X和Y在维度1进行拼接,得到最终输出(4, 23, 8, 8)
    X = torch.randn(4, 3, 8, 8)
    Y = blk(X)
    print(Y.shape)  # (4, 23, 8, 8)

1.2 过渡层(transition layer)

1.2.1 过渡层的介绍

  • 一个DenseNet 网络具有多个DenseNet块,DenseNet 块之间由过渡层连接。DenseNet 块之间的层称为过渡层,其主要作用是连接不同的DenseNet块。

  • 过渡层可以包含卷积或池化操作,从而改变前一个DenseNet 块的输出feature map 的大小(包括尺寸大小、通道数量)。

    • 论文中的过渡层由一个BN层、一个1x1 卷积层、一个2x2 平均池化层组成。其中 1x1 卷积层用于减少DenseNet 块的输出通道数,提高模型的紧凑性。
    • 如果不减少DenseNet 块的输出通道数,则经过了 个DenseNet 块之后,网络的feature map 的通道数会变得很大(通道数计算如下图公式)

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用,# 深度学习,神经网络,人工智能,深度学习

  • 如果Dense 块输出feature map的通道数为 m,则可以使得过渡层输出feature map 的通道数为 theta ✖ m ,其中0< theta <=1 为压缩因子。
    • 当theta = 1时,经过过渡层的feature map 通道数不变。
    • 当theta < 1时,经过过渡层的feature map 通道数减小。此时的DenseNet 称做 DenseNet-C
    • 结合了DenseNet-CDenseNet-B 的改进的网络称作 DenseNet-BC

1.2.2 过渡层的实现

'''
由于每个稠密块都会带来通道数的增加,使⽤过多则会过于复杂化模型。
⽽过渡层可以⽤来控制模型复杂度。它通过1 × 1卷积层来减⼩通道数,并使⽤步幅为2的平均汇聚层减半⾼和宽,从⽽进⼀步降低模型复杂度。
'''
def transition_block(input_channels, num_channels):
    return nn.Sequential(
            nn.BatchNorm2d(input_channels),
            nn.ReLU(),
            nn.Conv2d(input_channels, num_channels, kernel_size=1), # 1×1卷积层来减⼩通道数
            nn.AvgPool2d(kernel_size=2, stride=2)                   # 步幅为2的平均汇聚层减半⾼和宽
    )




if __name__ == '__main__':
    '''
    1、稠密块 dense block
    我们定义⼀个有2个输出通道数为10的DenseBlock。
    使⽤通道数为3的输⼊时,我们会得到通道数为3 + 2 × 10 = 23的输出。
    卷积块的通道数控制了输出通道数相对于输⼊通道数的增⻓,因此也被称为增⻓率(growth rate)。
    '''
    blk = DenseBlock(2, 3, 10)
    # X经过第一个卷积块后变为(4, 10, 8, 8),然后和原始X(4, 3, 8, 8)进行在维度1进行拼接,X变成(4, 13, 8, 8)
    # 然后输入到第二个卷积块,第二个卷积块将channels由(10+3)变为10,因此输出Y(4, 10, 8, 8)
    # 然后X和Y在维度1进行拼接,得到最终输出(4, 23, 8, 8)
    X = torch.randn(4, 3, 8, 8)
    Y = blk(X)
    print(Y.shape)  # (4, 23, 8, 8)


    '''
    2、过渡层 transition layer
    '''
    blk = transition_block(23, 10)
    print(blk(Y).shape)  # torch.Size([4, 10, 4, 4])

1.3 DenseNet网络性能

1.3.1 网络结构

网络结构:ImageNet 训练的DenseNet 网络结构,其中增长率k = 32 。

  • 表中的 conv 代表的是 BN-ReLU-Conv 的组合。如 1x1 conv 表示:先执行BN,再执行ReLU,最后执行1x1 的卷积。
  • DenseNet-xx 表示DenseNet 块有xx 层。如:DenseNet-169 表示 DenseNet 块有L=169 层 。
  • 所有的 DenseNet 使用的是 DenseNet-BC 结构,输入图片尺寸为224x224,初始卷积尺寸为7x7、输出通道 2k、步长为2 ,压缩因子 theta=0.5。
  • 在所有DenseNet 块的最后接一个全局平均池化层,该池化层的结果作为softmax 输出层的输入。

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用,# 深度学习,神经网络,人工智能,深度学习

1.3.2 在ImageNet 验证集的错误率

下图是DenseNetResNetImageNet 验证集的错误率的比较(single-crop)。左图为参数数量,右图为计算量。

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用,# 深度学习,神经网络,人工智能,深度学习

从实验可见:DenseNet 的参数数量和计算量相对ResNet 明显减少。

  • 具有 20M 个参数的DenseNet-201 与具有 40M 个参数的ResNet-101 验证误差接近。
  • ResNet-101 验证误差接近的DenseNet-201 的计算量接近于ResNet-50,几乎是ResNet-101 的一半。

1.3.3 一个简单版本DenseNet的实现

我们实现一个简单的版本的DenseNet,使用DenseNet,而非DenseNet-BC,以应用在Fashion-MNIST数据集上。

稠密块和过度层

import torch.nn as nn
import torch


'''
DenseNet使⽤了ResNet改良版的“批量规范化、激活和卷积”架构

    卷积块:BN-ReLU-Conv
'''
def conv_block(input_channels, num_channels):

    return nn.Sequential(
                  nn.BatchNorm2d(input_channels),
                  nn.ReLU(),
                  nn.Conv2d(input_channels, num_channels, kernel_size=3, padding=1)
         )



'''
⼀个稠密块由多个卷积块组成,每个卷积块使⽤相同数量的输出通道。

然⽽,在前向传播中,我们将每个卷积块的输⼊和输出在通道维上连结。
'''
class DenseBlock(nn.Module):
    def __init__(self, num_convs, input_channels, num_channels):
        super(DenseBlock, self).__init__()

        layer = []
        for i in range(num_convs):
            layer.append(
                conv_block(num_channels * i + input_channels, num_channels)     # 一个稠密块由多个卷积块组成
            )
        self.net = nn.Sequential(*layer)


    def forward(self, X):
        for blk in self.net:
            Y = blk(X)
            # 连接通道维度上每个块的输⼊和输出
            X = torch.cat((X, Y), dim=1)
        return X

'''
由于每个稠密块都会带来通道数的增加,使⽤过多则会过于复杂化模型。
⽽过渡层可以⽤来控制模型复杂度。它通过1 × 1卷积层来减⼩通道数,并使⽤步幅为2的平均汇聚层减半⾼和宽,从⽽进⼀步降低模型复杂度。
'''
def transition_block(input_channels, num_channels):
    return nn.Sequential(
            nn.BatchNorm2d(input_channels),
            nn.ReLU(),
            nn.Conv2d(input_channels, num_channels, kernel_size=1), # 1×1卷积层来减⼩通道数
            nn.AvgPool2d(kernel_size=2, stride=2)                   # 步幅为2的平均汇聚层减半⾼和宽
    )


if __name__ == '__main__':
    '''
    1、稠密块 dense block
    我们定义⼀个有2个输出通道数为10的DenseBlock。
    使⽤通道数为3的输⼊时,我们会得到通道数为3 + 2 × 10 = 23的输出。
    卷积块的通道数控制了输出通道数相对于输⼊通道数的增⻓,因此也被称为增⻓率(growth rate)。
    '''
    blk = DenseBlock(2, 3, 10)
    # X经过第一个卷积块后变为(4, 10, 8, 8),然后和原始X(4, 3, 8, 8)进行在维度1进行拼接,X变成(4, 13, 8, 8)
    # 然后输入到第二个卷积块,第二个卷积块将channels由(10+3)变为10,因此输出Y(4, 10, 8, 8)
    # 然后X和Y在维度1进行拼接,得到最终输出(4, 23, 8, 8)
    X = torch.randn(4, 3, 8, 8)
    Y = blk(X)
    print(Y.shape)  # (4, 23, 8, 8)


    '''
    2、过渡层 transition layer
    '''
    blk = transition_block(23, 10)
    print(blk(Y).shape)  # torch.Size([4, 10, 4, 4])

DenseNet

import torch.nn as nn
import torch
from _08_dense_block import DenseBlock,transition_block

class DenseNet(nn.Module):


    def __init__(self):
        super(DenseNet, self).__init__()
        '''
            1、DenseNet⾸先使⽤同ResNet⼀样的单卷积层和最⼤汇聚层。
        '''
        b1 = nn.Sequential(
                nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
                nn.BatchNorm2d(64),
                nn.ReLU(),
                nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        )
        '''
            2、接下来,类似于ResNet使⽤的4个残差块,DenseNet使⽤的是4个稠密块。
        与ResNet类似,我们可以设置每个稠密块使⽤多少个卷积层。这⾥我们设成4,从⽽之前的ResNet-18保持⼀致。
        稠密块⾥的卷积层通道数(即增⻓率)设为32,所以每个稠密块将增加128个通道。
        
        
            3、在每个模块之间,ResNet通过步幅为2的残差块减⼩⾼和宽,DenseNet则使⽤过渡层来减半⾼和宽,并减半通道数。
        '''
        # num_channels为当前的通道数
        num_channels, growth_rate = 64, 32
        num_convs_in_dense_blocks = [4, 4, 4, 4]
        blks = []
        for i, num_convs in enumerate(num_convs_in_dense_blocks):
            # 添加稠密块
            blks.append(DenseBlock(num_convs, num_channels, growth_rate))
            # 上⼀个稠密块的输出通道数
            num_channels += num_convs * growth_rate

            # 在稠密块之间添加⼀个转换层,使通道数量减半
            if i != len(num_convs_in_dense_blocks) - 1:
                blks.append(transition_block(num_channels, num_channels // 2))
                num_channels = num_channels // 2
        '''
        4、与ResNet类似,最后接上全局汇聚层和全连接层来输出结果。
        '''
        self.model = nn.Sequential(
            b1,
            *blks,
            nn.BatchNorm2d(num_channels),
            nn.ReLU(),
            nn.AdaptiveAvgPool2d((1, 1)),
            nn.Flatten(),
            nn.Linear(num_channels, 10)
        )




    def forward(self, X):
        return self.model(X)


if __name__ == '__main__':
    net = DenseNet()
    X = torch.rand(size=(1, 1, 224, 224), dtype=torch.float32)
    for layer in net.model:
        X = layer(X)
        print(layer.__class__.__name__, 'output shape:', X.shape)
Sequential output shape: torch.Size([1, 64, 56, 56])

DenseBlock output shape: torch.Size([1, 192, 56, 56])
Sequential output shape: torch.Size([1, 96, 28, 28])
DenseBlock output shape: torch.Size([1, 224, 28, 28])
Sequential output shape: torch.Size([1, 112, 14, 14])
DenseBlock output shape: torch.Size([1, 240, 14, 14])
Sequential output shape: torch.Size([1, 120, 7, 7])
DenseBlock output shape: torch.Size([1, 248, 7, 7])

BatchNorm2d output shape: torch.Size([1, 248, 7, 7])
ReLU output shape: torch.Size([1, 248, 7, 7])
AdaptiveAvgPool2d output shape: torch.Size([1, 248, 1, 1])
Flatten output shape: torch.Size([1, 248])
Linear output shape: torch.Size([1, 10])

1.4 DenseNet的内存或显存消耗过多问题

虽然 DenseNet 的计算效率较高、参数相对较少,但是DenseNet 对内存不友好。考虑到GPU 显存大小的限制,因此无法训练较深的 DenseNet

1.4.1 内存的计算

假设DenseNet块包含L层,则:
对于第 l 层,有 x l = H l ( [ x 0 , x 1 , . . . , x l − 1 ] ) 对于第l层,有x_l = H_l([x_0,x_1,...,x_{l-1}]) 对于第l层,有xl=Hl([x0,x1,...,xl1])
假设每层的输出feature map 尺寸均为W×H、通道数为k, 由BN-ReLU-Conv(3x3) 组成,则:

  • 拼接Concat操作 :需要生成临时feature map 作为第l层的输入,内存消耗为 W×H×k×l 。
  • BN 操作:需要生成临时feature map 作为ReLU 的输入,内存消耗为 W×H×k×l 。
  • ReLU 操作:可以执行原地修改,因此不需要额外的feature map 存放ReLU 的输出。
  • Conv 操作:需要生成输出feature map 作为第l层的输出,它是必须的开销。

因此除了第1,2,…,L层的输出feature map 需要内存开销之外,第l层还需要2W×H×k×l 的内存开销来存放中间生成的临时feature map
整个 D e n s e N e t 块需要 W × H × k × ( L + 1 ) L 的内存开销来存放中间生成的临时特征图。 即 D e n s e N e t 块的内存消耗为 O ( L 2 ) ,是网络深度的平方关系。 整个 DenseNet 块 需要W×H×k×(L+1)L 的内存开销来存放中间生成的临时特征图。\\ 即DenseNet 块 的内存消耗为O(L^2),是网络深度的平方关系。 整个DenseNet块需要W×H×k×(L+1)L的内存开销来存放中间生成的临时特征图。DenseNet块的内存消耗为O(L2),是网络深度的平方关系。

1.4.2 拼接的必要性及内存消耗的原因

  • 拼接Concat操作是必须的,因为当卷积的输入存放在连续的内存区域时,卷积操作的计算效率较高。而DenseNet Block 中,第l层的输入feature map 由前面各层的输出feature map 沿通道方向拼接而成。而这些输出feature map 并不在连续的内存区域。

  • DenseNet Block 的这种内存消耗并不是DenseNet Block 的结构引起的,而是由深度学习库引起的。因为Tensorflow/PyTorch 等库在实现神经网络时,会存放中间生成的临时节点(如BN 的输出节点),这是为了在反向传播阶段可以直接获取临时节点的值。

  • 这是在时间代价和空间代价之间的折中:通过开辟更多的空间来存储临时值,从而在反向传播阶段节省计算。

1.4.3 网络的参数也会消耗内存

除了临时feature map 的内存消耗之外,网络的参数也会消耗内存。设 H由BN-ReLU-Conv(3x3) 组成,则第l层的网络参数数量为: 9×l×k^2(不考虑 BN )。
整个 D e n s e N e t 块的参数数量为 9 k 2 ( L + 1 ) L 2 , 即 O ( L 2 ) 整个 DenseNet块的参数数量为\frac{9k^2(L+1)L}{2},即O(L^2) 整个DenseNet块的参数数量为29k2(L+1)L,O(L2)

  • 由于DenseNet 参数数量与网络的深度呈平方关系,因此DenseNet 网络的参数更多、网络容量更大。这也是DenseNet 优于其它网络的一个重要因素。
  • 通常情况下都有WH > (9×k/2) ,其中W,H为网络feature map 的宽、高,k为网络的增长率。所以网络参数消耗的内存要远小于临时feature map 消耗的内存。

1.5 DenseNet内存优化_共享内存

其思想是利用时间代价和空间代价之间的折中,但是侧重于牺牲时间代价来换取空间代价。

其背后支撑的因素是:Concat操作和BN 操作的计算代价很低,但是空间代价很高。因此这种做法在DenseNet 中非常有效。

1.5.1 传统做法

传统的DenseNet Block 的第 l 层。首先将 feature map 拷贝到连续的内存块,拷贝时完成拼接的操作。然后依次执行BNReLUConv 操作。

该层的临时feature map 需要消耗内存 2W×H×k×l,该层的输出feature map 需要消耗内存W×H×k 。

  • 另外某些实现(如LuaTorch)还需要为反向传播过程的梯度分配内存,如左图下半部分所示。如:计算 BN 层输出的梯度时,需要用到第 l 层输出层的梯度和BN 层的输出。存储这些梯度需要额外的 O(lk)的内存。
  • 另外一些实现(如PyTorch,MxNet)会对梯度使用共享的内存区域来存放这些梯度,因此只需要O(k)的内存。

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用,# 深度学习,神经网络,人工智能,深度学习

1.5.2 共享内存做法

右图为内存优化的DenseNet Block 的第 l 层。采用两组预分配的共享内存区Shared memory Storage location 来存concate 操作和BN 操作输出的临时feature map

对于第一组预分配的共享内存区:

第一组预分配的共享内存区:concat 操作共享区。第1,2,…,L 层的 concat 操作的输出都写入到该共享区,第(l+1) 层的写入会覆盖第 (l)层的结果。

  • 对于整个Dense Block,这个共享区只需要分配 W×H×k×L(最大的feature map )的内存,即内存消耗为O(kL) (对比传统DenseNet的O(kL^2) )。

  • 后续的BN 操作直接从这个共享区读取数据。

  • 由于第 (l+1)层的写入会覆盖第(l) 层的结果,因此这里存放的数据是临时的、易丢失的。因此在反向传播阶段还需要重新计算第 (l)层的Concat 操作的结果。

    因为concat 操作的计算效率非常高,因此这种额外的计算代价很低。

对于第二组预分配的共享内存区

第二组预分配的共享内存区:BN 操作共享区。第1,2,…,L 层的 concat 操作的输出都写入到该共享区,第(l+1) 层的写入会覆盖第 (l)层的结果。

  • 对于整个Dense Block,这个共享区也只需要分配W×H×k×L (最大的feature map )的内存,即内存消耗为O(kL) (对比传统DenseNet的O(kL^2) )。

  • 后续的卷积操作直接从这个共享区读取数据。

  • concat 操作共享区同样的原因,在反向传播阶段还需要重新计算第(l)层的BN 操作的结果。

    BN 的计算效率也很高,只需要额外付出大约 5% 的计算代价。

由于BN 操作和concat 操作在神经网络中大量使用,因此这种预分配共享内存区的方法可以广泛应用。它们可以在增加少量的计算时间的情况下节省大量的内存消耗。

2 DenseNet在Fashion-MNIST数据集上的应用示例

2.1 创建DenseNet网络模型

如1.3.3所示。

2.2 读取Fashion-MNIST数据集

batch_size = 256

# 为了使Fashion-MNIST上的训练短⼩精悍,将输⼊的⾼和宽从224降到96,简化计算
train_iter,test_iter = get_mnist_data(batch_size,resize=96)

2.3 在GPU上进行模型训练

from _08_DenseNet import DenseNet

# 初始化模型
net = DenseNet()

lr, num_epochs = 0.1, 10
train_ch(net, train_iter, test_iter, num_epochs, lr, try_gpu())

经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用,# 深度学习,神经网络,人工智能,深度学习文章来源地址https://www.toymoban.com/news/detail-524579.html

到了这里,关于经典神经网络(7)DenseNet及其在Fashion-MNIST数据集上的应用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python基于深度学习机器学习卷积神经网络实现垃圾分类垃圾识别系统(GoogLeNet,Resnet,DenseNet,MobileNet,EfficientNet,Shufflent)

    文章目录 1 前言+ 2 卷积神经网络(CNN)详解+ 2.1 CNN架构概述+ 2.1.1 卷积层+ 2.1.2 池化层+ 2.1.3 全连接层 2.2 CNN训练过程+ 2.3 CNN在垃圾图片分类中的应用 3 代码详解+ 3.1 导入必要的库+ 3.2 加载数据集+ 3.3 可视化随机样本+ 3.4 数据预处理与生成器+ 3.5 构建、编译和训练CNN模型+ 3.5.

    2024年02月04日
    浏览(48)
  • 神经网络的主要应用领域,神经网络技术及其应用

    神经网络原理及应用 1. 什么是神经网络? 神经网络是一种模拟动物神经网络行为特征,进行分布式并行信息处理的算法。这种网络依靠系统的复杂程度,通过调整内部大量节点之间相互连接的关系,从而达到处理信息的目的。 人类的神经网络 2. 神经网络基础知识 构成:大

    2024年02月09日
    浏览(51)
  • 经典卷积神经网络-LeNet-5

    LeNet-5是Yann LeCun等人在《Gradient-Based Learning Applied to Document Recogn》论文中提出的一个卷积神经网络,LeNet的基本思想和结构为后来更复杂的神经网络提供了灵感,并为研究者们提供了深入理解卷积神经网络的起点。 如图所示,这是论文中所介绍的LeNet-5网络结构。输入为一个3

    2024年02月03日
    浏览(38)
  • 经典卷积神经网络——VGG16

    我们都知道Alexnet是卷积神经网络的开山之作,但是由于卷积核太大,移动步长大,无填充,所以14年提出的VGG网络解决了这一问题 VGG网络由牛津大学在2014年ImageNet挑战赛本地和分类追踪分别获得了第一名和第二名。研究卷积网络深度对其影响在大规模图像识别设置中的准确性

    2024年02月03日
    浏览(63)
  • 卷积神经网络CNN的经典模型

    ILSVRC是一项基于 ImageNet 数据库的国际大规模视觉识别挑战赛(ImageNet Large Scale Visual Recognition Challenge,ILSVRC) (1)1958年,Rosenblatt发明了感知机。用于对输入的多维数据进行二分类且能够使用梯度下降法自动更新权值。 缺点:只能处理线性分类问题。 (2)1986年,Geoffrey Hi

    2024年02月07日
    浏览(37)
  • 【卷积神经网络】经典网络之 LeNet-5, AlexNet 与 VGG-16

    随着计算机硬件的升级与性能的提高,运算量已不再是阻碍深度学习发展的难题。卷积神经网络(Convolution Neural Network,CNN)是深度学习中一项代表性的工作,其雏形是 1998 年 LeCun 提出的 LeNet-5 模型。如今,卷积神经网络已被广泛应用于计算机视觉领域。本文主要介绍卷积神

    2024年02月11日
    浏览(38)
  • PyTorch+PyG实现图神经网络经典模型目录

    大家好,我是阿光。 本专栏整理了《图神经网络代码实战》,内包含了不同图神经网络的相关代码实现(PyG以及自实现),理论与实践相结合,如GCN、GAT、GraphSAGE等经典图网络,每一个代码实例都附带有完整的代码。 正在更新中~ ✨ 🚨 我的项目环境: 平台:Windows10 语言环

    2024年02月03日
    浏览(41)
  • 经典目标检测神经网络 - RCNN、SSD、YOLO

    目标检测算法主要分两类:One-Stage与Two-Stage。One-Stage与Two-Stage是两种不同的思路,其各有各的优缺点。 One-Stage     主要思路:直接通过卷积神经网络提取特征,预测目标的分类与定位; Two-Stage     主要思路:先进行区域生成,即生成候选区域(Region Proposal),在通

    2024年02月08日
    浏览(40)
  • 深度学习记录--神经网络表示及其向量化

    如下图 就这个神经网络图来说,它有三层,分别是 输入层 ( Input layer ), 隐藏层 ( Hidden layer ), 输出层 ( Output layer ) 对于其他的神经网络,隐藏层可以有很多层 一般来说,不把输入层算作一个标准的层,所以这是一个 双层神经网络 对于每一层的每个节点,以logistic为例,每

    2024年02月04日
    浏览(38)
  • 神经网络自适应PID控制及其应用

    总结来自重庆大学宋永瑞教授2022暑期校园行学术会议   目前人工智能的发展为很多领域里的研究提供了可延展性,提供了新的研究问题的思路,无人系统和人工智能正走向深度融合,无人系统里具有核心驱动作用的智能控制算法的研究成为了热点问题。 人工智能的理论深

    2024年01月21日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包