IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 《动手学深度学习》13.4锚框 -> 正文阅读

[人工智能]《动手学深度学习》13.4锚框

13.4.1生成多个锚框

参考: 13.4.1生成多个锚框.

Alt

代码实现

  • 导入功能包
import torch
import matplotlib.pyplot as plt
# 精简打印精度,保留两位小数
torch.set_printoptions(precision=2)  
  • 定义生成以每个像素为中心具有不同形状的锚框函数
# 指定输入、一组大小和一组宽高比,该函数将返回输入的所有锚框
def multibox_prior(feature_map, sizes, ratios):
    """生成以每个像素为中心具有不同形状的锚框。"""
    # 输入图像(特征图)的高和宽
    in_height, in_width = feature_map.shape[-2:]
    # 指定设备
    device = feature_map.device
    # 将比例s和高宽比r转换为tensor,用于后面的tensor计算
    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)
    # 通过在matplotlib中进行可视化,来查看函数运行后得到的网格化数据的结果
    # plt.plot(shift_x, shift_y, marker='.', color='red', linestyle="none",markersize="0.1")
    # plt.show()

    # 生成“n+m-1”个高和宽,之后用于创建锚框的四角坐标 (xmin, xmax, ymin, ymax)
    anc_w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),
                   sizes[0] * torch.sqrt(ratio_tensor[1:])))
    anc_h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]),
                   sizes[0] / torch.sqrt(ratio_tensor[1:])))

    # 除以2来获得半宽和半高,应该有hw个[5,4]
    anchor_manipulations = torch.stack([-anc_w, -anc_h, anc_w, anc_h], axis=1) / 2 # torch.Size([5, 4])
    # 每个中心点都将有“n+m-1”个锚框,所以生成含所有锚框中心的网格为[5hw,4]
    out_grid = torch.stack([shift_x, shift_y, shift_x, shift_y],dim=1) # torch.Size([hw, 4])

    # 广播机制out_grid [hw, 4]->[hw,1,4] anchor_manipulations:[5,4]->[1,5,4]
    anchors = out_grid.reshape((-1, 1, 4)) + anchor_manipulations.reshape((1, -1, 4)) #[hw,5,4]
    # 返回锚框的变量的形状是[批量大小,锚框的数量,4]
    return anchors.reshape(1,-1,4) #[1,5hw,4]
  • 测试
img = plt.imread('../img/catdog.jpg')
h, w = img.shape[:2]
X = torch.rand(size=(1, 3, h, w))
Y = multibox_prior(X, sizes=[0.75, 0.5, 0.25], ratios=[1, 2, 0.5])
print("Y.shape",Y.shape)
# 将锚框变量 Y 的形状更改为(图像高度、图像宽度、以同一像素为中心的锚框的数量,4)
boxes = Y.reshape(h, w, 5, 4)
print(boxes.shape)
# 获得以指定像素的位置为中心的所有锚框
# 访问以(250,250)为中心的第一个锚框的四个坐标点
res = boxes[250, 250, 0, :]
# tensor([-0.03,  0.07,  0.72,  0.82])
print("第一个锚框坐标",res)
# 可以验证以上输出对不对:size和ratio分别为0.75和1,则(归一化后的)宽和高均为0.75,
# 所以输出是正确的 0.75 = 0.82-0.07 = 0.71 + 0.03
res_w = res[3] - res[1]
res_h = res[2] - res[0]
print(res_w == res_h) # True

13.4.2交并比

Alt

  • 代码实现
# 计算交并比函数
def box_iou(boxes1, boxes2):
    """计算两个锚框或边界框列表中成对的交并比。"""
    # 计算一个框的面积(长X宽)
    box_area = lambda boxes: ((boxes[:, 2] - boxes[:, 0]) *
                              (boxes[:, 3] - boxes[:, 1]))
    # 分别计算给定锚框的面积
    areas1 = box_area(boxes1)
    areas2 = box_area(boxes2)
    # 计算两个锚框重叠部分的坐标
    inter_upperlefts = torch.max(boxes1[:, None, :2], boxes2[:, :2]) # 重叠部分左上角坐标
    inter_lowerrights = torch.min(boxes1[:, None, 2:], boxes2[:, 2:]) # 重叠部分右下角坐标
    inters = (inter_lowerrights - inter_upperlefts).clamp(min=0)
    # 计算相交面积
    inter_areas = inters[:, :, 0] * inters[:, :, 1]
    # 相并面积
    union_areas = areas1[:, None] + areas2 - inter_areas
    # 交并比=相交面积/相并面积
    return inter_areas / union_areas
  • 测试
    Alt
