EasyNLP整合K-Global Pointer演算法,支援中文資訊抽取

語言: CN / TW / HK

作者:周紀詠、汪誠愚、嚴俊冰、黃俊

導讀

資訊抽取的三大任務是命名實體識別、關係抽取、事件抽取。命名實體識別是指識別文字中具有特定意義的實體,包括人名、地名、機構名、專有名詞等;關係抽取是指識別文字中實體之間的關係;事件抽取是指識別文字中的事件資訊並以結構化的形式呈現出來。資訊抽取技術被廣泛應用於知識圖譜的構建、機器閱讀理解、智慧問答和資訊檢索系統中。資訊抽取的三大任務不是相互獨立的關係,而是相互依存、彼此依賴的關係。命名實體識別是關係抽取、事件抽取的基礎,關係抽取是事件抽取的基礎。同時,關係抽取、事件抽取對命名實體識別任務有幫助,事件抽取對關係抽取任務有幫助。但目前關於僅使用一個模型完成中文資訊抽取三大任務的研究相對較少,因此,我們提出K-Global Pointer演算法並整合進EasyNLP演算法框架中,使使用者可以使用自定義資料集訓練中文資訊抽取模型並使用。

EasyNLP(https://github.com/alibaba/EasyNLP)是阿⾥雲機器學習PAI團隊基於PyTorch開發的簡單易⽤且功能豐富的中⽂NLP演算法框架,⽀持常⽤的中⽂預訓練模型和⼤模型落地技術,並且提供了從訓練到部署的⼀站式NLP開發體驗。EasyNLP提供了簡潔的接⼝供⽤戶開發NLP模型,包括NLP應⽤AppZoo和預訓練ModelZoo,同時提供技術幫助⽤戶⾼效的落地超⼤預訓練模型到業務。由於跨模態理解需求的不斷增加,EasyNLP也⽀持各種跨模態模型,特別是中⽂領域的跨模態模型,推向開源社群,希望能夠服務更多的NLP和多模態演算法開發者和研究者,也希望和社群⼀起推動NLP/多模態技術的發展和模型落地。

本⽂簡要介紹K-Global Pointer的技術解讀,以及如何在EasyNLP框架中使⽤K-Global Pointer模型。

K-Global Pointer模型詳解

Global Pointer模型是由蘇劍林提出的解決命名實體識別任務的模型,\(n*n\) 的矩陣\(A\)\(n\)為序列長度),\(A[i,j]\)代表的是序列\(i\)到序列\(j\)組成的連續子串為對應實體型別的概率,通過設計門檻值$B$即可將文字中具有特定意義的實體識別出來。

K-Global Pointer模型是在Global Pointer模型的基礎之上改進的。首先我們將僅支援命名實體識別的模型拓展成支援中文資訊抽取三大任務的模型。然後,我們使用了MacBERT預訓練語言模型來將文字序列轉換成向量序列。最後我們針對不同的任務設計了一套prompt模板,其能幫助預訓練語言模型“回憶”起自己在預訓練時“學習”到的內容。接下來,我們將根據中文資訊抽取三大任務分別進行闡述。

針對命名實體識別任務,我們有文字\(w_{1},w_{2},w_{3},...,w_{n}\)以及需要提取的實體型別entity_type,對應的prompt為“找到文章中所有【entity_type】型別的實體?”,對應的輸入模型的文字\(H\)為“找到文章中所有【entity_type】型別的實體?文章:【\(w_{1},w_{2},w_{3},...,w_{n}\)】”,模型經過相應的處理即可輸出文字中實體型別為entity_type的實體。

image.png

