[譯] 自然語言處理真是有趣!

胖若倆人發表於2018-08-10

計算機如何理解人類的語言

計算機擅長處理結構化的資料,像電子表格和資料庫表之類的。但是我們人類的日常溝通是用詞彙來表達的,而不是表格,對計算機而言,這真是件棘手的事。

[譯] 自然語言處理真是有趣!

遺憾的是,我們並不是生活在處處都是結構化資料的時代。

這個世界上的許多資訊都是非結構化的 —— 不僅僅是英語或者其他人類語言的原始文字。我們該如何讓一臺計算機去理解這些非結構化的文字並且從中提取資訊呢?

[譯] 自然語言處理真是有趣!

自然語言處理,簡稱 NLP,是人工智慧領域的一個子集,目的是為了讓計算機理解並處理人類語言。讓我們來看看 NLP 是如何工作的,並且學習一下如何用 Python 寫出能夠從原始文字中提取資訊的程式。

注意:如果你不關心 NLP 是如何工作的,只想剪下和貼上一些程式碼,直接跳過至“用 Python 處理 NLP 管道”部分。

計算機能理解語言嗎?

自從計算機誕生以來,程式設計師們就一直嘗試去寫出能夠理解像英語這樣的語言的程式。這其中的原因顯而易見 —— 幾千年來,人類都是用寫的方式來記錄事件,如果計算機能夠讀取並理解這些資料將會對人類大有好處。

目前,計算機還不能像人類那樣完全瞭解英語 —— 但它們已經能做許多事了!在某些特定領域,你能用 NLP 做到的事看上去就像魔法一樣。將 NLP 技術應用到你的專案上能夠為你節約大量時間。

更好的是,在 NLP 方面取得的最新進展就是可以輕鬆地通過開源的 Python 庫比如 spaCytextacyneuralcoref 來進行使用。你需要做的只是寫幾行程式碼。

從文字中提取含義是很難的

讀取和理解英語的過程是很複雜的 —— 即使在不考慮英語中的邏輯性和一致性的情況下。比如,這個新聞的標題是什麼意思呢?

環境監管機構盤問了非法燒烤的業主。(“Environmental regulators grill business owner over illegal coal fires.”)

環境監管機構就非法燃燒煤炭問題對業主進行了詢問?或者按照字面意思,監管機構把業主烤了?正如你所見,用計算機來解析英語是非常複雜的一件事。

在機器學習中做一件複雜的事通常意味著建一條管道。這個辦法就是將你的問題分成細小的部分,然後用機器學習來單獨解決每一個細小的部分。再將多個相互補充的機器學習模型進行連結,這樣你就能搞定非常複雜的事。

而且這正是我們將要對 NLP 所使用的策略。我們將理解英語的過程分解為多個小塊,並觀察每個小塊是如何工作的。

一步步構建 NLP 管道

讓我們看一段來自維基百科的文字:

倫敦是英格蘭首都,也是英國的人口最稠密的城市。倫敦位於英國大不列顛島東南部泰晤士河畔,兩千年來一直是一個主要定居點。它是由羅馬人建立的,把它命名為倫蒂尼恩。(London is the capital and most populous city of England and the United Kingdom. Standing on the River Thames in the south east of the island of Great Britain, London has been a major settlement for two millennia. It was founded by the Romans, who named it Londinium.)

