代码编织梦想

😁大家好,我是CuddleSabe,目前大四在读,深圳准入职算法工程师,研究主要方向为多模态(VQA、ImageCaptioning等),欢迎各位佬来讨论!
🍭我最近在有序地计划整理CV入门实战系列NLP入门实战系列。在这两个专栏中,我将会带领大家一步步进行经典网络算法的实现,
欢迎各位读者(da lao)订阅🍀

👿本教程皆是对李沐老师的动手学深度学习-锚框视频教程及zh.d2l.ai中代码的详细解释(李沐老师跳过了一部分的代码解释)

锚框Anchor的生成处理及可视化

锚框的生成

⚠️代码警告!

def multibox_prior(data, sizes, ratios):
    """生成以每个像素为中心具有不同形状的锚框"""
    in_height, in_width = data.shape[-2:]
    device, num_sizes, num_ratios = data.device, len(sizes), len(ratios)
    boxes_per_pixel = (num_sizes + num_ratios - 1)
    size_tensor = torch.tensor(sizes, device=device)
    ratio_tensor = torch.tensor(ratios, device=device)

    # 为了将锚点移动到像素的中心,需要设置偏移量。
    # 因为一个像素的高为1且宽为1,我们选择偏移我们的中心0.5
    offset_h, offset_w = 0.5, 0.5
    steps_h = 1.0 / in_height  # 在y轴上缩放步长
    steps_w = 1.0 / in_width  # 在x轴上缩放步长

    # 生成锚框的所有中心点
    center_h = (torch.arange(in_height, device=device) + offset_h) * steps_h
    center_w = (torch.arange(in_width, device=device) + offset_w) * steps_w
    shift_y, shift_x = torch.meshgrid(center_h, center_w)
    shift_y, shift_x = shift_y.reshape(-1), shift_x.reshape(-1)

    # 生成“boxes_per_pixel”个高和宽,
    # 之后用于创建锚框的四角坐标(xmin,xmax,ymin,ymax)
    w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),
                   sizes[0] * torch.sqrt(ratio_tensor[1:])))\
                   * in_height / in_width  # 处理矩形输入
    h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]),
                   sizes[0] / torch.sqrt(ratio_tensor[1:])))
    # 除以2来获得半高和半宽
    anchor_manipulations = torch.stack((-w, -h, w, h)).T.repeat(
                                        in_height * in_width, 1) / 2

    # 每个中心点都将有“boxes_per_pixel”个锚框,
    # 所以生成含所有锚框中心的网格,重复了“boxes_per_pixel”次
    out_grid = torch.stack([shift_x, shift_y, shift_x, shift_y],
                dim=1).repeat_interleave(boxes_per_pixel, dim=0)
    output = out_grid + anchor_manipulations
    return output.unsqueeze(0)

第一眼看上去各位同学可能会有点迷糊,没关系,我们一行一行来解析!
首先,我们需要确定的是,作为生成锚框的函数,它的输入和输出都是什么?尺寸多少呢?

输入参数含义形状类型
data那当然是图片的数据啦[b, c, h, w]tensor
sizes锚框的尺寸!也称 S S S任意长度,本文为3list
ratios锚框的高宽比!也称 R R R任意长度,本文为3list
输出参数含义形状类型
output各个锚框的左上右下点坐标[b, 该图片的锚框数, 4]tensor

可以看到,该函数的任务是输入图片和想要的锚框的尺寸信息,则会返回所有该图片所有锚框的左上顶点和右下顶点顶坐标!那么它是如何实现的?我们接下来逐行看代码:

in_height, in_width = data.shape[-2:]
device, num_sizes, num_ratios = data.device, len(sizes), len(ratios)

这两行的作用是获取图片的尺寸(高和宽)以及其余参数的数量
boxes_per_pixel = (num_sizes + num_ratios - 1)

这里是获得一个像素有多少个锚框。
我们本教程中使用3个size和3个ratios,如果是标准官方实现的话是3*3=9,
但是我们这里为了加快运算,每个像素只会获得3+3-1=5个锚框

那么我们怎么通过 sizesratios 来判断锚框的尺寸呢? 例如,我们输入的
sizes=[0.75, 0.5, 0.25]ratios=[1, 2, 0.5],这里我们可以听下李沐老师的说法:

请添加图片描述

# 为了将锚点移动到像素的中心,需要设置偏移量。
# 因为一个像素的高为1且宽为1,我们选择偏移我们的中心0.5
offset_h, offset_w = 0.5, 0.5
steps_h = 1.0 / in_height  # 在y轴上缩放步长
steps_w = 1.0 / in_width  # 在x轴上缩放步长
# 生成锚框的所有中心点
center_h = (np.arange(in_height, ctx=device) + offset_h) * steps_h
center_w = (np.arange(in_width, ctx=device) + offset_w) * steps_w

