【传知代码】MonoCon解读与复现(论文复现)

news2024/11/24 17:07:46

前言:在快速发展的计算机视觉领域,单目视觉(Monocular Vision)技术凭借其独特的优势和广泛的应用前景,逐渐成为了研究的热点。MonoCon作为单目视觉领域的一项重要技术,其独特的算法设计和高效的性能表现,为我们带来了许多新的启示和可能性,通过本文的解读和复现,希望能够为读者提供一个全面而深入的MonoCon技术理解,同时也希望能够激发更多人对单目视觉技术的兴趣和研究热情。

本文所涉及所有资源均在传知代码平台可获取

目录

概述

演示效果

核心逻辑

写在最后


概述

        这篇文章描述了一种叫做MonoCon的技术,它主要用于辅助单目深度目标检测任务的学习过程。这种方法采用了训练数据中的丰富投影2D监督信号作为辅助工具,在训练过程中同时掌握了目标的3D边界框和辅助上下文信息。经过实验验证,这种方法在KITTI基准测试中展现出了卓越的性能,并且推理的速度也相当迅速。如下图所示:

该论文提出了一种名为MonoCon的单目深度估计方法,用于预测3D物体的中心位置、形状尺寸和观察角度等参数,论文地址 在这,画面如下:

        文中主要描述笔者对Kitti 3D目标检测基准所做的试验,并且和已有方法做对比。具体而言,笔者先介绍数据集及评估指标,再以MonoCon方法为对象进行训练与测试并详细分析说明。实验方面,笔者采用Kitti 3D目标检测基准下的数据集进行训练,共得到7481幅图片进行测试,7518幅图片进行对比。共对汽车,行人,自行车三大类产生兴趣。为了进行评估,作者使用了官方服务器提供的平均精度(AP)作为评价标准,这包括AP3D|R40和APBEV|R40两个评价指标。这两个指标都涉及到40个召回位置(R40),并且评估是在三个不同的难度级别下完成的。另外,笔者给出了训练验证子集划分模式。

关于实验的成果,作者首先把MonoCon与其他已有的技术手段做了对比。

在汽车分类方面,MonoCon在各种评价标准中都展现出了明显的优越性,与排名第二的GUPNet方法相比,其绝对增长率提高了1.44%。与此同时,MonoCon的运行速度要快于其他的方法。但就行人与自行车范畴而言,MonoCon并不像某些已有的方法那样具有良好性能。对于行人类,MonoCon相对于最佳模型GUPNet有1.35%的AP3D R40下降,但在所有方法中表现最好。对于自行车类别,MonoCon相对于最佳纯单目方法MonoDLE有1.29%的AP3D|R40下降,但仍然优于其他方法。笔者认为其原因可能是自行车类别3D边界框远小于汽车类别,且投影在特征图中的辅助语境通常很近,可能影响了辅助语境学习的效果。

最后笔者做了几个Ablation Study,对MonoCon结果做了更进一步的分析。在这些研究中,笔者发现学习辅助语境是改善MonoCon性能最重要的一个因素,注意力归一化效果比较差。另外,笔者对回归头进行类无关设置与训练设置效果进行了研究,并发现一定条件下能改善表现。

总体来说,本论文通过系列实验与分析来验证MonoCon完成3D目标检测任务的有效性并对其进行改进,如下图所示:

演示效果

训练模型的配置在config/monocon_configs.py:

需要修改数据集的路径。
模型训练保存的路径,比如./checkpoints_train,新建一个checkpoints_train文件夹。
如果GPU显存小于16G,要将_C.USE_BENCHMARK 设置为False;如果大约16G,设置为True。
设置BATCH_SIZE的大小,默认 _C.DATA.BATCH_SIZE = 8
设置CPU线程数,默认 _C.DATA.NUM_WORKERS = 4
设置验证模型和保存模型的间隔轮数,默认_C.PERIOD.EVAL_PERIOD = 10

from yacs.config import CfgNode as CN

_C = CN()
 