# 测试
box1 = torch.tensor([100,100,200,200]).unsqueeze(0)
box2 = torch.tensor([120,120,220,220]).unsqueeze(0)
iou = box_iou(box1,box2)
print("交并比为:",iou)
  • 计算结果Alt

13.4.3标注训练数据的锚框

  • 算法原理
    Alt
  • 代码实现
# ground_truth真实边界框[nb,4]
# anchors待分配的锚框[na,4]
# iou_threshold预先设定的阈值
def assign_anchor_to_bbox(ground_truth, anchors, device, iou_threshold=0.5):
    """将最接近的真实边界框分配给锚框。"""
    # 锚框数量和真实边界框数量
    num_anchors, num_gt_boxes = anchors.shape[0], ground_truth.shape[0]
    # 位于第i行和第j列的元素 x_ij 是锚框i和真实边界框j的IoU
    jaccard = box_iou(anchors, ground_truth) # 计算交并比 [na,nb]
    """
    tensor([[0.0536, 0.0000],
        [0.1417, 0.0000],
        [0.0000, 0.5657],
        [0.0000, 0.2059],
        [0.0000, 0.7459]])
    """
    # 对于每个锚框,分配的真实边界框的张量
    # 存放标签初始全为-1
    anchors_bbox_map = torch.full((num_anchors,), -1, dtype=torch.long,device=device)
    # 先为每个bb分配一个anchor(不要求满足iou_threshold)
    jaccard_cp = jaccard.clone()
    # 将最大元素的行和列用-1代替,相当于丢弃这行这列的所有元素
    col_discard = torch.full((num_anchors,), -1)
    row_discard = torch.full((num_gt_boxes,), -1)
    # 先遍历每一个真实边界框,为它们找到交并比最大的那个锚框
    for _ in range(num_gt_boxes):
        # 获取数值最大的那个元素的索引
        max_idx = torch.argmax(jaccard_cp)
        # 列索引
        box_idx = (max_idx % num_gt_boxes).long()
        # 行索引
        anc_idx = (max_idx / num_gt_boxes).long()
        # 将真实边界框分配给锚框
        anchors_bbox_map[anc_idx] = box_idx
        # 把anc_idx行box_idx列元素变为-1
        jaccard_cp[:, box_idx] = col_discard
        jaccard_cp[anc_idx, :] = row_discard

    # 遍历剩余的na?nb个锚框
    # 处理还未被分配的anchor, 要求满足iou_threshold
    for i in range(num_anchors):
        # 索引等于初始值-1 的就是剩下的锚框
        if anchors_bbox_map[i] == -1:
            j = torch.argmax(jaccard[i, :])
            # 根据阈值,决定是否分配真实边界框
            if jaccard[i, j] >= iou_threshold:
                anchors_bbox_map[i] = j

    # 每个anchor分配的真实bb对应的索引, 若未分配任何bb则为-1
    return anchors_bbox_map
  • 算法理解
    Alt
  • 代码测试
# 真实边界框
ground_truth = torch.tensor([[0, 0.1, 0.08, 0.52, 0.92],
                             [1, 0.55, 0.2, 0.9, 0.88]])
# 待分配的锚框
anchors = torch.tensor([[0, 0.1, 0.2, 0.3], [0.15, 0.2, 0.4, 0.4],
                        [0.63, 0.05, 0.88, 0.98], [0.66, 0.45, 0.8, 0.8],
                        [0.57, 0.3, 0.92, 0.9]])

device = torch.device("cuda")
res = assign_anchor_to_bbox(ground_truth[:,1:], anchors, device=device)
print("res:",res)
  • 输出结果
res: tensor([-1,  0,  1, -1,  1], device='cuda:0')
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-08-07 12:05:08  更:2021-08-07 12:07:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年9日历 -2024/9/21 9:03:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码