行人重识别评价指标相关代码

本文介绍了如何使用PyTorch的torch.topk函数计算模型的Top-K分类准确率,以及如何利用Cuhk03和Market1501评估标准计算人脸识别算法的CMC曲线和mAP。展示了如何在五分类任务中应用这些技术并提供了示例代码.

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

top_k分类准确率

pytorch中文文档

torch.topk(input, k, dim=None, largest=True, sorted=True, out=None) -> (Tensor, LongTensor)

沿给定dim维度返回输入张量input中 k 个最大值。
如果不指定dim,则默认为input的最后一维。
如果为largest为 False ,则返回最小的 k 个值。
返回一个元组 (values,indices),其中indices是原始输入张量input中测元素下标。
如果设定布尔值sorted 为_True_,将会确保返回的 k 个值被排序。

参数:
input (Tensor) – 输入张量
k (int) – “top-k”中的k
dim (int, optional) – 排序的维
largest (bool, optional) – 布尔值,控制返回最大或最小值
sorted (bool, optional) – 布尔值,控制返回值是否排序
out (tuple, optional) – 可选输出张量 (Tensor, LongTensor) output buffers

举例:

 _, pred = output.topk(maxk, 1, True, True)

其中maxk是取top1准确率,dim=1是按行取值,largest=True是返回最大值,sorted=True是返回值排序
若神经网络的输出为output,为五分类问题,topk()返回的pred结果中top1和top5分别如下:

tensor([[0.8161, 0.8626, 0.2278, 0.6167, 0.6919],
        [0.8636, 0.6710, 0.3882, 0.4844, 0.9402],
        [0.0261, 0.1724, 0.1653, 0.1755, 0.8592],
        [0.8785, 0.6654, 0.9979, 0.4739, 0.0806],
        [0.5178, 0.2201, 0.4477, 0.0618, 0.2030]], dtype=torch.float64)
tensor([[1],
        [4],
        [4],
        [2],
        [0]])
tensor([[1, 0, 4, 3, 2],
        [4, 0, 1, 3, 2],
        [4, 3, 1, 2, 0],
        [2, 0, 1, 3, 4],
        [0, 2, 1, 4, 3]])           
from __future__ import absolute_import

import torch
from ..utils import to_torch

# output:模型的输出,即模型对不同类别的评分,[batch_size,num_classes]
# target:真实的类别标签,[batch_size,]
# topk:需要计算top_k准确率中的k值,元组类型,若为(1,5)即返回top1和top5的分类准确率
def accuracy(output, target, topk=(1,)):
    with torch.no_grad(): # 不需要计算梯度,也不会进行反向传播
        output, target = to_torch(output), to_torch(target)
        maxk = max(topk) # 取top1准确率
        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))

        ret = []
        for k in topk:
            correct_k = correct[:k].view(-1).float().sum(dim=0, keepdim=True)
            ret.append(correct_k.mul_(1. / batch_size))
        return ret

根据距离矩阵评估算法性能(CMC曲线Rank-N与mAP)

from __future__ import division, print_function, absolute_import
import numpy as np
import warnings
from collections import defaultdict

try:
    from .rank_cylib.rank_cy import evaluate_cy
    IS_CYTHON_AVAI = True
except ImportError:
    IS_CYTHON_AVAI = False
    warnings.warn(
        'Cython evaluation (very fast so highly recommended) is '
        'unavailable, now use python evaluation.'
    )