(來源:維基百科“倫敦”

這段文字包含了幾個有用的資訊。如果電腦能夠閱讀這段文字並且理解倫敦是一個由羅馬人建立的,位於英國的城市等等,那就最好不過了。但是要達到這個要求,我們需要先將有關書面知識的最基本的概念傳授給電腦,然後不斷深入。

步驟一:語句分割

在管道中所要做的第一件事就是將這段文字分割成獨立的句子,由此我們可以得到:

  1. “倫敦是英國的首都,也是英格蘭和整個聯合王國人口最稠密的城市。(London is the capital and most populous city of England and the United Kingdom.)”
  2. “位於泰晤士河流域的倫敦,在此後兩個世紀內為這一地區最重要的定居點之一。(Standing on the River Thames in the south east of the island of Great Britain, London has been a major settlement for two millennia.)”
  3. 它由羅馬人建立,取名為倫蒂尼恩。(It was founded by the Romans, who named it Londinium.)”

我們假設每一個句子都代表一個獨立的想法。那麼相較於能理解整篇文章的程式而言,我們可以更加容易地寫出能夠理解獨立語句的程式。

建立一個語句分割模型就像使用標點符號來分割語句一樣簡單。但是現代 NLP 管道通常需要更加複雜的技術來解決文件排版不整齊的情況。

第二步:文字元號化

現在我們已經把文件分割成了句子,我們可以一步一步地處理這些句子,讓我們從文件中的第一個句子開始:

“London is the capital and most populous city of England and the United Kingdom.”

下一步就是在管道中將這個句子分割成獨立的詞語或符號。這就稱作分詞。接下來看看對這個句子分詞的結果:

“London”, “is”, “ the”, “capital”, “and”, “most”, “populous”, “city”, “of”, “England”, “and”, “the”, “United”, “Kingdom”, “.”

分詞在英語中是容易完成的。我們只要分割那些空格分隔的詞語。我們也將標點符號作為單詞,因為它們也具有含義。

第三步:猜測每個詞的屬性

接下來,我們需要猜測一下每一個詞的屬性 —— 名詞,動詞和形容詞等等。知道每個詞在句子中所扮演的角色之後,就能夠幫助我們推斷句子的含義。

要知道詞的屬性,我們可以將每個詞(包括一些上下文的詞)提供給預先訓練的詞性分類模型:

[譯] 自然語言處理真是有趣!

詞性分類模型在最初通過數百萬個英語句子的訓練,這些句子中每個詞的屬性都已經被標記,並以此讓模型學會複製這種標記的行為。

記住,這個模型是基於統計資料的 —— 它並不是以和人類一樣的方式理解詞的含義。它所知道的只是如何依靠之前標記的類似單詞和句子來猜測語句的含義。

在處理完整個句子之後,我們會得出這樣的結果:

[譯] 自然語言處理真是有趣!

根據這些資訊,我們已經能夠開始蒐集一些非常基礎的含義。比如,這個句子中的名詞包括“倫敦”和“首都”,所以這個句子極有可能是與倫敦有關的。

第四步:文字詞形還原

在英語(以及其它大多數語言)中,詞語以不同的形式出現。來看看下面這兩個句子:

I had a pony.

I had two ponies.

兩句話都講到了名詞小馬 (pony),但是它們有著不同的詞形變化。知道詞語的基本形式對計算機處理文字是有幫助的,這樣你就能知道兩句話在討論同一個概念。否則,“pony” 和 “ponies” 對於電腦來說就像兩個完全不相關的詞語。

在 NLP 中,我們稱這個過程為詞形還原 —— 找出句子中每一個詞的最基本的形式或詞元

對於動詞也一樣。我們也能夠通過尋找動詞最初的非結合形式來進行詞形還原。所以 “I had two ponies” 變為 “I [have] two [pony]”。

詞形還原一般是通過具有基於其詞性的詞彙形式的查詢表來完成工作的,並且可能具有一些自定義的規則來處理之前從未見過的詞語。

這就是經過詞形還原新增動詞最初形式的句子:

[譯] 自然語言處理真是有趣!

唯一變化的地方就是將 “is” 變為 “be”。

第五步:識別終止詞

接下來,我們需要考慮句子中的每個單詞的重要性。英語有很多頻繁出現的填充詞比如 “and”、“the” 和 “a”。 在對文字進行統計的時候,隨著這些詞出現頻率的升高,將會出現很多歧義。一些 NLP 管道將這些詞語標記為“終止詞” —— 在進行任何分析之前需要過濾掉的詞語。

這就是將終止詞過濾掉之後的句子:

[譯] 自然語言處理真是有趣!

終止詞的識別通常是由查詢一個硬編碼的已知終止詞列表來完成。但是不存在對於所有應用來說通用的標準終止詞列表。這個列表極大程度上是由你的應用所決定的。

舉個例子,如果你正在建立一個與搖滾樂隊有關的搜尋引擎,需要確保你沒有忽略單詞 “The”。不僅是因為這個單詞出現在很多樂隊名中,而且還有一個 80 年代的著名搖滾樂隊叫做 The The

第六步:依存語法解析

下一步就是找出句子中的每一個詞之間的依存關係,這就做依存語法解析

目標就是構建一棵樹,為句子中的每一個詞賦予一個父類詞語。樹的根是句子中的主要動詞。根據這個句子構造的解析樹的開頭就是這個樣子:

[譯] 自然語言處理真是有趣!

但我們還可以做的更多。為了識別每一個詞的父類詞,我們還可以預測這兩個詞之間存在的關係:

[譯] 自然語言處理真是有趣!

這顆解析樹為我們展示了這個句子的主體是名詞倫敦,而且它和首都之間有著 be 關係。我們最終發現了一些有用的資訊 —— 倫敦是一個首都!如果我們遵循著這個句子的整顆解析樹(不僅是圖示資訊),甚至能夠發現倫敦是英國的首都。

就像我們早前使用機器學習模型來預測詞性那樣,以將詞語輸入機器學習模型並輸出結果的方式來完成依存語法分析。 但是分析依存語法是一項十分複雜的任務,它需要用一整篇文章來作為分析某些細節的上下文。 如果你很好奇它是如何工作的,有一篇作者為 Matthew Honnibal 的優秀文章值得一讀 用 500 行 Python 程式碼來解析英語 (Parsing English in 500 Lines of Python)

但是儘管這位作者在 2015 年發表了一條說明稱這種方法現在已成為標準,但它已經過時甚至不再被作者使用過。在 2016 年,谷歌推出了一種新的依存語法分析方法,稱為 Parsey McParseface,它採用了一種新的深度學習方法,超越了之前的表現,並在業界內快速流傳。一年之後,他們又釋出了新的模型,稱為 ParseySaurus,對某些方面做了進一步改善。換句話說,解析技術依舊是搜尋領域的一項熱門技術,並且在不斷地變化和改進。

很多英語語句是十分模糊且難以解析的,這一點需要牢記在心。在那些例子中,模型會根據之前解析過的最相似的句子來進行猜測,但這並不完美,有時這個模型會產生令人尷尬的錯誤。但隨著時間的推移,我們的 NLP 模型將會繼續以合理的方式更好地解析文字。

想要在你自己的句子上試一試依存語法解析嗎?這是來自 spaCy 團隊的一個很棒的互動演示

第六步(下):查詢名詞短語

到現在為止,我們將句子中的每一個詞語都作為一個獨立的實體。但有時將一些詞語連線起來能夠更加合理地表達一個想法或事件。我們能夠用依存關係解析樹中的資訊來自動地將所有闡述相同事物的詞語組合在一起。

舉個例子,比如這一個:

[譯] 自然語言處理真是有趣!

我們可以將名詞短語組合在一起達到這樣的結果:

[譯] 自然語言處理真是有趣!

我們要根據最終目標來決定是否要進行這一步。但是如果我們並不需要得到哪些詞是形容詞這些額外細節而是更關注抽取句子中的完整含義,這通常是簡化句子一個簡單的方法。

第七步:命名實體識別(NER)

現在我們已經完成所有困難的工作,終於可以拋棄書面的語法並開始動手實現想法了。

在我們的句子中,有著以下名詞:

[譯] 自然語言處理真是有趣!

這些名詞中,有一部分與實際意義相同。比如說“倫敦”、“英格蘭”和“英國”代表了地圖上的物理位置。如果能檢測到這些那真是太棒了!有了這些資訊,我們就能夠使用 NLP 在自動地提取一個在文件中提及的真實世界地理位置列表。

命名實體識別NER)的目標就是為了檢測和標記這些代表真實世界中某些事物的名詞。在使用我們的 NER 標記模型對句子中的每個詞語進行處理之後,句子就變成這樣:

