当前位置: 首页 > news >正文

CenterNet官方代码—目标检测模型推理部分解析与项目启动

CenterNet模型推理部分解析

CenterNet官方代码环境部署

CenterNet作为2019年CVPR推出的论文,论文中给出了官方代码所在的github仓库地址。https://github.com/xingyizhou/CenterNet。

在这里插入图片描述

整个代码的代码量并不是特别大,但整个项目的难点在于使用了老版本的pytorch<1.0与一些依赖的资源库从而导致了整个项目在启动和加载时或产生很多的错误。

GPU版本安装问题

在这里插入图片描述
在官方代码的Readme文件夹的下面给出了安装步骤的文件。首先文件中说明了当时使用的时python3.6版本。(不建议使用python3.6版本

自己使用的conda激活虚拟环境后使用的是3.8版本。

对出错的部分没有进行截图,因此只是简单的进行一定的陈述。

  1. 错误一:使用pip来安装CUDA的pytorch版本,我在安装的时候发现,如果使用pip来安装torch会安装的是torch+cu这种版本。而使用conda安装的话会安装一些CUDA相关的依赖

在这里插入图片描述
而在安装dcnv2的过程中需要CUDA相关库的支持。所以pytorch要使用conda来进行安装。 (最好之间安装Gpu的版本)

gpu.c相关文件也需要编译而且容易报错。

  1. DCNV2文件对torch版本的不支持,(自己当时使用git切换conda的虚拟环境安装.make.sh文件时候报错)需要使用最新的DCNV2库,卸载之后重新安装替代。

在这里插入图片描述

  1. 踩坑的地方在启动setup.py文件之后,可能会产生两个错误,第一个是因为缺少c++的编译环境,缺少支持库的错误。第二个是说c++库的版本过高不支持

网上查的原因是因为CUDA更新比较慢,而vistual Studio的更新过快。我自己将2022的版本降为2019年的启动成功。

  1. 一定要下载nvcc完全对应的版本,我自己的是12.1但当时安装习惯安装的是11.8nvcc会报错

在这里插入图片描述
总结:我个人使用的是pytorch2.3.0的版本来进行安装的,如果安装过程中出现错误,可以联系博主简单交流。

模型推理部分代码

检测部分的启动参数示例

ctdet
–demo
…/images/17790319373_bd19b24cfc_k.jpg
–load_model
…/models/ctdet_coco_dla_2x.pth

启动部分会产生一个模型下载失败的错误,将模型自己手动的下载到C盘的cache->torch…文件下面即可以启动模型成功。

自己断点调试,报错的一部分主要是网络错误,作用是加载预训练的一部分权重数据。

在这里插入图片描述

和Yolo一样也是可以检测视频文件的。

断点调试分析

在这里插入图片描述

推理过程整体的执行流程图与代码

在这里插入图片描述

def demo(opt):os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str #指定GPU对哪些环境变量可用opt.debug = max(opt.debug, 1) # 设置debug属性便于进行调试Detector = detector_factory[opt.task]detector = Detector(opt)if opt.demo == 'webcam' or \opt.demo[opt.demo.rfind('.') + 1:].lower() in video_ext:cam = cv2.VideoCapture(0 if opt.demo == 'webcam' else opt.demo)detector.pause = Falsewhile True:_, img = cam.read()cv2.imshow('input', img)ret = detector.run(img)time_str = ''for stat in time_stats:time_str = time_str + '{} {:.3f}s |'.format(stat, ret[stat])print(time_str)if cv2.waitKey(1) == 27:return  # esc to quitelse:if os.path.isdir(opt.demo): # 如果参数中的待检测数据是文件夹image_names = []ls = os.listdir(opt.demo)for file_name in sorted(ls):ext = file_name[file_name.rfind('.') + 1:].lower()if ext in image_ext:image_names.append(os.path.join(opt.demo, file_name))else: # 普通文件image_names = [opt.demo] #获取文件名for (image_name) in image_names:ret = detector.run(image_name) # 通过检测网络执行推理(核心)time_str = ''for stat in time_stats:time_str = time_str + '{} {:.3f}s |'.format(stat, ret[stat])print(time_str)

核心推理函数的细化分析

在这里插入图片描述

run()函数整体的部分

  def run(self, image_or_path_or_tensor, meta=None):load_time, pre_time, net_time, dec_time, post_time = 0, 0, 0, 0, 0 #时间变量初始化merge_time, tot_time = 0, 0debugger = Debugger(dataset=self.opt.dataset, ipynb=(self.opt.debug==3), # Debugger便于调试与错误诊断theme=self.opt.debugger_theme)start_time = time.time()pre_processed = Falseif isinstance(image_or_path_or_tensor, np.ndarray):image = image_or_path_or_tensorelif type(image_or_path_or_tensor) == type (''): image = cv2.imread(image_or_path_or_tensor) # 通过opencv读取图片else:image = image_or_path_or_tensor['image'][0].numpy()pre_processed_images = image_or_path_or_tensorpre_processed = Trueloaded_time = time.time()load_time += (loaded_time - start_time)detections = [] # 检测列表for scale in self.scales:scale_start_time = time.time()if not pre_processed:images, meta = self.pre_process(image, scale, meta) # 执行图片的预处理else:# import pdb; pdb.set_trace()images = pre_processed_images['images'][scale][0]meta = pre_processed_images['meta'][scale]meta = {k: v.numpy()[0] for k, v in meta.items()}images = images.to(self.opt.device) # 将image张量移动到GPU上torch.cuda.synchronize() # 确保CUDA操作完成pre_process_time = time.time()pre_time += pre_process_time - scale_start_timeoutput, dets, forward_time = self.process(images, return_time=True)torch.cuda.synchronize()net_time += forward_time - pre_process_time # 根据之前的函数计算出推理解码等一系列的时间decode_time = time.time()dec_time += decode_time - forward_timeif self.opt.debug >= 2:self.debug(debugger, images, dets, output, scale)dets = self.post_process(dets, meta, scale) # 执行后处理的过程(得到80个类别的列表信息部分含有数据)torch.cuda.synchronize()post_process_time = time.time()post_time += post_process_time - decode_time # 计算后处理时间detections.append(dets)results = self.merge_outputs(detections)torch.cuda.synchronize()end_time = time.time()merge_time += end_time - post_process_timetot_time += end_time - start_timeif self.opt.debug >= 1:self.show_results(debugger, image, results) # 调用opencv函数显示结果return {'results': results, 'tot': tot_time, 'load': load_time, # 放入所有的信息进行返回'pre': pre_time, 'net': net_time, 'dec': dec_time,'post': post_time, 'merge': merge_time}

预处理函数的执行部分

  def pre_process(self, image, scale, meta=None):height, width = image.shape[0:2]new_height = int(height * scale)new_width  = int(width * scale)if self.opt.fix_res: # 转为输入大小512 x 512inp_height, inp_width = self.opt.input_h, self.opt.input_wc = np.array([new_width / 2., new_height / 2.], dtype=np.float32)s = max(height, width) * 1.0else:inp_height = (new_height | self.opt.pad) + 1inp_width = (new_width | self.opt.pad) + 1c = np.array([new_width // 2, new_height // 2], dtype=np.float32)s = np.array([inp_width, inp_height], dtype=np.float32)trans_input = get_affine_transform(c, s, 0, [inp_width, inp_height])# 获取仿射变换矩阵resized_image = cv2.resize(image, (new_width, new_height))# 读取图片裁剪inp_image = cv2.warpAffine(resized_image, trans_input, (inp_width, inp_height),flags=cv2.INTER_LINEAR) # 应用之前的仿射矩阵进行仿射变换inp_image = ((inp_image / 255. - self.mean) / self.std).astype(np.float32) # 归一化处理images = inp_image.transpose(2, 0, 1).reshape(1, 3, inp_height, inp_width)if self.opt.flip_test:images = np.concatenate((images, images[:, :, :, ::-1]), axis=0)images = torch.from_numpy(images) # 转为张量的格式meta = {'c': c, 's': s, 'out_height': inp_height // self.opt.down_ratio, # opt.down_ratio:下采样倍率'out_width': inp_width // self.opt.down_ratio} # 储存c:中心点坐标 s:缩放因子return images, meta # 128x128(下采样4倍的特征图)

解码扩增部分对应的代码信息

def ctdet_decode(heat, wh, reg=None, cat_spec_wh=False, K=100):batch, cat, height, width = heat.size() # cat:表示类别的数目# heat = torch.sigmoid(heat)# perform nms on heatmapsheat = _nms(heat) # maxpooling(3x3)类似nms算法# scores:得分最高的 K 个点的得分。# inds:得分最高的 K 个点的索引。# clses:得分最高的 K 个点对应的类别。# ys:得分最高的 K 个点的 y 坐标。# xs:得分最高的 K 个点的 x 坐标。scores, inds, clses, ys, xs = _topk(heat, K=K) # 在热力图 heat 上执行 Top-K 操作提取最高 K 个得分的点提取最高 K 个得分的点if reg is not None: # 位置微调的过程reg = _transpose_and_gather_feat(reg, inds) # 将回归参数 reg 按照 inds(Top-K 操作返回的索引)重新排列,以便收集与 Top-K 操作选择的热力图位置相对应的回归参数reg = reg.view(batch, K, 2) # 收集到的回归参数 reg 调整为形状 [batch, K, 2] 的张量,其中 batch 是批次大小,K 是 Top-K 操作选择的点的数量,2 表示每个点的两个回归参数(通常是一个点的 x 和 y 方向的偏移量)xs = xs.view(batch, K, 1) + reg[:, :, 0:1] # x坐标与回归偏移量的坐标相加ys = ys.view(batch, K, 1) + reg[:, :, 1:2]else:xs = xs.view(batch, K, 1) + 0.5ys = ys.view(batch, K, 1) + 0.5wh = _transpose_and_gather_feat(wh, inds) # 特征图的维度从 [batch, num_anchors, height, width] 转换为 [batch, K, num_anchors]if cat_spec_wh: # 是否每个类别有特定的宽度和高度预测wh = wh.view(batch, K, cat, 2) # wh 张量的形状调整为 [batch, K, num_classes, 2]clses_ind = clses.view(batch, K, 1, 1).expand(batch, K, 1, 2).long() # 创建一个索引张量,用于从 wh 中收集特定类别的宽度和高度wh = wh.gather(2, clses_ind).view(batch, K, 2) # 得到结果值else:wh = wh.view(batch, K, 2)clses  = clses.view(batch, K, 1).float()scores = scores.view(batch, K, 1)bboxes = torch.cat([xs - wh[..., 0:1] / 2,  # torch.cat 函数将四个坐标点(左上角和右下角)拼接成一个检测框的坐标张量ys - wh[..., 1:2] / 2,xs + wh[..., 0:1] / 2, # xs + wh[..., 0:1] / 2 和 ys + wh[..., 1:2] / 2:计算右下角的坐标。ys + wh[..., 1:2] / 2], dim=2) # xs - wh[..., 0:1] / 2 和 ys - wh[..., 1:2] / 2:计算左上角的坐标。detections = torch.cat([bboxes, scores, clses], dim=2)return detections # 连接之后返回检测框结果(论文中提到的扩增的过程)

后处理函数的执行部分

  def post_process(self, dets, meta, scale=1):dets = dets.detach().cpu().numpy() # 转为numpy格式进入cpu进行计算dets = dets.reshape(1, -1, dets.shape[2])dets = ctdet_post_process( # 尺度变换、坐标转换、非极大值抑制(NMS) 传入的meta['c']中心点 meta['s']缩放尺度dets.copy(), [meta['c']], [meta['s']],meta['out_height'], meta['out_width'], self.opt.num_classes)for j in range(1, self.num_classes + 1): # 后处理转换类型dets[0][j] = np.array(dets[0][j], dtype=np.float32).reshape(-1, 5)dets[0][j][:, :4] /= scalereturn dets[0]

剩余的部分函数不在进行说明了,但模型推理代码的复现流程主要还是需要按照我自己绘制的流程图进行debug

相关文章:

CenterNet官方代码—目标检测模型推理部分解析与项目启动

CenterNet模型推理部分解析 CenterNet官方代码环境部署 CenterNet作为2019年CVPR推出的论文&#xff0c;论文中给出了官方代码所在的github仓库地址。https://github.com/xingyizhou/CenterNet。 整个代码的代码量并不是特别大&#xff0c;但整个项目的难点在于使用了老版本的…...

测试开发基础——测试用例的设计

三、测试用例的设计 1. 什么是测试用例 测试用例(Test Case)是为了实施测试而向被测试的系统提供的一组集合&#xff0c;这组集合包含&#xff1a;测试环境、操作步骤、测试数据、预期结果等要素。 设计测试用例原则一&#xff1a;测试用例中一个必需部分是对预期输出或结果进…...

C++第五十一弹---IO流实战:高效文件读写与格式化输出

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1. C语言的输入与输出 2. 流是什么 3. CIO流 3.1 C标准IO流 3.2 C文件IO流 3.2.1 以写方式打开文件 3.2.1 以读方式打开文件 4 stringstre…...

C++中使用分治法求最大值

在C++中使用分治法(Divide and Conquer)来求一个数组中的最大值是一个经典的问题。分治法是一种通过将原问题分解为若干个小规模相似子问题,递归地求解这些子问题,然后将子问题的解合并成原问题的解的方法。 以下是使用分治法求数组中最大值的步骤: 分解(Divide):将数…...

数据集 CULane 车道线检测 >> DataBall

数据集 CULane 车道线检测 自动驾驶 无人驾驶目标检测 CULane是用于行车道检测学术研究的大规模具有挑战性的数据集。它由安装在六辆由北京不同驾驶员驾驶的不同车辆上的摄像机收集。收集了超过55小时的视频&#xff0c;并提取了133,235帧。数据示例如上所示。我们将数据集分为…...

Android CustomDialog圆角背景不生效的问题

一行解决: window?.setBackgroundDrawableResource(android.R.color.transparent) 原文件: /*** Created by Xinghai.Zhao* 自定义选择弹框*/ SuppressLint("InflateParams", "MissingInflatedId") class CustomDialog(context: Context?) : AlertDia…...

C++速通LeetCode简单第9题-二叉树的最大深度

深度优先算法递归&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right…...

com.microsoft.sqlserver:sqljdbc4:jar:4.0 was not found产生原因及解决步骤

文章目录 问题sqlserver 包找不到 报错原因分析主要原因 解决方案步骤 1&#xff1a;检查 pom.xml 中的依赖声明步骤 2&#xff1a;配置 Microsoft 的 Maven 仓库步骤 3&#xff1a;强制更新 Maven 依赖步骤 4&#xff1a;清理本地仓库缓存步骤 5&#xff1a;手动下载并安装 sq…...

【算法】 滑动窗口—最长无重复子串

“无重复字符的最长子串”&#xff0c;难度为Medium&#xff0c;看下题目&#xff1a; 输入一个字符串 s&#xff0c;请计算 s 中不包含重复字符的最长子串长度。 比如&#xff0c;输入 s "aabab"&#xff0c;算法返回2&#xff0c;因为无重复的最长子串是 "ab…...

SpringBoot2:web开发常用功能实现及原理解析-上传与下载

文章目录 一、上传文件1、前端上传文件给Java接口2、Java接口上传文件给Java接口 二、下载文件1、前端调用Java接口下载文件2、Java接口下载网络文件到本地3、前端调用Java接口下载网络文件 一、上传文件 1、前端上传文件给Java接口 Controller接口 此接口支持上传单个文件和…...

Linux:进程状态和优先级

一、进程状态 1.1 操作系统学科&#xff08;运行、阻塞、挂起&#xff09; 为了弄明白正在运行的进程是什么意思&#xff0c;我们需要知道进程的不同状态 大多数操作系统都遵循以下原则 1.1.1 运行状态 因为有一个调度器需要确保CPU的资源被合理使用&#xff0c;所以需要维护…...

代码随想录算法训练营day37

1.携带研究材料 1.1 题目 52. 携带研究材料&#xff08;第七期模拟笔试&#xff09; 1.2 题解 #include <iostream> #include <functional> #include <vector> using namespace std;int main() {//输入相关信息int classes, cabaity;cin >> classe…...

Java-idea小锤子图标

这一版的idea小锤子图标其实就在这里 点进去就找到了~...

最强神器Typora 2024(亲测有效)| Markdown 工具推荐

听俺讲一下 大家好&#xff0c;我是程序员-杨胡广&#xff0c;今天想给大家分享一个在编写文档时的神器——Typora。相信不少小伙伴都在寻找一款既简洁又强大的 Markdown 编辑工具&#xff0c;而 Typora 无疑是最值得推荐的选择。 当我在大学时偶然发现了它&#xff0c;直到今…...

【时时三省】tessy 单元测试 集成测试 专栏 文章阅读说明

目录 1&#xff0c;关于更新 2&#xff0c;关于文章阅读 3&#xff0c;关于文章分类 1&#xff0c;单元测试 2&#xff0c;集成测试 3&#xff0c;通用便捷操作 4&#xff0c;编译问题集锦 5&#xff0c;需求管理 6&#xff0c;CTE的使用 7&#xff0c;tessy自动化执…...

力扣刷题(6)

两数之和 II - 输入有序数组 两数之和 II - 输入有序数组-力扣 思路&#xff1a; 因为该数组是非递减顺序排列&#xff0c;因此可以设两个左右下标当左右下标的数相加大于target时&#xff0c;则表示右下标的数字过大&#xff0c;因此将右下标 - -当左右下标的数相加小于targ…...

TiDB 扩容过程中 PD 生成调度的原理及常见问题丨TiDB 扩缩容指南(一)

导读 作为一个分布式数据库&#xff0c;扩缩容是 TiDB 集群最常见的运维操作之一。本系列文章&#xff0c;我们将基于 v7.5.0 具体介绍扩缩容操作的具体原理、相关配置及常见问题的排查。 通常&#xff0c;我们根据当前资源状态来决定是否需要调整 TiKV 节点的规模&#xff0…...

匿名管道详解

进程间通讯的目的 数据传输&#xff1a;一个进程需要把它的数据发送给另一个数据资源共享&#xff1a;多个进程需要共享同样的资源通知事件&#xff1a;一个进程需要向另一个或者一组进程发送消息&#xff0c;通知它发生了某种事件&#xff08;如进程终止时要通知父进程&#…...

深度解读MySQL意向锁的工作原理机制与应用场景

意向锁 意向锁的概念 意向锁是InnoDB自动添加的一种锁&#xff0c;不需要用户去干预。 是数据库中的一种表级锁&#xff0c;一个事务要给一个资源加锁时&#xff0c;必须要先获取到对应类型的意向锁之后&#xff0c;才可以给这个资源加上自己想要的共享锁或者排他锁&#xff0…...

ZYNQ TCP 协议的远程更新 QSPI Flash

1 SDK直接少些Flash过程 ****** Xilinx Program Flash ****** Program Flash v2019.1 (64-bit)**** SW Build 2552052 on Fri May 24 14:49:42 MDT 2019** Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.WARNING: Failed to connect to hw_server at TCP:127.0.0.1:3…...

SQL 基础入门

SQL 基础入门 SQL&#xff08;全称 Structured Query Language&#xff0c;结构化查询语言&#xff09;是用于操作关系型数据库的标准语言&#xff0c;主要用于数据的查询、新增、修改和删除。本文面向初学者&#xff0c;介绍 SQL 的基础概念和核心操作。 1. 常见的 SQL 数据…...

1130 - Host ‘xxx.x.xx.xxx‘is not allowed to connect to this MySQL server

以下为本次问题的解决办法&#xff1a; 1、暂停mysql容器&#xff1a; docker stop mysql 2、删除mysql容器&#xff1a;docker rm mysql 3、查看mysql容器是否被删除&#xff1a;docker ps -a #没有mysql容器就是删除成功 4、run mysql容器&#xff1a; docker run -d --…...

全新Xsens Animate版本是迄今为止最大的软件升级,提供更清晰的数据、快捷的工作流程以及从录制开始就更直观的体验

我们整合了专业人士喜爱的 Xsens 动捕功能&#xff0c;并使其更加完善。全新Xsens Animate版本是我们迄今为止最大的软件升级&#xff0c;旨在提供更清晰的数据、更快捷的工作流程以及从录制开始就更直观的体验。 从制作游戏动画到流媒体直播头像或构建实时电影内容&#xff0…...

华为OD机试_2025 B卷_数组去重和排序(Python,100分)(附详细解题思路)

题目描述 给定一个乱序的数组&#xff0c;删除所有的重复元素&#xff0c;使得每个元素只出现一次&#xff0c;并且按照出现的次数从高到低进行排序&#xff0c;相同出现次数按照第一次出现顺序进行先后排序。 输入描述 一个数组 输出描述 去重排序后的数组 用例 输入1,3,…...

Chrome安装代理插件ZeroOmega(保姆级别)

目录 本文直接讲解一下怎么本地安装ZeroOmega一、下载文件在GitHub直接下ZeroOmega 的文件&#xff08;下最新版即可&#xff09; 二、安装插件打开 Chrome 浏览器&#xff0c;访问 chrome://extensions/ 页面&#xff08;扩展程序管理页面&#xff09;&#xff0c;并打开开发者…...

Python异步爬虫与代理完美结合

为了编写一个高性能的异步爬虫&#xff0c;并使用代理IP&#xff0c;我们可以使用以下技术栈&#xff1a;aiohttp &#xff08;用于异步HTTP请求&#xff09;、asyncio &#xff08;用于异步编程&#xff09;、代理IP可以使用一个代理池&#xff0c;我们从文件中读取或者从API获…...

Go语言爬虫系列教程5:HTML解析技术以及第三方库选择

Go语言爬虫系列教程5&#xff1a;HTML解析技术以及第三方库选择 在上一章中&#xff0c;我们使用正则表达式提取网页内容&#xff0c;但这种方法有局限性。对于复杂的HTML结构&#xff0c;我们需要使用专门的HTML解析库。在这一章中&#xff0c;我们将介绍HTML解析技术以及如何…...

JVM——打开JVM后门的钥匙:反射机制

引入 在Java的世界里&#xff0c;反射机制&#xff08;Reflection&#xff09;就像一把万能钥匙&#xff0c;能够打开JVM的“后门”&#xff0c;让开发者在运行时突破静态类型的限制&#xff0c;动态操控类的内部结构。想象一下&#xff0c;传统的Java程序如同按菜单点菜的食客…...

考研系列—操作系统:冲刺笔记(1-3章)

目录 第一章 计算机系统概述 1.基本概念 2.内核态和用户态 3.中断(外中断)、异常(内中断-与当前执行的) 4.系统调用 5.操作系统引导程序 2021年真题: 6.操作系统结构 大纲新增 (1)分层结构 (2)模块化 (3)外核 7.虚拟机 第二章 进程管理 1.画作业运行的顺序和甘…...

有人-无人(人机)交互记忆、共享心智模型与AI准确率的边际提升

有人-无人&#xff08;人机&#xff09;交互记忆、共享心智模型与AI准确率的边际提升是人工智能发展中相互关联且各有侧重的三个方面。人机交互记忆通过记录和理解用户与机器之间的交互历史&#xff0c;增强机器对用户需求的个性化响应能力&#xff0c;从而提升用户体验和协作效…...