假定图片大小为100*100,这里是先生成0,1,2,3...100的序列,
加上0.5后即是在图片中的像素坐标,再乘以steps_w(h)等同于除图片的宽()
等同于归一化到0-1,即在图片内到百分比坐标
shift_y, shift_x = torch.meshgrid(center_h, center_w)

这里我们使用meshgrid来对xy坐标两两组合得到网格坐标,
两个输出的尺寸信息为[输入图片高,输入图片宽],[100, 100]
shift_y, shift_x = shift_y.reshape(-1), shift_x.reshape(-1)

摊平,因为函数输出是宽和高在同一维度
w = np.concatenate((size_tensor * np.sqrt(ratio_tensor[0]),
                        sizes[0] * np.sqrt(ratio_tensor[1:]))) \
                        * in_height / in_width  # 处理矩形输入
    h = np.concatenate((size_tensor / np.sqrt(ratio_tensor[0]),
                        sizes[0] / np.sqrt(ratio_tensor[1:])))

怎么样,是不是有点眼熟?!

请添加图片描述
请添加图片描述

接下来重头戏来了!

anchor_manipulations = torch.stack((-w, -h, w, h)).T.repeat(in_height * in_width, 1) / 2

相信很多同学第一次看到的时候头都晕了,没关系,我们把它拆解开

torch.stack((-w, -h, w, h))
这里输出的shape是[4, 5],那么我们再加一个转置,相当于两个维度交换

torch.stack((-w, -h, w, h)).T
shpe为[54],即一个像素的锚框坐标,这里的5是因为每个像素有(num_sizes + num_ratios - 1)个锚框,也就是5。
而这里的4就是一个锚框的左上顶点和右下顶点的xy坐标。
那么这个只是一个像素的,我们在第一个维度(dim=0)重复h*w(总像素个数)次

torch.stack((-w, -h, w, h)).T.repeat(in_height * in_width, 1)
这时候的shape为[h*w*54],第一维度也就是一张图片所有的锚框数,第二维度为两个顶点的xy坐标。
但我们所需的是半宽半高(因为我们使用半宽半高加上中心点才是顶点坐标)

即
torch.stack((-w, -h, w, h)).T.repeat(in_height * in_width, 1)/2

接下来倒数第二行代码: 我们依旧一点点进行分解

torch.stack([shift_x, shift_y, shift_x, shift_y], dim=1)
输出为[h*w, 4],我们这里为什么要重复添加两个x和y呢?
因为我们上边的代码中获得了(-w/2, -h/2, w/2, h/2)即一个锚框的半宽半高。
但是我们现在一个像素只有一个框,因此我们将每一行重复5次,即(num_sizes + num_ratios - 1)次

torch.stack([shift_x, shift_y, shift_x, shift_y], dim=1).repeat_interleave(boxes_per_pixel, dim=0)

最后,我们将每个锚框的中心点坐标加上每个锚框的[负半宽,负半高,半宽,半高],就是每个锚框的左上顶点和右下顶点坐标(图片的纵坐标向下增长)

output = out_grid + anchor_manipulations

返回尺寸为 [b, h * w * 每个像素的锚框数, 4]

显示锚框

#@save
def show_bboxes(axes, bboxes, labels=None, colors=None):
    """显示所有边界框"""
    def _make_list(obj, default_values=None):
        if obj is None:
            obj = default_values
        elif not isinstance(obj, (list, tuple)):
            obj = [obj]
        return obj
        
    """将边界框(左上x, 左上y, 右下x, 右下y)格式转换成matplotlib格式((左上x, 左上y), 宽, 高)"""
	def bbox_to_rect(bbox, color):
    	return plt.Rectangle(xy=(bbox[0], bbox[1]), width=bbox[2]-bbox[0], height=bbox[3]-bbox[1], fill=False, edgecolor=color, linewidth=2)

    labels = _make_list(labels)
    colors = _make_list(colors, ['b', 'g', 'r', 'm', 'c'])
    for i, bbox in enumerate(bboxes):
        color = colors[i % len(colors)]
        rect = bbox_to_rect(bbox.detach().numpy(), color)
        axes.add_patch(rect)
        if labels and len(labels) > i:
            text_color = 'k' if color == 'w' else 'w'
            axes.text(rect.xy[0], rect.xy[1], labels[i],
                      va='center', ha='center', fontsize=9, color=text_color,
                      bbox=dict(facecolor=color, lw=0))

使用

我们使用上述的锚框生成函数,获得如下shape的输出 torch.Size([1, 2042040, 4])

Y = multibox_prior(X, sizes=[0.75, 0.5, 0.25], ratios=[1, 2, 0.5])

为了方便,我们将其reshape一下,如下

boxes = Y.reshape(h, w, 5, 4)

则这个变量代表了在250行250列像素的第一个锚框的俩顶点坐标值