_C.VERSION = 'v1.0.3'
_C.DESCRIPTION = "MonoCon Default Configuration"
 
_C.OUTPUT_DIR = "./checkpoints_train"                               # Output Directory
_C.SEED = -1                                     # -1: Random Seed Selection
_C.GPU_ID = 0                                    # Index of GPU to use
 
_C.USE_BENCHMARK = False                          # Value of 'torch.backends.cudnn.benchmark' and 'torch.backends.cudnn.enabled'
 
 
# Data
_C.DATA = CN()
_C.DATA.ROOT = r'./dataset'                  # KITTI Root
_C.DATA.BATCH_SIZE = 8
_C.DATA.NUM_WORKERS = 4
_C.DATA.TRAIN_SPLIT = 'train' 
_C.DATA.TEST_SPLIT = 'val' 
 
_C.DATA.FILTER = CN()
_C.DATA.FILTER.MIN_HEIGHT = 25
_C.DATA.FILTER.MIN_DEPTH = 2
_C.DATA.FILTER.MAX_DEPTH = 65
_C.DATA.FILTER.MAX_TRUNCATION = 0.5
_C.DATA.FILTER.MAX_OCCLUSION = 2
 
 
# Model
_C.MODEL = CN()
 
_C.MODEL.BACKBONE = CN()
_C.MODEL.BACKBONE.NUM_LAYERS = 34
_C.MODEL.BACKBONE.IMAGENET_PRETRAINED = True
 
_C.MODEL.HEAD = CN()
_C.MODEL.HEAD.NUM_CLASSES = 3
_C.MODEL.HEAD.MAX_OBJS = 30
 
 
# Optimization
_C.SOLVER = CN()
 
_C.SOLVER.OPTIM = CN()
_C.SOLVER.OPTIM.LR = 2.25E-04
_C.SOLVER.OPTIM.WEIGHT_DECAY = 1E-05
_C.SOLVER.OPTIM.NUM_EPOCHS = 20        # Max Training Epochs 200
 
_C.SOLVER.SCHEDULER = CN()
_C.SOLVER.SCHEDULER.ENABLE = True
 
_C.SOLVER.CLIP_GRAD = CN()
_C.SOLVER.CLIP_GRAD.ENABLE = True
_C.SOLVER.CLIP_GRAD.NORM_TYPE = 2.0
_C.SOLVER.CLIP_GRAD.MAX_NORM = 35 
 
 
# Period
_C.PERIOD = CN()
_C.PERIOD.EVAL_PERIOD = 10                      # In Epochs / Set -1 if you don't want validation 10
_C.PERIOD.LOG_PERIOD = 50                       # In Steps 50

模型推理的命令含义如下:

python test.py --config_file [FILL] # Config file (.yaml file)
–checkpoint_file [FILL] # Checkpoint file (.pth file)
–visualize # Perform visualization (Qualitative Results)
–gpu_id [Optional] # Index of GPU to use for testing (Default: 0)
–save_dir [FILL] # Path where visualization results will be saved to

使用刚才训练的权重,模型推理示例,命令如下:

python test.py --config_file checkpoints_train/config.yaml --checkpoint_file checkpoints_train/checkpoints/epoch_010.pth --visualize --save_dir save_output --gpu_id 0

视频推理的代码如下:

python test_raw.py  --data_dir          [FILL]      # Path where sequence images are saved
                    --calib_file        [FILL]      # Calibration file ("calib_cam_to_cam.txt")
                    --checkpoint_file   [FILL]      # Checkpoint file (.pth file)
                    --gpu_id            [Optional]  # Index of GPU to use for testing (Default: 0)
                    --fps               [Optional]  # FPS of the result video (Default: 25)
                    --save_dir          [FILL]      # Path of the directory to save the result video

核心逻辑

下面这段代码实现了一个名为 MonoConDetector 的单目目标检测模型,其作用主要有以下几个方面:

1)定义模型结构: 定义了一个基于 DLA 骨干网络的目标检测模型,包括了骨干网络、上采样模块以及头部模块的结构。

