在模型实际训练过程中,我发现了个问题:在yolov8模型的验证环节,采用自带验证代码计算得到AP值会与通过COCO数据集官方接口pycocotools计算得到的AP存在几个百分点的差距。
分析
接下来,针对这两个问题会进行分析及实验。
1. 通过对yolov8和pycocotools关于AP计算的方式进行对比,发现两者的差异在于获取PR曲线采样点时是否采用线性插值的方式。
yolov8采用线性插值:
pycocotools采用临近真值:
AP的计算需要采样点绘制出PR曲线,其中R∈[0:.01:1],共需采样101点。因为PR的原始真值点并不是按照R均匀分布,数量也不固定,所以需要在原始真值点的基础上采样出101个点用于计算AP。
在R依次从0均匀采样到1的过程中,遇到没有对应P真值的情况时,yolov8采用的线性插值方式会寻找左右临近两个真值点通过线性插值计算得到采样点对应P值,而pycocotools采用的临近真值方式则是寻找最接近采样点的真值点的P值作为采样点P值。最后对101个采样得到的P值取均值得到AP。
pycocotools采用的临近真值方式会更加合理,因为参与计算的P值全部是真值,而yolov8采用的线性插值方式会存在估值误差。另外,pycocotools作为COCO官方接口使用也更广泛。
针对yolov8的AP计算代码做以下修改即可达到和pycocotools相同的结果:
method = 'searchsorted'
if method == 'interp':
x = np.linspace(0, 1, 101) # 101-point interp (COCO)
ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate
elif method == 'searchsorted':
q = np.zeros((101,))
x = np.linspace(0, 1, 101) # 101-point interp (COCO)
inds = np.searchsorted(recall, x, side='left')
try:
for ri, pi in enumerate(inds):
q[ri] = precision[pi]
except:
pass
q_array = np.array(q)
ap = np.mean(q_array[q_array > -1])
else: # 'continuous'
i = np.where(mrec[1:] != mrec[:-1])[0] # points where x-axis (recall) changes
ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) # area under curve
return ap, mpre, mrec
https://mp.weixin.qq.com/s/JjuVSMaugMa2GEiBzOhI2Q
最后:
如果你想要进一步了解更多的相关知识,可以关注下面公众号联系~会不定期发布相关设计内容包括但不限于如下内容:信号处理、通信仿真、算法设计、matlab appdesigner,gui设计、simulink仿真......希望能帮到你!