Una breve introducción a la función guiada por flujo óptico (OFF)

Inicialmente, el código de este documento solo estaba disponible en la versión Caffe, y la versión pytorch se adjunta aquí.

JoeHEZHAO/Optical-Flow-Guided-Feature-Pytorch: Función guiada por flujo óptico para reconocimiento de acciones-Pytorch (github.com) icono-default.png?t=M85Bhttps://github.com/JoeHEZHAO/Optical-Flow-Guided-Feature-Pytorch es necesaria por algunos motivos Desmantelaré la parte OFF del código presentado en este documento, por lo que primero cubriré las partes relevantes del documento y luego explicaré más. El nivel es limitado y la expresión es inexacta. Por favor, perdóneme.

Portal de papel:

Función guiada por flujo óptico: una representación de movimiento rápida y sólida para el reconocimiento de acciones de video (thecvf.com) icono-default.png?t=M85Bhttps://openaccess.thecvf.com/content_cvpr_2018/papers/Sun_Optical_Flow_Guided_CVPR_2018_paper.pdf Para la CNN tradicional, al realizar la extracción de funciones en video es más Es difícil porque los videos son diferentes de las imágenes y las características espaciales + características temporales son más representativas de los videos. Este artículo se basa en la estructura de red de TSN. Sobre esta base, el autor diseñó una unidad OFF para extraer características de la dimensión temporal. Si está interesado en la estructura general de la red, puede consultar el artículo. Aquí solo presentaré la estructura y código de la unidad OFF.

Primero, echemos un vistazo a la posición de la Unidad APAGADA en la estructura general de la red:

Figura 1 Estructura de la red de papel

En la figura anterior, hay dos subredes para la extracción de características, que extraen características en diferentes períodos de tiempo. Una subred OFF compuesta por Unidades OFF extrae información de tiempo a través de las dos subredes anteriores y finalmente realiza la clasificación mediante la fusión de la puntuación de clase de cada una. subred. A continuación, observe más de cerca el diagrama de estructura de la Unidad OFF:

Figura 2 Estructura de la unidad OFF 

En el artículo, la combinación del operador Sobel y Resta se llama OFF y, junto con la convolución 1*1 anterior, forma la capa OFF. Las características se convolucionan dos veces a través de la Unidad OFF. Una rama usa el operador Sobel para extraer características espaciales, y la operación de resta por elementos (Restar) se usa para extraer información temporal. Combinada con la Figura 1, la información que sale de la Unidad OFF La unidad ingresa al siguiente módulo a través de ReseNet.

El código básico del módulo OFF se refleja en el código. No implementa OFF por separado como una clase. El documento contiene múltiples OFF. Algunos OFF tienen diferentes números de canal de entrada y tamaños al realizar la convolución. Aquí solo tome motion_3a como ejemplo. En cuanto a cómo unir otras estructuras de red, es necesario realizar más cálculos y diseños de las formas internas, de lo contrario ocurrirán problemas como dimensiones inconsistentes. Aquí, OFF se implementa como una Clase. El código relevante es el siguiente: Por favor corrija conmigo si hay algún error.

from __future__ import print_function, division, absolute_import
import torch
import torch.nn as nn
import torch.utils.model_zoo as model_zoo
import os
import sys
from torch.autograd import Variable
from util import SobelFilter, SobelFilter_Diagonal
from basic_ops import *
import pdb

class OFFNet(nn.Module):
    
    def __init__(self, batch, length, in_channels, h, w):
        super(OFFNet, self).__init__()
        self.batch = batch
        self.length = length

        self.motion_conv_gen = nn.Conv2d(in_channels[0], 128, kernel_size=(1, 1), stride=(1,1))
        self.motion_spatial_down = nn.Conv2d(in_channels[1], 32, kernel_size=(1,1), stride=(1,1))
        self.motion_spatial_grad = nn.Conv2d(in_channels[2], 32, kernel_size=(3,3), stride=(1,1), padding=(1,1), groups=32, bias=True)
        self.motion_relu_gen = nn.ReLU()
        self.dropout = nn.Dropout(p=0.8)


    def forward(self, x):
        # print(x.shape)
        # motion operating on [batch * length, c, h, w] level
        # motion_conv_gen = self.motion_conv_gen(x)
        motion_conv_gen = self.motion_conv_gen(x)
        motion_relu_gen = self.motion_relu_gen(motion_conv_gen)
        channel_size = motion_relu_gen.shape[1] # 
        reshape_rgb_frames = motion_relu_gen.view(self.batch, -1, self.h, self.w)
        # print(reshape_rgb_frames.shape)
        last_frames = reshape_rgb_frames[:, channel_size:, :, :]
        # print(last_frames.shape)
        first_frames = reshape_rgb_frames[:, :-channel_size, :, :]
        # print(first_frames.shape)
        eltwise_motion = last_frames - first_frames
        # print(eltwise_motion.shape)
        # convert back to [batch * (time - 1), c, h, w]
        temporal_grad = eltwise_motion.view(-1, channel_size, self.h, self.w) 
       
        spatial_frames = x[:self.batch * (self.length - 1), :, :, :]
        # downgrade dimension to 32
        spatial_down = self.motion_spatial_down(spatial_frames) 
        spatial_grad = self.motion_spatial_grad(spatial_down)
        spatial_grad = self.dropout(spatial_grad)
        # print(spatial_grad.shape)
        # concatenate temporal and spatial dimension
        # import pdb;pdb.set_trace()
        # print(spatial_grad.shape)
        # print(temporal_grad.shape)
        motion = torch.cat((spatial_grad, temporal_grad), dim=1)
        return motion



#in_channels[motion_3a:[256,256,32],
#            motion_3b:[320,320,32],
#            motion_3c:[576,576,32],
#            motion_4a:[576,576,32],
#            motion_4b:[576,576,32],
#            motion_4c:[608,608,32],
#            motion_4d:[608,608,32],
#            motion_5a:[1024,1024,32],
#            motion_5b:[1024,1024,32]
#            ]
          ]

Hay comentarios en el código, que se pueden leer correspondientes a la estructura de la capa OFF. Dado que el número de canales de entrada es inconsistente cuando OFF realiza la convolución en el papel, el número de canales de entrada se pasa aquí como un parámetro para facilitar agregando el módulo a otros módulos. El número de canales de salida en este documento es el mismo y no se realiza ningún procesamiento adicional. También se puede cambiar como parámetro. El número inferior es el número de canales de entrada para todas las operaciones de APAGADO en este documento. . En cuanto al operador de sobel, etc., si desea saber más, puede consultar la información relevante usted mismo.

Supongo que te gusta

Origin blog.csdn.net/Mr___WQ/article/details/127106835
Recomendado
Clasificación