2022年3月21日 星期一

SpaCy 學習筆記 (二) : 語法相依關係與命名實體的視覺化

SpaCy 的 NLP 任務管線中最重要的是語法相依關係, 這在機器理解自然語言上有關鍵的作用 (例如訂票系統判斷客戶是否要訂票等), 這個語法相依關係是放在 Token 物件的 head 屬性與 dep_ 屬性中, 但光從這兩個欄位並不容易判讀句法關係, 因此 SpaCy 內建了displayCy 這個 visualizer (繪圖模組) 來展示文句中各 Token 物件之間的語法相依關係, 也可以標記命名實體 (NER, named entity recognition), 參考 :


本系列之前的文章參考 :



一. 在本機中使用 displayCy : 

在本機使用 displayCy 做視覺化首先須匯入 displacy 模組, 然後呼叫其 serve() 函數, 並傳入語言物件與指定style 參數為 'dep', 格式如下 :

displaycy.serve(doc, [style='dep', port=5000, options=None])  

這樣會在本機建立一個預設埠為 5000 的網頁伺服器, 並將所傳入之 Doc 物件的 POS 標註與語法相依關係圖繪製於此網頁中. 備選參數說明如下 :
  • style : 指定欲繪製的對象, 預設 'dep' 為語法關係圖, 若設為 'ent' 為標記命名實體.
  • port : 網頁伺服器埠號, 預設為 5000
  • options : 型態為字典之選項設定, 可用之鍵如下 : 
    • 'bg' : 背景色, 值可為 16 進位色碼, 顏色名稱, (R, G, B) 元組
    • 'compact' : 是否以緊湊方式繪圖 (方形線取代弧線), 預設 False
    • 'color' : 線條色彩, 值可為 16 進位色碼, 顏色名稱, (R, G, B) 元組
    • 'font' : 字型名稱, 例如 'Arial'
注意, options 字典中的鍵必須為字串, 且其設定僅在 style='dep' 時有作用. 

例如 : 


測試 1 : 呼叫 displacy.render() 建立網頁伺服器以呈現語法相依圖 [看原始碼]

import spacy
from spacy import displacy
nlp=spacy.load('en_core_web_sm')
doc=nlp('I live in Taiwan.')
displacy.serve(doc)      # 預設繪製語法關係圖

此例於呼叫 displacy.serve() 時僅傳入 doc 物件, 預設是繪製語法關係圖 (style='dep'), 執行後會顯示如下結果 (在 Thonny 中執行) : 

>>> %Run displacy_test_1.py    
2022-03-20 14:58:12.357184: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'cudart64_101.dll'; dlerror: cudart64_101.dll not found
2022-03-20 14:58:12.357541: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.

Using the 'dep' visualizer
Serving on http://0.0.0.0:5000 ...

可見未傳入 style 參數時確實是預設啟動 dep 繪圖器, 底下會出現網頁伺服器位址為 0.0.0.0:5000 的提示, 但不要用 0.0.0.0 這網址去開啟 (因瀏覽器安全性限制無法開啟), 而是要改用 127.0.0.1 或 localhost, 結果如下 : 



  
可見 displayCy 會以弧線箭頭來表示每個 Token 的語法相依關係 (由 parent 指向 child), Token 底下的是 POS 詞類標註 (即 pos_ 欄位值), 弧線上的是語法相依性標註 (即 dep_ 欄位值). 按 Ctrl+C 可以停止此網頁伺服器

可以用迴圈走訪 doc 物件的各 Token, 顯示 tag_, pos_, 與 dep_ 等欄位來比對觀察 : 


測試 2 : 顯示 Doc 物件 (串列) 中每一個 Token 物件之主要屬性值 [看原始碼]

import spacy
nlp=spacy.load('en_core_web_sm')
doc=nlp('I live in Taiwan.')
print(f'text\tlemma_\ttag_\tpos_\tdep_\thead')  
for token in doc:
    fstr=(f'{token.text}\t{token.lemma_}\t{token.tag_}\t{token.pos_}\t'
          f'{token.dep_}\t{token.head}')
    print(fstr)

結果如下 : 




可見弧線上標註的是 dep_ 屬性之值 (身分為 ROOT 的動詞不會標示出來). 

下面是添加 options 選項參數的範例 : 


測試 3 : 呼叫 displacy.render() 時傳入 options 參數 [看原始碼]

import spacy
from spacy import displacy
nlp=spacy.load('en_core_web_sm')
doc=nlp('I live in Taiwan.')
displacy.serve(doc, options={'color': '#0000ff',
                             'bg': 'cyan',
                             'compact': True,
                             'font': 'Arial'})

此例傳入 options 參數, 設定字型, 背景與前景色, 以及用緊湊方式繪圖, 結果如下 :




可見關係線從較占空間的弧線改為較緊緻的方形線, 顏色也照設定值改變了. 

除了繪製語法相依圖外, 也可以傳入 style='ent' 來標記文句中的命名實體 (named entity), 例如 :


測試 4 : 標記文句中的命名實體 (NER) [看原始碼]

import spacy
from spacy import displacy
nlp=spacy.load('en_core_web_sm')
doc=nlp('I live in Taiwan.')
displacy.serve(doc, style='ent')   

此例傳入 style='ent' 表示要繪製所標記的命名實體, 結果如下 : 



可見 displayCy 將句中的命名實體 Taiwan 以高亮背景色標記出來了, 且打上 GPE 的標註, 表示這是一個地理上的名稱 (包含國家, 城市, 或省市州郡等). 

Doc 物件中的每個 Token 都有一個 ent_type_ 屬性, 若該 Token 被辨識出來是一個命名實體, 則該屬性欄會被填入命名實體類型名稱, 將此類型名稱傳入 spacy.explain() 函式會傳回該類型之解釋, 若該 Token 不是命名實體則傳回 None, 例如 : 


