[BEV] BEVFormer de notas de estudio (1)

1. Introducción

Realizar tareas visuales en el espacio BEV se ha convertido gradualmente en la tecnología principal en la conducción autónoma. Para comprender cómo realizar tareas visuales en el espacio BEV, planeo utilizar el proyecto BEVFormer para comprender sus pasos. Este artículo es el funcionamiento de BEVFormer y la combinación del marco general (ver el código fuente) es un poco desordenado), y si eres más hábil leyendo el código fuente más adelante, prepara un comentario más detallado.
Código fuente de BEVFormer: https://github.com/fundamentalvision/BEVFormer
Artículos de aprendizaje de BEVFormer: https://zhuanlan.zhihu.com/p/543335939

Video de aprendizaje de BEVFormer: https://www.bilibili.com/video/BV1rK411o7PS/?spm_id_from=333.788&vd_source=2055b62125c0277a0d6878f41c89fec2
Los amigos que están aprendiendo o quieren aprender el modelo BEV son bienvenidos a unirse al grupo de intercambio para discutir, estudiar documentos o problemas en implementación de código, puede agregar grupo v: Rex1586662742, grupo q: 468713665

2. Corre

La única forma de aprender un proyecto es ejecutar el proyecto primero. Se recomienda seguir el entorno de instalación oficial para evitar problemas. Después de instalar el entorno, ejecútelo de acuerdo con el comando oficial. Entonces, ¿cómo depurar para ver línea por línea? Uso pycharm para la depuración, que se puede dividir en los siguientes dos pasos

  • Enlace launch.py
    ​​​​primero busque el archivo launch.py ​​en el entorno actual de conda (bev) y enlace a este proyecto
sudo ln -s /home/***/miniconda3/envs/bev/lib/python3.8/site-packages/torch/distributed/launch.py ./
  • Edite la configuración
    , haga clic en Ejecutar, seleccione el archivo de configuración, complete la ruta absoluta de launch.py ​​​​en la ruta del script y complete los siguientes parámetros en los parámetros formales, que deben modificarse a la ruta del local máquina. En términos generales, puede depurar. Si se informa un error, no se puede encontrar. Para ver las imágenes en el conjunto de datos, consulte el tercer artículo a continuación.
--nproc_per_node=1
--master_port=29503
/data/rex/BEV/BEVFormer-master/tools/test.py
/data/rex/BEV/BEVFormer-master/projects/configs/bevformer/bevformer_tiny.py
/data/rex/BEV/bevformer_tiny_epoch_24.pth
--launcher
pytorch
--eval
bbox
  • Cuando el conjunto de datos vinculado
    se está ejecutando, se puede informar un error que indica que no se puede encontrar el conjunto de datos, que se puede agregar en tools/test.py
print(os.getcwd())
sys.path.append(os.getcwd())

Luego vincule la ruta del conjunto de datos en el proyecto a la ruta de os.getcwd(), y no se informará ningún error durante el tiempo de ejecución.

3. Estructura de la red

De acuerdo con la convención, en primer lugar, es necesario poner un diagrama esquemático en el papel para ilustrar. En la figura a continuación, se divide principalmente en tres partes, la columna vertebral en el extremo izquierdo, el codificador × 6 en el medio , y los cabezales Det/Seg en el medio.

La primera parte es ResNet + FPN.La principal innovación de BEVFormer es el codificador de la segunda parte, a saber, Autoatención Temporal y Atención Cruzada Espacial.
inserte la descripción de la imagen aquí

4. Archivo de configuración del modelo

Este artículo utiliza el modelo diminuto para las pruebas. Las principales diferencias entre varios modelos radican en el tamaño de bev_query y la cantidad de funciones de escala múltiple de FPN. El archivo de configuración es projects/configs/bevformer/bevformer_tiny.py, y la estructura de la red del modelo se implementa aquí Definición, cuando se ejecuta, los siguientes módulos se registrarán primero, de arriba a abajo es básicamente el paso de avance.

