4. 人脸特征提取:从传统方法到深度学习的演进

说到人脸特征提取,我刚开始做这个方向时,用的还是传统方法。那时候深度学习还没火起来,大家靠手工设计的特征吃饭。说白了,就是想办法把一张人脸图片,变成一串能代表“这个人是谁”的数字。

这串数字,就是我们今天要聊的核心——Embedding向量。

核心概念:Embedding向量是人脸在特征空间中的“坐标”。好的特征提取方法,能让同一个人的坐标靠得近,不同人的坐标离得远。

4.1 传统方法:LBP与HOG

先聊聊传统方法。我2014年做安防项目时,用的就是LBP。那时候觉得这方法真巧妙——用局部纹理模式来描述人脸。

4.1.1 LBP(局部二值模式)

LBP的原理其实很直观:

  • 对每个像素,比较它和周围8个邻居的灰度值
  • 比它大的记1,比它小的记0
  • 得到一个8位二进制数,转成十进制就是LBP值

举个例子:

原始灰度值:  120  130  90
              110  100  80
              95   105  85

比较结果:    1    1    0
              1    0    0
              0    1    0

二进制序列:11010010 → 十进制:210

嗯,这里要注意。LBP对光照变化比较鲁棒,但有个致命问题——它只描述纹理,不描述形状。我遇到过这样的情况:两个人脸纹理相似但五官不同,LBP就分不清了。

我的经验:LBP适合做人脸检测的粗筛,但不适合做精确识别。我在项目中通常用它做预处理,把明显不是目标的人脸快速过滤掉。

4.1.2 HOG(方向梯度直方图)

HOG的思路完全不同。它统计图像局部区域的梯度方向分布。说白了,就是看人脸轮廓的“走向”。

HOG的提取步骤:

  1. 计算梯度:用Sobel算子算每个像素的水平和垂直梯度
  2. 划分细胞单元:把图像分成8×8的小块
  3. 统计方向直方图:每个细胞单元统计9个方向的梯度强度
  4. 块归一化:把2×2的细胞单元组成一个块,做局部归一化
  5. 串联特征:把所有块的特征向量拼起来

一张64×128的人脸图,HOG特征维度大约是3780维。你想想看,这么高的维度,计算量可不小。

避坑指南:我曾经在嵌入式设备上跑HOG,发现帧率只有5fps。后来把图像缩放到32×64,特征维度降到756维,帧率才提到15fps。传统方法对计算资源很敏感,部署前一定要做性能评估。

4.2 传统方法的局限

我做了两年传统方法,越来越觉得力不从心。主要问题有三个:

问题 具体表现 影响
光照敏感 侧光、逆光下特征变化大 同一个人在不同光照下可能被识别为不同人
姿态鲁棒性差 人脸偏转超过30°时效果急剧下降 实际场景中很难要求用户正对摄像头
特征维度高 LBP约256维,HOG约3780维 存储和计算开销大,不适合大规模检索

为什么会这样?因为传统特征是“手工设计”的,它只能捕捉到人脸的局部模式,无法理解人脸的整体语义。说白了,它不知道什么是“眼睛”,什么是“鼻子”。

4.3 深度学习的崛起:FaceNet

2015年,Google的FaceNet出来时,我整个人都震惊了。它用深度学习直接学习从人脸图像到Embedding向量的映射,端到端训练,不需要手工设计特征。

4.3.1 FaceNet的核心思想

FaceNet用了一个叫三元组损失(Triplet Loss)的玩意儿。它的想法很巧妙:

  • 选三张图:锚点(Anchor)、正样本(Positive)、负样本(Negative)
  • 锚点和正样本是同一个人的不同照片
  • 负样本是另一个人的照片
  • 训练目标是:让锚点和正样本的距离近,和负样本的距离远

损失函数长这样:

L = max(d(A,P) - d(A,N) + margin, 0)

其中d是欧氏距离,margin是个超参数(通常设为0.2)。

关键点:FaceNet输出的Embedding向量是128维。相比HOG的3780维,压缩了近30倍,但识别精度反而更高。这就是深度学习的魅力——自动学习最有效的特征表示。

4.3.2 我在项目中用FaceNet的体会

2017年,我在一个智慧园区项目里用了FaceNet。效果确实比传统方法好,但有个坑——三元组的选择太难了。

