
度量學習:Siamese 網路與 Triplet Loss - 人臉門禁的少樣本比對
新員工到職只有一張註冊照,分類器束手無策——因為門禁要的不是「認得誰」,是「會認人」。本篇介紹度量學習:Siamese 雙塔架構、Contrastive 與 Triplet Loss、FaceNet 的難例挖掘,並完整公開一段訓練踩坑實錄:從輸給 30 年前的特徵臉,到嵌入塌縮,再到 BatchNorm 逆轉登頂。
WRITTEN BY

- Name
- Harry Chang
核心貢獻者
Jane Bromley 與 Yann LeCun (AT&T 貝爾實驗室) 於 1993 年為「支票簽名驗證」發明了 Siamese 網路——連體嬰般共享權重的雙塔架構,名字就取自連體雙胞胎。沉寂二十年後,Florian Schroff 等人 (Google) 於 2015 年發表 FaceNet,用 Triplet Loss 加上難例挖掘,在人臉驗證任務上一舉超越人類水準 (99.63% on LFW),奠定了至今所有人臉門禁系統的技術底座。
為什麼門禁不能用分類器?
假設用 Day 13 的 CNN 做 40 個員工的人臉分類器,馬上撞牆:
- 新員工到職怎麼辦? 分類器的輸出層寫死 40 類,加一個人就要改架構、重新訓練。
- 每人只有一張註冊照:分類器要每類幾百張才學得動,HR 只會給你一張大頭照。
- 離職員工怎麼辦? 又要重訓。
問題出在提問方式。分類器學的是「這是誰」,但門禁真正需要的是「這兩張是不是同一個人」——前者綁死名單,後者是一種通用能力。度量學習 (Metric Learning) 學的就是後者:把照片映射到一個嵌入空間,同一人的照片距離近、不同人距離遠。學會之後,任何陌生人都適用:新員工到職,把註冊照的嵌入向量存進資料庫就完事,模型一個參數都不用動。
1. 資料集來源
資料集:Olivetti Faces (AT&T)
備註:
sklearn.datasets.fetch_olivetti_faces一行載入。40 人、每人 10 張、64×64 灰階——正好是「小工廠門禁」的規模感。
實驗設計:關鍵在「陌生人」
- 訓練集:前 30 人 (300 張)——模型只從他們身上學「怎麼比較人臉」。
- 測試集:後 10 人 (100 張)——模型從沒見過的陌生人,考兩個門禁任務:
- 驗證 (1:1):兩張照片是不是同一人?(450 對本人 + 450 對冒充者,看 AUC)
- 單張註冊識別 (1:N):每人只用第 1 張照片當註冊照,其餘 90 張當刷臉查詢,看 Rank-1 命中率。
- 對照組:原始像素距離、PCA-50 特徵臉 (Day 08 的老朋友,1991 年的技術)。
2. 原理
2.1 Siamese 架構:一個網路,照兩次鏡子