[譯] 自然語言處理真是有趣!

但 NER 系統並不只是做這些簡單的查詢字典的工作。而是使用某個詞語在句子中的上下文以及統計模型來猜測某個詞語代表哪種型別的名詞。一個優秀的 NER 系統能夠根據上下文線索辨別出人名 “Brooklyn Decker” 和 地名 “Brooklyn”。

這些是經典的 NER 系統能夠標記的事物:

  • 人名
  • 公司名
  • 地理位置(物理位置和政治位置)
  • 產品名稱
  • 日期和時間
  • 金額
  • 事件名稱

自從 NER 能夠幫助輕易地從文字中獲取結構化資料,便被廣泛使用。它是從 NLP 管道中獲得結果的最便捷途徑之一。

想自己試一試專名識別技術嗎?這是來自 spaCy 團隊的另一個很棒的互動演示

第八步:共指解析

在此刻,我們已經對句子有了充分的瞭解。我們瞭解了每個詞語的詞性、詞語之間的依存關係以及哪些詞語是代表命名實體的。

可是,我們還需要解決一個大問題。英語中存在著大量的代詞 —— 比如。這些是我們對在句子中反覆出現的名稱的簡化。人們能夠根據上下文來得到這些詞代表的內容。但是我們的 NLP 模型並不知道這些代詞的含義,因為它每次只檢查一個句子。

