Clasificación de imágenes: Resumen de LeNet/AlexNet/VGG/GoogleNet/DarkNet

1.LeNet(1998)

LeNet es una de las primeras redes neuronales convolucionales [1], que se propuso para reconocer dígitos escritos a mano y caracteres impresos por máquina. En 1998, Yann LeCun aplicó la red neuronal convolucional LeNet a la clasificación de imágenes por primera vez y logró un gran éxito en la tarea de reconocimiento de dígitos escritos a mano. El algoritmo explica que la correlación entre las características de los píxeles en la imagen se puede extraer mediante la operación de convolución del intercambio de parámetros, y la estructura combinada de convolución, reducción de muestreo (agrupación) y mapeo no lineal es actualmente la base más popular de las redes de reconocimiento de imágenes profundas.

1.1 Estructura del modelo LeNet

LeNet extrae las características de la imagen mediante el uso continuo de una combinación de capas de convolución y agrupación. Su arquitectura se  muestra en la Figura 1. Aquí está el modelo LeNet-5 utilizado en la tarea de reconocimiento de dígitos escritos a mano del MNIST:

  • El primer módulo: contiene convolución de 6 canales de 5 × 5 y agrupación de 2 × 2. La convolución extrae los patrones de características contenidos en la imagen (la función de activación usa Sigmoid), y el tamaño de la imagen se reduce de 28 a 24. Después de la capa de agrupación, la sensibilidad del mapa de características de salida a la posición espacial se puede reducir y el tamaño de la imagen se reduce a 12.

  • El segundo módulo: del mismo tamaño que el primer módulo, el número de canales se incrementa de 6 a 16. La operación de convolución reduce el tamaño de la imagen a 8, que se convierte en 4 después de la agrupación.

  • El tercer módulo: Contiene convolución de 120 canales 4×4. El tamaño de la imagen después de la convolución se reduce a 1, pero el número de canales aumenta a 120. Ingrese el mapa de características extraído por la tercera convolución a la capa completamente conectada. El número de neuronas de salida en la primera capa totalmente conectada es 64, el número de neuronas de salida en la segunda capa totalmente conectada es el número de categorías de etiquetas de clasificación y el número de categorías para el reconocimiento de dígitos escritos a mano es 10. Luego use la función de activación Softmax para calcular la probabilidad prevista de cada categoría.


pista:

¿Cómo se puede utilizar el mapa de características de salida de la capa convolucional como entrada de la capa totalmente conectada?

El formato de datos de salida de la capa convolucional es [�,�,�,�][N,C,H,W]. Al ingresar la capa completamente conectada, los datos se aplanarán automáticamente.

Es decir, para cada muestra, se convierte automáticamente en un vector de longitud �K,

Entre ellos, �=�×�×�K=C×H×W, la dimensión de datos de un mini lote se convierte en un vector bidimensional de �×�N×K.


1.2 Implementación del modelo LeNet

El código de implementación de la red LeNet es el siguiente:

 
 

pitón

copiar codigo

#导入需要的包 import paddle import numpy as np from paddle.nn import Conv2D, MaxPool2D, Linear ##组网 import paddle.nn.functional as F #定义 LeNet 网络结构 class LeNet(paddle.nn.Layer): def __init__(self, num_classes=1): super(LeNet, self).__init__() # 创建卷积和池化层 # 创建第1个卷积层 self.conv1 = Conv2D(in_channels=1, out_channels=6, kernel_size=5) self.max_pool1 = MaxPool2D(kernel_size=2, stride=2) # 尺寸的逻辑:池化层未改变通道数;当前通道数为6 # 创建第2个卷积层 self.conv2 = Conv2D(in_channels=6, out_channels=16, kernel_size=5) self.max_pool2 = MaxPool2D(kernel_size=2, stride=2) # 创建第3个卷积层 self.conv3 = Conv2D(in_channels=16, out_channels=120, kernel_size=4) # 尺寸的逻辑:输入层将数据拉平[B,C,H,W] -> [B,C*H*W] # 输入size是[28,28],经过三次卷积和两次池化之后,C*H*W等于120 self.fc1 = Linear(in_features=120, out_features=64) # 创建全连接层,第一个全连接层的输出神经元个数为64, 第二个全连接层输出神经元个数为分类标签的类别数 self.fc2 = Linear(in_features=64, out_features=num_classes) #网络的前向计算过程 def forward(self, x): x = self.conv1(x) # 每个卷积层使用Sigmoid激活函数,后面跟着一个2x2的池化 x = F.sigmoid(x) x = self.max_pool1(x) x = F.sigmoid(x) x = self.conv2(x) x = self.max_pool2(x) x = self.conv3(x) #尺寸的逻辑:输入层将数据拉平[B,C,H,W] -> [B,C*H*W] x = paddle.reshape(x, [x.shape[0], -1]) x = self.fc1(x) x = F.sigmoid(x) x = self.fc2(x) return x

1.3 Características del modelo LeNet

  • La red convolucional utiliza una combinación de secuencias de 3 capas: convolución, reducción de muestreo (agrupación), mapeo no lineal (la característica más importante de LeNet-5, que sienta las bases para la red convolucional profunda actual);
  • Utilice la convolución para extraer características espaciales;
  • Reducción de muestreo usando la media espacial mapeada;
  • Use ��ℎtanh o ��������sigmoid para el mapeo no lineal;
  • Red neuronal multicapa (MLP) como clasificador final;
  • Una matriz de conexión escasa entre capas evita una gran sobrecarga computacional.

1.4 Indicadores del modelo LeNet

LeNet-5 ha llevado a cabo el entrenamiento y las pruebas del modelo en la tarea de reconocimiento de dígitos escritos a mano del MNIST. Los indicadores del modelo proporcionados en el documento se  muestran en la Figura 2. Después de usar el método de distorsiones, la tasa de error puede alcanzar el 0,8%.

  • referencias

[1]  Aprendizaje basado en gradientes aplicado al reconocimiento de documentos.

2.AlexNet(2012)

AlexNet[1] es el modelo campeón de la competencia ImageNet en 2012. Sus autores son Hinton, uno de los tres gigantes en el campo de las redes neuronales, y su alumno Alex Krizhevsky.

