半監(jiān)督學(xué)習(xí)實(shí)戰(zhàn):從標(biāo)注匱乏到準(zhǔn)確率89%的完整方案)
做圖像分類(lèi)項(xiàng)目時(shí)最扎心的不是模型選得不夠花而是標(biāo)注數(shù)據(jù)根本不夠用。我去年接手一個(gè)真實(shí)業(yè)務(wù)場(chǎng)景總共只有不到一千張人工標(biāo)注圖手里卻壓著幾十萬(wàn)張完全沒(méi)標(biāo)注的原始圖片。外包標(biāo)一輪問(wèn)了下報(bào)價(jià)直接放棄了。后來(lái)靠半監(jiān)督學(xué)習(xí)硬生生把分類(lèi)準(zhǔn)確率從78%拉到89%整個(gè)過(guò)程沒(méi)額外標(biāo)過(guò)一張圖。今天就把這套圖像分類(lèi)半監(jiān)督學(xué)習(xí)的完整思路和實(shí)操經(jīng)驗(yàn)整理出來(lái)核心方法怎么拆解、損失函數(shù)怎么設(shè)、訓(xùn)練時(shí)踩過(guò)哪些坑、什么情況下別硬上一條條說(shuō)清楚你們可以直接拿著調(diào)。1. 半監(jiān)督學(xué)習(xí)的核心思路與方案選型1.1 為什么要用半監(jiān)督學(xué)習(xí)標(biāo)注瓶頸才是真問(wèn)題很多人一提到圖像分類(lèi)第一反應(yīng)就是堆數(shù)據(jù)、上大模型。但真實(shí)項(xiàng)目里干凈、準(zhǔn)確、覆蓋所有類(lèi)別分布的標(biāo)注數(shù)據(jù)永遠(yuǎn)是稀缺資源。標(biāo)注成本高不只是錢(qián)的問(wèn)題還有時(shí)間成本醫(yī)學(xué)影像需要專(zhuān)業(yè)醫(yī)生逐張看工業(yè)質(zhì)檢缺陷圖需要老師傅確認(rèn)電商圖片需要熟悉商品體系的人打標(biāo)。這個(gè)過(guò)程又慢又貴而且標(biāo)注質(zhì)量不穩(wěn)定返工率高。反過(guò)來(lái)看無(wú)標(biāo)注數(shù)據(jù)幾乎遍地都是。監(jiān)控視頻抽幀、服務(wù)器上積壓的歷史圖片、爬蟲(chóng)采集的公開(kāi)圖像、生產(chǎn)線自動(dòng)拍攝的樣張這些數(shù)據(jù)沒(méi)有標(biāo)簽但數(shù)量可能是標(biāo)注數(shù)據(jù)的幾百倍。半監(jiān)督學(xué)習(xí)解決的就是這個(gè)問(wèn)題利用大量無(wú)標(biāo)注數(shù)據(jù)來(lái)提升模型的泛化能力讓模型在沒(méi)有額外標(biāo)注的情況下把分類(lèi)邊界學(xué)得更準(zhǔn)。它的適用人群也很明確手里有少量干凈標(biāo)注數(shù)據(jù)、同時(shí)有大量無(wú)標(biāo)注數(shù)據(jù)、但預(yù)算不足以繼續(xù)擴(kuò)標(biāo)注集的工程師和研究者。如果你已經(jīng)有十萬(wàn)張完美標(biāo)注的數(shù)據(jù)那直接走監(jiān)督學(xué)習(xí)就行半監(jiān)督的收益邊際不大。反過(guò)來(lái)如果標(biāo)注只有幾百?gòu)垺⒚款?lèi)幾十張半監(jiān)督幾乎是你成本最低的提點(diǎn)手段。1.2 半監(jiān)督到底在學(xué)什么三個(gè)基礎(chǔ)假設(shè)要理解半監(jiān)督學(xué)習(xí)必須弄明白它依賴(lài)的三個(gè)前提假設(shè)。這些假設(shè)既是方法有效性的來(lái)源也是翻車(chē)的原因。第一個(gè)是聚類(lèi)假設(shè)。同類(lèi)樣本在特征空間中應(yīng)當(dāng)彼此靠近。如果兩個(gè)樣本的特征表示很接近那它們的類(lèi)別大概率相同。模型可以利用無(wú)標(biāo)注數(shù)據(jù)來(lái)感知這種聚集結(jié)構(gòu)讓決策邊界更貼合數(shù)據(jù)分布。第二個(gè)是平滑假設(shè)。在數(shù)據(jù)分布的高密度區(qū)域決策邊界應(yīng)當(dāng)是平滑的。也就是說(shuō)對(duì)特征空間中的某個(gè)樣本做小擾動(dòng)其預(yù)測(cè)結(jié)果不應(yīng)發(fā)生劇烈變化。這給了半監(jiān)督方法一個(gè)操作抓手讓模型對(duì)“變形后的同一張圖”也保持穩(wěn)定輸出。第三個(gè)是低密度分離假設(shè)。不同類(lèi)別之間的決策邊界應(yīng)該穿過(guò)數(shù)據(jù)密度較低的區(qū)域。如果模型能把大量無(wú)標(biāo)注樣本分到明確的類(lèi)別簇中而類(lèi)別之間的空白地帶沒(méi)有樣本那說(shuō)明分類(lèi)邊界大概率是對(duì)的。這三個(gè)假設(shè)用大白話講就是長(zhǎng)得像的應(yīng)該歸一類(lèi)、換了個(gè)說(shuō)法意思不變、類(lèi)別中間最好留出空地。所有半監(jiān)督方法本質(zhì)上都是在用不同方式讓模型滿足這些假設(shè)。1.3 三條技術(shù)路線和我的選型建議目前圖像分類(lèi)半監(jiān)督主流有三條技術(shù)路線。第一條是一致性正則代表思路有 Π-Model、Temporal Ensembling、Mean Teacher。核心做法是對(duì)同一個(gè)輸入做兩次不同的隨機(jī)增強(qiáng)要求模型輸出一致。這種方式不依賴(lài)偽標(biāo)簽但收斂慢對(duì)增強(qiáng)策略敏感。第二條是偽標(biāo)簽法也就是自訓(xùn)練。先用標(biāo)注數(shù)據(jù)訓(xùn)練一個(gè)模型對(duì)無(wú)標(biāo)注數(shù)據(jù)預(yù)測(cè)出偽標(biāo)簽挑高置信度的樣本加入訓(xùn)練集迭代循環(huán)。實(shí)現(xiàn)簡(jiǎn)單但存在確認(rèn)偏差問(wèn)題模型一旦預(yù)測(cè)錯(cuò)了錯(cuò)誤會(huì)反復(fù)自我強(qiáng)化。第三條是混合方案把兩者結(jié)合起來(lái)比如 FixMatch 這類(lèi)思路。弱增強(qiáng)生成偽標(biāo)簽強(qiáng)增強(qiáng)輸入模型訓(xùn)練兩者用同一個(gè)模型?,F(xiàn)在學(xué)術(shù)界和工業(yè)界的基線基本都錨定這一方向。我的實(shí)際選型建議是如果無(wú)標(biāo)注數(shù)據(jù)量很大、但標(biāo)注數(shù)據(jù)每類(lèi)只有幾十張優(yōu)先嘗試混合方案性?xún)r(jià)比最高。如果標(biāo)注數(shù)據(jù)稍微充足一些但計(jì)算資源有限一致性正則也夠用。偽標(biāo)簽法最容易實(shí)現(xiàn)但必須要配高置信度閾值和較強(qiáng)的數(shù)據(jù)增強(qiáng)否則很容易訓(xùn)練崩。2. 關(guān)鍵方法拆解一致性正則與偽標(biāo)簽是怎么干活的2.1 一致性正則的直觀理解與損失設(shè)計(jì)一致性正則的思想非常樸素。你給模型看一張貓的照片模型說(shuō)這是貓你把照片水平翻轉(zhuǎn)、輕微裁剪、調(diào)一下亮度再讓模型看模型還是應(yīng)該說(shuō)這是貓。對(duì)無(wú)標(biāo)注數(shù)據(jù)來(lái)說(shuō)我們不知道它到底是什么類(lèi)別但我們知道同一張圖的不同增強(qiáng)版本類(lèi)別一定相同。這個(gè)約束落到損失函數(shù)上就是讓模型對(duì)兩個(gè)增強(qiáng)版本的預(yù)測(cè)分布盡量一致。常見(jiàn)的做法是算兩個(gè)預(yù)測(cè)分布之間的 KL 散度或交叉熵。以 Mean Teacher 思路為例一個(gè)學(xué)生模型做梯度更新一個(gè)教師模型用學(xué)生權(quán)重的指數(shù)移動(dòng)平均來(lái)維護(hù)訓(xùn)練時(shí)讓學(xué)生模型的預(yù)測(cè)去逼近教師模型的預(yù)測(cè)同時(shí)學(xué)生模型也接受有標(biāo)注數(shù)據(jù)的監(jiān)督損失。教師模型的輸出比單次預(yù)測(cè)更穩(wěn)定相當(dāng)于給學(xué)生提供了更可靠的學(xué)習(xí)目標(biāo)。實(shí)操中有一個(gè)需要注意的點(diǎn)一致性正則的損失權(quán)重不能從一開(kāi)始就拉滿否則模型還沒(méi)學(xué)好特征就先被“一致性”給僵住了。我常用的做法是前若干個(gè) epoch 讓監(jiān)督損失主導(dǎo)無(wú)監(jiān)督損失權(quán)重從一個(gè)很小的值逐漸上升到目標(biāo)值類(lèi)似一個(gè)升溫過(guò)程。2.2 偽標(biāo)簽的流程、閾值與確認(rèn)偏差偽標(biāo)簽法就更好理解了。模型先在標(biāo)注數(shù)據(jù)上學(xué)出初始能力然后對(duì)無(wú)標(biāo)注數(shù)據(jù)做預(yù)測(cè)把置信度高的預(yù)測(cè)結(jié)果當(dāng)作“偽標(biāo)簽”加入訓(xùn)練。聽(tīng)上去很簡(jiǎn)單但這里有個(gè)致命的坑確認(rèn)偏差。模型對(duì)某個(gè)樣本如果第一次就預(yù)測(cè)錯(cuò)了而且置信度還很高那么把它當(dāng)偽標(biāo)簽訓(xùn)練等于把錯(cuò)誤再教一遍。等到下一輪迭代模型對(duì)這類(lèi)樣本的錯(cuò)誤傾向會(huì)更強(qiáng)。幾輪下來(lái)模型就徹底被自己帶偏了。應(yīng)對(duì)確認(rèn)偏差的手段主要是兩個(gè)方向。一是設(shè)置高置信度閾值比如只有 max 概率超過(guò) 0.95 的偽標(biāo)簽才參與訓(xùn)練。閾值高雖然會(huì)丟掉很多候選樣本但留下的偽標(biāo)簽整體可靠性更高。二是增加偽標(biāo)簽的噪聲容忍度比如把硬標(biāo)簽改成軟標(biāo)簽用模型預(yù)測(cè)的概率分布直接做監(jiān)督信號(hào)這樣即使預(yù)測(cè)不完全正確梯度也不至于太“狠”。我在實(shí)際操作中通常先用高閾值跑通一個(gè)版本再考慮軟標(biāo)簽變體。2.3 為什么最終選 FixMatch 思路而不是 Mean Teacher 或 MixMatch我在項(xiàng)目里最終采用的是 FixMatch 這一類(lèi)混合思路。它的關(guān)鍵設(shè)計(jì)是對(duì)無(wú)標(biāo)注圖片打兩次增強(qiáng)一個(gè)弱增強(qiáng)、一個(gè)強(qiáng)增強(qiáng)。弱增強(qiáng)版本送入模型得到預(yù)測(cè)分布取 argmax 和對(duì)應(yīng)的置信度如果置信度超過(guò)閾值就把這個(gè) argmax 當(dāng)作偽標(biāo)簽然后用強(qiáng)增強(qiáng)版本作為輸入讓模型預(yù)測(cè)去擬合這個(gè)偽標(biāo)簽。整個(gè)過(guò)程只有一個(gè)模型、一份無(wú)監(jiān)督損失實(shí)現(xiàn)起來(lái)非常干凈。這里弱增強(qiáng)和強(qiáng)增強(qiáng)的分工特別關(guān)鍵。弱增強(qiáng)的目的是生成相對(duì)可靠的偽標(biāo)簽所以擾動(dòng)幅度要小不能讓模型“看花了眼”。強(qiáng)增強(qiáng)的目的是讓模型在更大的數(shù)據(jù)擾動(dòng)范圍內(nèi)保持穩(wěn)定所以要足夠“狠”逼模型去學(xué)習(xí)真正的語(yǔ)義特征而不是淺層的像素模式。我測(cè)試下來(lái)弱增強(qiáng)通常用隨機(jī)水平翻轉(zhuǎn)和裁剪強(qiáng)增強(qiáng)用 RandAugment 或 AutoAugment 加 CutOut效果比較穩(wěn)。為什么不選 Mean Teacher因?yàn)殡p模型結(jié)構(gòu)訓(xùn)練成本高且 EMA 更新需要額外調(diào)參收斂速度慢。為什么不選 MixMatch它用了多個(gè)增強(qiáng)分支和標(biāo)簽銳化性能不錯(cuò)但復(fù)雜度高工程上維護(hù)成本偏高。FixMatch 思路在效果和實(shí)現(xiàn)復(fù)雜度之間最平衡特別適合這類(lèi)“標(biāo)注少、無(wú)標(biāo)注多”的真實(shí)場(chǎng)景。方法思路核心機(jī)制優(yōu)點(diǎn)代價(jià)一致性正則Mean Teacher學(xué)生模型逼近 EMA 教師輸出目標(biāo)穩(wěn)定無(wú)需偽標(biāo)簽訓(xùn)練慢雙模型成本高偽標(biāo)簽Self-training高置信度偽標(biāo)簽自舉實(shí)現(xiàn)簡(jiǎn)單直接確認(rèn)偏差風(fēng)險(xiǎn)高混合方案FixMatch弱增強(qiáng)生成標(biāo)簽強(qiáng)增強(qiáng)訓(xùn)練效果好實(shí)現(xiàn)干凈對(duì)增強(qiáng)策略和閾值敏感3. 實(shí)操過(guò)程從數(shù)據(jù)準(zhǔn)備到訓(xùn)練收斂3.1 數(shù)據(jù)劃分與增強(qiáng)策略我拿一個(gè)公開(kāi)的十類(lèi)圖像數(shù)據(jù)集舉例類(lèi)別數(shù)不多比較典型。假設(shè)每類(lèi)只有 40 張標(biāo)注圖總共 400 張標(biāo)注數(shù)據(jù)另有 4 萬(wàn)張無(wú)標(biāo)注數(shù)據(jù)。先把標(biāo)注集按 8:2 切出訓(xùn)練子集和驗(yàn)證子集無(wú)標(biāo)注數(shù)據(jù)不參與驗(yàn)證和測(cè)試集劃分因?yàn)樗姆植己蜆?biāo)注集可能有偏移拿它做評(píng)估會(huì)虛高。數(shù)據(jù)加載時(shí)我把一個(gè) batch 設(shè)計(jì)成兩部分一部分是標(biāo)注樣本另一部分是無(wú)標(biāo)注樣本。比如每個(gè) batch 包含 64 張標(biāo)注圖和 64 張無(wú)標(biāo)注圖無(wú)標(biāo)注圖又同時(shí)生成兩個(gè)版本弱增強(qiáng)版本和強(qiáng)增強(qiáng)版本。這樣一次前向計(jì)算就能同時(shí)拿到監(jiān)督損失和無(wú)監(jiān)督損失所需的全部輸入。弱增強(qiáng)我用隨機(jī)水平翻轉(zhuǎn)加隨機(jī)裁剪后縮放回原尺寸這是圖像分類(lèi)里最常見(jiàn)的組合。強(qiáng)增強(qiáng)我用 RandAugment配合 CutOut。RandAugment 的幅度和操作數(shù)可以調(diào)整我常用幅度 10、操作數(shù) 2 起步如果發(fā)現(xiàn)無(wú)監(jiān)督損失下降困難再把幅度調(diào)小。CutOut 遮蔽的像素塊大小在 16 到 32 之間具體看圖像分辨率。3.2 損失函數(shù)、采樣配置與訓(xùn)練超參整體損失函數(shù)就是三部分相加監(jiān)督交叉熵?fù)p失、無(wú)監(jiān)督偽標(biāo)簽交叉熵?fù)p失和一個(gè)權(quán)重系數(shù) λ。無(wú)監(jiān)督損失只在高置信度 mask 為真的樣本上計(jì)算這樣做的本質(zhì)是對(duì)偽標(biāo)簽做了一次篩選。參數(shù)設(shè)置方面我給出一套經(jīng)過(guò)多次實(shí)驗(yàn)驗(yàn)證的初始配置優(yōu)化器SGDmomentum 0.9權(quán)重衰減 5e-4學(xué)習(xí)率0.03帶 5 個(gè) epoch 的線性 warmup之后 cosine 衰減總訓(xùn)練輪數(shù)200 epoch無(wú)監(jiān)督損失權(quán)重 λ前 20 個(gè) epoch 從 0 線性升到 1之后保持 1高置信度閾值0.95batch 構(gòu)成64 張標(biāo)注圖 64 張無(wú)標(biāo)注圖含強(qiáng)弱兩個(gè)版本EMA對(duì)模型參數(shù)做指數(shù)移動(dòng)平均decay 0.999用于最終評(píng)估這里有個(gè)容易忽略的點(diǎn)無(wú)標(biāo)注樣本的批次大小不要太少。半監(jiān)督的效果依賴(lài)無(wú)標(biāo)注數(shù)據(jù)的多樣性batch 太小會(huì)導(dǎo)致偽標(biāo)簽分布不穩(wěn)定訓(xùn)練震蕩。如果有顯存余量我建議無(wú)標(biāo)注部分至少和標(biāo)注部分一樣大。3.3 核心訓(xùn)練偽代碼我按 PyTorch 風(fēng)格整理一份核心訓(xùn)練邏輯把關(guān)鍵部分做了精簡(jiǎn)方便理解整體流程for step, batch in enumerate(loader): # batch 包含標(biāo)注圖像、標(biāo)注標(biāo)簽、無(wú)標(biāo)注弱增強(qiáng)、無(wú)標(biāo)注強(qiáng)增強(qiáng) x_l, y_l, x_u_w, x_u_s batch # 1. 監(jiān)督損失 logits_l model(x_l) loss_s ce_loss(logits_l, y_l) # 2. 無(wú)監(jiān)督損失先獲取弱增強(qiáng)的預(yù)測(cè)結(jié)果 logits_u_w model(x_u_w) probs_u_w softmax(logits_u_w, dim1) conf, pseudo_label torch.max(probs_u_w, dim1) # 3. 高置信度樣本的 mask mask (conf threshold).float() # 4. 強(qiáng)增強(qiáng)版本的預(yù)測(cè)與偽標(biāo)簽做交叉熵 logits_u_s model(x_u_s) loss_u ce_loss(logits_u_s, pseudo_label, reductionnone) loss_u (loss_u * mask).sum() / mask.sum().clamp(min1.0) # 5. 總損失 loss loss_s lambda_u * loss_u optimizer.zero_grad() loss.backward() optimizer.step()這條邏輯里最關(guān)鍵的就是 mask 的操作它直接決定了無(wú)監(jiān)督哪些樣本的反向傳播是激活的。我見(jiàn)過(guò)有人直接把所有樣本的無(wú)監(jiān)督損失都算進(jìn)去結(jié)果低置信度樣本的噪聲把模型帶崩了。mask 的作用等價(jià)于只讓模型在“自己比較有把握”的樣本上吸收信息其余樣本干脆忽略。3.4 評(píng)估、模型保存與監(jiān)控指標(biāo)訓(xùn)練過(guò)程中我保留一份單獨(dú)的標(biāo)注驗(yàn)證集每個(gè) epoch 結(jié)束后用 EMA 模型跑一次驗(yàn)證集準(zhǔn)確率。EMA 模型的作用是平滑震蕩它的準(zhǔn)確率通常比原始模型穩(wěn)定不少也更適合作為最終的預(yù)測(cè)版本。監(jiān)控指標(biāo)我會(huì)同時(shí)記錄四類(lèi)信息監(jiān)督損失值、無(wú)監(jiān)督損失值、偽標(biāo)簽啟用比例即 mask 的平均值、驗(yàn)證集準(zhǔn)確率。偽標(biāo)簽啟用比例是一個(gè)特別有用的早期預(yù)警信號(hào)。如果閾值設(shè)得太高可能大部分無(wú)標(biāo)注樣本都被過(guò)濾掉了導(dǎo)致無(wú)監(jiān)督損失幾乎不更新整個(gè)半監(jiān)督分支形同虛設(shè)。如果這個(gè)比例長(zhǎng)期在 90% 以上說(shuō)明閾值設(shè)得太低偽標(biāo)簽噪聲已經(jīng)被大量注入。模型保存方面我一般不只存最后一輪權(quán)重而是存驗(yàn)證集準(zhǔn)確率最高的 EMA 權(quán)重快照。這比“跑到最后一個(gè) epoch 就收工”要穩(wěn)得多因?yàn)橛?xùn)練后期往往有些震蕩峰值往往在最后幾輪之前。4. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄4.1 無(wú)監(jiān)督損失不下降模型根本不收斂這個(gè)現(xiàn)象通常有兩種表現(xiàn)。一種是無(wú)監(jiān)督損失持續(xù)停在某個(gè)固定值附近波動(dòng)另一種是驗(yàn)證集準(zhǔn)確率反而比純監(jiān)督基線還低。我排查的順序如下。先看偽標(biāo)簽啟用比例。如果低于 10%說(shuō)明高置信度閾值擋住了絕大多數(shù)樣本。原因可能是模型本身還沒(méi)學(xué)到足夠強(qiáng)的特征或者強(qiáng)增強(qiáng)太猛導(dǎo)致預(yù)測(cè)分布普遍低置信度。解決方法是把閾值從 0.95 降到 0.9 甚至 0.8 試一下同時(shí)把 RandAugment 的幅度調(diào)低。再看學(xué)習(xí)率。半監(jiān)督訓(xùn)練對(duì)學(xué)習(xí)率比純監(jiān)督更敏感學(xué)習(xí)率過(guò)大時(shí)模型很快震蕩過(guò)小時(shí)無(wú)監(jiān)督信息根本推不動(dòng)模型。我在實(shí)際項(xiàng)目中碰到的多數(shù)情況是學(xué)習(xí)率偏大SGD 配 0.03 只是一個(gè)起點(diǎn)如果你用的是 Adam建議從 1e-3 往下調(diào)。最后確認(rèn)無(wú)監(jiān)督數(shù)據(jù)分布是否和標(biāo)注數(shù)據(jù)差距太大。如果無(wú)標(biāo)注數(shù)據(jù)里混入了大量不屬于任何目標(biāo)類(lèi)別的圖片偽標(biāo)簽無(wú)論怎么篩選都學(xué)不到有效信息。這時(shí)候需要先對(duì)無(wú)標(biāo)注數(shù)據(jù)做一輪清洗或聚類(lèi)把離群部分剔除。4.2 偽標(biāo)簽噪聲太大模型被自己帶偏這里說(shuō)的噪聲大不是指置信度閾值低而是即使置信度很高預(yù)測(cè)結(jié)果依然是錯(cuò)的。高頻類(lèi)別尤其容易出現(xiàn)這種現(xiàn)象模型對(duì)“狗”這類(lèi)樣本見(jiàn)得多了把一些背景相似但不屬于狗的圖片也高置信度地標(biāo)成狗。偽標(biāo)簽和真實(shí)標(biāo)簽不一致又互相強(qiáng)化就是典型的確認(rèn)偏差。我的處理策略有三層。第一層是提升數(shù)據(jù)增強(qiáng)強(qiáng)度讓強(qiáng)增強(qiáng)真正制造出足夠的擾動(dòng)逼模型必須依賴(lài)語(yǔ)義特征而非紋理背景。第二層是臨時(shí)凍結(jié)監(jiān)督分支先用純監(jiān)督損失訓(xùn)練 10 到 20 個(gè) epoch讓模型初步收斂再打開(kāi)無(wú)監(jiān)督分支。不要一開(kāi)始就讓兩個(gè)分支同時(shí)優(yōu)化否則噪聲會(huì)污染早期特征學(xué)習(xí)。第三層是把硬偽標(biāo)簽換成軟標(biāo)簽即用模型的預(yù)測(cè)概率分布作為監(jiān)督目標(biāo)而不是只取 argmax這樣可以在一定程度上緩解錯(cuò)誤標(biāo)簽的“過(guò)度自信”。如果上述手段都不理想還可以試試改變偽標(biāo)簽的產(chǎn)生方式用一個(gè) EMA 模型的輸出來(lái)生成偽標(biāo)簽而不是用當(dāng)前快速更新的模型。EMA 模型變化慢輸出目標(biāo)更穩(wěn)定能明顯降低噪聲波動(dòng)。4.3 顯存翻倍與訓(xùn)練時(shí)間變長(zhǎng)的問(wèn)題半監(jiān)督訓(xùn)練相比純監(jiān)督訓(xùn)練最直接的工程代價(jià)就是多了一路強(qiáng)增強(qiáng)輸入。每個(gè) batch 里無(wú)標(biāo)注數(shù)據(jù)需要同時(shí)保存弱增強(qiáng)和強(qiáng)增強(qiáng)的中間特征顯存占用幾乎翻倍。訓(xùn)練時(shí)間也會(huì)因此變長(zhǎng)。我的處理經(jīng)驗(yàn)是分三步優(yōu)化。第一步是混精度訓(xùn)練模型前向和反向用 FP16 計(jì)算損失計(jì)算保留 FP32顯存和速度都能明顯改善。第二步是調(diào)整 batch 構(gòu)成不一定非得標(biāo)注和無(wú)標(biāo)注各 64可以把標(biāo)注壓到 32、無(wú)標(biāo)注保持 64這樣顯存壓力小一些整體效果損失不大。第三步是如果實(shí)在顯存不夠就把無(wú)監(jiān)督損失改成每隔一個(gè) step 計(jì)算一次相當(dāng)于把無(wú)監(jiān)督更新的頻率減半雖然訓(xùn)練速度會(huì)變慢但至少能跑起來(lái)。這里還要提醒一句不要把無(wú)標(biāo)注數(shù)據(jù)全部一股腦塞進(jìn)內(nèi)存再預(yù)處理。最好用在線增強(qiáng)讓 GPU 邊訓(xùn)練邊處理否則數(shù)據(jù) IO 會(huì)成為新的瓶頸。我頭幾次實(shí)驗(yàn)時(shí)直接在磁盤(pán)上預(yù)生成全部強(qiáng)增強(qiáng)版本結(jié)果磁盤(pán)讀寫(xiě)把訓(xùn)練速度拖垮了一半。4.4 類(lèi)別不平衡時(shí)半監(jiān)督反而拖后腿如果你標(biāo)注數(shù)據(jù)里的類(lèi)別分布不是均勻的比如 A 類(lèi)有 200 張、B 類(lèi)只有 20 張半監(jiān)督的收益會(huì)明顯下降甚至比純監(jiān)督還差。原因是模型會(huì)在高頻類(lèi)別上先形成高置信度的偽標(biāo)簽這些偽標(biāo)簽數(shù)量多在無(wú)監(jiān)督損失里占比大導(dǎo)致模型向高頻類(lèi)偏移低頻類(lèi)幾乎學(xué)不到。針對(duì)這種情況我采取兩個(gè)辦法。一是對(duì)每個(gè)類(lèi)別單獨(dú)計(jì)算置信度閾值而不是用全局同一個(gè)閾值。高頻類(lèi)可以設(shè) 0.95低頻類(lèi)降到 0.8讓低頻類(lèi)也有機(jī)會(huì)產(chǎn)生偽標(biāo)簽參與訓(xùn)練。二是無(wú)監(jiān)督損失按類(lèi)別做重加權(quán)計(jì)算每一類(lèi)的樣本數(shù)用類(lèi)頻率的倒數(shù)對(duì)損失加權(quán)避免高頻類(lèi)主導(dǎo)梯度更新。還有一個(gè)比較取巧的做法先統(tǒng)計(jì)無(wú)標(biāo)注數(shù)據(jù)在所有類(lèi)別上的預(yù)測(cè)分布如果發(fā)現(xiàn)某些類(lèi)幾乎沒(méi)有無(wú)標(biāo)注樣本被選中直接手動(dòng)對(duì)那些類(lèi)別的偽標(biāo)簽閾值做退火從 0.95 階梯降到 0.7。這樣雖然會(huì)引入一部分噪聲但至少讓低頻類(lèi)別在訓(xùn)練中“有存在感”。我試過(guò)之后低頻類(lèi)的單類(lèi)準(zhǔn)確率提升明顯整體平均準(zhǔn)確率也漲了。5. 幾個(gè)工程上的心得判斷5.1 半監(jiān)督不是萬(wàn)能藥什么時(shí)候用它收益最大經(jīng)過(guò)這個(gè)項(xiàng)目我對(duì)半監(jiān)督學(xué)習(xí)的適用邊界有了更清晰的認(rèn)識(shí)。它最適用的場(chǎng)景是標(biāo)注數(shù)據(jù)極度稀缺每類(lèi)幾十張甚至更少同時(shí)無(wú)標(biāo)注數(shù)據(jù)量大且分布與標(biāo)注集基本一致。在這種情況下半監(jiān)督能帶來(lái)從 70% 到 85% 量級(jí)的提升幾乎等于免費(fèi)標(biāo)注。但如果標(biāo)注數(shù)據(jù)已經(jīng)比較充足比如每類(lèi)超過(guò)幾百?gòu)埌氡O(jiān)督的提升就明顯減弱。這時(shí)候與其花時(shí)間調(diào)半監(jiān)督參數(shù)不如把算力留給數(shù)據(jù)清洗或更強(qiáng)的網(wǎng)絡(luò)結(jié)構(gòu)。另外如果無(wú)標(biāo)注數(shù)據(jù)本身噪聲極大包含大量無(wú)關(guān)類(lèi)別或重復(fù)圖片收益也會(huì)縮水需要先做一輪去重和過(guò)濾。從資源分配角度看我現(xiàn)在的習(xí)慣是先跑一個(gè)純監(jiān)督基線如果準(zhǔn)確率已經(jīng)超過(guò) 90%半監(jiān)督基本不用碰。如果準(zhǔn)確率只有 75% 以下半監(jiān)督就值得全力投入。在標(biāo)注和無(wú)標(biāo)注的比例上我一般要求無(wú)標(biāo)注量至少達(dá)到標(biāo)注量的 50 倍以上不然收益不明顯。5.2 如果還想再進(jìn)一步值得嘗試的方向這套流程穩(wěn)定跑通之后有幾條擴(kuò)展路徑可以明顯再拔高效果。一條是把半監(jiān)督和預(yù)訓(xùn)練特征結(jié)合?,F(xiàn)在很多圖像模型都用大規(guī)模無(wú)監(jiān)督預(yù)訓(xùn)練初始化把初始化權(quán)重?fù)Q成預(yù)訓(xùn)練模型再疊加偽標(biāo)簽訓(xùn)練收斂速度更快最終準(zhǔn)確率也更高。我測(cè)試過(guò)用預(yù)訓(xùn)練初始化的半監(jiān)督訓(xùn)練相比隨機(jī)初始化最終準(zhǔn)確率能再漲兩到三個(gè)點(diǎn)。另一條是引入更強(qiáng)的數(shù)據(jù)增強(qiáng)策略。RandAugment 的幅度調(diào)參范圍很寬如果進(jìn)一步搜索幅度和操作數(shù)的組合或者在強(qiáng)增強(qiáng)里加入更激進(jìn)的裁剪策略無(wú)監(jiān)督損失能提供更強(qiáng)的正則化信號(hào)。還有一條是和主動(dòng)學(xué)習(xí)結(jié)合。先用半監(jiān)督模型對(duì)無(wú)標(biāo)注數(shù)據(jù)打分挑出置信度最低、模型最“不確定”的樣本去做人工標(biāo)注再把新標(biāo)注的樣本加入標(biāo)注集繼續(xù)訓(xùn)練。這樣標(biāo)注人力極少但標(biāo)注的目標(biāo)樣本價(jià)值非常高形成了一個(gè)小成本高收益的閉環(huán)。結(jié)尾我個(gè)人在實(shí)際操作中的體會(huì)是半監(jiān)督不應(yīng)該被當(dāng)成一個(gè)花哨的學(xué)術(shù)技巧而是當(dāng)作一種免費(fèi)的“數(shù)據(jù)擴(kuò)充”手段。先用小規(guī)模數(shù)據(jù)快速跑通純監(jiān)督基線確認(rèn)模型架構(gòu)和增強(qiáng)策略沒(méi)有大問(wèn)題再啟動(dòng)半監(jiān)督分支按照三件事來(lái)檢查監(jiān)督損失是否正常下降、無(wú)監(jiān)督損失是否有效更新、偽標(biāo)簽啟用比例是否維持在一個(gè)健康的區(qū)間。最后再分享一個(gè)小技巧訓(xùn)練過(guò)程中每 100 步打印一次無(wú)標(biāo)注樣本的置信度均值也就是所有無(wú)標(biāo)注樣本 max 概率的平均值。它比 loss 值更能反映訓(xùn)練動(dòng)態(tài)。如果這個(gè)均值一直低于 0.7說(shuō)明增強(qiáng)太強(qiáng)或閾值太高模型根本沒(méi)有從無(wú)標(biāo)注數(shù)據(jù)里學(xué)到任何東西趁早調(diào)整別等訓(xùn)完一輪再回頭看。