Mejoras de YOLOv5, YOLOv8: Transformador BoTNet

 

Tabla de contenido

1. Introducción

2.Mejoras de YOLOv5

2.1 Agregue el siguiente archivo yolov5s_botnet.yaml

2.2 configuración común.py

2.3 modificación de la configuración de yolo.py


1. Introducción

dirección en papel

 Papel

 La BoTNet propuesta en este artículo es una red simple y eficiente que aplica SA de manera efectiva a una variedad de tareas visuales, como reconocimiento de imágenes, detección de objetivos y tareas de segmentación de instancias. Al reemplazar la convolución espacial de los últimos tres módulos de cuello de botella en ResNet50 con operaciones SA globales, se mejora efectivamente el rendimiento del modelo de referencia en la tarea de firma.


La mayoría de las CNN utilizadas comúnmente en la Sección I utilizan núcleos de convolución de 3 x 3. En vista del hecho de que las operaciones de convolución pueden evitar de manera efectiva la información local borrosa, es necesario establecer dependencias de largo alcance para algunas tareas visuales como la detección de objetivos, la segmentación de instancias y Detección de puntos clave . Por ejemplo, en la segmentación de instancias, se debe recopilar información relacionada con la escena para conocer la relación entre los objetos; luego, para agregar información local, se deben apilar múltiples capas convolucionales. Pero puede ser más eficiente basándose en operaciones no locales y no requiere apilar tantas capas. Modelar dependencias de largo alcance también es muy importante para las tareas de PNL. La autoatención puede aprender eficazmente la asociación entre cada par de entidades. Los transformadores basados ​​​​en SA se han convertido en la corriente principal de PNL, como GPT y BERT.


Una forma conveniente de aplicar SA a la visión es reemplazar las capas convolucionales con capas MHSA a tiempo, consulte la Figura 1. Según esta idea, hay dos direcciones de mejora: una es reemplazar la capa convolucional en Resnet con varias operaciones SA, como SASA, AACN y SANet, la otra es dividir la imagen en parches complementarios y superpuestos y luego enviar al módulo transformador apilado.

Aunque parezcan dos tipos de arquitectura diferentes, no es así. Este artículo propone que la capa MHSA utilizada en el módulo ResNet puede considerarse como un módulo Transformer con una estructura de cuello de botella, pero existen cambios sutiles, como la selección de conexiones residuales y capas de normalización. Por lo tanto, este artículo llama módulo BoT al módulo ResNet con la capa MHSA. La estructura específica se muestra en la Fig. 3.
Aplicar atención al campo visual tiene los siguientes desafíos:
(1) Las imágenes son generalmente más grandes que las imágenes utilizadas para la clasificación, y la clasificación es generalmente (224,224) es suficiente, la resolución de imagen utilizada para la detección de objetos y la segmentación de instancias es mayor.

(2) El cálculo de SA es el término cuadrado de la resolución de entrada, por lo que requiere memoria y potencia informática. Para

superar los desafíos anteriores, este artículo realiza los siguientes diseños:

(1) Utilice la convolución para aprender de manera eficiente baja resolución , características abstractas

(2) Este diseño híbrido que utiliza SA para procesar y agregar características extraídas por convolución

puede aprovechar de manera efectiva las ventajas de la convolución y SA, mientras que la reducción de resolución mediante convolución puede procesar de manera efectiva imágenes de entrada de mayor resolución.

Por lo tanto, este artículo propone un plan de diseño simple: reemplazar los últimos tres bloques de ResNet con módulos BoT, sin realizar ningún cambio en el resto. Para que quede más claro, solo las últimas tres convoluciones 3x3 de ResNet se reemplazan con capas MHSA.


Simplemente hacer este pequeño cambio mejoró la precisión de detección de objetivos en COCO en un 1,2%; y no hay nada novedoso en la estructura de BoTNet, por lo que este artículo cree que esta simplicidad lo convierte en una columna vertebral digna de investigación adicional. Al utilizar BoTNet, por ejemplo, la segmentación, el efecto también se ha mejorado significativamente, especialmente para objetos pequeños.



Finalmente, este artículo también escala BoTNet y descubre que BoTNet no tiene una mejora sustancial en conjuntos de datos más pequeños, pero alcanza un 84,7% de precisión superior en ImageNet; en la prueba de hardware TPU-V3, es mejor que el actualmente popular EfficientNet Block 1.64. veces. Según los resultados mostrados por BoTNet, este artículo espera que SA pueda usarse ampliamente en tareas visuales en el futuro.

 

Sección II Trabajo relacionado
La figura 2 resume la atención en las tareas de visión por computadora. Esta sección se centra principalmente en:

(1) Transformer vs BoTNet


(2) DETR vs BoTNet

 
(3) Bon-Local vs BoTNet

