经典目标检测YOLO系列(一)复现YOLOV1(2)反解边界框及后处理

经典目标检测YOLO系列(一)复现YOLOV1(2)反解边界框及后处理

在上个博客,我们提出了新的YOLOV1架构,这次我们解决前向推理过程中的两个问题。
经典目标检测YOLO系列(一)YOLOV1的复现(1)总体架构

1、边界框的计算

1.1 反解边界框公式的改变

1.1.1 原版YOLOV1的中心点量化误差的计算公式

如下图,目标狗的中心点所在网格为黄色部分,中心点为图中红点。

在原版的YOLOV1中,我们发现中心点【红点】距离黄色网格左上角处【坐标为(1, 4)】是有差距的,这其实就是由于降采样带来的量化误差,因此,我们只要获得了这个量化误差,就能获得中心点的准确坐标了。

在这里插入图片描述

YOLOv1原版中计算这个量化误差的过程如下:

在这里插入图片描述

在上图中计算出grid_x,grid_y的坐标,我们可以用矩阵进行表示,我们不妨称这个矩阵为G,矩阵的值如下

[[0., 0.],[1., 0.],[2., 0.],[3., 0.],[4., 0.],[5., 0.],[6., 0.],[0., 1.],[1., 1.],[2., 1.],[3., 1.],[4., 1.],[5., 1.],[6., 1.],[0., 2.],[1., 2.],[2., 2.],[3., 2.],[4., 2.],[5., 2.],[6., 2.],[0., 3.],[1., 3.],[2., 3.],[3., 3.],[4., 3.],[5., 3.],[6., 3.],[0., 4.],[1., 4.],[2., 4.],[3., 4.],[4., 4.],[5., 4.],[6., 4.],[0., 5.],[1., 5.],[2., 5.],[3., 5.],[4., 5.],[5., 5.],[6., 5.],[0., 6.],[1., 6.],[2., 6.],[3., 6.],[4., 6.],[5., 6.],[6., 6.]
]

计算出来的量化误差,其实就是中心点【红点】距离【黄色网格左上角点】的X轴和Y轴方向的偏移量。

在这里插入图片描述

1.1.2 原版YOLOV1反解边界框的公式

YOLOv1原版中根据预测值反解边界框的过程如下:
c e n t e r x = ( g r i d x + c x ) × s t r i d e c e n t e r y = ( g r i d y + c y ) × s t r i d e w = w p r e d × w i m a g e h = h p r e d × h i m a g e center_x = (grid_x + c_x)×stride \\ center_y = (grid_y + c_y)×stride \\ w = w_{pred} × w_{image} \\ h = h_{pred} × h_{image} centerx=(gridx+cx)×stridecentery=(gridy+cy)×stridew=wpred×wimageh=hpred×himage

1.1.3 改进YOLOV1

在原版的YOLOv1中,bbox预测主要包括目标中心点的偏移量 cx,cy 和归一化的边界框的宽高 w,h ,但是不论是哪个量,原版的YOLOv1均使用线性函数来输出,未加任何约束限制,很明显会有以下两点问题:

  • 由于偏移量cx,cy是介于01范围内的数,因此,其本身就是有上下界的,而线性输出并没有上下界,这就容易导致在学习的初期,网络可能预测的值非常大,导致bbox分支学习不稳定。

  • 边界框的宽高显然是个非负数,而线性输出不能保证这一点,这也可能造成训练过程中的不稳定,一些输出一些不合理的数值(比如负数)。

