Red neuronal clásica (7) DenseNet y su aplicación en el conjunto de datos Fashion-MNIST

Red neuronal clásica (7) DenseNet y su aplicación en el conjunto de datos Fashion-MNIST

1 Breve descripción de DenseNet

  1. DenseNetNo a través de estructuras más profundas o más amplias, sino mediante la reutilización de funciones para mejorar la capacidad de aprendizaje de la red.

  2. ResNetLa idea es crear una conexión directa desde la "capa cercana a la entrada" a la "capa cercana a la salida". Y DenseNetlo hace aún más radicalmente: todas las capas están interconectadas en forma feed-forward, de ahí el nombre DenseNet.

  3. DenseNetTiene las siguientes ventajas:

    • Aliviar el problema de los gradientes que desaparecen. Debido a que cada capa puede obtener directamente el gradiente de la función de pérdida y obtener información de la entrada original, es fácil de entrenar.
    • Las conexiones densas también tienen un efecto de regularización, lo que alivia el sobreajuste en tareas con conjuntos de entrenamiento pequeños.
    • Fomentar la reutilización de funciones. feature mapLa red combina lo aprendido por diferentes capas .
    • Reduce significativamente el número de parámetros. Debido a que el tamaño del núcleo de convolución de cada capa es relativamente pequeño, el número de canales de salida es pequeño (determinado por la tasa de crecimiento).
  4. DenseNetTiene menos parámetros que las redes convolucionales tradicionales porque no requiere reaprendizaje redundante feature map.

    • Las redes neuronales tradicionales pueden verse como 状态algoritmos que pasan entre capas. Cada capa recibe la información de la capa anterior 状态y luego pasa la nueva 状态información a la siguiente capa.

      Esto cambia 状态, pero también envía un mensaje que debe conservarse.

    • ResNetLa información que debe retenerse se transfiere directamente a través del mapeo de identidad, por lo que solo se requiere transferencia entre capas 状态的变化.

    • DenseNetTodas las capas de todas las capas se 状态guardarán en 集体知识, mientras que cada capa agregará una pequeña cantidad de capas feture mapa la red 集体知识中.

  5. DenseNetLas capas son muy estrechas (es decir, feature mapel número de canales es pequeño), por ejemplo, la salida de cada capa tiene solo 12 canales.

  6. En términos de conexiones entre capas, a diferencia de ResNet, donde se agregan entradas y salidas, las redes de conexiones densas (DenseNet) están en la dimensión del canal 连结输⼊与输出. Los principales componentes básicos de DenseNet son 稠密块和过渡层. Al construir DenseNet, necesitamos 添加过渡层来reducir la cantidad de canales nuevamente controlando la dimensionalidad de la red.

  7. Aunque DenseNettiene una alta eficiencia computacional y relativamente pocos parámetros, DenseNetno es compatible con la memoria. Puedes considerar compartir memoria para resolver este problema.

  8. Dirección de descarga del artículo: https://arxiv.org/pdf/1608.06993.pdf

1.1 Bloque denso (bloque denso)

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

La diferencia clave entre ResNet y DenseNet es que la salida de DenseNet es una conexión (representada por [,] en la figura siguiente), en lugar de una simple adición como ResNet.

inserte la descripción de la imagen aquí

El nombre DenseNet proviene de las "conexiones densas" entre variables, estando la última capa estrechamente conectada con todas las capas anteriores.

inserte la descripción de la imagen aquí

注意: Cuando feature mapse cambia el tamaño de, el empalme no se puede realizar a lo largo de la dirección del canal. En este momento, la red está dividida en varios DenseNetbloques, el tamaño interno de cada bloque feature mapes el mismo y el tamaño entre bloques feature mapes diferente.

1.1.1 Tasa de crecimiento

  1. DenseNetEn el bloque, el número de canales emitidos por cada capa de H (es decir, BN-ReLU-Conv) feature mapes el mismo, que es k. k es un hiperparámetro importante llamado tasa de crecimiento de la red.

    El número de canales de la entrada [mapa de características] de la l-ésima capa es: k 0 + k (l − 1). donde k 0 es el número de canales de la capa de entrada. El número de canales de la entrada [mapa de características] de la l-ésima capa es: k_0 + k (l-1). donde k_0 es el número de canales de la capa de entrada.El número de canales de la entrada [mapa de características] de la capa l es : k0+k ( l1 ) . entre ellos k0es el número de canales de la capa de entrada.

  2. DenseNetUna diferencia importante con las redes existentes es que DenseNetla red es muy estrecha, es decir, el número de feature mapcanales de salida es pequeño, como por ejemplo: k = 12.

    • Una pequeña tasa de crecimiento puede lograr buenos resultados. Una explicación es que DenseNetcada capa de un bloque tiene acceso a las salidas de todas las capas anteriores dentro del bloque feature map, lo que feature mappuede considerarse como DenseNetel estado global del bloque. La salida de cada capa feature mapse agregará al estado global del bloque, que puede entenderse como el [conocimiento colectivo] del bloque de red y es compartido por todas las capas del bloque. La tasa de crecimiento determina la proporción de nuevas características en el estado global.

    • Por lo tanto, feature mapno hay necesidad de replicación capa por capa (porque se comparte globalmente), lo que también es DenseNetdiferente de las estructuras de red tradicionales. Esto facilita la reutilización de funciones en la red y produce modelos más compactos.