boxes[250, 250, 0, :]
如下
tensor([0.06, 0.07, 0.63, 0.82])

同时,因为我们的顶点坐标都缩放到0-1之间,因此我们需要将其还原到原本的图像坐标上去,即乘上原图像的w和h

bbox_scale = torch.tensor((w, h, w, h))
boxes[250, 250, :, :] * bbox_scale 就是图片[250250]处的锚框在图片中的真实坐标
bbox_scale = torch.tensor((w, h, w, h))
fig = plt.imshow(img)
show_bboxes(fig.axes, boxes[250, 250, :, :] * bbox_scale,
            ['s=0.75, r=1', 's=0.5, r=1', 's=0.25, r=1', 's=0.75, r=2',
             's=0.75, r=0.5'])

请添加图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_15534667/article/details/127991387

mask rcnn 实战(一)--代码详细解析_to_be_better_one的博客-爱代码爱编程

Mask RCNN:(大家有疑问的请在评论区留言) 如果对原理不了解的话,可以花十分钟先看一下我的这篇博文,在来进行实战演练,这篇博文将是让大家对mask rcnn 进行一个入门,我在后面的博文中会介绍mask rcnn 如何用于 多人关键点检测和多人姿态估计,以及如何利用mask rcnn 训练自己的数据集,以及mobile_net版的mask rcn

动手学CV-目标检测入门教程3:锚框(anchor)-爱代码爱编程

3.3 锚框 or 先验框 本文来自开源组织 DataWhale 🐳 CV小组创作的目标检测入门教程。 对应开源项目 《动手学CV-Pytorch》 的第3章的内容,教程中涉及的代码也可以在项目中找到,后续会持续更新更多的优质内容,欢迎⭐️。 如果使用我们教程的内容或图片,请在文章醒目位置注明我们的github主页链接:https://github.

【深度学习】搞懂 Vision Transformer 原理和代码,看这篇技术综述就够了-爱代码爱编程

  作者丨科技猛兽 编辑丨极市平台 导读  本文对Vision Transformer的原理和代码进行了非常全面详细的解读,一切从Self-attention开始、Transformer的实现和代码以及Transformer+Detection:引入视觉领域的首创DETR。>>加入极市CV技术交流群,走在计算机视觉的最前沿 Tra

一份可视化特征图的代码-爱代码爱编程

前言 本文给大家分享一份我用的特征图可视化代码。 欢迎关注公众号CV技术指南,专注于计算机视觉的技术总结、最新技术跟踪、经典论文解读、CV招聘信息。 写在前面的话 特征图可视化是很多论文所需要做的一份工作,其作用可以是用于证明方法的有效性,也可以是用来增加工作量,给论文凑字数。 具体来说就是可视化两个图,使用了新方法的和使用之前的

[深度学习]如何替换YoloV5的主干网络:Flexible-Yolov5-爱代码爱编程

Flexible-Yolov5:可自定义主干网络的YoloV5工程实践 本文目录: 概述理论学习与环境配置准备自己的数据集修改或调整自定义的主干网络部署训练一、概述 YoloV5的主干网络是优秀的,但是许多时候默认的DarkNet并不能满足我们的需求,包括科研、立项时需要更多的创新性。而Yolo框架出色的集成了许多目标检测相关的功能与输出,很容易让人

深度学习与cv教程(12) | 目标检测 (两阶段,r-cnn系列)_pythonxxoo的博客-爱代码爱编程

🚀 优质资源分享 🚀 学习路线指引(点击解锁)知识定位人群定位🧡 Python实战微信订餐小程序 🧡进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。💛Python量化交易实战💛入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 作者:韩信子@ShowMeAI教程地址:http:

大盘点 | 基于range-view的数据处理及3d检测算法_自动驾驶之心的博客-爱代码爱编程

点击下方卡片,关注“自动驾驶之心”公众号 ADAS巨卷干货,即可获取 点击进入→自动驾驶之心技术交流群 后台回复【自动驾驶课程】获取全套图宾根大学自动驾驶入门课程! 基于Range-View的数据处理及3D检测算法汇总 0.为什么采用range-view? 相比于Point View或BEV而言Range image具有紧凑性,因为这两种表

[ 目标检测 ] 经典网络模型3——faster r-爱代码爱编程

🤵 Author :Horizon Max ✨ 编程技巧篇:各种操作小结 🎇 机器视觉篇:会变魔术 OpenCV 💥 深度学习篇:简单入门 PyTorch 🏆 神经网络篇:经典网络模型 💻 算法篇:再忙也别忘了

poly-爱代码爱编程

点击上方“计算机视觉工坊”,选择“星标” 干货第一时间送达 作者丨Edison_G 来源丨计算机视觉研究院  论文地址:https://arxiv.org/pdf/2005.13243.pdf 源代码:https://gitlab.com/irafm-ai/poly-yolo YOLOv3改进版来了!与YO