這是本系列博客的第三篇,也是最后一篇。這個(gè)系列之前的博客比較了兩個(gè)主要的開源自然語(yǔ)言處理軟件庫(kù):John Snow Labs的Apache Spark-NLP和Explosion AI的spaCy。在前兩篇中,我?guī)еx者一起過了一下訓(xùn)練分詞和POS模型的代碼,然后在一個(gè)基準(zhǔn)數(shù)據(jù)集上運(yùn)行了這些代碼,并評(píng)估了一下結(jié)果。在這一篇中,我會(huì)比較這兩個(gè)庫(kù)在其他基準(zhǔn)測(cè)試上的準(zhǔn)確性和性能,同時(shí)也會(huì)給出這兩個(gè)庫(kù)在哪些應(yīng)用場(chǎng)景里比較適合的建議。
準(zhǔn)確性
以下是本系列的第一篇中訓(xùn)練的模型的準(zhǔn)確性比較。

圖1 模型的準(zhǔn)確性比較。圖片由Saif Addin Ellafi提供
spaCy的預(yù)先訓(xùn)練模型在預(yù)測(cè)英語(yǔ)文本中的詞性標(biāo)記(POS)方面做得很好。如果你的文本是標(biāo)準(zhǔn)的、基于新聞或文章的文本(例如,不是像法律文件、財(cái)務(wù)報(bào)告或醫(yī)療記錄這樣的專業(yè)領(lǐng)域的文本),并且是spaCy支持的七種語(yǔ)言之一寫成的,用spaCy的預(yù)先訓(xùn)練的模式是一個(gè)很好的方法。需要注意的是,我的預(yù)先訓(xùn)練的模型里包括我自定義的分詞器,否則精度(特別是分詞的匹配率)將下降(參見圖2)。
spaCy自帶的預(yù)訓(xùn)練模型和Spark-NLP在使用相同訓(xùn)練數(shù)據(jù)時(shí)的表現(xiàn)相似,準(zhǔn)確率都在84%左右。
對(duì)spaCy的準(zhǔn)確性的主要影響似乎不是來自于訓(xùn)練數(shù)據(jù),而是來自于其英語(yǔ)vocab的內(nèi)容。Spark-NLP對(duì)語(yǔ)言沒有任何的依賴(它是完全語(yǔ)言不可知的),而且只從管道里的標(biāo)注器中學(xué)習(xí)。這意味著相同的代碼和算法,在訓(xùn)練另外一種語(yǔ)言的數(shù)據(jù)時(shí),不用改變。

圖2 分詞的準(zhǔn)確性比較。圖片由Saif Addin Ellafi提供
我們?cè)谶@里看到,對(duì)spaCy分詞器的修改對(duì)匹配目標(biāo)ANC語(yǔ)料庫(kù)的分詞造成了重要的影響。使用“開箱即用”的spaCy將會(huì)有比較差的結(jié)果。這在自然語(yǔ)言理解中非常常見,必須訓(xùn)練特定領(lǐng)域的模型才能學(xué)習(xí)輸入文本里的細(xì)微差別、上下文、專業(yè)俚語(yǔ)和語(yǔ)法。
性能
訓(xùn)練并預(yù)測(cè)大約77KB的txt文件(對(duì)21000個(gè)單詞進(jìn)行預(yù)測(cè)和比較)時(shí),一切看起來都挺好的。但當(dāng)我們訓(xùn)練的文件數(shù)量增加到原來的兩倍,預(yù)測(cè)9225個(gè)文件而不是14個(gè)文件時(shí),事情看起來就不那么好了。當(dāng)然,從任何維度來看,這都不是“大數(shù)據(jù)”,但卻比玩一玩或調(diào)試更貼近現(xiàn)實(shí)場(chǎng)景。下面是結(jié)果。
Spark-NLP 75mb prediction
Time to train: 4.798381899 seconds
Time to predict + collect: 311.773622473 seconds
Total words: 13,441,891
用spaCy進(jìn)行訓(xùn)練有點(diǎn)麻煩,因?yàn)橛?xùn)練數(shù)據(jù)里有一些奇怪的字符和文本格式的問題,我已經(jīng)在之前的訓(xùn)練算法中進(jìn)行了清理。但在使用了這些規(guī)避方法后,訓(xùn)練的時(shí)間出現(xiàn)了指數(shù)級(jí)的增加,所以我只能估計(jì)可能需要的時(shí)間?;跀U(kuò)展后的訓(xùn)練文件夾中的文件的數(shù)量,訓(xùn)練時(shí)間大約是兩小時(shí)或更多。
SpaCy 75mb prediction
Time to train: 386.05810475349426 seconds
Time to predict + collect: 498.60224294662476 seconds
Total words: 14,340,283