2)前向传播计算: 实现了模型的前向传播函数 forward,能够根据输入数据计算模型的输出结果,并在训练模式下返回损失值。

3)模型评估: 提供了批量评估函数 batch_eval,能够在推理模式下对输入数据进行评估,并生成评估格式的输出,用于模型性能评估和结果可视化。

4)模型参数加载: 提供了加载预训练模型参数的函数 load_checkpoint,能够加载预训练模型的权重参数,便于迁移学习或继续训练模型。

5)特征提取: 提供了从数据字典中提取特征的函数 _extract_feat_from_data_dict,用于将输入数据转换为模型可处理的特征表示。

总的来说,这段代码实现了一个完整的单目目标检测模型,并提供了训练、推理、评估等功能,可用于解决实际的目标检测问题。

import os
import sys
import torch
import torch.nn as nn

from typing import Tuple, Dict, Any

sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))
from model import DLA, DLAUp, MonoConDenseHeads


default_head_config = {
    'num_classes': 3,
    'num_kpts': 9,
    'num_alpha_bins': 12,
    'max_objs': 30,
}


default_test_config = {
    'topk': 30,
    'local_maximum_kernel': 3,
    'max_per_img': 30,
    'test_thres': 0.4,
}


class MonoConDetector(nn.Module):
    def __init__(self,
                 num_dla_layers: int = 34,
                 pretrained_backbone: bool = True,
                 head_config: Dict[str, Any] = None,
                 test_config: Dict[str, Any] = None):
        
        super().__init__()
        
        self.backbone = DLA(num_dla_layers, pretrained=pretrained_backbone)
        self.neck = DLAUp(self.backbone.get_out_channels(start_level=2), start_level=2)
        
        if head_config is None:
            head_config = default_head_config
        if test_config is None:
            test_config = default_test_config
            
        if num_dla_layers in [34, 46]:
            head_in_ch = 64
        else:
            head_in_ch = 128
            
        self.head = MonoConDenseHeads(in_ch=head_in_ch, test_config=test_config, **head_config)
        
        
    def forward(self, data_dict: Dict[str, Any], return_loss: bool = True) -> Tuple[Dict[str, torch.Tensor]]:
        
        feat = self._extract_feat_from_data_dict(data_dict)
        
        if self.training:
            pred_dict, loss_dict = self.head.forward_train(feat, data_dict)
            if return_loss:
                return pred_dict, loss_dict
            return pred_dict
        
        else:
            pred_dict = self.head.forward_test(feat)
            return pred_dict
        
    
    def batch_eval(self, 
                   data_dict: Dict[str, Any], 
                   get_vis_format: bool = False) -> Dict[str, Any]:
        
        if self.training:
            raise Exception(f"Model is in training mode. Please use '.eval()' first.")
        
        pred_dict = self.forward(data_dict, return_loss=False)
        eval_format = self.head._get_eval_formats(data_dict, pred_dict, get_vis_format=get_vis_format)
        return eval_format
    
    
    def load_checkpoint(self, ckpt_file: str):
        model_dict = torch.load(ckpt_file)['state_dict']['model']
        self.load_state_dict(model_dict)


    def _extract_feat_from_data_dict(self, data_dict: Dict[str, Any]) -> torch.Tensor:
        img = data_dict['img']
        return self.neck(self.backbone(img))[0]

当然需要对数据集划分:train训练集、val验证集,在dataset目录下新建一个文件to_train_val.py用于将training 带标签数据(7481帧),划分为train(3712帧)、val(3769帧),代码如下:

import os
import shutil
 
# 【一】、读取train.txt文件
with open('./ImageSets/train.txt', 'r') as file:
    # 逐行读取train.txt文件中的文件名ID
    file_ids = [line.strip() for line in file]
 
# 【1】calib
# 指定路径A和路径B
path_A = './training/calib'
path_B = './train/calib'
 
# 如果路径B不存在,创建它
if not os.path.exists(path_B):
    os.makedirs(path_B)
 
