Reid模型中的CMC和mAP评估指标详解

发布于:2025-07-17 ⋅ 阅读:(23) ⋅ 点赞:(0)

介绍

在行人重识别(ReID)任务中,CMC(Cumulative Matching Characteristic)和mAP(mean Average Precision)是两个核心评估指标。


代码示例

参考源代码:deep-person-reid/torchreid/metrics/rank.py#L94

def eval_market1501(distmat, q_pids, g_pids, q_camids, g_camids, max_rank):
    """
    Market1501数据集评估函数
    核心协议:对于每个query个体,丢弃相同摄像头视角的gallery图像
    
    参数:
    distmat : numpy数组 [num_q, num_g]
        query和gallery样本的距离矩阵(越小表示越相似)
    q_pids : numpy数组 [num_q]
        query样本的行人ID
    g_pids : numpy数组 [num_g]
        gallery样本的行人ID
    q_camids : numpy数组 [num_q]
        query样本的摄像头ID
    g_camids : numpy数组 [num_g]
        gallery样本的摄像头ID
    max_rank : int
        计算CMC指标的最大排名(如50)
    
    返回:
    all_cmc : numpy数组 [max_rank]
        CMC曲线值(Rank-1到Rank-max_rank的准确率)
    mAP : float
        平均精度均值
    """
    # 获取query和gallery的数量
    num_q, num_g = distmat.shape

    # 如果gallery样本数小于max_rank,调整max_rank值
    if num_g < max_rank:
        max_rank = num_g
        print('Note: number of gallery samples is quite small, got {}'.format(num_g))

    # 按距离从小到大排序,获取索引(最相似的排在前面)
    # 结果形状: [num_q, num_g]
    indices = np.argsort(distmat, axis=1)
    
    # 创建匹配矩阵:如果gallery的pid与query的pid相同则为1,否则为0
    # 使用np.newaxis扩展维度进行广播比较
    # 结果形状: [num_q, num_g]
    matches = (g_pids[indices] == q_pids[:, np.newaxis]).astype(np.int32)

    # 初始化存储变量
    all_cmc = []   # 存储每个query的CMC曲线
    all_AP = []    # 存储每个query的AP值
    num_valid_q = 0.  # 有效query计数(在gallery中有匹配项的query)

    # 遍历每个query样本
    for q_idx in range(num_q):
        # 获取当前query的pid和camid
        q_pid = q_pids[q_idx]
        q_camid = q_camids[q_idx]

        # 按相似度排序后的gallery索引
        order = indices[q_idx]
        
        # 创建掩码:标记需要移除的gallery样本(相同行人且相同摄像头)
        remove = (g_pids[order] == q_pid) & (g_camids[order] == q_camid)
        
        # 反转掩码:保留需要考虑的样本(跨摄像头)
        keep = np.invert(remove)

        # 获取过滤后的匹配结果(二进制向量) 结果形状: [num_g]
        raw_cmc = matches[q_idx][keep]  # 1表示匹配,0表示不匹配
        
        # 检查当前query是否有匹配项
        if not np.any(raw_cmc):
            # 如果没有匹配项,跳过此query(在gallery中无该行人)
            continue

        # =============================================
        # 计算CMC曲线 (Cumulative Matching Characteristic)
        # =============================================
        # 累积求和:记录前k个位置中正确匹配的数量
        cmc = raw_cmc.cumsum()
        # 将值限制在0-1之间(首次匹配成功后后续都为1)
        cmc[cmc > 1] = 1
        # 存储前max_rank个值   结果形状: [max_rank,]
        all_cmc.append(cmc[:max_rank])
        # 有效query计数+1
        num_valid_q += 1.

        # =============================================
        # 计算AP (Average Precision)
        # =============================================
        # 相关样本总数(正确匹配的数量)
        num_rel = raw_cmc.sum()
        
        # 计算每个位置的累积精度
        tmp_cmc = raw_cmc.cumsum()  # 到当前位置为止的正确匹配数
        # 计算每个位置的精度 = 累积正确匹配数 / 当前位置
        tmp_cmc = [x / (i+1.) for i, x in enumerate(tmp_cmc)]
        # 转换为numpy数组
        tmp_cmc = np.asarray(tmp_cmc)
        # 只考虑正确匹配位置的精度(其他位置置0)
        tmp_cmc = tmp_cmc * raw_cmc
        # AP = 所有正确匹配位置的精度和 / 相关样本总数
        AP = tmp_cmc.sum() / num_rel
        all_AP.append(AP)

    # 验证是否有有效query
    assert num_valid_q > 0, 'Error: all query identities do not appear in gallery'

    # ==============================
    # 计算最终评估指标
    # ==============================
    # 计算平均CMC曲线:所有query的CMC结果按列平均
    all_cmc = np.asarray(all_cmc).astype(np.float32)
    all_cmc = all_cmc.sum(0) / num_valid_q  # 形状: [max_rank]
    
    # 计算mAP:所有query的AP平均值
    mAP = np.mean(all_AP)

    return all_cmc, mAP