因此对于这两个问题,我们进行改进:

  • 第一个问题:假设模型的输出为 tx,ty ,我们使用sigmoid函数将其映射到0~1的范围内,保证网络的输出值是合理的,使得训练更加稳定。

  • 第二个问题:采用log-exp方法来处理。

    • YOLOv1所要预测的不是归一化的边界框宽高,而是经过log函数压缩后的宽高。
    • 由于log函数的指数级的压缩特性,在一定程度上可以拉近大目标和小目标之间的尺寸量级,因此,对于平衡不同尺度的目标的检测问题还能起到一定的缓解作用。
    • 为了更好地学习这一标签,会将目标框的坐标先映射到网格的尺度上:ws=w/stride,hs=h/stride ,然后再做log处理

    t w = l o g ( w s ) t h = l o g ( h s ) t_w = log(w_s) \\ t_h = log(h_s) tw=log(ws)th=log(hs)

    • 在推理阶段,使用exp函数即可将预测恢复到正常的尺度上。
      w = e ( t w ) ∗ s t r i d e h = e ( t h ) ∗ s t r i d e w = e^{(t_w)}*stride \\ h = e^{(t_h)}*stride w=e(tw)strideh=e(th)stride

因此,改进后根据预测值反解边界框的公式如下:
c e n t e r x = ( g r i d x + c x ) × s t r i d e c e n t e r y = ( g r i d y + c y ) × s t r i d e w = e ( t w ) ∗ s t r i d e h = e ( t h ) ∗ s t r i d e center_x = (grid_x + c_x)×stride \\ center_y = (grid_y + c_y)×stride \\ w = e^{(t_w)}*stride \\ h = e^{(t_h)}*stride centerx=(gridx+cx)×stridecentery=(gridy+cy)×stridew=e(tw)strideh=e(th)stride

1.2 反解边界框代码实现

前向推理过程中,我们通过yoloV1网络得到置信度、分类以及回归的预测值。然后,对其进行一些调整,方便后续处理。

    # RT-ODLab/models/detectors/yolov1/yolov1.py  @torch.no_grad()def inference(self, x):# 测试阶段的前向推理代码# 主干网络feat = self.backbone(x)# 颈部网络feat = self.neck(feat)# 检测头cls_feat, reg_feat = self.head(feat)# 预测层obj_pred = self.obj_pred(cls_feat)cls_pred = self.cls_pred(cls_feat)reg_pred = self.reg_pred(reg_feat)fmp_size = obj_pred.shape[-2:]# 对 pred 的size做一些view调整,便于后续的处理# [B, C, H, W] -> [B, H, W, C] -> [B, H*W, C]obj_pred = obj_pred.permute(0, 2, 3, 1).contiguous().flatten(1, 2)cls_pred = cls_pred.permute(0, 2, 3, 1).contiguous().flatten(1, 2)reg_pred = reg_pred.permute(0, 2, 3, 1).contiguous().flatten(1, 2)# 测试时,笔者默认batch是1,# 因此,我们不需要用batch这个维度,用[0]将其取走。obj_pred = obj_pred[0]       # [H*W, 1]cls_pred = cls_pred[0]       # [H*W, NC]reg_pred = reg_pred[0]       # [H*W, 4]# 每个边界框的得分scores = torch.sqrt(obj_pred.sigmoid() * cls_pred.sigmoid())# 解算边界框, 并归一化边界框: [H*W, 4]bboxes = self.decode_boxes(reg_pred, fmp_size)......

然后,我们通过回归参数,反解边界框。要想反解边界框,首先,我们需要一个由grid_x,grid_y组成的矩阵G。

    # RT-ODLab/models/detectors/yolov1/yolov1.py  def create_grid(self, fmp_size):""" 用于生成G矩阵,其中每个元素都是特征图上的像素坐标。"""# 特征图的宽和高ws, hs = fmp_size# 生成网格的x坐标和y坐标grid_y, grid_x = torch.meshgrid([torch.arange(hs), torch.arange(ws)])# 将xy两部分的坐标拼起来:[H, W, 2]grid_xy = torch.stack([grid_x, grid_y], dim=-1).float()# [H, W, 2] -> [HW, 2] -> [HW, 2]grid_xy = grid_xy.view(-1, 2).to(self.device)return grid_xy

不了解torch.meshgrid()函数的可以参考:

np.meshgrid()和torch.meshgrid()函数解析