# 遍历文件名ID并复制文件到路径B
for file_id in file_ids:
    source_file = os.path.join(path_A, f"{file_id}.txt")
    destination_file = os.path.join(path_B, f"{file_id}.txt")
    
    if os.path.exists(source_file):
        shutil.copy(source_file, destination_file)
    else:
        print(f"文件未找到:{file_id}.txt")
 
 
# 【2】image_2
# 指定路径A和路径B
path_A = './training/image_2'
path_B = './train/image_2'
 
# 如果路径B不存在,创建它
if not os.path.exists(path_B):
    os.makedirs(path_B)
 
# 遍历文件名ID并复制文件到路径B
for file_id in file_ids:
    source_file = os.path.join(path_A, f"{file_id}.png")
    destination_file = os.path.join(path_B, f"{file_id}.png")
    
    if os.path.exists(source_file):
        shutil.copy(source_file, destination_file)
    else:
        print(f"文件未找到:{file_id}.txt")
 
 
# 【3】label_2
# 指定路径A和路径B
path_A = './training/label_2'
path_B = './train/label_2'
 
# 如果路径B不存在,创建它
if not os.path.exists(path_B):
    os.makedirs(path_B)
 
# 遍历文件名ID并复制文件到路径B
for file_id in file_ids:
    source_file = os.path.join(path_A, f"{file_id}.txt")
    destination_file = os.path.join(path_B, f"{file_id}.txt")
    
    if os.path.exists(source_file):
        shutil.copy(source_file, destination_file)
    else:
        print(f"文件未找到:{file_id}.txt")
 
 
 
 
 
 
# 【二】、读取valtxt文件
with open('./ImageSets/val.txt', 'r') as file:
    # 逐行读取val.txt文件中的文件名ID
    file_ids = [line.strip() for line in file]
 
# 【1】calib
# 指定路径A和路径B
path_A = './training/calib'
path_B = './val/calib'
 
# 如果路径B不存在,创建它
if not os.path.exists(path_B):
    os.makedirs(path_B)
 
# 遍历文件名ID并复制文件到路径B
for file_id in file_ids:
    source_file = os.path.join(path_A, f"{file_id}.txt")
    destination_file = os.path.join(path_B, f"{file_id}.txt")
    
    if os.path.exists(source_file):
        shutil.copy(source_file, destination_file)
    else:
        print(f"文件未找到:{file_id}.txt")
 
 
# 【2】image_2
# 指定路径A和路径B
path_A = './training/image_2'
path_B = './val/image_2'
 
# 如果路径B不存在,创建它
if not os.path.exists(path_B):
    os.makedirs(path_B)
 
# 遍历文件名ID并复制文件到路径B
for file_id in file_ids:
    source_file = os.path.join(path_A, f"{file_id}.png")
    destination_file = os.path.join(path_B, f"{file_id}.png")
    
    if os.path.exists(source_file):
        shutil.copy(source_file, destination_file)
    else:
        print(f"文件未找到:{file_id}.txt")
 
 
# 【3】label_2
# 指定路径A和路径B
path_A = './training/label_2'
path_B = './val/label_2'
 
# 如果路径B不存在,创建它
if not os.path.exists(path_B):
    os.makedirs(path_B)
 
# 遍历文件名ID并复制文件到路径B
for file_id in file_ids:
    source_file = os.path.join(path_A, f"{file_id}.txt")
    destination_file = os.path.join(path_B, f"{file_id}.txt")
    
    if os.path.exists(source_file):
        shutil.copy(source_file, destination_file)
    else:
        print(f"文件未找到:{file_id}.txt")

