
自監督學習:SimCLR 與 DINO - 讓無標註的監視器畫面自己當老師
標一張畫面要錢,監視器每天卻吐上萬張沒人標。自監督學習讓資料自己出考題:SimCLR 逼「同一畫面的兩個視角要相似」,DINO 用師生自蒸餾連負樣本都省了。本篇在筆電 CPU 上完整重現,實測驚喜與打臉並存:每類只給 1 張標籤時 SimCLR 海放原始像素 12 個百分點;但數字太簡單,標籤一多 raw pixels 就追平;精簡版 DINO 學得動卻明顯落後——一場關於「省標籤到底能省多少」的誠實實驗。
WRITTEN BY

- Name
- Harry Chang
核心貢獻者
Ting Chen 與 Geoffrey Hinton 領銜的 Google Brain 團隊於 2020 年發表 SimCLR《A Simple Framework for Contrastive Learning of Visual Representations》,核心精神就藏在標題的 Simple:丟掉所有花俏設計,只要「強力資料增強 + 大批次對比」,自監督學到的特徵就能逼近監督式。一年後,Mathilde Caron 等 Meta (FAIR) 團隊在 2021 年發表 DINO《Emerging Properties in Self-Supervised ViT》——名字是 self-DIstillation with NO labels 的縮寫:師生自蒸餾、完全不用負樣本,還意外長出了能分割物件輪廓的注意力。兩篇論文共同宣告:視覺特徵,不一定要靠人類標註才能學會。
為什麼要讓資料自己當老師?
Day 045 的門禁模型 fθ,是用「有標籤的人臉配對」訓練出來的——我們得先知道哪兩張是同一人,才能拉近推遠。但現實更殘酷:廠區監視器 24 小時運轉,每天錄下數萬張畫面,沒有任何一張有標籤。
問題卡在標註成本。要標「這格畫面有沒有人違規」,得請老師傅一張張看;幾萬張根本標不完。於是有了一個大膽的提問:能不能不靠人給答案,讓資料自己出題、自己改?
這就是自監督學習 (Self-Supervised Learning):從資料本身「無中生有」造出監督訊號。它的核心假設樸素得驚人——一張圖經過不同的裁切、旋轉、加噪之後,它還是同一張圖。模型只要學會「認出這件事」,就被迫理解了影像的內容。標註費太貴,就讓資料自己當老師。
1. 資料集來源
資料集:Digits (scikit-learn)
備註:
sklearn.datasets.load_digits一行載入,1797 張 8×8 灰階手寫數字、10 類。為了讓整套 SimCLR/DINO 在筆電 CPU 上完整可重現,這裡用它當「監視器畫面」的代理資料集 (proxy)。真實監視器是幾十萬張 224×224 的畫面,道理一模一樣,只是算力差三個數量級。
實驗設計:關鍵是「假裝沒有標籤」
- 無標註影片庫:把訓練集 1257 張全部當成「錄下來但沒人標」的畫面,做自監督預訓練——過程完全不看
y。 - 評估方式 (線性探測 Linear Probe):凍結學好的特徵,只用每類 K 張標籤訓練一個邏輯回歸,在 540 張測試集上驗收。K 從 1 掃到 50,看「省標籤」的極限在哪。
- 對照組:原始像素、隨機權重 encoder (沒訓練過的同款網路)、以及從頭訓練 CNN (拿少量標籤直接端到端硬 train)。
2. 原理
2.1 沒有人給答案,就讓資料自己出題
自監督的招式叫前置任務 (Pretext Task):設計一個「答案藏在資料裡」的假任務,逼模型在解題過程中學到有用的特徵。對比學習的前置任務是——判斷這兩個視角是不是來自同一張圖。
2.2 SimCLR:同一畫面的兩個視角要相似