圖3 訓(xùn)練的可擴(kuò)展性。圖片由Saif Addin Ellafi提供
圖3顯示了在這個(gè)75MB的基準(zhǔn)上的結(jié)果:
- 相比spaCy,Spark-NLP在100 KB數(shù)據(jù)上的訓(xùn)練速度快38倍,在2.6 MB的數(shù)據(jù)上的速度快80倍??蓴U(kuò)展性上的區(qū)別是顯著的。
- 當(dāng)數(shù)據(jù)從100 KB增加到2.6 MB 時(shí),Spark-NLP的訓(xùn)練時(shí)間沒有顯著地增長(zhǎng)。
- spaCy的訓(xùn)練時(shí)間在數(shù)據(jù)量變大的時(shí)候呈指數(shù)增長(zhǎng)。
圖4顯示了運(yùn)行Spark-NLP管道時(shí)(即在訓(xùn)練階段結(jié)束后使用模型進(jìn)行預(yù)測(cè))的性能比較。spaCy在小數(shù)據(jù)集上是很快,但是它不像Spark-NLP那樣擴(kuò)展性良好。對(duì)于這些基準(zhǔn)測(cè)試:
- spaCy在140 KB數(shù)據(jù)集上更快(兩個(gè)庫(kù)都在不到1秒內(nèi)完成)。
- 在15 MB數(shù)據(jù)集上,Spark-NLP快1.4倍 (約40秒對(duì)70秒)
- 在75 MB數(shù)據(jù)集上,Spark-NLP快1.6倍,用了大約spaCy一半的時(shí)間完成(大概5分鐘對(duì)9分鐘)
spaCy針對(duì)單機(jī)運(yùn)行進(jìn)行了高度優(yōu)化。它用Cython從零開始編寫,并在2015年(Spark-NLP出現(xiàn)之前兩年)就被證明比用Python、Java和C++編寫的其他庫(kù)具有最快的語(yǔ)法解析器。spaCy沒有像Spark-NLP那樣的JVM和Spark開銷,這使得spaCy在小數(shù)據(jù)集上具有優(yōu)勢(shì)。
另一方面,Spark多年來所做的大量?jī)?yōu)化(尤其是對(duì)于單機(jī)、standalone的模式)在這里發(fā)揮了重要作用,即使數(shù)據(jù)集只有幾兆字節(jié)。自然,隨著數(shù)據(jù)量的增長(zhǎng)或管道復(fù)雜性(例如,更多自然的語(yǔ)言處理階段,加入機(jī)器學(xué)習(xí)或深度學(xué)習(xí)的階段等)的增加,這種優(yōu)勢(shì)會(huì)更加明顯。

圖4 運(yùn)行時(shí)性能的比較。圖片由Saif Addin Ellafi提供
可擴(kuò)展性
在這些基準(zhǔn)之外,Spark按自身的方式進(jìn)行擴(kuò)展??蓴U(kuò)展性的好壞取決于如何劃分?jǐn)?shù)據(jù),是否有寬表或高表(后者在Spark中更好),最重要的是,是否使用集群。在這里,所有的數(shù)據(jù)和代碼都在本地機(jī)器上。我對(duì)文件名運(yùn)行了groupBy操作,這意味著我的表的寬比高要大,因?yàn)閷?duì)于每個(gè)文件名都有大量的單詞。如果可以,我可能還會(huì)避免調(diào)用collect()操作,這會(huì)嚴(yán)重影響我的driver程序內(nèi)存,不如將結(jié)果存儲(chǔ)在分布式存儲(chǔ)中。
transform()操作后的groupBy操作是在預(yù)測(cè)之后進(jìn)行POS和分詞的合并。它變換一個(gè)比前一個(gè)表高得多的表(960302行,而不是表示文件的數(shù)量的9225行)。我還可以控制是否將CPU內(nèi)核過度分配給Spark(例如,local[6])以及向轉(zhuǎn)換操作中注入的分區(qū)數(shù)量。在調(diào)試Spark性能時(shí),性能通常呈現(xiàn)出正態(tài)分布。在我的例子中,最優(yōu)的情況大概是分配6個(gè)核和指定24個(gè)分區(qū)。
在spaCy方面,我在前幾段中使用的并行算法并沒有顯著地影響性能,而只是讓總的預(yù)測(cè)時(shí)間少了幾秒鐘。

