引 言 深度学习视觉识别任务在训练过程中的一个重要评价指标就是评估一批图像的模型预测类别与图像真实标签的匹配程度,匹配标签越多准确率越高。要想成为深度模型的资深玩家,就必须掌握最基础的视觉分类任务的准确率评价指标的方法函数,方便测评模型好坏。本文从原理和实现代码两方面对评价指标top@1和top@5进行介绍,由于代码的复用率比较高,文章最后部分粘贴了完整代码可以直接粘贴使用。
文章目录
一、top-1和top-5的含义
1.1 top-1 准确率
TOP-1 准确率是指模型的预测结果中的第一个预测(概率最高)是否与实际标签相符。如果模型的第一个预测与实际标签相符,则该图像被认为是正确分类的。TOP-1 准确率通常是最常用的分类性能指标。
1.2 top-5 准确率
与TOP-1准确率考虑不同,TOP-5准确率有更多的选择。在TOP-5准确率中,模型会按概率值从大到小顺序给出前五个预测结果,而图像被认为分类正确的前提是实际标签出现在这五个预测中的任何一个。TOP-5准确率通常适用于图像分类任务,其中图像包含许多相似的类别,使得正确分类更加困难。
1.3 top-1 错误率和top-5 错误率
top-1 错误率表示模型第一预测类别与真实标签的不匹配程度。top_1 错误率=1 - top-1 准确率
top-5错误率表示模型的前五个预测类别与真实标签的不匹配程度。top_5 错误率=1 - top-5 准确率
二、top-1和top-5的实现原理和代码
视觉识别、语义分割、目标检测等任务用的深度学习模型主要采用通道维度进行类别预测。对模型输出的 logits在通道维度上进行概率归一化处理(softmax\sigmoid),logits在通道维度上输出的向量数目必须与预测总类别数相同,这样才能够保证对于每个类别都有预测概率。根据预测概率值的大小提取对应的索引位置编号即为模型的优先预测类别。
- top@1预测
在图像分类任务中,B张图片的张量【B,C,W,H】经过模型卷积层、展平和全连接层处理后变成【B,C】二维张量,对通道维度上的数据采用torch.softmax(dim=1)
函数处理变成概率预测值,即每行元素和为1。每行数据预测概率值最大的索引为图像预测类别。下面代码模拟模型输出值的类别预测和计算top@1过程。四张图片的第一预测标签分别是【1,1,0,1】,与图像给出的真实标签【1, 0, 0, 1】进行比对,发现4张图像中有3张图像标签预测正确,top@1准确率为75%。
#模型输出4张图像logits
data = torch.randn(4,3)
print('data: \n{}'.format(data))
pred = data.softmax(dim=1)
print(f"pred: \n {pred}")
prob,indice = pred.max(dim=1)
print('预测概率:{} 预测类别索引:{}'.format(prob,indice))
target = torch.tensor([1,0,0,1]) #假设4张图像真实标签
print(f'target is :{target}')
#计算top-1准确率
top_1 = target.eq(indice).sum()/target.size(0)
print('top-1 accuracy is %.2f %%'%(top_1.item()*100))
###结果##
data:
tensor([[-0.8913, 0.4250, -1.3392],
[ 0.0037, 0.2725, 0.0727],
[-0.2003, -0.3867, -1.1362],
[-1.2875, 1.1898, 0.6018]])
pred:
tensor([[0.1863, 0.6947, 0.1190],
[0.2959, 0.3871, 0.3170],
[0.4500, 0.3735, 0.1765],
[0.0512, 0.6100, 0.3388]])
预测概率:tensor([0.6947, 0.3871, 0.4500, 0.6100]) 预测类别索引:tensor([1, 1, 0, 1])
target is :tensor([1, 0, 0, 1])
top-1 accuracy is 75.00 %
- top@5预测,过程与top@1类似,只是按照从大到小顺序保留前五个预测概率和对应的预测类别索引。对比每张图像的前五个预测类别中是否存在与图像真实类别对应的索引。类别匹配的图像数除以图像总数即为top@5准确率。
#模型输出的4张图像logits
data = torch.randn(4,10)
print('data: \n{}'.format(data))
pred = data.softmax(dim=1)
print(f"pred: \n {pred}")
prob,indice = torch.topk(pred,5,1,True,True)
print('预测概率:{} \n类别索引:{}'.format(prob,indice))
target = torch.tensor([1,0,0,1])
print(f'target is :{target}')
##计算top-5准确率
target = target.view(4,-1).expand_as(indice)
print(f'broadcast target is: \n {target}')
top_5 = target.eq(indice).sum()/target.size(0)
print('top-5 accuracy is %.2f %%'%(top_5.item()*100))
##结果##
data:
tensor([[-0.4706, 0.9594, 0.5815, 0.1848, 0.1793, 0.3996, -1.4341, 1.0193,
1.0513, -1.2530],
[-0.3900, -0.0430, -1.1158, -0.5487, -0.8261, -0.0408, -0.1403, -0.3947,
1.1815, -0.6190],
[-1.2900, 1.3107, -0.6746, 1.6993, 0.2995, -0.6908, -1.3841, -0.5851,
-0.0408, 0.6973],
[ 2.6348, -0.6179, 0.2768, 1.8813, -0.7883, -0.7050, -0.0241, 0.3157,
0.2264, 0.7279]])
pred:
tensor([[0.0414, 0.1732, 0.1187, 0.0798, 0.0794, 0.0989, 0.0158, 0.1839, 0.1899,
0.0190],
[0.0730, 0.1032, 0.0353, 0.0623, 0.0472, 0.1035, 0.0937, 0.0726, 0.3513,
0.0580],
[0.0177, 0.2379, 0.0327, 0.3509, 0.0865, 0.0321, 0.0161, 0.0357, 0.0616,
0.1288],
[0.4810, 0.0186, 0.0455, 0.2264, 0.0157, 0.0170, 0.0337, 0.0473, 0.0433,
0.0714]])
预测概率:tensor([[0.1899, 0.1839, 0.1732, 0.1187, 0.0989],
[0.3513, 0.1035, 0.1032, 0.0937, 0.0730],
[0.3509, 0.2379, 0.1288, 0.0865, 0.0616],
[0.4810, 0.2264, 0.0714, 0.0473, 0.0455]])
类别索引:tensor([[8, 7, 1, 2, 5],
[8, 5, 1, 6, 0],
[3, 1, 9, 4, 8],
[0, 3, 9, 7, 2]])
target is :tensor([1, 0, 0, 1])
broadcast target is:
tensor([[1, 1, 1, 1, 1],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1]])
top-5 accuracy is 50.00 %
4张图片的真实标签分别是【1,0,0,1】,每张图像的模型输出结果预测的5个类别索引标签中,只要存在与图像真实标签对应就认为匹配,四张图像中的第1张照片在第三个预测类别匹配,第2张在第5个索引上匹配,后两张图片的5个预测类别没有一个匹配成功,即top@5预测准确率为50%。上述为模拟实验,正常情况下实验结果top%5准确率高于top@1。
三、top-1和top-5的集成代码
上面模拟取每张图像的前5个预测概率时,用到一个函数torch.topk()
。本部分先介绍该函数的各参数用途,随后,介绍求top@1和top@5的完整代码方法,并具体分析代码的计算过程。
3.1 torch.topk()函数介绍
topk(input: Tensor, k: _int, dim: _int=-1, largest: _bool=True, sorted: _bool=True)
input
:输入数据张量k
:要获取几个数值dim
:确定在哪个维度上获取数据largest
:控制获取最大值还是最小值,默认情况下largest=True返回最大值。sorted
:控制返回值是否按顺序输出,默认情况下sorted=True按照顺序输出。- topk的返回值分为两部分,前部分是数值values,后部分是数值对应的索引号indices。
3.2 top@1和top@5的accuracy完整计算函数
def accuracy(output, target, topk=(1,)):
"""Computes the precision@k for the specified values of k"""
maxk = max(topk)
batch_size = target.size(0)
_, pred = output.topk(maxk, 1, True, True)
pred = pred.t()
correct = pred.eq(target.view(1, -1).expand_as(pred)).contiguous()
res = []
for k in topk:
correct_k = correct[:k].view(-1).float().sum(0, keepdim=True)
res.append(correct_k.mul_(100.0 / batch_size))
return res
if __name__ == '__main__':
#模拟模型输出的预测数据
data = torch.randn(4,8)
#模拟批次数据的真实标签
target = torch.randint(0,8,(4,))
print(f"data:\n{data}")
print("target:\n{}".format(target))
#调用函数计算top@1和top@5准确率
res = accuracy(data,target,topk=(1,5))
print(f"result: {res}")
###结果###
data:
tensor([[ 0.8036, -1.5535, 0.3257, 0.2196, -0.3886, 0.1040, -0.5854, -0.3164],
[-0.9698, 0.0780, -0.3011, 0.5382, -2.3513, -0.0949, -2.2967, -1.8669],
[ 0.1367, -1.3205, -0.4800, 1.0906, -1.7252, 1.9604, 1.3079, -0.7362],
[-1.4857, 0.4024, 0.7095, 0.7947, -0.7839, -0.1446, 1.3871, 0.5920]])
target:
tensor([0, 6, 3, 2])
result: [tensor([25.]), tensor([75.])]
注意:调用accuracy函数直接传递模型预测输出就可以,不用调用softmax(.)
变成概率预测。主要是因为softmax(.)
是一个单调递增函数,模型输出值越大转换后的概率也相应越大。
在accuracy方法函数中首先使用#3.1介绍的torch.topk()
函数分别获取每个数据样本按照预测概率从大到小顺序排列的预测类别索引。结果如下
tensor([[0, 2, 3, 5, 7],
[3, 1, 5, 2, 0],
[5, 6, 3, 0, 2],
[6, 3, 2, 7, 1]])
对预测的标签索引矩阵转置pred.t()
,转置后的每行数据不再代表一个样本的优先预测类别顺序,而是代表一批样本的预测类别等级,例如:第一行代表四个样本的第1预测类别(最优预测),第二行代表四个样本的第2预测类别(次优预测),…,第n行代表批量样本第n预测类别。
tensor([[0, 3, 5, 6],
[2, 1, 6, 3],
[3, 5, 3, 2],
[5, 2, 0, 7],
[7, 0, 2, 1]])
为计算真实标签与预测标签的匹配个数,需要对真实标签[0,6,3,2]先增加维度随后扩展成与预测标签矩阵一致的形状。target.view(1, -1).expand_as(pred)
tensor([[0, 6, 3, 2],
[0, 6, 3, 2],
[0, 6, 3, 2],
[0, 6, 3, 2],
[0, 6, 3, 2]])
调用torch.eq()
函数对预测类别和标签真实类别进行匹配,相同为True不同为False。要想获得top@k的准确匹配数量,截取结果矩阵的前k行,变成一维张量并计算矩阵中True的数量之和(True转换为浮点数为1.0,False转换为浮点数为0.0),除以batch_size即可获得top@k的准确率。
correct_k = correct[:k].view(-1).float().sum(0, keepdim=True)
res.append(correct_k.mul_(100.0 / batch_size))
3.3 top@1和top@5的accuracy函数鲁棒性写法
与3.2讲述的代码主体基本相同,只是增加少许校验功能。
def accuracy(pred, target, topk=1):
assert isinstance(topk, (int, tuple))
if isinstance(topk, int):
topk = (topk, )
return_single = True
else:
return_single = False
maxk = max(topk)
_, pred_label = pred.topk(maxk, dim=1)
pred_label = pred_label.t()
correct = pred_label.eq(target.view(1, -1).expand_as(pred_label)).contiguous()
res = []
for k in topk:
correct_k = correct[:k].view(-1).float().sum(0, keepdim=True)
res.append(correct_k.mul_(100.0 / pred.size(0)))
return res[0] if return_single else res
四、总结
top-1准确率和top-5准确率是评价深度模型在图像分类任务上表现的常见性能指标。这些指标通常用于大规模图像分类竞赛,例如ImageNet挑战,以评估不同模型的性能。