首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

yolov5 anchors设置详解

  • 24-03-17 21:10
  • 3972
  • 9422
blog.csdn.net

yolov5中增加了自适应锚定框(Auto Learning Bounding Box Anchors),而其他yolo系列是没有的。

一、默认锚定框

Yolov5 中默认保存了一些针对 coco数据集的预设锚定框,在 yolov5 的配置文件*.yaml 中已经预设了640×640图像大小下锚定框的尺寸(以 yolov5s.yaml 为例):

  1. # anchors
  2. anchors:
  3. - [10,13, 16,30, 33,23] # P3/8
  4. - [30,61, 62,45, 59,119] # P4/16
  5. - [116,90, 156,198, 373,326] # P5/32

 anchors参数共有三行,每行9个数值;且每一行代表应用不同的特征图;
1、第一行是在最大的特征图上的锚框

2、第二行是在中间的特征图上的锚框

3、第三行是在最小的特征图上的锚框;

在目标检测任务中,一般希望在大的特征图上去检测小目标,因为大特征图才含有更多小目标信息,因此大特征图上的anchor数值通常设置为小数值,而小特征图上数值设置为大数值检测大的目标。
 

二、自定义锚定框

1、训练时自动计算锚定框

yolov5 中不是只使用默认锚定框,在开始训练之前会对数据集中标注信息进行核查,计算此数据集标注信息针对默认锚定框的最佳召回率,当最佳召回率大于或等于0.98,则不需要更新锚定框;如果最佳召回率小于0.98,则需要重新计算符合此数据集的锚定框。

核查锚定框是否适合要求的函数在 /utils/autoanchor.py 文件中:

def check_anchors(dataset, model, thr=4.0, imgsz=640):

 其中 thr 是指 数据集中标注框宽高比最大阈值,默认是使用 超参文件 hyp.scratch.yaml 中的 “anchor_t” 参数值。

核查主要代码如下:

  1. def metric(k): # compute metric
  2. r = wh[:, None] / k[None]
  3. x = torch.min(r, 1. / r).min(2)[0] # ratio metric
  4. best = x.max(1)[0] # best_x
  5. aat = (x > 1. / thr).float().sum(1).mean() # anchors above threshold
  6. bpr = (best > 1. / thr).float().mean() # best possible recall
  7. return bpr, aat
  8. bpr, aat = metric(m.anchor_grid.clone().cpu().view(-1, 2))

其中两个指标需要解释一下(bpr 和 aat):

bpr(best possible recall) 

aat(anchors above threshold) 

 其中 bpr 参数就是判断是否需要重新计算锚定框的依据(是否小于 0.98)。

