ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

人脸识别算法演化史:从Eigenfaces到ArcFace的深度学习与损失函数演进

人脸识别算法演化史:从Eigenfaces到ArcFace的深度学习与损失函数演进 人脸识别这四个字今天听起来像是手机解锁、门禁打卡、高铁进站的默认配置默认到几乎没人会去想它背后到底发生了什么。但把时间轴拉回到十几年前让一台机器从一张照片里认出这是谁是一件让整个计算机视觉圈子头疼了几十年的事。我最早接触这块是在做门禁项目的时候当时用OpenCV自带的Haar级联做人脸检测光照一变、角度一偏框就飘了识别率更是惨不忍睹。后来一路从LBPH、Eigenfaces这些传统方法走到卷积神经网络、度量学习、ArcFace再到现在各种轻量化模型部署到树莓派和门禁机上算是完整地踩过了这条演化链上的大部分坑。这篇内容我想做的事情是把人脸识别算法的演化脉络从头到尾捋一遍不是那种教科书式的发展史罗列而是站在一个真正做过项目的人的角度讲清楚每一代方法为什么会出现、它解决了上一代的什么问题、又留下了什么新坑。关键词里提到的深度学习、卷积神经网络、损失函数是这条演化链上最核心的三根支柱我会重点拆解它们各自扮演的角色。无论你是刚入门计算机视觉的学生还是正在做人脸门禁、考勤机、相册聚类这类落地项目的工程师这篇内容应该都能帮你建立起一张清晰的算法地图知道在什么场景下该选什么方案以及为什么。1. 从几何特征到子空间方法早期人脸识别的朴素思路1.1 人脸识别问题的本质定义在聊具体算法之前得先把问题定义清楚。人脸识别严格来说包含两个子任务一是人脸检测从一张图里找到人脸的位置并框出来二是人脸识别本身把框出来的人脸和数据库里的身份对应起来。这两个任务经常被混为一谈但在工程上是完全不同的两件事用的模型、评价指标、优化方向都不一样。检测关心的是脸在哪识别关心的是这是谁。再往下拆识别又分人脸验证1:1判断两张脸是不是同一个人和人脸辨识1:N从一堆人里找出这张脸是谁。验证和辨识的难度差异巨大1:N的N越大误识率上升得越快这也是为什么门禁机通常只支持几百到几千人而上亿级的人脸库需要非常复杂的检索架构。理解这个定义很重要因为后面每一代算法的演化本质上都是在回答同一个问题如何把一张人脸图像映射成一个具有判别力的特征向量使得同一个人不同照片的特征距离近不同人之间的特征距离远。这个映射函数怎么设计就是整部演化史的主线。1.2 几何特征方法用五官距离描述一张脸最早的一批方法可以追溯到上世纪六七十年代思路非常朴素既然人脸是由眼睛、鼻子、嘴巴这些器官组成的那就测量这些器官之间的相对位置和距离用一组几何参数来描述一张脸。比如两眼间距、眼鼻距离、嘴巴宽度、脸型轮廓的比例等等把这些数字拼成一个向量就当作这张脸的特征。这种方法的优点是人能理解缺点是极其脆弱。你稍微歪个头、笑一下、戴个眼镜测出来的距离就全变了。而且从一张二维照片里精确提取五官关键点本身就是个难题早期靠手工标注或者简单的模板匹配误差很大。所以几何特征方法在实际项目里基本没有可用性它更多是学术探索阶段的一个起点。1.3 Eigenfaces与子空间降维的突破真正让人脸识别变得可用的第一个转折点是1991年提出的**Eigenfaces特征脸**方法。它的核心思想来自主成分分析PCA一张人脸图像可以看成是高维空间里的一个点比如一张100x100的灰度图就是10000维空间里的一个点。但人脸图像并不是均匀分布在这个空间里的它们集中在一个低维的子空间上。PCA做的事情就是找到这个子空间的主轴方向把高维的人脸图像投影到低维空间里用少数几个系数来表示一张脸。这些主轴方向还原成图像后看起来像一张张模糊的幽灵脸所以叫特征脸。识别的时候把待测人脸和库里每张人脸都投影到这个子空间比较投影系数的距离最近的就算匹配。这个方法在受控条件下正面、光照均匀、表情中性效果还不错而且计算量比逐像素比对小得多。但Eigenfaces有个致命问题PCA是无监督的它只关心如何用最少的维度重建人脸图像并不关心区分不同人这件事。换句话说它保留的是重建误差最大的方向而不是判别力最强的方向。两个人脸之间的差异可能恰好落在被PCA丢弃的那些维度上这就导致识别率上不去。1.4 Fisherfaces与LDA的判别式改进针对Eigenfaces的缺陷Fisherfaces方法引入了线性判别分析LDA。LDA是有监督的它的目标是最大化类间散度、最小化类内散度也就是让不同人的特征尽量分开同一个人的特征尽量聚拢。这个思路其实已经埋下了后来度量学习的种子——识别的本质是判别不是重建。Fisherfaces在标准人脸库上的识别率比Eigenfaces高出一截但它也有自己的限制LDA需要每个类别有足够的样本才能估计类内散度矩阵样本太少时会遇到矩阵奇异的问题需要做正则化或者降维预处理。而且这些子空间方法本质上都是线性的面对姿态、光照、表情这些非线性变化时能力有限。1.5 LBPH局部纹理特征的实用主义在子空间方法之外还有一条基于局部特征的路子其中最有代表性的是LBPH局部二值模式直方图。LBP的思路是对图像里每个像素比较它和周围一圈像素的灰度大小大于记1、小于记0拼成一个二进制数作为这个像素的纹理编码。然后把图像分成若干小块统计每块的LBP直方图拼起来作为整张脸的特征。LBPH的好处是对光照变化相对鲁棒因为LBP编码的是相对大小关系不是绝对灰度值。而且计算简单不需要训练OpenCV里直接有现成的实现。我在早期门禁项目里用过LBPH在光照可控的室内环境下几百人的库识别率能到八九成作为过渡方案是够用的。但它的天花板也很明显对姿态和表情变化敏感特征表达能力有限人一多误识率就上来了。这一整个阶段的方法我习惯称之为手工特征时代。它们的共同特点是特征是人根据经验设计出来的模型本身没有从数据里学习判别能力。这个局限最终被深度学习彻底打破。2. 深度学习入场卷积神经网络如何重塑特征提取2.1 从手工特征到学习特征的范式转移2012年是计算机视觉的分水岭。那一年AlexNet在ImageNet竞赛上把top-5错误率从26%直接拉到15%左右碾压了所有传统方法。这件事的意义不只是深度学习更强而是宣告了一个新范式特征不再需要人来设计网络可以从数据里自己学出来。对人脸识别来说这个转变是决定性的。传统方法里我们费尽心思设计LBP、HOG、Gabor这些特征本质上是在猜什么样的描述对识别人脸有用。而卷积神经网络CNN把这个猜测过程交给了数据和梯度下降。网络自己会学到浅层关注边缘和纹理中层关注眼睛鼻子这些部件深层关注整体的身份特征。这种层次化的特征表达是手工特征永远达不到的。2.2 卷积神经网络的三个核心机制要理解CNN为什么适合处理人脸图像得搞清楚它的三个核心设计。第一个是局部连接。传统全连接网络里每个神经元和上一层的所有神经元相连参数量爆炸。CNN假设图像里的有用模式是局部的比如一个边缘、一个角点所以每个卷积核只连接输入的一个小区域。这既大幅减少了参数又符合图像的局部相关性。第二个是权值共享。同一个卷积核在整张图上滑动用同一组权重去检测不同位置的同一种模式。这意味着不管眼睛出现在图像的左上角还是右下角同一个卷积核都能检测到它。这个特性叫平移不变性对人脸识别至关重要因为人脸在图像里的位置是不固定的。第三个是层次化抽象。通过堆叠多个卷积层和池化层网络能逐级构建越来越抽象的特征。浅层学到的边缘和纹理是通用的深层学到的身份特征是专用的。这种从具体到抽象的金字塔结构正是人脸识别需要的。2.3 早期人脸CNNDeepFace与DeepID的里程碑把CNN用到人脸识别上2014年前后出现了两个标志性工作Facebook的DeepFace和香港中文大学的DeepID系列。DeepFace的做法是先用3D模型把人脸对齐到一个标准姿态然后用一个9层的CNN提取特征最后用孪生网络的结构比较两张脸。它在LFW数据集上做到了97.35%的验证准确率第一次接近了人类的水平人类在LFW上大约97.5%。这个数字在当时是震撼的因为在此之前传统方法在LFW上卡在95%左右很久了。DeepID系列则探索了更深的网络结构和更多的监督信号把准确率进一步推高。这两个工作共同证明了一件事只要有足够的数据和合理的网络结构CNN能学到比任何手工特征都强的人脸表达。但这里有个关键问题需要点出来早期的这些网络训练目标往往还是分类——把每个人当成一个类别用softmax做多分类。这个思路在训练集人数固定时没问题但实际场景里人数是动态变化的今天来了个新人难道要重新训练整个网络这就引出了后面度量学习的整条演化线。2.4 分类训练与开集识别的矛盾用softmax分类训练人脸模型会遇到一个根本性的矛盾。分类任务假设测试时的类别一定在训练集里出现过这叫闭集识别。但人脸识别的真实场景是开集识别测试时遇到的人很可能不在训练集里系统需要判断这个人我不认识而不是硬把他分到某个已知类别。这个矛盾催生了度量学习的思路不再让网络输出这是第几号人而是让网络输出一个特征向量然后通过比较特征向量之间的距离来判断是不是同一个人。训练的目标从分类正确变成了同类特征近、异类特征远。这个转变是整个人脸识别算法演化史上最关键的一步也是损失函数这条主线真正登场的地方。3. 损失函数驱动的演化从Softmax到ArcFace的判别力竞赛3.1 度量学习的基本框架度量学习的框架其实很简单网络把输入的人脸图像映射成一个特征向量通常是128维或512维然后用一个距离度量最常用的是余弦相似度或欧氏距离来比较两个特征向量。训练时每次取几张同一个人的人脸正样本对和几张不同人的人脸负样本对让网络学会把正样本对拉近、负样本对推远。这个框架的代表是孪生网络和三元组损失Triplet Loss。三元组损失每次取三张图一张锚点Anchor、一张和锚点同人的正样本Positive、一张和锚点不同人的负样本Negative要求锚点到正样本的距离比锚点到负样本的距离小至少一个margin。FaceNet就是用这个方法做的在LFW上做到了99.63%。但三元组损失有个著名的痛点三元组的选取极其影响训练效果。如果负样本太容易区分比如随便选个长得完全不像的人网络学不到东西如果太难又容易导致训练不稳定。所以需要难例挖掘hard negative mining而这个过程计算量大、调参困难。我在复现FaceNet的时候就吃过这个亏三元组采样策略没设计好训练loss震荡得厉害最后收敛出来的模型还不如直接用softmax分类的。3.2 从Softmax到A-Softmax的边界改造既然三元组损失这么难伺候研究者开始想能不能直接在softmax上做文章让它天然具有度量学习的能力Softmax的决策边界是线性的它只要求不同类别的特征能被一条线分开但不要求同类特征聚拢、异类特征拉开足够大的间隔。于是**Large Margin SoftmaxL-Softmax和A-SoftmaxAngular Softmax**出现了它们的核心思路是在softmax的决策边界上引入一个角度margin强制网络把特征学得更加紧凑。A-Softmax也就是SphereFace的做法是把权重向量归一化让决策边界只取决于角度然后在角度上乘以一个整数m放大类间的角度间隔。这样训练出来的特征同类之间的角度更小异类之间的角度更大判别力显著提升。3.3 CosFace与ArcFace加性margin的胜利A-Softmax的margin是乘性的角度乘以m这导致它的优化比较困难而且margin随角度变化不均匀。后续的CosFaceAM-Softmax和ArcFace改用了加性margin思路更简洁也更有效。CosFace是在余弦值上减去一个margin mArcFace是在角度上加上一个margin m。两者殊途同归都是让正确类别的决策边界往内收缩逼迫网络学出更大的类间间隔。ArcFace因为几何意义更清晰直接在角度空间上加margin成为了目前工业界最主流的人脸识别损失函数之一。我用ArcFace做过一个几千人的考勤项目相比之前用普通softmax训练的模型在跨姿态和跨年龄的场景下误识率下降非常明显。这里的关键在于ArcFace的margin让模型对类内差异和类间差异的区分更加敏感泛化能力更强。3.4 损失函数演化的内在逻辑把这条线捋一遍会发现一个清晰的逻辑从能分开到分得开且聚得拢再到分得开、聚得拢且间隔大。损失函数核心机制主要问题Softmax线性决策边界类内散、类间间隔小Triplet Loss三元组距离约束难例挖掘困难训练不稳L-Softmax/A-Softmax乘性角度margin优化困难margin不均匀CosFace加性余弦margin角度空间解释不够直观ArcFace加性角度margin需要较大的batch和调参这张表基本概括了损失函数这条主线的演化。每一步都是在解决上一步留下的问题同时引入新的权衡。理解这个逻辑比死记每个损失函数的公式重要得多。4. 轻量化与工程落地从服务器到门禁机的最后一公里4.1 学术指标与工程现实的鸿沟在LFW、MegaFace这些数据集上刷到99%以上和在真实门禁机上稳定运行是两件完全不同的事。学术数据集大多是受控条件下采集的而真实场景里充满了各种挑战逆光、侧脸、戴口罩、低分辨率、运动模糊。更关键的是真实设备往往算力有限不可能跑一个几百兆的大模型。这就是轻量化这条线的价值所在。关键词里提到的剪枝算法、树莓派人脸识别、门禁机都是这个方向的具体体现。4.2 轻量网络结构的设计取舍轻量化网络的核心思路是在保持精度的前提下尽可能减少参数量和计算量。代表性的结构有MobileNet系列用深度可分离卷积替代标准卷积、ShuffleNet系列用通道混洗增强特征交流、以及各种基于NAS搜索出来的轻量结构。深度可分离卷积是其中最基础也最重要的一个技巧。标准卷积同时做空间滤波和通道融合计算量是卷积核大小乘以输入通道乘以输出通道。深度可分离卷积把它拆成两步先对每个通道单独做空间卷积depthwise再用1x1卷积做通道融合pointwise。这样计算量能降到原来的八分之一到九分之一精度损失却很小。我在树莓派上部署人脸识别时用的就是MobileNet的变体。实测下来在树莓派4B上一张224x224的人脸图推理时间能控制在几十毫秒配合一个轻量的人脸检测模型整体能做到接近实时的体验。如果用ResNet50这种大模型推理时间直接翻好几倍体验就崩了。4.3 模型剪枝与量化的实操要点除了换轻量结构还有两个常用的压缩手段剪枝和量化。剪枝的思路是训练好的网络里很多权重其实接近于零对输出贡献很小把它们去掉网络变小但精度基本不变。剪枝分结构化剪枝和非结构化剪枝前者直接砍掉整个通道或层能真正加速后者只是把个别权重置零需要专门的稀疏计算库才能加速实际部署时往往不划算。量化是把32位浮点权重压缩成8位整数甚至更低模型体积直接缩小四倍推理速度也能提升。但量化会带来精度损失需要做量化感知训练来补偿。我在门禁项目里做过INT8量化精度掉了不到一个百分点但推理速度提升了将近一倍性价比很高。提示剪枝和量化不要盲目上先在验证集上测精度损失如果掉得太多说明模型本身冗余度不够应该先考虑换更轻的结构。4.4 端侧部署的完整链路一个完整的人脸识别落地链路通常包含这几步人脸检测 → 关键点定位 → 人脸对齐 → 特征提取 → 特征比对。检测负责找到脸关键点定位找到眼睛鼻子这些位置对齐把脸摆正这一步对识别率影响很大歪脸直接喂给识别网络精度会掉一大截特征提取输出特征向量最后和库里的特征做比对。每一步都有工程上的坑。比如检测模型在逆光下容易漏检需要做图像预处理对齐时关键点定位不准会导致对齐后的脸扭曲特征比对时如果库里特征没做归一化余弦相似度和欧氏距离的结果会不一致。这些细节学术论文里通常不会讲但实际项目里每一个都能让你调半天。5. 我踩过的那些坑与选型建议5.1 数据集质量比模型结构更重要这是我做了这么多项目最深的体会。很多人一上来就纠结用哪个网络、哪个损失函数但真正决定识别率上限的是训练数据的质量和多样性。如果训练集里全是正面、光照均匀的照片模型在侧脸和逆光场景下必然拉胯。我的做法是宁可少几个身份也要保证每个身份有足够多的姿态、光照、表情变化。数据增强也很关键随机裁剪、旋转、亮度调整、加噪声这些都能显著提升泛化能力。有条件的话用同一个人不同时期的照片做训练对跨年龄识别帮助很大。5.2 阈值设定是个经验活人脸验证的阈值设定直接决定了误识率和拒识率的平衡。阈值设高了安全但用户体验差本人经常被拒设低了方便但容易被冒认。这个没有标准答案取决于你的场景。门禁场景通常要求高安全阈值要设高一些宁可让本人多刷几次也不能让陌生人混进去。而相册聚类这种场景误识的代价很低阈值可以设低一些追求更高的召回。我的经验是先在目标场景下采集一批真实数据画出ROC曲线根据业务能接受的误识率反推阈值而不是拍脑袋定一个0.5。5.3 活体检测不能省纯人脸识别有个天然的安全漏洞拿一张照片就能骗过系统。所以在门禁、支付这类场景活体检测是必须的。活体检测分配合式和静默式配合式要求用户眨眼、转头体验差但实现简单静默式靠分析纹理、反射、深度等信息体验好但实现复杂容易被高级攻击绕过。我在项目里用过配合式活体虽然用户体验一般但胜在可靠。如果场景允许加上红外或3D结构光安全性会高很多。5.4 选型建议速查场景推荐方案理由服务器端高精度识别ResNet100 ArcFace精度优先算力充足门禁机/考勤机MobileNet ArcFace精度与速度平衡树莓派等边缘设备MobileFaceNet 轻量检测算力受限需极致轻量相册聚类任意中等模型 低阈值召回优先误识代价低高安全场景识别 活体 多模态安全优先这张表是我根据实际项目经验总结的不是绝对标准但能帮你快速定位方向。核心原则是先明确场景的约束算力、精度要求、安全等级再倒推技术选型而不是反过来。人脸识别这条演化线从几何特征到子空间方法从手工特征到CNN从分类损失到度量学习每一步都是被真实问题推着往前走的。理解了这条线背后的为什么比记住一堆算法名字有用得多。技术还会继续演化但如何让同类聚拢、异类分开这个核心命题短期内不会变。
返回列表