yolov5目标检测代码,yolov3 anchor的数值设置
训练yolo网络检测目标时,需要根据待检测目标的位置和大小分布来调整锚,尽可能提高检测效果。下面这篇文章主要介绍YOLOv5目标探测的锚点设置的相关信息,有需要的可以参考一下。
00-1010锚的序言检查过程锚生成过程的总结
目录
Yolo算法作为one-stage领域的佼佼者,采用基于锚点的方法检测目标,使用不同尺度的锚点直接返回目标框,一次性输出目标框的位置和类别置信度。
为什么使用anchor进行检测?
一开始YOLOv1的初期训练过程很不稳定。在YOLOv2的设计过程中,笔者观察了大量图片的地面真相,发现同品类的目标实例有着相似的gt长宽比:比如汽车和gt都是又矮又胖的长方形;比如行人,gt都是又高又瘦的长方形。因此,受此启发,作者事先从数据集中准备了几个概率较大的包围盒,然后以此为基准进行预测。
前言
首先,yolov5使用的coco数据集的输入图片大小为640x640,但是训练过程的输入大小并不唯一,因为v5可以使用masaic增强技术将四张图片合并成一张一定大小的输入图片。但如果需要使用预训练权重,最好将输入图片大小调整为与作者相同的大小,并且输入图片大小必须是32的倍数,这与后面的锚点检测阶段有关。
上图是我自己画的v5 v6.0的网络结构图。当我们的输入大小为640*640时,会得到三种不同比例的输出:80x80(640/8)、40x40(640/16)、20x20(640/32),也就是上图中CSP2_3模块的输出。
主播:
-# P3/8
- [30,61,62,45,59,119] # P4/16
- [116,90,156,198,373,326] # P5/32
其中,80x80代表浅层特征图(P3),包含了更多的低层信息,适合检测小目标,因此该特征图使用的锚尺度较小;同样,20x20代表深度特征图(P5),包含了更多的轮廓、结构等高层信息,适用于大目标的检测,因此该特征图使用的锚尺度更大。在另一幅40x40特征地图(P4)上,这两个比例尺之间的锚点用于探测中型目标。yolov5之所以能高效快速地检测跨尺度目标,这种对不同特征图使用不同尺度的anchor的思想功不可没。
以上是yolov5中对主播的具体讲解。
anchor的检测过程
对于大多数图片,因为它们的大小与我们预设的输入大小不匹配,所以它们在输入阶段被调整大小,导致预先标记的边界框大小的改变。锚点是根据我们输入网络中包围盒的大小来计算的,所以在这个调整大小的过程中有一个锚点重新聚类的过程。在yolov5/utils/autoanchor.py文件下,有一个函数kmeans_anchor,锚是由kmeans计算的。如下所示:
def kmean_anchors(dataset=。/data/coco128.yaml ,n=9,img_size=640,thr=4.0,gen=1000,verbose=True):
根据训练数据集创建kmeans进化锚点
参数:
dataset : data . YAML或已加载数据集的路径
n:锚的数量
img_size:用于训练的图像大小
thr:锚-标签wh比率阈值超参数hyp[anchor_t]用于训练,默认值=4.0
gen:代进化锚定我们
ing genetic algorithm
verbose: print all results
Return:
k: kmeans evolved anchors
Usage:
from utils.autoanchor import *; _ = kmean_anchors()
"""
from scipy.cluster.vq import kmeans
thr = 1. / thr
prefix = colorstr(autoanchor: )
def metric(k, wh): # compute metrics
r = wh[:, None] / k[None]
x = torch.min(r, 1. / r).min(2)[0] # ratio metric
# x = wh_iou(wh, torch.tensor(k)) # iou metric
return x, x.max(1)[0] # x, best_x
def anchor_fitness(k): # mutation fitness
_, best = metric(torch.tensor(k, dtype=torch.float32), wh)
return (best * (best > thr).float()).mean() # fitness
def print_results(k):
k = k[np.argsort(k.prod(1))] # sort small to large
x, best = metric(k, wh0)
bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr
print(f{prefix}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr)
print(f{prefix}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best,
fpast_thr={x[x > thr].mean():.3f}-mean: , end=)
for i, x in enumerate(k):
print(%i,%i % (round(x[0]), round(x[1])), end=, if i < len(k) - 1 else \n) # use in *.cfg
return k
if isinstance(dataset, str): # *.yaml file
with open(dataset, errors=ignore) as f:
data_dict = yaml.safe_load(f) # model dict
from datasets import LoadImagesAndLabels
dataset = LoadImagesAndLabels(data_dict[train], augment=True, rect=True)
# Get label wh
shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True)
wh0 = np.concatenate([l[:, 3:5] * s for s, l in zip(shapes, dataset.labels)]) # wh
# Filter
i = (wh0 < 3.0).any(1).sum()
if i:
print(f{prefix}WARNING: Extremely small objects found. {i} of {len(wh0)} labels are < 3 pixels in size.)
wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels
# wh = wh * (np.random.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1
# Kmeans calculation
print(f{prefix}Running kmeans for {n} anchors on {len(wh)} points...)
s = wh.std(0) # sigmas for whitening
k, dist = kmeans(wh / s, n, iter=30) # points, mean distance
assert len(k) == n, f{prefix}ERROR: scipy.cluster.vq.kmeans requested {n} points but returned only {len(k)}
k *= s
wh = torch.tensor(wh, dtype=torch.float32) # filtered
wh0 = torch.tensor(wh0, dtype=torch.float32) # unfiltered
k = print_results(k)
# Plot
# k, d = [None] * 20, [None] * 20
# for i in tqdm(range(1, 21)):
# k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance
# fig, ax = plt.subplots(1, 2, figsize=(14, 7), tight_layout=True)
# ax = ax.ravel()
# ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker=.)
# fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh
# ax[0].hist(wh[wh[:, 0]<100, 0],400)
# ax[1].hist(wh[wh[:, 1]<100, 1],400)
# fig.savefig(wh.png, dpi=200)
# Evolve
npr = np.random
f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma
pbar = tqdm(range(gen), desc=f{prefix}Evolving anchors with Genetic Algorithm:) # progress bar
for _ in pbar:
v = np.ones(sh)
while (v == 1).all(): # mutate until a change occurs (prevent duplicates)
v = ((npr.random(sh) < mp) * random.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0)
kg = (k.copy() * v).clip(min=2.0)
fg = anchor_fitness(kg)
if fg > f:
f, k = fg, kg.copy()
pbar.desc = f{prefix}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}
if verbose:
print_results(k)
return print_results(k)
代码的注释部分其实已经对参数及调用方法解释的很清楚了,这里我只简单说一下:
Arguments:dataset: 数据的yaml路径
n: 类簇的个数
img_size: 训练过程中的图片尺寸(32的倍数)
thr: anchor的长宽比阈值,将长宽比限制在此阈值之内
gen: k-means算法最大迭代次数(不理解的可以去看k-means算法)
verbose: 打印参数
Usage:
from utils.autoanchor import *; _ = kmean_anchors()
总结
到此这篇关于YOLOv5目标检测之anchor设定的文章就介绍到这了,更多相关YOLOv5 anchor设定内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。