Modelo Yolov3 - implementación de pytorch

Paper Portal: YOLOv3: una mejora incremental

Mejoras de Yolov3:

1. Usar Darknet53 como la columna vertebral
2. Predicción de características multiescala (similar a la estructura FPN)
3. Otros trucos .

La estructura de Yolov3:

La columna vertebral es la parte de extracción de características de Darknet53, donde Convolucional significa Conv+BN+LeakyReLU, y Residual significa conexión residual; la
imagen de entrada se extrae a través de la columna vertebral para extraer tres capas de capas de características , que se marcan respectivamente como característica0, característica1 y feature2 de la capa poco profunda a la capa profunda;
primero pase la función 2 a través de las capas convolucionales, emita la salida 2 a través de Convolucional + Conv en un lado, Convolucional y Upsampling en el otro lado, y luego conéctese a la función 1; las
funciones Concat generan la salida 1 a través de Convolucional + Conv en por un lado, Convolucional y Upsampling en el otro lado, y luego característica0 Conectado;
finalmente, las características de salida Concat a través de Convolucional+Conv;
entre ellas, la estructura de Capas Convolucionales es una pila Convolucional de 5 capas, y su tamaño de núcleo de convolución es [ 1 , 3 , 1 , 3 , 1 ] [1,3,1, 3,1][ 1 ,3 ,1 ,3 ,1 ] ;
Excepto por el primer Convolucional después de Concat y el primer Convolucional de entrada de imagen, entre otros Convolucionales, si el tamaño del núcleo de convolución es 3, el número de canales se duplicará; si el tamaño del núcleo de convolución es 1, el número de canales se reducirá a la mitad.
Estructura Yolov3

Salida de Yolov3:

La salida de la red es de tres capas.En la tarea de detección de objetivos COCO, cuando el tamaño de la imagen de entrada es (3.416.416), el resultado de salida es:
Out 0 (255,52,52), que se utiliza para predecir objetivos de tamaño pequeño
; 1 (255, 26,26), para predecir objetos de tamaño mediano
, Out 1 (255,13,13), para predecir objetos de gran tamaño .
Similar a Yolov2, donde 52x52, 26x26 y 13x13 representan las posiciones de anclaje predeterminadas; 255 = ( 4 + 1 + 80 ) ∗ 3 255=(4+1+80)*3255=( 4+1+80 )3 , 4 representa los parámetros de regresión objetivo, 1 representa la confianza objetivo, 80 representa la probabilidad condicional de 80 categorías y los últimos 3 representan el tamaño del ancla, es decir, hay 3 tamaños de anclas en cada posición (para cada capa de salida).
(El código solo implementa la parte de la estructura del modelo)

El intento de Yolov3:

En cuanto a la forma de predicción y la función de pérdida, el autor ha probado algunas estrategias que no han funcionado, entre las que destaca Focal Loss . El autor usa Focal Loss como la forma básica de la función de pérdida, lo que da como resultado una reducción de mAP en dos puntos, y el autor no está completamente seguro de por qué no funciona.
Pérdida focal

import torch
import torch.nn as nn


def convolutional(in_channels, out_channels, kernel_size, strid):  # Conv+BN+LeakyReLU
    padding = 1 if kernel_size == 3 else 0
    return nn.Sequential(
        nn.Conv2d(in_channels, out_channels, kernel_size, strid, padding, bias=False),
        nn.BatchNorm2d(out_channels),
        nn.LeakyReLU(0.1)
    )


class Residual(nn.Module):  # Residual结构
    def __init__(self, in_channels, hidden_channels):
        super(Residual, self).__init__()
        self.residual_block = nn.Sequential(
            convolutional(in_channels, hidden_channels, 1, 1),
            convolutional(hidden_channels, in_channels, 3, 1)
        )

    def forward(self, x):
        return x + self.residual_block(x)  # x+F(x)


