• 【源码解读】YOLO v3


      前几日YOLO系列迎来了YOLOv4,再来回看一遍YOLOv3。

    anchor box

      YOLO v1中,bounding-box做回归时没有限制,导致可能会预测一个距离很远的object,效率不高。在YOLO v2中,开始引入了anchor box的概念,只对网格邻近的object负责正所谓各司其职

      anchor-box用于在边界框预测时,通过伸缩、平移变换,最终能够标定该物体。其尺寸大小的设定,对于网络的运行效率影响较大。因为图像中不同类型的特殊形状的物体,通常在图像中呈现的大小是不尽相同的(有的物体大,有的物体小)。因此,有必要对训练数据集设定适合其anchor-box的大小(即anchor-box的宽高)。K-Means便可以用于解决这一问题

      (此时不需要对图像进行416的处理 ,只需要标记的数据)  

    数据准备

      在数据集标定的过程中,产生的样本集中包含 数据的路径、标定图像四周的坐标、以及标定的类别编码(4+classe), 如下所示,路径与标定信息按照空格分隔

    1 D:keras-yolo3-master-person/VOCdevkit/VOC2007/JPEGImages/person0000.jpg 115,93,414,519,0

      在YOLO v3中,有三种尺度的预测,每种尺度根据其大小赋予其相应大小的anchor-box,即共需要9个anchor-box,这就决定了在K-Means中的聚类个数为9类。  

    K-Means代码的梳理:

    代码主线:

    1 def txt2clusters(self):
    2     all_boxes = self.txt2boxes()      # 将txt中数值信息转化为图像标记框的宽高,并返回
    3     result = self.kmeans(all_boxes, k=self.cluster_number)
    4     result = result[np.lexsort(result.T[0, None])]
    5     self.result2txt(result)
    6     print("K anchors:
     {}".format(result))
    7     print("Accuracy: {:.2f}%".format(
    8         self.avg_iou(all_boxes, result) * 100))

    1. 获取训练样本标定数据框的宽高信息 self.txt2boxes()

      逐行读取文件,按空格将路径和信息分隔。对信息中四周的坐标进行计算(右-左;下-上),获取宽高信息,最终返回宽、高的二维数组。

     1 for line in f:
     2     infos = line.split(" ")
     3     length = len(infos)
     4     for i in range(1, length):
     5         width = int(infos[i].split(",")[2]) - 
     6             int(infos[i].split(",")[0])
     7         height = int(infos[i].split(",")[3]) - 
     8             int(infos[i].split(",")[1])
     9         dataSet.append([width, height])
    10     result = np.array(dataSet)

    2. 对获取到的宽高信息进行聚类self.kmeans(all_boxes, k=self.cluster_number)

    聚类过程:

    1)随机选取k个类中心

      首先,在宽高信息中,随机选取k个类中心。

    1 clusters = boxes[np.random.choice(box_number, k, replace=False)]

    2) 计算各点到类中心的距离

      传统的聚类是计算各样本到各类中心的距离,将样本归为到类中心最近的类。最终的目的是使得属于某一类的样本到类中心的距离越小越好。

      此处,由于样本信息是宽高,是一个具体的形状。此处采用的是IOU越大越好,为了与聚类的选择方式相同 此处采用d=1-IOU 越小越好

    1 distances = 1 - self.iou(boxes, clusters)

      IOU的实现 实际上式通过面积的计算来衡量的交集和并集的比例,下图所示的是理解这么做是交集和并集的示例,红色的为类中心的框,黑色的是3个示例样本。

     1 box_area = boxes[:, 0] * boxes[:, 1]    # 把要聚类的框的宽高相乘,作为了一个box_area
     2 box_area = box_area.repeat(k)     # 要算到k个类中心的距离,需要搞一个每个都有k个的矩阵
     3 box_area = np.reshape(box_area, (n, k))
     4 
     5 cluster_area = clusters[:, 0] * clusters[:, 1]
     6 cluster_area = np.tile(cluster_area, [1, n])
     7 cluster_area = np.reshape(cluster_area, (n, k))
     8 # 把box和cluster的宽都整理成n行k列的形式,并把两者做比较,最后还是一个n行k列的形式,这个
     9 # 过程其实在比较box和两个cluster的宽,并选出小的
    10 box_w_matrix = np.reshape(boxes[:, 0].repeat(k), (n, k))
    11 cluster_w_matrix = np.reshape(np.tile(clusters[:, 0], (1, n)), (n, k))
    12 min_w_matrix = np.minimum(cluster_w_matrix, box_w_matrix)
    13 # 把box和cluster的高都整理成n行k列的形式,并把两者做比较,最后还是一个n行k列的形式,这个
    14 # 过程其实在比较box和两个cluster的高,并选出小的
    15 box_h_matrix = np.reshape(boxes[:, 1].repeat(k), (n, k))
    16 cluster_h_matrix = np.reshape(np.tile(clusters[:, 1], (1, n)), (n, k))
    17 min_h_matrix = np.minimum(cluster_h_matrix, box_h_matrix)
    18 # 将筛选出来的小的宽高 相乘
    19 inter_area = np.multiply(min_w_matrix, min_h_matrix)
    20 
    21 result = inter_area / (box_area + cluster_area - inter_area)  

    3)类中心的更新

      为了避免标记的物体中,框存在特别小,或者特别大的情况,在类中心的更新中,采用的是聚到一类中的个体的中位数,而不是均值。如下述代码所示,dist设置的是median(中位数)。

    1 def kmeans(self, boxes, k, dist=np.median):
    2     ...
    3     for cluster in range(k):
    4         clusters[cluster] = dist(boxes[current_nearest == cluster], axis=0) 
  • 相关阅读:
    C# Nugut CsvHelper 使用
    C# 读写txt
    Js打开QQ聊天对话窗口
    Js 读写Cookies
    js 计算时间差
    C# 读取CSV文件
    使用 SqlBulkCopy 批量插入数据
    sql 添加列并设置默认值
    C# 获取Enum 描述和值集合
    SQL连接其它服务器操作
  • 原文地址:https://www.cnblogs.com/monologuesmw/p/12761653.html
Copyright © 2020-2023  润新知