行人重识别评价指标

CMC曲线

CMC曲线是算top-k的击中率,主要用来评估闭集中rank的正确率。举个简单的例子,例如在人脸识别中,底库中有100个人,现在来了一个待识别的人脸(假设label为m1),与底库中的人脸对比后按照从高到低的顺序排序,我们发现:

  1. 如果识别结果是 m1、m2、m3、m4、m5…,则此时rank-1是100%,rank-2是100%,rank-5也是100%
  2. 如果识别结果是 m2、m1、m3、m4、m5…,则此时rank-1是0%,rank-2是100%,rank-5是100%
  3. 如果识别结果是 m2、m3、m4、m5、m1…,则此时rank-1是0%,rank-2是0%,rank-5是100%

同理,如果待识别的人脸有很多时,则采取取平均的做法,例如待识别的人脸有三个,(假设label分别是m1、m2、m3),同样对每个人脸都有一个从高到低的得分,
4. 比如人脸1结果为m1、m2、m3、m4、m5……,人脸2结果为m2、m1、m3、m4、m5……,人脸3结果m3、m1、m2、m4、m5……,则此时rank-1的正确率为(1+1+1)/3=100%;rank-2的正确率也为(1+1+1)/3=100%;rank-5的正确率也为(1+1+1)/3=100%;
5. 比如人脸1结果为m4、m2、m3、m5、m6……,人脸2结果为m1、m2、m3、m4、m5……,人脸3结果m3、m1、m2、m4、m5……,则此时rank-1的正确率为(0+0+1)/3=33.33%;rank-2的正确率为(0+1+1)/3=66.66%;rank-5的正确率也为(0+1+1)/3=66.66%;

Rank-1就是CMC中的第一个元素

mAP

mAP要计算多次输入的综合AP结果, 每张测试图像计算如下:

返回图片12345678910
query1010010011

query中为1表示寻找到了正确的图片

ap = ( 1 1 \frac{1}{1} 11 + 2 3 \frac{2}{3} 32 + 3 6 \frac{3}{6} 63 + 4 9 \frac{4}{9} 94 + 5 10 \frac{5}{10} 105 ) / 5 = 0.62

依次解释上面五个数字的来源:
1 1 \frac{1}{1} 11 : 第一个正确的图片,在第一个位置
2 3 \frac{2}{3} 32 : 第二个正确的图片,在第三个位置
3 6 \frac{3}{6} 63 : 第三个正确的图片,在第六个位置
4 9 \frac{4}{9} 94 : 第四个正确的图片,在第九个位置
5 10 \frac{5}{10} 105 : 第五个正确的图片,在第十个位置

计算CMC和mAP的代码实现

query和gallery的距离矩阵计算:

# if resnet50, qf: [query_num, 2048], gf: [gallery_num, 2048]
m, n = qf.shape[0], gf.shape[0]
distmat = torch.pow(qf, 2).sum(dim=1, keepdim=True).expand(m, n) + \
              torch.pow(gf, 2).sum(dim=1, keepdim=True).expand(n, m).t()
distmat.addmm_(mat1=qf, mat2=gf.T, beta=1, alpha=-2)
distmat = distmat.numpy()
def evaluate(distmat, q_pids, g_pids, q_camids, g_camids, max_rank):
	"""
	distmat: [m, n]  query和gallery中两两距离矩阵
	q_pids: [m, ]  query中的行人id
	g_pids: [n, ]  gallery中的行人id
	q_camids: [m, ]  query中每个行人是由哪个相机拍摄的
	g_camids: [n, ]  gallery中每个行人是由哪个相机拍摄的
	max_rank: int
	"""
    # dismat [m, n] 含义是query中有m张图片, 每一行共n个元素, 是query (m) 中每张图片和gallery (n)中每张图片算出的距离
    num_q, num_g = distmat.shape
    if num_g < max_rank:
        max_rank = num_g
        print(f'Note: number of gallery samples is quite small, got {num_g}')
    # indices: [m, n]   输出按行进行排序的索引 (升序, 从小到大)
    indices = np.argsort(distmat, axis=1)
    # g_pids[indices] shape is [m, n]
    # g_pids 原来是 [n, ], g_pids[indices]操作之后, 扩展到了 [m, n]
    # 也就是每一行中的n个元素都按照 indices 中每一行的顺序进行了重排列
    # q_pids[:, np.newaxis] shape is [m, 1]
    g_pids_exp_dims, g_camids_exp_dims = g_pids[indices], g_camids[indices]
    q_pids_exp_dims = np.expand_dims(q_pids, axis=1)

    # matches中为 1 的表示query中和gallery中的行人id相同, 也就是表示同一个人
    # matches中的结果就是和后续预测出的结果进行对比的正确label
    matches = (g_pids_exp_dims == q_pids_exp_dims).astype(np.int32)      # shape is [m, n]

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

    # 遍历每一张query图片
    for q_idx in range(num_q):
        # q_pid, q_camid 分别都是一个数字
        q_pid, q_camid = q_pids[q_idx], q_camids[q_idx]

        # remove gallery samples that have the same pid and camid with query
        # TODO: 这里要用 & ,因为前后都是np.ndarray类型, 如果前后都是list, 则可以使用 and
        removed = (g_pids_exp_dims[q_idx] == q_pid) & (g_camids_exp_dims[q_idx] == q_camid)    # [n, ]

        # keep中为True的表示gallery中符合查找条件的行人图片,
        # 这些为True的部分还需要借助matches才能完成正确的查找
        # 且keep中从左到右就是当前查找图片和每一个gallery中图片的距离距离依次递增的顺序
        keep = np.where(removed == 0, True, False)    # [n, ]

        # ===== compute cmc curve =====
        # orig_cmc中为1的位置表示查找的图片匹配正确了
        orig_cmc = matches[q_idx][keep]

        # 如果orig_cmc全为0, 也就是待查询图片没有在gallery中匹配到
        # 也就不计算top-n和ap值了
        if np.all(orig_cmc == 0):
            continue

        cmc = orig_cmc.cumsum()
        cmc = np.where(cmc >= 1, 1, 0)
        all_cmc.append(cmc[:max_rank])
        num_valid_q += 1

        # ===== compute average precision =====
        num_rel = orig_cmc.sum()    # 在gallery的n中图片中,匹配对了多少张
        tmp_cmc = orig_cmc.cumsum()
        tmp_cmc = [(x / (i + 1)) for i, x in enumerate(tmp_cmc)]
        tmp_cmc = np.asarray(tmp_cmc) * orig_cmc
        ap = tmp_cmc.sum() / num_rel
        all_ap.append(ap)
    
    assert num_valid_q > 0, "Error: all query identity do not appear in gallery"

    # all_cmc中一共有num_valid_q个元素, 其中每个元素又包含max_rank个值
    # 将all_cmc按列求和, 可以得到 n 个值,然后除以 num_valid_q
    all_cmc = np.asarray(all_cmc).astype(np.float32)
    all_cmc = all_cmc.sum(axis=0) / num_valid_q
    mAP = np.mean(all_ap)

    return all_cmc, mAP
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值