AlexNet lideró el segundo lugar en la competencia ImageNet 2012 con una gran ventaja, lo que trajo un gran impacto en los círculos académicos e industriales en ese momento. Desde entonces, se han propuesto redes neuronales cada vez más profundas, como excelentes VGG, GoogLeNet, ResNet, etc.

2.1 Estructura del modelo AlexNet

En comparación con LeNet anterior, AlexNet tiene una estructura de red más profunda, que incluye 5 capas de convolución y 3 capas de conexión completa. La estructura específica se  muestra en la Figura 1.

1) El primer módulo: para una imagen en color de 224 × 224224 × 224, primero se convoluciona con 96 núcleos de convolución de 11 × 11 × 311 × 11 × 3 para extraer los patrones de características contenidos en la imagen (el tamaño de paso es 4 , el padding es 2 y se obtienen 96 resultados de convolución (mapas de características) de 54×5454×54, luego se realiza el pooling con un tamaño de 2×22×2 y se obtienen 96 mapas de características de tamaño 27×2727×27 ;

2) El segundo módulo: contiene 256 circunvoluciones de agrupación de 5 × 55 × 5 y 2 × 22 × 2. Después de la operación de convolución, el tamaño de la imagen permanece sin cambios.

3) El tercer módulo: contiene 384 circunvoluciones de 3×33×3, y el tamaño de la imagen permanece sin cambios después de la operación de convolución;

4) El cuarto módulo: contiene 384 circunvoluciones de 3×33×3, y el tamaño de la imagen permanece sin cambios después de la operación de convolución;

5) El quinto módulo: contiene 256 circunvoluciones de 3 × 33 × 3 y agrupación de 2 × 22 × 2. Después de la operación de convolución, el tamaño de la imagen permanece sin cambios y se convierte en 256 6 × 66 × 6 después de agrupar el mapa de características de .

El mapa de características extraído por la quinta convolución se ingresa a la capa completamente conectada para obtener la representación vectorial de la imagen original. La cantidad de neuronas de salida en las dos primeras capas completamente conectadas es 4096, y la cantidad de neuronas de salida en la tercera capa completamente conectada es la cantidad de etiquetas de clasificación (la cantidad de categorías de clasificación en la competencia ImageNet es 1000), y luego use la función de activación de Softmax Se puede calcular la probabilidad prevista de cada categoría.

2.2 Implementación del modelo AlexNet

Basado en el marco de Paddle, el código de implementación específico de AlexNet es el siguiente:

 
 

pitón

copiar codigo

#-*- coding:utf-8 -*- #导入需要的包 import paddle import numpy as np from paddle.nn import Conv2D, MaxPool2D, Linear, Dropout ##组网 import paddle.nn.functional as F #定义 AlexNet 网络结构 class AlexNet(paddle.nn.Layer): def __init__(self, num_classes=1): super(AlexNet, self).__init__() # AlexNet与LeNet一样也会同时使用卷积和池化层提取图像特征 # 与LeNet不同的是激活函数换成了‘relu’ self.conv1 = Conv2D(in_channels=3, out_channels=96, kernel_size=11, stride=4, padding=5) self.max_pool1 = MaxPool2D(kernel_size=2, stride=2) self.conv2 = Conv2D(in_channels=96, out_channels=256, kernel_size=5, stride=1, padding=2) self.max_pool2 = MaxPool2D(kernel_size=2, stride=2) self.conv3 = Conv2D(in_channels=256, out_channels=384, kernel_size=3, stride=1, padding=1) self.conv4 = Conv2D(in_channels=384, out_channels=384, kernel_size=3, stride=1, padding=1) self.conv5 = Conv2D(in_channels=384, out_channels=256, kernel_size=3, stride=1, padding=1) self.max_pool5 = MaxPool2D(kernel_size=2, stride=2) self.fc1 = Linear(in_features=12544, out_features=4096) self.drop_ratio1 = 0.5 self.drop1 = Dropout(self.drop_ratio1) self.fc2 = Linear(in_features=4096, out_features=4096) self.drop_ratio2 = 0.5 self.drop2 = Dropout(self.drop_ratio2) self.fc3 = Linear(in_features=4096, out_features=num_classes) def forward(self, x): x = self.conv1(x) x = F.relu(x) x = self.max_pool1(x) x = self.conv2(x) x = F.relu(x) x = self.max_pool2(x) x = self.conv3(x) x = F.relu(x) x = self.conv4(x) x = F.relu(x) x = self.conv5(x) x = F.relu(x) x = self.max_pool5(x) x = paddle.reshape(x, [x.shape[0], -1]) x = self.fc1(x) x = F.relu(x) # 在全连接之后使用dropout抑制过拟合 x = self.drop1(x) x = self.fc2(x) x = F.relu(x) # 在全连接之后使用dropout抑制过拟合 x = self.drop2(x) x = self.fc3(x) return x

2.3 Características del modelo AlexNet

AlexNet contiene varios puntos técnicos relativamente nuevos y, por primera vez, aplicó con éxito trucos como ReLU, Dropout y LRN en CNN. Al mismo tiempo, AlexNet también usa GPU para la aceleración informática.