1.1.2 Transformación no lineal

  • H puede ser una función compuesta que incluye normalización por lotes (BN), unidad ReLU, agrupación o convolución y otras operaciones.

  • La estructura en el artículo es: primero realice BN, luego realice ReLU y finalmente siga una convolución de 3 x 3, es decir: BN-ReLU-Conv (3x3)

  • pytorch se implementa de la siguiente manera

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 cuello de botella

inserte la descripción de la imagen aquí

1.1.4 pytorch implementa bloques densos

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 Capa de transición

1.2.1 Introducción a la capa de transición

  • Una DenseNetred tiene múltiples DenseNetbloques DenseNetconectados por capas de transición. DenseNetLa capa entre bloques se llama capa de transición y su función principal es conectar diferentes DenseNetbloques.

  • Las capas de transición pueden contener operaciones de convolución o agrupación, cambiando así el tamaño (incluido el tamaño, el número de canales) de DenseNetla salida del bloque anterior .feature map

    • La capa de transición en el papel consta de una BNcapa, una 1x1capa de convolución y una 2x2capa de agrupación promedio. La 1x1capa convolucional se utiliza para reducir DenseNetla cantidad de canales de salida del bloque y mejorar la compacidad del modelo.
    • Si no se reduce el número de canales de salida del bloque , el número de canales de la red será muy grande después de DenseNetpasar los bloques (el número de canales se calcula según la fórmula de la siguiente figura)DenseNetfeature map

inserte la descripción de la imagen aquí

  • Si el número de canales Denseemitidos por el bloque es m, el número de canales feature mapemitidos por la capa de transición puede ser theta ✖ m, donde 0 < theta <= 1 es el factor de compresión.feature map
    • Cuando theta = 1, feature mapel número de canales que pasan a través de la capa de transición permanece sin cambios.
    • Cuando theta <1, feature mapel número de canales que pasan a través de la capa de transición disminuye. En este momento DenseNetse llama DenseNet-C.
    • La red mejorada que combina DenseNet-Cy se llamaDenseNet-BDenseNet-BC

1.2.2 Implementación de la capa de transición

