DL Troubleshooting:如何最佳化你的Performance?搞清楚現在該做甚麼!

Full Stack Deep Learning Bootcamp筆記

倢愷 Oscar
16 min readFeb 12, 2021

前言(可略)

3年前我們實驗室的學長受到孫民老師的資助去UC Berkeley參加了第一年的Full Stack Deep Learning Bootcamp (FSDL),並把當時學界業界最前瞻、最頂尖的DL實務知識帶回到實驗室,那時候我也受益很多,重新改善了自己的整個思考流程、工作流程,可惜在第一年的時候FSDL的內容是不公開的,所以在當時我想推廣這些知識是藉由在清大一年一度開了給學生的ML bootcamp,而後來在19年FSDL Bootcamp把他們的資料內容都公開給大眾,不過台灣好像這塊到現在還是很少人在提倡,所以接下來會有一個系列文章都是基於FSDL的知識,並且輔以一些實務的經驗來補充說明相關概念。如果對相關議題有興趣歡迎追隨我,預計年中會更新到一個大段落~~

我會優先寫我認為大家比較少談論但是比較重要的概念,不會依照FSDL的順序。

Full Stack Deep Learning 2019 : https://fall2019.fullstackdeeplearning.com/

正文開始

如何最佳化你的Performance這個問題,在FSDL裡面談的其實不是如何設計出更好的model,而是「知道我現在要做甚麼」,只有在流程正確的時候去設計更大的模型才有用,大部分入門DL的人都犯過一個錯,拿太大的model去train太小的dataset,導致完全收斂不了,這種時候很多人會想說這麼簡單的dataset performance不好應該是overfitting,因此狂加一大堆regularization、dropout之類的,結果完全無法改善,這就是當自己定位出錯問題就很容易空耗很多時間在錯誤的方法上。

比起學習更多厲害的方法,知道現在處於甚麼階段,要做甚麼,是DL裡面最重要的事情之一。

在開始談整個流程時,先談一下我們怎麼分dataset。

大部分的ML/DL學習者可能都已經很熟悉了dataset可以被分成三部分,training set 、 validation set跟test set,有些人會稱validation set為development set,我統一都用validation set稱呼。

我想先用一點點篇幅帶大家複習一下這幾個dataset的目的,如果很熟悉可以直接跳過~

我們要train一個ML model需要足夠量的training data,這就是training set的目的,但是當我們train好model後我們馬上遇到一個困難,我們如何了解我們的模型做得多好?直接拿training set上的perforamance當作model的成績嗎?這樣做的話就像是給學生考古題然後期中考又出一模一樣的題目,model自然而然會表現很好,但是遇到新的題目可能馬上死掉(這也是俗稱的overfitting)。因此提出了test set。 Test set的唯一目標就是用來衡量模型的好壞。但是為甚麼要衡量模型的好壞?因為我們想知道我們的模型上線後能夠真正做到的事情。因此Test set有兩個核心要求,一、在model training時不能被model看到,這樣才能取得真正準確的分數,二、要盡量貼合我們真實應用時會遇到的資料,這樣才能夠代表上線後的情況。

而上面分完training set跟test set後,validation set又是哪裡來的?大家應該多少都知道每個模型多多少少都有一些Hyperparameters要調,像是Random Forest的n_estmators,也就是說我們需要train多次model,每次用不同的hyperparameter,然後看不同hyperparameter的模型哪個比較好。而要比較model大家之前就想到,我們可以用training performance或是testing performance來比較各個模型,但是這兩個方法各有各自的問題。如果用training performance做比較,那我們挑出來的模型也只是最會「背」考古題的模型,是不是真正比較強不確定,如果使用testing performance做比較,那我們最終的testing performance又會相對應不準,因為我們已經挑了最會寫期中考的學生出來考期中考了,當然會考的好,所以不論用training set還是test set都不適合。因此聰明的人們就提出了,不如我們把資料多切出一塊validation set,這塊就像是「模擬考」,基本上跟test set一樣在training過程中絕對不能碰到,單純只用來挑選hyperparameters,而因為是用validation set挑選hyperparameters,最終的testing performance還是很準。

所以過去的偉人帶我們到了這步,資料被分為三塊:training set 、 validation set跟test set

Traditional Dataset Splitting: 3-fold splitting

但是在業界很少是這樣做的!

上面的分法預設了training set跟test set都是同一個來源,或是說來自同一個distribution,所以我們可以直接切出一塊validation。

請大家想一個問題:Training set跟Test set的來源會不會一樣?