測試 4-1 : 走訪 Token 物件檢視 ent_type_ 屬性與其解釋 [看原始碼]

import spacy
from spacy import displacy
nlp=spacy.load('en_core_web_sm')
doc=nlp('I live in Taiwan.')
print('Token\tent_type_\texplain')
for token in doc:
    print(f'{token.text}\t{token.ent_type_}\t{spacy.explain(token.ent_type_)}')

此例以迴圈走訪 Doc 物件, 並列印各 Token 的 ent_type_ 屬性與其解釋, 結果如下 :




可見此句中只有 Taiwan 這個 Token 是命名實體, 其類型為 GPE, 代表國家 (countries), 城市 (cities), 或州郡 (states) 等. 


二. 在 Jupyter Notebook 上使用 displayCy : 

以上在本機命令列的操作也可以在 Jupyter Notebook 的網頁介面上執行, 但繪圖指令不是用 displacy.serve(), 而是要改用 displaycy.render(), 其介面與 displacy.serve() 類似 :

displaycy.render(doc, [style='dep', options=None])  

首先在命令提示字元視窗輸入 jupyter lab, 這是新版的 Jupyter, 其安裝參考 :

 
D:\Python\test>jupyter lab    
[I 23:20:18.791 LabApp] JupyterLab extension loaded from c:\python37\lib\site-packages\jupyterlab
[I 23:20:18.791 LabApp] JupyterLab application directory is c:\python37\share\jupyter\lab
[I 23:20:18.803 LabApp] Serving notebooks from local directory: D:\Python\test
[I 23:20:18.803 LabApp] The Jupyter Notebook is running at:
[I 23:20:18.804 LabApp] http://localhost:8888/?token=7db060eaec8fe94b1ef39f8377e47ca5bd048846441d00a7
[I 23:20:18.808 LabApp]  or http://127.0.0.1:8888/?token=7db060eaec8fe94b1ef39f8377e47ca5bd048846441d00a7
[I 23:20:18.809 LabApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 23:20:18.957 LabApp]

    To access the notebook, open this file in a browser:
        file:///C:/Users/User/AppData/Roaming/jupyter/runtime/nbserver-8756-open.html
    Or copy and paste one of these URLs:
        http://localhost:8888/?token=7db060eaec8fe94b1ef39f8377e47ca5bd048846441d00a7
     or http://127.0.0.1:8888/?token=7db060eaec8fe94b1ef39f8377e47ca5bd048846441d00a7
[I 23:20:22.135 LabApp] Build is up to date
[I 23:20:23.208 LabApp] Kernel started: 2285a805-2962-4f9c-9f52-61cb9a37d7f4
2022-03-20 23:20:49.178605: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'cudart64_101.dll'; dlerror: cudart64_101.dll not found
2022-03-20 23:20:49.178949: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
[I 23:22:22.899 LabApp] Saving file at /Untitled.ipynb
[I 23:24:07.160 LabApp] Creating new notebook in /
[I 23:24:07.435 LabApp] Kernel started: 82934c28-4c3a-48e2-b16b-5b4b95fd06c3
[I 23:26:07.470 LabApp] Saving file at /Untitled1.ipynb

這會自動開啟 Jupyter Notebook 網頁, 然後在方框中輸入如下的指令按上方的 Play 鍵執行 : 

import spacy
nlp=spacy.load('en_core_web_sm')
doc=nlp('I live in Taiwan.')
spacy.displacy.render(doc)

結果如下 : 




接著輸入下面兩個指令 :

spacy.displacy.render(doc, style='ent')
spacy.displacy.render(doc, options={'color': '#0000ff','bg': 'cyan', 'compact': True, 'font': 'Arial'})

結果如下 : 




可見在 Jupyter Notebook 上執行 spacy visualization 也是非常方便的. 


三. 使用 Spacy 的線上視覺化功能 :

除了在本機自行做視覺化外, 還可以利用 Spacy 官網上所提供的視覺化功能, 語法相依關係圖的網址如下 :





其中 Text to parse 欄位用來輸入要分析的文句, Model 欄位用來挑選語言的統計模型 (預設是英文的 en_core_web_sm), 下方預設已勾選的 Merge Punctuation 用來設定是否要將標點符號與其前一個 Token 合併 (這樣會使圖形更緊湊), 而 Merge Phrases 則用來設定是否要將形容詞與其後的名詞合併 (同樣會使圖形更緊湊).

預設情形下輸入 "I live in New York." 按 search 鈕結果如下 : 




下方兩個選項都不勾選的結果是 : 



 
可見語法圖變得比較詳細但卻較複雜了.

命名實體視覺化的網址如下 :





左上方的輸入框用來輸入句子, 左下方用來選擇語言統計模型, 右方則可勾選要辨認的實體標籤, 例如輸入 "I live in New York." 後按 search 鈕, 結果如下 : 




線上視覺化的好處是不用自行安裝語言統計模型, 它已提供下列 13 種模型可用 :




例如選擇最後一項 Chinese 中文 zh_core_seb_sm 這個模型, 然後輸入如下句子 : 

戴笠, 浙江省江山縣人, 中華民國陸軍中將, 生於清光緒 23 年, 國民政府軍統局少將副局長, 蔣介石愛將, 民國 35 年 3 月 17 日於南京上空飛機失事身亡.

實體標籤用預設, 按 search 結果如下 : 





可見年份 (23 年, 35 年 3 月) 與地點 (浙江省, 南京) 都有辨認出來, 但是人名 (戴笠, 蔣介石), 機構名 (國民政府, 軍統局, 中華民國) 卻沒辨識出來, 應該是模型較小的緣故. 

沒有留言:

張貼留言