AlexNet llevó adelante la idea de LeNet y aplicó los principios básicos de CNN a una red profunda y amplia. Las nuevas tecnologías utilizadas principalmente por AlexNet son las siguientes:

  • Usó con éxito ReLU como la función de activación de CNN y verificó que su efecto superaba a Sigmoid en redes más profundas y resolvió con éxito el problema de dispersión de gradiente de Sigmoid en redes más profundas. Aunque la función de activación de ReLU se propuso hace mucho tiempo, no se llevó adelante hasta la aparición de AlexNet.
  • Durante el entrenamiento, Dropout se usa para ignorar aleatoriamente algunas neuronas para evitar el sobreajuste del modelo. Aunque Dropout tiene un documento separado, AlexNet lo puso en práctica y demostró su efecto a través de la práctica. En AlexNet, Dropout se usa principalmente en las últimas capas completamente conectadas.
  • Uso de agrupación máxima superpuesta en CNN . Anteriormente, la agrupación promedio se usaba comúnmente en CNN, y AlexNet usaba la agrupación máxima para evitar el efecto confuso de la agrupación promedio. Y en AlexNet, se propone que la longitud del paso sea más pequeña que el tamaño del kernel de agrupación, de modo que habrá superposición y cobertura entre las salidas de la capa de agrupación, lo que mejora la riqueza de características.
  • Se propone la capa de normalización de respuesta local LRN para crear un mecanismo de competencia para la actividad de las neuronas locales, de modo que el valor con una respuesta relativamente grande se vuelva relativamente más grande e inhiba otras neuronas con retroalimentación más pequeña, mejorando la capacidad de generalización del modelo.
  • Utilice CUDA para acelerar el entrenamiento de redes convolucionales profundas y use las potentes capacidades de computación paralela de GPU para manejar una gran cantidad de operaciones matriciales durante el entrenamiento de redes neuronales. AlexNet usa dos GPU GTX 580 para el entrenamiento y una sola GTX 580 tiene solo 3 GB de memoria de video, lo que limita el tamaño máximo de la red que se puede entrenar. Por lo tanto, el autor distribuye AlexNet en dos GPU y almacena la mitad de los parámetros de las neuronas en la memoria de cada GPU. Debido a que la comunicación entre las GPU es conveniente y se puede acceder a la memoria de video sin pasar por la memoria del host, también es muy eficiente usar varias GPU al mismo tiempo. Al mismo tiempo, el diseño de AlexNet permite que la comunicación entre GPU se realice solo en ciertas capas de la red, lo que controla la pérdida de rendimiento de la comunicación. 
  • Usando el aumento de datos , una región de tamaño 224 × 224224 × 224 (y una imagen especular volteada horizontalmente) se corta aleatoriamente de la imagen original de tamaño 256 × 256256 × 256, lo que equivale a un aumento de 2 × (256−224) 2=20482×( 256−224)2=2048 veces la cantidad de datos. Si no hay mejora de datos, solo se basa en el volumen de datos original, CNN con muchos parámetros caerá en sobreajuste Después de usar la mejora de datos, el sobreajuste se puede reducir en gran medida y la capacidad de generalización se puede mejorar. Al hacer predicciones, se toman un total de 5 posiciones de las cuatro esquinas de la imagen más el centro, y se giran hacia la izquierda y hacia la derecha para obtener un total de 10 imágenes, predecirlas y calcular el promedio de los 10 resultados. Al mismo tiempo, el documento de AlexNet mencionó que el procesamiento PCA se realizará en los datos RGB de la imagen y se realizará una perturbación gaussiana con una desviación estándar de 0,1 en el componente principal para agregar algo de ruido. tasa de error en otro 1%.

2.4 Indicadores del modelo AlexNet

Como el algoritmo campeón de la competencia ImageNet 2012, AlexNet logró una tasa de error entre los 5 primeros del 15,3 % en el conjunto de prueba de ImageNet, superando con creces el 26,2 % del segundo lugar (SIFT+FV). Como se muestra en la Figura  2  .

  • referencias

[1]  Clasificación de Imagenet con redes neuronales convolucionales profundas.

3.VGG (2012)

Después de que AlexNet brilló en la competencia ImageNet en 2012, la red neuronal convolucional entró en una etapa de rápido desarrollo. En 2014, la red VGG [1] propuesta por Simonyan y Zisserman obtuvo el segundo lugar en ImageNet. El nombre de VGG proviene del Visual Geometry Group, el laboratorio del autor del artículo. Ha mejorado la red neuronal convolucional, explorado la relación entre la profundidad y el rendimiento de la red, y logrado mejores resultados con núcleos de convolución más pequeños y estructuras de red más profundas. El buen efecto se ha convertido en una red más importante en la historia del desarrollo de CNN. VGG utiliza una serie de núcleos de convolución de tamaño pequeño de 3x3 y capas de agrupación para construir una red neuronal convolucional profunda. Es muy bien recibido por los investigadores debido a su estructura simple y gran aplicabilidad, especialmente su método de diseño de estructura de red. , proporcionando una dirección para la construcción. redes neuronales profundas.

3.1 Estructura del modelo VGG

La Figura 1  es un diagrama esquemático de la estructura de red de VGG-16, con 13 capas de convolución y 3 capas de capas completamente conectadas. El diseño de la red VGG usa estrictamente una capa convolucional de 3×33×3 y una capa de agrupación para extraer características, y usa tres capas completamente conectadas al final de la red, y usa la salida de la última capa completamente conectada como clasificación predicción.

También hay una característica notable en VGG: el tamaño del mapa de características se duplica después de cada paso a través de la capa de agrupación (maxpooling) y la cantidad de canales se duplica (excepto la última capa de agrupación).

En VGG, cada capa de convolución usará ReLU como función de activación, y se agregará el abandono después de la capa completamente conectada para suprimir el sobreajuste. El uso de un kernel de convolución pequeño puede reducir de manera efectiva la cantidad de parámetros, lo que hace que el entrenamiento y las pruebas sean más eficientes. Por ejemplo, usar dos capas convolucionales de 3×33×3 puede obtener un mapa de características con un campo receptivo de 5, lo que requiere menos parámetros que usar una capa convolucional de 5×55×5. Dado que el kernel de convolución es relativamente pequeño, se pueden apilar más capas de convolución para aumentar la profundidad de la red, lo que es beneficioso para las tareas de clasificación de imágenes. El éxito del modelo VGG demuestra que aumentar la profundidad de la red puede aprender mejor los patrones de características en la imagen.

3.2 Implementación del modelo VGG

Basado en el marco de Paddle, la implementación específica de VGG se muestra en el siguiente código:

 
 

pitón

copiar codigo