圖5 并行算法的影響不顯著。圖片由Saif Addin Ellafi提供
使用一個(gè)Amazon EMR集群,對(duì)相同算法進(jìn)行簡(jiǎn)單的比較。相對(duì)單一節(jié)點(diǎn),使用一個(gè)分布式y(tǒng)arn管理的集群,POS預(yù)測(cè)的速度提升了2.5倍。集群中的數(shù)據(jù)集被放在HDFS中。在實(shí)際情景里,這意味著僅僅依靠調(diào)整配置和線性擴(kuò)展即可以實(shí)現(xiàn)不同的成本/性能權(quán)衡。這是Spark、Spark ML和Spark-NLP的核心優(yōu)勢(shì)。

圖6 使用亞馬遜EMR集群的比較。圖片由Saif Addin Ellafi提供
結(jié)論
這兩個(gè)庫(kù)的應(yīng)用場(chǎng)景是非常不同的。如果只是使用一個(gè)小數(shù)據(jù)集并想快速獲得輸出,那么spaCy是贏家。可以下載它的某個(gè)自然語(yǔ)言的模型,處理數(shù)據(jù),并將其逐行傳遞給NLP對(duì)象。spaCy包含了大量關(guān)于自然語(yǔ)言的策略詞匯集,以及一系列經(jīng)過訓(xùn)練的非常先進(jìn)的模型。這些模型擁有用C++ (Cython) 高度優(yōu)化的性能。如果想要并行化任務(wù),可以定制一個(gè)組件(就像我們?yōu)榉衷~器所做的那樣),或者為特定領(lǐng)域的數(shù)據(jù)訓(xùn)練一個(gè)模型,接著利用spaCy的API來編寫更多的代碼。
另一方面,如果你有一個(gè)很大的任務(wù),那么Spark-NLP就會(huì)非??臁2⑶覐囊欢ǖ囊?guī)模開始,它是唯一的選擇。當(dāng)使用更大的數(shù)據(jù)集或擴(kuò)展Spark集群時(shí),它會(huì)自動(dòng)擴(kuò)展。對(duì)于訓(xùn)練NLP模型來說,它的速度比spaCy快1到2個(gè)數(shù)量級(jí),同時(shí)能保證同樣的準(zhǔn)確度。
spaCy為各種常見的NLP任務(wù)提供了一組超級(jí)優(yōu)化的模型。Spark-NLP沒有(在撰寫本文時(shí))預(yù)先訓(xùn)練好的模型。spaCy的模型是“黑盒子”,如果你自己的文本數(shù)據(jù)和模型的訓(xùn)練內(nèi)容相似的話,結(jié)果表現(xiàn)通常會(huì)在頂尖的1%以內(nèi)。當(dāng)使用Spark-NLP訓(xùn)練特定領(lǐng)域的模型時(shí),管道是語(yǔ)言不可知的,最終的結(jié)果嚴(yán)格地說是各部分的總和。每個(gè)注釋器都根據(jù)被提供的知識(shí)進(jìn)行工作,每個(gè)注釋器都將與其他注釋器進(jìn)行通信,以實(shí)現(xiàn)最終的結(jié)果。你可以加入一個(gè)拼寫檢查器、一個(gè)句子檢測(cè)器或一個(gè)正歸化器,并產(chǎn)生結(jié)果,而不必編寫額外的代碼或自定義腳本。
我們希望你喜歡對(duì)這兩個(gè)庫(kù)的概述,它將幫助你更快更好地交付下一個(gè)NLP項(xiàng)目。如果你有興趣學(xué)習(xí)更多的話,可以在查看2018年3月的Strata數(shù)據(jù)圣何塞大會(huì)和5月的Strata數(shù)據(jù)倫敦大會(huì)上進(jìn)行的為期半天的“使用spaCy和Spark ML進(jìn)行大規(guī)模自然語(yǔ)言理解”的課程。
相關(guān)資料:
Saif Addin Ellafi
Saif Addin Ellafi是一名軟件開發(fā)者、分析師、數(shù)據(jù)科學(xué)家,并永遠(yuǎn)是一名學(xué)生。他同時(shí)還是一名極限運(yùn)動(dòng)和游戲愛好者。他在銀行和金融行業(yè)的數(shù)據(jù)領(lǐng)域擁有豐富的解決問題和測(cè)試的經(jīng)驗(yàn)?,F(xiàn)在他在John Snow Labs,并是Spark-NLP的主要貢獻(xiàn)者。

