自然語言處理中的命名實體辨識 (NER) 技術,能有效識別文字中的關鍵實體。雖然預訓練模型如 spaCy 已具備一定的 NER 能力,但在特定領域的應用常需微調才能達到最佳效能。本文將逐步講解如何運用 Prodigy 進行資料標註,並使用 spaCy 訓練客製化 NER 模型,同時比較 Transformer GPU 加速模型與 CPU 模型的效能差異。透過實際案例與程式碼,示範如何提升 NER 模型在特定實體型別上的辨識能力,並探討自定義模型與原始模型的差異。
命名實體辨識(Named Entity Recognition, NER)的進階應用與自定義模型微調
前言
命名實體辨識(NER)是自然語言處理(NLP)中的一項基礎任務,主要用於識別文字中具有特定意義的實體,如人名、地名、組織機構名等。預訓練的模型如spaCy在許多NLP任務中表現出色,但在處理特定領域或任務時,可能需要對模型進行微調以提升效能。
利用預訓練模型進行NER
預訓練的spaCy模型已經在多個NLP任務上展現了其強大的能力。例如,在新聞文章資料集上,spaCy能夠有效地識別出日期、人名、組織機構名等實體。然而,當面對與訓練資料分佈不同的資料時,如技術檔案或金融報告,預訓練模型的表現可能會下降。
自定義NER模型的微調
為了提升模型在特定任務或資料集上的表現,可以透過以下步驟進行自定義微調:
資料標註:使用工具如Prodigy對資料進行標註。Prodigy是一款由Explosion開發的註解工具,能夠與spaCy模型無縫整合。透過Prodigy,可以方便地對文字資料進行實體標註。
模型選擇:選擇適合的預訓練模型作為基礎。目前,spaCy的transformer-based模型在多個NLP任務上表現出色,但需要注意版本相容性問題。
微調:使用標註好的資料對預訓練模型進行微調。這一步驟能夠使模型更好地適應特定的資料分佈或任務需求。
使用Prodigy進行資料標註
Prodigy是一款強大的資料標註工具,支援多種NLP任務的標註,包括NER。以下是使用Prodigy進行NER標註的基本步驟:
安裝Prodigy
- 購買Prodigy授權並下載對應的Python wheel檔案。
- 建立並啟用一個新的虛擬環境,以避免與其他專案的依賴衝突。
$ conda create -n prodigy anaconda python=3.8 $ conda activate prodigy - 在虛擬環境中安裝Prodigy及所需的spaCy模型。
$ pip install prodigy*.whl $ pip install -U spacy[cuda110]==2.3.5 $ pip install -U spacy-lookups-data==1.0.0 $ pip install cupy-cuda110==8.5.0 $ python -m spacy download en_core_web_lg
準備資料並進行標註
- 將待標註的文字資料準備成CSV格式,並確保文字列的名稱為"text"。
train_prodigy_ner = data.copy() train_prodigy_ner = train_prodigy_ner.description train_prodigy_ner.rename("text", inplace=True) train_prodigy_ner.to_csv(cwd + "data/ag_dataset/ner/raw/train_prodigy_ner.csv", index=False) - 使用Prodigy的
ner.manual配方進行NER標註。
微調spaCy模型
透過Prodigy標註的資料,可以用於微調spaCy模型,以提升其在特定任務或資料集上的表現。
內容解密:
準備標註資料:首先,需要將原始資料轉換為適合Prodigy處理的格式,即CSV檔案,並且確保文字資料儲存在名為"text"的列中。
使用Prodigy進行標註:啟動Prodigy後,透過其提供的UI介面對文字進行實體標註。對於NER任務,可以使用
ner.manual配方來手動標註實體。微調模型:將標註好的資料用於微調預訓練的spaCy模型。這一步驟能夠使模型更好地理解特定領域的文字,從而提高NER任務的準確率。
版本相容性:需要注意的是,Prodigy與spaCy的版本相容性問題。目前,Prodigy尚未完全支援spaCy 3.x版本,因此在安裝時需要指定相應的版本。
使用Prodigy進行命名實體識別(NER)註解
在命令列中,我們需要指定配方名稱(ner.manual)、要儲存註解的資料集名稱(例如,ag_data_ner_ticker)、一個spaCy模型(例如,en_core_web_lg或空白:en,如果我們想從空白模型開始)、文字來源(在我們的例子中,是train_prodigy_ner.csv的路徑),以及我們希望在Prodigy UI中可用的實體標籤來註解文字:
$ python -m prodigy ner.manual <dataset> <spacy_model> <source> \
--label ORG,PERSON,GPE,TICKER
內容解密:
python -m prodigy ner.manual:使用Prodigy的ner.manual配方進行命名實體識別註解。<dataset>:指定儲存註解的資料集名稱。<spacy_model>:指定使用的spaCy模型,例如en_core_web_lg或blank:en。<source>:文字來源的路徑,例如train_prodigy_ner.csv。--label ORG,PERSON,GPE,TICKER:指定在Prodigy UI中可用的實體標籤。
如果成功,您將在命令列中看到此訊息:
✨ Starting the web server at http://localhost:8080 … Open the app in your browser and start annotating!
將URL複製到您的網頁瀏覽器中,您應該會看到一個註解UI,如圖3-3所示。
圖3-3. Prodigy NER註解UI
現在,我們可以突出顯示範圍並為資料標記正確的實體,如圖3-4所示。點選大綠色勾選框以繼續下一個範例(或在鍵盤上按“a”鍵)。如果您不確定答案,可以按鍵盤上的空格鍵跳過該範例。
圖3-4. Prodigy NER註解UI:註解第一個範例
讓我們註解幾百個範例,然後透過點選UI左上角“prodigy”旁邊的軟碟圖示來儲存它們。幾百個註解應該足以建立一個不錯的微調模型,儘管,像往常一樣,註解越多,模型的效能就越好。
完成註解後,我們可以使用data-to-spaCy Prodigy配方將NER註解以spaCy的JSON格式輸出(見圖3-5)。
圖3-5. data-to-spaCy Prodigy配方
對於這個配方,我們需要指定輸出路徑(用於訓練模型)、評估輸出路徑(用於評估模型)、語言(在我們的例子中是“en”),以及使用–ner標籤的NER資料集:
$ python -m prodigy data-to-spacy <output> <eval_output> --lang en \
--ner ag_data_ner_ticker
內容解密:
python -m prodigy data-to-spacy:使用Prodigy的data-to-spacy配方將註解輸出為spaCy的JSON格式。<output>:指定輸出路徑,用於訓練模型。<eval_output>:指定評估輸出路徑,用於評估模型。--lang en:指定語言為英語。--ner ag_data_ner_ticker:指定NER資料集。
此命令以JSON格式輸出註解,但截至spaCy v3.0(2021年1月發布),spaCy的主要資料格式是二進位制格式。在使用spaCy進行訓練之前,我們需要將JSON格式轉換為二進位制。spaCy有一個轉換配方(見圖3-6),我們現在將使用它:
$ python -m spacy convert <path-to-json> <path-for-binary-output>
內容解密:
python -m spacy convert:使用spaCy的convert配方將JSON格式轉換為二進位制格式。<path-to-json>:指定JSON檔案的路徑。<path-for-binary-output>:指定二進位制輸出檔案的路徑。
使用spaCy訓練自定義NER模型
我們將訓練兩個獨立的NER模型。首先,我們將使用遷移學習訓練一個NER模型。為了進行遷移學習,我們將使用一個名為RoBERTa的變壓器模型,這是一個由Facebook在2019年發布的大型預訓練語言模型。其次,我們將在沒有變壓器模型和GPU的情況下訓練一個NER模型,而僅依賴於根據CPU的訓練流程。這將幫助我們比較根據變壓器的GPU啟用的效能與標準的根據CPU的效能。
讓我們首先訓練根據變壓器的模型。我們將使用spaCy中的train命令,如圖3-7所示。
圖3-7. spaCy train命令
對於這個命令,我們需要指定組態路徑、輸出路徑和GPU標籤以啟用GPU上的訓練。對訓練組態路徑的要求是spaCy v3.0的新增功能。訓練組態是設定模型開發的所有設定和超引數的檔案:
$ python -m spacy train <config_path> --output <output_path> \
--gpu-id 0
內容解密:
python -m spacy train:使用spaCy的train命令訓練模型。<config_path>:指定組態檔案的路徑。--output <output_path>:指定輸出模型的路徑。--gpu-id 0:啟用GPU上的訓練。
首先,讓我們生成這個組態檔案。令人驚訝的是,有一個spaCy配方可以從頭開始建立組態檔案(見圖3-8)。對於這個命令,我們需要指定語言(en)、需要修改的流程元件(ner)、最佳化標籤(“efficiency”以獲得更快的推斷/更小的模型,或“accuracy”以獲得更高的準確度/更慢、更大的模型)、是否使用GPU,以及命令是否應該覆寫輸出檔案(如果存在)。
圖3-8. spaCy init config
$ python -m spacy init config <config_path> --lang --pipeline \
--optimize --gpu --force
內容解密:
python -m spacy init config:使用spaCy的init config命令建立組態檔案。<config_path>:指定組態檔案的路徑。--lang、--pipeline、--optimize、--gpu、--force:根據需求設定組態檔案的相關引數。
或者,可以使用spaCy官方網站上的訓練組態UI來生成NER的最佳實踐版本的組態檔案。我們將使用這個方法,並啟動一個空白的根據變壓器的範本(啟用GPU)。
我們需要使用另一個名為init fill-config的spaCy命令來自動填充這個基本的NER範本,如圖3-9所示。
圖3-9. spaCy init fill-config
$ python -m spacy init fill-config <config_path_original> \
<config_path_new>
內容解密:
python -m spacy init fill-config:使用spaCy的init fill-config命令自動填充組態檔案。<config_path_original>:指定原始組態檔案的路徑。<config_path_new>:指定新組態檔案的路徑。
執行完上述步驟後,我們就可以開始訓練模型了。我們將進行30個epoch的訓練,並觀察模型的效能。結果如範例3-1所示。正如您所見,模型在30個epoch內達到了超過95的F1分數。
名為實體辨識的自然語言處理任務:以spaCy為例
在自然語言處理(NLP)領域中,名為實體辨識(Named Entity Recognition, NER)是一項關鍵任務,旨在從文字中識別和分類別具有特定意義的實體,如人名、地名、組織名稱等。本文將探討如何使用spaCy,一個流行的NLP函式庫,來建立和訓練NER模型。
使用spaCy訓練NER模型
spaCy提供了一種高效的方式來訓練NER模型,無論是使用預訓練的transformer模型還是從頭開始訓練。以下範例展示瞭如何使用spaCy訓練兩個不同的NER模型:一個根據transformer且使用GPU加速,另一個則不使用transformer且根據CPU。
transformer GPU-based NER模型
首先,我們來看看使用transformer和GPU進行訓練的NER模型的結果。
========================= Training pipeline =============================
[i] Pipeline: ['transformer', 'ner']
[i] Initial learn rate: 0.0
E # LOSS TRANS... LOSS NER ENTS_F ENTS_P ENTS_R SCORE
---
---
---
-
---
-
---
-
---
--
---
-
---
-
---
---
---
---
---
---
---
--
0 0 866.56 1087.32 3.31 1.75 29.99 0.03
8 200 127924.74 63854.97 94.39 94.05 94.75 0.94
17 400 2339.89 2798.22 94.13 93.78 94.48 0.94
26 600 166.36 2400.21 95.40 95.00 95.81 0.95
#### 內容解密:
- 訓練流程:此模型使用了包含transformer的訓練流程,這是一種預訓練語言模型,能夠提供豐富的語義資訊。
- 損失函式:LOSS TRANS和LOSS NER分別代表transformer部分和NER部分的損失函式值,隨著訓練的進行,這些值逐漸降低,表明模型的表現越來越好。
- 評估指標:ENTS_F、ENTS_P和ENTS_R分別代表F1分數、精確率和召回率,這些指標顯示了模型在NER任務上的表現。最終,模型的F1分數達到了0.95,表現出色。
非transformer CPU-based NER模型
接下來,我們看看不使用transformer且根據CPU訓練的NER模型的結果。
========================= Training pipeline =============================
[i] Pipeline: ['tok2vec', 'ner']
[i] Initial learn rate: 0.001
E # LOSS TOK2VEC LOSS NER ENTS_F ENTS_P ENTS_R SCORE
---
---
---
-
---
-
---
-
---
--
---
-
---
-
---
---
---
---
---
---
---
--
0 0 0.00 51.44 4.16 2.39 16.14 0.04
...
21 2200 179.27 60.26 89.19 89.91 88.48 0.89
#### 內容解密:
- 訓練流程:此模型使用了’tok2vec’和’ner’的訓練流程,不依賴transformer。
- 損失函式:LOSS TOK2VEC和LOSS NER顯示了模型在不同階段的損失。
- 評估指標:最終,模型的F1分數達到了約0.89,雖然不如根據transformer的模型,但仍然是一個不錯的成績。
自定義NER模型與原始模型的比較
透過比較自定義訓練的NER模型與spaCy原始的en_core_web_trf模型,可以觀察到自定義模型在特定實體型別上的表現略有提升。
#### 載入自定義NER模型並檢視其後設資料
# 載入自定義NER模型
spacy.require_gpu()
custom_ner_model = spacy.load(cwd + '/models/ag_dataset/ner/ner-gpu-blank/model-best')
# 檢視模型的後設資料
import pprint
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(custom_ner_model.meta)
#### 使用內建視覺化工具比較兩個模型的NER結果
# 對比原始模型與自定義模型的NER結果
from spacy import displacy
import random
base_model = spacy.load("en_core_web_trf")
options = {"ents": ["ORG","PERSON","GPE","TICKER"]}
for j in range(3):
i = random.randint(0, len(data))
print("Article",i)
doc_base = base_model(data.loc[i,"description"])
doc_custom = custom_ner_model(data.loc[i,"description"])
print("Base Model NER:")
displacy.render(doc_base, style="ent", options=options, jupyter=True)
print("Custom Model NER:")
displacy.render(doc_custom, style="ent", options=options, jupyter=True)
print("\n")
#### 結果分析:
透過視覺化比較,可以發現自定義模型在某些樣本上表現更好,例如正確識別出「NewsFactor」和「Cingular Wireless」作為組織名稱。然而,兩者的表現並非總是存在顯著差異,自定義模型有時也會錯失某些實體。