#-*- coding:utf-8 -*- #VGG模型代码 import numpy as np import paddle #from paddle.nn import Conv2D, MaxPool2D, BatchNorm, Linear from paddle.nn import Conv2D, MaxPool2D, BatchNorm2D, Linear #定义vgg网络 class VGG(paddle.nn.Layer): def __init__(self): super(VGG, self).__init__() in_channels = [3, 64, 128, 256, 512, 512] # 定义第一个卷积块,包含两个卷积 self.conv1_1 = Conv2D(in_channels=in_channels[0], out_channels=in_channels[1], kernel_size=3, padding=1, stride=1) self.conv1_2 = Conv2D(in_channels=in_channels[1], out_channels=in_channels[1], kernel_size=3, padding=1, stride=1) # 定义第二个卷积块,包含两个卷积 self.conv2_1 = Conv2D(in_channels=in_channels[1], out_channels=in_channels[2], kernel_size=3, padding=1, stride=1) self.conv2_2 = Conv2D(in_channels=in_channels[2], out_channels=in_channels[2], kernel_size=3, padding=1, stride=1) # 定义第三个卷积块,包含三个卷积 self.conv3_1 = Conv2D(in_channels=in_channels[2], out_channels=in_channels[3], kernel_size=3, padding=1, stride=1) self.conv3_2 = Conv2D(in_channels=in_channels[3], out_channels=in_channels[3], kernel_size=3, padding=1, stride=1) self.conv3_3 = Conv2D(in_channels=in_channels[3], out_channels=in_channels[3], kernel_size=3, padding=1, stride=1) # 定义第四个卷积块,包含三个卷积 self.conv4_1 = Conv2D(in_channels=in_channels[3], out_channels=in_channels[4], kernel_size=3, padding=1, stride=1) self.conv4_2 = Conv2D(in_channels=in_channels[4], out_channels=in_channels[4], kernel_size=3, padding=1, stride=1) self.conv4_3 = Conv2D(in_channels=in_channels[4], out_channels=in_channels[4], kernel_size=3, padding=1, stride=1) # 定义第五个卷积块,包含三个卷积 self.conv5_1 = Conv2D(in_channels=in_channels[4], out_channels=in_channels[5], kernel_size=3, padding=1, stride=1) self.conv5_2 = Conv2D(in_channels=in_channels[5], out_channels=in_channels[5], kernel_size=3, padding=1, stride=1) self.conv5_3 = Conv2D(in_channels=in_channels[5], out_channels=in_channels[5], kernel_size=3, padding=1, stride=1) # 使用Sequential 将全连接层和relu组成一个线性结构(fc + relu) # 当输入为224x224时,经过五个卷积块和池化层后,特征维度变为[512x7x7] self.fc1 = paddle.nn.Sequential(paddle.nn.Linear(512 * 7 * 7, 4096), paddle.nn.ReLU()) self.drop1_ratio = 0.5 self.dropout1 = paddle.nn.Dropout(self.drop1_ratio, mode='upscale_in_train') # 使用Sequential 将全连接层和relu组成一个线性结构(fc + relu) self.fc2 = paddle.nn.Sequential(paddle.nn.Linear(4096, 4096), paddle.nn.ReLU()) self.drop2_ratio = 0.5 self.dropout2 = paddle.nn.Dropout(self.drop2_ratio, mode='upscale_in_train') self.fc3 = paddle.nn.Linear(4096, 1) self.relu = paddle.nn.ReLU() self.pool = MaxPool2D(stride=2, kernel_size=2) def forward(self, x): x = self.relu(self.conv1_1(x)) x = self.relu(self.conv1_2(x)) x = self.pool(x) x = self.relu(self.conv2_1(x)) x = self.relu(self.conv2_2(x)) x = self.pool(x) x = self.relu(self.conv3_1(x)) x = self.relu(self.conv3_2(x)) x = self.relu(self.conv3_3(x)) x = self.pool(x) x = self.relu(self.conv4_1(x)) x = self.relu(self.conv4_2(x)) x = self.relu(self.conv4_3(x)) x = self.pool(x) x = self.relu(self.conv5_1(x)) x = self.relu(self.conv5_2(x)) x = self.relu(self.conv5_3(x)) x = self.pool(x) x = paddle.flatten(x, 1, -1) x = self.dropout1(self.relu(self.fc1(x))) x = self.dropout2(self.relu(self.fc2(x))) x = self.fc3(x) return x

3.3 Características del modelo VGG

  • Toda la red utiliza el mismo tamaño de kernel de convolución de tamaño 3×33×3 y el tamaño máximo de agrupación 2×22×2.
  • La importancia de la convolución 1 × 11 × 1 radica principalmente en la transformación lineal, mientras que la cantidad de canales de entrada y de salida permanece sin cambios y no se produce una reducción de la dimensionalidad.
  • Dos capas convolucionales de 3×33×3 conectadas en serie equivalen a una capa convolucional de 5×55×5, y el tamaño del campo receptivo es de 5×55×5. De manera similar, el efecto de concatenar tres capas convolucionales de 3×33×3 es equivalente a una capa convolucional de 7×77×7. Este método de conexión hace que los parámetros de la red sean más pequeños y la función de activación multicapa hace que la red sea más capaz de aprender características.
  • VGGNet tiene un pequeño truco durante el entrenamiento. Primero entrene la red simple superficial VGG11 y luego reutilice el peso de VGG11 para inicializar VGG13. El entrenamiento repetido y la inicialización de VGG19 pueden hacer que la velocidad de convergencia del entrenamiento sea más rápida.
  • En el proceso de entrenamiento, se utiliza la transformación multiescala para mejorar los datos originales, de modo que el modelo no sea fácil de sobreajustar.

3.4 Indicadores del modelo VGG

VGG ganó el segundo lugar en la competencia ImageNet en 2014, y los indicadores específicos se  muestran en la Figura 2. La primera línea de la Figura 2  es el índice de la competencia de ImageNet. La tasa de error del conjunto de prueba alcanzó el 7,3 %. En el artículo, el autor optimizó el algoritmo hasta cierto punto, y finalmente alcanzó una tasa de error del 6,8 %.

  • referencias

[1]  Redes convolucionales muy profundas para el reconocimiento de imágenes a gran escala.

4.GoogLeNet(2014)

GoogLeNet [1] es el campeón de la competencia ImageNet en 2014. Su característica principal es que la red no solo tiene profundidad, sino que también tiene "ancho" en la dirección horizontal. Por el nombre GoogLeNet, podemos saber que se trata de una estructura de red diseñada por los ingenieros de Google, y el nombre GoogLeNet es un tributo a LeNet. La parte central de GoogLeNet es su estructura de subred interna Inception, que está inspirada en NIN (Network In Network).

4.1 Estructura del modelo GoogLeNet