你想想看,如果随机选三元组,大部分都是“简单样本”:锚点和负样本本来就差别很大,模型学不到东西。我后来用了难样本挖掘策略:只选那些锚点和负样本距离比较近的三元组,强迫模型去区分难区分的对。

实用技巧:训练FaceNet时,建议每轮迭代都重新计算所有样本的Embedding,然后在线生成难三元组。离线生成的三元组容易过拟合。

4.4 更进一步的ArcFace

FaceNet虽然好,但三元组损失有个问题——它只关心相对距离,不关心角度。2018年,ArcFace提出了加性角度间隔损失,把问题从欧氏空间搬到了超球面上。

4.4.1 ArcFace的原理

ArcFace的核心改进:

  • 把特征向量归一化到单位超球面上
  • 在角度空间中增加一个固定的间隔m
  • 让同类样本在球面上更紧凑,异类样本更分散

损失函数变成:

L = -log( e^(s*cos(θ_y+m)) / (e^(s*cos(θ_y+m)) + Σ e^(s*cos(θ_j)) ) )

其中θ_y是特征向量和真实类别权重的夹角,m是角度间隔(通常设为0.5),s是特征缩放因子(通常设为64)。

方法 特征空间 损失函数 LFW精度 Embedding维度
LBP 欧氏空间 无(手工特征) ~85% 256
HOG 欧氏空间 无(手工特征) ~88% 3780
FaceNet 欧氏空间 Triplet Loss ~99.2% 128
ArcFace 超球面 ArcFace Loss ~99.8% 512

注意:ArcFace的512维Embedding虽然比FaceNet的128维大,但精度提升明显。我建议在安全等级高的场景(如金融支付)用ArcFace,在实时性要求高的场景(如门禁)用FaceNet。

4.5 Embedding向量的本质

说了这么多,到底什么是Embedding向量?

我个人习惯把它理解成人脸在特征空间中的“身份证号”。但这个身份证号不是随机的,而是有数学意义的:

  • 语义相似性:同一个人在不同条件下的Embedding向量距离很近
  • 判别性:不同人的Embedding向量距离很远
  • 紧凑性:用低维向量表示高维人脸信息

举个例子:

# 假设我们有两个人的Embedding向量
person_A = [0.12, 0.34, -0.56, ..., 0.78]  # 512维
person_B = [0.15, 0.31, -0.52, ..., 0.81]  # 512维

# 计算余弦相似度
cos_sim = dot(person_A, person_B) / (norm(person_A) * norm(person_B))
# 如果cos_sim > 0.7,认为是同一个人

嗯,这里要注意。Embedding向量的质量取决于训练数据的质量和多样性。我见过一个项目,训练数据全是亚洲人脸,结果在欧美人的识别上精度暴跌。数据分布一定要覆盖实际场景。

4.6 方法演进路线图

为了让你更直观地理解整个演进过程,我画了张图:

人脸特征提取方法演进路线 2000年 2005年 2015年 2018年 LBP HOG FaceNet ArcFace 256维 3780维 128维 512维 传统手工特征 深度学习特征 关键改进 • 传统方法:手工设计特征提取算子,依赖专家经验 • FaceNet:端到端学习,Triplet Loss优化,128维Embedding • ArcFace:角度间隔损失,超球面特征空间,512维Embedding • 趋势:特征维度降低,判别性增强,鲁棒性提升

4.7 实际选型建议

最后,结合我的项目经验,给你一些选型建议:

应用场景 推荐方法 理由
低算力设备(如门禁) FaceNet(128维) Embedding小,匹配速度快
高安全场景(如支付) ArcFace(512维) 精度高,误识率低
大规模检索(百万级) ArcFace + 量化 512维量化到128维,精度损失小
快速原型验证 FaceNet预训练模型 开箱即用,不需要自己训练

我的建议:如果你刚开始做人脸识别,先用FaceNet的预训练模型跑通流程。等理解了Embedding向量的含义,再考虑用ArcFace提升精度。别一上来就追求最先进的方法,先把基础打牢。

从LBP到ArcFace,这二十年的演进,说白了就是一句话:从“人教机器看脸”变成了“机器自己学会看脸”。Embedding向量就是机器学会的“看脸方式”。理解了这个本质,你就能灵活运用各种方法了。