Coincidencia estéreo: análisis de la estructura de la red GC-Net

  1. Primero mire el código correspondiente al diagrama de estructura de la red y la tabla de la capa de red.
    Inserte la descripción de la imagen aquí
    Inserte la descripción de la imagen aquí

1. Extracción de características de características unarias

1. Utilice convolución 2-D para extraer características profundas. Primero, use conv2d con un tamaño de ajuste: 5 * 5 y stride: 2 para reducir la dimensión de entrada (1 / 2H, 1 / 2W).

 imgl0=F.relu(self.bn0(self.conv0(imgLeft)))
 imgr0=F.relu(self.bn0(self.conv0(imgRight)))
self.conv0=nn.Conv2d(3,32,5,2,2)
self.bn0=nn.BatchNorm2d(32)

2. Seguido de una red residual de 8 capas.
Inserte la descripción de la imagen aquí

  • Tenga en cuenta que aquí num_block [0], donde el valor es 8 representa residuales de ocho niveles, y las variables se definen a continuación
 self.res_block=self._make_layer(block,self.in_planes,32,num_block[0],stride=1)
 def _make_layer(self,block,in_planes,planes,num_block,stride):
        strides=[stride]+[1]*(num_block-1)
        layers=[]
        for step in strides:
            layers.append(block(in_planes,planes,step))
        return nn.Sequential(*layers)
  • Tenga en cuenta que este parámetro 'num_block' es una matriz [8,1],
  • Este bucle for debe prestar atención, porque la estructura residual penetra num_block = 8, por lo que aquí strides = [[1], [1], [1], [1], [1], [1], [1] , [1]], step toma el valor cada vez, por lo que la zancada pasada al bloque es zancada = 1

def GcNet(height,width,maxdisp):
    return GC_NET(BasicBlock,ThreeDConv,[8,1],height,width,maxdisp)
  • El siguiente es un análisis detallado de los detalles del código de los residuales de 8 niveles
  • La estructura residual consta de dos capas de conv (entrada = 32, salida = 32, kernel_size = 3, stride = 1, padding = 1), un total de ocho capas. La función principal de esta capa residual es extraer las 'características únicas' de las imágenes izquierda y derecha.
class BasicBlock(nn.Module):  #basic block for Conv2d
    def __init__(self,in_planes,planes,stride=1):
        super(BasicBlock,self).__init__()
        self.conv1=nn.Conv2d(in_planes,planes,kernel_size=3,stride=stride,padding=1)
        self.bn1=nn.BatchNorm2d(planes)
        self.conv2=nn.Conv2d(planes,planes,kernel_size=3,stride=1,padding=1)
        self.bn2=nn.BatchNorm2d(planes)
        self.shortcut=nn.Sequential()
    def forward(self, x):
        out=F.relu(self.bn1(self.conv1(x)))
        out=self.bn2(self.conv2(out))
        out+=self.shortcut(x)
        out=F.relu(out)
        return out
  • Finalmente, se pasa una capa de convolución (sin RELU, sin BN). No entiendo el papel de esta capa. ¿Quizás sea para expandir el campo de percepción?
   self.conv1=nn.Conv2d(32,32,3,1,1)

2. Forme un volumen de costos

  • Las 'características unarias' formadas por la capa residual, a través del empalme de la columna (por qué w es el empalme de la columna, consulte el resultado de impresión de mi PSMNet ), formando un cuerpo de costo de tamaño (1,64,96,1 / 2H, 1 / 2W) . Calculé esto refiriéndome a la salida de PSMNet. No ejecuté el código. Para configurar el entorno, es principalmente para entender la idea.
 def cost_volume(self,imgl,imgr):
        B, C, H, W = imgl.size()
        cost_vol = torch.zeros(B, C * 2, self.maxdisp , H, W).type_as(imgl)
        for i in range(self.maxdisp):
            if i > 0:
                cost_vol[:, :C, i, :, i:] = imgl[:, :, :, i:]
                cost_vol[:, C:, i, :, i:] = imgr[:, :, :, :-i]
            else:
                cost_vol[:, :C, i, :, :] = imgl
                cost_vol[:, C:, i, :, :] = imgr
        return cost_vol
 cost_volum = self.cost_volume(imgl1, imgr1)
  • A través de este método de empalme, las dimensiones de la característica y se conservan unary features, de modo que la red pueda aprender absolute representationy combinarse con el contexto. Este método de empalme es mejor que la función de medición de distancia (L1, L2, coseno)
  • La siguiente explicación del
    volumen de costos es muy vívida: (Para una determinada característica, el volumen de costo coincidente es un cuadrado tridimensional, la primera capa es el mapa de características cuando la disparidad es 0 y la segunda capa es el mapa de características cuando la disparidad es 1. Por analogía, hay un total de paralaje máximo + 1 capa, la longitud y el ancho son respectivamente el tamaño del mapa de características, asumiendo que se extraen un total de 10 características, hay 10 de estos cuadrados tridimensionales)
    Inserte la descripción de la imagen aquí