Debido a la gran diferencia en el tamaño espacial de la información de la imagen, es más difícil elegir un kernel de convolución adecuado para extraer características. La información de imagen con una distribución espacial más amplia es adecuada para extraer sus características con un núcleo de convolución más grande, mientras que la información de imagen con una distribución espacial más pequeña es adecuada para extraer sus características con un núcleo de convolución más pequeño. Para resolver este problema, GoogLeNet propuso un esquema llamado módulo Inception. Como se muestra en la Figura  1  :


ilustrar:

  • Para rendir homenaje a LeNet, los investigadores de Google nombraron especialmente el modelo GoogLeNet.

  • La palabra Inception proviene de la película "Inception".

La Figura 1(a) es la idea de diseño del módulo Inception. Se utilizan tres núcleos de convolución de diferentes tamaños para realizar operaciones de convolución en la imagen de entrada, y se agrega una agrupación máxima adicional. Las salidas de estas cuatro operaciones se empalman. a lo largo de la dimensión del canal. El mapa de características de salida resultante contendrá características extraídas por núcleos de convolución de diferentes tamaños, para lograr el efecto de capturar información de diferentes escalas. El módulo Inception adopta una forma de diseño de rutas múltiples, cada rama usa un kernel de convolución de diferentes tamaños, y la cantidad de canales del mapa de características de salida final es la suma de la cantidad de canales de salida de cada rama, lo que dará como resultado la canal de salida El número se vuelve muy grande, especialmente cuando se usan múltiples módulos Inception para operar en serie, la cantidad de parámetros del modelo será muy grande.

Para reducir la cantidad de parámetros, el módulo Inception utiliza el método de diseño de la Figura (b).Antes de cada capa convolucional de 3x3 y 5x5, agregue una capa convolucional de 1x1 para controlar el número de canales de salida; aumente después de la capa de agrupación máxima A La capa convolucional 1x1 reduce el número de canales de salida. Sobre la base de esta idea de diseño, se forma la estructura que se muestra en (b) anterior. El siguiente programa es la implementación específica del bloque Inception, que se puede leer junto con el código como se muestra en la Figura (b).


pista:

Algunos lectores pueden preguntarse, ¿no se reducirá el tamaño de la imagen después de una agrupación máxima de 3x3?¿Por qué se puede empalmar con la salida de mapas de características por las otras 3 convoluciones? Esto se debe a que la operación de agrupación puede especificar el tamaño de la ventana ℎ=��=3kh​=kw​=3, stride=1 y padding=1, y el tamaño del mapa de características de salida puede permanecer sin cambios.


La implementación específica del módulo Inception se muestra en el siguiente código:

 
 

pitón

copiar codigo

#GoogLeNet模型代码 import numpy as np import paddle from paddle.nn import Conv2D, MaxPool2D, AdaptiveAvgPool2D, Linear ##组网 import paddle.nn.functional as F #定义Inception块 class Inception(paddle.nn.Layer): def __init__(self, c0, c1, c2, c3, c4, **kwargs): ''' Inception模块的实现代码, c1,图(b)中第一条支路1x1卷积的输出通道数,数据类型是整数 c2,图(b)中第二条支路卷积的输出通道数,数据类型是tuple或list, 其中c2[0]是1x1卷积的输出通道数,c2[1]是3x3 c3,图(b)中第三条支路卷积的输出通道数,数据类型是tuple或list, 其中c3[0]是1x1卷积的输出通道数,c3[1]是3x3 c4,图(b)中第一条支路1x1卷积的输出通道数,数据类型是整数 ''' super(Inception, self).__init__() # 依次创建Inception块每条支路上使用到的操作 self.p1_1 = Conv2D(in_channels=c0,out_channels=c1, kernel_size=1) self.p2_1 = Conv2D(in_channels=c0,out_channels=c2[0], kernel_size=1) self.p2_2 = Conv2D(in_channels=c2[0],out_channels=c2[1], kernel_size=3, padding=1) self.p3_1 = Conv2D(in_channels=c0,out_channels=c3[0], kernel_size=1) self.p3_2 = Conv2D(in_channels=c3[0],out_channels=c3[1], kernel_size=5, padding=2) self.p4_1 = MaxPool2D(kernel_size=3, stride=1, padding=1) self.p4_2 = Conv2D(in_channels=c0,out_channels=c4, kernel_size=1) def forward(self, x): # 支路1只包含一个1x1卷积 p1 = F.relu(self.p1_1(x)) # 支路2包含 1x1卷积 + 3x3卷积 p2 = F.relu(self.p2_2(F.relu(self.p2_1(x)))) # 支路3包含 1x1卷积 + 5x5卷积 p3 = F.relu(self.p3_2(F.relu(self.p3_1(x)))) # 支路4包含 最大池化和1x1卷积 p4 = F.relu(self.p4_2(self.p4_1(x))) # 将每个支路的输出特征图拼接在一起作为最终的输出结果 return paddle.concat([p1, p2, p3, p4], axis=1)

La arquitectura de GoogLeNet se  muestra en la Figura 2. Se usan cinco módulos (bloques) en la parte de convolución principal, y se usa una capa de agrupación máxima de 3 × 3 con un paso de 2 entre cada módulo para reducir la altura y el ancho de salida.

  • El primer módulo utiliza una capa convolucional de 7 × 7 de 64 canales.
  • El segundo módulo utiliza 2 capas convolucionales: primero una capa convolucional de 1 × 1 con 64 canales, seguida de una capa convolucional de 3 × 3 con 3 veces los canales.
  • El tercer módulo conecta 2 bloques Inception completos en serie.
  • El cuarto módulo conecta 5 bloques Inception en serie.
  • El quinto módulo conecta 2 bloques Inception en serie.
  • El quinto módulo es seguido por la capa de salida, utilizando la capa de agrupación promedio global para cambiar la altura y el ancho de cada canal a 1, y finalmente conectando una capa completamente conectada cuyo número de salida es el número de categorías de etiquetas.

Explicación:  Los dos clasificadores auxiliares softmax1 y softmax2 que se muestran en la figura se agregan al artículo original del autor.Como se muestra en la figura a continuación, las funciones de pérdida de los tres clasificadores se ponderan y suman durante el entrenamiento para aliviar el fenómeno de desaparición del gradiente.

4.2 Implementación del modelo GoogLeNet

La implementación específica de GoogLeNet se muestra en el siguiente código:

 
 

pitón

copiar codigo