class Darknet53(nn.Module):  # Darknet53的特征提取部分
    def __init__(self):
        super(Darknet53, self).__init__()
        self.feature0 = nn.Sequential(
            convolutional(3, 32, 3, 1),
            convolutional(32, 64, 3, 2),
            Residual(64, 32),
            convolutional(64, 128, 3, 2),
            *[Residual(128, 64) for i in range(2)],
            convolutional(128, 256, 3, 2),
            *[Residual(256, 128) for i in range(8)],
        )
        self.feature1 = nn.Sequential(
            convolutional(256, 512, 3, 2),
            *[Residual(512, 256) for i in range(8)],
        )
        self.feature2 = nn.Sequential(
            convolutional(512, 1024, 3, 2),
            *[Residual(1024, 512) for i in range(4)],
        )

    def forward(self, x):
        feature0 = self.feature0(x)  # 浅层特征
        feature1 = self.feature1(feature0)  # 中层特征
        feature2 = self.feature2(feature1)  # 深层特征
        return feature0, feature1, feature2


class Convlayers(nn.Module):  # 5个Convolutional的堆叠
    def __init__(self, in_channels, hidden_channels):
        super(Convlayers, self).__init__()
        self.convlayers = nn.Sequential(
            convolutional(in_channels, hidden_channels, 1, 1),
            convolutional(hidden_channels, hidden_channels * 2, 3, 1),
            convolutional(hidden_channels * 2, hidden_channels, 1, 1),
            convolutional(hidden_channels, hidden_channels * 2, 3, 1),
            convolutional(hidden_channels * 2, hidden_channels, 1, 1),
        )

    def forward(self, x):
        return self.convlayers(x)


class Yolov3(nn.Module):  # yolov3模型
    def __init__(self):
        super(Yolov3, self).__init__()
        self.backbone = Darknet53()
        self.convlayers2 = Convlayers(1024, 512)
        self.convlayers1 = Convlayers(512 + 256, 256)
        self.convlayers0 = Convlayers(256 + 128, 128)
        self.final_conv2 = nn.Sequential(
            convolutional(512, 1024, 3, 1),
            nn.Conv2d(1024, 255, 1, 1, 0),
        )
        self.final_conv1 = nn.Sequential(
            convolutional(256, 512, 3, 1),
            nn.Conv2d(512, 255, 1, 1, 0),
        )
        self.final_conv0 = nn.Sequential(
            convolutional(128, 256, 3, 1),
            nn.Conv2d(256, 255, 1, 1, 0),
        )
        self.upsample2 = nn.Sequential(
            convolutional(512, 256, 1, 1),
            nn.Upsample(scale_factor=2)
        )
        self.upsample1 = nn.Sequential(
            convolutional(256, 128, 1, 1),
            nn.Upsample(scale_factor=2)
        )

    def forward(self, x):
        # (B,256,52,52),(B,512,26,26),(B,1024,13,13)
        feature0, feature1, feature2 = self.backbone(x)  # 输入图像经过backbone提取到3层特征
        f2 = self.convlayers2(feature2)  # 深层特征经过Conolutional layers得到f2,(B,1024,13,13)-->(B,512,13,13)
        out2 = self.final_conv2(f2)  # f2经过Convolutional+Conv获得out2,(B,512,13,13)-->(B,255,13,13)

        f1 = self.convlayers1(  # f2经过Convolutional+Upsampling与中层特征拼接,再经过Conolutional layers得到f1
            torch.cat([self.upsample2(f2), feature1], dim=1))  # (B,256,26,26)cat(B,512,26,26)-->(B,256,26,26)
        out1 = self.final_conv1(f1)  # f1经过Convolutional+Conv获得out1,(B,256,26,26)-->(B,255,26,26)

        f0 = self.convlayers0(  # f1经过Convolutional+Upsampling与浅层特征拼接,再经过Conolutional layers得到f0
            torch.cat([self.upsample1(f1), feature0], dim=1))  # (B,128,52,52)cat(B,256,52,52)-->(B,128,52,52)
        out0 = self.final_conv0(f0)  # f0经过Convolutional+Conv获得out0,(B,128,52,52)-->(B,255,52,52)
        return out0, out1, out2

Supongo que te gusta

Origin blog.csdn.net/Peach_____/article/details/128762798
Recomendado
Clasificación