答案是大概率不會

因為我們希望test set能盡量貼合真實環境,所以我們會花錢、花時間、花資源收集很精準的test set,這能夠當作我們產品上線最後的守門員,不讓任何不好的產品上線。但是training set如果也用這種高標準收集大多數是非常浪費時間、金錢的一件事。所以training set在產品初期都是盡量有免費用免費,沒有免費看看能不能模擬,再不行就先自己手動label或是請比較低價的工人label,同時也會大量找到相似的data來當作可能可以用的training set,這造就了大部分時候我們test set跟training set來源不同。

而即便今天是大公司,training set跟test set都請專人進行label,或是來自於某種behavior data,我們也會將比較貼近現實情況data放到test set裡面,Ex:如果我們的data跟時間相關,我們會把比較新的data放到test set,比較舊的data放到training set,來讓我們testing的結果跟現實情況越相近越好,這也導致了training set跟test set內部必然有一些不一致

有些時候在做完testing後我們會把training跟test合併起來變成一個大training set再去retrain我們的model,這種情況就已經不在我討論的範疇裡面了。

那當我們training set跟test set來源不同或是有差異時,我們的validation set要從哪裡切出來?

答案是:都切

也就是說我們傳統的3分法在這邊變成4分法(如下圖),不同來源的training set跟test set分別又各自被切出來一塊validation,稱為train-val跟test-val。

dataset 4分法

而四分法我們就會有4種performance score要討論,等等就要來討論分別每種情況是如何。

基於4分法來optimize performance

現在我們有4分dataset,我們就有4個performance可以看(如下圖)。

borrow from FSDL slide

從上圖可以看到,我們一般在training前會先設定一個目標,這個目標通常是依附著商業價值來想,不過滿多會設定要達到或是超越某種Human level performance(左圖藍線),這裡先不討論這個設定是否合理。因為我們現在有4個data set,所以我們在左圖中也有4條對應的error曲線,越低越好,而一般我們初期都是human error < train error < train-val error < test-val error < test error,因此我們其實有4種gap要縮小,每兩個error之間的gap如果都能縮小,我們最終就可以達到test error ~= human error,而讓我們的系統達成預期目標

所以我們的第一步其實就是:定位出目前是哪兩個error之間有gap

這邊我直接把結論給你(如下圖),今天如果我們發現哪兩個error之間有gap,我們可以馬上使用這個對應表了解我們現在身處的情況,而接下來就來快速談談在這些情況要做甚麼

error gap table

Human error/Train error gap = Underfitting

李宏毅老師說過:ML的起手式就是training set performance衝刺到完美(類似的意思)

當自己train error跟Human error還有gap時,只有兩種可能:Underfitting跟這個dataset train不起來。

我們一般是優先當成underfitting來解,除非gap太大,這個部分之後再提。

現在假設已經知道是underfitting了,那我們有甚麼事情可以做?

borrow from FSDL slide

FSDL推薦我們優先做這事情,基本上就是大家心中想的,Underfitting時重點就是把model capacity拉高,把model加大跟reduce regularization是最直接做的事情。

而如果這兩件事做完效果不明顯,那應該要做的就是Error Analysis,像是所謂的noise data或是outlier,可能就會導致我們在training set上面一直fit的不好,但是這些data是不必要學的,在kaggle很多比賽也都是做完data cleaning後夠有一波明顯的performance improvement。

而最下面E調參數、F加feature,這兩件事很多新手會在早期做,但是實際上大部分都不推薦做這兩件事情,這邊特別講一下,這裡說的調參數是說跟model大小無關的參數,跟model大小有關的參數都被歸類於A:把model加大。

調參數(跟model大小無關的參數)大部分都只是微微影響到最終performance,不必要,而加feature是一件非常危險的事情,加少少幾個沒問題,但是如果大量加feature,像是做polynomial feature engineering通常後期會導致overfitting,但是這不代表不能加feature,如果今天研究過domain knowledge後特別想要加某些feature,那這完全是可以的

Train error/Train-val error gap = Overfitting

borrow from FSDL slide

當我們已經確定model在training set上面fit好了,但是在train-val上面做不好,那大概率就是overfitting,除非你training跟train-val有某種切割data的問題,導致它們長相不一樣,不然兩個應該是要幾乎同樣distribution的。

Overfitting在過去比較常被討論,基本上也是很常見的事情,前4步都是能做就做,一樣Error Analysis後面一般不推薦。