3. Submuestreo convolucional 3D (codificador)

1.El tamaño de la característica de 'volumen de costo' combinado = 64, el tamaño de la característica se reduce a 32 a través de dos capas de conv3d.

        self.conv3d_1 = nn.Conv3d(64, 32, 3, 1, 1)
        self.bn3d_1 = nn.BatchNorm3d(32)
        self.conv3d_2 = nn.Conv3d(32, 32, 3, 1, 1)
        self.bn3d_2 = nn.BatchNorm3d(32)

2. La primera capa submuestreada hace 1/2 en 1/4.

self.block_3d_1 = self._make_layer(block_3d, 64, 64, num_block[1], stride=2)
  • En este momento num_block [1] = 1. Ejecute el módulo de convolución 3D, donde stride = 2 se usa para reducir la resolución.
class ThreeDConv(nn.Module):
    def __init__(self,in_planes,planes,stride=1):
        super(ThreeDConv, self).__init__()
        self.conv1 = nn.Conv3d(in_planes, planes, kernel_size=3, stride=stride, padding=1)
        self.bn1 = nn.BatchNorm3d(planes)
        self.conv2 = nn.Conv3d(planes, planes, kernel_size=3, stride=1, padding=1)
        self.bn2 = nn.BatchNorm3d(planes)
        self.conv3=nn.Conv3d(planes,planes,kernel_size=3,stride=1,padding=1)
        self.bn3=nn.BatchNorm3d(planes)

    def forward(self, x):
        out=F.relu(self.bn1(self.conv1(x)))
        out=F.relu(self.bn2(self.conv2(out)))
        out=F.relu(self.bn3(self.conv3(out)))
        return out

Inserte la descripción de la imagen aquí

  • La descripción en el texto original es que la capa de reducción de resolución va seguida de dos capas de conv3d () con agitación = 2. Al comunicarse con el autor del código, kernel_size = 1 de la segunda capa solo jugó un papel en el cambio de canal.
 self.conv3d_3 = nn.Conv3d(64, 64, 3, 2, 1)
        self.bn3d_3 = nn.BatchNorm3d(64)

3. La segunda y la tercera capa de reducción de resolución son similares, así que hablemos de la cuarta capa de reducción de resolución.

  • Tenga en cuenta que el canal de salida de esta capa se convierte en 128.
  self.block_3d_4 = self._make_layer(block_3d, 64, 128, num_block[1], stride=2)

Four. Upsampling (decodificador)

1. La descripción del texto original es que si bien la reducción de resolución aumenta la velocidad y aumenta el campo receptivo, también pierde detalles. El autor usa la capa residual para conectar en cascada el mapa de características de alta resolución con la capa de muestreo descendente. La imagen de alta resolución se obtiene usando la convolución transpuesta nn.ConvTranspose3d (), echemos un vistazo a cómo se forma la estructura residual.

  • Convolución transpuesta: observe que el tamaño de la característica se cambia a 2F = 64
      # deconv3d
        self.deconv1 = nn.ConvTranspose3d(128, 64, 3, 2, 1, 1)
        self.debn1 = nn.BatchNorm3d(64)

Inserte la descripción de la imagen aquí

  • La muestra ascendente del resultado de la reducción de resolución directamente perderá muchas características y se conectará en cascada con la salida de la capa de reducción de resolución de alta resolución para compensar los detalles faltantes. Hay cuatro niveles de muestreo superior y cuatro estructuras residuales que no se describen una a una.
  deconv3d = F.relu(self.debn1(self.deconv1(conv3d_block_4)) + conv3d_block_3)
  • La última capa se muestra hacia arriba y genera
    Inserte la descripción de la imagen aquí
    2. Finalmente, agregue una capa de convolución transpuesta con un canal de salida de '1', comprima el 'volumen de costo' en una capa de mapa de disparidad inicial, restaure el tamaño (1 D H W), observe el primero La salida de conv2d de una capa de 5 5 es (1 / 2H, 1 / 2W), aquí restaure el tamaño de la imagen original
 original_size = [1, self.maxdisp*2, imgLeft.size(2), imgLeft.size(3)]
  • Aquí está la sintaxis de view ()
  self.deconv5 = nn.ConvTranspose3d(32, 1, 3, 2, 1, 1)
  out = deconv3d.view( original_size)

V. Regresión de paralaje

  1. Para este volumen de costo coincidente, podemos estimar el valor de disparidad usando la operación soft argmin en la dimensión de disparidad. La función tiene dos características:
  • Diferenciable, puede usar el optimizador para el cálculo del gradiente
  • Se puede devolver, la pérdida se puede pasar
 prob = F.softmax(-out, 1)
  • Regresión de paralaje
 disp1 = self.regression(prob)

Inserte la descripción de la imagen aquí

Six. Optimizador y pérdida

    criterion = SmoothL1Loss().to(device)
    optimizer = optim.Adam(model.parameters(), lr=0.001)

Supongo que te gusta

Origin blog.csdn.net/weixin_41405284/article/details/109381542
Recomendado
Clasificación