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研究相關知識

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

倢愷 Oscar
倢愷 Oscar

Written by 倢愷 Oscar

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

No responses yet

Write a response