model = dick(
    type='BEVFormer',
    ...,
    # 主干网络
     img_backbone = dict(
         type='ResNet',
         ...
     )
    # 提取不同尺度的特征
     img_neck=dict(
         type='FPN',
         ...
     )
    # 编解码
     pts_bbox_head = dict(
         type='BEVFormerHead',
         ...
         transformer=dict(
             type='PerceptionTransformer',
             ...
            # 编码网络
             encoder=dict(
                 type='BEVFormerEncoder',
                 ...
                # 单个block 推理时将会重复6次
                 transformerlayers=dict(
                     type='BEVFormerLayer',
                     attn_cfgs=[
                         dict(
                             type='TemporalSelfAttention'
                             ...
                         ),
                         dict(
                             type='SpatialCrossAttention',
                             deformable_attention=dict(
                                 type='MSDeformableAttention3D'
                                 ...
                             )
                         )
                ]
            )
        )
        # 解码网络
        decoder=dict(
         type='DetectionTransformerDecoder',
         ...
         # decode block
         transformerlayers=dict(
            type='DetrTransformerDecoderLayer',
            attn_cfgs=[
               dict(
                    type='MultiheadAttention',
               ),
               dict(
                    type='CustomMSDeformableAttention',
                    ...
               )
            ]
         )
        )
    )
    bbox_coder = dict(
        type='NMSFreeCoder'
        ...
    )
    # 可学习的位置编码
    positional_encoding = dict(
        type='LearnedPositionalEncoding',
        ...
    )
)

5. proceso de reenvío

Después de poder depurar, puede verificar la forma de la variable línea por línea. Dado que el proyecto involucra muchos módulos y se implementa con openmmlab, será un poco confuso cuando se ponga en contacto por primera vez. Entonces, a través de la depuración múltiple, grabé el razonamiento El proceso general puede llevarse a cabo básicamente en secuencia de acuerdo con los números siguientes.

1, herramientas/prueba.py

outputs = custom_multi_gpu_test(model, data_loader, args.tmpdir,args.gpu_collect)
# 进入到projects/mmdet3d_plugin/bevformer/apis/test.py

2, proyectos/mmdet3d_plugin/bevformer/apis/test.py

def custom_multi_gpu_test(...):
    ...
    for i, data in enumerate(data_loader):
    with torch.no_grad():
        result = model(return_loss=False, rescale=True, **data)
        # 进入到 projects/mmdet3d_plugin/bevformer/detectors/bevformer.py
        ...

3, proyectos/mmdet3d_plugin/bevformer/detectores/bevformer.py

class BEVFormer(...):
    def forward(...):
        if return_loss:
            return self.forward_train(**kwargs)
        else:
            return self.forward_test(**kwargs)
            # 进入到下面 self.forward_test 

    def forward_test(...):
        ...
        # forward
        new_prev_bev, bbox_results = self.simple_test(...)
        # 进入到下面 self.simple_test 
        ...
    def simple_test(...):
        # self.extract_feat 主要包括两个步骤 img_backbone、img_neck,通过卷积提取特征
        # 网络为resnet + FPN
        # 如果是base模型,img_feats 为四个不同尺度的特征层
        # 如果是small、tiny,img_feats 为一个尺度的特征层
        img_feats = self.extract_feat(img=img, img_metas=img_metas)

        # Temproral Self-Attention + Spatial Cross-Attention
        new_prev_bev, bbox_pts = self.simple_test_pts(img_feats, img_metas, prev_bev, rescale=rescale)
        # 进入到下面 self.simple_test_pts 
    def simple_test_pts(...):
        # 对特征层进行编解码
        outs = self.pts_bbox_head(x, img_metas, prev_bev=prev_bev)
        # 进入到 projects/mmdet3d_plugin/bevformer/dense_heads/bevformer_head.py

4, proyectos/mmdet3d_plugin/bevformer/dense_heads/bevformer_head.py

class BEVFormerHead(DETRHead):
    def forward(...):
    	...
        if only_bev:
            ...
        else:
        	outputs = self.transformer(...)
        	# 进入到 projects/mmdet3d_plugin/bevformer/modules/transformer.py
        
        for lvl in range(hs.shape[0]):
            # 类别
            outputs_class = self.cls_branches[lvl](hs[lvl])
            # 回归框信息
            tmp = self.reg_branches[lvl](hs[lvl])
        outs = ...
        return out
    	# 返回到 projects/mmdet3d_plugin/bevformer/detectors/bevformer.py  simple_test_pts函数中

5, proyectos/mmdet3d_plugin/bevformer/modules/transformer.py

class PerceptionTransformer(...):
    def forward(...):
       # 获得bev特征
        bev_embed = self.get_bev_features(...)

    def get_bev_features(...):
        # 获得bev特征 block * 6
        bev_embed = self.encoder(...)
        # 进入到projects/mmdet3d_plugin/bevformer/modules/encoder.py
        ...
        # decoder
        inter_states, inter_references = self.decoder(...)
        # 进入到 projects/mmdet3d_plugin/bevformer/modules/decoder.py 中

        return bev_embed, inter_states, init_reference_out, inter_references_out
        # 返回到projects/mmdet3d_plugin/bevformer/dense_heads/bevformer_head.py

6, proyectos/mmdet3d_plugin/bevformer/modules/encoder.py

class BEVFormerEncoder(...):
    def forward(...):
  		...
        for lid, layer in enumerate(self.layers):
            out = ...
            # 进入到下面的 class BEVFormerLayer 

class BEVFormerLayer(...):
    def forward(...):
        # 通过layer进入到不同的模块中
        for layer in self.operation_order:
            # tmporal_self_attention
            if layer == 'self_attn':
                # self.attentions 为 temporal_self_attention模块
                query = self.attentions[attn_index]
                # 进入到projects/mmdet3d_plugin/bevformer/modules/temporal_self_attention.py
            #  Spatial Cross-Attention
            elif layer == 'cross_attn':
                query = self.attentions[attn_index]
                # 进入到 projects/mmdet3d_plugin/bevformer/modules/spatial_cross_attention.py

7, proyectos/mmdet3d_plugin/bevformer/modules/temporal_self_attention.py

class TemporalSelfAttention(...):
    def forward(...):
        output = ...
        # 残差链接   返回的结果为 Spatial Cross-Attention 模块的输入
        return self.dropout(output) + identity
    	# 返回到projects/mmdet3d_plugin/bevformer/modules/encoder.py

8, proyectos/mmdet3d_plugin/bevformer/modules/spatial_cross_attention.py

class SpatialCrossAttention(...):
def forward(...):
	
    queries = self.deformable_attention(...)
	# 进入到下面的MSDeformableAttention3D
	return self.dropout(slots) + inp_residual
	# 返回到返回到projects/mmdet3d_plugin/bevformer/modules/encoder.py

# self.deformable_attention
 class MSDeformableAttention3D(BaseModule):
    def forward(...):eights
    	output = ...
        return output
    	# 返回到上面 SpatialCrossAttention
        

9, proyectos/mmdet3d_plugin/bevformer/modules/decoder.py

class DetectionTransformerDecoder(...):
    def forward(...):
 
        for lid, layer in enumerate(self.layers):

            output = layer(...)
			# 进入到下面CustomMSDeformableAttention
            ...
            if self.return_intermediate:
                intermediate.append(output)
                intermediate_reference_points.append(reference_points)
            return output, reference_points
            # 返回到 projects/mmdet3d_plugin/bevformer/modules/transformer.py
            
class CustomMSDeformableAttention(...):
    def forward(...):
        '''
        query: [900, 1, 256] 
        query_pos:[900, 1, 256] 可学习的位置编码
        '''
        output = multi_scale_deformable_attn_pytorch(...)
        output = self.output_proj(output)
        return self.dropout(output) + identity
    	# 返回到上面的DetectionTransformerDecoder

6. Resumen

Después de los pasos anteriores, los pasos de razonamiento de BEVFormer básicamente se aclaran, pero hay muchos detalles en él. Dado que todavía estoy mirando el código fuente y algunos problemas no se han resuelto, la versión detallada posterior hará anotaciones detalladas en el variables en el código (ya escribiendo Si no hay problema), las dimensiones y funciones, por un lado, profundizan la comprensión de BEVFormer y, por otro lado, mejoran la propia comprensión del modelo BEV.

Supongo que te gusta

Origin blog.csdn.net/weixin_42108183/article/details/128426721
Recomendado
Clasificación