DL Troubleshooting:我的bug來自哪裡?完整DL debug流程!

Full Stack Deep Learning筆記part 2

倢愷 Oscar
12 min readFeb 13, 2021

這次內容一樣大量參考Full Stack Deep Learning 2019,加上一部份個人解讀,歡迎大家去看原始影片介紹。

有做過DL的research或是自行開發DL model經驗的人大部分都有一個非常非常痛恨的疑問,那就是

到底我的bug來自哪裡?

screen shot from Andrej Karpathy’s tweet

Andrej Karpathy對DL的debugging給出了非常深刻的描述XD,我們大部分reproduce別人的model甚至自己開發的時候,都會經歷這麼一段非常痛苦的時刻,這個痛苦我個人認為比傳統的debugging更有過之而無不及。

為甚麼呢?

請大家想像一個情況,假設你今天要reproduce別人的model,而你的結果如下。

borrow from FSDL slides

左側是paper裡面寫的learning curve,經過多個iteration最終降到 30%以下的error,而右邊是你reproduce出來的結果,此時你發現你的結果跟paper裡的有一段不小的差距,那你要如何debug?

大多數的人在此時完全毫無頭緒怎麼辦!為甚麼?因為太多可能性了!

borrow from FSDL slides

不好的結果(Poor model performance)可能來自於

  • Implementation bugs:有時候label跟data根本沒對齊,有時候不小心鎖死weight,有時候讀錯data,這都是很常見的implementation bugs,進而導致performance掛在那邊。
  • Hyperparameter choices:很多DL的model都對hyperparameter choice非常敏感,尤其像是learning rate,差個2 3倍就有可能從收斂變成完全發散調,drop out rate差一點、LSTM的hidden state大小都會直接影響到最終performance。
  • Data/model fit:有些model就只適合處理某幾個dataset,常常我們把research上很好用的model利用到我們自己的dataset上卻緊緊比baseline高一點。
  • Dataset construction:有時候甚至根本Data本身就有問題,class imbalance 、 noisy label等問題在業界真實收集到的data非常常見,而當你在不同dataset上reproduce別人的model時根本不清楚怎樣的performance是合理的。

光是上面有列出的幾種可能,裡面就蘊含著數百種的可能,並且如果考慮到組合的效應,有些問題沒有同時解掉效果就都沒有明顯改善,這就已經讓我們夠麻煩了。

更不用考慮其他更多更多的可能

像是很多paper裡面其實有用到learning rate scheduler才做到很好的效果,但是卻很少人會report這個結果,有些有自己特殊的feature engineering的方法,有些甚至不公開他的dataset讓你無從觀察,這些都讓DL的debugging更困難一層。

而這種reproduce很困難的問題,在近幾年KDD就推出了reproducibility factor,把是否能夠reproduce一篇paper result當成一個重要的指標,如果沒辦法被reproduce出來,在2018的NeurIPS也由FAIR的研究員Joelle Pineau給了一個talk名為Reproducible, Reusable, and Robust Reinforcement Learning,也提出了RL reproducibility checklist

RL reproducibility checklist

這裡並沒有要深入提reproducibility這件事,但是這個問題絕對是每個ML engineer切身的痛,也是區分一個有經驗的ML engineer跟一個菜鳥的差別。

那我們到底該怎麼做?

既然Debugging那麼困難,那我們就從簡單的事情開始一步一步做起!!

borrow from FSDL slides

FSDL給出了一個框架型的debugging或是說build DL的先後流程,在這種流程下debugging的難度相對會被簡化。

這裡每一步其實都很複雜,我先給個quick summary。

borrow from FSDL slides

總共分為五步,接下來我一步一步講,但是核心就是上面的quick summary,一定要把上面的流程熟記在心,這裡每一步都很複雜,我只會大概談一下,因為實際上很case by case。

Start simple

Start simple的核心就是「先有baseline再說」,所以我們挑選比較簡單的dataset、比較簡單的architecture、比較基準的hyperparameters。

一開始為了快速製造出baseline跟ML pipeline,能多簡單就多簡單,這樣才可以更高效,所以一開始可能使用一個比較小但是跟我們問題類似的dataset,然後class只用比較少幾種class,然後使用一些比較基礎的architecture像是LeNET,或是resnet18之類的,然後hyperparameters也挑選比較標準的像是adam learning rate= 3e-4或1e-3,這樣去跑實驗。

而因為data小、model小,所以一開始可以重複跑很多次,把我們目前的最好效果跑出來。

