人脸识别有个反直觉的地方:它本质上不是一个分类问题。如果你把它当成分类,那么世界上每新增一个人,模型就要多一个输出类别、就要重训——这显然不现实。真正能落地的人脸识别系统解决的是一个开放集(open-set)问题:把任意一张脸映射成一个向量,让"同一个人"的向量靠得近、"不同人"的向量离得远。这套思路叫度量学习(metric learning),核心产物叫特征嵌入(embedding)

直觉:从识别到比对

完整管线大致是:检测(找到脸在哪)→ 关键点对齐(把脸摆正)→ 嵌入(提特征向量)→ 比对(算相似度)。前两步是预处理,真正的智能在第三步。

对齐这一步常被低估。检测出人脸框后,用 5 个或更多关键点(眼、鼻、嘴角)做仿射变换,把脸归一化到标准姿态和尺度。对齐质量直接决定上限:歪着的脸、侧脸会让同一个人的嵌入漂移,再好的模型也救不回来。

嵌入阶段,一个 CNN(或 ViT)骨干网络把对齐后的人脸图像 xx 映射成向量 f(x)Rdf(x) \in \mathbb{R}^ddd 通常是 128、256 或 512。识别时不再做分类,而是算两张脸嵌入的距离或余弦相似度,跟阈值比:

same(x1,x2)=[cos(f(x1),f(x2))>τ]\text{same}(x_1, x_2) = \big[\, \cos(f(x_1), f(x_2)) > \tau \,\big]

这种设计的好处是一次训练,永久通用:新来一个人,只需存一张照片的嵌入作为底库,无需重训模型。这就是"1:N 检索"和"1:1 核验"能工作的根基。

机制:怎么学出好的嵌入

关键问题是:用什么损失函数,能逼着网络把同人拉近、异人推远?这条线索的演进非常清晰。

Triplet Loss——直接但难训

最直观的是三元组损失。每次取一个锚点 aa、一个正样本 pp(同人)、一个负样本 nn(异人),要求正样本距离比负样本距离至少近一个 margin mm

L=max(0, f(a)f(p)2f(a)f(n)2+m)\mathcal{L} = \max\big(0,\ \|f(a)-f(p)\|^2 - \|f(a)-f(n)\|^2 + m\big)

思路漂亮,但工程上很痛:三元组的组合是 O(N3)O(N^3) 量级,绝大多数三元组都是"轻松满足约束"的简单样本,梯度为零、毫无信息。于是必须做难样本挖掘(hard mining)——专门找那些异人却长得像、同人却差异大的三元组。挖掘做得不好,训练要么不收敛要么塌陷。

从 Softmax 到角度间隔

后来主流转向了改造分类损失。训练时仍然用分类头(每个训练身份是一类),但在 softmax 上动手脚,逼出更好的嵌入几何。

先把权重和特征都做 L2 归一化,此时 logit 变成余弦:Wjf=Wjfcosθj=cosθjW_j^\top f = \|W_j\|\|f\|\cos\theta_j = \cos\theta_j(归一化后模长为 1)。然后把特征缩放到半径 ss,并在目标类的角度上加一个间隔(margin),让同类必须挤得更紧才能被正确分类。一种广泛使用的形式(加性角度间隔)是:

L=logescos(θy+m)escos(θy+m)+jyescosθj\mathcal{L} = -\log \frac{e^{s\cos(\theta_{y}+m)}}{e^{s\cos(\theta_{y}+m)} + \sum_{j\neq y} e^{s\cos\theta_j}}

直觉解释:普通 softmax 只要求"目标类分数最大"就够了,决策边界松。而 θy+m\theta_y + m 相当于人为给目标类"加难度"——必须让真实类的角度比其它类小一个 margin 才算分对。结果是同类样本在超球面上被压成更紧的簇,类间留出更大的角度间隔。这类角度间隔损失训练比 triplet 稳定得多,也不需要复杂的三元组挖掘,成了现代人脸嵌入的主流。

1
2
3
4
5
6
7
8
# 角度间隔 softmax 的核心逻辑(示意)
f = l2_normalize(backbone(x)) # 特征归一化, [B, d]
W = l2_normalize(W, axis=0) # 类中心归一化, [d, C]
cos = f @ W # 余弦相似度, [B, C]
theta = arccos(clamp(cos, -1+eps, 1-eps))
target_logit = cos(theta + m) # 仅对真实类加 margin
logits = s * scatter(cos, target_idx, target_logit)
loss = cross_entropy(logits, labels)

注意 ss(尺度)和 mm(间隔)都是关键超参:ss 太小梯度饱和学不动,mm 太大训练不收敛。

推理与检索:嵌入怎么用

训练完成后,分类头被丢弃,只保留骨干网络做嵌入器。

  • 1:1 核验(这是不是本人):算两个嵌入的余弦相似度,跟阈值比。刷脸支付、过闸机就是这个模式。
  • 1:N 检索(这是谁):把待识别嵌入和底库 NN 个嵌入逐一比对取最相似。底库大时用 ANN 索引(如 HNSW)加速,从 O(N)O(N) 降到约 O(logN)O(\log N)

因为嵌入都归一化到单位超球面上,余弦相似度等价于欧氏距离的单调变换,二者择一即可。

工程权衡与边界

  1. 阈值即策略。同一个模型,调高 τ\tau 会降低误识率(FAR,把陌生人当成本人)但升高拒识率(FRR)。安防场景要极低 FAR,宁可多拒;考勤场景更在意体验,可放宽。ROC 曲线和 FAR@FRR 工作点的选择是产品决策,不是模型决策。
  2. 类别极度不均衡与长尾。训练身份成千上万,但每个身份样本数差异巨大。长尾身份的类中心学不充分,是精度瓶颈之一。
  3. 域偏移。训练集多是清晰正脸,线上却有逆光、口罩、低分辨率、跨年龄。嵌入对这些变化不鲁棒就会失效,需要针对性数据增强或专门训练。
  4. 活体检测是另一个系统。识别只回答"嵌入像不像",但照片、视频、面具能轻易骗过纯识别模型。防攻击靠独立的活体检测(红外、结构光、动作配合),不要把它和识别混为一谈。

小结

人脸识别的精髓是把"识别"转化为"嵌入 + 比对":用度量学习训练一个把人脸映射到超球面的编码器,让几何距离编码身份相似度。损失函数从 triplet 的难样本挖掘演进到角度间隔 softmax,本质都是在做同一件事——压缩类内、扩张类间。理解了这一点,检索、阈值、长尾、域偏移这些工程问题就都能挂在同一根主线上。