來看看我們的文件中的第三個句子:

“It was founded by the Romans, who named it Londinium.”

如果我們用 NLP 管道解析這個句子,我們就能知道“它”是由羅馬人建立的。但如果能知道“倫敦”是由羅馬人建立的那會更有用。

當人們讀這個句子時,能夠很容易得出“它”代表“倫敦”。共指解析的目的是根據整個句子中的代詞來找出這種相同的對映。我們是想要找出所有指向同一實體的詞語。

這就是在我們的文件中對“倫敦”使用共指解析的結果:

[譯] 自然語言處理真是有趣!

將共指資訊、解析樹和命名實體資訊結合在一起,我們就能夠從這個文件中提取出很多資訊!

共指解析是我們正在進行工作的管道中的最艱難步驟之一。它甚至比語句解析還要困難。深度學習的最新進展帶來更精確的方法,但它還不夠完美。如果你想多瞭解一下它是如何工作的,從這裡開始

想要參與協作共指解析?看看這個來自 Hugging Face 的協作共指解析演示

用 Python 來構建 NLP 管道

這是我們的完整 NLP 管道的概覽:

[譯] 自然語言處理真是有趣!

共指解析是一項並不總要完成的可選步驟。

哎呀,有好多步驟啊!

注意:在我們往下看之前,值得一提的是,這些都是構建傳統 NLP 管道的步驟,你可以根據你的目的以及如何實現你的 NLP 庫來決定是跳過還是重複某些步驟。舉個例子,一些像 spaCy 這樣的庫,是先使用依存語法解析,得出結果後再進行語句分割。

那麼,我們該如何構建這個管道?多謝像 spaCy 這樣神奇的 python 庫,管道的構建工作已經完成!所有的步驟都已完成,時刻準備為你所用。

首先,假設你已經安裝了 Python 3,你可以按如下步驟來安裝 spaCy:

# 安裝 spaCy 
pip3 install -U spacy

# 下載針對 spaCy 的大型英語模型
python3 -m spacy download en_core_web_lg

# 安裝同樣大有用處的 textacy
pip3 install -U textacy
複製程式碼

在一段文件中執行 NLP 管道的程式碼如下所示:

import spacy

# 載入大型英語模型
nlp = spacy.load('en_core_web_lg')

# 我們想要檢驗的文字
text = """London is the capital and most populous city of England and 
the United Kingdom.  Standing on the River Thames in the south east 
of the island of Great Britain, London has been a major settlement 
for two millennia. It was founded by the Romans, who named it Londinium.
"""

# 用 spaCy 解析文字. 在整個管道執行.
doc = nlp(text)

