CDP(Consensus-Driven Propagation)是一种高效的大规模无标签人脸聚类方法。该方法通过投票机制和图传播算法,实现对人脸特征的快速准确聚类。CDP具有线性时间复杂度,能够处理大规模数据集,并在保持高精度的同时提供出色的聚类性能。
在现代计算机视觉应用中,人脸聚类是一项重要任务。传统聚类方法在处理大规模无标签人脸数据时面临以下挑战:
CDP方法通过创新的投票机制和图传播算法,有效解决了这些问题。
CDP算法分为三个核心阶段:
cpp展开代码void initializeClusterRepresentationAndPredictFeatures(
    const std::vector<std::vector<float>> &features,
    std::map<std::string, std::vector<std::vector<float>>> &clusterRepresentation,
    std::vector<int> &predict,
    std::map<std::string, std::vector<int>> &predictHumanreadable,
    int accept = 0,           // 投票接受阈值
    float threshold = 0.62,   // 相似度阈值
    float threshold_recall = 0.62,  // 召回阈值
    int knn_k = 15,          // KNN邻居数
    int max_sz = 600,        // 最大簇大小
    float step = 0.05,       // 阈值递增步长
    int max_iter = 100       // 最大迭代次数
);
cpp展开代码// 构建K近邻图
std::vector<std::vector<int>> knn_idx;
std::vector<std::vector<float>> knn_dist;
create_knn(features, knn_idx, knn_dist, knn_k);
算法首先为每个特征找到K个最近邻,构建局部邻域关系。
cpp展开代码void vote(std::vector<std::vector<int>> knn_idx,
          const std::vector<std::vector<float>> &knn_dist,
          std::vector<std::vector<int>> &unique_pairs,
          std::vector<float> &unique_scores,
          int accept,
          float threshold) {
    
    // 计算相似度矩阵(1 - 距离)
    std::vector<std::vector<float>> simi;
    for (auto &knn_d: knn_dist) {
        std::vector<float> simi_row;
        for (float j: knn_d) {
            simi_row.push_back(1.0f - j);
        }
        simi.push_back(simi_row);
    }
    
    // 选择高置信度的相似对
    std::vector<std::pair<int, int>> selidx;
    for (int i = 0; i < knn.size(); i++) {
        for (int j = 0; j < knn[i].size(); j++) {
            if (simi[i][j] > threshold && knn[i][j] != -1 && knn[i][j] != anchor[i][j]) {
                selidx.emplace_back(i, j);
            }
        }
    }
    
    // 构建边对并去重
    // ... 边处理逻辑
}
投票机制的核心思想是:
cpp展开代码void graph_propagation(std::vector<std::vector<int>> edges,
                       std::vector<float> score,
                       std::vector<std::vector<Data>> &components,
                       int max_sz,
                       float step,
                       int max_iter) {
    
    // 构建图节点和边
    std::vector<Data> vertex;
    for (auto &node: nodes) {
        Data data;
        data.name = node;
        vertex.push_back(data);
    }
    
    // 添加边连接
    for (auto &i: link_idx) {
        add_links1(&(vertex[i[0]]), &(vertex[i[1]]));
    }
    
    // 约束连通分量分析
    float th = *std::min_element(score.begin(), score.end());
    std::vector<std::vector<Data>> comps;
    std::vector<Data> remain;
    
    while (!remain.empty() && iter < max_iter) {
        th = th + (1 - th) * step;  // 自适应阈值调整
        connected_components_constraint(remain, max_sz, score_dict, th, comps, remain);
        components.insert(components.end(), comps.begin(), comps.end());
        iter++;
    }
}
图传播的关键特点:
cpp展开代码void initClusterRepresentation(const std::vector<std::vector<float>> &features,
                               const std::vector<int> &pre,
                               std::map<std::string, std::vector<std::vector<float>>> &clusterRepresentation,
                               const std::vector<std::vector<int>> &knn_idx,
                               const std::vector<std::vector<float>> &knn_dist) {
    
    // 对于每个簇,选择最多3个代表特征
    for (auto &p: unique_pre) {
        std::vector<std::vector<float>> featuresInCluster;
        
        if (count <= 3) {
            // 小簇:直接使用所有特征
            for (auto &idx: indexs) {
                featuresInCluster.push_back(features[idx]);
            }
        } else {
            // 大簇:选择最具代表性的3个特征
            // 1. 找到距离最大的两个特征
            // 2. 找到与前两个距离适中的第三个特征
        }
        
        clusterRepresentation[std::to_string(p)] = featuresInCluster;
    }
}
| 方法 | 时间复杂度 | 精确率 | 召回率 | 内存占用 | 
|---|---|---|---|---|
| K-means | O(nkt) | 0.75 | 0.72 | 中等 | 
| DBSCAN | O(n²) | 0.82 | 0.78 | 高 | 
| 层次聚类 | O(n³) | 0.85 | 0.80 | 很高 | 
| CDP | O(n) | 0.92 | 0.89 | 低 | 
threshold(相似度阈值)
knn_k(邻居数量)
max_sz(最大簇大小)


本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!