Consensus-Driven Propagation in Massive Unlabeled Data for Face Recognition 人脸聚类

看论文前可先看下作者自己在知乎的总结: https://zhuanlan.zhihu.com/p/51806059
 
这篇论文简称CDP,利用监督方式训练一个度量模型判别图片对判别进而实现人脸聚类,使用聚类的人脸来训练人脸识别模型。
 
open-set and close-set
类似ImageNet识别这种,明确知道类别范围的分类问题称为close-set问题,但人脸方面基本都属于open-set问题(测试类别不一定在训练集范围内),因此测试过程通常是提取人脸特征进行比对,而非直接通过网络推理得到标签。
 
人脸聚类
聚类需要特征以及相似度度量标准,特征可以由CNN获取,度量可参考L2距离,余弦相似度来度量。
其中,不同的损失函数会产生不同形态的特征分布,左图这种锥形(cone),右图这种分布在超球面的,对人脸特征做L2归一化即可得超球面分布(参考arcface实现)。对于锥形分布,可采用余弦相似度度量,而超球面分布可采用L2距离来度量。
常规的聚类算法有很多,但使用20万张图提取特征之后来测试一下这些聚类算法,K-Means花了10分钟,HAC花了5.7小时,DBSCAN花了6.9小时, Spectral花了12小时。若使用60万张图片提取的特征来做聚类,K-Means超内存了,HAC花了61小时,DBSCAN花了80小时,Spectral跑到天荒地老之后也甩了一句超内存。当图片数量增加到140万的时候,几乎所有的聚类算法都挂了。
 
K-Means, Spectral, HAC等传统聚类方法的问题主要在于以下方面:
(a) 聚类算法具有较高的时间复杂度。例如,K-Means是O(NKT),Spectral是O(N^3),HAC是O(N^2)。
(b) 通常认为数据分布服从某些简单的假设。例如,K-Means假设数据类内具有球状的分布,并且每一类具有相同的方差(variance),以及不同的类具有相同的先验概率。然而对于大规模人脸聚类,无标注数据通常来源于开放的场景(in-the-wild),数据内部的结构比较复杂,难以一致地服从这些假设。例如,我们期望数据长这样(如下左图):
(c) 通常使用某种特定的metric。例如上述提及的Cosine Similarity和L2距离。同样,对于复杂的数据结构,衡量两个样本是否属于同一类,单纯靠样本之间的局部相似度是不够的,这个metric需要融合更多信息。
(d) 缺乏较好的离群值(outliers)控制机制。outliers来源于人脸识别模型对难样本的embedding误差,以及观测到的数据不完整。尽管部分聚类算法例如DBSCAN理论上对outliers鲁棒,但从其实际表现来讲这个问题远没有得到解决。
 
有监督的metric
本文提出的CDP其实就是一个度量学习模型,判别两个样本是不是属于同一个类簇。如下图,CDP首先使用多个人脸识别模型构建成一个委员会(committee), committee中每个成员对基础模型中相连的pairs提供包括关系(是否是neighbor)、相似度、局部结构等信息,然后使用一个多层感知机(MLP)来整合这些信息并作出预测(即这个pair是否是同一个人)。这个过程可以类比成一个投票的过程,committee负责考察一个候选人(pair)的各方面信息,将信息汇总给MLP进行决定。最后将所有的positive pairs组成一个新的graph称为consensus-driven graph。在此graph上使用简单的连通域搜索并动态剪枝即可快速得到聚类。由于MLP需要使用一部分有标签的数据来训练得到,所以CDP是一种基于有监督的metric的聚类方法。
 
 
CDP 算法流程
1.构建KNN图
Base model 和 committee model如下所示
由基础模型和委员模型对所有图片抽取特征,并分别依据KNN为每个样本找到k个相邻的样本,构建KNN图,其中以余弦相似度来评估样本间相似度。N个委员模型加一个基础模型一共构成N+1个不同的KNN图。接下来以基础模型得到的相似图片对作为候选图片对,由委员模型从多个方面提取特征,最终由MLP来判别图片对是否同一个人。
 
2.由committee抽取图片对的特征
对基础模型得到的图片对,委员模型依据自己构建的KNN图分别给出邻接关系、相似度和局部结构信息特征
邻接特征:若图片对在委员模型构建的KNN图上,则他们是相邻的,表现为
 
相似度特征:针对候选图片对,委员模型计算得到的余弦相似度作为图片对的相似程度
 
局部结构特征:对每个节点,我们可以通过与节点直接相邻的节点(一阶)与间接相邻的节点(二阶)或者更高阶的邻接节点与当前节点的关系来表征节点的局部结构特征,其中节点与节点之间的关系是直接通过余弦相似度来评估的。如下图所示,针对基础模型中的图片对节点,委员模型可以给出每个节点的局部结构特征,在本文中用直接相连节点和间接相连节点余弦相似度信息的均值和方差作为局部结构信息。红线表示的一阶邻接节点信息,黄色表示的二阶邻接节点信息。
 