#GoogLeNet模型代码 import paddle from paddle import ParamAttr import paddle.nn as nn import paddle.nn.functional as F from paddle.nn import Conv2D, BatchNorm, Linear, Dropout from paddle.nn import AdaptiveAvgPool2D, MaxPool2D, AvgPool2D from paddle.nn.initializer import Uniform import math #全连接层参数初始化 def xavier(channels, filter_size, name): stdv = (3.0 / (filter_size**2 * channels))**0.5 param_attr = ParamAttr(initializer=Uniform(-stdv, stdv), name=name + "_weights") return param_attr class ConvLayer(nn.Layer): def __init__(self, num_channels, num_filters, filter_size, stride=1, groups=1, act=None, name=None): super(ConvLayer, self).__init__() self._conv = Conv2D( in_channels=num_channels, out_channels=num_filters, kernel_size=filter_size, stride=stride, padding=(filter_size - 1) // 2, groups=groups, weight_attr=ParamAttr(name=name + "_weights"), bias_attr=False) def forward(self, inputs): y = self._conv(inputs) return y #定义Inception块 class Inception(nn.Layer): def __init__(self, input_channels, output_channels, filter1, filter3R, filter3, filter5R, filter5, proj, name=None): ''' Inception模块的实现代码, c1,图(b)中第一条支路1x1卷积的输出通道数,数据类型是整数 c2,图(b)中第二条支路卷积的输出通道数,数据类型是tuple或list, 其中c2[0]是1x1卷积的输出通道数,c2[1]是3x3 c3,图(b)中第三条支路卷积的输出通道数,数据类型是tuple或list, 其中c3[0]是1x1卷积的输出通道数,c3[1]是3x3 c4,图(b)中第一条支路1x1卷积的输出通道数,数据类型是整数 ''' super(Inception, self).__init__() # 依次创建Inception块每条支路上使用到的操作 self._conv1 = ConvLayer(input_channels, filter1, 1, name="inception_" + name + "_1x1") self._conv3r = ConvLayer(input_channels, filter3R, 1, name="inception_" + name + "_3x3_reduce") self._conv3 = ConvLayer(filter3R, filter3, 3, name="inception_" + name + "_3x3") self._conv5r = ConvLayer(input_channels, filter5R, 1, name="inception_" + name + "_5x5_reduce") self._conv5 = ConvLayer(filter5R, filter5, 5, name="inception_" + name + "_5x5") self._pool = MaxPool2D(kernel_size=3, stride=1, padding=1) self._convprj = ConvLayer(input_channels, proj, 1, name="inception_" + name + "_3x3_proj") def forward(self, inputs): # 支路1只包含一个1x1卷积 conv1 = self._conv1(inputs) # 支路2包含 1x1卷积 + 3x3卷积 conv3r = self._conv3r(inputs) conv3 = self._conv3(conv3r) # 支路3包含 1x1卷积 + 5x5卷积 conv5r = self._conv5r(inputs) conv5 = self._conv5(conv5r) # 支路4包含 最大池化和1x1卷积 pool = self._pool(inputs) convprj = self._convprj(pool) # 将每个支路的输出特征图拼接在一起作为最终的输出结果 cat = paddle.concat([conv1, conv3, conv5, convprj], axis=1) cat = F.relu(cat) return cat class GoogLeNet(nn.Layer): def __init__(self, class_dim=1000): super(GoogLeNetDY, self).__init__() # GoogLeNet包含五个模块,每个模块后面紧跟一个池化层 # 第一个模块包含1个卷积层 self._conv = ConvLayer(3, 64, 7, 2, name="conv1") # 3x3最大池化 self._pool = MaxPool2D(kernel_size=3, stride=2) # 第二个模块包含2个卷积层 self._conv_1 = ConvLayer(64, 64, 1, name="conv2_1x1") self._conv_2 = ConvLayer(64, 192, 3, name="conv2_3x3") # 第三个模块包含2个Inception块 self._ince3a = Inception(192, 192, 64, 96, 128, 16, 32, 32, name="ince3a") self._ince3b = Inception(256, 256, 128, 128, 192, 32, 96, 64, name="ince3b") # 第四个模块包含5个Inception块 self._ince4a = Inception(480, 480, 192, 96, 208, 16, 48, 64, name="ince4a") self._ince4b = Inception(512, 512, 160, 112, 224, 24, 64, 64, name="ince4b") self._ince4c = Inception(512, 512, 128, 128, 256, 24, 64, 64, name="ince4c") self._ince4d = Inception(512, 512, 112, 144, 288, 32, 64, 64, name="ince4d") self._ince4e = Inception(528, 528, 256, 160, 320, 32, 128, 128, name="ince4e") # 第五个模块包含2个Inception块 self._ince5a = Inception(832, 832, 256, 160, 320, 32, 128, 128, name="ince5a") self._ince5b = Inception(832, 832, 384, 192, 384, 48, 128, 128, name="ince5b") # 全局池化 self._pool_5 = AvgPool2D(kernel_size=7, stride=7) self._drop = Dropout(p=0.4, mode="downscale_in_infer") self._fc_out = Linear( 1024, class_dim, weight_attr=xavier(1024, 1, "out"), bias_attr=ParamAttr(name="out_offset")) self._pool_o1 = AvgPool2D(kernel_size=5, stride=3) self._conv_o1 = ConvLayer(512, 128, 1, name="conv_o1") self._fc_o1 = Linear( 1152, 1024, weight_attr=xavier(2048, 1, "fc_o1"), bias_attr=ParamAttr(name="fc_o1_offset")) self._drop_o1 = Dropout(p=0.7, mode="downscale_in_infer") self._out1 = Linear( 1024, class_dim, weight_attr=xavier(1024, 1, "out1"), bias_attr=ParamAttr(name="out1_offset")) self._pool_o2 = AvgPool2D(kernel_size=5, stride=3) self._conv_o2 = ConvLayer(528, 128, 1, name="conv_o2") self._fc_o2 = Linear( 1152, 1024, weight_attr=xavier(2048, 1, "fc_o2"), bias_attr=ParamAttr(name="fc_o2_offset")) self._drop_o2 = Dropout(p=0.7, mode="downscale_in_infer") self._out2 = Linear( 1024, class_dim, weight_attr=xavier(1024, 1, "out2"), bias_attr=ParamAttr(name="out2_offset")) def forward(self, inputs): x = self._conv(inputs) x = self._pool(x) x = self._conv_1(x) x = self._conv_2(x) x = self._pool(x) x = self._ince3a(x) x = self._ince3b(x) x = self._pool(x) ince4a = self._ince4a(x) x = self._ince4b(ince4a) x = self._ince4c(x) ince4d = self._ince4d(x) x = self._ince4e(ince4d) x = self._pool(x) x = self._ince5a(x) ince5b = self._ince5b(x) x = self._pool_5(ince5b) x = self._drop(x) x = paddle.squeeze(x, axis=[2, 3]) out = self._fc_out(x) x = self._pool_o1(ince4a) x = self._conv_o1(x) x = paddle.flatten(x, start_axis=1, stop_axis=-1) x = self._fc_o1(x) x = F.relu(x) x = self._drop_o1(x) out1 = self._out1(x) x = self._pool_o2(ince4d) x = self._conv_o2(x) x = paddle.flatten(x, start_axis=1, stop_axis=-1) x = self._fc_o2(x) x = self._drop_o2(x) out2 = self._out2(x) return [out, out1, out2]

