Red neuronal clásica (7) DenseNet y su aplicación en el conjunto de datos Fashion-MNIST
1 Breve descripción de DenseNet
-
DenseNet
No 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. -
ResNet
La idea es crear una conexión directa desde la "capa cercana a la entrada" a la "capa cercana a la salida". YDenseNet
lo hace aún más radicalmente: todas las capas están interconectadas en forma feed-forward, de ahí el nombreDenseNet
. -
DenseNet
Tiene 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 map
La 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).
-
DenseNet
Tiene menos parámetros que las redes convolucionales tradicionales porque no requiere reaprendizaje redundantefeature 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. -
ResNet
La información que debe retenerse se transfiere directamente a través del mapeo de identidad, por lo que solo se requiere transferencia entre capas状态的变化
. -
DenseNet
Todas las capas de todas las capas se状态
guardarán en集体知识
, mientras que cada capa agregará una pequeña cantidad de capasfeture map
a la red集体知识中
.
-
-
DenseNet
Las capas son muy estrechas (es decir,feature map
el número de canales es pequeño), por ejemplo, la salida de cada capa tiene solo 12 canales. -
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. -
Aunque
DenseNet
tiene una alta eficiencia computacional y relativamente pocos parámetros,DenseNet
no es compatible con la memoria. Puedes considerar compartir memoria para resolver este problema. -
Dirección de descarga del artículo: https://arxiv.org/pdf/1608.06993.pdf
1.1 Bloque denso (bloque denso)
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.
El nombre DenseNet proviene de las "conexiones densas" entre variables, estando la última capa estrechamente conectada con todas las capas anteriores.
注意
: Cuando feature map
se 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 DenseNet
bloques, el tamaño interno de cada bloque feature map
es el mismo y el tamaño entre bloques feature map
es diferente.
1.1.1 Tasa de crecimiento
-
DenseNet
En el bloque, el número de canales emitidos por cada capa de H (es decir, BN-ReLU-Conv)feature map
es 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 ( l−1 ) . entre ellos k0es el número de canales de la capa de entrada.
-
DenseNet
Una diferencia importante con las redes existentes es queDenseNet
la red es muy estrecha, es decir, el número defeature map
canales 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
DenseNet
cada capa de un bloque tiene acceso a las salidas de todas las capas anteriores dentro del bloquefeature map
, lo quefeature map
puede considerarse comoDenseNet
el estado global del bloque. La salida de cada capafeature map
se 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 map
no hay necesidad de replicación capa por capa (porque se comparte globalmente), lo que también esDenseNet
diferente 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
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
DenseNet
red tiene múltiplesDenseNet
bloquesDenseNet
conectados por capas de transición.DenseNet
La capa entre bloques se llama capa de transición y su función principal es conectar diferentesDenseNet
bloques. -
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
DenseNet
la salida del bloque anterior .feature map
- La capa de transición en el papel consta de una
BN
capa, una1x1
capa de convolución y una2x2
capa de agrupación promedio. La1x1
capa convolucional se utiliza para reducirDenseNet
la 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
DenseNet
pasar los bloques (el número de canales se calcula según la fórmula de la siguiente figura)DenseNet
feature map
- La capa de transición en el papel consta de una
- Si el número de canales
Dense
emitidos por el bloque es m, el número de canalesfeature map
emitidos 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 map
el número de canales que pasan a través de la capa de transición permanece sin cambios. - Cuando theta <1,
feature map
el número de canales que pasan a través de la capa de transición disminuye. En este momentoDenseNet
se llamaDenseNet-C
. - La red mejorada que combina
DenseNet-C
y se llamaDenseNet-B
DenseNet-BC
- Cuando theta = 1,
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 ImageNet
entrenada DenseNet
con tasa de crecimiento k = 32.
- en la tabla
conv
representaBN-ReLU-Conv
la combinación de . Por ejemplo1x1 conv
, significa: ejecutar primeroBN
, luego ejecutarReLU
y finalmente ejecutar1x1
la convolución de. DenseNet-xx
Indica queDenseNet
el bloque tienexx
capas. Por ejemplo:DenseNet-169
significa queDenseNet
el bloque tiene L=169 capas.- Todos
DenseNet
usanDenseNet-BC
la estructura, el tamaño de la imagen de entrada es224x224
, el tamaño de convolución inicial es7x7
, el canal de salida2k
, el tamaño del paso es2
y el factor de compresión theta = 0,5. - Al
DenseNet
final de todos los bloques, hay una capa de agrupación promedio global y el resultado de esta capa de agrupación se utiliza comosoftmax
entrada de la capa de salida.
1.3.2 ImageNet
Tasa de error en el conjunto de validación
La siguiente figura es una comparación de las tasas de error de DenseNet
y ResNet
en ImageNet
el 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.
Del experimento se puede ver que DenseNet
el número de parámetros y la cantidad de cálculo se ResNet
reducen de manera relativamente significativa.
- El error de validación de con
20M
parámetros es cercanoDenseNet-201
al de con40M
parámetros .ResNet-101
- El esfuerzo computacional de está cerca del
ResNet-101
error de verificación de está cerca , casi la mitad.DenseNet-201
ResNet-50
ResNet-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 DenseNet
tiene una alta eficiencia computacional y relativamente pocos parámetros, DenseNet
no es compatible con la memoria. Teniendo en cuenta GPU
la 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 DenseNet
el 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 map
es 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 temporalfeature map
como entrada de la l-ésima capa, y el consumo de memoria es W × H × k × l. BN
Operación: Es necesario generar temporalfeature map
comoReLU
entrada de, el consumo de memoria es W×H×k×l.ReLU
Acción: Se pueden realizar modificaciones in situ, por lo que no se requiere ningún resultadofeature map
almacenado adicional.ReLU
Conv
Operación: Necesidad de generar salidafeature map
Como salida de la capa l, es una sobrecarga necesaria.
feature map
Por 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
Concat
operació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. EnDenseNet Block
, la entrada de la capa l se empalma a lo largo de la dirección del canalfeature map
desde la salida de las capas anteriores .feature map
Estas salidasfeature map
no están en áreas de memoria contiguas. -
DenseNet Block
Este consumo de memoria no esDenseNet Block
causado por la estructura de, sino por la biblioteca de aprendizaje profundo. PorqueTensorflow/PyTorch
cuando la biblioteca implementa la red neuronal, almacenará los nodos temporales generados en el medio (comoBN
el 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 map
consumo 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
DenseNet
el número de parámetros tiene una relación cuadrada con la profundidad de la red,DenseNet
la red tiene más parámetros y una mayor capacidad de red. Este también esDenseNet
un factor importante sobre otras redes. - Por lo general, hay WH > (9×k/2), donde W y H son
feature map
el 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 quefeature map
la 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 Concat
las operaciones y las operaciones es muy bajo, pero el costo del espacio es alto. BN
Entonces este enfoque funciona DenseNet
muy bien en .
1.5.1 Prácticas tradicionales
La capa tradicional DenseNet Block
l. Primero, feature map
copie en bloques de memoria contiguos y complete la operación de empalme durante la copia. Luego realice las operaciones BN
, ReLU
, Conv
en secuencia.
La memoria temporal feature map
de esta capa necesita consumir 2W × H × k × l, y la salida de esta capa feature map
necesita 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 calcularBN
el gradiente de la salida de la capa,BN
se 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).
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 location
para almacenar concate
operaciones y BN
resultados de operaciones temporalmente feature map
.
对于第一组预分配的共享内存区:
El primer conjunto de áreas de memoria compartida preasignadas: concat
el área operativa compartida. concat
Las 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 asignarfeature map
memoria W × H × k × L (la más grande), es decir, el consumo de memoria es O (kL) (对比传统
DenseNet的O(kL^2)
). -
Las operaciones posteriores
BN
leen 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
concat
la 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: BN
el área operativa compartida. concat
Las 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 Block
toda el área compartida, solo esfeature map
necesario 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)
concat
también deben recalcularse durante la etapa de retropropagación .BN
BN
La eficiencia del cálculo también es muy alta, sólo se requiere alrededor del 5% de costo de cálculo adicional.
Dado que BN
las operaciones y concat
las 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())