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还只拿来让我们人类心里有底,看这模型好不好而已。

於是,会开始有这样的想法:每次都是我人类下去看,觉得这次正确率很低,才去改模型,这段能不能做成自动化?例如当这次的模型参数,套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. Train(800), Test(200),没有广泛比较过,随便人为自己选的基本模型。
  2. Train(800), Validation(100), Test(100),系统化追求更好的模型。
  3. Train(900), Test(100),步骤2模型已稳定,追求相同模型参数下更好的系数。
  4. 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)。

所以…各位同学,不要再误会了齁……接着开放提问。

(这件事果然很难三言两语解释清楚,今天有点空,把内容完整写出来,以後若遇到有人被困惑住,可以请他先来看这篇。)
 
 
 
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给我,工作上还是比较习惯收信看信,也比较留意得到。许多回应上,心有余力不足,万分抱歉。


<<:  [实作教学]使用Line Notify收到Dcard最新文章通知

>>:  [Day31]那转职稽核好玩吗

Day#05 Storyboard

前言 今天的东西比较少程序,不过就是UIvs方法拉来拉去做连结,所以我尽量截图让开发过程能被描述的更...

Day 04:程序语言

写 Android 会遇到的语言 Kotlin 用途: 这是写 Android 的主要语言,请务必熟...

[JS] You Don't Know JavaScript [Scope & Closures] - Using Closures?

前言 目前为止我们都专注在解释辞法范围,以及他会对程序中的变量与使用产生什麽影响,本章节会将角度转移...

Day 19 Knative Serving DNS 测试

Knative v0.20.0 requires a Kubernetes cluster v1.1...

SQL Server 死结 (deadlock) 的分析查询 - 心得分享

DBABootcamp 在 SQL Server, 死结的发生是因为有两个或多个工作(process...