針對關係抽取任務,我們有文字\(w_{1},w_{2},w_{3},...,w_{n}\)以及需要提取的關係型別relation_type(subject_type-predicate-object_type),分為兩步。第一步,對應的prompt為“找到文章中所有【subject_type】型別的實體?”,對應的輸入模型的文字\(H\)為“找到文章中所有【subject_type】型別的實體?文章:【\(w_{1},w_{2},w_{3},...,w_{n}\)】”,模型經過相應的處理即可輸出文字中實體型別為subject_type的實體\(e_{1}\)。第二步,對應的prompt為“找到文章中所有【\(e_{1}\)】的【\(predicate\)】?”,對應的輸入模型的文字$H$為“找到文章中所有【\(e_{1}\)】的【\(predicate\)】?文章:【\(w_{1},w_{2},w_{3},...,w_{n}\)】”,模型經過相應的處理即可輸出實體\(e_{2}\)。即可構成關係三元組(\(e_{1}、predicate、e_{2}\))。

image.png

針對事件抽取任務,我們有文字\(w_{1},w_{2},w_{3},...,w_{n}\)以及需要提取的事件型別$class$,每個\(class\)包含event_type以及role_list(\(r_{1},r_{2}\),...),分為兩步。第一步,對應的prompt為“找到文章中所有【event_type】型別的實體?”,對應的輸入模型的文字$H$為“找到文章中所有【event_type】型別的實體?文章:【\(w_{1},w_{2},w_{3},...,w_{n}\)】”,模型經過相應的處理即可輸出的實體\(e\)。第二步,針對role_list中不同的\(r_{x}\),對應的prompt為“找到文章中所有【\(e\)】的【\(r_{x}\)】?”,對應的輸入模型的文字$H$為“找到文章中所有【\(e\)】的【\(r_{x}\)】?文章:【\(w_{1},w_{2},w_{3},...,w_{n}\)】”,模型經過相應的處理即可輸出實體\(e_{x}\)。即可構成事件{event_type:\(e\),role_list:{\(r_{1}:e_{1},r_{2}:e_{2}\),...}}。

image.png

K-Global Pointer模型的實現與效果

在EasyNLP框架中,我們在模型層構建了K-Global Pointer模型的Backbone,其核⼼程式碼如下所示:

self.config = AutoConfig.from_pretrained(pretrained_model_name_or_path)
self.backbone = AutoModel.from_pretrained(pretrained_model_name_or_path)
self.dense_1 = nn.Linear(self.hidden_size, self.inner_dim * 2)
self.dense_2 = nn.Linear(self.hidden_size, self.ent_type_size * 2)

context_outputs = self.backbone(input_ids, attention_mask, token_type_ids)
outputs = self.dense_1(context_outputs.last_hidden_state)
qw, kw = outputs[..., ::2], outputs[..., 1::2]

pos = SinusoidalPositionEmbedding(self.inner_dim, 'zero')(outputs)
cos_pos = pos[..., 1::2].repeat_interleave(2, dim=-1)
sin_pos = pos[..., ::2].repeat_interleave(2, dim=-1)
qw2 = torch.stack([-qw[..., 1::2], qw[..., ::2]], 3)
qw2 = torch.reshape(qw2, qw.shape)
qw = qw * cos_pos + qw2 * sin_pos
kw2 = torch.stack([-kw[..., 1::2], kw[..., ::2]], 3)
kw2 = torch.reshape(kw2, kw.shape)
kw = kw * cos_pos + kw2 * sin_pos

logits = torch.einsum('bmd,bnd->bmn', qw, kw) / self.inner_dim ** 0.5
bias = torch.einsum('bnh->bhn', self.dense_2(last_hidden_state)) / 2
logits = logits[:, None] + bias[:, ::2, None] + bias[:, 1::2, :, None]
        
mask = torch.triu(attention_mask.unsqueeze(2) * attention_mask.unsqueeze(1))
y_pred = logits - (1-mask.unsqueeze(1))*1e12
y_true = label_ids.view(input_ids.shape[0] * self.ent_type_size, -1)
y_pred = y_pred.view(input_ids.shape[0] * self.ent_type_size, -1)
loss = multilabel_categorical_crossentropy(y_pred, y_true)

