在之前深度學(xué)習(xí)debug沉思錄第一集中,我們曾經(jīng)討論過在深度學(xué)習(xí)實踐過程中可能遇到的一些bug或者問題,總共討論了20個問題。在本文中,我們將繼續(xù)討論與深度學(xué)習(xí)有關(guān)的bug和問題,其中很多是關(guān)于一些超參數(shù)的實踐中的調(diào)優(yōu)問題。后期將持續(xù)更新。需要強(qiáng)調(diào)的是,本文的很多單純只是經(jīng)驗,在盡可能列出參考文獻(xiàn)的同時卻并無嚴(yán)格理論驗證,希望大家見諒。
本文轉(zhuǎn)載自徐飛翔的“深度學(xué)習(xí)debug沉思錄第二集”。
版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。
文章目錄
- 1. 協(xié)變性和不變性
- 2. 在視覺任務(wù)中從頭開始訓(xùn)練模型可能存在loss的“平坦期”
- 3. 若出現(xiàn)`training loss`一直不下降的情況,可以嘗試縮小網(wǎng)絡(luò)參數(shù)量
- 4. 進(jìn)行模型遷移時,要根據(jù)任務(wù)進(jìn)行特定層的保留和舍去
- 5. 在某些場景可能使用局部連接的卷積層更好
- 6. 一種特殊的過擬合現(xiàn)象
- 7. 通過矩陣分解對全連接層進(jìn)行壓縮
- 8. 在使用CTC Loss時其loss會Nan
- 9. 在進(jìn)行預(yù)訓(xùn)練模型的測試時,容易出現(xiàn)標(biāo)簽沒對齊的情況
- 10. 在進(jìn)行不同的深度學(xué)習(xí)框架之間進(jìn)行模型遷移時的調(diào)試
- 11. 在大批次訓(xùn)練中,可以增加學(xué)習(xí)率
- Reference
1. 協(xié)變性和不變性
協(xié)變性(Covariance)和不變性(Invariance)是在深度學(xué)習(xí)任務(wù)中比較重要的兩個概念,用于指導(dǎo)根據(jù)不同任務(wù)來進(jìn)行卷積網(wǎng)絡(luò)的設(shè)計。
其中,協(xié)變性[6]簡單來說,是網(wǎng)絡(luò)的輸入和輸出能夠在線形変換(比如translation操作,簡單的deformation也可以看成線性的)下,呈現(xiàn)相同比例的變化,用Wikipedia[6]上的解釋來說,就是:
For a covector
to be basis-independent, its components must co-vary with a change of basis to remain representing the same covector. That is, the components must be transformed by the same matrix as the change of basis matrix.(In English)對于某個covector是基底無關(guān)的,而且它的線性分解的系數(shù)
必須跟隨著基底的變化而變化,以保持同個covector表示的不變性,也就是,當(dāng)基底用矩陣
進(jìn)行變換時,系數(shù)
必須也用同樣的矩陣
進(jìn)行變換。
而不變性則好理解得多,就是指不管網(wǎng)絡(luò)的輸入怎么變化,其輸出始終會保持在一個誤差范圍內(nèi)(很難做到絕對的不變),數(shù)學(xué)表達(dá)為:
其中為一個變換。
那么,在一些應(yīng)用場景,比如語義分割(semantic image segmentation)和動作估計(motion estimation),物體識別(object detection)中,則要求網(wǎng)絡(luò)模型具有協(xié)變性,因為其實體可能分布在圖像的任意角落中,并且圖像中通常有多個不同的實體,如果網(wǎng)絡(luò)模型要求協(xié)變性,那么通常不使用池化pooling等手段進(jìn)行尺度下采樣。
反之,在一些應(yīng)用中,比如物體分類(image classification)中,因為通常圖像上只包含一種目標(biāo)實體,因此要求網(wǎng)絡(luò)模型具有不變性,此時就可以用池化pooling手段對圖像feature map進(jìn)行下采樣了。[7]
我們知道,池化pooling[8]會選取某個固定大小區(qū)域中的具有代表性的值(最大值或者平均值等)作為這個區(qū)域的代表,那么,如果圖像的某個小塊在其中旋轉(zhuǎn)(rotation)或者平移(translation),因為這個下采樣的特性,將會使得特征具有平移和旋轉(zhuǎn)不變性,然而,正如上面所述的,在某些場景中,這個不變性是不期望得到的,可能會有負(fù)效果。
2. 在視覺任務(wù)中從頭開始訓(xùn)練模型可能存在loss的“平坦期”
筆者以前多在skeleton數(shù)據(jù)[9]上跑動作識別模型,而skeleton數(shù)據(jù)有個特點就是足夠的緊致(compact),而傳統(tǒng)的RGB視頻數(shù)據(jù)則有著很多和動作信息(pose-related)無關(guān)的信息,比如背景信息,光照等,因此使用skeleton信息作為動作識別的輸入媒體,能在剛開始訓(xùn)練模型時就得到快速的loss下降。
而一些視覺模型使用的是RGB信息,比如ImageNet, UCF101等,如果從頭訓(xùn)練這些模型(from scratch),因為沒有任何預(yù)訓(xùn)練模型提供足夠好的淺層特征,在訓(xùn)練過程中就需要模型去“關(guān)注表演動作的實體”并且去學(xué)習(xí)圖像的淺層特征,如紋理,邊緣等,因此訓(xùn)練過程中可能出現(xiàn):loss在剛開始的幾個epoch不會下降,即便是訓(xùn)練率已經(jīng)很低了,在某個epoch后才開始正常下降。
因此,即便是你的模型在前幾個epoch不收斂,也可以繼續(xù)跑下去觀察是否是這個問題造成的。可以嘗試在前面使用預(yù)訓(xùn)練的模型進(jìn)行淺層特征提取,將有利于整個模型的收斂。
3. 若出現(xiàn)training loss一直不下降的情況,可以嘗試縮小網(wǎng)絡(luò)參數(shù)量
在第二節(jié)中筆者曾經(jīng)談到過關(guān)于training from scratch時的開始的“平坦期”的情況,現(xiàn)在還有一種情況是:整個網(wǎng)絡(luò)在訓(xùn)練過程中,訓(xùn)練損失總是不下降,或者下降得很慢,也就是說網(wǎng)絡(luò)模型甚至沒有辦法過擬合。而這個相同的網(wǎng)絡(luò)在其他更大型的數(shù)據(jù)集上卻能正常工作 這個問題很可能是因為你的網(wǎng)絡(luò)模型參數(shù)量太大了,特別是在全連接層中參數(shù)量太大了,而訓(xùn)練集樣本不足以支撐整個網(wǎng)絡(luò)。
這個解釋有點奇怪而且違反了常理,因為即便是網(wǎng)絡(luò)參數(shù)量太大也應(yīng)該只會導(dǎo)致過擬合而不至于沒法擬合才對。但是筆者在實驗過程中卻發(fā)現(xiàn)了這個情況。后面筆者將最后一層的卷積層(shape (N, c=512, h=128,w=171))用1x1卷積將通道數(shù)弄成1之后,才大大減少了后續(xù)的全連接層的參數(shù)量,解決了這個問題。這個情況歡迎各位討論,給予意見。
PS: 這個情況在筆者跑C3D模型[10]驗證RGB video數(shù)據(jù)時出現(xiàn)的,數(shù)據(jù)集是筆者實驗室自己采集的,規(guī)模較小。
4. 進(jìn)行模型遷移時,要根據(jù)任務(wù)進(jìn)行特定層的保留和舍去
在進(jìn)行視覺相關(guān)的任務(wù),如image/video caption, video/image action recognition, object detection時,常常會用預(yù)先在大型數(shù)據(jù)集ImageNet上進(jìn)行過預(yù)訓(xùn)練的卷積模型,如resnet,vgg等作為遷移特征提取器,以在新任務(wù)中提取出有效地低級特征,如條紋,邊緣等,加快訓(xùn)練的收斂。有些模型因為訓(xùn)練難度,甚至一定需要用預(yù)訓(xùn)練好的模型進(jìn)行特征提取后,進(jìn)行分步驟地訓(xùn)練,才能得到正常的收斂,如LRCN[11]。
然而,在這些預(yù)訓(xùn)練模型中,經(jīng)常也是和特定任務(wù)有關(guān)的,比如說分類任務(wù),就肯定會在最后存在若干全連接層。一般來說,越靠近最后的層,其和特定任務(wù)的關(guān)聯(lián)就最大,因此在遷移模型的時候,只會使用卷積層過后的最前面的全連接層作為特征,然后進(jìn)行后續(xù)其他任務(wù)的遷移等。
如上圖所示,一般來說只會用fc_1的特征進(jìn)行模型的遷移使用。
5. 在某些場景可能使用局部連接的卷積層更好
卷積網(wǎng)絡(luò)是在圖像處理領(lǐng)域率先使用的,在卷積網(wǎng)絡(luò)中,一個很重要的假設(shè)就是圖片的局部統(tǒng)計特征具有一致性,換句話說就是,一張圖片上,某個小區(qū)域的統(tǒng)計特性應(yīng)該和同一張圖片的其他區(qū)域的是相似的,在這種情況下,就可以采用參數(shù)共享(weights sharing)的手段以大幅度減少需學(xué)習(xí)的參數(shù)的數(shù)量,并且有利于泛化。[12]
但是,在某些場景中,比如人臉識別中,因為人臉的局部特征不能很好地符合這個假設(shè),因此在一些工作中,會嘗試使用不帶有參數(shù)共享的卷積網(wǎng)絡(luò)進(jìn)行處理[15],比如DeepFace[13,14],其結(jié)構(gòu)就如:
- Conv:32個11×11×3的卷積核
- max-pooling: 3×3, stride=2
- Conv: 16個9×9的卷積核
- Local-Conv: 16個9×9的卷積核,Local的意思是卷積核的參數(shù)不共享
- Local-Conv: 16個7×7的卷積核,參數(shù)不共享
- Local-Conv: 16個5×5的卷積核,參數(shù)不共享
- Fully-connected: 4096維
- Softmax: 4030維
因此,在某些特定的圖像領(lǐng)域,如果覺得你的待處理對象不符合這個假設(shè)都可以嘗試這個手段。其也有成熟的API接口,比如:
- TensorFlow: tf.keras.layers.LocallyConnected2D。 (Keras中同樣也有)
- PyTorch: 可以通過torch.nn.fold和torch.nn.unfold間接實現(xiàn),目前還沒有直接的API,不過下一版本應(yīng)該會出來。[16,17,18]
6. 一種特殊的過擬合現(xiàn)象
筆者在近日的實驗中,發(fā)現(xiàn)了一種比較特殊的過擬合現(xiàn)象,實驗場景大致是:
對特征
進(jìn)行注意力機(jī)制的操作,公式如:
, 其中加上1的目的是做所謂的加強(qiáng)特征的處理。這里的
中的元素都在[0,1]之間。
在實驗過程中發(fā)現(xiàn),輸出的分類的logit中,經(jīng)常有一個值會比其他值有數(shù)量級上的差距,比如20.03和0.03, 0.20等,這樣導(dǎo)致很容易在交叉熵的計算過程中導(dǎo)致出現(xiàn)接近0的現(xiàn)象(當(dāng)logit預(yù)測位和label相同時),同時,此時的loss很容易上下震蕩,并且很容易出現(xiàn)0.0000的現(xiàn)象(交叉熵不可能等于0,此處只是因為太接近0了)。此時應(yīng)該也是出現(xiàn)了過擬合的現(xiàn)象,形成原因暫且不明。
7. 通過矩陣分解對全連接層進(jìn)行壓縮
全連接層在深度學(xué)習(xí)中也有著廣泛的應(yīng)用,數(shù)學(xué)表示為:
其中,當(dāng)其中的n , m都比較大時,無論是對于計算還是內(nèi)存都是一個大考驗,因此可以用基于矩陣奇異值分解的思想,進(jìn)行分解。我們將奇異值縮減到只保留最大的t tt個,稱之為truncated SVD,我們有:
其中,
,
,通過這種手段可以將參數(shù)量從之前的
縮減到
,當(dāng)然,要求這里的
那么在實踐中,我們把一層的全連接層更換成兩層全連接層疊加,兩層之間不添加非線性激活單元,第一層的參數(shù)矩陣為
(同時,這個層沒有添加偏置),第二層的參數(shù)矩陣為
,這層的偏置就是原先的
中的偏置。
因此,在學(xué)習(xí)到了之后,可以通過這種方法,將一層換成兩層全連接進(jìn)行近似,取得更高的計算效率和儲存效率。
8. 在使用CTC Loss時其loss會Nan
CTC Loss(Connectionist Temporal Classification Loss)[19]是在序列到序列(Seq2Seq)模型中常見的loss,使用此類loss的好處就是可以避免對序列進(jìn)行顯式地對齊(alignment),比如在語音翻譯成文本的過程中,顯式地對語音進(jìn)行每個音節(jié)的標(biāo)注是需要大量人力物力的,而使用CTC Loss可以避免這種標(biāo)注。
在使用這種loss的時候,很基本的,需要注意你預(yù)測出來的類別是,其中的加1表示的是加上blank字符也就是下圖中的
。如果預(yù)測出來的類別沒有加1,則可能會導(dǎo)致loss變成Nan,梯度爆炸等。最一般的的就是在特征提取網(wǎng)絡(luò)之后的LSTM之后需要輸出若干個類的概率分布時,將這個類設(shè)置成
。[20]
9. 在進(jìn)行預(yù)訓(xùn)練模型的測試時,容易出現(xiàn)標(biāo)簽沒對齊的情況
筆者最近犯了一個很傻丫丫的錯誤。筆者最近需要評估一個動作識別模型的性能,其在github上有預(yù)訓(xùn)練好的模型,因此筆者直接下載完數(shù)據(jù)集Kinetics 400之后就直接考慮去評估模型性能了。因為數(shù)據(jù)集中的每個文件夾中都包含著同一類的樣本,一共有著400個類別,因此有400個文件夾。筆者一開始并不知道每個文件名,也就是類別名字與其label數(shù)字標(biāo)簽的對應(yīng)關(guān)系,竟然傻傻地對其進(jìn)行os.listdir()之后按順序進(jìn)行排序,順序給了一個數(shù)字標(biāo)簽,這個顯然是不對的,因為模型是加載預(yù)訓(xùn)練模型的,其輸出的標(biāo)簽的規(guī)則和我自己定義的不一定相同,如果是自己從頭訓(xùn)練還好不會受到影響,如果是打算在預(yù)訓(xùn)練模型上進(jìn)行,筆者的這個操作就放了大錯誤了。后果當(dāng)然就是模型的評估結(jié)果很差,讓筆者花了不少時間調(diào)bug啊。讀者一定要注意這種低級錯誤,如果評估一個現(xiàn)有的預(yù)訓(xùn)練模型,一定要注意這個預(yù)訓(xùn)練模型對標(biāo)簽是怎么定義的。不要一上手就急著進(jìn)行評估和編碼,欲速則不達(dá)。
10. 在進(jìn)行不同的深度學(xué)習(xí)框架之間進(jìn)行模型遷移時的調(diào)試
不同深度學(xué)習(xí)框架(比如pytorch,tensorflow,caffe2等等)之間的底層運(yùn)算細(xì)則,底層運(yùn)算精度可能相差很多,并且其某些層的默認(rèn)參數(shù)(比如BN層中有eps參數(shù))可能每個框架都不同,因此為了更好地在不同的深度學(xué)習(xí)框架中進(jìn)行模型遷移,及時地盤查出出錯的遷移層,我們可以用相同的輸入(比如全1矩陣),在兩個不同的框架中的相同模型中進(jìn)行前向傳播,當(dāng)然,兩個不同的框架的模型需要載入相同的模型參數(shù),然后觀測到底在哪層開始中間的輸出張量的具體值(比如對張量進(jìn)行取均值layer_out.mean())開始變得不同,據(jù)此去進(jìn)行高效地調(diào)試。
11. 在大批次訓(xùn)練中,可以增加學(xué)習(xí)率
文獻(xiàn)[21]指出,訓(xùn)練過程中,在batch size越大的情況下,可以加大學(xué)習(xí)率。這個想法其實相當(dāng)直觀,從理論上說,深度學(xué)習(xí)模型在學(xué)習(xí)過程中是從隨機(jī)樣本中采樣得到的,采樣的一個批次我們稱之為batch,增大批次的數(shù)量大小,并不會影響到隨機(jī)梯度下降的均值,但會減少其方差。換句話說,批次越大,在梯度下降過程中其噪聲就越小,梯度的方向可信度就越高,因此可以用更大的學(xué)習(xí)率進(jìn)行學(xué)習(xí)。文獻(xiàn)[22]指出在resnet-50的訓(xùn)練過程中,學(xué)習(xí)率可以隨著batch size線性增大或減小。如果將batch size = 256時的學(xué)習(xí)率初始化為0.1,讓實際的batch size表示為b bb,那么有初始化學(xué)習(xí)率為。
Reference
[1]. 深度學(xué)習(xí)debug沉思錄
[2]. Ioffe S, Szegedy C. Batch normalization: accelerating deep network training by reducing internal covariate shift[C]// International Conference on International Conference on Machine Learning. JMLR.org, 2015:448-456.[3]. Pytorch的BatchNorm層使用中容易出現(xiàn)的問題
[4].https://github.com/tensorflow/tensorflow/blob/r1.12/tensorflow/python/ops/nn_impl.py
[5]. https://www.tensorflow.org/api_docs/python/tf/nn/batch_normalization
[6]. https://en.wikipedia.org/wiki/Covariance_and_contravariance_of_vectors
[7]. Bronstein M M, Bruna J, LeCun Y, et al. Geometric deep learning: going beyond euclidean data[J]. IEEE Signal Processing Magazine, 2017, 34(4): 18-42.[8]. https://www.cnblogs.com/makefile/p/pooling.html
[9]. 【動作識別相關(guān),第一篇】skeleton骨骼點數(shù)據(jù)類型介紹
[10]. Tran, Du, et al. “Learning spatiotemporal features with 3d convolutional networks.”Proceedings of the IEEE international conference on computer vision. 2015.
[11]. Donahue J, Anne Hendricks L, Guadarrama S, et al. Long-term recurrent convolutional networks for visual recognition and description[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2015: 2625-2634.
[12].https://www.quora.com/What-exactly-is-meant-by-shared-weights-in-convolutional-neural-network
[13]. Taigman Y, Yang M, Ranzato M A, et al. Deepface: Closing the gap to human-level performance in face verification[C]//Computer Vision and Pattern Recognition (CVPR), 2014 IEEE Conference on. IEEE, 2014: 1701-1708.
[14].https://blog.csdn.net/app_12062011/article/details/78510531
[15].https://prateekvjoshi.com/2016/04/12/understanding-locally-connected-layers-in-convolutional-neural-networks/
[16].https://github.com/pytorch/pytorch/pull/1583
[17].https://github.com/pytorch/pytorch/issues/499
[18].https://discuss.pytorch.org/t/locally-connected-layers/26979
[19].https://towardsdatascience.com/intuitively-understanding-connectionist-temporal-classification-3797e43a86c
[20].https://stackoverflow.com/questions/39565451/how-to-avoid-nan-value-in-ctc-training/43380602
[21]. He, T., Zhang, Z., Zhang, H., Zhang, Z., Xie, J., & Li, M. (2019). Bag of tricks for image classification with convolutional neural networks. In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (pp. 558-567).
[22]. P. Goyal, P. Dollar, R. B. Girshick, P. Noordhuis, ´L. Wesolowski, A. Kyrola, A. Tulloch, Y. Jia, and K. He.Accurate, large minibatch SGD: training imagenet in 1 hour.CoRR, abs/1706.02677, 2017
未完待續(xù)?。。?/p>