在什麼都先不知道的狀況下,如果問:
「先測試,再驗證。」
「先驗證,再測試。」
各位覺得哪個語意上比較合理呢?
自從幾個月前與人聊過後,三不五時有機會,我就會問身邊的人,這兩個哪個比較合理?大多數人(且沒有受模型處理荼毒過)的答案都會是:先測試,再驗證。
歸納一下這樣回答的想法(同時也是我的想法),中文這兩個詞:「測試」通常指的是開發階段,換言之是工程師自己在測試,無論程式碼或商品,都還沒完成,都還在「測試」而已;而「驗證」,通常是已經開發完了,現在要把這套開發出來的東西,不管是程式碼或實體商品,拿來實際運作,例如我們常說做市場驗證、做商業驗證。
無論如何,以中文語意而言,直覺上的理解,會認為「測試」在前,「驗證」在後。但當這兩個詞彙進到【機器學習】或者任何【數據模型】的領域時,這兩個單詞,卻會令許多人相當混淆。幾個月前跟人聊到這議題,分享如下,也借這機會,說明到底何謂:Train、Test、Validation,並闡述整個演變的脈絡。這可惜我在書中沒有寫得更詳細,當年若更多時間,應該完整把以下內容收錄進書裡。
手上有1,000組的數據,每1組數據包含9個自變數(X1~X9),和1個依變數(Y)。
換言之,我們可以用X1~X9去預測Y:
A群集:800組資料,「800個X1~X9」與「800個Y」。
B群集:200組資料,「200個X1~X9」與「200個Y」。
現在跑模型,拿A群集進去訓練,得到一個模型後,將B群集的200個X1~X9丟進去,會得到200個Y_hat,也就是我們透過得到的模型,預測了B群的這200個Y應該是多少?換言之,我們有200個「預測出來的Y(Y_hat)」和200個「實際上的Y(Y_real)」,可以讓我們看這個模型到底好不好,準確度如何。
A群叫做【Train Dataset】訓練資料集。
B群叫做【Test Dataset】測試資料集。
B群的X有沒有做「修正模型」這件事?還沒有,目前還沒有,這時B群的X還只拿來讓我們人類心裡有底,看這模型好不好而已。
於是,會開始有這樣的想法:每次都是我人類下去看,覺得這次正確率很低,才去改模型,這段能不能做成自動化?例如當這次的模型參數,套B群的X跑出來正確率很低,我就嘗試別的模型參數,最後再一口氣去看,全部測試出來的模型參數結果,哪個正確率最高就選誰。
這種時候,無意間,B的X已經是修正模型的其中一個變項。所以請停止你那可怕的想法。
換句話說,它已經失去【Test Dataset】測試資料的身分,當它的X會影響模型時,它就不是Test,請務必了解,Test的X,不能拿去影響模型、不能拿去修正模型。因為Test的Y是解答,不能看完答案,再回頭去做題目,這種作弊出來的考試成績,是絕對不能用的。換言之,當我看到Test的正確率很差,而決定回頭去改模型時,我就已經正在做可能會overfitting的事情了。
於是失去Test身分的B群,有了新的身分,它就是【Validation Dataset】驗證資料集。
然而問題來了,A群訓練模型,又用B群去反饋修正模型,那這模型肯定有overfitting可能,同時還沒有客觀資料可以看正確性,因此對於AB群的拆分,有了新的想法:
A群集:800組資料,「800個X1~X9」與「800個Y」。
B群集:100組資料,「100個X1~X9」與「100個Y」。
C群集:100組資料,「100個X1~X9」與「100個Y」。
A群一樣訓練模型、B群做反饋修正模型、拿C群來看模型好壞,且C群的X不會再回頭修正模型,我也不會因為看到C群結果很差,而回頭去改模型,換言之,C群的定位正是【Test Dataset】測試資料。於是發生了非常違背中文語意的狀況:A群訓練(Train) 後、先B群驗證(Validation)反饋修正模型、再C測試(Test)看模型好壞。
這邊的「驗證」,談的已經不是文章一開頭,模型開發完成後,所謂的市場驗證、商業驗證;反而,它仍舊在模型本身,甚至它正是修正模型的資料集之一,它仍在開發階段,而且還沒有開發完。這在外國詞彙語意上或許不會有問題,在中文,卻非常容易令人誤解。因為,連「測試」也已不是原本我們所習慣的意思,反而,「測試」在模型運作上的定位,更像是中文所說的「驗證」呢……
會發生誤解也不單純在於中文字眼的使用上,同時也因實務運作上,會有許多不同期間階段性的演變,而難免令人困惑。
模型開發,不會永遠停在第一步、第一次,開發一陣子後,會有個「還不錯、還堪用、且排除overfitting狀況」的模型,後續再進行「係數上的」優化調整,而不是「參數上的」優化調整。
換言之參數要用什麼、模型要用什麼,在前期開發中都已經確定,投入更多的X,只在於將模型的係數優化,這種時候,就不需要再使用Validation,而可以單純的做Train(800), Test(200)即可,甚至我們有信心不會overfitting的話,直接Train(1,000),理論上會有最精準的係數。
但因實務上差異已不會太大……(增加少量資料調整係數仍會優化模型但幅度並不大,大幅度優化模型的重點仍然在增加變數或選用到更好的模型或參數配置)……且仍需Test來看模型好壞,而不能只靠「我們有信心」,所以仍是會保留一小部分的Test Data,例如做成Train(900), Test(100),是模型穩定後比較常見的最終配置。
換言之當我們找到一個穩定模型後,是可以將Validation階段去掉的,然後讓此模型盡可能地去運作更多的資料,取得更好的係數(不是參數)。
接著問題來了,老闆會一直問你,我們有新的資料不斷進來耶,阿你的模型,參數都不用改喔?都不用試看看有沒有更好的模型喔?坐領乾薪喔?(我們先當作老闆知道參數和係數的差別,且他要求的是改參數和測試新模型,而不僅僅是優化係數。)
新資料的關鍵在於,【有沒有實際的Y(Y_real)】,例如像股票資料,如果我們做的是時間序列,做半年預測,那確實新資料的X每營業日都有啊,但Y_real要「X的營業日+半年後」才會知道啊。沒有Y_real的新資料,沒啥好選擇的,它最多只能當Test Data,後續再每天等它的Y_real出來確認正確性,確認沒有出大事。
這麼做,等於是當下投入了所有具備Y_real的資料進模型去訓練,並盲目…呃不是…並有信心的去相信目前的模型已經穩定,為了取得最好的係數,所以丟入了全部的資料;接著就等每天Test的Y_real出來,讓自己的信心不崩潰。
但如果是有Y_real的資料,它雖然是新資料,但它能不能補進Validation Dataset?當然可以啊!甚至要把它拿去進Train Dataset都可以啊!在保留後續有Test(且Test有Y_real)可以觀察正確率的前提下,具備Y_real的資料,想怎麼處理都馬可以!
新資料變成Test?可以!
新資料變成Train?可以!
新資料變成Validation?可以!
反正現在老闆要你改測試新模型,而不是同一個模型改改係數,那取得新資料可當作擁有一份完整的新資料,怎麼做都可以!
那什麼狀況下不行?
老闆說,欸現在有新資料50組喔,原本模型Test出來的結果不錯,套看看新資料結果如何?這需求就不是改模型,而是指定要把新資料當成Test來看既有的模型好不好。結果!一套完新資料,完了~結果超爛,怎辦?(穩定模型照理說是不會這樣啦,再差都還是有一定水準,第一時間看到新資料的準確率低,通常是因為忘記把新資料作和模型相同模式的正規化)
「把新資料倒進Validation回去改模型啊!」在並非忘記正規化時,這肯定是第一個想法,因為實務處理起來最簡單,不用動train(900), test(100),且重新跑尋找模型(和參數)的程式即可,這最快。
「把新資料和舊資料併一併,當成全新的資料,重新切train / validation / test 啊!」這肯定是第二個想法,因為這根本就叫做【砍掉重練】,這最慢。
因此在不同時空背景下、不同期間做模型,整個演變過程依序如下:
上面這過程有「一定」嗎?並沒有,實務上視模型結果而決定要做什麼事情。
上面1~4的過程是非常可能發生的,然而,無論1到2,或3到4的過程演變會有一個有趣的狀況,就是「先存在測試資料,再加入驗證資料」的這個過程發生了,在網路上的許多討論裡面,看到許多人將其理解為「模型的運作步驟是先測試,再驗證」,同時這實在非常符合中文語意……
但這實屬誤解,更正確應該叫做「在開發模型的多個期間裡,模型運作的演變很可能某個期間沒有使用驗證資料集,下個期間才加入驗證資料集。」
縱使實務運作上,可能Train和Test都已經存在了,後人想要優化,之後才加入了Validation階段,但並不代表模型運作是【先進行測試資料步驟,再進行驗證資料步驟】,反而是【先進行驗證資料步驟,再進行測試資料步驟】。因為測試資料就是拿來對答案的,永遠是最後一步。
在小馬我實務經驗上,通常會把新資料做成Validation,以追求偷懶…呃不是…以追求更好的模型,但這絕對不是說模型當下運作的過程中,「先Test再Validation」;而是「前面穩定模型的期間」已捨棄Validation階段,當我拿到新資料後,又重新將Validation階段加進了我的模型中。一個是單一動作(一次性的運作模型),一個是多個動作(每次運作模型時,隨著時空背景不同,每次跑模型使用的資料劃分可能不同,有時候跑模型只用Train / Test,有時候會有Train / Validation / Test)。
所以…各位同學,不要再誤會了齁……接著開放提問。
(這件事果然很難三言兩語解釋清楚,今天有點空,把內容完整寫出來,以後若遇到有人被困惑住,可以請他先來看這篇。)
Q:看到有人說「如果現在有新資料,可以拿Test進去跑模型,並拿新資料來驗證。」這說法正確嗎?Test不是不能拿去跑模型?
A:不得不說,這段話聽起來真的超順耳的,但這邊講的「驗證」並非指「Validation」,可能被「驗證」這兩個中文字困惑了,縱使中文語意很通順,但他實際要表達的是「可以將原本的Test改成Validation或Train,重新去做模型,並拿新的資料當成新的Test。」但當然前提是新的資料有Y_real,另外這屬於「舊資料都拿去跑模型,新資料都拿來看模型好不好」的邏輯思維,以偷懶的角度(像我)會直接把新資料當validation就好,train和test都不用動。
Q:所以模型處理可以不必有Validation,但一定要有Test?
A:正確,一定需要公正客觀第三方,來看訓練出來的模型準確度(Testing Accuracy)如何,同時又因為它必須具備Y_real,所以第一次跑模型,拿到的資料,不能全部都做成Train或Train + Validation,而一定要保留Test。但後續有新資料,就能視狀況自由運用舊資料了。
Q:應該要建置Validation Dataset嗎?
A:理論上,我們測越多的模型、測越多的參數、建置越完善的反饋模型,就能找到更棒的模型及參數配置,但人的一生有限,你希望窮盡一生只為了找到眼前更棒的模型嗎?所以這很視需求而定,如果在穩定的產業下,經驗豐富的數據分析師,已經習慣幾個很不錯的模型和參數配置,新資料來就不見得需要每次都得轉變成Validation Dataset去找更好的模型。
但換個角度想是,模型就再也不會進步了,所以應該這樣問:在你的時空背景裡,讓模型進步是必要的嗎?有足夠的軟硬體、好的效能、穩定且充分的新資料來源,可以讓你看到模型進步嗎?這權衡的是Validation運作下去的效益,不然單純比較模型正確性,當然有Validation Dataset去反饋訓練,理論上Test準確度會較高。
Q:所以如果我看到Testing Accuracy很不好,而回頭改模型,是不行的?
A:對,不行。理論上這樣只是把模型改得更符合Test而已,對未來的新資料並沒有幫助。
Q:但如果不透過觀察Testing Accuracy,每次回頭改模型,那我該怎麼知道要往什麼方向去修正模型?
A:當你有這樣的考量,你就需要做Validation Dataset,每次觀察Validation Dataset的Accuracy,去試圖修正你的模型,並觀察每次的修正,是否有帶動Validation Accuracy的改善?如果有,再觀察Testing Accuracy是否也有同步改善。如果兩個數值是同步改善的,那姑且就能先相信這樣的改善方向正確,但也有機率會發生,你只是剛好做到了同時overfitting Validation和Test的改善罷了。這種時候就得等新資料來當新的Test才能發現了。
(註:這裡得看實際到底運作什麼模型,但本文不細究各模型,不然談不完,光釐清Validation和Test已經一長篇了。)
Q:之前你曾經遇過完全把Validation和Test搞反的主管,你為什麼沒有糾正他?
A:不要說業界主管了,我還遇過教機器學習的老師搞反的……。但有時候我覺得可能非戰之罪,因為中文語意上真的很容易講出這句話「拿新資料來驗證」,對啊,沒錯啊,我有新資料我確實可以驗證原本的模型是不是真的有做好啊,但隨後你可能馬上聽到他說「把新資料拿來test看看 」……。哇靠所以新資料到底是要進Validation還是進Test,你搞得我好亂啊!Validation的X可以拿來修模型,Test的X不行欸!甚至連我想看著Test Accuracy回頭去修模型都不行欸!
Q:那當老師提到「驗證」或「test」的時候,到底該怎麼區別?
A:我覺得就直接問,老師你說的「驗證」,指的是把新資料進「Validation Dataset」嗎?老師可能會很慌張地發現自己無意間說出了非常會誤導的字眼,他可能會回你:「喔不是不是!我這邊說的『驗證』不是Validation,我意思是能拿來看模型『好不好』,換句話說我意思是可以拿來進『Test Dataset』。」這時候你就清楚了,但我知道台灣學生都不太愛發問,於是就會一直困惑住自己。
就像我也曾經很省略地說過「Validation確實不是拿來建Model」,但我的意思其實是「當這次拿到新資料且不想不需要重新處理Validation階段時,Validation確實可以不用進Model去反饋訓練,可以當作Test。」(對啦其實我知道我這樣講很有語病,因為當我決定Validation資料要當作Test用時,其實已經沒有所謂「Validation資料」了,它就是單純的「新資料」罷了,後面提到習慣動作會再補充說明這個。)
Q:還是想問你為什麼沒有糾正那個主管?讓他知道自己錯了?
A:那你不是當場讓他很沒面子嗎?(笑)……好啦應該說,慣用中文的人,會誤把Validation和Test搞混,把「驗證」和「測試」搞混,在我認為非常合理,甚至不能苛責他們,就說了你問絕大多數沒碰過模型的人,他們肯定都回答你「先測試,再驗證」。所以我心裡並沒有覺得這是【非改不可、非釐清不可】的事情,甚至放寬心胸來看,那不過就是一個專有名詞定義罷了。我還看過把網路共用資料夾稱為資料庫的呢……
另外,如果當場我糾正他,那接著的討論會非常麻煩,因為如果對方接受糾正,那麼……當他很順地在描述「所以我們的Validation……」,你會無法確定他還在原本的錯誤,他講其實是Test,還是他已經有改過來,他講的真的是Validation?所以當下都不應該糾正,反而應該順著他的思路,我們也將Validation和Test反過來講,會議才能順利進行。
真的要糾正,也是整場會議結束後,甚至只剩下自己跟客戶主管獨處時,再試著討論這件事。而且也不要劈頭就說「你講反了」,盡可能委婉地說「其實通常拿來做反饋模型的資料集,我們比較會把他稱為是Validation,也就是驗證資料集,而不是測試資料集,不過無妨,各家公司有自己慣用的專有名詞名稱,是很常見的,只是網路上大多會把這個功能的資料集稱為Validation啦~(輕鬆帶過,但也暗示他可以去多了解)」
Q:為什麼你很常把新資料直接當作驗證資料(Validation Dataset)?
A:還是特別強調一下,這並不是唯一解。我之所以很常直接把新資料當驗證資料,大概幾個原因:首先如前面所說這是我的慣用做法,不同人會有風格上的差異,新資料當驗證資料的好處,在於我不必重新調整我的Train和Test,又可以直接嘗試看能不能找到好的模型跟參數配置,所以新資料先進Validation通常是我習慣上的第一動作。
但接著,我真的會重新去跑「找模型和找參數配置」的程式嗎?有時候我想想一跑要好幾天甚至幾週,我就懶了,那這時候已經寫進Validation的新資料怎辦?不怎辦,就直接當Test,和Test合併後去看準確率就好,或是直接替換掉Test,單看新資料的準確率如何?如果還不差,那「找模型和找參數配置」的程式我就肯定更懶得去跑了。
另外還有一個原因,在不同期間,模型的改善勢必有新資料進來,模型運作不該只有單一期間,跑完就了事,模型必須長時間不斷優化,所以我一直把新資料當成是模型運作的其中一環。那問題來了,單一期間如果我們已經定義完 Train / Test / Validation,那新資料要把它稱為什麼?所以在我習慣上,我並不會在第一個期間就做Validation,而只有Train / Test,會等新資料進來,再重新來找好的模型或參數配置,這也是你很常見到我會直接把新資料叫做Validation的原因,姑且當作小馬個人風格吧!
其實還有一個私人因素,我一直覺得「測試」和「驗證」在中文語意上存在與機器學習定位上的矛盾,畢竟我是慣用中文的人,我會試著想讓這之間沒有矛盾(縱使這個想法不太對,所以說這是私人情感因素),那當我現在只有train / test,爾後我又把新資料直接作為validation,欸嘿~你看,我是不是達成了「先測試,再驗證」的合理性呢?
再講下去好像變成哲學討論了,那我們今天就先到這囉。
如果看完最後一個QA,發現自己變得更混淆,請先忽略最後一個QA,這只是小馬我私人對於模型處理上的習慣定義與任性為之,更往前的內容才是實質客觀上的討論。
另外因自己開公司後,真是忙到昏天黑地,除了講座上能有充裕的時間回答學員問題,網路上我已經越來越少時間可以回覆大家提問,真的不好意思,連IT邦都幾乎沒空來上了;想跟我聯繫建議可以直接Email給我,工作上還是比較習慣收信看信,也比較留意得到。許多回應上,心有餘力不足,萬分抱歉。