yolo v5_anchor设计
1.评估函数
def metric(k): # compute metric
# wh为GT的宽度和高度,形状为(N,9,2); k为anchor,形状为(9,2), r形状为(N, 9, 2) r = wh[:, None] / k[None]
# (N,9,2)按维度2求最小值,即GT的宽高分别和预测的anchor宽高比值按照 9 所有anchor值得维度的最小值,输出形状为(N, 9) x = torch.min(r, 1 / r).min(2)[0] # ratio metric
# (N, 9)按维度1求最大值,输出形状N best = x.max(1)[0] # best_x
aat = (x > 1 / thr).float().sum(1).mean() # anchors above threshold # thr为设置的超参阈值,anchor wh比例阈值, 当best中每行的值大于该阈值,被认为可以召回,来计算召回率
bpr = (best > 1 / thr).float().mean() # best possible recall return bpr, aat
2. anchor计算 -下面为计算anchor核心代码
# wh0为所有GT的宽度和高度,形状为(N,2)
wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels
#(N,2)按照 行维度分别计算宽度和高度的标准差,s形状为(2)
s = wh.std(0) # sigmas for whitening
# (N,2)除以标准差之后进行kmean聚类,类别数为n=9,输出k为n=9个聚类的中心,形状为(9,2) 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
# 下面的操作就是在聚类出来得点进行细微的扰动,得到最终的anchor
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) # 对得到的anchor进行细微的扰动 kg = (k.copy() * v).clip(min=2.0)
# 通过评估函数,计算召回率 fg = anchor_fitness(kg)
# 召回比之前的anchor好,本次计算的anchor就是结果 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, verbose)