写在最后

        这篇论文介绍了一种简洁且高效的单目3D目标检测技术,该技术无需依赖任何附加信息。该论文首先介绍了背景建模技术。作者所提出的MonoCon方法对辅助单目上下文进行了学习,这些上下文是基于训练过程中的3D边界框投影得出的。这种新方法能从大量数据集中自动地提取出足够数量的有用信息。这种方法使用了简洁的设计实现,它包括一个卷积神经网络特征背心和一组具有相同模块结构的回归头,用于提供必要的参数和辅助上下文。另外,为了提高网络性能,该算法将多个分类器集成到一起,以便于对不同种类物体或场景有更好地区分能力。在实验过程中,MonoCon在Kitti 3D目标检测基准测试上展现了卓越的性能,特别是在汽车类别上超越了最先进的技术,并且在行人和骑自行车的类别上也达到了相似的水平。除此之外,该技术还借助Cramer-Wold定理解来阐释其实用性,并已通过实验进行了有效的验证。

        当然该论文提出的方法为单目3D目标检测提供了一个新的思路,但仍然存在一些挑战需要克服。例如,如何进一步提高模型的准确性和鲁棒性,以及如何将该方法扩展到其他应用场景中。因此,未来的研究方向可能包括改进模型的设计和优化算法,以提高模型的性能和效率。同时,还需要进一步探索单目上下文的潜力,以便更好地应用于实际场景中。

详细复现过程的项目源码、数据和预训练好的模型可从该文章下方附件获取。

【传知科技】关注有礼     公众号、抖音号、视频号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1718338.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用pkg打包了一个使用了sqlite3的nodejs项目,启动后闪退

从截图来看,问题出在 sqlite3 模块上。说明在打包过程中,sqlite3 模块的 .node 文件没有正确加载。 紧急解决方法: 其实就是exe文件还需要node_modules中的sqlite3 依赖,我们直接在系统顶级放一个node_modules,且其中只…

(2024,Video2Game,NeRF,Mesh,物理模块,游戏引擎)通过单个视频实现实时、交互、逼真且兼容浏览器的环境

Video2Game: Real-time, Interactive, Realistic and Browser-Compatible Environment from a Single Video 公众号:EDPJ(进 Q 交流群:922230617 或加 VX:CV_EDPJ 进 V 交流群) 目录 0. 摘要 2. 相关工作 3. Video…

论文115:Reinforced GNNs for multiple instance learning (TNNLS‘24)

文章目录 1 要点2 预备知识2.1 MIL2.2 MIL-GNN2.3 Markov博弈2.4 深度Q-Learning 3 方法3.1 观测生成与交互3.2 动作选择和指导3.3 奖励计算3.4 状态转移和终止3.5 多智能体训练 1 要点 题目:用于MIL的强化GNN 代码:https://github.com/RingBDStack/RG…

Ollama 本地大模型框架

该篇教程主要讲解*Ollama的安装和简单使用* Ollama: 在本地启动并运行大型语言模型。 主要流程目录: 1.安装 2.使用 2.1.下载模型 2.2.简单使用 2.3.中文模型 2.4.中文社区 3.总结 1.安装 创建一个容器 切换”高级视图“ 参考填写 ollama oll…

ARM32开发——总线与时钟

🎬 秋野酱:《个人主页》 🔥 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 APB总线时钟树时钟树 外部晶振内部晶振 在这个例子中,这条大街和巴士构成了一套系统,我们称之为AHB总线。 …

响应式界面控件DevExtreme - 更强的数据分析和可视化功能

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合,使您可以利用现代Web开发堆栈(包括React,Angular,ASP.NET Core,jQuery,Knockout等)构建交互式的Web应用程序。从Angular和Reac&#xff0c…

新火种AI|OpenAI要和苹果合作了?微软有些不高兴

作者:一号 编辑:美美 和苹果之间的合作,可能会称为Altman引以为傲的功绩。 根据 The Information 援引知情人士的消息,OpenAI 已经和苹果达成了协议,将在其产品中运用 OpenAI 的对话式 AI。 如果进展顺利&#xff…

gitlab服务器迁移(亲测有效)

描述:最近公司迁移gitlab,我没有迁移过,经过网上查找资料最终完成迁移,途中也遇到挺多坑和两个问题,希望能帮到你。 新服务器安装gitlab 注意:新服务器gitlab版本也需要和旧版本一致。 首先查看原Gitlab…