兩張照片分別通過同一個 (共享權重的) 嵌入網路 ,各得到一個向量,然後只比較距離:
「雙塔」其實是同一座塔照兩次——這保證了嵌入空間的一致性:比較的標準對所有人都一樣。
2.2 Contrastive Loss:拉近本人,推開陌生人
- (同一人):最小化 ,把兩者拉近。
- (不同人):只要距離小於邊界 就懲罰,把兩者推開到 m 之外——超過 m 就不管了,不浪費力氣。
2.3 Triplet Loss:三人行必有我師
FaceNet 的升級版一次看三張:錨點 (Anchor)、同一人的正例 (Positive)、別人的負例 (Negative):
- 目標:本人距離要比陌生人距離近至少 m——學的是「相對排序」而不是絕對距離,更貼近門禁的實際決策。
- 難例挖掘 (Batch-Hard Mining) 是靈魂:隨機抽的三元組大多太簡單 (損失為 0,白算)。FaceNet 的做法是每批抽 P 人 × K 張,對每個錨點只挑最遠的本人和最近的陌生人來學——專攻長得像的陌生人與狀態差很多的本人。
2.4 訓練踩坑實錄:一段誠實的調參記
這篇的模型不是一次到位的,四個版本的心電圖值得公開:
| 版本 | 配方 | 陌生人驗證 AUC | 診斷 |
|---|---|---|---|
| v1 | Contrastive、隨機配對、30 輪 | 0.876 | 欠訓練,輸給 1991 年的特徵臉 |
| v2 | 同上、300 輪 + 翻轉增強 | 0.896 | 損失有降,泛化沒跟上——隨機配對太簡單 |
| v3 | Batch-Hard Triplet、450 迭代 | 0.916 | 追平基準;但損失長期卡在 0.20 (= margin) |
| v4 | v3 + BatchNorm + 900 迭代 | 0.962 | 反超登頂 |
- v3 的症狀是經典教材:損失恰好停在 margin 值,代表嵌入塌縮 (Collapse)——網路把所有照片映射到幾乎同一個點,,損失自然等於 m。
- v4 的解方:卷積層之間插入 BatchNorm,穩住特徵分布,塌縮立刻解除 (300 迭代後訓練損失歸零)。從頭訓練嵌入網路,BatchNorm 不是選配。
3. 實戰
Python 程式碼實作
class EmbedNet(nn.Module):
def __init__(self, dim=64):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(1, 32, 3, padding=1), nn.BatchNorm2d(32), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(32, 64, 3, padding=1), nn.BatchNorm2d(64), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(64, 128, 3, padding=1), nn.BatchNorm2d(128), nn.ReLU(),
nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Linear(128, dim))
def forward(self, x):
return nn.functional.normalize(self.net(x), dim=1) # 單位球面上比距離
def batch_hard_triplet(Z, labels, margin=0.2):
"""FaceNet 式難例挖掘:每個錨點只學最難的正例與負例"""
D = torch.cdist(Z, Z)
same = labels[:, None] == labels[None, :]
hardest_pos = D.masked_fill(~same, 0).max(1).values # 最遠的本人
hardest_neg = D.masked_fill(same, float('inf')).min(1).values # 最近的陌生人
return (hardest_pos - hardest_neg + margin).clamp(min=0).mean()
程式碼重點:
- 嵌入向量做 L2 正規化,所有人臉都住在單位球面上,距離範圍固定 (0 到 2),門檻才好訂。
- 批次組成必須是 P 人 × K 張 (本篇 15×4),難例挖掘才有料可挖。
4. 模型評估
三方法 × 兩任務總成績 (10 個陌生人)
| 方法 | 驗證 AUC (1:1) | 單張註冊識別 Rank-1 (1:N) |
|---|---|---|
| Raw pixels | 0.9158 | 0.6556 |
| PCA-50 特徵臉 (1991) | 0.9181 | 0.7000 |
| Siamese embedding (v4) | 0.9622 | 0.7778 |
距離分布:門禁決策的全貌

- 左圖 (原始像素):綠 (本人) 紅 (冒充者) 大面積重疊——不管門檻切哪裡,都是大量誤放行或誤拒門。
- 右圖 (Siamese):兩座山明顯分開,門檻切在 0.8 附近就能兼顧。門禁系統的品質,就是這兩座山的距離。
嵌入空間:從沒見過的人,自動各聚一團

10 個陌生人的 100 張照片投影到 2D——模型從未見過任何一位,他們卻在嵌入空間自動聚成一團一團。這就是度量學習的本質:它學會的不是 40 張臉,是「人臉相似性」這個概念本身。
那個 1.11 的難例
回頭看配對範例圖:第一組明明是同一人,學到的距離卻高達 1.11——比第四組陌生人配對 (1.00) 還遠。眼鏡反光加表情變化,連模型都會看走眼。工安落地的對應設計:門檻內直接放行、門檻外不是拒絕而是「請再刷一次/轉人工」——誤拒率每提高 1%,員工每天早上的怨氣都會告訴你。
工安視角的解讀
- 承攬商管理是真正的主場:廠區每天進出的施工承攬商,每人只有進場申請時的一張證件照——這正是「單張註冊識別」場景,分類器無解,度量學習原生支援。
- 個資的意外好處:資料庫存的是 64 維嵌入向量,不是照片本身;向量無法還原成人臉,對《個資法》的遵循比存照片友善得多。
- 誠實的提醒:本篇 0.96 的 AUC 是教學規模;產線等級的門禁 (FaceNet、ArcFace) 靠的是百萬級身分的預訓練——自建門檻高,商用方案的內核也是同一套數學。
5. 總結
我們學習了度量學習與 Siamese 網路:
- 換一個問題:不學「這是誰」,學「像不像」——新員工註冊一張照片即用,模型零重訓。
- 兩代損失函數:Contrastive (拉近/推開) 到 Triplet (相對排序),而難例挖掘才是 FaceNet 超越人類的關鍵。
- 踩坑實錄:隨機配對學不動、損失卡在 margin 是塌縮警報、BatchNorm 是從頭訓練的救命符——AUC 從 0.876 一路修到 0.962。
- 工安啟示:門禁與承攬商管理天生是少樣本問題;嵌入向量比照片更省、更快、更合規。
下一篇把「不用標籤」推到極致:監視器每天錄下數萬張無人標註的畫面,能不能讓模型自己教自己?自監督與對比學習 (SimCLR、DINO)——標註費太貴,就讓資料自己當老師。