然后,我们按照改进后的公式,得到边界框中心坐标以及宽高,最后转换为(xmin,ymin,xmax,ymax)的格式。

    # RT-ODLab/models/detectors/yolov1/yolov1.py  def decode_boxes(self, pred, fmp_size):"""将txtytwth转换为常用的x1y1x2y2形式。pred:回归预测参数fmp_size:特征图宽和高"""# 生成网格坐标矩阵grid_cell = self.create_grid(fmp_size)# 计算预测边界框的中心点坐标和宽高pred_ctr = (torch.sigmoid(pred[..., :2]) + grid_cell) * self.stridepred_wh = torch.exp(pred[..., 2:]) * self.stride# 将所有bbox的中心带你坐标和宽高换算成x1y1x2y2形式pred_x1y1 = pred_ctr - pred_wh * 0.5pred_x2y2 = pred_ctr + pred_wh * 0.5pred_box = torch.cat([pred_x1y1, pred_x2y2], dim=-1)return pred_box

2、后处理

反解边界框后,我们会遇到两个问题:

  • 一些边界框的score过低,我们需要剔除。
  • 边界框有很多冗余,即多个box检测到了同一个物体,而我们对于每一个物体只需要一个框就够了。因此,我们有必要去剔除掉多余的结果(通过非极大值抑制nms)。

2.1 非极大值抑制

非极大值抑制的步骤:

  1. 首先挑选出得分score最高的框;

  2. 依次计算其他框与这个得分最高的框的 IoU ,超过给定 IoU 阈值的框舍掉。

  3. 对每一类别都进行以上的操作,直到无框可剔除为止。

非极大值抑制的python实现:

def nms(bboxes, scores):# 1、将xmin,ymin,xmax,ymax拿出xmin = bboxes[:, 0]ymin = bboxes[:, 1]xmax = bboxes[:, 2]ymax = bboxes[:, 3]# 2、置信度从大到小的下标order = scores.argsort()[::-1]print(order)# 3、每个bbox的面积area = (ymax - ymin) * (xmax - xmin)print(area)keep = [] # 保存框的索引while order.size > 0:i = order[0]keep.append(i)# 4、求当前置信度最大的bbox与其他bbox的iou# 4.1 计算交集的坐上角的点 和  右下角的点x1 = np.maximum(xmin[i], xmin[order[1:]])y1 = np.maximum(ymin[i], ymin[order[1:]])x2 = np.minimum(xmax[i], xmax[order[1:]])y2 = np.minimum(ymax[i], ymax[order[1:]])# 4.2 计算交集的宽和高w = np.maximum(1e-10, x2 - x1)h = np.maximum(1e-10, y2 - y1)# 4.3 计算iouinter = w * hiou = inter / (area[i] + area[order[1:]]  - inter)print('iou = ', iou)# 滤除超过nms阈值的检测框nms_thresh = 0.4inds = np.where(iou <= nms_thresh)[0]print(inds + 1)order = order[inds + 1]return keepif __name__ == '__main__':bboxes = np.asarray([[1, 1, 3, 3],[1, 1, 4, 4],[0, 0, 1.9, 1.9],[0, 0, 2, 2],]) * 100scores = np.asarray([0.6, 0.7, 0.9, 0.1])keep = nms(bboxes, scores)print(keep)print(bboxes[[2, 1]])
[2, 1]
[[  0.   0. 190. 190.][100. 100. 400. 400.]]

2.2 后处理代码实现