'''
由于每个稠密块都会带来通道数的增加,使⽤过多则会过于复杂化模型。
⽽过渡层可以⽤来控制模型复杂度。它通过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 Rendimiento de la red DenseNet

1.3.1 Estructura de la red

Estructura de red: estructura de red ImageNetentrenada DenseNetcon tasa de crecimiento k = 32.

  • en la tabla convrepresenta BN-ReLU-Convla combinación de . Por ejemplo 1x1 conv, significa: ejecutar primero BN, luego ejecutar ReLUy finalmente ejecutar 1x1la convolución de.
  • DenseNet-xxIndica que DenseNetel bloque tiene xxcapas. Por ejemplo: DenseNet-169significa que DenseNetel bloque tiene L=169 capas.
  • Todos DenseNetusan DenseNet-BCla estructura, el tamaño de la imagen de entrada es 224x224, el tamaño de convolución inicial es 7x7, el canal de salida 2k, el tamaño del paso es 2y el factor de compresión theta = 0,5.
  • Al DenseNetfinal de todos los bloques, hay una capa de agrupación promedio global y el resultado de esta capa de agrupación se utiliza como softmaxentrada de la capa de salida.

inserte la descripción de la imagen aquí

1.3.2 ImageNetTasa de error en el conjunto de validación

La siguiente figura es una comparación de las tasas de error de DenseNety ResNeten ImageNetel conjunto de validación ( single-crop). La imagen de la izquierda muestra la cantidad de parámetros y la imagen de la derecha muestra la cantidad de cálculo.

inserte la descripción de la imagen aquí

Del experimento se puede ver que DenseNetel número de parámetros y la cantidad de cálculo se ResNetreducen de manera relativamente significativa.

  • El error de validación de con 20Mparámetros es cercano DenseNet-201al de con 40Mparámetros .ResNet-101
  • El esfuerzo computacional de está cerca del ResNet-101error de verificación de está cerca , casi la mitad.DenseNet-201ResNet-50ResNet-101

1.3.3 Implementación de una versión simple de DenseNet

Implementamos una versión simple de DenseNet, usando DenseNet en lugar de DenseNet-BC, para su aplicación en el conjunto de datos 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 El problema del consumo excesivo de memoria o memoria de video de DenseNet

Aunque DenseNettiene una alta eficiencia computacional y relativamente pocos parámetros, DenseNetno es compatible con la memoria. Teniendo en cuenta GPUla limitación del tamaño de la memoria de vídeo, es imposible entrenar memorias más profundas DenseNet.

1.4.1 Cálculo de la memoria

Supongamos que DenseNetel bloque contiene L capas, entonces:
para la l-ésima capa, hay xl = H l ( [ x 0 , x 1 , . . . , xl − 1 ] ) para la l-ésima capa, hay . ..,x_{l-1}])Para la capa l , hay xyo=hyo([ x0,X1,... ,Xl - 1])
Suponiendo que el tamaño de salida de cada capafeature mapes W × H, el número de canales es k yBN-ReLU-Conv(3x3)consta de, entonces:

  • Operación de empalme Concat: es necesario generar un temporal feature mapcomo entrada de la l-ésima capa, y el consumo de memoria es W × H × k × l.
  • BNOperación: Es necesario generar temporal feature mapcomo ReLUentrada de, el consumo de memoria es W×H×k×l.
  • ReLUAcción: Se pueden realizar modificaciones in situ, por lo que no se requiere ningún resultado feature mapalmacenado adicional.ReLU
  • ConvOperación: Necesidad de generar salida feature mapComo salida de la capa l, es una sobrecarga necesaria.

feature mapPor lo tanto, además de la sobrecarga de memoria requerida para la salida de las capas 1, 2,..., L, la capa l también requiere una sobrecarga de memoria de 2W×H×k×l para almacenar el temporal generado en el medio feature map.
Todo el bloque DenseNet requiere una sobrecarga de memoria W × H × k × (L + 1) L para almacenar el mapa de características temporal generado en el medio. Es decir, el consumo de memoria del bloque DenseNet es O (L 2), que es la relación cuadrática de la profundidad de la red. Todo el bloque DenseNet requiere una sobrecarga de memoria W×H×k×(L+1)L para almacenar los mapas de características temporales generados en el medio. \\ Es decir, el consumo de memoria del bloque DenseNet es O (L ^ 2), que es la relación cuadrática de la profundidad de la red.Todo el bloque D en se N e t requiere W×h×k×( l+1 ) L sobrecarga de memoria para almacenar el mapa de características temporal generado en el medio.Es decir, el consumo de memoria del bloque Den se N e t es O ( L2 ), es la relación cuadrática de la profundidad de la red.

1.4.2 La necesidad de empalmar y los motivos del consumo de memoria.

  • La Concatoperación de empalme es necesaria porque la operación de convolución es más eficiente desde el punto de vista computacional cuando las entradas a la convolución se almacenan en áreas de memoria contiguas. En DenseNet Block, la entrada de la capa l se empalma a lo largo de la dirección del canal feature mapdesde la salida de las capas anteriores . feature mapEstas salidas feature mapno están en áreas de memoria contiguas.

  • DenseNet BlockEste consumo de memoria no es DenseNet Blockcausado por la estructura de, sino por la biblioteca de aprendizaje profundo. Porque Tensorflow/PyTorchcuando la biblioteca implementa la red neuronal, almacenará los nodos temporales generados en el medio (como BNel nodo de salida), para que el valor del nodo temporal se pueda obtener directamente durante la etapa de retropropagación.

  • Este es un compromiso entre el costo de tiempo y el costo de espacio: ahorrar cálculo durante la etapa de retropropagación al abrir más espacio para almacenar valores temporales.

1.4.3 Los parámetros de red también consumen memoria

Además del feature mapconsumo de memoria temporal, los parámetros de red también consumen memoria. Suponiendo que H BN-ReLU-Conv(3x3)consta de , el número de parámetros de red en la capa l es: 9 × l × k ^ 2 (no considerado BN).
El número de parámetros de todo el bloque DenseNet es 9 k 2 ( L + 1 ) L 2 , es decir, O ( L 2 ) El número de parámetros de todo el bloque DenseNet es \frac{9k^2(L+1) L}{2} , es decir, O(L^2)El número de parámetros para todo el bloque D en se N e t es29k _2 (L+1 ) L,Eso es O ( L2 )

  • Dado que DenseNetel número de parámetros tiene una relación cuadrada con la profundidad de la red, DenseNetla red tiene más parámetros y una mayor capacidad de red. Este también es DenseNetun factor importante sobre otras redes.
  • Por lo general, hay WH > (9×k/2), donde W y H son feature mapel ancho y alto de la red, y k es la tasa de crecimiento de la red. Por lo tanto, la memoria consumida por los parámetros de la red es mucho menor que feature mapla memoria consumida temporalmente.

1.5 Optimización de la memoria DenseNet_memoria compartida

La idea es explotar el compromiso entre costo de tiempo y costo de espacio, pero centrarse en sacrificar el costo de tiempo a cambio de costo de espacio.

Los factores de apoyo detrás de esto son: el costo computacional de Concatlas operaciones y las operaciones es muy bajo, pero el costo del espacio es alto. BNEntonces este enfoque funciona DenseNetmuy bien en .

1.5.1 Prácticas tradicionales

La capa tradicional DenseNet Blockl. Primero, feature mapcopie en bloques de memoria contiguos y complete la operación de empalme durante la copia. Luego realice las operaciones BN, ReLU, Conven secuencia.

La memoria temporal feature mapde esta capa necesita consumir 2W × H × k × l, y la salida de esta capa feature mapnecesita consumir memoria W × H × k.

  • Además, algunas implementaciones (como LuaTorch) también necesitan asignar memoria para el gradiente del proceso de retropropagación, como se muestra en la mitad inferior de la figura izquierda. Por ejemplo: al calcular BNel gradiente de la salida de la capa, BNse debe utilizar el gradiente de la l-ésima capa de salida y la salida de la capa. El almacenamiento de estos gradientes requiere memoria O(lk) adicional.
  • Otras implementaciones (por ejemplo, PyTorch,MxNet) utilizan un área de memoria compartida para que los gradientes almacenen estos gradientes, por lo que solo requieren memoria O(k).

inserte la descripción de la imagen aquí

1.5.2 Prácticas de memoria compartida

La imagen de la derecha muestra la capa l optimizada para memoria DenseNet Block. Se utilizan dos conjuntos de áreas de memoria compartida preasignadas Shared memory Storage locationpara almacenar concateoperaciones y BNresultados de operaciones temporalmente feature map.

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

El primer conjunto de áreas de memoria compartida preasignadas: concatel área operativa compartida. concatLas salidas de las operaciones en las capas 1, 2,..., L se escriben todas en el área compartida, y escribir en la capa (l+1) sobrescribirá los resultados en la capa (l).

  • En general Dense Block, esta área compartida solo necesita asignar feature mapmemoria W × H × k × L (la más grande), es decir, el consumo de memoria es O (kL) ( 对比传统DenseNet 的O(kL^2)).

  • Las operaciones posteriores BNleen datos directamente desde esta área compartida.

  • Dado que la escritura de la (l)ésima capa sobrescribirá los resultados de la (l)ésima capa, los datos almacenados aquí son temporales y se pierden fácilmente. Por lo tanto, el resultado de la operación de la capa (l) debe recalcularse en la etapa de retropropagación Concat.

    Debido a que concatla operación es muy eficiente desde el punto de vista computacional, este costo computacional adicional es bajo.

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

El segundo conjunto de áreas de memoria compartida preasignadas: BNel área operativa compartida. concatLas salidas de las operaciones en las capas 1, 2,..., L se escriben todas en el área compartida, y escribir en la capa (l+1) sobrescribirá los resultados en la capa (l).

  • Para Dense Blocktoda el área compartida, solo es feature mapnecesario asignar memoria W × H × k × L (la más grande), es decir, el consumo de memoria es O (kL) ( 对比传统DenseNet的O(kL^2) ).

  • Las operaciones de convolución posteriores leen datos directamente desde esta área compartida.

  • Por la misma razón que opera el área compartida, los resultados de las operaciones de la capa (l) concattambién deben recalcularse durante la etapa de retropropagación .BN

    BNLa eficiencia del cálculo también es muy alta, sólo se requiere alrededor del 5% de costo de cálculo adicional.

Dado que BNlas operaciones y concatlas operaciones se usan ampliamente en las redes neuronales, este método de preasignación de áreas de memoria compartida se puede usar ampliamente. Pueden ahorrar una gran cantidad de consumo de memoria y al mismo tiempo agregar una pequeña cantidad de tiempo de computación.

2 Ejemplos de aplicación de DenseNet en el conjunto de datos Fashion-MNIST

2.1 Crear modelo de red DenseNet

Como se muestra en 1.3.3.

2.2 Leer el conjunto de datos Fashion-MNIST

batch_size = 256

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

2.3 Entrenamiento de modelos en 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())

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_44665283/article/details/131558669
Recomendado
Clasificación