重新计算符合此数据集标注框的锚定框,是利用 kmean聚类方法实现的,代码在  /utils/autoanchor.py 文件中:

  1. def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True):
  2. """ Creates kmeans-evolved anchors from training dataset
  3. Arguments:
  4. path: path to dataset *.yaml, or a loaded dataset
  5. n: number of anchors
  6. img_size: image size used for training
  7. thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0
  8. gen: generations to evolve anchors using genetic algorithm
  9. verbose: print all results
  10. Return:
  11. k: kmeans evolved anchors
  12. Usage:
  13. from utils.autoanchor import *; _ = kmean_anchors()
  14. """
  15. thr = 1. / thr
  16. prefix = colorstr('autoanchor: ')
  17. def metric(k, wh): # compute metrics
  18. r = wh[:, None] / k[None]
  19. x = torch.min(r, 1. / r).min(2)[0] # ratio metric
  20. # x = wh_iou(wh, torch.tensor(k)) # iou metric
  21. return x, x.max(1)[0] # x, best_x
  22. def anchor_fitness(k): # mutation fitness
  23. _, best = metric(torch.tensor(k, dtype=torch.float32), wh)
  24. return (best * (best > thr).float()).mean() # fitness
  25. def print_results(k):
  26. k = k[np.argsort(k.prod(1))] # sort small to large
  27. x, best = metric(k, wh0)
  28. bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr
  29. print(f'{prefix}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr')
  30. print(f'{prefix}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, '
  31. f'past_thr={x[x > thr].mean():.3f}-mean: ', end='')
  32. for i, x in enumerate(k):
  33. print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg
  34. return k
  35. if isinstance(path, str): # *.yaml file
  36. with open(path) as f:
  37. data_dict = yaml.load(f, Loader=yaml.SafeLoader) # model dict
  38. from utils.datasets import LoadImagesAndLabels
  39. dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True)
  40. else:
  41. dataset = path # dataset
  42. # Get label wh
  43. shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True)
  44. wh0 = np.concatenate([l[:, 3:5] * s for s, l in zip(shapes, dataset.labels)]) # wh
  45. # Filter
  46. i = (wh0 < 3.0).any(1).sum()
  47. if i:
  48. print(f'{prefix}WARNING: Extremely small objects found. {i} of {len(wh0)} labels are < 3 pixels in size.')
  49. wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels
  50. # wh = wh * (np.random.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1
  51. # Kmeans calculation
  52. print(f'{prefix}Running kmeans for {n} anchors on {len(wh)} points...')
  53. s = wh.std(0) # sigmas for whitening
  54. k, dist = kmeans(wh / s, n, iter=30) # points, mean distance
  55. k *= s
  56. wh = torch.tensor(wh, dtype=torch.float32) # filtered
  57. wh0 = torch.tensor(wh0, dtype=torch.float32) # unfiltered
  58. k = print_results(k)
  59. # Plot
  60. # k, d = [None] * 20, [None] * 20
  61. # for i in tqdm(range(1, 21)):
  62. # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance
  63. # fig, ax = plt.subplots(1, 2, figsize=(14, 7), tight_layout=True)
  64. # ax = ax.ravel()
  65. # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.')
  66. # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh
  67. # ax[0].hist(wh[wh[:, 0]<100, 0],400)
  68. # ax[1].hist(wh[wh[:, 1]<100, 1],400)
  69. # fig.savefig('wh.png', dpi=200)
  70. # Evolve
  71. npr = np.random
  72. f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma
  73. pbar = tqdm(range(gen), desc=f'{prefix}Evolving anchors with Genetic Algorithm:') # progress bar
  74. for _ in pbar:
  75. v = np.ones(sh)
  76. while (v == 1).all(): # mutate until a change occurs (prevent duplicates)
  77. v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0)
  78. kg = (k.copy() * v).clip(min=2.0)
  79. fg = anchor_fitness(kg)
  80. if fg > f:
  81. f, k = fg, kg.copy()
  82. pbar.desc = f'{prefix}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}'
  83. if verbose:
  84. print_results(k)
  85. return print_results(k)

对 kmean_anchors()函数中的参数做一下简单解释(代码中已经有了英文注释):

  • path:包含数据集文件路径等相关信息的 yaml 文件(比如 coco128.yaml), 或者 数据集张量(yolov5 自动计算锚定框时就是用的这种方式,先把数据集标签信息读取再处理)
  • n:锚定框的数量,即有几组;默认值是9
  • img_size:图像尺寸。计算数据集样本标签框的宽高比时,是需要缩放到 img_size 大小后再计算的;默认值是640
  • thr:数据集中标注框宽高比最大阈值,默认是使用 超参文件 hyp.scratch.yaml 中的 “anchor_t” 参数值;默认值是4.0;自动计算时,会自动根据你所使用的数据集,来计算合适的阈值。
  • gen:kmean聚类算法迭代次数,默认值是1000
  • verbose:是否打印输出所有计算结果,默认值是true

如果你不想自动计算锚定框,可以在 train.py 中设置参数即可:

parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check')

 

2、训练前手动计算锚定框

如果使用 yolov5 训练效果并不好(排除其他原因,只考虑 “预设锚定框” 这个因素), yolov5在核查默认锚定框是否符合要求时,计算的最佳召回率大于0.98,没有自动计算锚定框;此时你可以自己手动计算锚定框。【即使自己的数据集中目标宽高比最大值小于4,默认锚定框也不一定是最合适的】

 首先可以自行编写一个程序,统计一下你所训练的数据集所有标签框宽高比,看下宽高比主要分布在哪个范围、最大宽高比是多少? 比如:你使用的数据集中目标宽高比最大达到了 5:1(甚至 10:1) ,那肯定需要重新计算锚定框了,针对coco数据集的最大宽高比是 4:1 。