4.3 Características del modelo GoogLeNet

  • El uso de núcleos de convolución de diferentes tamaños significa diferentes tamaños de campos receptivos y, finalmente, la fusión de características de diferentes escalas se logra a través del empalme;
  • La razón por la cual el tamaño del kernel de convolución es 1, 3 y 5 es principalmente por la conveniencia de la alineación. Después de configurar el paso de convolución stride = 1, simplemente configure pad = 0, 1, 2 respectivamente, luego las características de la misma dimensión se pueden obtener después de la convolución, y luego estas características se pueden empalmar directamente;
  • Cuanto más avanza la red, más abstractas son las características y mayor es el campo receptivo involucrado en cada característica, por lo que a medida que aumenta el número de capas, también aumenta la proporción de convoluciones de 3x3 y 5x5. Sin embargo, el uso de un núcleo de convolución de 5x5 todavía implica una gran cantidad de cómputo. Con este fin, el artículo utiliza un núcleo de convolución 1x1 para la reducción de la dimensionalidad.

4.4 Indicadores del modelo de GoogleLeNet

GoogLeNet ganó el campeonato en la competencia ImageNet 2014 y los indicadores específicos se  muestran en la Figura 3. La tasa de error alcanzó el 6,67 % en el conjunto de prueba.

  • referencias

[1]  Profundizando con las circunvoluciones.

5.DarkNet (YOLOv2, 3)

En la serie de algoritmos YOLO en el campo de la detección de objetivos, el autor configuró y entrenó la red DarkNet como red troncal para lograr mejores resultados de clasificación. Entre ellos, YOLOv2[1] propuso por primera vez la red DarkNet, que al tener 19 capas convolucionales también se denomina DarkNet19. Posteriormente, en YOLOv3[2], el autor continuó absorbiendo las ideas de los excelentes algoritmos actuales, como la red residual y la fusión de características, etc., y propuso una red troncal DarkNet53 con 53 capas convolucionales. El autor realizó experimentos en ImageNet y descubrió que, en comparación con ResNet-152 y ResNet-101, DarkNet53 ha logrado una velocidad computacional líder bajo la premisa de una precisión de clasificación similar.

5.1 Estructura del modelo DarkNet

5.1.1 DarkNet19

En DarkNet19, se toma prestada la experiencia de muchos algoritmos excelentes, tales como: tomar prestada la idea de VGG, usar más convoluciones de 3×33×3, duplicar el número de canales después de cada operación de agrupación; dibujar en la red en The La idea de la red utiliza el pooling promedio global (agrupación promedio global) para hacer predicciones, y coloca un kernel de convolución de 1×11×1 entre kernels de convolución de 3×33×3 para comprimir características; al mismo tiempo, use The La capa de normalización por lotes estabiliza el entrenamiento del modelo, acelera la convergencia y desempeña un papel en la regularización. La estructura de red de DarkNet19  se muestra en la Figura 1.

La precisión de DarkNet19 es comparable a la de la red VGG, pero la cantidad de operaciones de coma flotante es de solo 1551, por lo que la velocidad de operación es extremadamente rápida.

5.1.2 DarkNet53

Sobre la base anterior, DarkNet53 se basa en la idea de ResNet y utiliza una gran cantidad de conexiones residuales en la red, por lo que la estructura de la red se puede diseñar con mucha profundidad y se alivia el problema de la desaparición de gradientes en el entrenamiento, haciendo que el modelo más fácil de converger. Al mismo tiempo, se usa la capa convolucional con un paso de 2 en lugar de la capa de agrupación para lograr la reducción de muestreo. La estructura de red de DarkNet53  se muestra en la Figura 2.

Teniendo en cuenta que la red Darknet19 actualmente se usa con menos frecuencia, lo siguiente se centrará principalmente en la implementación y explicación de la red Darknet53.

5.2 Implementación del modelo DarkNet

Basado en el marco de Paddle, el código de implementación específico de DarkNet53 es el siguiente:

 
 

pitón

copiar codigo

