Test / Validation 帶給中文使用者的困惑

在什麼都先不知道的狀況下,如果問:
「先測試,再驗證。」
「先驗證,再測試。」
各位覺得哪個語意上比較合理呢?

自從幾個月前與人聊過後,三不五時有機會,我就會問身邊的人,這兩個哪個比較合理?大多數人(且沒有受模型處理荼毒過)的答案都會是:先測試,再驗證。

歸納一下這樣回答的想法(同時也是我的想法),中文這兩個詞:「測試」通常指的是開發階段,換言之是工程師自己在測試,無論程式碼或商品,都還沒完成,都還在「測試」而已;而「驗證」,通常是已經開發完了,現在要把這套開發出來的東西,不管是程式碼或實體商品,拿來實際運作,例如我們常說做市場驗證、做商業驗證。

無論如何,以中文語意而言,直覺上的理解,會認為「測試」在前,「驗證」在後。但當這兩個詞彙進到【機器學習】或者任何【數據模型】的領域時,這兩個單詞,卻會令許多人相當混淆。

幾個月前跟人聊到這議題,分享如下,也借這機會,說明到底何謂: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跑出來的Y_hat還只拿來讓我們人類心裡有底,看這模型好不好而已。

於是,會開始有這樣的想法:每次都是我人類下去看,覺得這次正確率很低,才去改模型,這段能不能做成自動化?例如當這次的模型參數,套B群的X跑出來Y_hat正確率很低,我就嘗試別的模型參數,最後再一口氣去看,全部測試出來的模型參數結果,哪個正確率最高就選誰。

這種時候,無意間,B的X已經是修正模型的其中一個變項。所以請停止你那可怕的想法!

換句話說,它已經失去【Test Dataset】測試資料的身分,當它的X會影響模型時,它就不是Test,請務必了解,Test的X和Y_hat,絕對不能拿去影響模型、不能拿去修正模型。因為Test的Y_real是解答,不能看完答案,再回頭去做題目,這種作弊出來的考試成績,是絕對不能用的。

換言之,當我看到Test的正確率很差,而決定回頭去改模型時,我就已經正在做可能會over-fitting的事情了。

於是因此失去Test身分的B群,有了新的身分,它就是【Validation Dataset】驗證資料集。

然而問題來了,A群訓練模型,又用B群去反饋修正模型,那這模型肯定有over-fitting可能,同時還沒有客觀資料可以看正確性,因此對於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)看模型好壞。

這邊的「驗證」,談的已經不是文章一開頭,模型開發完成後,所謂的市場驗證、商業驗證;反而,它仍舊在模型本身,甚至它正是修正模型的資料集之一,它仍在開發階段,而且還沒有開發完。

這在外國詞彙語意上或許不會有問題,在中文,卻非常容易令人誤解。因為,連「測試」也已不是原本我們所習慣的意思,反而,「測試」在模型運作上的定位,更像是中文所說的「驗證」呢……

會發生誤解也不單純在於中文字眼的使用上,同時也因實務運作上,會有許多不同期間階段性的演變,而難免令人困惑。

模型開發,不會永遠停在第一步、第一次,開發一陣子後,會有個「還不錯、還堪用、且排除over-fitting狀況」的模型,後續再進行「係數上的」優化調整,而不是「參數上的」優化調整。

換言之參數要用什麼、模型要用什麼,在前期開發中都已經確定,投入更多的X,只在於將模型的係數優化,這種時候,就不需要再使用Validation,而可以單純的做Train(800), Test(200)即可,甚至我們有信心不會over-fitting的話,直接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 啊!」這肯定是第二個想法,因為這根本就叫做【砍掉重練】,這最慢。

因此在不同時空背景下、不同期間做模型,整個演變過程依序如下:

Train(800), Test(200),未廣泛比較過,隨便人為自選基本模型。
Train(800), Validation(100), Test(100),系統化追求更好模型。
Train(900), Test(100),步驟2模型已穩定,追求相同模型參數下更好的係數。
Train(900), Validation(50), Test(100),新資料進來,老闆要求追求更好的模型。
上面這過程有「一定」嗎?並沒有,實務上視模型結果而決定要做什麼事情。

上面1~4的過程是非常可能發生的,然而,無論1到2,或3到4的過程演變會有一個有趣的狀況,就是「先存在測試資料,再加入驗證資料」的這個過程發生了,在網路上的許多討論裡面,看到許多人將其理解為「模型的運作步驟是先測試,再驗證」,同時這實在非常符合中文語意……

但這實屬誤解,更正確應該叫做「在開發模型的多個期間裡,模型運作的演變很可能某個期間沒有使用驗證資料集,下個期間才加入驗證資料集。」

縱使實務運作上,可能Train和Test都已經存在了,後人想要優化,之後才加入了Validation階段,但並不代表模型運作是【先進行測試資料步驟,再進行驗證資料步驟】,反而是【先進行驗證資料步驟,再進行測試資料步驟】。因為測試資料就是拿來對答案的,永遠是最後一步。

在小馬我實務經驗上,通常會把新資料做成Validation,以追求偷懶…呃不是…以追求更好的模型,但這絕對不是說模型當下運作的過程中,「先Test再Validation」;而是「前面穩定模型的期間」已捨棄Validation階段,當我拿到新資料後,又重新將Validation階段加進了我的模型中。一個是單一動作(一次性的運作模型),一個是多個動作(每次運作模型時,隨著時空背景不同,每次跑模型使用的資料劃分可能不同,有時候跑模型只用Train / Test,有時候會有Train / Validation / Test)。

所以…各位同學,不要再誤會了齁……以下開放提問。

這件事果然很難三言兩語解釋清楚,最近利用點時間,把內容完整寫出來,以後若遇到有人被困惑住,可以請他先來看這篇。

(下一篇QA)