UIE: 信息抽取的大一統(tǒng)模型
原始論文
uie論文鏈接: https://arxiv.org/abs/2203.12277
uie項目地址:https://github.com/PaddlePaddle/PaddleNLP/tree/develop/model_zoo/uie
背景
之前的信息抽取做法:子任務(wù)實體抽取、關(guān)系抽取、事件抽取和情感分析分開抽取,如a。本文要做的是聯(lián)合抽取,如b
信息抽取語言
作者自定義了結(jié)構(gòu)化的信息抽取語言SEL:結(jié)構(gòu)如下
((定位:實體或觸發(fā)等
(關(guān)系或角色:實體或觸發(fā)等)
(關(guān)系或角色:實體或觸發(fā)等)))
文章實例:輸入句子“Steve became CEO of Apple in 1997.”,則藍色表示關(guān)系抽取,紅色表示事件抽取,剩余的是實體抽取。例如,紅色部分事件的觸發(fā)詞是became,雇員是Steve,雇主是Apple,時間是1997年
上圖就是UIE模型的三大聯(lián)合抽取任務(wù),左邊就是輸入數(shù)據(jù)結(jié)構(gòu),右邊就是預(yù)測數(shù)據(jù)結(jié)構(gòu),那么模型是如何訓(xùn)練和預(yù)測的呢?重點就是定義損失函數(shù)(見下小節(jié))。
需要注意的是,這里的輸入數(shù)據(jù)由SSI+Text表示,其中SSI(Structural Schema Instructor)是指結(jié)構(gòu)模式指引,就是提示哪些類型的數(shù)據(jù)需要被定位和關(guān)聯(lián),例如“[spot] person [spot] company [asso] work for [text]”表示需要從句子中提取關(guān)系模式為“該人為公司工作”,此時,根據(jù)SSI提示,UIE模型會對文本test進行編碼,再通過編碼器-解碼器式的架構(gòu)生成SEL語言的目標記錄y
注:(4)式中的h(d)(i)是解碼器狀態(tài),就是用解碼器生成y
損失函數(shù)定義
作者定義了三個重要的損失函數(shù):
介紹損失函數(shù)之前,作者介紹了他們使用的數(shù)據(jù)集是知識庫(結(jié)構(gòu)化數(shù)據(jù))、文本(非結(jié)構(gòu)化數(shù)據(jù))和維基百科(并行數(shù)據(jù))來預(yù)訓(xùn)練UIE模型,并按需微調(diào)使預(yù)訓(xùn)練的UIE模型適應(yīng)特定的下游IE任務(wù)。簡單講,就是UIE的通用性比較強,可以適應(yīng)大多數(shù)場景的信息抽取任務(wù),實在厲害。
詳細結(jié)構(gòu)一下數(shù)據(jù)集:
數(shù)據(jù)集1:Dpair是文本x-結(jié)構(gòu)y對的并行數(shù)據(jù)集,通過維基百科搜集,用于預(yù)訓(xùn)練UIE對文本test轉(zhuǎn)換為結(jié)構(gòu)structure的能力。例如 “[spot] person [asso] work for [text]Steve became CEO of Apple in 1997.-((person: Steve(work for: Apple)))”;
數(shù)據(jù)集2:Drecord是結(jié)構(gòu)化數(shù)據(jù)集,每一條數(shù)據(jù)就是結(jié)構(gòu)y,用于預(yù)訓(xùn)練UIE的結(jié)構(gòu)解碼能力。例如“((person: Steve(work for: Apple)))”
數(shù)據(jù)集3:Dtext是非結(jié)構(gòu)化數(shù)據(jù)集,來自英語維基百科所有純文本,用于預(yù)訓(xùn)練UIE的語義編碼能力
了解了數(shù)據(jù)集,下面就是重要的損失函數(shù)設(shè)計了。
1、第一個損失函數(shù)是:Lpair,用于訓(xùn)練模型對文本到結(jié)構(gòu)的映射能力。
簡單理解就是對生成的token加個損失。作者這里還加了一個技巧,在已有正樣本的
的同時構(gòu)造了負樣本
ss是指spots,sa是指association,負樣本的添加可以讓模型學(xué)習(xí)一般的映射能力。
舉個例子,正樣本是“((person: Steve(work for: Apple)))”,負樣本是“((vehicle: Steve(located in: Apple)))”
2、第二個損失函數(shù)是:Lrecord,用于訓(xùn)練模型對SEL結(jié)構(gòu)的生成能力。
這里用了UIE的decoder解碼器作為結(jié)構(gòu)化語言模型,在數(shù)據(jù)集2 Drecord做預(yù)訓(xùn)練,相當于一個自回歸損失,通過對結(jié)構(gòu)生成的預(yù)訓(xùn)練,解碼器可以捕捉到SEL的規(guī)律性和不同標簽之間的相互作用。
3、第三個損失函數(shù)是:Ltext,作者把這個損失叫做改善語義表征(Retrofitting Semantic Representation)。
這里就是一個MLM task,一個類似于bert的語言屏蔽模型任務(wù),如果想具體了解參考論文:Exploring the limits of transfer learning with a unified text-to-text transformer
作者認為這個損失的加入可以緩解對SPOTNAME和ASSONAME標記語義的災(zāi)難性遺忘(可以參考bert MLM任務(wù))
至此,總損失就是上面三個損失相加:
實驗與結(jié)論
作者采用了13個典型的IE數(shù)據(jù)集進行了實驗,涉及了4個具有代表性的IE任務(wù)(包括實體提取、關(guān)系提取、事件提取、結(jié)構(gòu)化情感提?。┘捌浣M合(例如,聯(lián)合實體-關(guān)系提?。?,實驗結(jié)果很驚人(非常好了)
上圖是UIE-base模型在13個典型數(shù)據(jù)集上達到的效果。SEL指的是沒有經(jīng)過預(yù)訓(xùn)練的UIE,直接使用T5-v1.1-large的效果,而經(jīng)過預(yù)訓(xùn)練的UIE效果基本上都提升了。
對小樣本數(shù)據(jù)集的實驗(Experiments on Low-resource Settings):目的是驗證UIE的快速適應(yīng)能力。作者對原始訓(xùn)練集進行了6種采樣,前三種分別是1/5/10shot(就是在少量的實驗中,我們對訓(xùn)練集中的每個實體/關(guān)系/事件/情感類型的1/5/10句子進行抽樣),后三種是直接1/5/10%的比例下采樣。
用上面6種方式分別對4個任務(wù)中低資源實驗,為了避免隨機抽樣的影響,作者對不同的樣本重復(fù)每個實驗10次,結(jié)果如下:
作者還比較了四種模型的效果。其中,1)T5-v1.1-base是UIE-base的初始化模型;2)Fine-tuned T5-base是微調(diào)的T5-base模型,這個模型是用與序列生成任務(wù)(如摘要)經(jīng)過微調(diào)的模型,這在許多低資源的NLP任務(wù)中被證明是有效的(把它拿出來對比,說明UIE比這個通用的T5還要強);3)UIEbase w/o SSI是UIE的有監(jiān)督版本,就是說在預(yù)訓(xùn)練階段沒有SSI(把它拿出來做對比是為了驗證SSI在小樣本低資源下對適應(yīng)UIE的必要性)
直接看上圖吧,很好的展示出了UIE-base的不錯效果。
作者重點說明了UIE模型的優(yōu)點:1)在與沒有SSI的UIE模型相比,配備SSI的UIE在n-shot和n-ratio實驗中平均取得了4.16和3.30的改進。2)我們的預(yù)訓(xùn)練算法可以學(xué)習(xí)一般的IE能力,而不是捕捉特定的任務(wù)信息。 與只有少量樣本的baseline相比,即使UIE的預(yù)訓(xùn)練中沒有事件和情感相關(guān)知識,UIE在這些任務(wù)上仍然取得了明顯更好的性能。
表4顯示了UIE-base在四個下游任務(wù)上的消融實驗結(jié)果,目的是研究不同預(yù)訓(xùn)練任務(wù)的效果:
上表說明1)預(yù)訓(xùn)練LPair和Lrecord對于UIE-base至關(guān)重要;在小數(shù)據(jù)集CoNLL04和16res上 2)使用掩碼語言模型任務(wù)LText進行語義改造對于復(fù)雜的提取任務(wù)更為重要。33種類型的事件提取在去除LText文本任務(wù)后性能從72.63下降到70.89。3)用LPair進行映射預(yù)訓(xùn)練使模型能夠?qū)W習(xí)提取的能力。消減LPair后,UIE的提取能力明顯下降。
表5展示了生成錯誤標簽與不生成錯誤標簽(負樣本)對模型的影響。
結(jié)論
作者提出了一個統(tǒng)一的文本到結(jié)構(gòu)生成框架 , 即 UIE , 可以普遍地模擬不同的 信息抽取(IE)任務(wù) , 自適應(yīng)地生成目標結(jié)構(gòu) , 并能不厭煩得從不同的知識數(shù)據(jù)源中學(xué)習(xí)通用的 IE 能力。作者認為,UIE在有監(jiān)督和低資源環(huán)境下都取得了非常有競爭力的性能,這驗證了其普遍性、有效性和可轉(zhuǎn)移性。一個大規(guī)模的預(yù)訓(xùn)練文本-結(jié)構(gòu)模型的發(fā)布有利于未來的研究。對于未來的工作 , 他們希望將 UIE 擴展到 KB 感知的 IE 任務(wù)種 , 如實體鏈接 ( Cao 等人 , 2021 ) , 以及文檔感知的 IE 任務(wù) , 如co-reference( Lee 等人 , 2017 ; Lu 等人 , 2022 ) 。
UIE實戰(zhàn)
實戰(zhàn)一:Paddlenlp之UIE模型實戰(zhàn)實體抽取任務(wù)【打車數(shù)據(jù)、快遞單】
本項目將演示如何通過小樣本進行模型微調(diào),快速且準確抽取快遞單中的目的地、出發(fā)地、時間、打車費用等內(nèi)容,形成結(jié)構(gòu)化信息。輔助物流行業(yè)從業(yè)者進行有效信息的提取,從而降低客戶填單的成本。其他信息抽取項目也可用此項目思想來做。
先看一下結(jié)果展示:
輸入:
城市內(nèi)交通費7月5日金額114廣州至佛山
從百度大廈到龍澤苑東區(qū)打車費二十元
上海虹橋高鐵到杭州時間是9月24日費用是73元
上周末坐動車從北京到上海花費五十塊五毛
昨天北京飛上海話費一百元
輸出:
{"出發(fā)地": [{"text": "廣州", "start": 15, "end": 17, "probability": 0.9073772252165782}], "目的地": [{"text": "佛山", "start": 18, "end": 20, "probability": 0.9927365183877761}], "時間": [{"text": "7月5日", "start": 6, "end": 10, "probability": 0.9978010396512218}]}
{"出發(fā)地": [{"text": "百度大廈", "start": 1, "end": 5, "probability": 0.968825147409472}], "目的地": [{"text": "龍澤苑東區(qū)", "start": 6, "end": 11, "probability": 0.9877913072493669}]}
{"目的地": [{"text": "杭州", "start": 7, "end": 9, "probability": 0.9929172180094881}], "時間": [{"text": "9月24日", "start": 12, "end": 17, "probability": 0.9953342057701597}]}
{"出發(fā)地": [{"text": "北京", "start": 7, "end": 9, "probability": 0.973048366717471}], "目的地": [{"text": "上海", "start": 10, "end": 12, "probability": 0.988486130309397}], "時間": [{"text": "上周末", "start": 0, "end": 3, "probability": 0.9977407699595275}]}
{"出發(fā)地": [{"text": "北京", "start": 2, "end": 4, "probability": 0.974188953533556}], "目的地": [{"text": "上海", "start": 5, "end": 7, "probability": 0.9928200521486445}], "時間": [{"text": "昨天", "start": 0, "end": 2, "probability": 0.9731559534465504}]}
1、先升級paddlenlp
! pip install --upgrade paddlenlp
2、數(shù)據(jù)集加載(快遞單數(shù)據(jù)、打車數(shù)據(jù))
2.1 使用doccano進行數(shù)據(jù)標注,將標注好的數(shù)據(jù)放到data文件夾中
# ! wget https://paddlenlp.bj.bcebos.com/uie/datasets/waybill.jsonl
# ! mv waybill.jsonl ./data/
# ! mv doccano_ext.jsonl ./data/
# ! mv dev_test.jsonl ./data/
數(shù)據(jù)集情況:
waybill.jsonl文件是快遞單信息數(shù)據(jù)集:
{"id": 57, "text": "昌勝遠黑龍江省哈爾濱市南崗區(qū)寬橋街28號18618391296", "relations": [], "entities": [{"id": 111, "start_offset": 0, "end_offset": 3, "label": "姓名"}, {"id": 112, "start_offset": 3, "end_offset": 7, "label": "省份"}, {"id": 113, "start_offset": 7, "end_offset": 11, "label": "城市"}, {"id": 114, "start_offset": 11, "end_offset": 14, "label": "縣區(qū)"}, {"id": 115, "start_offset": 14, "end_offset": 20, "label": "詳細地址"}, {"id": 116, "start_offset": 20, "end_offset": 31, "label": "電話"}]} {"id": 58, "text": "易穎18500308469山東省煙臺市萊陽市富水南路1號", "relations": [], "entities": [{"id": 118, "start_offset": 0, "end_offset": 2, "label": "姓名"}, {"id": 119, "start_offset": 2, "end_offset": 13, "label": "電話"}, {"id": 120, "start_offset": 13, "end_offset": 16, "label": "省份"}, {"id": 121, "start_offset": 16, "end_offset": 19, "label": "城市"}, {"id": 122, "start_offset": 19, "end_offset": 22, "label": "縣區(qū)"}, {"id": 123, "start_offset": 22, "end_offset": 28, "label": "詳細地址"}]}
doccano_ext.jsonl是打車數(shù)據(jù)集:
{"id": 1, "text": "昨天晚上十點加班打車回家58元", "relations": [], "entities": [{"id": 0, "start_offset": 0, "end_offset": 6, "label": "時間"}, {"id": 1, "start_offset": 11, "end_offset": 12, "label": "目的地"}, {"id": 2, "start_offset": 12, "end_offset": 14, "label": "費用"}]} {"id": 2, "text": "三月三號早上12點46加班,到公司54", "relations": [], "entities": [{"id": 3, "start_offset": 0, "end_offset": 11, "label": "時間"}, {"id": 4, "start_offset": 15, "end_offset": 17, "label": "目的地"}, {"id": 5, "start_offset": 17, "end_offset": 19, "label": "費用"}]} {"id": 3, "text": "8月31號十一點零四工作加班五十塊錢", "relations": [], "entities": [{"id": 6, "start_offset": 0, "end_offset": 10, "label": "時間"}, {"id": 7, "start_offset": 14, "end_offset": 16, "label": "費用"}]} {"id": 4, "text": "5月17號晚上10點35分加班打車回家,36塊五", "relations": [], "entities": [{"id": 8, "start_offset": 0, "end_offset": 13, "label": "時間"}, {"id": 1, "start_offset": 18, "end_offset": 19, "label": "目的地"}, {"id": 9, "start_offset": 20, "end_offset": 24, "label": "費用"}]} {"id": 5, "text": "2009年1月份通訊費一百元", "relations": [], "entities": [{"id": 10, "start_offset": 0, "end_offset": 7, "label": "時間"}, {"id": 11, "start_offset": 11, "end_offset": 13, "label": "費用"}]}
2.2 轉(zhuǎn)換doccano標注數(shù)據(jù)集為uie格式的標注數(shù)據(jù)
!python doccano.py \
--doccano_file ./data/doccano_ext.jsonl \
--task_type 'ext' \
--save_dir ./data \
--splits 0.8 0.1 0.1 \
--negative_ratio 5 \
--seed 1000
參數(shù)解釋:
doccano_file: 從doccano導(dǎo)出的數(shù)據(jù)標注文件。
save_dir: 訓(xùn)練數(shù)據(jù)的保存目錄,默認存儲在data目錄下。
negative_ratio: 最大負例比例,該參數(shù)只對抽取類型任務(wù)有效,適當構(gòu)造負例可提升模型效果。負例數(shù)量和實際的標簽數(shù)量有關(guān),最大負例數(shù)量 = negative_ratio * 正例數(shù)量。該參數(shù)只對訓(xùn)練集有效,默認為5。為了保證評估指標的準確性,驗證集和測試集默認構(gòu)造全負例。
splits: 劃分數(shù)據(jù)集時訓(xùn)練集、驗證集所占的比例。默認為[0.8, 0.1, 0.1]表示按照8:1:1的比例將數(shù)據(jù)劃分為訓(xùn)練集、驗證集和測試集。
task_type: 選擇任務(wù)類型,可選有抽取和分類兩種類型的任務(wù)。
options: 指定分類任務(wù)的類別標簽,該參數(shù)只對分類類型任務(wù)有效。默認為[“正向”, “負向”]。
prompt_prefix: 聲明分類任務(wù)的prompt前綴信息,該參數(shù)只對分類類型任務(wù)有效。默認為"情感傾向"。
is_shuffle: 是否對數(shù)據(jù)集進行隨機打散,默認為True。
seed: 隨機種子,默認為1000.
*separator: 實體類別/評價維度與分類標簽的分隔符,該參數(shù)只對實體/評價維度級分類任務(wù)有效。默認為"##"。
3、訓(xùn)練UIE模型
!python finetune.py \
--train_path "./data/train.txt" \
--dev_path "./data/dev.txt" \
--save_dir "./checkpoint" \
--learning_rate 1e-5 \
--batch_size 8 \
--max_seq_len 512 \
--num_epochs 100 \
--model "uie-base" \
--seed 1000 \
--logging_steps 10 \
--valid_steps 50 \
--device "gpu"
使用標注數(shù)據(jù)進行小樣本訓(xùn)練,模型參數(shù)保存在./checkpoint/目錄。
推薦使用GPU環(huán)境,否則可能會內(nèi)存溢出。CPU環(huán)境下,可以修改model為uie-tiny,適當調(diào)下batch_size。
增加準確率的話:–num_epochs 設(shè)置大點多訓(xùn)練訓(xùn)練
可配置參數(shù)說明:
train_path: 訓(xùn)練集文件路徑。
dev_path: 驗證集文件路徑。
save_dir: 模型存儲路徑,默認為./checkpoint。
learning_rate: 學(xué)習(xí)率,默認為1e-5。
batch_size: 批處理大小,請結(jié)合顯存情況進行調(diào)整,若出現(xiàn)顯存不足,請適當調(diào)低這一參數(shù),默認為16。
max_seq_len: 文本最大切分長度,輸入超過最大長度時會對輸入文本進行自動切分,默認為512。
num_epochs: 訓(xùn)練輪數(shù),默認為100。
model 選擇模型,程序會基于選擇的模型進行模型微調(diào),可選有uie-base和uie-tiny,默認為uie-base。
seed: 隨機種子,默認為1000.
logging_steps: 日志打印的間隔steps數(shù),默認10。
valid_steps: evaluate的間隔steps數(shù),默認100。
device: 選用什么設(shè)備進行訓(xùn)練,可選cpu或gpu。
4、評估UIE模型
!python evaluate.py \
--model_path ./checkpoint/model_best \
--test_path ./data/test.txt \
--batch_size 16 \
--max_seq_len 512
!python evaluate.py \
--model_path ./checkpoint/model_best \
--test_path ./data/test.txt \
--debug
可配置參數(shù)說明:
model_path: 進行評估的模型文件夾路徑,路徑下需包含模型權(quán)重文件model_state.pdparams及配置文件model_config.json。
test_path: 進行評估的測試集文件。
batch_size: 批處理大小,請結(jié)合機器情況進行調(diào)整,默認為16。
max_seq_len: 文本最大切分長度,輸入超過最大長度時會對輸入文本進行自動切分,默認為512。
model: 選擇所使用的模型,可選有uie-base, uie-medium, uie-mini, uie-micro和uie-nano,默認為uie-base。
debug: 是否開啟debug模式對每個正例類別分別進行評估,該模式僅用于模型調(diào)試,默認關(guān)閉。
5、結(jié)果預(yù)測
from pprint import pprint
import json
from paddlenlp import Taskflow
def openreadtxt(file_name):
data = []
file = open(file_name,'r',encoding='UTF-8')
file_data = file.readlines()
for row in file_data:
data.append(row)
return data
data_input=openreadtxt('./input/text1.txt')
schema = ['出發(fā)地', '目的地','時間']
few_ie = Taskflow('information_extraction', schema=schema, batch_size=1, task_path='./checkpoint/model_best') #task_path為訓(xùn)練好的模型位置
results=few_ie(data_input)
with open("./output/test.txt", "w+",encoding='UTF-8') as f:
for result in results:
line = json.dumps(result, ensure_ascii=False) #對中文默認使用的ascii編碼,想輸出真正的中文需要指定ensure_ascii=False
f.write(line + "\n")
print("數(shù)據(jù)結(jié)果已導(dǎo)出")
text1輸入文件展示:
城市內(nèi)交通費7月5日金額114廣州至佛山
從百度大廈到龍澤苑東區(qū)打車費二十元
上海虹橋高鐵到杭州時間是9月24日費用是73元
上周末坐動車從北京到上?;ㄙM五十塊五毛
昨天北京飛上海話費一百元
輸出展示:
{"出發(fā)地": [{"text": "廣州", "start": 15, "end": 17, "probability": 0.9073772252165782}], "目的地": [{"text": "佛山", "start": 18, "end": 20, "probability": 0.9927365183877761}], "時間": [{"text": "7月5日", "start": 6, "end": 10, "probability": 0.9978010396512218}]}
{"出發(fā)地": [{"text": "百度大廈", "start": 1, "end": 5, "probability": 0.968825147409472}], "目的地": [{"text": "龍澤苑東區(qū)", "start": 6, "end": 11, "probability": 0.9877913072493669}]}
{"目的地": [{"text": "杭州", "start": 7, "end": 9, "probability": 0.9929172180094881}], "時間": [{"text": "9月24日", "start": 12, "end": 17, "probability": 0.9953342057701597}]}
{"出發(fā)地": [{"text": "北京", "start": 7, "end": 9, "probability": 0.973048366717471}], "目的地": [{"text": "上海", "start": 10, "end": 12, "probability": 0.988486130309397}], "時間": [{"text": "上周末", "start": 0, "end": 3, "probability": 0.9977407699595275}]}
{"出發(fā)地": [{"text": "北京", "start": 2, "end": 4, "probability": 0.974188953533556}], "目的地": [{"text": "上海", "start": 5, "end": 7, "probability": 0.9928200521486445}], "時間": [{"text": "昨天", "start": 0, "end": 2, "probability": 0.9731559534465504}]}
實戰(zhàn)二:Paddlenlp之UIE模型實戰(zhàn)實體抽取任務(wù)【產(chǎn)品型號、品牌、數(shù)量等信息識別】
1、需求背景
信息抽取類任務(wù)是近幾年工業(yè)上應(yīng)用比較廣泛的技術(shù)。電商行業(yè)中電子商城會根據(jù)客戶訂單信息來查詢和匹配客戶的具體需求,例如服裝類電商會匹配客戶需求的服裝品類、顏色、尺寸、數(shù)量等。原始的做法是用人工識別、或者簡單的正則匹配來去提取特征,再到數(shù)據(jù)庫中查詢符合客戶需求的產(chǎn)品型號等信息,人工智能席卷工業(yè)界后,電商逐漸引進深度學(xué)習(xí)技術(shù)來替代傳統(tǒng)的人工、機器學(xué)習(xí)等方法。本實戰(zhàn)的背景是為解決電子元器件領(lǐng)域電商平臺對用戶提交的訂單進行產(chǎn)品型號等信息識別的需求。用到的模型有:ERNIE\UIE、SBERT對比學(xué)習(xí)等。
2、結(jié)果展示
輸入:
['LTC4425IDD#TRPBF ADI 44', 'LTC4380HDD-4#TRPBF ADI 2500', 'LT8652SEV#PBF ADI;LINEAR 105']
輸出:
[{'品牌': [{'end': 20, 'probability': 0.9998956, 'start': 17, 'text': 'ADI'}],
'型號': [{'end': 16,
'probability': 0.99998116,
'start': 0,
'text': 'LTC4425IDD#TRPBF'}],
'數(shù)量': [{'end': 23, 'probability': 0.9997663, 'start': 21, 'text': '44'}]},
{'品牌': [{'end': 22, 'probability': 0.99987614, 'start': 19, 'text': 'ADI'}],
'型號': [{'end': 18,
'probability': 0.9999769,
'start': 0,
'text': 'LTC4380HDD-4#TRPBF'}],
'數(shù)量': [{'end': 27, 'probability': 0.9997887, 'start': 23, 'text': '2500'}]},
{'品牌': [{'end': 24,
'probability': 0.99944764,
'start': 14,
'text': 'ADI;LINEAR'}],
'型號': [{'end': 13,
'probability': 0.99997973,
'start': 0,
'text': 'LT8652SEV#PBF'}],
'數(shù)量': [{'end': 28, 'probability': 0.9996749, 'start': 25, 'text': '105'}]}]
3、訓(xùn)練環(huán)境配置(需升級paddlenlp,否則報錯)
# 升級paddlenlp。如果報錯還需卸載和重新安裝paddlepaddle:pip install paddlepaddle==2.4.0rc0
!pip install --upgrade paddlenlp
4、數(shù)據(jù)集加載
步驟一:用doccano標注平臺進行標注數(shù)據(jù)(本項目共標注了3萬條數(shù)據(jù))
doccano標注后下載數(shù)據(jù)文件:doccano_3w_1.json
步驟二:轉(zhuǎn)換標注數(shù)據(jù)集為uie訓(xùn)練的數(shù)據(jù)格式
python doccano.py --doccano_file ./work/doccano_3w_1.json --task_type ext --save_dir ./work/data3w_1 --splits 0.8 0.2 0
建議將數(shù)據(jù)保存在work文件夾,如果放在data文件夾下,飛槳會定期刪除;可直接用于訓(xùn)練的標準數(shù)據(jù)集下載地址:https://aistudio.baidu.com/bj-cpu-01/user/4707772/6147417/lab/tree/work/data3w(建議用doccano平臺標注或用腳本生成所需的數(shù)據(jù)集,以便熟悉整個流程)
5、訓(xùn)練模型
# 設(shè)定訓(xùn)練好的最佳模型存儲路徑
export finetuned_model=./checkpoint/model_best
# 訓(xùn)練模型
python finetune.py \
--device gpu \
--logging_steps 10 \
--save_steps 100 \
--eval_steps 100 \
--seed 42 \
--model_name_or_path uie-base \
--output_dir $finetuned_model \
--train_path work/data3w_1/train.txt \
--dev_path work/data3w_1/dev.txt \
--max_seq_length 128 \
--per_device_eval_batch_size 4 \
--per_device_train_batch_size 4 \
--num_train_epochs 10 \
--learning_rate 1e-5 \
--label_names 'start_positions' 'end_positions' \
--do_train \
--export_model_dir $finetuned_model \
--overwrite_output_dir \
--disable_tqdm True \
--metric_for_best_model eval_f1 \
--save_total_limit 1
調(diào)參說明:
1)微調(diào)時間:3w多條數(shù)據(jù),V100 32G GPU環(huán)境大概需要6個多小時執(zhí)行完成
2)num_train_epochs 為1效果不好,10還可以(型號識別率70%),硬件條件好的話設(shè)置30以上
3)batch_size = 16效果不好。改小batch_size =4后,效果型號提升到21%,品牌提升到32%,數(shù)量下降到72%,總體提升10%
4)epochs為20輪出現(xiàn)過擬合,效果不如10輪好
5)改動學(xué)習(xí)率lr 效果不明顯,建議默認1e-5
6)改用改用uie-nano、uie-m-base后均出現(xiàn)效果下降現(xiàn)象
7)默認max_seq_length為512,改小max_seq_length =128后,效果有明顯提升,一些識別不出的品牌、數(shù)量可以識別出。建議根據(jù)需要識別的單條文本長度調(diào)整,即按項目實際情況調(diào)整
6、模型評估
直接在notebook上或用腳本調(diào)用模型來進行預(yù)測,代碼如下:
# 模型預(yù)測
from pprint import pprint
from paddlenlp import Taskflow
import time
import pandas as pd
# 時間1
old_time = time.time()
f = pd.read_csv('./work/test.csv', encoding='gbk') #70條測試數(shù)據(jù)
texts = f['輸入'][:70].values.tolist()
print(texts)
schema1 = ['型號','品牌','數(shù)量','價格','批次','封裝','分類','尺寸','阻值','精度','功率','溫度系數(shù)','容值','電壓','等效串聯(lián)電阻','電感值','電流','直流電阻','Q值','等級','主頻','IO數(shù)量','電壓范圍','溫度范圍','內(nèi)核','直流反向耐壓','平均整流電流','正向壓降','反向電流','替代型號','替代品牌']
ie = Taskflow('information_extraction', schema=schema1, task_path='./checkpoint/model_best')
current_time = time.time()
print("數(shù)據(jù)模型載入運行時間為" + str(current_time - old_time) + "s")
#時間2
old_time1 = time.time()
results=ie(texts)
current_time1 = time.time()
print("模型計算運行時間為" + str(current_time1 - old_time1) + "s")
#時間3
old_time2 = time.time()
with open('./test_result.txt', 'w+', encoding='utf-8') as f:
f.write(str(results))
pprint(results)
current_time2 = time.time()
print("數(shù)據(jù)導(dǎo)出運行時間為" + str(current_time2 - old_time2) + "s")
預(yù)測結(jié)果展示(部分):
總耗時2783.4346766471863s
[{'IO數(shù)量': [{'end': 19,
'probability': 0.9993238283852008,
'start': 14,
'text': '50000'}],
'功率': [{'end': 13,
'probability': 0.440991799711405,
'start': 11,
'text': 'TI'}],
'反向電流': [{'end': 13,
'probability': 0.35759727639392835,
'start': 11,
'text': 'TI'}],
'品牌': [{'end': 13,
'probability': 0.9997595669970032,
'start': 11,
'text': 'TI'}],
'型號': [{'end': 10,
'probability': 0.9998958115887291,
'start': 0,
'text': 'TXB0108PWR'}],
'容值': [{'end': 13,
'probability': 0.6812789449635943,
'start': 11,
'text': 'TI'}],
'平均整流電流': [{'end': 13,
'probability': 0.5963570205261135,
'start': 11,
'text': 'TI'}],
'數(shù)量': [{'end': 19,
'probability': 0.9996966930740641,
'start': 14,
'text': '50000'}],
'替代品牌': [{'end': 13,
'probability': 0.9278777681837767,
'start': 11,
'text': 'TI'}],
'溫度范圍': [{'end': 13,
'probability': 0.426431107305703,
'start': 11,
'text': 'TI'}],
'直流電阻': [{'end': 13,
'probability': 0.37594026631118993,
'start': 11,
'text': 'TI'}],
'等效串聯(lián)電阻': [{'end': 13,
'probability': 0.49062035507806456,
'start': 11,
'text': 'TI'}],
'精度': [{'end': 13,
'probability': 0.3204111132783609,
'start': 11,
'text': 'TI'}],
'阻值': [{'end': 13,
'probability': 0.3574524486612276,
'start': 11,
'text': 'TI'}]},...]
7*、模型蒸餾(該部分取決于硬件條件,條件不好的建議閱讀,有足夠GPU資源的不用做此步驟,直接進行部署即可)
核心思想是采用離線蒸餾方式,首先獲取大規(guī)模無監(jiān)督數(shù)據(jù)(需同源保證分布與訓(xùn)練模型用的數(shù)據(jù)集一致),再用前面訓(xùn)練好的模型對這些無監(jiān)督數(shù)據(jù)進行預(yù)測,最后使用標注數(shù)據(jù)以及對無監(jiān)督數(shù)據(jù)的預(yù)測數(shù)據(jù)訓(xùn)練出封閉域Student Model。
步驟一:構(gòu)造離線蒸餾數(shù)據(jù)集
共需三個文件,第一個是無監(jiān)督文本unlabeled_data.txt,如下無監(jiān)督文本構(gòu)造很簡單,直接將用于模型訓(xùn)練的同源數(shù)據(jù)(原始未標注)取出一些即可,注意要根據(jù)硬件條件來確定無監(jiān)督文本條數(shù),建議給2000條以內(nèi)。本項目用的是飛槳AI Studio的V100 32G GPU,但為了減少耗時,還是只用了100條無監(jiān)督文本數(shù)據(jù);第二個文件是標注數(shù)據(jù)doccano_ext.json,如下
注意標注數(shù)據(jù)需要更改格式,變成離線蒸餾所需的格式(使用簡單腳本對doccano標注后的數(shù)據(jù)集doccano_3w_1.json進行修改即可,提供代碼:
# 將只標注實體轉(zhuǎn)換為實體+關(guān)系格式。格式轉(zhuǎn)換代碼僅供參考。
import re
import json
doccano_label = ['型號', '品牌', '數(shù)量', '價格', '批次']
entities2id = {}
with open(r'./doccano_ext.json', 'r', encoding='utf-8') as f:
content = f.readlines()
count = 0
entities_id = 70000
relations_id = 100
while count != len(content):
for line in content:
count += 1
outpath = r'./doccano_r_6w.json'
with open(outpath, 'a', encoding='utf-8') as f:
if eval(line)['text'] != '' and eval(line)['label'] != '':
line_b = line.split('label')[0]
line_l = {}
label_list = eval(line)['label']
entities_val = []
relations_val = []
ent2rel = {}
for label in label_list:
entity = {}
ent = eval(line)['text'][label[0]:label[1]]
if ent not in entities2id:
entities2id[ent] = entities_id
entities_id += 1
entity['id'] = entities2id[ent]
entity['label'] = label[2]
entity['start_offset'] = label[0]
entity['end_offset'] = label[1]
entities_val.append(entity)
if label[2] == '型號':
ent2rel['型號'] = entities2id[ent]
elif label[2] == '品牌':
ent2rel['品牌'] = entities2id[ent]
# # 創(chuàng)建關(guān)系
# if len(ent2rel) == 2: #只有一種關(guān)系:主動件。多種關(guān)系需調(diào)整
# relation = {}
# relation['id'] = relations_id
# relation['from_id'] = ent2rel['型號']
# relation['to_id'] = ent2rel['品牌']
# relation['type'] = '主動件'
# relations_val.append(relation)
# relations_id += 1
line_l['entities'] = entities_val
line_l['relations'] = relations_val
line_json = json.dumps(line_l, ensure_ascii=False)
line_l = re.sub(' ', '', str(line_json))
f.write(line_b[:-1] + line_l[1:])
f.write('\n')
#f.write('\n')
);第三個文件是訓(xùn)練采樣參數(shù)sample_index.json,記錄了訓(xùn)練和驗證數(shù)據(jù)的編號,此文件由前面數(shù)據(jù)集加載時產(chǎn)生,如下
步驟二:通過訓(xùn)練好的UIE定制模型預(yù)測無監(jiān)督數(shù)據(jù)的標簽
# 注意:無監(jiān)督文本unlabeled_data.txt不要太多,否則耗時太長,建議1000條以內(nèi)
cd /home/aistudio/data_distill
python data_distill.py \
--data_path /home/aistudio/work/data_distill_unlabel \
--save_dir student_data \
--task_type entity_extraction \
--synthetic_ratio 10 \
--model_path /home/aistudio/checkpoint_3w/model_best
可配置參數(shù)說明:
-
data_path
: 標注數(shù)據(jù)(doccano_ext.json
)及無監(jiān)督文本(unlabeled_data.txt
)路徑。 -
model_path
: 訓(xùn)練好的UIE定制模型路徑。 -
save_dir
: 學(xué)生模型訓(xùn)練數(shù)據(jù)保存路徑。 -
synthetic_ratio
: 控制合成數(shù)據(jù)的比例。最大合成數(shù)據(jù)數(shù)量=synthetic_ratio*標注數(shù)據(jù)數(shù)量。 -
task_type
: 選擇任務(wù)類型,可選有entity_extraction
,relation_extraction
,event_extraction
和opinion_extraction
。因為是封閉域信息抽取,需指定任務(wù)類型。 -
seed
: 隨機種子,默認為1000。
步驟三:老師模型評估
UIE微調(diào)階段針對UIE訓(xùn)練格式數(shù)據(jù)評估模型效果(該評估方式非端到端評估,不適合關(guān)系、事件等任務(wù)),可通過以下評估腳本針對原始標注格式數(shù)據(jù)評估模型效果
cd /home/aistudio/data_distill
python evaluate_teacher.py \
--task_type entity_extraction \
--test_path ./student_data/dev_data.json \
--label_maps_path ./student_data/label_maps.json \
--model_path /home/aistudio/checkpoint_3w/model_best \
--max_seq_len 128 #可以嘗試不加,查看256是否可以
可配置參數(shù)說明:
model_path: 訓(xùn)練好的UIE定制模型路徑。
test_path: 測試數(shù)據(jù)集路徑。
label_maps_path: 學(xué)生模型標簽字典。
batch_size: 批處理大小,默認為8。
max_seq_len: 最大文本長度,默認為256。
task_type: 選擇任務(wù)類型,可選有entity_extraction,relation_extraction,event_extraction和opinion_extraction。因為是封閉域信息抽取的評估,需指定任務(wù)類型。
結(jié)果展示:
aistudio@jupyter-3723932-5602938:~/data_distill$ python evaluate_teacher.py --task_type entity_extraction --test_path ./student_data/dev_data.json --label_maps_path ./student_data/label_maps.json --model_path /home/aistudio/checkpoint_3w/model_best --max_seq_len 128
[2023-04-03 10:28:41,140] [ INFO] - We are using <class 'paddlenlp.transformers.ernie.tokenizer.ErnieTokenizer'> to load '/home/aistudio/checkpoint_3w_1/model_best'.
[2023-04-03 10:28:41,164] [ INFO] - We are using <class 'paddlenlp.transformers.ernie.tokenizer.ErnieTokenizer'> to load 'ernie-3.0-base-zh'.
[2023-04-03 10:28:41,165] [ INFO] - Already cached /home/aistudio/.paddlenlp/models/ernie-3.0-base-zh/ernie_3.0_base_zh_vocab.txt
[2023-04-03 10:28:41,187] [ INFO] - tokenizer config file saved in /home/aistudio/.paddlenlp/models/ernie-3.0-base-zh/tokenizer_config.json
[2023-04-03 10:28:41,187] [ INFO] - Special tokens file saved in /home/aistudio/.paddlenlp/models/ernie-3.0-base-zh/special_tokens_map.json
[2023-04-03 10:37:01,468] [ INFO] - Evaluation precision: {'entity_f1': 0.4, 'entity_precision': 0.29412, 'entity_recall': 0.625}
步驟四:學(xué)生模型訓(xùn)練
# cd /home/aistudio/data_distill
# 可以改大epochs和batch_size嘗試效果
# 可以改encoder\warmup策略
# 注意先安裝python -m pip install paddlepaddle-gpu==2.4.2.post117 -f https://www.paddlepaddle.org.cn/whl/linux/mkl/avx/stable.html
python train.py \
--task_type entity_extraction \
--train_path student_data/train_data.json \
--dev_path student_data/dev_data.json \
--label_maps_path student_data/label_maps.json \
--num_epochs 10 \
--encoder ernie-3.0-mini-zh\
--device "gpu"\
--valid_steps 100\
--logging_steps 10\
--save_dir './checkpoint2'\
--batch_size 4 \
--max_seq_len 128
可配置參數(shù)說明:
train_path: 訓(xùn)練集文件路徑。
dev_path: 驗證集文件路徑。
batch_size: 批處理大小,默認為16。
learning_rate: 學(xué)習(xí)率,默認為3e-5。
save_dir: 模型存儲路徑,默認為./checkpoint。
max_seq_len: 最大文本長度,默認為256。
weight_decay: 表示AdamW優(yōu)化器中使用的 weight_decay 的系數(shù)。
warmup_proportion: 學(xué)習(xí)率warmup策略的比例,如果0.1,則學(xué)習(xí)率會在前10%訓(xùn)練step的過程中從0慢慢增長到learning_rate, 而后再緩慢衰減,默認為0.0。
num_epochs: 訓(xùn)練輪數(shù),默認為100。
seed: 隨機種子,默認為1000。
encoder: 選擇學(xué)生模型的模型底座,默認為ernie-3.0-mini-zh。
task_type: 選擇任務(wù)類型,可選有entity_extraction,relation_extraction,event_extraction和opinion_extraction。因為是封閉域信息抽取,需指定任務(wù)類型。
logging_steps: 日志打印的間隔steps數(shù),默認10。
valid_steps: evaluate的間隔steps數(shù),默認200。
device: 選用什么設(shè)備進行訓(xùn)練,可選cpu或gpu。
init_from_ckpt: 可選,模型參數(shù)路徑,熱啟動模型訓(xùn)練;默認為None。
注:底座模型encoder參數(shù)可以參考下面進行替換
Pretrained Weight Language Details of the model
ernie-1.0-base-zh Chinese 12-layer, 768-hidden, 12-heads, 108M parameters. Trained on Chinese text.
ernie-tiny Chinese 3-layer, 1024-hidden, 16-heads, _M parameters. Trained on Chinese text.
ernie-2.0-base-en English 12-layer, 768-hidden, 12-heads, 103M parameters. Trained on lower-cased English text.
ernie-2.0-base-en-finetuned-squad English 12-layer, 768-hidden, 12-heads, 110M parameters. Trained on finetuned squad text.
ernie-2.0-large-en English 24-layer, 1024-hidden, 16-heads, 336M parameters. Trained on lower-cased English text.
ernie-3.0-base-zh Chinese 12-layer, 768-hidden, 12-heads, 118M parameters. Trained on Chinese text.
ernie-3.0-medium-zh Chinese 6-layer, 768-hidden, 12-heads, 75M parameters. Trained on Chinese text.
ernie-3.0-mini-zh Chinese 6-layer, 384-hidden, 12-heads, 27M parameters. Trained on Chinese text.
ernie-3.0-micro-zh Chinese 4-layer, 384-hidden, 12-heads, 23M parameters. Trained on Chinese text.
ernie-3.0-nano-zh Chinese 4-layer, 312-hidden, 12-heads, 18M parameters. Trained on Chinese text.
rocketqa-base-cross-encoder Chinese 12-layer, 768-hidden, 12-heads, 118M parameters. Trained on DuReader retrieval text.
rocketqa-medium-cross-encoder Chinese 6-layer, 768-hidden, 12-heads, 75M parameters. Trained on DuReader retrieval text.
rocketqa-mini-cross-encoder Chinese 6-layer, 384-hidden, 12-heads, 27M parameters. Trained on DuReader retrieval text.
如果想用在線蒸餾技術(shù),參考:
https://github.com/PaddlePaddle/PaddleNLP/tree/develop/model_zoo/ernie-3.0
8、Taskflow部署學(xué)生模型以及性能測試
通過Taskflow一鍵部署封閉域信息抽取模型,task_path為學(xué)生模型路徑
注意:1)Schema 在閉域信息抽取中是固定的,無需再指定;2)建議將use_faster(默認為False)設(shè)定為True。可使用C++實現(xiàn)的高性能分詞算子FasterTokenizer進行文本預(yù)處理加速。前提是安裝FasterTokenizer庫后方可使用(pip install faster_tokenizer)
# 蒸餾后:學(xué)生模型評估
# 優(yōu)點:速度快、準確率接近教師模型
# 采用UIE FasterTokenizer 提速測試時間
from pprint import pprint
from paddlenlp import Taskflow
import time
import pandas as pd
# 時間1
old_time = time.time()
f = pd.read_csv('./work/test.csv', encoding='gbk')
texts = f['輸入'][:70].values.tolist()
ie = Taskflow('information_extraction', model="uie-data-distill-gp", task_path='./data_distill/checkpoint2/model_best',use_faster=True) # Schema 在閉域信息抽取中是固定的
# 時間1
current_time = time.time()
print("數(shù)據(jù)模型載入運行時間為" + str(current_time - old_time) + "s")
#時間2
old_time1 = time.time()
results=ie(texts)
current_time1 = time.time()
print("模型計算運行時間為" + str(current_time1 - old_time1) + "s")
#時間3
old_time2 = time.time()
with open('./pre_checkpoint_distill_wendy.txt', 'w+', encoding='utf-8') as f:
f.write(str(results))
pprint(results)
current_time2 = time.time()
print("數(shù)據(jù)導(dǎo)出運行時間為" + str(current_time2 - old_time2) + "s")
測試結(jié)果:文章來源:http://www.zghlxwxcb.cn/news/detail-459207.html
[2023-04-04 15:02:11,183] [ INFO] - We are using <class 'paddlenlp.transformers.ernie.tokenizer.ErnieTokenizer'> to load './data_distill/checkpoint2/model_best'.
數(shù)據(jù)模型載入運行時間為0.816422700881958s
模型計算運行時間為1.5694572925567627s
[{'品牌': [{'end': 20, 'probability': 0.9998956, 'start': 17, 'text': 'ADI'}],
'型號': [{'end': 16,
'probability': 0.99998116,
'start': 0,
'text': 'LTC4425IDD#TRPBF'}],
'數(shù)量': [{'end': 23, 'probability': 0.9997663, 'start': 21, 'text': '44'}]},...]
數(shù)據(jù)導(dǎo)出運行時間為2.251406669616699s
(下一篇介紹UIE在圖片文本中的信息抽取實戰(zhàn),如電子稅票中的信息抽取等應(yīng)用)文章來源地址http://www.zghlxwxcb.cn/news/detail-459207.html
到了這里,關(guān)于從UIE模型理解到UIE工業(yè)實戰(zhàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!