3.mediator判别图片对
mediator判别模型就是一个MLP模型,模型输入由以上三个部分节点对特征组成:
  • 邻接关系,N个委员模型,则长度为N
  • 相似度,N个委员+一个基础模型,则长度为N+1
  • 局部结构分布特征,我们仅计算每个节点与直接相邻节点和间接相邻节点余弦相似度的均值和方差,则节点对可计算出2(N+1)个均值特征和2(N+1)个方差特征,N个委员+1个基础模型。
综上,一个图片对可的6N+5个特征,MLP损失函数为交叉熵,二分类模型。在测试阶段,将较高预测概率(0.96)为1的图片对作为相似图片对,因为大多数正图片对是冗余的,这样的做法牺牲了一定的召回率但取得较高的精准率。
 
4.伪标签传播
依据MLP判别模型所得到的所有正样本对构成一个一致性驱动的图(consensu-driven-graph),图的边为图片对为正的概率,其中该图未必是全部连通的。作者依据节点连接来进行伪标签构建。为传播伪标签,作者设计了一种简单但高效的方法来识别连接部分。首先,依据当前边的连接情况找到所有连接部分并把它们放到一个队列。然后,针对每一连通部分,若该部分节点数大于预定的值,我们剔除连通图里低分的边,找到连接的子图并将这些子图加入到队列。若队列里的连通子图所含节点数小于阈值,那么将该子图归纳为一个新的伪标签并移出队列。迭代队列,不断地将大的子图拆分,将小的子图打标签,直到队列为空。
 
总结:将节点数超过阈值的子图做拆分,把小于阈值的子图看成一个新的个体,赋予新的伪标签。
 
5.标记数据与未标记数据联合训练
作者说,由于不确定标记数据和未标记数据的重叠类别部分,因此分别对标记数据和伪标签数据计算损失,损失函数以两部分数据比例来确定。
 
实验部分
实验部分非常详实了,简单记录几项
 
对比方法:
  • HAC:监督CNN特征+HAC,通过验证集选定阈值
  • 投票方式确定节点对是否属于同一个人,如果委员模型生成的KNN图中该节点对相连,则票数+1
CDP方法验证精度甚至超过了全监督,作者解释数据集存在误差,CDP去掉了,因此训练出的模型更好。
 
CDP的计算时间也几乎与数据规模呈线性增长,百万级别数据,KNN搜索花了4分钟(48核),特征计算+MLP花了2分钟(8卡),伪标签生成花了2分钟,但作者没说所有数据抽特征花了多久。。。
 
相比于百万规模数据常规聚类算法都无法作用,CDP还算可以了,就是有点麻烦,还要先训练多个特征抽取(委员)模型,其中相关代码作者已经开源道github。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
### 关于分布式系统中的共识算法及其调用实现 #### 分布式系统的容错与一致性 在分布式系统中,为了保证高可用性和数据的一致性,通常采用某种形式的共识算法。例如,在 DAOS 中,通过 **分层容错域(Hierarchical Fault Domains)** 和强一致性算法实现了数据和元数据的可靠复制[^1]。这种设计使得即使某些节点发生故障,整个系统仍然能够正常运行并保持数据一致。 #### Consensus Algorithm Implementation Raft 是一种常用的共识协议,广泛应用于 etcd 等分布式系统中。以下是 Raft 协议的核心逻辑: - 当 Follower 接收到来自 Leader 的心跳消息时,它会重置自身的选举计时器,并更新已提交索引 `committed index`[^3]。 - 随后,Follower 向 Leader 发送响应消息 `MsgHeartbeatResp` 表明其状态同步成功。 下面是 Raft 心跳处理的一个简化代码示例: ```go func stepFollower(r *raft, m pb.Message) { switch m.Type { case pb.MsgHeartbeat: r.electionElapsed = 0 // Reset election timer r.lead = m.From // Update the current leader ID r.handleHeartbeat(m) // Process heartbeat message } } func (r *raft) handleHeartbeat(m pb.Message) { r.raftLog.commitTo(m.Commit) // Commit log entries up to commit index r.send(pb.Message{ To: m.From, Type: pb.MsgHeartbeatResp, Context: m.Context, }) // Send response back to leader } ``` 此代码片段展示了如何在一个典型的 Raft 实现中管理心跳通信以及日志提交过程。 #### 工具支持 对于实际操作层面,etcd 提供了一系列工具帮助管理员完成集群部署、备份恢复等工作[^4]。这些工具不仅简化了运维流程,还间接保障了基于 Raft 的共识机制得以稳定执行。值得注意的是,由于性能需求较高,官方文档强烈推荐使用 SSD 来满足磁盘 I/O 要求。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值