En la Fig. 3, el lado izquierdo es el Transformador, el medio es el módulo BoT definido en este artículo y el lado derecho es el resultado de reemplazar la capa convolucional con MHSA en el Bloque ResNet. Conexión al Transformador. Como se menciona


en


la Título, la clave de este artículo es convertir el bloque en ResNet Reemplazado con la capa MHSA, pero el diseño arquitectónico de BoT no es la contribución de este artículo. Este artículo solo señala la relación entre MHSA ResNet Bottleneck y Transformer, que puede mejorar la comprensión y el diseño de SA en visión por computadora.



Además de las diferencias que se ven en la Fig. 3, existen algunas diferencias en las conexiones residuales, como:




(1) El transformador normalizado usa LN y ResNet usa BN

(2) Transformemr no lineal introduce no linealidad en la capa FFN, ResNet usa 3 transformaciones no lineales en BoT

(3) El mapeo de salida MHSA en Transformer contiene una proyección de salida pero no en BoT

(4) SGD Optimizer se usa a menudo para tareas visuales generales y Adam Optimizer se usa generalmente para Transformer

Connection a DETR


DETR Es un marco de detección de objetivos basado en Transformer. Tanto DETR como BoTNet intentan utilizar SA para mejorar el rendimiento de la detección de objetivos y la segmentación de instancias. La diferencia es que DETR utiliza módulos SA fuera de la columna vertebral. El objetivo principal es evitar el uso de RP y supresión de valores grandes no polares; El


propósito El objetivo de BoTNet es proponer un marco troncal para realizar directamente la detección de objetivos y la segmentación de instancias. Los resultados experimentales muestran que BoTNet tiene una mejora significativa en la detección de objetos pequeños y se cree que el problema de la mala detección de objetos pequeños de DETR se puede resolver en el futuro.



Conexión a redes neuronales no locales




Non-Local Nets combina principalmente Transformer con algoritmos no locales. Por ejemplo, los módulos no locales se introducen en las últimas 1 o 2 etapas de ResNet para mejorar el efecto de la segmentación de instancias y la clasificación de video. BoT es un diseño híbrido que utiliza convolución. núcleo SA.




La figura 4 muestra la diferencia entre la capa no local y la capa SA:





(1) MHSA contiene múltiples cabezales para mapear Q, K, V





(2) El bloque NL generalmente contiene un factor de escala de canal para escalar el canal, y el factor es generalmente se establece en 2, mientras que MHSA se establece en 4





(3) El bloque NL se inserta en el bloque ResNet como un módulo adicional, pero BoTNet es un reemplazo directo

Método de la Sección III
El diseño de BoTNet es muy simple: las últimas tres convoluciones 3x3 de ResNet se reemplazan por MHSA, logrando así el cálculo global del mapa de características. Por lo general, ResNet contiene 4 etapas [c2, c3, c4, c5], en cada etapa se apilan diferentes bloques y se utilizan conexiones residuales.




 
El objetivo de este artículo es utilizar SA para la segmentación de instancias de alta resolución. Por lo tanto, el método más simple es prestar atención al mapa de características de baja resolución de la red troncal, es decir, la etapa c5. C5 generalmente contiene 3 residuos, entonces Reemplace estos tres bloques residuales con módulos MHSA para formar BoTNet.

La Tabla 1 muestra la estructura de la red de BoTNet y la Figura 4 muestra la estructura de MHSA. En este artículo, las operaciones que implican convolución de zancada se reemplazan por operaciones de agrupación.




 
Codificaciones de posición relativa




 
Investigaciones recientes muestran que la codificación de posición relativa es más efectiva porque tiene en cuenta la distancia relativa entre diferentes características de posición, por lo que tiene en cuenta de manera efectiva la distancia relativa entre diferentes contenidos. Por lo tanto, BoTNet utiliza codificación de posición relativa 2D.

2.Mejoras de YOLOv5

2.1 Agregue el siguiente archivo yolov5s_botnet.yaml

# parameters
nc: 80  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple

anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

# YOLOv5 backbone
backbone:
  # [from, number, module, args]               # [c=channels,module,kernlsize,strides]
  [[-1, 1, Conv, [64, 6, 2, 2]],   # 0-P1/2           [c=3,64*0.5=32,3]
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4    
   [-1, 3, C3, [128]],                                
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8            
   [-1, 6, C3, [256]],                         
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16       
   [-1, 9, C3, [512]],                     
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 1, SPPF, [1024,5]],
   [-1, 3, BoT3, [1024]],  # 9
  ]

# YOLOv5 head
head:
  [[-1, 1, Conv, [512, 1, 1]], 
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 5], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [512, False]],  # 13

   [-1, 1, Conv, [256, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 3], 1, Concat, [1]],  # cat backbone P3
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)
  
   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 14], 1, Concat, [1]],  # cat head P4
   [-1, 3, C3, [512, False]],  # 20 (P4/16-medium)       [256, 256, 1, False]  
 
   [-1, 1, Conv, [512, 3, 2]],                           #[256, 256, 3, 2] 
   [[-1, 10], 1, Concat, [1]],  # cat head P5
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)       [512, 512, 1, False]
  
   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