def eval_cuhk03(distmat, q_pids, g_pids, q_camids, g_camids, max_rank):
    """Evaluation with cuhk03 metric
    Key: one image for each gallery identity is randomly sampled for each query identity.
    Random sampling is performed num_repeats times.
    """
    num_repeats = 10
    num_q, num_g = distmat.shape

    if num_g < max_rank:
        max_rank = num_g
        print(
            'Note: number of gallery samples is quite small, got {}'.
            format(num_g)
        )

    indices = np.argsort(distmat, axis=1)
    matches = (np.asarray(g_pids)[np.asarray(indices)] == np.asarray(q_pids)[:, np.newaxis]).astype(np.int32)

    # compute cmc curve for each query
    all_cmc = []
    all_AP = []
    num_valid_q = 0. # number of valid query

    for q_idx in range(num_q):
        # get query pid and camid
        q_pid = q_pids[q_idx]
        q_camid = q_camids[q_idx]

        # remove gallery samples that have the same pid and camid with query
        order = indices[q_idx]
        remove = (np.asarray(g_pids)[order] == q_pid) & (np.asarray(g_camids)[order] == q_camid)
        keep = np.invert(remove)

        # compute cmc curve
        raw_cmc = matches[q_idx][
            keep] # binary vector, positions with value 1 are correct matches
        if not np.any(raw_cmc):
            # this condition is true when query identity does not appear in gallery
            continue

        kept_g_pids = g_pids[order][keep]
        g_pids_dict = defaultdict(list)
        for idx, pid in enumerate(kept_g_pids):
            g_pids_dict[pid].append(idx)

        cmc = 0.
        for repeat_idx in range(num_repeats):
            mask = np.zeros(len(raw_cmc), dtype=np.bool)
            for _, idxs in g_pids_dict.items():
                # randomly sample one image for each gallery person
                rnd_idx = np.random.choice(idxs)
                mask[rnd_idx] = True
            masked_raw_cmc = raw_cmc[mask]
            _cmc = masked_raw_cmc.cumsum()
            _cmc[_cmc > 1] = 1
            cmc += _cmc[:max_rank].astype(np.float32)

        cmc /= num_repeats
        all_cmc.append(cmc)
        # compute AP
        num_rel = raw_cmc.sum()
        tmp_cmc = raw_cmc.cumsum()
        tmp_cmc = [x / (i+1.) for i, x in enumerate(tmp_cmc)]
        tmp_cmc = np.asarray(tmp_cmc) * raw_cmc
        AP = tmp_cmc.sum() / num_rel
        all_AP.append(AP)
        num_valid_q += 1.

    assert num_valid_q > 0, 'Error: all query identities do not appear in gallery'

    all_cmc = np.asarray(all_cmc).astype(np.float32)
    all_cmc = all_cmc.sum(0) / num_valid_q
    mAP = np.mean(all_AP)

    return all_cmc, mAP

'''
输入:
distmat:距离矩阵
q_pids:query集person id
g_pids:gallery集person id
q_camids:query集camera id
g_camids:gallery集camera id
max_rank:rank-n中n最大值

输出:
all_cmc:cmc曲线中rank-n的列表
mAP:所有符合要求的query数据的mAP
'''
def eval_market1501(distmat, q_pids, g_pids, q_camids, g_camids, max_rank):
    """Evaluation with market1501 metric
    Key: for each query identity, its gallery images from the same camera view are discarded.
    """
    num_q, num_g = distmat.shape # 距离矩阵的shape

	# 若gallery数据少于max_rank,将max_rank设为gallery数据集的数量
    if num_g < max_rank:
        max_rank = num_g
        print(
            'Note: number of gallery samples is quite small, got {}'.
            format(num_g)
        )

	'''
	np.argsort()指定按照行进行排序,并返回每行按升序排列的元素下标
	举例:列表[1,2,0],按行排列后,返回[2,0,1]
	'''
    indices = np.argsort(distmat, axis=1) # 每行按照距离大小进行排序,并获取排序后的下标顺序
 
 	'''
 	np.asarray(g_pids)[np.asarray(indices)]:与distmat距离矩阵相同规模的矩阵,但矩阵元素是按距离大小升序排列后对应的gallery的person id。举例:距离矩阵某一行为[1,0,5,6],按行升序排列后得到的下标列表为[1,0,2,3],gallery行人ID为[4,5,6,8],则可以计算得到g_pids[indices]对应的那一行为[5,4,6,8]。
	np.asarray(q_pids)[:, np.newaxis]:将q_pids矩阵增加了一维。
	==:将g_pids[indices]与q_pids进行匹配,对应位置相同则元素为1,否则为0,则获得一个对应关系矩阵matches,该矩阵与距离矩阵规模相同。
	matches矩阵第i行第j个元素代表query第i个行人ID与gallery中与其距离第j近的数据行人ID是否相同。举例,matches[1][3]=1,说明query中第1个行人与距离第三近的gallery数据属于同一行人。
 	'''
 	# 进行ID匹配,计算匹配矩阵matched,便于计算cmc与AP
    matches = (np.asarray(g_pids)[np.asarray(indices)] == np.asarray(q_pids)[:, np.newaxis]).astype(np.int32)

    # compute cmc curve for each query
    all_cmc = [] # 记录每个query数据的cmc数据
    all_AP = [] # 记录每个query数据的AP
    num_valid_q = 0. # 记录符合CMC与mAP计算的query数据的总数,便于计算总Rank-N

    for q_idx in range(num_q): # 对于query集合中的每一个数据
       
        q_pid = q_pids[q_idx] # 获取该数据的person id
        q_camid = q_camids[q_idx] # 获取该数据的camera id
        order = indices[q_idx] # 获取该数据相关的gallery数据距离排序

        # 删除与该query数据有相同person id ,camera id 的数据,相同摄像机相同行人的gallery数据不符合跨摄像机的要求
        remove = (np.asarray(g_pids)[order] == q_pid) & (np.asarray(g_camids)[order] == q_camid)
        keep = np.invert(remove) # 对remove进行翻转得到可以保留的数据的bool类型列表

        raw_cmc = matches[q_idx][keep] # 匹配矩阵只保留对应keep中为True的元素,得到该query数据的匹配列表
        if not np.any(raw_cmc):
             # 如果该query数据未在可以保留的gallery集中出现,说明该query数据不符合CMC与mAP计算要求,返回循环头
            continue

		'''
		计算每个query的cmc
		'''
        cmc = raw_cmc.cumsum() # 计算匹配列表的叠加和
        cmc[cmc > 1] = 1 # 根据叠加和得到该query数据关于gallery数据的Rank-N
        # 将该query数据的CMC数据加入all_AP列表便于之后计算mAP,可以通过指定max_rank来指定一行保留多少列,默认50列
        all_cmc.append(cmc[:max_rank]) 

		# 统计符合CMC与mAP计算的query数据的总数,便于计算总Rank-N
        num_valid_q += 1.

        '''
        计算每个query的AP
        '''
        num_rel = raw_cmc.sum() # 每个query数据的正确匹配总数
        tmp_cmc = raw_cmc.cumsum() # 计算匹配列表的叠加和
        tmp_cmc = [x / (i+1.) for i, x in enumerate(tmp_cmc)] # 计算每次正确匹配的准确率
        tmp_cmc = np.asarray(tmp_cmc) * raw_cmc # 将错误匹配的准确率降为0
        AP = tmp_cmc.sum() / num_rel # 计算平均准确度
        all_AP.append(AP) # 将该query数据的AP加入all_AP列表便于之后计算mAP

	# 如果符合CMC计算的query数据的总数小于等于0,则报错所有query数据都不符合要求
    assert num_valid_q > 0, 'Error: all query identities do not appear in gallery'

    all_cmc = np.asarray(all_cmc).astype(np.float32) # 将all_cmc转换为np.array类型
    # 将所有符合条件的query数据的Rank-N按列求和并取平均数,即可计算总CMC曲线中的Rank-N
    all_cmc = all_cmc.sum(0) / num_valid_q 
    # 平均准确率均值就是所有符合条件的query数据平均准确率的平均数
    mAP = np.mean(all_AP) 

    return all_cmc, mAP