這邊特別提一下Overfitting時做的error analysis,我們在training中做error analysis如剛剛所講,其實大部分是在找noise data或是outlier,或是從model做不好的sample中看出model architecture的問題(像是image data用CNN就比較適合但是用DNN就不好train),那在overfitting時做error analysis我們會發現甚麼事情?在這時我們常常會發現model在奇怪的sample上over confidence。也就是說model找到某種奇怪的feature,人眼發現不了,而這些feature其實不通用,所以只到train-val時就出錯了,所以在overfitting時做error analysis其實有時候也可以做到debias或是找到data collection的錯誤,這個比較細節之後有時間再開篇幅來找實例討論。

而最下面的Early stopping 、 remove feature跟reduce model size非常不推薦做,只要你從underfitting那步都是小心的走過來,那當你遇到overfitting的時候,再減小model size或是remove feature高機率會讓你回歸到underfitting的狀態。而Early stopping則是因為,常常我們會一個model放著train,原本以為已經收斂了,但是過個一週發現model又進步了,所以如果做early stopping反而拋棄了這種可能性。

Train-val error/Test-val error gap = Distribution mismatch

當我們train-val error小但是test-val error有問題時,這時候就很嚴重了,因為這代表我們原本的training跟test的來源不同,並且這個不同是嚴重的,導致了我們在train跟train-val上面已經tune好的model到test-val上面爛掉,而這就是俗稱的distribution shift,也就是說原始的train distribution跟原始的test distribution不一致。

borrow from FSDL slide

當我們遇到distribution shift的時候,其實如果可能,我們要檢討一下要怎麼樣重新收集我們的training set,或是收集到更好的training set,但是這件事通常都做不到,所以我們我們另外可以做的就是synthesize data跟domain adaptation。

synthesize data跟domain adaptation都很難做,這兩塊我考慮之後各開一個篇幅來說明。

但是這邊就用FSDL的slide給出一個基礎的例子。

在遇到任何問題都是可以做error analysis,而distribution shift也不例外。在distribution shift這裡做error analysis時,最重要的就是找兩邊dataset裡面,只在test-val出現並且model犯錯的特殊feature或是特殊data。

在FDSL的slides裡面他們提了3個在這個階段找到的error type,如下面三張圖。

Error type 1
Error type 2
Error type 3

而其中因為只有Error type3是只在test-val出現的問題,所以這裡我們要專注在這種error裡面

而基於上面的觀察它們就提出了下面的解法

potential solution

因此我們可以發現FSDL把Nighttime scenes放在最高priority,具體怎麼解之後再討論,但是當我們在distribution shift這個階段的時候,一定要專注在這種只有test-val嚴重犯錯的情況,專注在解決這些才會解掉distribution shift,而其他問題可能解掉是讓你training error又更低一點,但是你已經度過那個階段就代表training error你已經可以接受了,所以實際幫助不大。

Test-val error/Test error gap = probably too small test-val set

最後這種情況最奇怪,通常出現的情況就是Test set太小導致test-val切出來也很小,而我們model的hyperparameters tune在test-val上,所以在太小的data上面選hyperparameters並不具有足夠的代表性,而找到不好的hyperparameter。而FSDL針對這種情況推薦的做法就是如下圖

結語

在training的過程中時時檢查自己目前處於哪個階段,能夠讓每個我們學到的工具更物盡其用,不再會把regularization用來解underfitting,並且也能夠更清晰我們目前這個產品遇到的困境是甚麼,做出更精準的策略,所以這件事也是PM需要明確了解的事情。

這個流程我也應用在kaggle上面,train跟train-val就是我們拿到的有label的data,而test-val就是public leaderboard成績、test就是private leaderboard,所以大家會說如果在labeled data上的cross validation score跟public leaderboard score有差時要很謹慎,因為這很有可能是distribution mismatch,代表官方在切data的時候特別在搞事,尤其是時間相關的data就非常嚴重,所以用一樣的流程在kaggle上也能幫助我們更推進我們的score,即便我們沒有private leaderboard的成績。

如果喜歡這篇文章可以幫我多拍手幾次XD,或是對於哪個類型文章有興趣都可以在留言區跟我講~ 後續會以中難度的ML/DS/AI知識為主,以及AI/HCI研究相關知識

--

--

倢愷 Oscar

我是倢愷,CTO at TeraThinker an AI Adaptive Learning System Company。AI/HCI研究者,超過100場的ML、DL演講、workshop經驗。主要學習如何將AI落地於業界。 有家教、演講合作,可以email跟我聯絡:axk51013@gmail.com