代码详细解释

1. CMC(累积匹配特性)

核心概念:衡量正确匹配出现在排名前K位的概率
计算过程

  1. 过滤相同摄像头样本
    对每个query,排除gallery中相同行人ID且相同摄像头ID的样本(Market1501协议要求):

    remove = (g_pids[order] == q_pid) & (g_camids[order] == q_camid)
    keep = np.invert(remove)
    raw_cmc = matches[q_idx][keep]  # 过滤后的匹配结果
    
  2. 计算单query的CMC

    • raw_cmc:按相似度排序后的二进制匹配向量(1=匹配,0=不匹配)
    • 通过累计求和并二值化得到CMC曲线:
      cmc = raw_cmc.cumsum()
      cmc[cmc > 1] = 1  # 首次匹配成功后后续位置设为1
      
  3. 聚合所有query
    对所有有效query的CMC结果取平均:

    all_cmc = np.asarray(all_cmc).astype(np.float32)
    all_cmc = all_cmc.sum(0) / num_valid_q  # 按列求平均
    

输出意义
all_cmc[0] = Rank-1准确率,all_cmc[4] = Rank-5准确率,反映模型在Top-K位置的识别能力。


2. mAP(平均精度均值)

核心概念:综合考量检索结果排序质量的指标
计算过程

  1. 计算单query的AP

    • num_rel:相关样本总数(raw_cmc.sum()
    • 计算每个位置的精度(Precision@K):
      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  # 平均精度
      

    示例:若匹配结果为[1, 0, 1],则:
    位置1精度=1/1=1.0
    位置3精度=2/3≈0.67
    AP = (1.0 + 0.67) / 2 ≈ 0.83

  2. 计算全局mAP
    所有query的AP平均值:

    mAP = np.mean(all_AP)
    

优势:对排序敏感,惩罚错误样本靠前的情况,更全面评估模型性能。


3. 关键实现细节
  1. 跨摄像头验证
    排除相同摄像头ID的匹配(实际应用需跨摄像头匹配):

    # 关键过滤逻辑
    remove = (g_pids[order] == q_pid) & (g_camids[order] == q_camid)
    
  2. 无效query处理
    若query在gallery中无有效匹配则跳过:

    if not np.any(raw_cmc):
        continue
    
  3. 结果聚合

    • CMC:所有query在相同排名位置的准确率平均
    • mAP:所有query的AP直接平均

4. 指标意义对比
指标 侧重点 优势 局限性
CMC Top-K匹配成功率 直观反映排名性能 忽略排序中间结果
mAP 整体排序质量 全面评估检索性能 计算复杂度较高

典型应用

  • CMC:部署场景关注首次匹配成功率(Rank-1)
  • mAP:学术研究/系统评估的核心指标

通过这两个指标,可全面评估ReID模型在行人检索任务中的精度和鲁棒性。代码实现严格遵循Market1501评估协议,是ReID领域的标准评估方法。


网站公告

今日签到

点亮在社区的每一天
去签到