import paddle from paddle import ParamAttr import paddle.nn as nn import paddle.nn.functional as F from paddle.nn import Conv2D, BatchNorm, Linear, Dropout from paddle.nn import AdaptiveAvgPool2D, MaxPool2D, AvgPool2D from paddle.nn.initializer import Uniform import math #将卷积和批归一化封装为ConvBNLayer,方便后续复用 class ConvBNLayer(nn.Layer): def __init__(self, input_channels, output_channels, filter_size, stride, padding, name=None): # 初始化函数 super(ConvBNLayer, self).__init__() # 创建卷积层 self._conv = Conv2D( in_channels=input_channels, out_channels=output_channels, kernel_size=filter_size, stride=stride, padding=padding, weight_attr=ParamAttr(name=name + ".conv.weights"), bias_attr=False) # 创建批归一化层 bn_name = name + ".bn" self._bn = BatchNorm( num_channels=output_channels, act="relu", param_attr=ParamAttr(name=bn_name + ".scale"), bias_attr=ParamAttr(name=bn_name + ".offset"), moving_mean_name=bn_name + ".mean", moving_variance_name=bn_name + ".var") def forward(self, inputs): # 前向计算 x = self._conv(inputs) x = self._bn(x) return x #定义残差块 class BasicBlock(nn.Layer): def __init__(self, input_channels, output_channels, name=None): # 初始化函数 super(BasicBlock, self).__init__() # 定义两个卷积层 self._conv1 = ConvBNLayer( input_channels, output_channels, 1, 1, 0, name=name + ".0") self._conv2 = ConvBNLayer( output_channels, output_channels * 2, 3, 1, 1, name=name + ".1") def forward(self, inputs): # 前向计算 x = self._conv1(inputs) x = self._conv2(x) # 将第二个卷积层的输出和最初的输入值相加 return paddle.add(x=inputs, y=x) class DarkNet53(nn.Layer): def __init__(self, class_dim=1000): # 初始化函数 super(DarkNet, self).__init__() # DarkNet 每组残差块的个数,来自DarkNet的网络结构图 self.stages = [1, 2, 8, 8, 4] # 第一层卷积 self._conv1 = ConvBNLayer(3, 32, 3, 1, 1, name="yolo_input") # 下采样,使用stride=2的卷积来实现 self._conv2 = ConvBNLayer( 32, 64, 3, 2, 1, name="yolo_input.downsample") # 添加各个层级的实现 self._basic_block_01 = BasicBlock(64, 32, name="stage.0.0") # 下采样,使用stride=2的卷积来实现 self._downsample_0 = ConvBNLayer( 64, 128, 3, 2, 1, name="stage.0.downsample") self._basic_block_11 = BasicBlock(128, 64, name="stage.1.0") self._basic_block_12 = BasicBlock(128, 64, name="stage.1.1") # 下采样,使用stride=2的卷积来实现 self._downsample_1 = ConvBNLayer( 128, 256, 3, 2, 1, name="stage.1.downsample") self._basic_block_21 = BasicBlock(256, 128, name="stage.2.0") self._basic_block_22 = BasicBlock(256, 128, name="stage.2.1") self._basic_block_23 = BasicBlock(256, 128, name="stage.2.2") self._basic_block_24 = BasicBlock(256, 128, name="stage.2.3") self._basic_block_25 = BasicBlock(256, 128, name="stage.2.4") self._basic_block_26 = BasicBlock(256, 128, name="stage.2.5") self._basic_block_27 = BasicBlock(256, 128, name="stage.2.6") self._basic_block_28 = BasicBlock(256, 128, name="stage.2.7") # 下采样,使用stride=2的卷积来实现 self._downsample_2 = ConvBNLayer( 256, 512, 3, 2, 1, name="stage.2.downsample") self._basic_block_31 = BasicBlock(512, 256, name="stage.3.0") self._basic_block_32 = BasicBlock(512, 256, name="stage.3.1") self._basic_block_33 = BasicBlock(512, 256, name="stage.3.2") self._basic_block_34 = BasicBlock(512, 256, name="stage.3.3") self._basic_block_35 = BasicBlock(512, 256, name="stage.3.4") self._basic_block_36 = BasicBlock(512, 256, name="stage.3.5") self._basic_block_37 = BasicBlock(512, 256, name="stage.3.6") self._basic_block_38 = BasicBlock(512, 256, name="stage.3.7") # 下采样,使用stride=2的卷积来实现 self._downsample_3 = ConvBNLayer( 512, 1024, 3, 2, 1, name="stage.3.downsample") self._basic_block_41 = BasicBlock(1024, 512, name="stage.4.0") self._basic_block_42 = BasicBlock(1024, 512, name="stage.4.1") self._basic_block_43 = BasicBlock(1024, 512, name="stage.4.2") self._basic_block_44 = BasicBlock(1024, 512, name="stage.4.3") # 自适应平均池化 self._pool = AdaptiveAvgPool2D(1) stdv = 1.0 / math.sqrt(1024.0) # 分类层 self._out = Linear( 1024, class_dim, weight_attr=ParamAttr( name="fc_weights", initializer=Uniform(-stdv, stdv)), bias_attr=ParamAttr(name="fc_offset")) def forward(self, inputs): x = self._conv1(inputs) x = self._conv2(x) x = self._basic_block_01(x) x = self._downsample_0(x) x = self._basic_block_11(x) x = self._basic_block_12(x) x = self._downsample_1(x) x = self._basic_block_21(x) x = self._basic_block_22(x) x = self._basic_block_23(x) x = self._basic_block_24(x) x = self._basic_block_25(x) x = self._basic_block_26(x) x = self._basic_block_27(x) x = self._basic_block_28(x) x = self._downsample_2(x) x = self._basic_block_31(x) x = self._basic_block_32(x) x = self._basic_block_33(x) x = self._basic_block_34(x) x = self._basic_block_35(x) x = self._basic_block_36(x) x = self._basic_block_37(x) x = self._basic_block_38(x) x = self._downsample_3(x) x = self._basic_block_41(x) x = self._basic_block_42(x) x = self._basic_block_43(x) x = self._basic_block_44(x) x = self._pool(x) x = paddle.squeeze(x, axis=[2, 3]) x = self._out(x) return x

5.3 Características del modelo DarkNet

  • El modelo DarkNet53 utiliza una gran cantidad de conexiones residuales, lo que alivia el problema de la desaparición del gradiente durante el entrenamiento y facilita la convergencia del modelo.
  • El modelo DarkNet53 utiliza una capa convolucional con un paso de 2 en lugar de una capa de agrupación para lograr la reducción de resolución.

5.4 Indicadores del modelo DarkNet

En el artículo de YOLOv3, el autor comparó la precisión y la velocidad de la red DarkNet y la red ResNet en el conjunto de datos de ImageNet, como se muestra en la Figura 3. Se puede ver que la precisión de los 5 primeros de DarkNet53 puede alcanzar el 93,8%, y la velocidad también supera significativamente a ResNet101 y ResNet152.

Para más artículos, preste atención a la cuenta oficial: Ting, inteligencia artificial

  • referencias

[1]  YOLO9000: Mejor, Más Rápido, Más Fuerte

[2]  YOLOv3: una mejora incremental

Supongo que te gusta

Origin blog.csdn.net/bruce__ray/article/details/131144482
Recomendado
Clasificación