為了驗證EasyNLP框架中K-Global Pointer模型的有效性,我們使用DuEE1.0、DuIE2.0、CMeEE-V2、CLUENER2020、CMeIE、MSRA、People's_Daily 7個數據集聯合進行訓練,並在各個資料集上分別進行驗證。其中CMeEE-V2、CLUENER2020、MSRA、People's_Daily資料集適用於命名實體識別任務,DuIE2.0、CMeIE資料集適用於關係抽取任務,DuEE1.0資料集適用於事件抽取任務。結果如下所示:

資料集 DuEE1.0 DuIE2.0 CMeEE-V2 CLUENER2020 CMeIE MSRA People's_Daily
引數設定B=0.6 0.8657 0.8725 0.8266 0.889 0.8155 0.9856 0.9933

可以通過上述結果,驗證EasyNLP框架中K-Global Pointer演算法實現的正確性、有效性。

K-Global Pointer模型使用教程

以下我們簡要介紹如何在EasyNLP框架使⽤K-Global Pointer模型。分為三種情況,分別是①使用者使用資料訓練模型②使用者驗證訓練好的模型③使用者使用訓練好的模型完成中文資訊抽取任務。我們提供了聯合DuEE1.0、DuIE2.0、CMeEE-V2、CLUENER2020、CMeIE、MSRA、People's_Daily 7個數據集的資料,可以通過sh run_train_eval_predict_user_defined_local.sh來下載獲取train.tsv、dev.tsv、predict_input_EE.tsv、predict_input_NER.tsv檔案,其中train.tsv檔案可用於訓練、dev.tsv檔案可用於驗證、predict_input_EE.tsv、predict_input_NER.tsv檔案可用於測試。使用者也可以使用自定義資料。

⽤戶可以直接參考GitHubhttps://github.com/alibaba/EasyNLP)上的說明安裝EasyNLP演算法框架。然後cd EasyNLP/examples/information_extraction。

①使用者使用資料訓練模型

資料準備

訓練模型需要使用訓練資料和驗證資料。使用者可以使用我們提供的資料,也可以使用自定義資料。資料表示為train.tsv檔案以及dev.tsv檔案,這兩個⽂件都包含以製表符\t分隔的五列,第一列是標籤,第二列是上文K-Global Pointer模型詳解中提到的,第三列是答案的開始,第四列是答案的的結束,第五列是答案。樣例如下:

People's_Daily-train-0	['找到文章中所有【LOC】型別的實體?文章:【海釣比賽地點在廈門與金門之間的海域。】']	[29, 32]	[31, 34]	廈門|金門
DuIE2.0-train-0	['找到文章中所有【圖書作品】型別的實體?文章:【《邪少兵王》是冰火未央寫的網路小說連載於旗峰天下】']	[24]	[28]	邪少兵王
DuIE2.0-train-1	['找到文章中【邪少兵王】的【作者】?文章:【《邪少兵王》是冰火未央寫的網路小說連載於旗峰天下】']	[28]	[32]	冰火未央
DuEE1.0-train-25900	['找到文章中所有【競賽行為-奪冠】型別的實體?文章:【蓋斯利在英國大獎賽首場練習賽中奪冠】']	[41]	[43]	奪冠
DuEE1.0-train-25901	['找到文章中【奪冠】的【冠軍】?文章:【蓋斯利在英國大獎賽首場練習賽中奪冠】']	[19]	[22]	蓋斯利
DuEE1.0-train-25902	['找到文章中【奪冠】的【奪冠賽事】?文章:【蓋斯利在英國大獎賽首場練習賽中奪冠】']	[25]	[35]	英國大獎賽首場練習賽

訓練模型

程式碼如下:

python main.py \
--mode train \
--tables=train.tsv,dev.tsv \
--input_schema=id:str:1,instruction:str:1,start:str:1,end:str:1,target:str:1 \
--worker_gpu=4 \
--app_name=information_extraction \
--sequence_length=512 \
--weight_decay=0.0 \
--micro_batch_size=2 \
--checkpoint_dir=./information_extraction_model/ \
--data_threads=5 \
--user_defined_parameters='pretrain_model_name_or_path=hfl/macbert-large-zh' \
--save_checkpoint_steps=500 \
--gradient_accumulation_steps=8 \
--epoch_num=3  \
--learning_rate=2e-05  \
--random_seed=42

訓練好的模型儲存在information_extraction_model資料夾中。

②使用者驗證訓練好的模型

資料準備

驗證模型需要使用驗證資料。使用者可以使用我們提供的資料,也可以使用自定義資料。資料表示為dev.tsv檔案,這個⽂件包含以製表符\t分隔的五列,第一列是標籤,第二列是上文K-Global Pointer模型詳解中提到的\(H\),第三列是答案的開始,第四列是答案的的結束,第五列是答案。樣例如下:

People's_Daily-train-0	['找到文章中所有【LOC】型別的實體?文章:【海釣比賽地點在廈門與金門之間的海域。】']	[29, 32]	[31, 34]	廈門|金門
DuIE2.0-train-0	['找到文章中所有【圖書作品】型別的實體?文章:【《邪少兵王》是冰火未央寫的網路小說連載於旗峰天下】']	[24]	[28]	邪少兵王
DuIE2.0-train-1	['找到文章中【邪少兵王】的【作者】?文章:【《邪少兵王》是冰火未央寫的網路小說連載於旗峰天下】']	[28]	[32]	冰火未央
DuEE1.0-train-25900	['找到文章中所有【競賽行為-奪冠】型別的實體?文章:【蓋斯利在英國大獎賽首場練習賽中奪冠】']	[41]	[43]	奪冠
DuEE1.0-train-25901	['找到文章中【奪冠】的【冠軍】?文章:【蓋斯利在英國大獎賽首場練習賽中奪冠】']	[19]	[22]	蓋斯利
DuEE1.0-train-25902	['找到文章中【奪冠】的【奪冠賽事】?文章:【蓋斯利在英國大獎賽首場練習賽中奪冠】']	[25]	[35]	英國大獎賽首場練習賽

驗證模型

程式碼如下:

python main.py \
--mode evaluate \
--tables=dev.tsv \
--input_schema=id:str:1,instruction:str:1,start:str:1,end:str:1,target:str:1 \
--worker_gpu=4 \
--app_name=information_extraction \
--sequence_length=512 \
--weight_decay=0.0 \
--micro_batch_size=2 \
--checkpoint_dir=./information_extraction_model/ \
--data_threads=5

③使用者使用訓練好的模型完成中文資訊抽取任務

資料準備

測試模型需要使用測試資料。使用者可以使用我們提供的資料,也可以使用自定義資料。

對於命名實體識別任務,資料表示為predict_input_NER.tsv檔案,這個⽂件包含以製表符\t分隔的三列,第一列是標籤,第二列是實體型別,第三列是文字。我們支援對同一個文字識別多種實體型別,僅需要在第二列中將不同的實體型別用;分隔開。樣例如下:

1	LOC;ORG	海釣比賽地點在廈門與金門之間的海域。

對於關係抽取任務,資料表示為predict_input_RE.tsv檔案,這個⽂件包含以製表符\t分隔的三列,第一列是標籤,第二列是關係型別,第三列是文字。我們支援對同一個文字識別多種關係型別,僅需要在第二列中將不同的關係型別用;分隔開。對於一個關係型別relation_type(subject_type-predicate-object_type)表示為subject_type:predicate,樣例如下:

1	圖書作品:作者	《邪少兵王》是冰火未央寫的網路小說連載於旗峰天下