了解非极大值后,我们就可以进行后处理了。

    # RT-ODLab/models/detectors/yolov1/yolov1.py    def postprocess(self, bboxes, scores):"""后处理代码,包括阈值筛选和非极大值抑制1、滤掉低得分(边界框的score低于给定的阈值)的预测边界框;2、滤掉那些针对同一目标的冗余检测。Input:bboxes: [HxW, 4]scores: [HxW, num_classes]Output:bboxes: [N, 4]score:  [N,]labels: [N,]"""# 获取最大分数labels = np.argmax(scores, axis=1)scores = scores[(np.arange(scores.shape[0]), labels)]# threshold# 1、滤掉低得分(边界框的score低于给定的阈值)的预测边界框;keep = np.where(scores >= self.conf_thresh)bboxes = bboxes[keep]scores = scores[keep]labels = labels[keep]# nms# 2、滤掉那些针对同一目标的冗余检测。scores, labels, bboxes = multiclass_nms(scores, labels, bboxes, self.nms_thresh, self.num_classes, self.nms_class_agnostic)return bboxes, scores, labels
# RT-ODLab/utils/misc.py# ---------------------------- NMS ----------------------------
## basic NMS
def nms(bboxes, scores, nms_thresh):""""Pure Python NMS."""x1 = bboxes[:, 0]  #xminy1 = bboxes[:, 1]  #yminx2 = bboxes[:, 2]  #xmaxy2 = bboxes[:, 3]  #ymaxareas = (x2 - x1) * (y2 - y1)order = scores.argsort()[::-1]keep = []while order.size > 0:i = order[0]keep.append(i)# compute iouxx1 = np.maximum(x1[i], x1[order[1:]])yy1 = np.maximum(y1[i], y1[order[1:]])xx2 = np.minimum(x2[i], x2[order[1:]])yy2 = np.minimum(y2[i], y2[order[1:]])w = np.maximum(1e-10, xx2 - xx1)h = np.maximum(1e-10, yy2 - yy1)inter = w * hiou = inter / (areas[i] + areas[order[1:]] - inter + 1e-14)#reserve all the boundingbox whose ovr less than threshinds = np.where(iou <= nms_thresh)[0]order = order[inds + 1]return keep## class-agnostic NMS
def multiclass_nms_class_agnostic(scores, labels, bboxes, nms_thresh):# nms# 在所有的检测结果上执行的,不会考虑类别的差异keep = nms(bboxes, scores, nms_thresh)scores = scores[keep]labels = labels[keep]bboxes = bboxes[keep]return scores, labels, bboxes## class-aware NMS 
def multiclass_nms_class_aware(scores, labels, bboxes, nms_thresh, num_classes):# nms# 逐类别地去做NMS操作,不同类别之间的检测不会相互影响keep = np.zeros(len(bboxes), dtype=np.int32)for i in range(num_classes):inds = np.where(labels == i)[0]if len(inds) == 0:continuec_bboxes = bboxes[inds]c_scores = scores[inds]c_keep = nms(c_bboxes, c_scores, nms_thresh)keep[inds[c_keep]] = 1keep = np.where(keep > 0)scores = scores[keep]labels = labels[keep]bboxes = bboxes[keep]return scores, labels, bboxes## multi-class NMS 
def multiclass_nms(scores, labels, bboxes, nms_thresh, num_classes, class_agnostic=False):if class_agnostic:return multiclass_nms_class_agnostic(scores, labels, bboxes, nms_thresh)else:return multiclass_nms_class_aware(scores, labels, bboxes, nms_thresh, num_classes)

如此,yolov1的推理过程就已经介绍完毕。

接下来,在训练过程中,我们需要改进损失函数,训练过程中,如何确定正负样本呢?

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

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

相关文章

踩坑RV1106板端部署rknn模型

文章目录 1、交叉编译2、板上跑通3、验证自己模型 1、交叉编译 官方给的一个流程: RKNN 模型推理测试为了避免踩坑在开头提出来 按照官方的流程可以跑通&#xff0c;他自己提供的yolov5s.rknn&#xff08;640*640&#xff09;的模型&#xff0c;但是跑自己的模型的时候加载就会…

【星海随笔】浅谈用户态和内核态

内核 操作系统的核心是内核(kernel)&#xff0c;它独立于普通的应用程序&#xff0c;可以访问受保护的内存空间&#xff0c;也有访问底层硬件设备的所有权限。 linux 内核空间在虚拟空间中是固定大小的&#xff0c;并且在物理空间中同样也是固定大小的。 一般情况下&#xff…

