數(shù)據(jù)科學(xué)家“恐怖故事”
大數(shù)據(jù)文摘出品
編譯:張秋玥、蔣寶尚
文字語(yǔ)音轉(zhuǎn)換圈內(nèi)流傳這么一則真假未知的故事:一個(gè)研究者花了數(shù)月(甚至數(shù)年)調(diào)整他/她的語(yǔ)音生成模型,使其語(yǔ)音樣本聽起來(lái)效果非常好。最后他們發(fā)現(xiàn),他們從頭到尾都誤用同一語(yǔ)音文件進(jìn)行訓(xùn)練,最終模型只是完全符合該語(yǔ)音文件特征所以才擁有如此流暢的語(yǔ)音樣本輸出。這個(gè)故事到現(xiàn)在都讓人不寒而栗。
想象一下另一則恐怖故事:你是個(gè)小實(shí)習(xí)生,老板讓你搭建一個(gè)判斷識(shí)別“Yes”與“No”的語(yǔ)音識(shí)別分類器。你有這些音頻文件:yes1.wav,no1.wav,yes2.wav,no2.wav,yes3.wav等等。你建好了分類器,效果也很好。就在你要展示工作成果之前,你發(fā)現(xiàn)這個(gè)模型唯一在做的事情就是通過讀取文件名里的yes或者no來(lái)預(yù)測(cè)結(jié)果,壓根不會(huì)聽文件里面的音頻。你嚇傻了,大哭一場(chǎng),準(zhǔn)備跑路。
這就是本文作者Vincent Vanhoucke所經(jīng)歷的恐怖故事,完全真實(shí),這些小事故也決定了這位Google首席科學(xué)家的職業(yè)生涯。
以下是他以第一人稱講述的更多小故事,讓我們看看能夠從中得到哪些經(jīng)驗(yàn):
那是我作為研究者的第一份工作。任務(wù)很明確,提供了大量數(shù)據(jù)以及優(yōu)秀的預(yù)測(cè)準(zhǔn)確度標(biāo)準(zhǔn)來(lái)評(píng)估模型效果。模型的基準(zhǔn)結(jié)果很強(qiáng),我最后甚至和一位客戶一起在生產(chǎn)實(shí)踐中部署了這個(gè)模型。
我有試圖根據(jù)我覺得很聰明很厲害的方法來(lái)改進(jìn)模型表現(xiàn)指標(biāo)——它沒有很完美但每一天都在進(jìn)步。我都能看到我腦子里慢慢形成的一篇優(yōu)秀學(xué)術(shù)論文啦。生活真美好。
這算是一項(xiàng)產(chǎn)業(yè)研究,所以在開始撰寫論文之前我還需要通過最后一項(xiàng)測(cè)試:使用真實(shí)顧客數(shù)據(jù)來(lái)評(píng)估模型,以便于快速在生產(chǎn)實(shí)踐中部署改進(jìn)方案。在真實(shí)數(shù)據(jù)集上我的模型達(dá)成了零精確度成就。我可是一直在提高我覺得超級(jí)厲害的表現(xiàn)指標(biāo)來(lái)著。
八成是出了bug,要不就是真實(shí)顧客數(shù)據(jù)質(zhì)量很糟糕——我腦子這么想著,覺得沒多大關(guān)系就急著開始上手寫論文了。但實(shí)際上我又并沒有辦法完全放下這個(gè)糟糕結(jié)果,所以我就開始研究到底是怎么回事。我最后發(fā)現(xiàn)的是全世界數(shù)據(jù)科學(xué)家共同的噩夢(mèng):準(zhǔn)確度就是零,這一點(diǎn)毫無(wú)疑問。我其他所有的準(zhǔn)確度數(shù)據(jù)都是所謂的“幽靈”數(shù)字。我簡(jiǎn)直不敢信:這些數(shù)字看起來(lái)超可信啊,它們比基準(zhǔn)高但并沒有高到不可能的地步。
人們常說(shuō),災(zāi)難一般不會(huì)“成單”出現(xiàn),而是在有兩件事一起出錯(cuò)時(shí),因?yàn)槲覀兛傮w來(lái)說(shuō)很擅長(zhǎng)預(yù)判并改正單個(gè)失誤。為了完全了解到底是什么樣幾乎不可能發(fā)生的系列事件導(dǎo)致了這些看似可信的精確度數(shù)字的出現(xiàn),我必須得從細(xì)節(jié)開始分析。
模型目標(biāo)是改善用來(lái)識(shí)別人名的語(yǔ)法數(shù)據(jù)結(jié)構(gòu)。比如說(shuō),假如你叫“Robert Moore”,語(yǔ)音識(shí)別系統(tǒng)可能將會(huì)把你的名字編譯成為一個(gè)語(yǔ)音圖,大致看起來(lái)像是某種正則表達(dá)式:“/(ˈɹɑb.əɹt|ˈbob|ˈɹɑb) mʊɹ/”——它還兼容類似于“Rob”或“Bob”的昵稱呢。我的任務(wù)是生成更好的語(yǔ)音圖。我的數(shù)據(jù)被存儲(chǔ)為鍵值對(duì)數(shù)據(jù)庫(kù)的形式:
- record {
- key (string): “robert_moore”
- value (Grammar): /(ˈɹɑb.əɹt|ˈbob|ˈɹɑb)mʊɹ/
- }
這里有一個(gè)bug:有些我的語(yǔ)法數(shù)據(jù)結(jié)構(gòu)里用到的語(yǔ)音符號(hào)并不會(huì)被發(fā)音引擎識(shí)別。系統(tǒng)嘗試把語(yǔ)法數(shù)據(jù)結(jié)構(gòu)編譯為一個(gè)應(yīng)當(dāng)代表正則表達(dá)式的圖像對(duì)象,但它失敗了。在層層代碼的深處,有人曾嘗試將系統(tǒng)變得對(duì)于這些失敗更加穩(wěn)?。寒吘?,只要可能,你永遠(yuǎn)不希望系統(tǒng)在生產(chǎn)實(shí)踐中突然垮掉嘛。那段代碼看起來(lái)類似于這樣:
- Graph* graph = compile(record->value);
- if (!graph) { // Failed to compile.
- graph = compile(record->key); // (什么鬼???)
- }
這可真的讓我大吃一驚措手不及:怎么會(huì)有人覺得只要一條數(shù)據(jù)庫(kù)記錄損壞了就代表這條記錄的鍵包含真正的負(fù)載?而且這怎么可能可行嘛?“值”就是一條序列化的型語(yǔ)法,“鍵”就只是一串字符而已。再深挖一點(diǎn)——看,更“穩(wěn)健”的在這里:
- Grammar* grammar = parse(record);
- if (!grammar) { // Failed to parse.
- grammar = parse(pronounce(record)); // (啥???)
- }
如果數(shù)據(jù)不是我們預(yù)想的類型,我們就會(huì)盡量提取那條記錄的內(nèi)容為單詞進(jìn)行發(fā)音。為什么不呢,反正已經(jīng)毫無(wú)希望了嘛。而且,發(fā)音生成是一項(xiàng)非常耗時(shí)耗計(jì)算力的操作。想象一下,不管出于什么原因,一大串沒有任何意義的垃圾字符(包括對(duì)于拒絕服務(wù)的報(bào)復(fù)性操作)突然被輸入到系統(tǒng)里,這對(duì)于系統(tǒng)意味著什么。系統(tǒng)將會(huì)立刻過載,而非“逐漸失敗”。
你可能已經(jīng)意識(shí)到接下來(lái)要發(fā)生什么了。我的數(shù)據(jù)的鍵都是用戶的真名,比如“robert_moore”。發(fā)音引擎很容易就將其近似于“/ˈɹɑb.əɹt mʊɹ/.”。所以,我的數(shù)據(jù)的問題直接來(lái)自于決定模型評(píng)估標(biāo)準(zhǔn)的事實(shí)。
理論上來(lái)說(shuō)這就與我在前文提到的根據(jù)文件名預(yù)測(cè)音頻是yes還是no一個(gè)道理。我沒預(yù)料到的是,發(fā)音模型的隨機(jī)試驗(yàn)看起來(lái)確實(shí)改善了結(jié)果。然而,那其實(shí)只是取決于每次實(shí)驗(yàn)中未編譯成功的數(shù)據(jù)比例而已。我的模型失敗次數(shù)越多,生成的錯(cuò)誤就更多,真實(shí)鍵值使用的更多,我的模型精確度就越好。至于解鎖零精確度成就的真實(shí)數(shù)據(jù)?那個(gè)數(shù)據(jù)庫(kù)里的鍵都是亂七八糟的字符串,看起來(lái)類似于“h4a7n6ks2l”這種發(fā)音模型?
我還算是幸運(yùn)的。我對(duì)符號(hào)檢索問題進(jìn)行的修復(fù)確實(shí)提高了效果,新系統(tǒng)確實(shí)得到了改進(jìn)。數(shù)周的實(shí)驗(yàn)最后都是竹籃打水一場(chǎng)空,我還得跟同事解釋我這個(gè)模型差點(diǎn)就上線運(yùn)行害了所有客戶,以及為啥我越傷害這個(gè)模型線下精確度就越高。必須得說(shuō)一句,他們最后只是大笑了一場(chǎng)這事兒就過去了,還是很客氣的。
下面是我學(xué)到的經(jīng)驗(yàn)教訓(xùn):
第一,不要相信任何人、任何事情。
誰(shuí)都想抓住你的把柄,尤其是數(shù)據(jù)科學(xué)界。大多數(shù)問題會(huì)將預(yù)測(cè)結(jié)果變得看起來(lái)糟糕很多,但有時(shí)結(jié)果看起來(lái)還是足夠好且真實(shí)讓人無(wú)法起疑心。實(shí)際上在語(yǔ)言建模領(lǐng)域,這是一個(gè)超級(jí)常見的問題。計(jì)算以及比較困惑度階段超多陷阱,極小的錯(cuò)誤都時(shí)常能夠提高實(shí)驗(yàn)數(shù)字(而非降低!)。因此,這個(gè)領(lǐng)域的人對(duì)于證明的要求都很高;基于這個(gè)原因,我建議在將模型推廣之前你最好多在開源評(píng)估工具上試驗(yàn)試驗(yàn)。
第二,更不要相信你自己。
在我整個(gè)學(xué)術(shù)生涯中,我很快就學(xué)到了我需要過分質(zhì)疑任何我得到的結(jié)果,盡管我本性并非如此。我現(xiàn)在會(huì)為了模型結(jié)果持續(xù)尋求外部意見,最好是使用一個(gè)完全不同的代碼庫(kù)。
第三,寫簡(jiǎn)單的防衛(wèi)代碼
不要自作聰明。你的代碼應(yīng)該跟你本人一樣偏執(zhí),就算是合同里最小的細(xì)節(jié)有一點(diǎn)不符,你的模型都該立刻引人注目地垮掉。每個(gè)程序員都肯定經(jīng)歷過這樣的事:閱讀堆棧跟蹤到一段標(biāo)注為“這就永遠(yuǎn)不該發(fā)生”的代碼。大量數(shù)據(jù)被寫入磁盤,甚至位翻轉(zhuǎn)這種事情都時(shí)有發(fā)生。我以前有過一個(gè)生產(chǎn)系統(tǒng),因?yàn)閄ML分析錯(cuò)誤就直接崩潰了。磁盤上配置文件(程序自動(dòng)生成的)看起來(lái)就像這樣:
- <item/>
- <item/>
- …類似的一百萬(wàn)行…
- <item/>
- <itel/>
- <item/>
- <item/>
- …再省略一百萬(wàn)行…
- <item/>
看到哪里不同了嘛?我都等不及下一次日冕物質(zhì)拋射活動(dòng)來(lái)讓我們都變成更厲害的程序員啦(譯者注:這個(gè)作者只是在這里發(fā)泄怨氣…)。
第四,不要相信你的代碼,更不要相信你自己的數(shù)據(jù)處理能力。
想讓你的數(shù)據(jù)出錯(cuò),方法超多的。即使你只有1%的數(shù)據(jù)出錯(cuò),你的A/B測(cè)試結(jié)果可能也完全不對(duì)。比如,有些著名網(wǎng)絡(luò)數(shù)據(jù)集里的某些圖片就是無(wú)法被某些圖像解析器讀取。如果你使用另一個(gè)解析器,或者你將這些圖片計(jì)入分母,最后的結(jié)果都會(huì)與別人不同。很長(zhǎng)一段時(shí)間內(nèi),我都在評(píng)估結(jié)果內(nèi)重復(fù)計(jì)入了某些測(cè)試圖像,因此得到了壓根不正確卻看似很可信的數(shù)字結(jié)果。
第五,盡量故意擾亂你的實(shí)驗(yàn)。
把標(biāo)簽打亂,計(jì)算概率層面精確度。在1%的數(shù)據(jù)上進(jìn)行訓(xùn)練,確保你過度擬合。更好的方法是:把你的模型交給別人,讓他們自己上手使用。每個(gè)實(shí)驗(yàn)室都有這么一個(gè)永遠(yuǎn)能第一時(shí)間掛掉你完美代碼的人。盯住他們就對(duì)啦!
這種對(duì)結(jié)果的有益的懷疑論可能是我在博士與非博士之間發(fā)現(xiàn)的品質(zhì)上的最大區(qū)別。我們博士都經(jīng)受過這樣的打擊。回想起來(lái),我很幸運(yùn)能夠以這么一種尷尬又沒有很不合適的方式在職業(yè)生涯早期收到驚訝,以確保我永遠(yuǎn)都小心翼翼地進(jìn)行研究。必須說(shuō)不幸的是,數(shù)據(jù)科學(xué)界從來(lái)沒有“幸福小事故”這種事情(西方公眾名人Bob Ross名言:世上沒有“錯(cuò)誤”一說(shuō),它們只是“幸福小事故”)。
相關(guān)報(bào)道:https://medium.com/s/story/no-happy-little-accidents-8663540763f8
【本文是51CTO專欄機(jī)構(gòu)大數(shù)據(jù)文摘的原創(chuàng)譯文,微信公眾號(hào)“大數(shù)據(jù)文摘( id: BigDataDigest)”】