一言以蔽之:train 不起來的時候,第一件事永遠是看 training loss。因為病有兩種,而且吃錯藥會更糟。
好啊,我們來開始上課吧。
今天這堂課跟前兩堂不太一樣。前兩堂我們在蓋房子——第 1 講講機器學習就是找一個函式,第 2 講講怎麼把 model 變得有彈性,可以畫出彎彎曲曲的線。
今天我們不蓋房子。今天是修水電。
因為你一定會遇到這件事:你照著前兩講做,程式碼一行不差,跑下去——然後 loss 就卡在那邊不動了。或者更慘,你看到一排 nan。
這時候你會做什麼?我猜你會做一件很多人都會做的事:開始亂改。把 learning rate 調小一點試試看,沒用;把層數加深一點試試看,沒用;換個 optimizer,還是沒用。改到半夜三點,你也不知道自己在改什麼。
今天這堂課就是要讓你不要變成那樣。
我先把整堂課的骨架給你。如果你今天只記得一件事,請記這張圖。
你的 model train 不起來,第一件事不是看 testing loss,是先看 training loss——也就是它在「考古題」上考幾分。
注意看那兩欄的「藥」。它們是相反的。一邊叫你把 model 變大,一邊叫你把 model 變小。
所以如果你診斷錯了——你明明是 optimization 走不到,卻以為自己 overfitting,然後把 model 砍小——那你不是沒治好,你是把病加重了。
你可能會想說:「不對啊,我最後在意的不是 testing loss 嗎?我當然要先看 testing loss 啊。」
對,你最後在意的是 testing loss,這沒錯。但在意它跟拿它來診斷是兩回事。你想想看,testing loss 很大,這件事本身給你的資訊超級少——它可能是因為你的 model 太爛,也可能是因為你 overfitting。這兩件事的藥剛好相反。
所以 testing loss 大,只是告訴你「你生病了」。training loss 才是告訴你「你生什麼病」的那個。這其實就是先驗血再開藥而已,沒有什麼高深的東西。
那今天分成三段:
需要的先備知識:第 1 講的 gradient descent、第 2 講的 network。中間有一點點數學,但都是加減乘除等級的。
這一版是互動的。每一個滑桿你都可以拉、每一個點都可以拖,圖會馬上重畫。而且這一講的每一個數字都是你的瀏覽器現場算出來的,不是預先錄好的表演。請務必動手。
今天要 fit 的東西是一條彎彎曲曲的線:,加一點雜訊,總共 120 筆資料。故意選一條有點難的——它有大的起伏,也有小的抖動。
正式開始之前,我要你先記一個數字:這份資料的變異數是 …。
為什麼這個數字重要?因為那是一個完全放棄的 model 會拿到的分數。
什麼叫完全放棄?就是不管你輸入什麼 ,我一律回答「平均值」。這種 model 完全沒有學到任何東西,而它的 mean squared error 剛好就是資料的變異數。
所以等一下如果你看到某個 model 的 training loss 停在 … 附近,那代表什麼?代表它根本什麼都沒學到,它只是在猜平均而已。
這條「放棄基準線」你自己做實驗的時候也應該算一下。很多人 train 半天,其實 model 從頭到尾都在猜平均,但因為沒有基準線可以比,就一直沒發現。等一下你會看到,這條線會抓到兩個兇手。
好,假設你 train 下去,training loss 很大。看流程圖,你知道有兩種可能:model bias(model 太爛,它連在訓練資料上都畫不出那條線)或 optimization(model 其實畫得出來,但 gradient descent 走不到那組參數)。
這兩個要吃的藥不一樣。model bias 你要把 model 加大;optimization 你把 model 加大是沒用的——加大只會讓它更難走。
那怎麼分辨呢?
這裡有一個判準,我覺得是整個 deep learning 裡面最漂亮的推理之一。做法很簡單:拿一個比較淺的 model 來當對照組,然後看那個比較深的 model,它的 training loss 有沒有比淺的低。
為什麼這樣就分得出來呢?你想想看。假設我有一個 2 層的 network,跟一個 6 層的 network。
6 層的表達力一定包含 2 層的。為什麼?因為你只要讓多出來的那 4 層什麼事都不做(原封不動地把輸入複製到輸出),那 6 層就變成 2 層了。所以 2 層畫得出來的每一條線,6 層一定也畫得出來。這是數學上的事實,不是我猜的。
所以:如果 6 層的 training loss 比 2 層還高,那絕對不可能是 model bias。因為 model bias 的意思是「這個 model 的能力範圍裡面根本沒有好答案」,但我們剛剛證明了 6 層的能力範圍完全包含 2 層的。那它為什麼考得比較差?只有一個解釋:它找不到。
好,那我們來實際跑一次。同樣的資料、同樣的 learning rate、同樣的步數,只有深度不一樣。下面每一根長條都是在你的瀏覽器裡當場 train 出來的。
好,你看到了。0 層(就是一條直線,沒有 hidden layer)loss 是 …,最高。這個很合理——它就是 model bias。一條直線本來就畫不出那個彎彎曲曲的東西,這是 model 能力的問題,你把它 train 到天荒地老也沒用。
然後 1 到 4 層,全部掉到 … 這一帶。比直線好一大截,加 hidden layer 確實有用。
眼睛很利的同學會發現:1、2、3、4 層彼此並沒有一路往下,它們大概都在同一個高度上下抖。這也是實話——今天這個問題其實不難,一層 10 個 neuron 就差不多夠用了,再加下去也榨不出什麼。「加深一定會更好」本來就不是真的,我們現在要看的是另一件更嚴重的事。
那件更嚴重的事就在右邊:6 層跟 8 層,直接彈回那條紅色的放棄基準線上。
欸你知道嗎,這代表 8 層的 network 從頭到尾什麼都沒學到,它就只是在輸出平均值而已。它比一條直線還爛。
那我問你,這是 model bias 嗎?
不可能。8 層的表達力包含 4 層的,4 層做得到的事,8 層一定做得到。所以這一定是 optimization 的問題——它走不到。你切到 6 層或 8 層看看左邊那張圖:那條線一開始掉了一點點,然後就整條平掉了。那不是它在慢慢學,那是它完全停住了。
這件事在歷史上是真的發生過的喔。深度學習在 2010 年之前一直做不起來,很大一部分原因就是這個——不是大家的 model 不夠大,是根本 train 不動。
很多人看到上面那個實驗,第一個反應是:「所以深的 network 比較差嘛,那我用淺的就好了啊。」
千萬不要這樣想。這是把「走不到」跟「不存在」搞混了。那個好答案是存在的,8 層的 network 裡面一定有一組參數比 3 層更好,只是 gradient descent 沒有走到而已。
你可能還會想說:「那我把 sigmoid 換掉是不是就好了?」對,有一部分就是這樣。sigmoid 的微分最大只有 0.25,一層一層往回乘,8 層下來 gradient 就變成 0.25 的 8 次方,也就是六萬五千分之一——這叫 vanishing gradient(梯度消失),白話文就是訊號傳到前面幾層的時候已經沒聲音了。
但我要你注意的是:換 activation 這件事,是在修 optimization,不是在加大 model。
這就是為什麼診斷要做對。診斷對了,你才知道自己該去修哪一邊;診斷錯了,你會在錯的那一邊改到天亮。
Learning rate 就是「一步跨多大」,第 1 講講過。大家都知道它很重要,但是「太大」跟「太小」到底長什麼樣子,這件事你一定要親眼看過一次。看過一次以後,你在螢幕上瞄一眼就認得出來了。
下面這個 2 層的 network,什麼都不改,只換 learning rate。你把滑桿從最左邊拉到最右邊,看它經歷什麼。
上面那排 optimizer 按鈕先不要碰,我們等一下會回來。現在先固定在 plain GD。
四種命運,我們一條一條看。你自己拉到對應的位置對一下:
這幾種長相你記起來:爆炸、看起來活著但其實死了、漂亮下降、龜速。
順帶一提,第二種給了我們一個很重要的教訓:learning rate 太大不一定會報錯。它可能只是安靜地把你的 model 弄壞,然後給你一條「看起來有在收斂」的平線。這就是為什麼前面要先算放棄基準線——沒有那條線,你根本抓不到這個兇手。
好,我們知道 learning rate 要調對了。但為什麼會這樣呢?
要看清楚,我們得把 error surface 畫出來。可是剛剛那個 network 有幾百個參數,畫不出來。所以我們換一個只有兩個參數的問題——兩個參數才畫得出等高線圖。
這個問題我動了一點手腳:我讓兩個 feature 的尺度差很多。第一個 feature 的數值大概在 ±3 這個範圍,第二個大概在 ±0.2。比如說你在預測房價,一個 feature 是「坪數」(幾十),一個 feature 是「屋齡佔比」(0 到 1)。這種事情超常發生的。
算出來的結果是這樣:這個 error surface 兩個方向的陡峭程度是 … 跟 …,差了 … 倍。一個是懸崖,一個是平原。數學上還可以直接算出來,learning rate 只要超過 …,就一定會發散。
你等一下在「動手玩 ④」的下半部就會看到這個地形。它根本不像一個碗,它像一條窄縫。
而這就帶出一個很根本的麻煩:你只有一個 learning rate,但你要同時應付懸崖跟平原。你把步伐調到在懸崖上剛好不會摔下去,那你在平原上就是龜速前進;你把步伐調到在平原上走得夠快,那你在懸崖上一步就飛出去了。一個 learning rate 沒辦法同時滿足兩邊。
而且我要提醒你:這裡的「兩個方向」只是為了畫圖才簡化成兩個。真正的 network 有幾百萬個方向,每一個方向的陡峭程度都不一樣。你要用一個數字去應付幾百萬種地形——你就知道這有多不合理了。
這件事很重要,我們等一下會回來解決它。先記著。現在我們先處理另一個更根本的問題:它到底是卡在什麼東西上面?
好,我們來想一件事。什麼時候 gradient descent 會停下來?答案很簡單:gradient 等於 0 的時候。因為更新量是 gradient,gradient 是 0,你乘什麼都是 0,它就不動了。那 gradient 等於 0 的地方叫什麼?我們統稱它 critical point(臨界點)。
現在問題來了:你被卡在一個 critical point,那是什麼地方?
大部分人第一個想到的是 local minima(區域最小值)——一個小山谷,四面八方都往上,你被困在裡面出不去。大家講到 deep learning 的困難,十個有九個會講這個。
但其實,在高維度的空間裡,local minima 是很稀有的東西。你更常卡到的是另一種,叫 saddle point(鞍點)——就是有些方向往上,有些方向往下的地方。名字來自馬鞍:你坐上去,前後是往下的,左右是往上的。
這個東西 gradient 也是 0,所以 gradient descent 一樣會在那邊發呆。但它跟 local minima 有一個天大的差別:saddle point 是有路可以走的。你只要往對的方向走,loss 就會繼續下降。它不是死路。
下面這個地形有三個 critical point:兩個 local minimum、一個 saddle point。拖那顆白色的球去逛逛,右邊那朵花會告訴你「站在這個位置,往四面八方走分別會上坡還是下坡」——藍色是往上,紅色是往下。
你沒有看錯。一維的時候大概一半的臨界點是 local minima;到了 3 維只剩百分之二點多;到了 5 維以上,三千次裡面一次都沒有出現過。
而我們現在隨便一個 network 都有幾萬、幾百萬、甚至幾千億個參數。
所以結論是:你以為你卡在 local minima,其實你八成是卡在 saddle point。
這是個好消息喔。因為 local minima 是死路,saddle point 不是。saddle point 一定有往下的方向,你只是需要一點力氣、一點運氣,或者一點慣性,把自己推過去而已。
那要怎麼推過去呢?怎麼辦呢?
好,這邊我們換個角度想。
現在的 gradient descent 是這樣:我站在山上,看一下腳下哪邊低,往那邊走一步。停下來,再看一次,再走一步。
你有沒有覺得這個行為很奇怪?它每一步都是從靜止開始的。
這不像球在滾啊。真的球從斜坡滾下來,它會越滾越快;而且滾到一個小坑的時候,它不會就停在裡面——它有慣性,會衝過去。
那我們能不能讓參數也有慣性呢?可以,而且改起來出乎意料地簡單:
就這樣。多記一個「上一步移動了多少」,然後把它的一部分留下來。寫成式子:
就是速度, 通常設 0.9。這個東西叫 momentum(動量)——其實就是把上一步的方向留一點下來而已。那它為什麼能衝過小坑呢?因為在坑底 gradient 是 0,但 不是 0,它還帶著之前累積的速度,所以它會繼續往前跑。
下面是一個有兩個坑的地形,右邊的坑淺,左邊的坑深。球從右邊放下去。你來調那個 ,從 0 慢慢往上加,看它什麼時候才翻得過去。
先看雙坑那組。普通的 gradient descent(灰色)滑到右邊那個淺坑就停了。它沒有做錯任何事——那裡的 gradient 確實是 0,它就是該停。
但 β 調上去以後就不一樣了。綠球衝進淺坑沒有停,帶著慣性爬上小丘,翻過去,然後掉進左邊那個真正的谷底。
右邊那張圖更有意思:綠色那條線中間往上跑了一段。這件事很反直覺喔——我們不是在最小化 loss 嗎?怎麼會允許它變大?
但這正是重點。有時候你要先讓 loss 變糟,才能到更好的地方。一路只走下坡的人,走到第一個坑就結束了。
而且你會發現 β 有個門檻:慣性不夠大就是翻不過去,中間沒有模糊地帶。你可以自己拉滑桿找那個臨界點在哪。
好,我們現在回來處理那個懸而未決的問題。
還記得嗎?窄縫地形,一個方向陡、一個方向平,差了 … 倍。結論是一個 learning rate 沒辦法同時滿足兩邊。
你去看上面那張窄縫圖:紅色那條(純 GD)一開始「唰」一下衝到谷底,然後就沿著谷底慢慢爬,250 步爬到一半就沒了。它不是壞掉,它就是慢。
那怎麼辦呢?這時候你會想到一個很自然的想法:那不要用同一個 learning rate 不就好了?陡的方向用小步伐,平的方向用大步伐,每一個參數都有它自己的 learning rate。
好,那新的問題來了:機器怎麼知道哪個方向陡、哪個方向平?沒有人會告訴它。但其實它手上早就有答案了——看 gradient 的大小就知道了嘛。
所以做法就是:把每個參數的 gradient 平方累積起來,然後拿步伐去除以它的平方根。
其中 是 gradient 平方的移動平均, 是 gradient 的移動平均。那個 是什麼?就是剛剛的 momentum 啊。
所以你把 momentum(記得方向)跟 adaptive learning rate(記得陡不陡)這兩個東西加在一起,會得到什麼?
你會得到 Adam。
對,就是那個你在每一份程式碼裡面都看到的 optim.Adam。它其實就是「有慣性」加上「每個參數自己一個步伐」而已。這一頁的 Adam 是我們自己刻的,總共七行,沒有別的東西。
回去看那張窄縫圖的綠線:Adam 一路走過去,直接踩在星星上。為什麼?因為它發現 w2 這個方向 gradient 一直很小,就自動把 w2 的步伐放大了。沒有人教它,它自己從 gradient 裡面看出來的。
好,那現在請你回到「動手玩 ②」,把 optimizer 切成 momentum 跟 Adam,再把 learning rate 滑桿從頭拉到尾一次。你會看到三件事:
所以實務上你就先用 Adam。真的,不用想太多,先 Adam 下去。如果 Adam 都 train 不起來,那通常不是 optimizer 的問題,你要回去看資料、看 model 架構、看 loss 有沒有寫錯。
我們前面算 gradient 的時候,都是一次拿全部資料去算,這個叫 full batch。這樣算出來的 gradient 是最準的,它是「真正的」下坡方向。
但你想想看,如果你有一千萬筆資料呢?你每走一步都要把一千萬筆算過一遍,那你一天走不了幾步。所以實務上大家的做法是每次隨機抓一小把出來算,這叫 mini-batch。
代價當然有——你抓的那一小把不見得能代表全部,所以你算出來的方向是歪的,它會抖。我們實際測了一下(同一個 network、同樣 800 步):
full batch 那條線最平滑,也走得最低,這符合直覺。但你看最後一欄「每步成本」:mini-batch 4 每一步只算 … 的資料量。同樣的秒數,它可以多走幾十倍的步數。所以「哪個比較好」這個問題,要看你問的是每一步還是每一秒。
但接下來這件事才有趣。那個「吵」,我們一直把它當缺點在講。
其實它是優點。
你想想看,full batch 算出來的 gradient 是固定的。它走到一個 critical point,gradient 是 0,那就是 0,它永遠不會動了。但 mini-batch 不一樣——你換一把資料,error surface 就長得不太一樣,剛剛那個 gradient 是 0 的地方,換一把資料以後可能就不是 0 了。它會被自己的雜訊震出去。
我們用剛剛那個雙坑地形驗證一下。這次不用 momentum,只用最原始的 gradient descent,但在 gradient 上加雜訊——這就是在模擬 mini-batch 的效果。每個雜訊大小放 200 顆球,全部從淺坑那邊出發:
完全沒有雜訊的時候,一顆球都逃不出來,200 顆全部卡在淺坑。雜訊加大以後,逃出去的比例一路往上。
所以那個「吵」不是純粹的壞事,它是一種免費的探索。這就是為什麼實務上幾乎沒有人用 full batch——不是只因為它慢,也是因為它太乖了。太乖的人走不出第一個坑。
好,第二段到這邊結束。左邊那條路(optimization)我們走完了。
好,現在假設你把 optimization 的問題都修好了,你的 training loss 掉到很低很低。你很開心,然後你去看 testing loss。
然後你就笑不出來了。
這就是 overfitting。第 1 講我們提過一次:training loss 低只代表 model 把考古題背熟了。今天我們要真的做出來給你看。
怎麼做出 overfitting 呢?食譜很簡單:資料給得很少,model 給得很大。我們只給 20 個點,但給它一個兩層、每層 24 個 neuron 的 network,參數量遠遠超過資料量。
下面那個滑桿是訓練步數。你從 0 慢慢往右拉,就等於在看這個 model 一步一步被 train 壞的過程。
左圖就是那條經典的交叉圖,你之後會看到一輩子。
藍色的 training loss 一路往下,掉到幾乎是 0。從 training loss 來看,這個 model 完美無缺。但紅色的 testing loss 呢?它先跟著往下,到了某一點——它掉頭往上了。那個轉折點(綠色虛線)之後,你每多 train 一步,model 就變爛一點。
右圖告訴你為什麼。把滑桿拉到最右邊,看那條紅線:它穿過了每一個藍點,一個都沒漏。為了穿過每一個點,它在點跟點之間扭出各種奇怪的形狀。
但那些點上面是有雜訊的啊。它不只學了規律,它把雜訊也一起背下來了。這就是 overfitting——說穿了就是把考古題連印刷錯誤都一起背起來。
那怎麼辦呢?我們有四帖藥。上面那排按鈕已經有三帖了。
按「60 筆」跟「120 筆」看看。你會發現一件很有趣的事:資料越多,training loss 反而越高。
這不是壞事喔。20 筆資料的時候 training loss 低到 0.00 幾,但那是因為它在背答案。資料變多以後它背不動了,被迫去學真正的規律,所以 training loss 上升——但 testing loss 下降,而且兩者的差距一路縮小:
這就是為什麼加資料是最好的藥。它不是在壓制 model,它是在讓「背答案」這條路變得不划算。
這帖是課本上最常寫的第二帖。我們也測了:資料固定 20 筆,只改 hidden layer 的寬度,每個設定換三組不同的隨機初始值重跑,取平均,而且把誤差也畫出來。
這裡有一個做實驗的重要習慣,我要特別提一下:一次實驗不能說明任何事。隨機初始值不一樣,結果就會不一樣。你等一下就會知道為什麼這件事非做不可。
好,這裡我要跟你講一件老實話,因為實驗結果跟課本講的不一樣。
我們原本的預期是什麼?把 model 變小,overfitting 應該要改善才對。結果你看那排橘色的 testing loss,從最寬一路往左砍——它不但沒有變好,反而一路變糟。最大的那個 model,testing loss 反而是最低的。
那寬度 1 跟寬度 2 為什麼那麼慘?看綠色的 training loss 就知道了——它們連訓練資料都 fit 不起來。回去看流程圖:training loss 很大,那就不是 overfitting 了,那是 model bias。
所以「把 model 變小」這一刀砍下去,發生了什麼事?我們沒有治好 overfitting,我們是把病換成了另外一種。
而且你看那個誤差棒。中間那幾根,光是換一組隨機初始值,結果就可以差 …——比很多人論文裡宣稱的「改進」還大。如果我只跑一次就下結論,我可以「證明」出任何我想要的結果。
這件事你要記住:在 network 上,「把 model 變小」是一把很鈍的刀。它是傳統機器學習留下來的直覺,但在深度學習裡它常常不成立——反而是「model 放大,然後用別的方法管住它」比較有效。為什麼會這樣,到今天都還是個活躍的研究題目。
所以你之後如果聽到有人說「overfitting 喔?那你把 model 改小一點」,你可以在心裡打一個問號,然後問他:那你的 training loss 有跟著變高嗎?
那真正好用的是什麼?就是接下來這兩帖。
這兩帖才是實務上天天在用的,而且它們有一個共同的好處:你不用動資料,也不用動架構。
Early stopping 最直覺:既然 testing loss 是先降後升,那我就在它開始升之前停下來不就好了。回到「動手玩 ⑤」,把資料切回 20 筆、weight decay 切回 0,然後把滑桿拉到那條綠色虛線上——你會看到 testing loss 從 … 變成 …,好了 … 倍。什麼都沒改,只是早點收手而已。
但這裡有一個超級重要的細節:你絕對不可以看著 testing loss 決定什麼時候停。為什麼不行?下一段就是專門在講這件事。實務上要用驗證集(validation set),一份我們自己另外切出來、專門用來做決定的資料。
Regularization 換個角度想。剛剛那條紅線為什麼那麼扭?因為它的參數很大——參數大,函式才能急轉彎。那我們就在 loss 裡面多加一項懲罰,懲罰參數的大小:
這樣機器在降低 loss 的時候,就會順便把參數壓小,函式就平滑了。微分之後,這一項的效果就是每次更新都把參數乘上一個略小於 1 的數,所以它也叫 weight decay(權重衰減)——其實就是每一步都把參數縮水一點點而已。程式碼就一行。
回到「動手玩 ⑤」,把 weight decay 依序切成 0 → 1e-4 → 3e-3,看 testing loss 怎麼變:
你有沒有發現一個模式?今天講的每一帖藥,都是有劑量的。learning rate 有劑量、model 大小有劑量、regularization 也有劑量。太少沒效,太多有毒——weight decay 開到 3e-3,training loss 自己就爛掉了,那又變回 model bias 了。
那劑量怎麼決定?這就是最後一段了,而且這一段是今天最容易做錯的地方。
好,我們現在有一堆選擇要做:幾層?每層幾個 neuron?learning rate 多少?weight decay 多少?什麼時候停?
你會怎麼決定?很自然的想法是:都試試看,哪個 testing loss 最低就用哪個。
這個想法非常直覺。它也非常危險。
我先講結論:你用 testing set 挑了 100 次,那 testing set 就變成 training set 了。
為什麼呢?我用一個實驗讓你看。這個實驗我把它設計得很極端:我做 500 個 model,但這 500 個 model 實力完全一樣,而且全部都是亂猜的。每一題都是丟銅板,正確率就是 50%,一個都不例外。然後我拿一份 40 題的 testing set 給它們考,考完挑分數最高的那個。
你覺得會發生什麼事?
右邊那張散布圖是重點。
如果 testing set 的分數真的代表實力,那這張圖上的點應該要沿著對角線排——在這份考卷考得好的,在那份考卷也該考得好。但你看,那就是一團雲,相關係數大概是 0。
那顆紅星星就是我們挑出來的「冠軍」。它在左邊那份考卷上是第一名,在新考卷上就是一個平凡人。
你多按幾次「重跑」。你會發現偶爾那位冠軍在新考卷上還是考得不錯——但那也只是運氣,就跟他第一次考好一樣。單獨一次實驗永遠說明不了什麼(這句話今天已經出現第二次了)。真正的證據是讀數最後那一行:整套流程重複 300 次,冠軍在「挑他出來的那份考卷」上平均七十幾分,換一張新考卷就掉回 50 分附近。中間那二十幾分,完全是「挑選」這個動作自己變出來的。
所以你想想看這件事的可怕之處。你每挑一次,就等於用掉了一點 testing set 的公信力。挑一次還好,挑 500 次,你挑出來的就不是「最強的 model」,而是「最會在這 40 題上碰運氣的 model」。那個 model 在 testing set 上的分數,已經不能拿來預測它在真實世界的表現了。
這件事有一個很好記的說法:你不能拿考卷來練習,然後又拿同一張考卷來評分。
很簡單:把資料切成三份,而不是兩份。
所有的挑選、比較、調參,全部在 validation set 上做。testing set 你把它鎖起來,做完全部的事情以後打開來測一次,然後那就是答案。如果你測完覺得不滿意,回去改,再測一次——恭喜你,你的 testing set 已經被污染了。
這也是為什麼你看到某個模型「號稱」在某個 benchmark 上拿到很高的分數時,心裡可以留一個問號。不是說那個數字是假的,而是你要問:這個分數是第一次測出來的,還是調了三百次以後的最好一次?這兩件事在數字上長得一模一樣,但意義差很多。
而且更麻煩的是,一個 benchmark 被整個領域用了幾年之後,就算每個團隊都只測一次,整個領域加起來也已經對它挑了幾千次了。這時候那個 benchmark 的分數,就開始跟真實能力脫鉤。
我自己是覺得,這是「評估」這件事最難、也最沒有完美解的地方。唯一的解法其實只有一個:不斷做新的考卷。
三題,選了馬上告訴你對不對。
光看是學不會的,你一定要自己改改看。
練習 3 就是下一堂課的入口。想不出來很正常,那正是重點。
今天講了很多工具,但如果你只帶走三件事,請帶走這三件:
然後還有一件事,是今天的實驗自己告訴我們的:課本上寫的藥方,也要拿數據去驗。「overfitting 就把 model 變小」聽起來很有道理,但我們實際測下去,它在這個問題上根本不成立,而且雜訊比效果還大。寫論文、看論文、自己做實驗,都要記得問一句:這個結論跑了幾次?誤差有多大?
然後,今天所有東西都是自己刻的。Adam 就是七行,momentum 就是一行,regularization 也是一行。裡面真的沒有魔法。
你回頭看今天的每一個實驗,還有前面兩堂課的每一個實驗。我們的輸入是什麼?是一個固定長度的數字組合——一個數字、七個數字、兩個 feature,長度永遠是固定的。因為 network 第一層那個 W 矩陣,形狀是寫死的。
可是這個世界上最有意思的資料,長度都是會變的啊。
一個句子可以是 3 個字,也可以是 300 個字。一段語音可以是 2 秒,也可以是 20 分鐘。一段 DNA、一個分子、一張社群網路的圖——長度全部都不固定。
而且更麻煩的是,順序有意義。「我不喜歡你」跟「你不喜歡我」,字一模一樣,意思完全不同。
所以我們需要一個 model,它要能吃長度會變的一整排東西,而且它要知道誰跟誰有關係。
那,怎麼辦呢?
這個東西叫 self-attention,我們下一堂課再跟大家講。
以上就是我今天想跟大家分享的內容。