如何合理配置云服务器的CPU和内存?

​  提到云服务器性能&#xff0c;大抵有两个主要影响因素&#xff0c;CPU 核心数量和内存容量 &#xff0c;它们决定了云服务器的速度和可靠性。日常运用中&#xff0c;我们如何判断网站需要需要更多或更少?如何扩大或缩小它们以优化网站的性能? 一般来说&#xff0c;您拥…

黑白图如何转换成彩色图

将黑白图转换为伪彩色图是通过给黑白图中的灰度值映射到彩虹色等色谱上&#xff0c;从而呈现出彩色效果。以下是一些常见的黑白图伪彩转换方式&#xff1a; 热度图&#xff08;Heatmap&#xff09;&#xff1a; 将低灰度值映射为冷色&#xff0c;高灰度值映射为热色。通常使用…

鸿蒙4.0实战应用(ArkTS)-抽奖转盘

构建主界面 在这个章节中&#xff0c;我们将完成示例主界面的开发&#xff0c;效果如图所示&#xff1a; 功能要求&#xff1a; 通过画布组件Canvas&#xff0c;画出抽奖圆形转盘。通过显式动画启动抽奖功能。通过自定义弹窗弹出抽中的奖品。 在绘制抽奖圆形转盘前&#xff…

文献速递:人工智能医学影像分割---高效的MR引导CT网络训练,用于CT图像中前列腺分割

01 文献速递介绍 如今&#xff0c;根据国家癌症研究所的报告&#xff0c;美国约有9.9%的男性患有前列腺癌。1 此外&#xff0c;根据美国癌症协会的数据&#xff0c;预计2019年将有174,650个新病例被诊断出前列腺癌&#xff0c;与此同时大约有31,620名男性将死于前列腺癌。因此…

大数据与人工智能|信息技术产业架构、行业发展与前沿技术(第2节)

内容链接&#xff1a;信息技术产业架构、行业发展与前沿技术&#xff08;大数据与人工智能系列课程 第2节&#xff09; 声明&#xff1a;学习使用&#xff0c;侵权必删&#xff01; 主要内容&#xff1a;1. 从算盘到量子计算机&#xff0c;介绍了半导体行业的发展历程和技术原…

软件测试/测试开发丨Python自动化测试学习笔记

1. 引言 自动化测试是软件开发中的关键环节&#xff0c;它可以提高测试效率、减少重复工作&#xff0c;并提供更快速、稳定的测试结果。Python作为一种易学易用的编程语言&#xff0c;为自动化测试提供了强大的工具和库。本文将介绍如何使用Python进行自动化测试。 2. 安装Py…

涨见识!微信还能这样批量导出好友

我们在使用微信的过程中&#xff0c;有时会因为种种原因&#xff0c;导致微信被封号&#xff0c;特别是永久封号这种情况&#xff0c;会导致微信里的好友丢失。面对这种情况&#xff0c;我们可以提前把微信里的好友导出来进行备份&#xff0c;万一被封号了&#xff0c;还可以用…

华帝,业绩好起来了,但股价还没

作者 | 辰纹 来源 | 洞见新研社 成为奥运会的赞助商&#xff0c;往往是一个品牌从本土走向全球的起点。 1928年&#xff0c;阿迪达斯首次出现在阿姆斯特丹奥运会上&#xff0c;从那一刻开始&#xff0c;阿迪达斯与耐克在全球相爱相杀&#xff0c;“缠绵”了近百年&#xff1…

uniapp 安装插件 uView (多平台快速开发的UI框架)

1. 下载并导入插件 打开链接 https://ext.dcloud.net.cn/plugin?id1593 导入成功后&#xff0c;可见 2. 添加配置 main.js import uView from /uni_modules/uview-ui Vue.use(uView)uni.scss import /uni_modules/uview-ui/theme.scss;App.vue <style lang"scss&qu…