12V转5V5A降压芯片:AH8317的全面解析

# 12V转5V降压芯片:AH8317的全面解析 在电子设计领域,电压转换器是不可或缺的组件之一,它们允许电子设备在不同的电源电压下稳定运行。今天,我们将深入探讨一款高性能的同步降压转换器——AH8317,它以其出色的性能和广…

连锁便利店水电远程抄表管理系统是什么?

一、系统概述 连锁便利店水电远程抄表管理系统是一种高效、智能化的解决方案,旨在优化便利店的能源管理,提高运营效率。它通过先进的技术手段,实现了对便利店水电用量的实时监控和远程抄表,大大降低了人工成本,提升了…

悬剑武器库5.04版

工具介绍 悬剑5 基于“悬剑网盘”精选工具集悬剑5“飞廉”云武器库制作。 操作系统:Windows 10 专业版 锁屏密码:secquan.org 解压密码: 圈子社区secquan.org 镜像大小:33.1GB 系统占用空间63.0 GB 镜像导入 下载镜像,文末…

vm:为虚拟机配置多个虚拟网卡(ubuntu20.04)

前言: 环境:虚拟机 ubuntu 20.04 要求:如标题,但是这里针对的是 ubuntu 20.04,对于其他操作系统,可以找一下其他操作系统对应的配置文件是什么 vm 添加虚拟网卡 首先进入 vm: 点击设置&#xf…

员工恶意删除公司数据怎么办,如何防范员工恶意删除公司数据

员工恶意删除公司数据怎么办,如何防范员工恶意删除公司数据 面对员工恶意删除公司数据的情况,企业应当采取一系列紧急且有序的应对措施,以最小化损失并确保业务连续性。以下是一套推荐的应对流程: 1.立即行动: 断开网…

freertos初体验 - 在stm32上移植

1. 说明 freertos内核 非常精简,代码量也很少,官方也针对主流的编译器和内核准备好了移植文件,所以 freertos 的移植是非常简单的,很多工具(例如CubeMX)点点鼠标就可以生成一个 freertos 的工程&#xff0…

【Python】解决Python报错:ModuleNotFoundError: No module named ‘xxx.yyy‘

🧑 博主简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向…

VNC server ubuntu20 配置

介绍 最近想使用实验室的4卡服务器跑一些深度学习实验,因为跑的是三维建图实验,需要配上可视化界面,本来自带的IPMI可以可视化,但分辨率固定在640*480,看起来很别扭,就捣鼓服务器远程可视化访问了两天&…

无法删除dll文件

碰到xxxxxx.dll文件无法删除不要慌! 通过Tasklist /m dll文件名称 去查看它和哪个系统文件绑定运行,发现是explorer.exe。 我们如果直接通过del命令【当然需要在该dll文件所在的路径中】。发现拒绝访问 我们需要在任务管理器中,将资源管理器…

【开源】在线考试系统 JAVA+Vue.js+SpringBoot 新手入门项目

目录 一、项目介绍 二、项目截图 三、核心代码 【开源】在线考试系统 JAVAVue.jsSpringBoot 新手入门项目 一、项目介绍 经典老框架SSM打造入门项目《在线考试系统》,包括班级模块、教师学生模块、试卷模块、试题模块、考试模块、考试回顾模块,项目编…

采样频率低于“奈奎斯特频率”时发生的混叠现象(抽样定理与信号恢复实验)

混叠现象(Aliasing) 混叠现象发生在采样频率低于奈奎斯特频率时,即采样频率低于信号最高频率的两倍。此时,信号的高频成分会被错误地映射到低频范围内,导致无法正确重建原始信号。具体来说: 奈奎斯特频率…

6-Django项目--分页模块化封装参数共存

目录 utils/page_data.py 分页模块化封装 在app当中创建一个python package 在当前包里面创建py文件 参数共存 完整代码 utils/page_data.py --包里创建py文件. # -*- coding:utf-8 -*- from django.utils.safestring import mark_safe from copy import deepcopyclass…