天然語言處理 (Natural Language Processing,NLP)是一門融合了計算機科學、人工智能以及語言學的交叉學科,它們的關係如圖 1-1 所示。這門學科研究的是如何經過機器學習等技術,讓計算機學會處理人類語言,乃至實現終極目標——理解人類語言或人工智能①。html
事實上,天然語言處理這個術語並無被普遍接受的定義②。注重語言學結構的學者喜歡使用 計算語言學 (Computational Linguistics,CL)這個表達,而強調最終目的的學者則更偏好 天然語言理解 (Natural Language Understanding,NLU)這個術語。因爲 NLP 聽上去含有更多工程意味,因此本書將一直使用該術語,而不去細究它們的異同。java
如同其自己的複雜性同樣,天然語言處理一直是一個艱深的課題。雖然語言只是人工智能的一部分(人工智能還包括計算機視覺等),但它很是獨特。這個星球上有許多生物擁有超過人類的視覺系統,但只有人類才擁有這麼高級的語言。天然語言處理的目標是讓計算機處理或 「理解」天然語言,以完成有意義的任務,好比訂機票、購物或同聲傳譯等。徹底理解和表達語言是極其困難的,完美的語言理解等價於實現人工智能。python
在這一章中,咱們將圍繞天然語言處理的縮略圖,瞭解一些基本概念。git
① 著名的圖靈測試就是根據機器是否能像人類同樣理解語言來判斷它是否具有人工智能。
② Smith N. A. Linguistic structure prediction[J]. Synthesis lectures on human language technologies, 2011, 4(2): 1-274.複製代碼
做爲咱們將要處理的對象,天然語言具有高度靈活的特色。咱們太熟悉本身的語言,就像水對魚來說是透明的同樣,咱們很難體會到語言的複雜程度。不如拿天然語言與人工語言作一番比較,看看計算機理解咱們的語言是多麼困難。程序員
天然語言中的詞彙比編程語言中的關鍵詞豐富。在咱們熟悉的編程語言中,能使用的關鍵詞數量是有限且肯定的。好比,C 語言一共有 32 個關鍵字,Java 語言則有 50 個。雖然咱們能夠自由地取變量名、函數名和類名,但這些名稱在編譯器看來只是區別符號,不含語義信息,也不影響程序的運行結果。但在天然語言中,咱們能夠使用的詞彙量是無窮無盡的,幾乎沒有意義徹底相同的詞語。以漢語爲例,由國家語言文字工做委員會發布的《現代漢語經常使用詞表(草案)》一共收錄了 56 008 個詞條。除此以外,咱們還能夠隨時創造各類類型的新詞,而不只限於名詞。github
天然語言是非結構化的,而編程語言是結構化的。所謂結構化,指的是信息具備明確的結構關係,好比編程語言中的類與成員、數據庫中的表與字段,均可以經過明確的機制來讀寫。舉個例子,咱們來看看兩種語言對同一事實的表述,一些面向對象的編程語言能夠如此書寫:正則表達式
算法
class Company(object): def __init__(self, founder, logo) -> None: self.founder = founder self.logo = logo 複製代碼apple = Company(founder='喬布斯', logo='apple')複製代碼
因而,程序員能夠經過 apple.founder和 apple.logo來獲取蘋果公司的創始人和標誌。像這樣,程序語言經過 class Company這個結構爲信息提供了層次化的模板,而在天然語言中則不存在這樣的顯式結構。人類語言是線性的字符串,給定一句話「蘋果的創始人是喬布斯,它的 logo 是蘋果」,計算機須要分析出以下結論:數據庫
●這句漢語轉換爲單詞序列後,應該是「蘋果 的 創始人 是 喬布斯 , 它 的 logo 是 蘋果」;express
●第一個「蘋果」指的是蘋果公司,而第二個「蘋果」指的是帶缺口的蘋果 logo ;
● 「喬布斯」是一我的名;
● 「它」指代的是蘋果公司;
●蘋果公司與喬布斯之間的關係是「的創始人是」,與帶缺口的蘋果 logo 之間的關係爲「的logo 是」。
這些結論的得出分別涉及中文分詞、命名實體識別、指代消解和關係抽取等天然語言處理任務。這些任務目前的準確率都達不到人類水平。可見,人類以爲很簡單的一句話,要讓計算機理解起來並不簡單。
天然語言含有大量歧義,這些歧義根據語境的不一樣而表現爲特定的義項。好比漢語中的多義詞,只有在特定的上下文中才能肯定其含義,甚至存在故意利用沒法肯定的歧義營造幽默效果的用法。除了上文「蘋果」的兩種意思以外,「意思」這個詞也有多種意義。好比,下面這則經典的笑話。
他說:「她這我的真有意思(funny)。」她說:「他這我的怪有意思的(funny)。」因而人們覺得他們有了意思(wish),並讓他向她意思意思(express)。他火了:「我根本沒有那個意思(thought)!」她也生氣了:「大家這麼說是什麼意思(intention)?」過後有人說:「真有意思(funny)。」也有人說:「真沒意思(nonsense)。」(原文見《生活報》1994.11.13. 第六版)[吳尉天,1999]①
這個例子中特意用英文註解「意思」的不一樣義項,從側面體現了處理中文比處理英文更難。
但在編程語言中,則不存在歧義性②。若是程序員無心中寫了有歧義的代碼,好比兩個函數的簽名同樣,則會觸發編譯錯誤。
書刊中的語言即便通過編輯的屢次校對,也仍然沒法徹底避免錯誤。而互聯網上的文本則更加隨性,錯別字或病句、不規範的標點符號等隨處可見。不過,哪怕一句話錯得再離譜,人們仍是能夠猜出它想表達的意思。而在編程語言中,程序員必須保證拼寫絕對正確、語法絕對規範,不然要麼獲得編譯器無情的警告,要麼形成潛在的 bug。
事實上,區別於規範的新聞領域,如何處理不規範的社交媒體文本也成爲了一個新的課題。
① 摘自宗成慶《統計天然語言處理》。
② 編程語言被特地設計爲無歧義的肯定上下文無關文法,而且能在 O(n) 時間內分析完畢,其中 n 爲文本長度。複製代碼
任何語言都是不斷髮展變化的,不一樣的是,編程語言的變化要緩慢溫和得多,而天然語言則相對迅速嘈雜一些。
編程語言由某個我的或組織發明而且負責維護。以 C++ 爲例,它的發明者是 Bjarne Stroustrup,它如今由 C++ 標準委員會維護。從 C++ 98 到 C++ 03,再到 C++ 11 和 C++ 14,語言標準的變化是以年爲單位的遷越過程,且新版本大體作到了對舊版本的前向兼容,只有少數廢棄掉的特性。
而天然語言不是由某個我的或組織發明或制定標準的。或者說,任何一門天然語言都是由全人類共同約定俗成的。雖然存在普通話、簡體字等規範,但咱們每一個人均可以自由創造和傳播新詞彙和新用法,也在不停地賦予舊詞彙以新含義,致使古代漢語和現代漢語相差巨大。此外,漢語不斷吸取英語和日語等外語中的詞彙,而且也在輸出 niubility 等中式英語。這些變化是連續的,每時每刻都在進行,給天然語言處理帶來了不小的挑戰。這也是天然語言明明是人類發明的,卻還要稱做「天然」的緣由。
因爲說話速度和聽話速度、書寫速度和閱讀速度的限制,人類語言每每簡潔、幹練。咱們常常省略大量背景知識或常識,好比咱們會對朋友說「老地方見」,而沒必要指出「老地方」在哪裏。對於機構名稱,咱們常用簡稱,好比「工行」「地稅局」,假定對方熟悉該簡稱。若是上文提出一個對象做爲話題,則下文常用代詞。在連續的新聞報道或者一本書的某一頁中,並不須要重複前面的事實,而假定讀者已經熟知。這些省略掉的常識,是交流雙方共有而計算機不必定擁有的,這也給天然語言處理帶來了障礙。
按照處理對象的顆粒度,天然語言處理大體能夠分爲圖 1-2 所示的幾個層次。
本節逐一介紹這些天然語言處理任務的定義,爲讀者提供一個概覽。
天然語言處理系統的輸入源一共有 3 個,即語音、圖像與文本。其中,語音和圖像雖然正引發愈來愈大的關注,但受制於存儲容量和傳輸速度,它們的信息總量仍是沒有文本多。另外,這兩種形式通常通過識別後轉化爲文本,再進行接下來的處理,分別稱爲語音識別(Speech Recognition)和光學字符識別(Optical Character Recognition)。一旦轉化爲文本,就能夠進行後續的 NLP 任務。因此,文本處理是重中之重。
這 3 個任務都是圍繞詞語進行的分析,因此統稱詞法分析。詞法分析的主要任務是將文本分隔爲有意義的詞語(中文分詞),肯定每一個詞語的類別和淺層的歧義消除(詞性標註),而且識別出一些較長的專有名詞(命名實體識別)。對中文而言,詞法分析經常是後續高級任務的基礎。在流水線式① 的系統中,若是詞法分析出錯,則會波及後續任務。所幸的是,中文詞法分析已經比較成熟,基本達到了工業使用的水準。
① 指的是前一個系統的輸出是後一個系統的輸入,而且前一個系統不依賴於後續系統。複製代碼
做爲一個初級且資源豐富的任務,詞法分析將在本書後續章節中詳細闡述。另外,因爲這是讀者接觸的第一個 NLP 任務,它將引出許多有趣的模型、算法和思想。所以,詞法分析不只是天然語言處理的基礎任務,它所屬的章節也會成爲讀者知識體系的基礎。
詞法分析以後,文本已經呈現出部分結構化的趨勢。至少,計算機看到的再也不是一個超長的字符串,而是有意義的單詞列表,而且每一個單詞還附有本身的詞性以及其餘標籤。
根據這些單詞與標籤,咱們能夠抽取出一部分有用的信息,從簡單的高頻詞到高級算法提取出的關鍵詞,從公司名稱到專業術語,其中詞語級別的信息已經能夠抽取很多。咱們還能夠根據詞語之間的統計學信息抽取出關鍵短語乃至句子,更大顆粒度的文本對用戶更加友好。
值得一提的是,一些信息抽取算法用到的統計量能夠複用到其餘任務中,會在相應章節中詳細介紹。
將文本拆分爲一系列詞語以後,咱們還能夠在文章級別作一系列分析。
有時咱們想知道一段話是褒義仍是貶義的,判斷一封郵件是不是垃圾郵件,想把許多文檔分門別類地整理一下,此時的 NLP 任務稱做文本分類。
另外一些時候,咱們只想把類似的文本歸檔到一塊兒,或者排除重複的文檔,而不關心具體類別,此時進行的任務稱做文本聚類。
這兩類任務看上去挺類似,實際上分屬兩種大相徑庭的算法流派,咱們會在單獨的章節中分別講解。
詞法分析只能獲得零散的詞彙信息,計算機不知道詞語之間的關係。在一些問答系統中,須要獲得句子的主謂賓結構。好比「查詢劉醫生主治的內科病人」這句話,用戶真正想要查詢的不是「劉醫生」,也不是「內科」,而是「病人」。雖然這三個詞語都是名詞,甚至「劉醫生」 離表示意圖的動詞「查詢」最近,但只有「病人」纔是「查詢」的賓語。經過句法分析,能夠獲得如圖 1-3 所示的語法信息。
咱們發現圖 1-3 中果真有根長長的箭頭將「查詢」與「病人」聯繫起來,而且註明了它們之間的動賓關係。後續章節會詳細介紹上面這種樹形結構,以及句法分析器的實現方法。
不只是問答系統或搜索引擎,句法分析還常常應用於基於短語的機器翻譯,給譯文的詞語從新排序。好比,中文「我吃蘋果」翻譯爲日文後則是「私は(我)林檎を(蘋果)食べる(吃)」,二者詞序不一樣,但句法結構一致。
相較於句法分析,語義分析側重語義而非語法。它包括詞義消歧(肯定一個詞在語境中的含義,而不是簡單的詞性)、語義角色標註(標註句子中的謂語與其餘成分的關係)乃至語義依存分析(分析句子中詞語之間的語義關係)。
隨着任務的遞進,它們的難度也逐步上升,屬於較爲高級的課題。即使是最前沿的研究,也還沒有達到可以實用的精確程度。另外,相應的研究資源比較稀缺,大衆難以獲取,因此本書不會涉及。
除了上述「工具類」的任務外,還有許多綜合性的任務,與終端應用級產品聯繫更緊密。好比:
● 自動問答,根據知識庫或文本中的信息直接回答一個問題,好比微軟的Cortana和蘋果的Siri;
● 自動摘要,爲一篇長文檔生成簡短的摘要;
● 機器翻譯,將一句話從一種語言翻譯到另外一種語言。
注意,通常認爲信息檢索(Information Retrieve,IR)是區別於天然語言處理的獨立學科。雖然二者具備密切的聯繫,但 IR 的目標是查詢信息,而 NLP 的目標是理解語言。此外,IR 檢索的未必是語言,還能夠是以圖搜圖、聽曲搜曲、商品搜索乃至任何信息的搜索。現實中還存在大量不須要理解語言便可完成檢索任務的場景,好比 SQL 中的 LIKE。
本書做爲入門讀物,不會討論這些高級任務,但瞭解天然語言處理的整個宏觀圖景有助於咱們開拓視野,找準定位與方向。
上一節比較了天然語言與人工語言的異同,展現了天然語言處理的困難所在,介紹了一些常見的 NLP 任務。這一節簡要介紹進行天然語言處理的幾種不一樣手法。
規則,指的是由專家手工制定的肯定性流程。小到程序員平常使用的正則表達式,大到飛機的自動駕駛儀①,都是固定的規則系統。
在天然語言處理的語境下,比較成功的案例有波特詞幹算法(Porter stemming algorithm),它由馬丁•波特在 1980 年提出,普遍用於英文詞幹提取。該算法由多條規則構成,每一個規則都是一系列固定的 if then條件分支。當詞語知足條件則執行固定的工序,輸出固定的結果。摘錄其中一部分規則爲例,收錄於表 1-1 中。
專家系統要求設計者對所處理的問題具有深刻的理解,而且儘可能以人力全面考慮全部可能的狀況。它最大的弱點是難以拓展。當規則數量增長或者多個專家維護同一個系統時,就容易出現衝突。好比表 1-1 這個僅有 3 條規則的簡單系統,規則 1 和規則 2 其實有衝突,相似 feed這樣的單詞會同時知足這兩個規則的條件,從而引發矛盾。此時,專家系統一般依靠規則的優先級來解決。好比定義規則 1 優先於規則 2,當知足規則 1 的條件時,則忽略其餘規則。幾十條規則尚可接受,隨着規則數量與團隊人數的增長,須要考慮的兼容問題也愈來愈多、愈來愈複雜,系統維護成本也愈來愈高,沒法拓展。
大多數語言現象比英文詞幹複雜得多,咱們已經在上文了解了很多。這些語言現象沒有必然遵循的規則,也在時刻變化,使得規則系統顯得僵硬、死板與不穩定。
① 區別於汽車的無人駕駛技術,飛機的自動駕駛系統只能處理預約狀況,在異常狀況下會報警或切換到手動駕駛。
② 下面的例子中,feed 爲特殊狀況,不是過去式,不執行替換。bled 是 bleed 的過去式,不該執行「去 ed」。sing 不是如今進行時,不該執行「去 ing」。複製代碼
爲了下降對專家的依賴,自適應靈活的語言問題,人們使用統計方法讓計算機自動學習語言。所謂「統計」,指的是在語料庫上進行的統計。所謂語料庫,指的是人工標註的結構化文本,咱們會在接下來的小節中詳細闡述。
因爲天然語言靈活多變,即使是語言學專家,也沒法總結出完整的規則。哪怕真的存在完美的規則集,也難以隨着語言的不停發展而逐步升級。因爲沒法用程序語言描述天然語言,因此聰明的人們決定以舉例子的方式讓機器自動學習這些規律。而後機器將這些規律應用到新的、未知的例子上去。在天然語言處理的語境下,「舉例子」就是「製做語料庫」。
統計學習方法實際上是機器學習的別稱,而機器學習則是當代實現人工智能的主流途徑。機器學習在天然語言處理中的重要性很是之大,能夠說天然語言處理只是機器學習的一種應用。此處咱們僅僅用「舉例學習」來簡單理解,後續章節將濃墨重彩地系統學習。
既然天然語言處理是機器學習的應用層,那麼如同人工智能的歷史同樣,天然語言處理也經歷了從邏輯規則到統計模型的發展之路。圖 1-4 列出了歷史上幾個重要的時間段。
20 世紀 50 年代是人工智能與天然語言處理的萌芽期,出現了許多奠定性的工做。其中最具表明性的是數學家阿蘭•圖靈在論文 Computing Machinery and Intelligence 提出的人工智能的充分條件——圖靈測試,以及語言學家喬姆斯基的《句法結構》——認爲句子是按某種與語境無關的廣泛語法規則生成的。有趣的是,先驅們的早期估計或理論都過於樂觀。圖靈曾預言在2014 年一臺 1 GB 內存的計算機就能以 70% 的機率在 5 分鐘內不被識破機器的身份,然而這個樂觀的預言截至今日也沒有實現。而喬姆斯基的「廣泛語法」則由於對語義的忽視而備受爭議,並在後續理論中作了相應修正。不管是人工智能仍是天然語言處理,都是任重道遠的課題。
20 世紀 80 年代以前的主流方法都是規則系統,由專家手工編寫領域相關的規則集。那時候計算機和計算機語言剛剛發明,從事編程的都是精英學者。他們雄心勃勃,認爲只要經過編程就能賦予計算機智能。表明性工做有 MIT AI 實驗室的 BASEBALL 以及 Sun 公司(2009 年被甲骨文公司收購)的 LUNAR,分別專門回答北美棒球賽事的問題和阿波羅探月帶回來的岩石樣本問題。這一時期還有不少相似的問答系統,都是主要依賴手寫規則的專家系統。以BASEBALL 爲例,其中的詞性標註模塊是這樣判斷 score 的詞性的:「若是句子中不含其餘動詞,則 score 是一個動詞,不然是名詞。」接着該系統依靠詞性上的規則合併名詞短語、介詞短語以及副詞短語。語法模塊則根據「若最後一個動詞是主要動詞並位於 to be 以後」之類的規則判斷被動句、主語和謂語。而後該系統利用詞典上的規則來將這些信息轉化爲「屬性名 = 屬性值」或「屬性名 = ?」的鍵值對,用來表示知識庫中的文檔以及問句。最後利用相似「若除了問號以外全部屬性名都匹配,則輸出該文檔中問句所求的屬性」的規則匹配問句與答案。如此僵硬嚴格的規則致使該系統只能處理固定的問句,沒法處理與或非邏輯、比較級與時間段。因而,這些規則系統被稱爲「玩具」。爲了方便表述這樣的規則邏輯,1972 年人們還特地發明了 Prolog(Programming in Logic)語言來構建知識庫以及專家系統。
20 世紀 80 年代以後,統計模型給人工智能和天然語言處理領域帶來了革命性的進展——人們開始標註語料庫用於開發和測試 NLP 模塊:1988 年隱馬爾可夫模型被用於詞性標註,1990年 IBM 公佈了第一個統計機器翻譯系統,1995 年出現第一個健壯的句法分析器(基於統計)。爲了追求更高的準確率,人們繼續標註更大的語料庫(TREC 問答語料庫、CoNLL 命名實體識別、語義角色標註與依存句法語料庫)。而更大的語料庫與硬件的發展又吸引人們應用更復雜的模型。到了 2000 年,大量機器學習模型被普遍使用,好比感知機和條件隨機場。人們再也不依賴死板的規則系統,而是指望機器自動學習語言規律。要提升系統的準確率,要麼換用更高級的模型,要麼多標註一些語料。今後 NLP 系統能夠健壯地拓展,而再也不依賴專家們手寫的規則。但專家們依然有用武之地,根據語言學知識爲統計模型設計特徵模板(將語料表示爲方便計算機理解的形式)成爲立竿見影的方法,這道工序被稱爲「特徵工程」。2010 年基於 SVM 的Turbo 依存句法分析器在英語賓州樹庫(Penn Treebank)上取得了 92.3% 的準確率①,是當時最早進的系統。本書將着重介紹一些實用的統計模型及實現,它們並不是遙不可及的技術,徹底能夠實現,且在普通的硬件資源下運行起來。
2010 年以後語料庫規模、硬件計算力都獲得了很大提高,爲神經網絡的復興創造了條件。但隨着標註數據的增長,傳統模型的準確率提高愈來愈不明顯,人們須要更復雜的模型,因而深層的神經網絡從新迴歸研究者的視野。神經網絡依然是統計模型的一種,其理論奠定於 20世紀 50 年代左右。 1951 年,Marvin Lee Minsky 設計了首臺模擬神經網絡的機器。1958 年, Rosenblatt 首次提出可以模擬人類感知能力的神經網絡模型——著名的感知機。1989 年,Yann LeCun 在貝爾實驗室利用美國郵政數據集訓練了首個深度卷積神經網絡,用於識別手寫數字。只不過限於計算力和數據量,神經網絡一直到 2010 年先後才被普遍應用,並被冠以「深度學習」的新術語,以區別於以前的淺層模型。深度學習的魅力在於,它再也不依賴專家制定特徵模板,而可以自動學習原始數據的抽象表示,因此它主要用於表示學習。做爲入門書,咱們僅僅在最後一章介紹一些概念與應用,做爲銜接傳統方法與深度學習的橋樑。
① 準確來說,是斯坦福標準下忽略標點符號的 Unlabeled Attachment Score,將會在第12 章中詳細介紹。複製代碼
純粹的規則系統已經日漸式微,除了一些簡單的任務外,專家系統已經落伍了。20 世紀 70年代,美國工程院院士賈里尼克在 IBM 實驗室開發語音識別系統時,曾經評論道:「我每開除一名語言學家,個人語音識別系統的準確率就提升一點。」① 這句廣爲流傳的快人快語未免有些刻薄,但公正地講,隨着機器學習的日漸成熟,領域專家的做用愈來愈小了。
實際工程中,語言學知識的做用有兩方面:一是幫助咱們設計更簡潔、高效的特徵模板,二是在語料庫建設中發揮做用。事實上,實際運行的系統在預處理和後處理的部分依然會用到一些手寫規則。固然,也存在一些特殊案例更方便用規則特殊處理。
本書尊重工程實踐,以統計爲主、規則爲輔的方式介紹實用型 NLP 系統的搭建。
雖然深度學習在計算機視覺領域取得了耀眼的成績,但在天然語言處理領域中的基礎任務上發力並不大。這個結論或許有點意外,做爲數據科學從業者,用數聽說明問題最合適。表 1-2收錄了《華爾街日報》語料庫上的詞性標註任務的前沿準確率。
① 原話是「Every time I fire a linguist, the performance of the speech recognizer goes up」。
② 「做者姓 ( 年份 )」是一種常見的論文引用格式,可經過該信息(必要時加入主題關鍵詞)搜索到論文。複製代碼
截止 2015 年,除了 Bi-LSTM-CRF 之外,其餘系統都是傳統模型,最高準確率爲 97.36%,而 Bi-LSTM-CRF 深度學習模型爲 97.55%,僅僅提升了 0.19%。2016 年,傳統系統 NLP4J 經過使用額外數據與動態特徵提取算法,準確率能夠達到 97.64%。
相似的情形也在句法分析任務上重演,以斯坦福標準下賓州樹庫的準確率爲例,如表 1-3所示。
2014 年首個神經網絡驅動的句法分析器還不如傳統系統 TurboParser 準確,通過幾年的發展準確率終於達到 95.7%,比傳統算法提升 3.4%。這個成績在學術界是很是顯著的,但在實際使用中並不明顯。
另外一方面,深度學習涉及大量矩陣運算,須要特殊計算硬件(GPU、TPU 等)的加速。目前,一臺入門級塔式服務器的價格在 3000 元左右,一臺虛擬服務器每個月僅需 50 元左右,但僅一塊入門級計算顯卡就須要 5000 元。從性價比來看,反而是傳統的機器學習方法更適合中小企業。
此外,從傳統方法到深度學習的遷移不可能一蹴而就。二者是基礎和進階的關係,許多基礎知識和基本概念用傳統方法講解會更簡單、易懂,它們也會在深度學習中反覆用到(好比 CRF與神經網絡的結合)。不管是傳統模型仍是神經網絡,它們都屬於機器學習的範疇。掌握傳統方法,不只能夠解決計算資源受限時的工程問題,還能夠爲未來挑戰深度學習打下堅實的基礎。
在前面的小節中,咱們邂逅了一些機器學習的術語。按照遞歸學習的思路,如今咱們來遞歸瞭解一下機器學習的基本概念。
本書雖然主要面向天然語言處理,不會專門設立章節詳談機器學習,但仍然會在合適的時候介紹引擎蓋下的機器學習算法。機器學習是天然語言處理的基石,一些基本概念依然須要預先掌握。熟練掌握這些術語,還方便咱們與其餘人流暢交流。
人工智能領域的先驅 Arthur Samuel 在 1959 年給出的機器學習定義是:不直接編程卻能賦予計算機提升能力的方法。
聰明的讀者或許都曾經思考過,計算機是否只能執行人類設計好的步驟?機器學習給了這個問題積極的答覆,機器能夠經過學習提升自身能力,而不須要程序員硬編碼該項能力。美國工程院院士 Tom Mitchell 給過一個更明確的定義,機器學習指的是計算機經過某項任務的經驗數據提升了在該項任務上的能力。
簡而言之,機器學習是讓機器學會算法的算法。這個說法有些繞口,不如拿咱們熟悉的數據庫作類比:數據庫中的「元數據」指的是描述數據的數據(表名、字段等),而其中的一行則是普通數據。類比過來,機器學習算法則能夠稱做「元算法」,它指導機器自動學習出另外一個算法,這個算法被用來解決實際問題。爲了不混淆,人們一般稱被學習的算法爲模型。
模型是對現實問題的數學抽象,由一個假設函數以及一系列參數構成。舉個簡單的例子,咱們要預測中國人名對應的性別。假設中國人名由函數 f x()輸出的符號決定,負數表示女性,非負數表示男性。
咱們選取的 f x()的定義以下:
其中, w 和 b 是函數的參數,而 x 是函數的自變量。那麼,模型指的就是包括參數在內的整個函數。不過模型並不包括具體的自變量 x ,由於自變量是由用戶輸入的。自變量 x 是一個特徵向量,用來表示一個對象的特徵。
讀者能夠將式 (1.1) 理解爲初中的直線方程,也能夠理解爲高中的平面方程,或者高維空間中的超平面方程。總之,沒必要擔憂問題的抽象性,咱們將在第 5 章中用代碼完整地實現這個案例。
特徵指的是事物的特色轉化的數值,好比牛的特徵是 4 條腿、0 雙翅膀,而鳥的特徵是 2條腿、1 雙翅膀。那麼在性別識別問題中,中國人名的特徵是什麼呢?
首先,對於一箇中國人名,姓氏與性別無關,真正起做用的是名字。而計算機不知道哪部分是姓,哪部分是名。姓氏屬於無用的特徵,不該被提取。另外,有一些特殊的字(壯、雁、健、強)是男性經常使用的,而另外一些(麗、燕、冰、雪)則是女性經常使用的,還有一些(文、海、寶、玉)則是男女通用的。讓咱們把人名錶示爲計算機能夠理解的形式,一個名字是否含有這些字就成了最容易想到的特徵。在專家系統中,咱們顯式編程:
若是有人叫「沈雁冰」① 怎麼辦?「雁」聽上去像男性,而「冰」聽上去像女性,而這個名字實際上是男性用的。看來,每一個字與男女的相關程度是不同的,「雁」與男性的相關程度彷佛大於「冰」與女性的相關程度。這個衝突彷佛能夠經過「優先級」解決,不過這種機械的工做交給機器好了。在機器學習中,「優先級」能夠看做特徵權重或模型參數。咱們只須要定義一系列特徵,讓算法根據數據自動決定它們的權重就好了。爲了方便計算機處理,咱們將它們表示爲數值類型的特徵,這個過程稱爲特徵提取。以「沈雁冰」的特徵提取爲例,如表 1-4 所示。
特徵的數量是因問題而定的,2 個特徵顯然不足以推斷名字的性別,咱們能夠增長到 4 個,如表 1-5 所示。
① 做家茅盾原名沈德鴻,字雁冰,以字行於世,所以「沈雁冰」一樣爲人熟知。複製代碼
有時候,咱們還能夠將位置信息也加入特徵中,好比「是否以雪字結尾」。咱們還能夠組合兩個特徵獲得新的特徵,好比「是否以雪字結尾而且倒數第二個字是吹」,這樣就可讓「西門吹雪」這個特殊名字獲得特殊處理,而不至於同「小雪」「陸雪琪」混爲一談。
工程上,咱們並不須要逐個字地寫特徵,而是定義一套模板來提取特徵。好比姓名爲 name的話,則定義特徵模板爲 name[1] + name[2]之類,只要咱們遍歷一些姓名,則 name[1] + name[2]可能組合而成的特徵就基本覆蓋了。這種自動提取特徵的模板稱做特徵模板。
如何挑選特徵,如何設計特徵模板,這稱做特徵工程。特徵越多,參數就越多;參數越多,模型就越複雜。模型的複雜程度應當與數據集匹配,按照遞歸學習的思路,數據集的概念將在下一節中介紹。
如何讓機器自動學習,以獲得模型的參數呢?首先得有一本習題集。有許多問題沒法直接編寫算法(規則)解決(好比人名性別識別,咱們說不清楚什麼樣的名字是男性),因此咱們準備了大量例子(人名 x 及其對應的性別 y)做爲習題集,但願機器自動從習題集中學習中國人名的規律。其中,「例子」通常稱做樣本。
這本習題集在機器學習領域稱做數據集,在天然語言處理領域稱做語料庫,會在 1.5 節詳細介紹。數據集的種類很是多,根據任務的不一樣而不一樣。表 1-6 收錄了一些經常使用的數據集。
在使用數據集時,咱們不光要考慮它的規模、標註質量,還必須考慮它的受權。大部分數據集都不可商用,許多冷門領域的數據集也比較匱乏,此時咱們能夠考慮自行標註。
若是這本習題集附帶標準答案 y ,則此時的學習算法稱做監督學習。監督學習算法讓機器先作一遍題,而後與標準答案做比較,最後根據偏差糾正模型的錯誤。大多數狀況下,學習一遍偏差還不夠小,須要反覆學習、反覆調整。此時的算法是一種迭代式的算法,每一遍學習都稱做一次迭代。監督學習在日語中被稱做「教師あり學習」,意思是「有老師的學習」。經過提供標準答案,人類指出了模型的錯誤,充當了老師的角色。
這種在有標籤的數據集上迭代學習的過程稱爲訓練,訓練用到的數據集稱做訓練集。訓練的結果是一系列參數(特徵權重)或模型。利用模型,咱們能夠爲任意一個姓名計算一個值,若是非負則給出男性的結論,不然給出女性的結論。這個過程稱爲預測。
總結一下,監督學習的流程如圖 1-5 所示。
在性別識別的例子中:
● 非結構化數據是許多個相似「沈雁冰」「丁玲」的人名;
● 通過人工標註後獲得含有許多個相似「沈雁冰=男」「丁玲=女」樣本的標註數據集;
● 而後經過訓練算法獲得一個模型;
● 最後利用這個模型,咱們能夠預測任何名字(如「陸雪琪」)的性別。
待預測的名字不必定出如今數據集中,但只要樣本數量充足且男女均衡、特徵模板設計得當、算法實現正確,咱們依然能夠預期一個較高的準確率。
另外,圖 1-5 中的標註數據其實也是結構化數據。但因爲它含有人工標註的成本,有時被稱做「黃金數據」(gold data),與模型預測的、有必定偏差的結果仍是有很大區別的。
本書將從第 3 章開始詳細介紹一些 NLP 中實用的監督學習方法。
若是咱們只給機器作題,卻不告訴它參考答案,機器仍然能夠學到知識嗎?
能夠,此時的學習稱做無監督學習,而不含標準答案的習題集被稱做無標註(unlabeled)的數據集。無監督學習在日語中被稱做「教師なし學習」,意爲「沒有老師的學習」。沒有老師的指導,機器只能說發現樣本之間的聯繫,而沒法學習樣本與答案之間的關聯。
無監督學習通常用於聚類和降維,二者都不須要標註數據。
聚類已經在 1.2 節中介紹過了,咱們再也不贅述。在性別識別的例子中,若是咱們選擇將一系列人名聚成 2 個簇的話,「周樹人」「周立人」極可能在一個簇裏面,「陸雪琪」和「曹雪芹」 在另外一個簇裏面。這是由樣本之間的類似性和簇的顆粒度決定的,但咱們並不知道哪一個簇表明男性哪一個簇表明女性,它們也未必能經過肉眼區分。
降維指的是將樣本點從高維空間變換到低維空間的過程。機器學習中的高維數據比比皆是,好比在性別識別的例子中,以經常使用漢字爲特徵的話,特徵數量輕易就突破了 2000。若是樣本具備 n 個特徵,則樣本對應着 n +1 維空間中的一個點,多出來的維度是給假設函數的因變量用的。若是咱們想要讓這些樣本點可視化,則必須將其降維到二維或三維空間。有一些降維算法的中心思想是,降維後儘可能不損失信息,或者說讓樣本在低維空間中每一個維度上的方差都儘可能大。試想一下這樣的極端案例:平地上豎直地插着一些等長的鋼管,將這些鋼管的頂端降維到二維平面上,就是拔掉鋼管後留下來的孔洞。垂直維度上鋼管長度都是同樣的,沒有有用信息,因而被捨棄掉了。
有一些無監督方法也能夠用來驅動中文分詞、詞性標註、句法分析等任務。因爲互聯網上存儲了豐富的非結構化數據,因此無監督學習十分誘人。然而無監督學習時,模型與用戶之間沒有發生任何信息交換,這種缺少監督信號的學習致使模型沒法捕捉用戶的標準,最終預測的結果每每與用戶心目中的理想答案相去甚遠。目前,無監督學習的 NLP 任務的準確率總比監督學習低十幾個到幾十個百分點,沒法達到生產要求。
本書將在第 10 章詳細介紹聚類算法的原理和實現。
若是咱們訓練多個模型,而後對同一個實例執行預測,會獲得多個結果。若是這些結果多數一致,則能夠將該實例和結果放到一塊兒做爲新的訓練樣本,用來擴充訓練集。這樣的算法①被稱爲半監督學習。因爲半監督學習能夠綜合利用標註數據和豐富的未標註數據,因此正在成爲熱門的研究課題。
現實世界中的事物之間每每有很長的因果鏈:咱們要正確地執行一系列彼此關聯的決策,才能獲得最終的成果。這類問題每每須要一邊預測,一邊根據環境的反饋規劃下次決策。這類算法被稱爲強化學習。強化學習在一些涉及人機交互的問題上成果斐然,好比自動駕駛、電子競技和問答系統。
本書做爲入門讀物,不會深刻這些前沿課題。但瞭解這些分支的存在,有助於構建完整的知識體系。
① 稱做啓發式半監督學習,是全部半監督學習方法中最容易理解的一種。複製代碼
語料庫做爲天然語言處理領域中的數據集,是咱們教機器理解語言不可或缺的習題集。在這一節中,咱們來了解一下中文處理中的常見語料庫,以及語料庫建設的話題。
中文分詞語料庫指的是,由人工正確切分後的句子集合。
以著名的 1998 年《人民日報》語料庫爲例,該語料庫由北京大學計算語言學研究所聯合富士通研究開發中心有限公司,在人民日報社新聞信息中心的許可下,從 1999 年 4 月起到 2002年 4 月底,共同標註完成。語料規模達到 2600 萬漢字,市售爲 1998 年上半年的語料部分(約1300 萬字=約 730 萬詞)。
在 2005 年的第二屆國際中文分詞比賽中,曾經公開過約 1 個月份的語料。其中的一句樣例爲:
先有通貨膨脹干擾,後有通貨緊縮叫板。
從這句簡單的標註語料中,無須語言學知識,咱們也能發現一個問題:爲什麼「通貨膨脹」是一個詞,而「通貨 緊縮」卻分爲兩個詞呢?這涉及語料標註規範和標註員內部一致性的問題。咱們將在後續章節中詳細介紹這些話題,如今只需留個印象:語料規範很難制定,規範很難執行。
事實上,中文分詞語料庫雖然總量很少,但派別卻很多。咱們將在第 3 章中瞭解這些語料的受權、下載與使用。
它指的是切分併爲每一個詞語指定一個詞性的語料。總之,咱們要教機器幹什麼,咱們就得給機器示範什麼。依然以《人民日報》語料庫爲例,1998 年的《人民日報》一共含有 43 種詞性,這個集合稱做詞性標註集。這份語料庫中的一句樣例爲:
邁向/v 充滿/v 但願/n 的/u 新/a 世紀/n ——/w 一九九八年/t 新年/t 講話/n (/w 附/v 圖片/n 1/m 張/q )/w複製代碼
這裏每一個單詞後面用斜槓隔開的就是詞性標籤,關於每種詞性的意思將會在第 7 章詳細介紹。這句話中值得注意的是,「但願」的詞性是「名詞」(n)。在另外一些句子中,「但願」還能夠做爲動詞。
這種語料庫人工標註了文本內部製做者關心的實體名詞以及實體類別。好比《人民日報》語料庫中一共含有人名、地名和機構名 3 種命名實體:
薩哈夫/nr 說/v ,/w 伊拉克/ns 將/d 同/p [聯合國/nt 銷燬/v 伊拉克/ns 大規模/b 殺傷性/n 武器/n 特別/a 委員會/n] /nt 繼續/v 保持/v 合做/v 。/w複製代碼
這個句子中的加粗詞語分別是人名、地名和機構名。中括號括起來的是複合詞,咱們能夠觀察到:有時候機構名和地名複合起來會構成更長的機構名,這種構詞法上的嵌套現象增長了命名實體識別的難度。
命名實體類型有什麼取決於語料庫製做者關心什麼。在本書第 8 章中,咱們將演示如何標註一份語料庫用來實現對戰鬥機名稱的識別。
漢語中經常使用的句法分析語料庫有 CTB(Chinese Treebank,中文樹庫),這份語料庫的建設工做始於 1998 年,歷經賓夕法尼亞大學、科羅拉多大學和布蘭迪斯大學的貢獻,一直在發佈多個改進版本。以 CTB 8.0 版爲例,一共含有來自新聞、廣播和互聯網的 3007 篇文章,共計 71 369個句子、1 620 561 個單詞和 2 589 848 個字符。每一個句子都通過了分詞、詞性標註和句法標註。其中一個句子可視化後如圖 1-6 所示。
圖 1-6 中,中文單詞上面的英文標籤表示詞性,而箭頭表示有語法聯繫的兩個單詞,具體是何種聯繫由箭頭上的標籤表示。關於句法分析語料庫的可視化和利用,將會在第 12 章中介紹。
它指的是人工標註了所屬分類的文章構成的語料庫。相較於上面介紹的 4 種語料庫,文本分類語料庫的數據量明顯要大不少。以著名的搜狗文本分類語料庫爲例,一共包含汽車、財經、 IT、健康、體育、旅遊、教育、招聘、文化、軍事 10 個類別,每一個類別下含有 8000 篇新聞,每篇新聞大約數百字。
另外,一些新聞網站上的欄目通過了編輯的手工整理,相互之間的區分度較高,也可做爲文本分類語料庫使用。情感分類語料庫則是文本分類語料庫的一個子集,無非是類別限定爲 「正面」「負面」等而已。
若是這些語料庫中的類目、規模不知足實際需求,咱們還能夠按需自行標註。標註的過程實際上就是把許多文檔整理後放到不一樣的文件夾中。
語料庫建設指的是構建一份語料庫的過程,分爲規範制定、人員培訓與人工標註這 3 個階段。
規範制定指的是由語言學專家分析並制定一套標註規範,這份規範包括標註集定義、樣例和實施方法。在中文分詞和詞性標註領域,比較著名的規範有北京大學計算語言學研究所發佈的《現代漢語語料庫加工規範——詞語切分與詞性標註》和中國國家標準化管理委員會發佈的《信息處理用現代漢語詞類標記規範》。
人員培訓指的是對標註員的培訓。因爲人力資源的限制,制定規範與執行規範的未必是同一批人。大型語料庫每每須要多人協同標註,這些標註員對規範的理解必須達到一致,不然會致使標註員內部衝突,影響語料庫的質量。
針對不一樣類型的任務,人們開發出許多標註軟件,其中比較成熟的一款是 brat(brat rapid annotation tool) ①,它支持詞性標註、命名實體識別和句法分析等任務。brat 是典型的 B/S 架構,服務端用 Python 編寫,客戶端運行於瀏覽器。相較於其餘標註軟件,brat 最大的亮點是多人協同標註功能。此外,拖曳式的操做體驗也爲 brat 增色很多。
① 詳見 http://brat.nlplab.org/。複製代碼
目前開源界貢獻了許多優秀的 NLP 工具,它們爲咱們提供了多種選擇,好比教學經常使用的NLTK(Natural Language Toolkit)、斯坦福大學開發的 CoreNLP,以及國內哈工大開發的 LTP (Language Technology Platform)、我開發的 HanLP(Han Language Processing)。
選擇一個工具包,咱們須要考慮的問題有:功能、精度、運行效率、內存效率、可拓展性、商業受權和社區活躍程度。表 1-7 比較了 4 款主流的開源 NLP 工具包。
關於這些開源工具的發展速度,根據 GitHub 上 Star 數量的趨勢,HanLP 是發展最迅猛的,如圖 1-7 所示。
① 關於 HanLP 與 LTP 的具體性能對比,請參考 @zongwu233 的第三方開源評測:https://github.com/zongwu233/ HanLPvsLTP。關於 HanLP 與包括結巴、IK、Stanford、Ansj、word 在內的其餘 Java 開源分詞器的性能對比,可參考阿里巴巴架構師楊尚川的第三方開源評測:https://github.com/ysc/cws_evaluation。我不保證第三方開源評測的準確與公正,更不採信任何閉源評測。本書將在相關章節中詳細介紹如何規範地評估常見 NLP 任務的精度。 複製代碼② 截至 2019 年 8 月份在 GitHub 上的 Star 數量。複製代碼
另外,我也研究過其餘開源項目的原理,借鑑了其中優秀的設計。但畢竟仍是本身寫的代碼講得最清楚,因此綜合以上各類考慮,最後選取了 HanLP 做爲本書的實現。
得益於 Python 簡潔的設計,使用這門動態語言調用 HanLP 會省下很多時間。不管用戶是否經常使用 Python,都推薦一試。
HanLP 的 Python 接口由 pyhanlp 包提供,其安裝只需一句命令:
$ pip install pyhanlp複製代碼
這個包依賴 Java 和 JPype。Windows 用戶若是遇到以下錯誤:
building '_jpype' extension
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual
C++ Build Tools": http://visualstudio.microsoft.com/visual-cpp-build-tools/複製代碼
既能夠按提示安裝 Visual C++,也能夠安裝更輕量級的 Miniconda。Miniconda 是 Python 語言的開源發行版,提供更方便的包管理。安裝時請勾選如圖 1-8 所示的兩個複選框。
而後執行以下命令:
$ conda install -c conda-forge jpype1
$ pip install pyhanlp複製代碼
若是遇到 Java 相關的問題:
jpype._jvmfinder.JVMNotFoundException: No JVM shared library file (jvm.dll) found. Try setting up the JAVA_HOME environment variable properly.複製代碼
請安裝 Java 運行環境①。HanLP 主項目採用 Java 開發,因此須要 JDK 或 JRE。若是發生其餘錯誤,歡迎前往項目討論區② 彙報問題。
一切順利的話,在命令行中鍵入以下命令,能夠驗證安裝結果:
若是 Linux 用戶遇到權限問題,則須要執行 sudo hanlp。由於在第一次運行時,pyhanlp 會自動下載 HanLP 的 jar 包(包含許多算法)和數據包(包含許多模型)到 pyhanlp 的系統路徑。
經過命令行,咱們能夠在不寫代碼的前提下輕鬆調用 HanLP 提供的常見功能。
① 官網(http://www.oracle.com/technetwork/java/javase/downloads/index.html)推薦選擇 JDK 8 以上版本。 複製代碼② 詳見 github.com/hankcs/HanL…複製代碼
使用命令 hanlp segment進入交互分詞模式;輸入一個句子並回車,HanLP 會輸出分詞結果:
$ hanlp segment
商品和服務
商品/n 和/cc 服務/vn
當下雨天地面積水分外嚴重
當/p 下雨天/n 地面/n 積水/n 分外/d 嚴重/a王總和小麗結婚了
王總/nr 和/cc 小麗/nr 結婚/vi 了/ule複製代碼
在 Linux 下還能夠重定向字符串做爲輸入:
$ hanlp segment <<< '歡迎新老師生前來就餐'
歡迎/v 新/a 老/a 師生/n 前來/vi 就餐/vi複製代碼
注意 Windows 不支持字符串的 <<< 定向,只能手動輸入。
這裏默認執行了詞性標註,咱們能夠禁用它:
$ hanlp segment --no-tag <<< ' 歡迎新老師生前來就餐'
歡迎 新 老 師生 前來 就餐複製代碼
任何平臺都支持重定向文件輸入 / 輸出,好比咱們將一本小說存儲爲 input.txt :
$ head input.txt
第一章 隱憂
張小凡看着前方那個中年文士,也就是當今正道的心腹大患「鬼王」,腦海中一片混亂。
這些日子以來,他在深心處不時對本身往日的信仰有小小的疑惑,其實都根源於當日空桑山下茶攤裏的一番對話。現在,又見故人,這份心情當真複雜,幾乎讓他一時間忘了此時此地的處境。
不過就算他忘了,旁邊的人可不會忘。
小周伸手擦去了嘴邊的鮮血,勉強站了起來,低聲對張小凡、田靈兒二人道:「此人道行過高,不可力敵,我來拖住他,大家二人快走!」
說罷,他伸手一招,倒插在巖壁中到如今兀自在輕微振動的「七星劍」,似受他召喚,「錚」的一聲破壁而出,飛回到他手上。
鬼王看了看小周,點了點頭,臉上依然帶着一絲微笑,道:「以你的道行,看來青雲門門下年輕弟子一輩裏,要以你爲首。
想不到青雲門除了這個張小凡,竟然還有你這樣的人才,不錯,不錯!」
張小凡嚇了一跳,卻發覺師姐田靈兒與那小周的眼光都瞄了過來,一時臉上有些發熱,殊不知道該說什麼纔好。複製代碼
經過重定向,只需一條命令就能夠給小說分詞:
$ hanlp segment < input.txt > output.txt -a crf --no-tag複製代碼
此處經過 -a參數指定分詞算法爲 CRF。關於該算法,咱們會在第 6 章中詳細介紹。如今,咱們先來感性觀察一下 CRF 分詞的效果:
$ head output.txt
第一 章 隱憂
張小凡 看着 前方 那個 中年 文士 , 也 就是 當今 正道 的 心腹大患 「 鬼王 」 , 腦海中 一片 混亂。這些 日子 以來 , 他 在 深心 處 不時 對 本身 往日 的 信仰 有 小小 的 疑惑 , 其實 都 根源 於 當日 空桑山 下 茶攤 裏 的 一番 對話 。
現在 , 又 見 故人 , 這 份 心情 當真 複雜 , 幾乎 讓 他 一 時間 忘 了 此時此地 的 處境 。不過 就算 他 忘 了 , 旁邊 的 人 可 不會 忘 。
小周 伸手 擦去 了 嘴邊 的 鮮血 , 勉強 站 了 起來 , 低聲 對 張小凡 、 田靈兒 二 人 道 :
「 此人 道行 太 高 , 不可力敵 , 我 來 拖住 他 , 大家 二 人 快走 !」
說罷 , 他 伸手 一 招 , 倒 插 在 巖壁 中 到 如今 兀自 在 輕微 振動 的 「 七星劍 」 , 似 受 他 召喚 , 「 錚 」 的 一 聲 破壁 而 出 , 飛 回到 他 手上 。
鬼王 看 了 看 小周 , 點 了 點頭 , 臉上 依然 帶 着 一 絲 微笑 , 道 : 「 以 你 的 道行 , 看來 青雲門 門下 年輕 弟子 一 輩 裏 , 要以 你 爲首 。
想不到 青雲門 除了 這個 張小凡 , 竟然 還有 你 這樣 的 人才 , 不錯 , 不錯 ! 」
張小凡 嚇了一跳 , 卻 發覺 師姐 田靈兒 與 那 小周 的 眼光 都 瞄 了 過來 , 一時 臉上 有些 發熱 , 卻 不 知道 該 說 什麼 才 好 。複製代碼
效果彷佛還行,「鬼王」「空桑山」「七星劍」「青雲門」等詞語都正確切分出來了。但仍然有不盡如人意的地方。好比「此時此地」「嚇了一跳」爲何被看成一個詞?這些分詞標準是由分詞器做者定的嗎?這些問題咱們將會在後續章節中逐個討論。
句法分析功能也是同樣的道理,一句命令便可:
這些命令還支持許多其餘參數,這能夠經過 --help參數來查看最新的幫助手冊:
在初步體驗 HanLP 後,來看看如何在 Python 中調用 HanLP 的經常使用接口。這裏給出一個大而不全的例子:
HanLP 的經常使用功能能夠經過工具類 HanLP來調用,而不須要建立實例。對於其餘更全面的功能介紹,可參考 GitHub 上的 demos 目錄:https://github.com/hankcs/pyhanlp/tree/master/tests/demos。
Java 用戶能夠經過 Maven 方便地引入 HanLP 庫,只需在項目的 pom.xml 中添加以下依賴項便可:
此外,能夠訪問發佈頁https://github.com/hankcs/HanLP/releases 獲取其最新的版本號。
而後就能夠用一句話調用HanLP 了:
System.out.println(HanLP.segment("你好,歡迎使用HanLP漢語處理包!"));複製代碼
經常使用的 API 依然封裝在工具類 HanLP中,你可經過 https://github.com/hankcs/HanLP 瞭解接口的用法。固然,你也能夠隨着本書的講解,逐步熟悉這些功能。
HanLP 的數據與程序是分離的。爲了減少 jar 包的體積,portable 版只含有少許數據。對於一些高級功能(CRF 分詞、句法分析等),則須要下載額外的數據包,並經過配置文件將數據包的位置告訴給 HanLP。
若是讀者安裝過 pyhanlp 的話,則數據包和配置文件已經安裝就緒。咱們能夠經過以下命令獲取它們的路徑:
最後一行 hanlp.properties 就是所需的配置文件,咱們只需將它複製到項目的資源目錄src/main/resources 便可(沒有該目錄的話,手動建立一個)。此時 HanLP 就會從 /usr/local/lib/python3.6/site-packages/pyhanlp/static 加載 data,也就是說與 pyhanlp 共用同一套數據包。
若是讀者沒有安裝過 pyhanlp,或者但願使用獨立的 data,也並不困難。只需訪問項目主頁https://github.com/hankcs/HanLP,下載 data.zip 並將其解壓到一個目錄,好比 D:/hanlp。而後下載並解壓 hanlp-1.7.5-release.zip,將獲得的 hanlp.properties 中的第一行 root 設爲 data 文件夾的父目錄:
root=D:/hanlp複製代碼
注意 Windows 用戶請注意,路徑分隔符統一使用斜槓「/」。Windows 默認的「\」與絕大多數編程語言的轉義符衝突,好比「D:\nlp」中的「\n」實際上會被Java 和Python 理解爲換行符,引起問題。
最後,將 hanlp.properties 移動到項目的 resources 目錄中便可。
因爲本書將深刻講解 HanLP 的內部實現,因此還推薦讀者去 GitHub 上建立分支(fork)並克隆(clone)一份源碼。版本庫中的文件結構以下:
限於文件體積,版本庫中依然不含完整的 model 文件夾,須要用戶下載數據包和配置文件。下載方式有自動與手動兩種,本書 Java 配套代碼在運行時會自動下載並解壓,另外用戶也能夠自行下載解壓。按照前面提到的方法,建立 resources 目錄並將 hanlp.properties 放入其中。而後將下載到的 data/model 放入版本庫的相應目錄便可。完成後的路徑示意圖以下:
接下來,咱們就能夠運行本書配套的代碼了(配套代碼位於 src/test/java/com/hankcs/book)。如今咱們來運行一個 Hello Word(詳見 ch01/HelloWord.java):
HanLP.Config.enableDebug(); // 爲了不你等得無聊,開啓調試模式說點什麼
System.out.println(HanLP.segment("王國維和服務員"));複製代碼
運行一下,會獲得相似以下的輸出:
相較於上一個例子,它們有如下兩個區別。
● 咱們打開了調試模式,此時會將運行過程的中間結果輸出到控制檯。
● 咱們運行的是GitHub倉庫版,該版本中的詞典和模型都是文本形式。HanLP中的詞典通常有文本和二進制兩種形式,它們的關係相似於源碼和程序。當二進制不存在時,HanLP會加載文本詞典並自動緩存爲同名的二進制。二進制的加載比文本要快不少,一般是5 倍的加速比。好比在上面的例子中,加載文本花了341 ms,但再次運行時加載相應的二進制只花了64 ms。經過緩存機制和內部重寫的IO 接口,HanLP 能夠將系統的冷啓動控制在幾百毫秒內。這爲程序員反覆調試提供了極大的便利。
再來看看調試輸出,裏面分爲兩個過程:粗分過程和細分過程。粗分過程的結果是 [王國 /n, 維和 /vn, 服務員 /nnt],這顯然是不合理① 的,這個句子不該該這樣理解。因而在細分過程當中,算法進行了人名識別,召回了「王國維」這個詞語。接着算法以爲 [王國維 /nr, 和 /cc, 服務員 /nnt]通順多了,因而將其做爲最終結果。
算法內部還有許多細節,但咱們已經有了趁手的武器。具體武器的基本骨架、鍛造過程和使用場景,將以遞歸的形式逐步講解。
本章給出了人工智能、機器學習與天然語言處理的宏觀縮略圖與發展時間線。機器學習是人工智能的子集,而天然語言處理則是人工智能與語言學、計算機科學的交集。這個交集雖然小,它的難度卻很大。爲了實現理解天然語言這個宏偉目標,人們嘗試了規則系統,並最終發展到基於大規模語料庫的統計學習系統。
在接下來的章節中,就讓咱們按照這種由易到難的發展規律去解決第一個 NLP 問題——中文分詞。咱們將先從規則系統入手,介紹一些快而不許的算法,而後逐步進化到更加準確的統計模型。
① 稱其「不合理」而非「不正確」的緣由是,咱們沒法排除在某個奇幻世界裏存在一個特立獨行的王國,裏面養着一隻維和部隊,部隊的成員卻不是戰士而是服務員。但這種可能性很是低,幾乎不可能發生。
本文摘自《天然語言處理入門》