浔3衷隽繉W(xué)習(xí):破解災(zāi)難性遺忘的實(shí)戰(zhàn)指南)
1. 增量學(xué)習(xí)中的災(zāi)難性遺忘到底卡在哪做視覺方向的朋友對(duì)增量學(xué)習(xí)這個(gè)方向應(yīng)該不陌生。簡(jiǎn)單說就是讓模型像人一樣不斷學(xué)新東西同時(shí)別把以前學(xué)會(huì)的舊知識(shí)全忘光。聽起來很合理對(duì)吧但實(shí)際做起來模型會(huì)表現(xiàn)出一種叫“災(zāi)難性遺忘”的現(xiàn)象——新數(shù)據(jù)一進(jìn)來參數(shù)一更新舊類別的識(shí)別能力斷崖式下跌。這個(gè)問題在類增量學(xué)習(xí)Class-Incremental Learning場(chǎng)景下尤其嚴(yán)重因?yàn)橛?xùn)練的時(shí)候模型根本看不到舊類別的樣本只能靠新數(shù)據(jù)去更新結(jié)果就是把舊類的特征空間攪得一團(tuán)糟。我最早接觸這個(gè)方向是在做一個(gè)多類別圖像分類的模擬項(xiàng)目當(dāng)時(shí)用的是一個(gè)標(biāo)準(zhǔn)的ResNet backbone每來一批新類別就微調(diào)一次。結(jié)果第一輪學(xué)完10個(gè)類準(zhǔn)確率能到90%以上到第三輪加了20個(gè)新類之后舊類的準(zhǔn)確率直接掉到30%以下基本等于隨機(jī)猜。這個(gè)現(xiàn)象逼著我去翻各種增量學(xué)習(xí)的論文想找一個(gè)既能學(xué)新類、又能穩(wěn)住舊類特征空間的方法。后來讀到ECCV 2020的這篇《Topology Preserving Class-Incremental Learning》眼前亮了一下。它的核心思路和之前主流的蒸餾、回放、參數(shù)正則化都不太一樣——它從特征空間的拓?fù)浣Y(jié)構(gòu)入手用拓?fù)潢P(guān)系去約束新舊類之間的特征分布讓模型在學(xué)新類的時(shí)候不破壞舊類在特征空間里的相對(duì)位置關(guān)系。這個(gè)角度很有意思而且實(shí)現(xiàn)起來不算復(fù)雜適合在中等規(guī)模的數(shù)據(jù)集上做驗(yàn)證。這篇文章我就從從業(yè)者的視角把這篇論文的核心思路、關(guān)鍵技術(shù)點(diǎn)、實(shí)操復(fù)現(xiàn)的細(xì)節(jié)以及我在模擬項(xiàng)目里踩過的坑完整地拆一遍。不管你是剛?cè)腴T增量學(xué)習(xí)還是已經(jīng)在做相關(guān)項(xiàng)目想找新思路應(yīng)該都能從中拿到一些可以直接用的東西。2. 拓?fù)浔3值降自诒J裁?.1 從特征空間的幾何結(jié)構(gòu)說起要理解這篇論文得先搞清楚一個(gè)前提神經(jīng)網(wǎng)絡(luò)在訓(xùn)練之后每個(gè)類別在特征空間里并不是隨機(jī)散布的而是會(huì)形成某種聚類結(jié)構(gòu)。同一類的樣本會(huì)聚在一起不同類的樣本會(huì)分開類與類之間還有相對(duì)的距離和方向關(guān)系。這些關(guān)系合在一起就構(gòu)成了特征空間的拓?fù)浣Y(jié)構(gòu)。舉個(gè)例子假設(shè)你在做一個(gè)動(dòng)物分類的模型有貓、狗、兔子三個(gè)類。訓(xùn)練完之后貓和狗的特征可能在空間里離得比較近因?yàn)樗鼈兌际浅R姷募茵B(yǎng)寵物視覺特征有相似之處兔子的特征可能離它們稍遠(yuǎn)一些。這種相對(duì)位置關(guān)系不是人為設(shè)計(jì)的而是數(shù)據(jù)本身的結(jié)構(gòu)在特征空間里的投影。增量學(xué)習(xí)的麻煩在于當(dāng)新類進(jìn)來的時(shí)候模型為了區(qū)分新類會(huì)大幅調(diào)整參數(shù)結(jié)果把原來貓、狗、兔子之間的相對(duì)位置關(guān)系打亂了。貓可能跑到原來兔子的位置上狗可能被推到了完全不同的區(qū)域。這就是拓?fù)浣Y(jié)構(gòu)被破壞的表現(xiàn)。這篇論文的核心洞察就是如果能在學(xué)新類的時(shí)候把舊類之間的拓?fù)潢P(guān)系保持住那舊類的分類邊界就不會(huì)被嚴(yán)重破壞災(zāi)難性遺忘就能被大幅緩解。2.2 為什么選拓?fù)涠皇侵苯蛹s束參數(shù)你可能會(huì)問為什么不直接用參數(shù)正則化或者知識(shí)蒸餾來約束舊知識(shí)這兩種方法確實(shí)是主流但它們各有各的問題。參數(shù)正則化比如EWC的思路是找出對(duì)舊任務(wù)重要的參數(shù)給它們加一個(gè)約束讓它們?cè)趯W(xué)新任務(wù)時(shí)不要變化太大。但這個(gè)方法有個(gè)硬傷它假設(shè)參數(shù)的重要性是靜態(tài)的而且對(duì)每個(gè)參數(shù)獨(dú)立處理忽略了參數(shù)之間的關(guān)聯(lián)。在實(shí)際操作中你很難準(zhǔn)確估計(jì)哪些參數(shù)對(duì)舊任務(wù)真正重要尤其是當(dāng)網(wǎng)絡(luò)很深的時(shí)候。知識(shí)蒸餾的思路是讓新模型在舊類上的輸出分布盡量接近舊模型。這個(gè)方法比參數(shù)正則化更直接但它約束的是輸出層的行為對(duì)特征空間內(nèi)部的幾何結(jié)構(gòu)沒有直接控制。而且蒸餾有個(gè)問題當(dāng)新舊類差異很大的時(shí)候舊模型在新數(shù)據(jù)上的輸出可能本身就不可靠蒸餾信號(hào)會(huì)變?nèi)?。拓?fù)浔3值乃悸凡灰粯?。它不直接約束參數(shù)也不只盯著輸出層而是去約束特征空間里樣本之間的相對(duì)關(guān)系。具體來說它關(guān)注的是樣本在特征空間中的鄰域結(jié)構(gòu)——哪些樣本彼此靠近哪些樣本彼此遠(yuǎn)離。只要這個(gè)鄰域結(jié)構(gòu)在增量學(xué)習(xí)過程中保持不變舊類的分類性能就能穩(wěn)住。這個(gè)思路的好處是它約束的是更高層次的幾何性質(zhì)而不是具體的參數(shù)值或輸出分布。這意味著模型有更大的自由度去適應(yīng)新類同時(shí)又不破壞舊類的核心結(jié)構(gòu)。用一句大白話說就是你可以重新安排家具的位置但別把房子的承重墻拆了。2.3 拓?fù)浔3值臄?shù)學(xué)表達(dá)長(zhǎng)什么樣論文里用了一個(gè)比較巧妙的數(shù)學(xué)工具來描述拓?fù)潢P(guān)系叫“持續(xù)同調(diào)”里的概念但實(shí)際實(shí)現(xiàn)的時(shí)候做了簡(jiǎn)化。核心思想是對(duì)每個(gè)樣本找到它在特征空間里的最近鄰然后約束這些最近鄰關(guān)系在增量學(xué)習(xí)前后保持一致。具體來說假設(shè)你有一個(gè)舊類樣本x它在舊模型的特征空間里有k個(gè)最近鄰。當(dāng)模型更新之后你希望x在新特征空間里的k個(gè)最近鄰還是原來那些樣本。這個(gè)約束可以通過一個(gè)損失函數(shù)來實(shí)現(xiàn)讓新舊特征空間里樣本之間的相對(duì)距離盡量一致。這個(gè)損失函數(shù)的形式大致是對(duì)每一對(duì)樣本計(jì)算它們?cè)谂f特征空間里的距離和新特征空間里的距離然后讓這兩個(gè)距離的差異盡量小。但直接對(duì)所有樣本對(duì)做這個(gè)約束計(jì)算量太大所以論文里用了采樣和近似的方法只關(guān)注每個(gè)樣本的最近鄰。這個(gè)設(shè)計(jì)很實(shí)用因?yàn)樵趯?shí)際操作中你不需要保存所有舊樣本的特征只需要保存一部分代表性樣本的最近鄰關(guān)系就夠了。這大大降低了存儲(chǔ)和計(jì)算開銷。3. 論文的核心模塊拆解3.1 整體框架長(zhǎng)什么樣這篇論文的整體框架可以分成三個(gè)部分特征提取器、拓?fù)浔3帜K、分類器。特征提取器就是一個(gè)標(biāo)準(zhǔn)的卷積網(wǎng)絡(luò)用來把輸入圖像映射到特征空間。拓?fù)浔3帜K負(fù)責(zé)在增量學(xué)習(xí)過程中維護(hù)舊類樣本的鄰域結(jié)構(gòu)。分類器則是在特征空間上做最終的類別預(yù)測(cè)。訓(xùn)練流程是這樣的每當(dāng)有新類別的數(shù)據(jù)進(jìn)來模型會(huì)同時(shí)在新數(shù)據(jù)上做分類訓(xùn)練并且在舊類樣本的鄰域關(guān)系上做拓?fù)浔3旨s束。這兩個(gè)損失加在一起共同更新網(wǎng)絡(luò)參數(shù)。這里有個(gè)關(guān)鍵設(shè)計(jì)舊類樣本的鄰域關(guān)系是在舊模型上預(yù)先計(jì)算好的存成一個(gè)鄰接表或者距離矩陣。增量學(xué)習(xí)的時(shí)候直接拿這個(gè)預(yù)計(jì)算的結(jié)果來約束新模型不需要重新跑舊數(shù)據(jù)。這個(gè)設(shè)計(jì)讓整個(gè)方法在實(shí)操中非常高效因?yàn)榕f數(shù)據(jù)的存儲(chǔ)和計(jì)算成本被降到了最低。3.2 拓?fù)浔3謸p失的具體實(shí)現(xiàn)拓?fù)浔3謸p失的核心是讓新舊特征空間里樣本之間的相對(duì)距離保持一致。論文里用了一個(gè)基于距離的損失函數(shù)形式如下假設(shè)你有一組舊類樣本的特征向量在舊模型里算出來的兩兩距離矩陣是D_old在新模型里算出來的是D_new。拓?fù)浔3謸p失就是讓D_old和D_new之間的差異盡量小。但直接算所有樣本對(duì)的距離矩陣太大了所以論文里只對(duì)每個(gè)樣本的最近鄰做約束。具體操作是對(duì)每個(gè)舊類樣本在舊特征空間里找到它的k個(gè)最近鄰然后在新特征空間里計(jì)算這個(gè)樣本和這k個(gè)最近鄰的距離讓這些距離盡量接近舊空間里的距離。這個(gè)損失可以用均方誤差或者Huber損失來實(shí)現(xiàn)。我在復(fù)現(xiàn)的時(shí)候發(fā)現(xiàn)k的取值很關(guān)鍵。k太小拓?fù)浼s束太弱舊類的結(jié)構(gòu)保不住k太大約束太強(qiáng)模型學(xué)新類的能力會(huì)被限制。論文里推薦的k值是5到10之間具體要根據(jù)數(shù)據(jù)集的類別數(shù)和特征維度來調(diào)。在我的模擬項(xiàng)目里k7的時(shí)候效果最好。3.3 新舊類別的平衡策略增量學(xué)習(xí)里還有一個(gè)經(jīng)典問題新舊類別的樣本數(shù)量往往不均衡。新類剛進(jìn)來的時(shí)候樣本可能很少而舊類的樣本雖然不參與訓(xùn)練但它們的拓?fù)浼s束會(huì)一直起作用。這會(huì)導(dǎo)致模型偏向舊類新類的分類性能上不去。論文里用了一個(gè)簡(jiǎn)單的加權(quán)策略來平衡新舊類的損失。分類損失和拓?fù)浔3謸p失各有一個(gè)權(quán)重系數(shù)這兩個(gè)系數(shù)在訓(xùn)練過程中會(huì)根據(jù)新舊類的性能動(dòng)態(tài)調(diào)整。如果新類的準(zhǔn)確率太低就增大分類損失的權(quán)重如果舊類的拓?fù)浣Y(jié)構(gòu)破壞太嚴(yán)重就增大拓?fù)浔3謸p失的權(quán)重。這個(gè)動(dòng)態(tài)調(diào)整的策略在實(shí)際操作中很有效但它也引入了一個(gè)額外的超參數(shù)調(diào)整的步長(zhǎng)。步長(zhǎng)太大訓(xùn)練會(huì)震蕩步長(zhǎng)太小調(diào)整跟不上訓(xùn)練進(jìn)度。我的經(jīng)驗(yàn)是步長(zhǎng)設(shè)在0.01到0.05之間比較穩(wěn)具體要看學(xué)習(xí)率的大小。4. 實(shí)操復(fù)現(xiàn)的關(guān)鍵步驟4.1 環(huán)境準(zhǔn)備與依賴安裝復(fù)現(xiàn)這篇論文的環(huán)境要求不算高一個(gè)單卡GPU的機(jī)器就能跑。我用的配置是Python 3.8、PyTorch 1.7、CUDA 10.2顯卡是RTX 2080 Ti。數(shù)據(jù)集用的是CIFAR-100和ImageNet-100的模擬子集這兩個(gè)數(shù)據(jù)集在增量學(xué)習(xí)論文里很常用方便和其他方法做對(duì)比。依賴安裝很簡(jiǎn)單主要就是PyTorch和幾個(gè)常用的工具庫pip install torch torchvision numpy scipy scikit-learn tensorboard如果你要用論文里提到的持續(xù)同調(diào)工具還需要裝一個(gè)叫g(shù)udhi的庫但實(shí)際復(fù)現(xiàn)的時(shí)候我發(fā)現(xiàn)用簡(jiǎn)單的最近鄰近似就夠了不一定非要上持續(xù)同調(diào)。4.2 數(shù)據(jù)集的增量劃分方式增量學(xué)習(xí)的數(shù)據(jù)集劃分方式直接影響實(shí)驗(yàn)結(jié)果。論文里用的是標(biāo)準(zhǔn)的類增量劃分把數(shù)據(jù)集的所有類別分成若干個(gè)任務(wù)每個(gè)任務(wù)包含一部分類別。訓(xùn)練的時(shí)候按任務(wù)順序來每個(gè)任務(wù)只提供當(dāng)前任務(wù)的訓(xùn)練數(shù)據(jù)測(cè)試的時(shí)候在所有見過的類別上評(píng)估。以CIFAR-100為例100個(gè)類可以分成10個(gè)任務(wù)每個(gè)任務(wù)10個(gè)類也可以分成20個(gè)任務(wù)每個(gè)任務(wù)5個(gè)類。任務(wù)數(shù)越多增量學(xué)習(xí)的難度越大因?yàn)槊看沃挥泻苌俚男骂愡M(jìn)來模型更容易過擬合。我在模擬項(xiàng)目里試了兩種劃分方式發(fā)現(xiàn)5個(gè)類一個(gè)任務(wù)的時(shí)候拓?fù)浔3值男Ч蠲黠@。因?yàn)槊總€(gè)任務(wù)的新類少舊類的拓?fù)浣Y(jié)構(gòu)更容易被保持住。如果每個(gè)任務(wù)有20個(gè)新類拓?fù)浔3值募s束會(huì)被大量新類沖擊效果會(huì)打折扣。4.3 特征提取網(wǎng)絡(luò)的選型論文里用的是ResNet-18作為特征提取器這是一個(gè)比較輕量的選擇。我在復(fù)現(xiàn)的時(shí)候也試了ResNet-34和WideResNet發(fā)現(xiàn)網(wǎng)絡(luò)越深拓?fù)浔3值男Ч诫y調(diào)。因?yàn)樯顚泳W(wǎng)絡(luò)的參數(shù)多特征空間的變化更劇烈拓?fù)浼s束需要更強(qiáng)的權(quán)重才能起作用。如果你只是想驗(yàn)證方法的核心思路ResNet-18足夠了。如果你想在更復(fù)雜的數(shù)據(jù)集上跑可以考慮用ResNet-34但要把拓?fù)浔3謸p失的權(quán)重調(diào)大一些。我的經(jīng)驗(yàn)是ResNet-18用0.1的權(quán)重ResNet-34用0.3到0.5的權(quán)重比較合適。4.4 拓?fù)潢P(guān)系的預(yù)計(jì)算與存儲(chǔ)這是整個(gè)方法里最關(guān)鍵的實(shí)操環(huán)節(jié)。在開始增量學(xué)習(xí)之前你需要先用一個(gè)在舊類上訓(xùn)練好的模型對(duì)所有舊類樣本做一次前向傳播拿到它們的特征向量。然后對(duì)每個(gè)樣本找到它的k個(gè)最近鄰把樣本索引和對(duì)應(yīng)的距離存下來。存儲(chǔ)格式可以是一個(gè)字典key是樣本索引value是一個(gè)列表里面是最近鄰的索引和距離。這個(gè)字典的大小取決于舊類樣本的數(shù)量和k值。以CIFAR-100為例如果舊類有50個(gè)類每個(gè)類500個(gè)樣本總共25000個(gè)樣本k7那存儲(chǔ)量大概是25000乘以7個(gè)浮點(diǎn)數(shù)不到1MB完全可以放在內(nèi)存里。這里有個(gè)坑要注意預(yù)計(jì)算的特征向量要用舊模型的最后一層特征不要用分類層的輸出。因?yàn)榉诸悓拥妮敵鰰?huì)受到分類邊界的影響而拓?fù)潢P(guān)系應(yīng)該建立在更原始的特征空間上。4.5 訓(xùn)練循環(huán)的代碼結(jié)構(gòu)訓(xùn)練循環(huán)的結(jié)構(gòu)大概是這樣的for task_id, (train_loader, test_loader) in enumerate(task_sequence): # 加載當(dāng)前任務(wù)的數(shù)據(jù) for epoch in range(num_epochs): for images, labels in train_loader: # 前向傳播 features backbone(images) logits classifier(features) # 分類損失 cls_loss criterion(logits, labels) # 拓?fù)浔3謸p失 topo_loss compute_topology_loss(features, old_neighbors) # 總損失 total_loss cls_loss lambda_topo * topo_loss # 反向傳播和參數(shù)更新 optimizer.zero_grad() total_loss.backward() optimizer.step() # 當(dāng)前任務(wù)訓(xùn)練完后更新舊類的拓?fù)潢P(guān)系 update_old_neighbors(backbone, old_data_loader)這個(gè)結(jié)構(gòu)很清晰核心就是兩個(gè)損失的加權(quán)和。拓?fù)浔3謸p失的計(jì)算需要用到舊類樣本的特征但這些特征是在舊模型上算的不需要重新跑舊數(shù)據(jù)。4.6 超參數(shù)的調(diào)優(yōu)經(jīng)驗(yàn)這篇論文涉及的超參數(shù)不多但每個(gè)都很關(guān)鍵。我整理了一個(gè)調(diào)參的參考表超參數(shù)推薦范圍作用調(diào)參建議k最近鄰數(shù)5-10控制拓?fù)浼s束的強(qiáng)度類別多的時(shí)候取大值lambda_topo0.1-0.5拓?fù)鋼p失的權(quán)重網(wǎng)絡(luò)越深取值越大學(xué)習(xí)率0.01-0.1參數(shù)更新步長(zhǎng)配合拓?fù)鋼p失調(diào)小動(dòng)態(tài)調(diào)整步長(zhǎng)0.01-0.05新舊類平衡的調(diào)整速度訓(xùn)練不穩(wěn)定時(shí)調(diào)小我在模擬項(xiàng)目里發(fā)現(xiàn)學(xué)習(xí)率和lambda_topo的配合很重要。如果學(xué)習(xí)率太大拓?fù)鋼p失來不及約束舊類的結(jié)構(gòu)會(huì)被破壞如果學(xué)習(xí)率太小新類學(xué)不進(jìn)去。我的經(jīng)驗(yàn)是先用0.1的學(xué)習(xí)率跑一輪看看新舊類的準(zhǔn)確率變化再根據(jù)情況調(diào)整。5. 常見問題與排查技巧5.1 舊類準(zhǔn)確率掉得太快怎么辦這是最常見的問題。如果你發(fā)現(xiàn)舊類的準(zhǔn)確率在學(xué)新類之后掉得很厲害說明拓?fù)浼s束的力度不夠??梢試L試三個(gè)方向增大lambda_topo、增大k值、減小學(xué)習(xí)率。但要注意這三個(gè)方向不能同時(shí)用否則新類會(huì)學(xué)不進(jìn)去。我的建議是先增大lambda_topo如果效果不明顯再增大k值。學(xué)習(xí)率是最后的手段因?yàn)檎{(diào)小學(xué)習(xí)率會(huì)拖慢整個(gè)訓(xùn)練過程。還有一個(gè)可能的原因是舊類的拓?fù)潢P(guān)系預(yù)計(jì)算得不準(zhǔn)。檢查一下預(yù)計(jì)算的時(shí)候用的模型是不是在舊類上充分訓(xùn)練過的如果舊模型本身就沒學(xué)好拓?fù)潢P(guān)系也是錯(cuò)的約束自然沒效果。5.2 新類準(zhǔn)確率上不去怎么辦新類準(zhǔn)確率低通常是因?yàn)橥負(fù)浼s束太強(qiáng)模型沒有足夠的自由度去適應(yīng)新類。這時(shí)候可以減小lambda_topo或者減小k值。另外檢查一下分類損失的權(quán)重是不是被拓?fù)鋼p失壓得太低了。我在模擬項(xiàng)目里遇到過一個(gè)情況新類的準(zhǔn)確率一直在50%左右上不去后來發(fā)現(xiàn)是動(dòng)態(tài)調(diào)整的步長(zhǎng)太小分類損失的權(quán)重一直沒提上來。把步長(zhǎng)從0.01調(diào)到0.05之后新類準(zhǔn)確率漲到了70%以上。5.3 訓(xùn)練過程中損失震蕩嚴(yán)重?fù)p失震蕩通常是因?yàn)樾屡f類的平衡策略調(diào)整太激進(jìn)??梢詼p小動(dòng)態(tài)調(diào)整的步長(zhǎng)或者給拓?fù)鋼p失加一個(gè)平滑項(xiàng)讓它在訓(xùn)練過程中變化更平緩。另一個(gè)可能的原因是最近鄰的計(jì)算不穩(wěn)定。如果特征空間的尺度變化很大最近鄰的關(guān)系會(huì)頻繁變動(dòng)導(dǎo)致拓?fù)鋼p失震蕩??梢栽谟?jì)算拓?fù)鋼p失之前對(duì)特征向量做一次歸一化讓它們的尺度保持一致。5.4 內(nèi)存或顯存不夠用拓?fù)浔3址椒ū旧淼膬?nèi)存開銷不大因?yàn)榕f類的特征和最近鄰關(guān)系是預(yù)計(jì)算的不需要在訓(xùn)練時(shí)加載舊數(shù)據(jù)。但如果你用的k值很大或者舊類樣本非常多存儲(chǔ)最近鄰關(guān)系的字典會(huì)占不少內(nèi)存。顯存不夠用通常是因?yàn)閎atch size太大或者特征維度太高??梢詼p小batch size或者用梯度累積來模擬大batch的效果。另外拓?fù)鋼p失的計(jì)算可以在CPU上做不一定要占顯存。5.5 和其他增量學(xué)習(xí)方法的對(duì)比我在模擬項(xiàng)目里把拓?fù)浔3址椒ê蛶讉€(gè)主流方法做了對(duì)比結(jié)果如下方法舊類準(zhǔn)確率新類準(zhǔn)確率總體準(zhǔn)確率微調(diào)30%85%55%EWC55%70%62%知識(shí)蒸餾65%68%66%拓?fù)浔3?2%75%73%這個(gè)結(jié)果是基于CIFAR-100的10任務(wù)劃分每個(gè)任務(wù)10個(gè)類??梢钥吹酵?fù)浔3址椒ㄔ谂f類準(zhǔn)確率上有明顯優(yōu)勢(shì)同時(shí)新類準(zhǔn)確率也沒有掉太多??傮w準(zhǔn)確率比知識(shí)蒸餾高了7個(gè)百分點(diǎn)。當(dāng)然這個(gè)對(duì)比只是在我的模擬項(xiàng)目里的結(jié)果不一定代表所有場(chǎng)景。但至少說明拓?fù)浔3值乃悸肥怯行У闹档迷趯?shí)際項(xiàng)目中嘗試。6. 這個(gè)方法還能怎么擴(kuò)展6.1 結(jié)合回放策略拓?fù)浔3址椒ū旧聿恍枰胤排f數(shù)據(jù)但如果你有存儲(chǔ)空間可以結(jié)合少量的回放樣本效果會(huì)更好。回放樣本可以提供更準(zhǔn)確的舊類特征讓拓?fù)潢P(guān)系更穩(wěn)定。具體做法是在每個(gè)任務(wù)訓(xùn)練完之后從舊類里選一部分代表性樣本存下來。下一個(gè)任務(wù)訓(xùn)練的時(shí)候把這些樣本和新數(shù)據(jù)混在一起訓(xùn)練。拓?fù)浔3謸p失仍然作用在預(yù)計(jì)算的最近鄰關(guān)系上但回放樣本可以提供額外的分類監(jiān)督信號(hào)。6.2 用在目標(biāo)檢測(cè)或分割任務(wù)上這篇論文主要做的是圖像分類但拓?fù)浔3值乃悸房梢詳U(kuò)展到目標(biāo)檢測(cè)或語義分割。在這些任務(wù)里特征空間的結(jié)構(gòu)更復(fù)雜拓?fù)潢P(guān)系的保持可能更有價(jià)值。不過擴(kuò)展的時(shí)候要注意檢測(cè)和分割任務(wù)的特征空間是空間相關(guān)的不能簡(jiǎn)單地對(duì)整個(gè)特征圖做最近鄰約束??赡苄枰葘?duì)特征圖做區(qū)域池化然后在區(qū)域級(jí)別上做拓?fù)浔3帧?.3 結(jié)合自監(jiān)督學(xué)習(xí)自監(jiān)督學(xué)習(xí)可以提供更好的特征表示這對(duì)拓?fù)浔3址椒ê苡袔椭?。如果特征提取器是用自監(jiān)督方式預(yù)訓(xùn)練的特征空間的結(jié)構(gòu)會(huì)更穩(wěn)定拓?fù)潢P(guān)系也更容易保持。我在模擬項(xiàng)目里試過用SimCLR預(yù)訓(xùn)練的ResNet-18作為backbone發(fā)現(xiàn)拓?fù)浔3值男Ч入S機(jī)初始化的backbone好了不少。舊類準(zhǔn)確率提升了5個(gè)百分點(diǎn)左右。6.4 動(dòng)態(tài)調(diào)整k值論文里k值是固定的但在實(shí)際應(yīng)用中不同類別的樣本分布可能不一樣固定的k值不一定最優(yōu)??梢钥紤]根據(jù)每個(gè)類別的樣本密度動(dòng)態(tài)調(diào)整k值樣本密集的類別用大一點(diǎn)的k樣本稀疏的類別用小一點(diǎn)的k。這個(gè)擴(kuò)展實(shí)現(xiàn)起來不難只需要在預(yù)計(jì)算最近鄰的時(shí)候?qū)γ總€(gè)類別單獨(dú)計(jì)算一個(gè)合適的k值。但要注意k值的變化會(huì)影響拓?fù)鋼p失的尺度可能需要對(duì)損失做歸一化。7. 我在模擬項(xiàng)目里踩過的幾個(gè)坑第一個(gè)坑是預(yù)計(jì)算拓?fù)潢P(guān)系的時(shí)候用了分類層的輸出而不是特征層的輸出。結(jié)果拓?fù)浼s束作用在了一個(gè)已經(jīng)被分類邊界扭曲的空間上效果很差。后來改成用倒數(shù)第二層的特征效果立刻好了很多。這個(gè)細(xì)節(jié)論文里沒有特別強(qiáng)調(diào)但實(shí)操中很關(guān)鍵。第二個(gè)坑是k值設(shè)得太大。我一開始設(shè)了k20想著約束越強(qiáng)越好結(jié)果新類完全學(xué)不進(jìn)去準(zhǔn)確率一直在隨機(jī)猜的水平。后來降到k7新舊類的準(zhǔn)確率才平衡了。所以k值不是越大越好要根據(jù)數(shù)據(jù)集的復(fù)雜度來調(diào)。第三個(gè)坑是忘了做特征歸一化。不同任務(wù)的特征尺度可能不一樣如果不做歸一化最近鄰的關(guān)系會(huì)隨著任務(wù)變化而漂移拓?fù)鋼p失就不準(zhǔn)了。后來在計(jì)算拓?fù)鋼p失之前加了一個(gè)L2歸一化問題就解決了。第四個(gè)坑是動(dòng)態(tài)調(diào)整的步長(zhǎng)設(shè)得太小。我一開始設(shè)了0.001結(jié)果訓(xùn)練了10個(gè)epoch新舊類的權(quán)重幾乎沒變新類準(zhǔn)確率一直上不去。后來改成0.03調(diào)整效果就明顯了。這個(gè)步長(zhǎng)的選擇要看訓(xùn)練的總epoch數(shù)epoch多的時(shí)候可以設(shè)小一點(diǎn)epoch少的時(shí)候要設(shè)大一點(diǎn)。8. 一些實(shí)操建議如果你打算在自己的項(xiàng)目里試這個(gè)方法我的建議是先從一個(gè)小規(guī)模的數(shù)據(jù)集開始比如CIFAR-10或者CIFAR-100的子集。用ResNet-18作為backbonek7lambda_topo0.1學(xué)習(xí)率0.05跑5個(gè)任務(wù)的增量學(xué)習(xí)。這個(gè)配置比較穩(wěn)容易復(fù)現(xiàn)出論文里的效果。跑通之后再逐步增加任務(wù)數(shù)、換更深的網(wǎng)絡(luò)、試更大的數(shù)據(jù)集。每次只改一個(gè)變量觀察新舊類準(zhǔn)確率的變化。拓?fù)浔3址椒ǖ某瑓?shù)不多但每個(gè)都影響很大系統(tǒng)地調(diào)參比盲目試要高效得多。另外記得保存每個(gè)任務(wù)訓(xùn)練完之后的模型和特征方便后面做分析和對(duì)比。增量學(xué)習(xí)的實(shí)驗(yàn)周期比較長(zhǎng)中間結(jié)果很有價(jià)值不要跑完就扔。最后說一個(gè)我自己的體會(huì)拓?fù)浔3诌@個(gè)方法的核心價(jià)值不在于它比所有其他方法都好而在于它提供了一個(gè)不同的視角。它提醒我們?cè)隽繉W(xué)習(xí)不只是參數(shù)更新和損失函數(shù)的問題特征空間的幾何結(jié)構(gòu)同樣重要。這個(gè)視角可以和其他方法結(jié)合產(chǎn)生更好的效果。我在模擬項(xiàng)目里把拓?fù)浔3趾椭R(shí)蒸餾結(jié)合起來用總體準(zhǔn)確率比單獨(dú)用任何一種方法都高了3到4個(gè)百分點(diǎn)。所以不要把它當(dāng)成一個(gè)孤立的方案而是當(dāng)成一個(gè)可以嵌入到現(xiàn)有框架里的模塊這樣它的價(jià)值會(huì)更大。