然后在 yolov5 程序中创建一个新的 python 文件 test.py,手动计算锚定框:

  1. import utils.autoanchor as autoAC
  2. # 对数据集重新计算 anchors
  3. new_anchors = autoAC.kmean_anchors('./data/mydata.yaml', 9, 640, 5.0, 1000, True)
  4. print(new_anchors)

输入信息如下(只截取了部分):

  1. autoanchor: Evolving anchors with Genetic Algorithm: fitness = 0.6604: 87%|████████▋ | 866/1000 [00:00<00:00, 2124.00it/s]autoanchor: thr=0.25: 0.9839 best possible recall, 3.84 anchors past thr
  2. autoanchor: n=9, img_size=640, metric_all=0.267/0.662-mean/best, past_thr=0.476-mean: 15,20, 38,25, 55,65, 131,87, 97,174, 139,291, 256,242, 368,382, 565,422
  3. autoanchor: thr=0.25: 0.9849 best possible recall, 3.84 anchors past thr
  4. autoanchor: n=9, img_size=640, metric_all=0.267/0.663-mean/best, past_thr=0.476-mean: 15,20, 39,26, 54,64, 127,87, 97,176, 142,286, 257,245, 374,379, 582,424
  5. autoanchor: thr=0.25: 0.9849 best possible recall, 3.84 anchors past thr
  6. autoanchor: n=9, img_size=640, metric_all=0.267/0.663-mean/best, past_thr=0.476-mean: 15,20, 39,26, 54,63, 126,86, 97,176, 143,285, 258,241, 369,381, 583,424
  7. autoanchor: thr=0.25: 0.9849 best possible recall, 3.84 anchors past thr
  8. autoanchor: n=9, img_size=640, metric_all=0.267/0.663-mean/best, past_thr=0.476-mean: 15,20, 39,26, 54,63, 127,86, 97,176, 143,285, 258,241, 369,380, 583,424
  9. autoanchor: thr=0.25: 0.9849 best possible recall, 3.84 anchors past thr
  10. autoanchor: n=9, img_size=640, metric_all=0.267/0.663-mean/best, past_thr=0.476-mean: 15,20, 39,26, 53,63, 127,86, 97,175, 143,284, 257,243, 369,381, 582,422
  11. autoanchor: thr=0.25: 0.9849 best possible recall, 3.84 anchors past thr
  12. autoanchor: n=9, img_size=640, metric_all=0.267/0.663-mean/best, past_thr=0.476-mean: 15,20, 40,26, 53,62, 129,85, 96,175, 143,287, 256,240, 370,378, 582,419
  13. autoanchor: Evolving anchors with Genetic Algorithm: fitness = 0.6605: 100%|██████████| 1000/1000 [00:00<00:00, 2170.29it/s]
  14. Scanning '..\coco128\labels\train2017.cache' for images and labels... 128 found, 0 missing, 2 empty, 0 corrupted: 100%|██████████| 128/128 [00:00<?, ?it/s]
  15. autoanchor: thr=0.25: 0.9849 best possible recall, 3.84 anchors past thr
  16. autoanchor: n=9, img_size=640, metric_all=0.267/0.663-mean/best, past_thr=0.476-mean: 15,20, 40,26, 53,62, 129,85, 96,175, 143,287, 256,240, 370,378, 582,419
  17. [[ 14.931 20.439]
  18. [ 39.648 25.53]
  19. [ 53.371 62.35]
  20. [ 129.07 84.774]
  21. [ 95.719 175.08]
  22. [ 142.69 286.95]
  23. [ 256.46 239.83]
  24. [ 369.9 378.3]
  25. [ 581.87 418.56]]
  26. Process finished with exit code 0

输出的 9 组新的锚定框即是根据自己的数据集来计算的,可以按照顺序替换到你所使用的配置文件*.yaml中(比如 yolov5s.yaml)。就可以重新训练了。

参考的博文(表示感谢!):

https://github.com/ultralytics/yolov5

http://iyenn.com/rec/2144252.html

https://zhuanlan.zhihu.com/p/183838757

https://blog.csdn.net/aabbcccddd01/article/details/109578614

注:本文转载自blog.csdn.net的高祥xiang的文章"https://blog.csdn.net/qq_27278957/article/details/120036450"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top