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

阿里靈傑回顧