# 'doc' 現在包含了解析之後的文字。我們可以用它來做我們想做的事!
# 比如,這將會列印出所有被檢測到的命名實體:
for entity in doc.ents:
    print(f"{entity.text} ({entity.label_})")
複製程式碼

如果你執行了這條語句,你就會得到一個關於文件中被檢測出的命名實體和實體型別的表:

London (GPE)  
England (GPE)  
the United Kingdom (GPE)  
the River Thames (FAC)  
Great Britain (GPE)  
London (GPE)  
two millennia (DATE)  
Romans (NORP)  
Londinium (PERSON)
複製程式碼

你可以檢視每一個實體程式碼的含義

需要注意的是,它誤將 “Londinium” 作為人名而不是地名。這可能是因為在訓練資料中沒有與之相似的內容,不過它做出了最好的猜測。如果你要解析具有專業術語的文字,命名實體的檢測通常需要做一些微調

讓我們把這實體檢測的思想轉變一下,來做一個資料清理器。假設你正在嘗試執行新的 GDPR 隱私條款並且發現你所持有的上千個文件中都有個人身份資訊,例如名字。現在你的任務就是移除文件中的所有名字。

如果將上千個文件中的名字手動去除,需要花上好幾年。但如果用 NLP,事情就簡單了許多。這是一個移除檢測到的名字的資料清洗器:


import spacy

# 載入大型英語 NLP 模型
nlp = spacy.load('en_core_web_lg')

# 如果檢測到名字,就用 "REDACTED" 替換
def replace_name_with_placeholder(token):
    if token.ent_iob != 0 and token.ent_type_ == "PERSON":
        return "[REDACTED] "
    else:
        return token.string

# 依次解析文件中的所有實體並檢測是否為名字
def scrub(text):
    doc = nlp(text)
    for ent in doc.ents:
        ent.merge()
    tokens = map(replace_name_with_placeholder, doc)
    return "".join(tokens)

s = """
In 1950, Alan Turing published his famous article "Computing Machinery and Intelligence". In 1957, Noam Chomsky’s 
Syntactic Structures revolutionized Linguistics with 'universal grammar', a rule based system of syntactic structures.
"""

print(scrub(s))
複製程式碼

如果你執行了這個,就會看到它如預期般工作:

In 1950, [REDACTED] published his famous article "Computing Machinery and Intelligence". In 1957, [REDACTED]   
Syntactic Structures revolutionized Linguistics with 'universal grammar', a rule based system of syntactic structures.
複製程式碼

資訊提取

開箱即用的 spaCy 能做的事實在是太棒了。但你也可以用 spaCy 解析的輸出來作為更復雜的資料提取演算法的輸入。這裡有一個叫做 textacy 的 python 庫,它實現了多種基於 spaCy 的通用資料提取演算法。這是一個良好的開端。

它實現的演算法之一叫做半結構化語句提取。我們用它來搜尋解析樹,查詢主體為“倫敦”且動詞是 “be” 形式的簡單語句。這將會幫助我們找到有關倫敦的資訊。

來看看程式碼是怎樣的:

import spacy
import textacy.extract

# 載入大型英語 NLP 模型
nlp = spacy.load('en_core_web_lg')

# 需要檢測的文字
text = """London is the capital and most populous city of England and  the United Kingdom.  
Standing on the River Thames in the south east of the island of Great Britain, 
London has been a major settlement  for two millennia.  It was founded by the Romans, 
who named it Londinium.
"""

# 用 spaCy 來解析文件
doc = nlp(text)

# 提取半結構化語句
statements = textacy.extract.semistructured_statements(doc, "London")

# 列印結果
print("Here are the things I know about London:")

for statement in statements:
    subject, verb, fact = statement
    print(f" - {fact}")
複製程式碼

它列印出了這些:

Here are the things I know about London:

 - the capital and most populous city of England and the United Kingdom.  
- a major settlement for two millennia.
複製程式碼

也許這不會太令人印象深刻。但如果你將這段程式碼用於維基百科上關於倫敦的整篇文章上,而不只是這三個句子,就會得到令人印象十分深刻的結果:

Here are the things I know about London:

 - the capital and most populous city of England and the United Kingdom  
 - a major settlement for two millennia  
 - the world's most populous city from around 1831 to 1925  
 - beyond all comparison the largest town in England  
 - still very compact  
 - the world's largest city from about 1831 to 1925  
 - the seat of the Government of the United Kingdom  
 - vulnerable to flooding  
 - "one of the World's Greenest Cities" with more than 40 percent green space or open water  
 - the most populous city and metropolitan area of the European Union and the second most populous in Europe  
 - the 19th largest city and the 18th largest metropolitan region in the world  
 - Christian, and has a large number of churches, particularly in the City of London  
 - also home to sizeable Muslim, Hindu, Sikh, and Jewish communities  
 - also home to 42 Hindu temples  
 - the world's most expensive office market for the last three years according to world property journal (2015) report  
 - one of the pre-eminent financial centres of the world as the most important location for international finance  
 - the world top city destination as ranked by TripAdvisor users  
 - a major international air transport hub with the busiest city airspace in the world  
 - the centre of the National Rail network, with 70 percent of rail journeys starting or ending in London  
 - a major global centre of higher education teaching and research and has the largest concentration of higher education institutes in Europe  
 - home to designers Vivienne Westwood, Galliano, Stella McCartney, Manolo Blahnik, and Jimmy Choo, among others  
 - the setting for many works of literature  
 - a major centre for television production, with studios including BBC Television Centre, The Fountain Studios and The London Studios  
 - also a centre for urban music  
 - the "greenest city" in Europe with 35,000 acres of public parks, woodlands and gardens  
 - not the capital of England, as England does not have its own government
複製程式碼

現在事情變得有趣了起來!我們自動收集了大量的資訊。

為了讓事情變得更有趣,試試安裝 neuralcoref 庫並且新增共指解析到你的管道。這將為你提供更多的資訊,因為它會捕捉含有“它”的而不是直接表示“倫敦”的句子。

我們還能做什麼?

看看這個 spaCy 文件textacy 文件,你會發現很多能夠用於解析文字的方法示例。目前我們所看見的只是一個小示例。

這裡有另外一個例項:想象你正在構建一個能夠向使用者展示我們在上一個例子中提取出的全世界城市的資訊的網站。

如果你的網站有搜尋功能,能像谷歌那樣能夠自動補全常規的查詢就太好了:

[譯] 自然語言處理真是有趣!

谷歌對於“倫敦”的自動補全建議

如果這麼做,我們就需要一個可能提供給使用者的建議列表。我們可以使用 NLP 來快速生成這些資料。

這是從文件中提取常用名詞塊的一種方式:

import spacy
import textacy.extract

# 載入大型英語 NLP 模型
nlp = spacy.load('en_core_web_lg')

# 需要檢測的文件
text = """London is the capital and most populous city of England and  the United Kingdom.  
Standing on the River Thames in the south east of the island of Great Britain, 
London has been a major settlement  for two millennia.  It was founded by the Romans, 
who named it Londinium.
"""

# 用 spaCy 解析文件
doc = nlp(text)

# 提取半結構化語句
statements = textacy.extract.semistructured_statements(doc, "London")

# 列印結果
print("Here are the things I know about London:")

for statement in statements:
    subject, verb, fact = statement
    print(f" - {fact}")
複製程式碼

如果你用這段程式碼來處理維基百科上關於倫敦的文章,就會得到如下結果:

westminster abbey  
natural history museum  
west end  
east end  
st paul's cathedral  
royal albert hall  
london underground  
great fire  
british museum  
london eye

.... etc ....
複製程式碼

更進一步

這只是你可以用 NLP 做到的事中的一個小示例。在以後的文章中,我們將會談論一些其他的應用,例如文字分類或亞馬遜 Alexa 系統是如何解析問題的。

但目前要做的事,就是安裝 spaCy 並使用它。如果你不是 Python 程式設計師並且使用不同的 NLP 庫,這種想法應該也能奏效。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章