如上圖,同一張數字經過旋轉、縮放、加噪、遮擋,產生多個視角 (view)。SimCLR 的規則簡單粗暴:
- 正樣本對:同一張圖的兩個增強視角,要在嵌入空間拉近。
- 負樣本:同批次裡其他所有圖的視角,一律推遠。
用的損失是 NT-Xent (溫度縮放的交叉熵),對一個正樣本對 :
- 增強是靈魂:增強太弱,模型靠背景就能配對,學不到內容;增強夠強,它才被逼著理解「這是個數字」。
- 大批次是本錢:批次越大,負樣本越多,對比訊號越銳利——這也是 SimCLR 出了名吃資源的原因。
SimCLR 架構:同一張無標籤圖產生兩個增強視角,各自通過權重共用的編碼器 fθ 與投影頭 g,得到 z1、z2;NT-Xent 把這對正樣本拉近、把批次內其他圖推遠。
2.3 DINO:師生自蒸餾,連負樣本都不要
SimCLR 需要一堆負樣本撐開空間,DINO 反其道而行:只有正向訊號,沒有負樣本。它擺兩個同款網路——學生 (student) 與老師 (teacher):
- 學生看視角 、老師看視角 ,學生要去預測老師輸出的機率分布——跨視角的自我一致。
- 老師不做反向傳播,而是學生的 EMA (指數移動平均):老師是學生的「慢速穩定版分身」。
DINO 架構:學生與老師看不同視角,學生去追老師輸出的機率分布(交叉熵);老師不回傳梯度、是學生的 EMA 慢速分身,再靠「扣 center + 低溫銳化」防止塌縮。
2.4 SimCLR vs DINO:兩種省標籤哲學
| 面向 | SimCLR | DINO |
|---|---|---|
| 監督訊號 | 對比 (正 vs 負) | 自蒸餾 (師生一致) |
| 需要負樣本 | 需要,且越多越好 | 完全不需要 |
| 抗塌縮機制 | 負樣本自然撐開 | centering + sharpening |
| 對批次大小 | 敏感 (大批次才強) | 相對不敏感 |
| 代表骨幹 | ResNet | ViT (Day 44 的主角) |
2.5 共同的頭號敵人:表徵塌縮
兩派方法看似南轅北轍,對抗的卻是同一個惡魔——塌縮 (Collapse):網路偷懶把所有圖都映射到同一個點,損失照樣很低,但特徵全廢 (這正是 Day 45 那個「損失卡在 margin」的老朋友)。SimCLR 靠負樣本硬撐開空間;DINO 沒有負樣本,改用兩招:centering (老師輸出扣掉移動平均,避免退化成單一類) 加上 sharpening (老師溫度 比學生低,讓分布更尖銳)。三招缺一,DINO 立刻塌給你看。
3. 實戰
Python 程式碼實作
# 增強:同一張圖呼叫兩次 = 兩個「視角」,這是自監督的燃料
def augment(x):
x = rand_affine(x) # 旋轉 ±15°、縮放、平移
x = x * (0.7 + 0.6 * torch.rand_like(x[:, :1, :1, :1])) # 強度抖動
x = x + 0.10 * torch.randn_like(x) # 高斯雜訊
return cutout(x).clamp(0, 1) # 隨機遮擋一小塊
# SimCLR:NT-Xent —— 正樣本是「另一個視角」,負樣本是批次裡其他所有圖
def nt_xent(z, temp=0.5):
z = F.normalize(z, dim=1) # 2N 個視角,住在單位球面
sim = z @ z.t() / temp
sim.fill_diagonal_(-1e9) # 挖掉「和自己比」
targets = (torch.arange(len(z)) + len(z) // 2) % len(z)
return F.cross_entropy(sim, targets) # 一行搞定對比損失
# DINO:student 追 teacher,靠三招防塌縮
s = F.log_softmax(head_s(enc_s(v1)) / 0.1, dim=1) # student 溫度高
with torch.no_grad(): # ③ teacher stop-grad
t = F.softmax((head_t(enc_t(v2)) - center) / 0.04, dim=1) # 低溫 sharpening + 扣 center
loss = -(t * s).sum(1).mean()
center = 0.9 * center + 0.1 * teacher_out.mean(0) # ① centering
for ps, pt in zip(enc_s.parameters(), enc_t.parameters()):
pt.mul_(0.996).add_(ps, alpha=0.004) # ② teacher = student 的 EMA
程式碼重點:
- 增強是自監督的燃料:仿射 + 強度抖動 + 雜訊 + cutout,同一張圖呼叫兩次就是兩個視角——沒有增強,對比學習無事可學。
- NT-Xent 一行交叉熵搞定:把對角線挖掉 (不跟自己比),正確答案標在「另一個視角」的位置。
- DINO 的防塌縮三開關:teacher 用 EMA 不回傳梯度、center 扣掉移動平均、teacher 溫度 (0.04) 比 student (0.1) 低。三招缺一,特徵全部塌成一坨。
4. 模型評估
標籤效率總成績 (每類 K 張標籤,測試集 540 張)
| 方法 | 每類1張 | 每類2張 | 每類5張 | 每類10張 | 每類20張 | 每類50張 |
|---|---|---|---|---|---|---|
| SimCLR (自監督) | 0.765 | 0.778 | 0.898 | 0.920 | 0.946 | 0.957 |
| DINO (自監督) | 0.633 | 0.635 | 0.735 | 0.783 | 0.867 | 0.894 |
| 原始像素 (基準) | 0.643 | 0.694 | 0.907 | 0.915 | 0.931 | 0.950 |
| 隨機權重 (對照) | 0.302 | 0.372 | 0.456 | 0.465 | 0.539 | 0.546 |
從頭訓練 CNN (端到端):每類 5 張 →
0.817;每類 50 張 →0.770(過擬合甚至倒退)。
少量標籤時,自監督海放

- 最左端是自監督的主場:每類只有 1~2 張標籤時,SimCLR (0.765) 大勝原始像素 (0.643) 整整 12 個百分點——特徵先學好,標籤稀缺時直接發威。
- 隨機權重只有 0.30:同款網路沒訓練過就這分數,證明 SimCLR 的能力是訓練學來的,不是網路結構撿到的。
- 從頭訓練 CNN 雙雙落敗:紅星每類 5 張 (0.817)、50 張 (0.770,過擬合倒退) 全輸給 SimCLR 線性探測。少標籤時,與其硬 train 一個 CNN,不如拿凍結的自監督特徵配一個邏輯回歸。
沒看過標籤,類別自己分開

把 SimCLR 的測試集特徵投影到 2D——全程沒餵過任何一個標籤,數字 0、1、4、7 卻自己聚成了清楚的團 (中央 3/5/8/9 有些重疊,是 2D 投影與數字本身相似所致)。這就是自監督的本質:它學到的不是「這是幾」,而是影像相似性這個概念本身。
誠實的打臉:數字太簡單
這篇的結果不全是漂亮話,兩個必須講清楚的地方:
- 標籤一多,原始像素就追平:每類 5 張以上時,raw pixels (0.907) 甚至小勝 SimCLR (0.898)。因為 8×8 數字太簡單、像素本身就近乎線性可分。自監督的紅利會隨「資料變難、標籤變少」而放大;在這種玩具級任務上,它的優勢集中在最左端。
- 精簡版 DINO 明顯落後:我們的 DINO 損失有在降 (11 → 9,確實學得動),但全程輸給 SimCLR。DINO 原論文的驚艷靠的是 ViT + multi-crop + 長訓練排程;剝到最精簡,它比 SimCLR 更難調——方法真正的威力,常常藏在工程細節裡。
工安視角的解讀
- 喚醒沉睡的監視器資料:廠區攝影機錄了幾年,幾乎全是無標註畫面。自監督能先把這些資料變成一座「特徵庫」,日後任何下游任務 (誰沒戴安全帽、誰闖入禁區) 只要少量標籤就能微調上線。
- 標註成本的算術:標一張工安違規畫面要老師傅逐格判讀,幾萬張標不完。自監督把「非標不可的量」砍到零頭——這是它最務實的價值。
- 個資友善:同 Day 45,資料庫存的是特徵向量而非原始畫面,對隱私更友善。
- 誠實提醒:玩具級 0.9 不等於產線級。真實場景 (SimCLR/DINO 跑在 ResNet/ViT、百萬張畫面) 才是紅利真正爆發之處;但省標籤的核心數學,和這篇一模一樣。
5. 總結
我們學習了自監督與對比學習:
- 換一個老師:不靠人標答案,讓資料自己出題——「同一張圖的兩個視角要相似」就是免費的監督訊號。
- 兩種哲學:SimCLR 用正負樣本對比 (大批次是本錢);DINO 用師生自蒸餾 (centering + sharpening 防塌縮,連負樣本都省)。共同敵人都是表徵塌縮。
- 實驗結論:每類 1 張標籤時 SimCLR 海放像素 12 個百分點、也輾壓從頭訓練;但數字太簡單,標籤一多優勢就收斂——自監督的紅利屬於「資料多、標籤少、任務難」的真實世界。
- 工安啟示:監視器畫面天生無標註,自監督把它們變成可用的特徵庫,讓下游工安任務用最少的標註成本落地。
下一篇把「不用標籤」再推一步:如果連「同類」都不必自己定義,直接拿網路上的圖片與文字配對來學呢?CLIP 多模態對齊——讓模型看懂文字與影像的共同語義,直接打字「沒戴安全帽的人」,就能在監視器畫面裡把人一個個撈出來。