0
点赞
收藏
分享

微信扫一扫

【CV源码与项目实现】darknet yolov3中anchor box的理解

小_北_爸 2022-07-18 阅读 64

前言

训练定制数据集之后,测试发现bbox框的位置有时候不准确,当然与定制数据集的大小有很大关系,另外,是否也和模型参数配置有关呢?!

anchorbox的理解

1. 修改主干部分的模型参数,还能使用预训练权重吗?

修改了主干的话,如果不是用的现有的网络,基本上预训练权重是不能用的,要么就自己判断权值里卷积核的shape然后自己匹配,要么只能自己预训练去了;修改了后半部分的话,前半部分的主干部分的预训练权重还是可以用的。

答:一般来讲,网络从0开始的训练效果会很差,因为权值太过随机,特征提取效果不明显,因此非常、非常、非常不建议大家从0开始训练!如果一定要从0开始,可以了解imagenet数据集,首先训练分类模型,获得网络的主干部分权值,分类模型的 主干部分 和该模型通用,基于此进行训练。 网络修改了主干之后也是同样的问题,随机的权值效果很差。

 

2. anchorbox的引入

首先可以把anchor理解为:多尺度滑动窗口。

传统的检测过程是:

step1. 生成图像金字塔,因为待检测的物体的scale是变化的。

step2. 用滑动窗口在图片的特征金字塔上面滚动生成很多候选区域。

step3. 各种特征提取hog和分类器svm来对上面产生的候选区域中的图片信息来分类。

step4. NMS非极大值抑制得到最后的结果。

但由于cnn具有强大的提取特征的能力,可以替代第三步,但第一第二步独立于cnn之外的,需要大量循环,速度也限制了,因此要更好的定位,需要更多的scale和ratio不同窗口,但又增加了时间。而窗口滑动的时候,本质就是遍历像素的过程,因此直接为每个像素分配不同的尺度和比例的窗口矩形,它们的中心都是其所属的像素点。对于长度和比例的分配们可以根据标注图像信息通过k-means聚类得到。而每个像素分配几个不同长度和比例的窗口矩形框就是Anchor。一般模型的anchor非常多,因此可以看这些anchor与给定矩形的IOU是否满足条件来决定是否是所要的框。

3. anchorbox先验参数计算

排序;

 get_anchor.py

【CV源码与项目实现】darknet yolov3中anchor box的理解_权值

【CV源码与项目实现】darknet yolov3中anchor box的理解_权值_02

# -*- coding=utf-8 -*-
import glob
import os
import sys
import xml.etree.ElementTree as ET
import numpy as np
from kmeans import kmeans, avg_iou

# 根文件夹
ROOT_PATH = './tfl_dataset/'
# 聚类的数目
CLUSTERS = 6
# 模型中图像的输入尺寸,默认是一样的
SIZE = 416

# 加载YOLO格式的标注数据
def load_dataset(path):
jpegimages = os.path.join(path, 'JPEGImages')
if not os.path.exists(jpegimages):
print('no JPEGImages folders, program abort')
# sys.exit(0)
labels_txt = os.path.join(path, 'labels')
if not os.path.exists(labels_txt):
print('no labels folders, program abort')
sys.exit(0)

label_file = os.listdir(labels_txt)
print('label count: {}'.format(len(label_file)))
dataset = []

for label in label_file:
with open(os.path.join(labels_txt, label), 'r') as f:
txt_content = f.readlines()

for line in txt_content:
line_split = line.split(' ')
roi_with = float(line_split[len(line_split)-2])
roi_height = float(line_split[len(line_split)-1])
if roi_with == 0 or roi_height == 0:
continue
dataset.append([roi_with, roi_height])
# print([roi_with, roi_height])

return np.array(dataset)

data = load_dataset(ROOT_PATH)
out = kmeans(data, k=CLUSTERS)

print(out)
print("Accuracy: {:.2f}%".format(avg_iou(data, out) * 100))
print("Boxes:\n {}-{}".format(out[:, 0] * SIZE, out[:, 1] * SIZE))

ratios = np.around(out[:, 0] / out[:, 1], decimals=2).tolist()
print("Ratios:\n {}".format(sorted(ratios)))

View Code

kmeans.py

【CV源码与项目实现】darknet yolov3中anchor box的理解_权值

【CV源码与项目实现】darknet yolov3中anchor box的理解_权值_02

import numpy as np


def iou(box, clusters):
"""
Calculates the Intersection over Union (IoU) between a box and k clusters.
:param box: tuple or array, shifted to the origin (i. e. width and height)
:param clusters: numpy array of shape (k, 2) where k is the number of clusters
:return: numpy array of shape (k, 0) where k is the number of clusters
"""
x = np.minimum(clusters[:, 0], box[0])
y = np.minimum(clusters[:, 1], box[1])
if np.count_nonzero(x == 0) > 0 or np.count_nonzero(y == 0) > 0:
raise ValueError("Box has no area")

intersection = x * y
box_area = box[0] * box[1]
cluster_area = clusters[:, 0] * clusters[:, 1]

iou_ = intersection / (box_area + cluster_area - intersection)

return iou_


def avg_iou(boxes, clusters):
"""
Calculates the average Intersection over Union (IoU) between a numpy array of boxes and k clusters.
:param boxes: numpy array of shape (r, 2), where r is the number of rows
:param clusters: numpy array of shape (k, 2) where k is the number of clusters
:return: average IoU as a single float
"""
return np.mean([np.max(iou(boxes[i], clusters)) for i in range(boxes.shape[0])])


def translate_boxes(boxes):
"""
Translates all the boxes to the origin.
:param boxes: numpy array of shape (r, 4)
:return: numpy array of shape (r, 2)
"""
new_boxes = boxes.copy()
for row in range(new_boxes.shape[0]):
new_boxes[row][2] = np.abs(new_boxes[row][2] - new_boxes[row][0])
new_boxes[row][3] = np.abs(new_boxes[row][3] - new_boxes[row][1])
return np.delete(new_boxes, [0, 1], axis=1)


def kmeans(boxes, k, dist=np.median):
"""
Calculates k-means clustering with the Intersection over Union (IoU) metric.
:param boxes: numpy array of shape (r, 2), where r is the number of rows
:param k: number of clusters
:param dist: distance function
:return: numpy array of shape (k, 2)
"""
rows = boxes.shape[0]

distances = np.empty((rows, k))
last_clusters = np.zeros((rows,))

np.random.seed()

# the Forgy method will fail if the whole array contains the same rows
clusters = boxes[np.random.choice(rows, k, replace=False)]

while True:
for row in range(rows):
distances[row] = 1 - iou(boxes[row], clusters)

nearest_clusters = np.argmin(distances, axis=1)

if (last_clusters == nearest_clusters).all():
break

for cluster in range(k):
clusters[cluster] = dist(boxes[nearest_clusters == cluster], axis=0)

last_clusters = nearest_clusters

return

View Code

 

 

4. anchor参数如何设置?

 

5. 更改anchor参数,可以使用预训练权重嘛???

 只更改测试阶段的anchor参数,也是可以进行测试的。。

 

参考

1. YOLO-v3模型参数anchor设置;

2. YOLOv3中Anchor理解;

3. ​​kmeans-anchor-boxes​​;

举报

相关推荐

0 条评论