Python经典游戏 唤醒你童年记忆

这些游戏你玩过几个&#xff1f; 1.贪吃蛇2.吃豆人3.加农炮4.四子棋5. Fly Bird<font color #f3704ab>6.记忆&#xff1a;数字对拼图游戏&#xff08;欢迎挑战&#xff01;用时&#xff1a;2min&#xff09;7.乒乓球8.上课划水必备-井字游戏&#xff08;我敢说100%的人都…

桥接模式-举例

概叙&#xff1a;桥接模式用一种巧妙的方式处理多层继承存在的问题&#xff0c; 用抽象关联取代了传统的多层继承&#xff0c; 将类之间的静态继承关系转换为动态的对象组合关系&#xff0c; 使得系统更加灵活&#xff0c;并易于扩展&#xff0c; 同时有效控制了系统中类的个数…

硅像素传感器文献调研(三)

写在前面&#xff1a; 引言&#xff1a;也是先总结前人的研究结果&#xff0c;重点论述其不足之处。 和该方向联系不大&#xff0c;但还是有值得学习的地方。逻辑很清晰&#xff0c;易读性很好。 1991年—场板半阻层 使用场板和半电阻层的高压平面器件 0.摘要 提出了一种…

基于JAVA的瑜伽馆管理系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 瑜伽课程模块2.3 课程预约模块2.4 系统公告模块2.5 课程评价模块2.6 瑜伽器械模块 三、系统设计3.1 实体类设计3.1.1 瑜伽课程3.1.2 瑜伽课程预约3.1.3 系统公告3.1.4 瑜伽课程评价 3.2 数据库设计3.2.…

在微服务中如何实现全链路的金丝雀发布?

目录 1. 什么金丝雀发布&#xff1f;它有什么用&#xff1f; 2.如何实现全链路的金丝雀发布 2.1 负载均衡模块 2.2 网关模块 2.3 服务模块 2.3.1 注册为灰色服务实例 2.3.2 设置负载均衡器 2.3.3 传递灰度发布标签 2.4 其他代码 2.4.1 其他业务代码 2.4.2 pom.xml 关…

Linux下MQTT环境的简单应用及搭建——之Mosquitto

文章目录 前言一、ubuntu搭建mqtt服务器 | 概要二、整体架构流程 | 技术实现细节1、下载源码2、安装Mosquitto3、解压并修改配置文件4、关于Mosquitto常见的一些操作指令5、启动mosquitto6、测试mosquitto测试1&#xff1a;Linux多终端交互测试测试2&#xff1a;Linux与Windows…

中职网络安全Web2003-2——Web渗透测试

需要环境或换&#xff0c;有问题可以私信我或加Q 1.通过URL访问http://靶机IP/1&#xff0c;对该页面进行渗透测试&#xff0c;将完成后返回的结果内容作为Flag值提交&#xff1b; FLAGflag{htmlcode} 2.通过URL访问http://靶机IP/2&#xff0c;对该页面进行渗透测试&#xff…

【C#】深拷贝和浅拷贝

文章目录 深拷贝和浅拷贝的定义深拷贝&#xff08;Deep Copy&#xff09;浅拷贝&#xff08;Shallow Copy&#xff09; 深拷贝和浅拷贝的定义 深拷贝&#xff08;Deep Copy&#xff09;和浅拷贝&#xff08;Shallow Copy&#xff09;是在复制对象时涉及的两个不同概念 深拷贝…

硅像素传感器文献调研(四)

写在前面&#xff1a; 好喜欢这种短论文哈哈哈哈哈 感觉这篇文献已经提到了保护环的概念啊&#xff0c;只不过叫的是&#xff1a;场限制环。 1986——高压功率器件场终端横向掺杂的变化 0.摘要 对于高压平面结提出了一个简单的新概念。通过在氧化物掩模中的小开口和随后的驱…