實際上在公司初期我們要定義產品時,在不確定哪個問題可以被ML解掉,我們也會進行類似的Proof of Concept,拿手邊or線上就有的data,定義一個跟最終問題類似但是被簡化的問題,然後拿現有的model(有code,或是有package能夠輕鬆做出來的),去快速train一遍,確認一下一件事是否能夠被達成,這邊proof of concept跟ML project的start simple雖然目標不同(一個是要驗證一個問題能不能被ML解,另一個是為了先做出基準baseline),但是因為都要求快速驗證,所以其實流程很像。

這邊特別提一下,在初期做的時候我們也會試試看non-ML/DL solution能做到多好,如果做一做發現rule based就可以把這個問題解掉,或是用simple ML + rule based就可以解掉,那就不用浪費時間、資源在後期train model。

Implement & debug

而在implement & debug這塊,用不同框架的debug細節其實差很多,但是大致流程是類似的。

borrow from FSDL

第一步最重要一定是要先讓model run起來,就跟performance無關的error一定是要優先解掉的,這塊不好解的理由主要是很多DL package的error message都不知道在寫甚麼XD,但是從pytorch出來以及keras功能逐步完整後,這個問題逐漸縮小。

這裡run不起來的問題大部分太細節了,所以不贅述,但是在DL已經成熟的現在,大部分的問題都可以在stack overflow上找到解答,另外推薦一下pytorch的issue作者會親自回,以及pytorch跟tensorflow 2.0的文檔其實都在慢慢完善,可以多去看看官方document。

而第二步是最重要的一步!Overfit a single batch

這裡其實就是檢驗我們的model有沒有在training set上做到100%的能李,雖然叫做overfit a single batch,但是我更常做的是直接看training loss能不能降到超低,或是在1000筆的training data上能不能做到接近完美,這能確定我們的model能力是否夠強以及有沒有基礎的implementation bug,像是loss傳不回去之類的。

所以這裡重點其實是看loss curve

一般我們可以把loss curve出問題的狀況分4類

  • Error goes up:這通常是learning rate設的稍為高了,或是loss function的正負號寫反。
  • Error explodes:這也有可能是learning rate設太高,但是同時也有可能是numerical issue,尤其Error衝到inf之類的,那大概率就是我們的prediction出現Nan或是inf之類的太奇怪的數字。
  • Error oscillates(震盪):一樣可能是learning rate太高XD,不過也有可能是有noisy data,或是label跟data沒對齊(被glob的謎之排序雷到,或是不小心只shuffle一個)。
  • Error plateaus(停滯):這可能是learning rate太小,或是gradient傳不回整個model(包含freeze住weight跟model太大),reularization太高,loss function寫錯...等問題。

可以發現上面4個情況都有可能是learning rate造成的,所以我們習慣都是先tune好learning rate,如果learning rate調了兩三種大小,loss curve卻都差不多,那才開始解其他問題。

另一個重點是這裡也可以做error analysis,因為data量比較小,花一點時間做error analysis順便累積對data的熟悉度絕對不是壞事。

補充:我之前遇過一個問題是,我的data太整齊了,導致我麼model學不起來,簡單來講我的class有3種,而我data前1/3的data都是label 0,中間1/3都是label 1,後1/3都是label 2,這導致我的data loader每次抓一個batch的data近來,全部都是同label,所以我的model在訓練的過程中就不斷來回學習全部猜0、全部猜1、全部猜2三件事,導致我最終performance都卡在1/3。

最後是跟現有result做比較,現有result指的不只是別人的論文,相同的model執行在類似的dataset,類似的model執行在相同的dataset,別人的unofficial reproduction都可以,只要跟你的情況越像,並且有code,就都可以參考。

Evaluate

這邊就是一個checkpoint,了解一下目前做到多好。回頭看一下一開始的流程圖。

borrow from FSDL slides

Evaluate後其實就是看目前的效果有沒有達標,如果沒有的話就有兩條路可以走,improve model/data跟tune hyperparameters。

Tune hyperparameters

這邊我在介紹sklearn 0.24的新function successive halving時,有系統性的整理過hyperparameters tuning的方法,目前除了auto ML的方法以外重要的方法都講了。請務必回去參考之前那篇,裡面有講實務上最好用的multi-fidelity search以及自動幫你安排運算資源的successive halving

Improve model/data

這邊請參考我之前的文章,告訴你用4分法的dataset判斷自己現在要做甚麼。

這邊就不贅述。請務必回去複習我的文章,這會讓你的DL流程順很多。

這樣就是一個完整的build ML project的流程,裡面每一步都還是很需要經驗,但是現在把一個複雜的問題拆解成一個5步的流程,並且明確告訴你每一步應該是針對甚麼情況做甚麼事,我在kaggle上以及自己工作時使用這個流程有非常明顯的效率提升。

不過還是要提醒一下,日常無聊就reproduce別人的model,累積自己的coding能力以及對DL的bug的敏感度才是根本的解法。

如果喜歡這篇文章可以幫我多拍手幾次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