2.2 configuración común.py

class MHSA(nn.Module):
    def __init__(self, n_dims, width=14, height=14, heads=4,pos_emb=False):
        super(MHSA, self).__init__()

        self.heads = heads
        self.query = nn.Conv2d(n_dims, n_dims, kernel_size=1)
        self.key = nn.Conv2d(n_dims, n_dims, kernel_size=1)
        self.value = nn.Conv2d(n_dims, n_dims, kernel_size=1)
        self.pos=pos_emb
        if self.pos :
            self.rel_h_weight = nn.Parameter(torch.randn([1, heads, (n_dims ) // heads, 1, int(height)]), requires_grad=True)
            self.rel_w_weight = nn.Parameter(torch.randn([1, heads, (n_dims )// heads, int(width), 1]), requires_grad=True)
        self.softmax = nn.Softmax(dim=-1)
     
    def forward(self, x):
        n_batch, C, width, height = x.size() 
        q = self.query(x).view(n_batch, self.heads, C // self.heads, -1)
        k = self.key(x).view(n_batch, self.heads, C // self.heads, -1)
        v = self.value(x).view(n_batch, self.heads, C // self.heads, -1)
        #print('q shape:{},k shape:{},v shape:{}'.format(q.shape,k.shape,v.shape))  #1,4,64,256
        content_content = torch.matmul(q.permute(0,1,3,2), k) #1,C,h*w,h*w
        # print("qkT=",content_content.shape)
        c1,c2,c3,c4=content_content.size()
        if self.pos:
       # print("old content_content shape",content_content.shape) #1,4,256,256
            content_position = (self.rel_h_weight + self.rel_w_weight).view(1, self.heads, C // self.heads, -1).permute(0,1,3,2)   #1,4,1024,64
           
            content_position = torch.matmul(content_position, q)# ([1, 4, 1024, 256])
            content_position=content_position if(content_content.shape==content_position.shape)else content_position[:,: , :c3,]
            assert(content_content.shape==content_position.shape)
        #print('new pos222-> shape:',content_position.shape)
       # print('new content222-> shape:',content_content.shape)
            energy = content_content + content_position
        else:
            energy=content_content
        attention = self.softmax(energy)
        out = torch.matmul(v, attention.permute(0,1,3,2)) #1,4,256,64
        out = out.view(n_batch, C, width, height)
        return out
class BottleneckTransformer(nn.Module):
    # Transformer bottleneck
    #expansion = 1

    def __init__(self, c1, c2, stride=1, heads=4, mhsa=True, resolution=None,expansion=1):
        super(BottleneckTransformer, self).__init__()
        c_=int(c2*expansion)
        self.cv1 = Conv(c1, c_, 1,1)
        #self.bn1 = nn.BatchNorm2d(c2)
        if not mhsa:
            self.cv2 = Conv(c_,c2, 3, 1)
        else:
            self.cv2 = nn.ModuleList()
            self.cv2.append(MHSA(c2, width=int(resolution[0]), height=int(resolution[1]), heads=heads))
            if stride == 2:
                self.cv2.append(nn.AvgPool2d(2, 2))
            self.cv2 = nn.Sequential(*self.cv2)
        self.shortcut = c1==c2 
        if stride != 1 or c1 != expansion*c2:
            self.shortcut = nn.Sequential(
                nn.Conv2d(c1, expansion*c2, kernel_size=1, stride=stride),
                nn.BatchNorm2d(expansion*c2)
            )
        self.fc1 = nn.Linear(c2, c2)     

    def forward(self, x):
        out=x + self.cv2(self.cv1(x)) if self.shortcut else self.cv2(self.cv1(x))
        return out
        
class BoT3(nn.Module):
    # CSP Bottleneck with 3 convolutions
    def __init__(self, c1, c2, n=1,e=0.5,e2=1,w=20,h=20):  # ch_in, ch_out, number, , expansion,w,h
        super(BoT3, self).__init__()
        c_ = int(c2*e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c1, c_, 1, 1)
        self.cv3 = Conv(2 * c_, c2, 1)  # act=FReLU(c2)
        self.m = nn.Sequential(*[BottleneckTransformer(c_ ,c_, stride=1, heads=4,mhsa=True,resolution=(w,h),expansion=e2) for _ in range(n)])
        # self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])

    def forward(self, x):
        return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1)) 

2.3 modificación de la configuración de yolo.py

Luego busque la función parse_model en el archivo ./models/yolo.py y agregue el nombre del módulo agregado BoT3a
la carpeta models/yolo.py.

 

Supongo que te gusta

Origin blog.csdn.net/weixin_45303602/article/details/132570474
Recomendado
Clasificación