def evaluate_py(
    distmat, q_pids, g_pids, q_camids, g_camids, max_rank, use_metric_cuhk03
):
    if use_metric_cuhk03:
        return eval_cuhk03(
            distmat, q_pids, g_pids, q_camids, g_camids, max_rank
        )
    else:
        return eval_market1501(
            distmat, q_pids, g_pids, q_camids, g_camids, max_rank
        )


def evaluate_rank(
    distmat,
    q_pids,
    g_pids,
    q_camids,
    g_camids,
    max_rank=50,
    use_metric_cuhk03=False,
    use_cython=True
):
    """Evaluates CMC rank.
    Args:
        distmat (numpy.ndarray): distance matrix of shape (num_query, num_gallery).
        q_pids (numpy.ndarray): 1-D array containing person identities
            of each query instance.
        g_pids (numpy.ndarray): 1-D array containing person identities
            of each gallery instance.
        q_camids (numpy.ndarray): 1-D array containing camera views under
            which each query instance is captured.
        g_camids (numpy.ndarray): 1-D array containing camera views under
            which each gallery instance is captured.
        max_rank (int, optional): maximum CMC rank to be computed. Default is 50.
        use_metric_cuhk03 (bool, optional): use single-gallery-shot setting for cuhk03.
            Default is False. This should be enabled when using cuhk03 classic split.
        use_cython (bool, optional): use cython code for evaluation. Default is True.
            This is highly recommended as the cython code can speed up the cmc computation
            by more than 10x. This requires Cython to be installed.
    """
    if use_cython and IS_CYTHON_AVAI:
        return evaluate_cy(
            distmat, q_pids, g_pids, q_camids, g_camids, max_rank,
            use_metric_cuhk03
        )
    else:
        return evaluate_py(
            distmat, q_pids, g_pids, q_camids, g_camids, max_rank,
            use_metric_cuhk03
        )
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值