對於事件抽取任務,資料表示為predict_input_EE.tsv檔案,這個⽂件包含以製表符\t分隔的三列,第一列是標籤,第二列是事件型別class,第三列是文字。我們支援對同一個文字識別多種事件型別,僅需要在第二列中將不同的事件型別用;分隔開。對於一個事件型別class包含event_type以及role_list(r1,r2,……)表示為event_type:r1,r2,……,樣例如下:

1	競賽行為-奪冠:奪冠賽事,裁員人數	蓋斯利在英國大獎賽首場練習賽中奪冠

測試模型

對於命名實體識別任務,程式碼如下:

python main.py \
--tables=predict_input_NER.tsv \
--outputs=predict_output_NER.tsv \
--input_schema=id:str:1,scheme:str:1,content:str:1 \
--output_schema=id,content,q_and_a \
--worker_gpu=4 \
--app_name=information_extraction \
--sequence_length=512 \
--weight_decay=0.0 \
--micro_batch_size=4 \
--checkpoint_dir=./information_extraction_model/ \
--data_threads=5 \
--user_defined_parameters='task=NER'

模型輸出結果見predict_output_NER.tsv檔案

對於關係抽取任務,程式碼如下:

python main.py \
--tables=predict_input_RE.tsv \
--outputs=predict_output_RE.tsv \
--input_schema=id:str:1,scheme:str:1,content:str:1 \
--output_schema=id,content,q_and_a \
--worker_gpu=4 \
--app_name=information_extraction \
--sequence_length=512 \
--weight_decay=0.0 \
--micro_batch_size=4 \
--checkpoint_dir=./information_extraction_model/ \
--data_threads=5 \
--user_defined_parameters='task=RE'

模型輸出結果見predict_output_RE.tsv檔案

對於事件抽取任務,程式碼如下:

python main.py \
--tables=predict_input_EE.tsv \
--outputs=predict_output_EE.tsv \
--input_schema=id:str:1,scheme:str:1,content:str:1 \
--output_schema=id,content,q_and_a \
--worker_gpu=4 \
--app_name=information_extraction \
--sequence_length=512 \
--weight_decay=0.0 \
--micro_batch_size=4 \
--checkpoint_dir=./information_extraction_model/ \
--data_threads=5 \
--user_defined_parameters='task=EE'

模型輸出結果見predict_output_EE.tsv檔案

在阿里雲機器學習PAI-DSW上進行中文資訊抽取

PAI-DSW(Data Science Workshop)是阿里雲機器學習平臺PAI開發的雲上IDE,面向不同水平的開發者,提供了互動式的程式設計環境(文件)。在DSW Gallery中,提供了各種Notebook示例,方便使用者輕鬆上手DSW,搭建各種機器學習應用。我們也在DSW Gallery中上架了使用PAI-Diffusion模型進行中文資訊抽取的Sample Notebook,歡迎大家體驗!

image.png

未來展望

在未來,我們計劃進一步改進K-Global Pointer模型,敬請期待。我們將在EasyNLP框架中整合更多中⽂模型,覆蓋各個常⻅中⽂領域,敬請期待。我們也將在EasyNLP框架中整合更多SOTA模型,來⽀持各種NLP和多模態任務。此外,阿⾥雲機器學習PAI團隊也在持續推進中⽂NLP和多模態模型的⾃研⼯作,歡迎⽤戶持續關注我們,也歡迎加⼊我們的開源社群,共建中⽂NLP和多模態演算法庫!

Github地址:https://github.com/alibaba/EasyNLP

Reference

  1. Chengyu Wang, Minghui Qiu, Taolin Zhang, Tingting Liu, Lei Li, Jianing Wang, Ming Wang, Jun Huang, Wei Lin. EasyNLP: A Comprehensive and Easy-to-use Toolkit for Natural Language Processing. EMNLP 2022
  2. GlobalPointer:https://kexue.fm/archives/8373

阿里靈傑回顧