本项目链接:https:aistudio。baidu。comaistudioprojectdetail4157455?contributionType11。ERNIE1。0完成快递单信息抽取 命名实体识别是NLP中一项非常基础的任务,是信息提取、问答系统、句法分析、机器翻译等众多NLP任务的重要基础工具。命名实体识别的准确度,决定了下游任务的效果,是NLP中的一个基础问题。在NER任务提供了两种解决方案,一类LSTMGRUCRF,通过RNN类的模型来抽取底层文本的信息,而CRF(条件随机场)模型来学习底层Token之间的联系;另外一类是通过预训练模型,例如ERNIE,BERT模型,直接来预测Token的标签信息。 本项目将演示如何使用PaddleNLP语义预训练模型ERNIE完成从快递单中抽取姓名、电话、省、市、区、详细地址等内容,形成结构化信息。辅助物流行业从业者进行有效信息的提取,从而降低客户填单的成本。 在2017年之前,工业界和学术界对文本处理依赖于序列模型RecurrentNeuralNetwork(RNN)。 图1:RNN示意图 基于BiGRUCRF的快递单信息抽取项目介绍了如何使用序列模型完成快递单信息抽取任务。 近年来随着深度学习的发展,模型参数的数量飞速增长。为了训练这些参数,需要更大的数据集来避免过拟合。然而,对于大部分NLP任务来说,构建大规模的标注数据集非常困难(成本过高),特别是对于句法和语义相关的任务。相比之下,大规模的未标注语料库的构建则相对容易。为了利用这些数据,我们可以先从其中学习到一个好的表示,再将这些表示应用到其他任务中。最近的研究表明,基于大规模未标注语料库的预训练模型(PretrainedModels,PTM)在NLP任务上取得了很好的表现。 近年来,大量的研究表明基于大型语料库的预训练模型(PretrainedModels,PTM)可以学习通用的语言表示,有利于下游NLP任务,同时能够避免从零开始训练模型。随着计算能力的不断提高,深度模型的出现(即Transformer)和训练技巧的增强使得PTM不断发展,由浅变深。 图2:预训练模型一览,图片来源于:https:github。comthunlpPLMpapers 本示例展示了以ERNIE(EnhancedRepresentationthroughKnowledgeIntegration)为代表的预训练模型如何Finetune完成序列标注任务。!pipinstallupgradepaddlenlp下载并解压数据集frompaddle。utils。downloadimportgetpathfromurlURLhttps:paddlenlp。bj。bcebos。compaddlenlpdatasetswaybill。tar。gzgetpathfromurl(URL,。)查看预测的数据!headn5datatest。txtfromfunctoolsimportpartialimportpaddlefrompaddlenlp。datasetsimportMapDatasetfrompaddlenlp。dataimportStack,Tuple,Padfrompaddlenlp。transformersimportErnieTokenizer,ErnieForTokenClassificationfrompaddlenlp。metricsimportChunkEvaluatorfromutilsimportconvertexample,evaluate,predict,loaddict1。1加载自定义数据集 推荐使用MapDataset()自定义数据集。defloaddataset(datafiles):defread(datapath):withopen(datapath,r,encodingutf8)asfp:next(fp)Skipheaderforlineinfp。readlines():words,labelsline。strip()。split()wordswords。split(02)labelslabels。split(02)yieldwords,labelsifisinstance(datafiles,str):returnMapDataset(list(read(datafiles)))elifisinstance(datafiles,list)orisinstance(datafiles,tuple):return〔MapDataset(list(read(datafile)))fordatafileindatafiles〕Createdataset,tokenizeranddataloader。trainds,devds,testdsloaddataset(datafiles(。datatrain。txt,。datadev。txt,。datatest。txt))foriinrange(5):print(trainds〔i〕)(〔1,6,6,2,0,2,0,0,0,7,7,宣,荣,嗣,甘,肃,省,白,银,市,会,宁,县,河,畔,镇,十,字,街,金,海,超,市,西,行,5,0,米〕,〔TB,TI,TI,TI,TI,TI,TI,TI,TI,TI,TI,PB,PI,PI,A1B,A1I,A1I,A2B,A2I,A2I,A3B,A3I,A3I,A4B,A4I,A4I,A4I,A4I,A4I,A4I,A4I,A4I,A4I,A4I,A4I,A4I,A4I,A4I〕)(〔1,3,5,5,2,6,6,4,3,0,7,姜,骏,炜,云,南,省,德,宏,傣,族,景,颇,族,自,治,州,盈,江,县,平,原,镇,蜜,回,路,下,段〕,〔TB,TI,TI,TI,TI,TI,TI,TI,TI,TI,TI,PB,PI,PI,A1B,A1I,A1I,A2B,A2I,A2I,A2I,A2I,A2I,A2I,A2I,A2I,A2I,A3B,A3I,A3I,A4B,A4I,A4I,A4I,A4I,A4I,A4I,A4I〕)(〔内,蒙,古,自,治,区,赤,峰,市,阿,鲁,科,尔,沁,旗,汉,林,西,街,路,南,1,3,7,0,1,0,8,5,3,9,0,那,峥〕,〔A1B,A1I,A1I,A1I,A1I,A1I,A2B,A2I,A2I,A3B,A3I,A3I,A3I,A3I,A3I,A4B,A4I,A4I,A4I,A4I,A4I,TB,TI,TI,TI,TI,TI,TI,TI,TI,TI,TI,PB,PI〕)(〔广,东,省,梅,州,市,大,埔,县,茶,阳,镇,胜,利,路,1,3,6,0,1,3,2,8,1,7,3,张,铱〕,〔A1B,A1I,A1I,A2B,A2I,A2I,A3B,A3I,A3I,A4B,A4I,A4I,A4I,A4I,A4I,TB,TI,TI,TI,TI,TI,TI,TI,TI,TI,TI,PB,PI〕)(〔新,疆,维,吾,尔,自,治,区,阿,克,苏,地,区,阿,克,苏,市,步,行,街,1,0,号,1,5,8,1,0,7,8,9,3,7,8,慕,东,霖〕,〔A1B,A1I,A1I,A1I,A1I,A1I,A1I,A1I,A2B,A2I,A2I,A2I,A2I,A3B,A3I,A3I,A3I,A4B,A4I,A4I,A4I,A4I,A4I,TB,TI,TI,TI,TI,TI,TI,TI,TI,TI,TI,PB,PI,PI〕) 每条数据包含一句文本和这个文本中每个汉字以及数字对应的label标签。 之后,还需要对输入句子进行数据处理,如切词,映射词表id等。1。2数据处理 预训练模型ERNIE对中文数据的处理是以字为单位。PaddleNLP对于各种预训练模型已经内置了相应的tokenizer。指定想要使用的模型名字即可加载对应的tokenizer。 tokenizer作用为将原始输入文本转化成模型model可以接受的输入数据形式。 图3:ERNIE模型示意图 labelvocabloaddict(。datatag。dic)tokenizerErnieTokenizer。frompretrained(ernie1。0)transfuncpartial(convertexample,tokenizertokenizer,labelvocablabelvocab)trainds。map(transfunc)devds。map(transfunc)testds。map(transfunc)print(trainds〔0〕)(〔1,208,515,515,249,540,249,540,540,540,589,589,803,838,2914,1222,1734,244,368,797,99,32,863,308,457,2778,484,167,436,930,192,233,634,99,213,40,317,540,256,2〕,〔0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0〕,40,〔12,2,3,3,3,3,3,3,3,3,3,3,0,1,1,4,5,5,6,7,7,8,9,9,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12〕)1。3数据读入 使用paddle。io。DataLoader接口多线程异步加载数据。ignorelabel1batchifyfnlambdasamples,fnTuple(Pad(axis0,padvaltokenizer。padtokenid),inputidsPad(axis0,padvaltokenizer。padtokentypeid),tokentypeidsStack(),seqlenPad(axis0,padvalignorelabel)labels):fn(samples)trainloaderpaddle。io。DataLoader(datasettrainds,batchsize36,returnlistTrue,collatefnbatchifyfn)devloaderpaddle。io。DataLoader(datasetdevds,batchsize36,returnlistTrue,collatefnbatchifyfn)testloaderpaddle。io。DataLoader(datasettestds,batchsize36,returnlistTrue,collatefnbatchifyfn)1。4PaddleNLP一键加载预训练模型 快递单信息抽取本质是一个序列标注任务,PaddleNLP对于各种预训练模型已经内置了对于下游任务文本分类Finetune网络。以下教程以ERNIE为预训练模型完成序列标注任务。 paddlenlp。transformers。ErnieForTokenClassification()一行代码即可加载预训练模型ERNIE用于序列标注任务的finetune网络。其在ERNIE模型后拼接上一个全连接网络进行分类。 paddlenlp。transformers。ErnieForTokenClassification。frompretrained()方法只需指定想要使用的模型名称和文本分类的类别数即可完成定义模型网络。DefinethemodelnetwordanditslossmodelErnieForTokenClassification。frompretrained(ernie1。0,numclasseslen(labelvocab)) PaddleNLP不仅支持ERNIE预训练模型,还支持BERT、RoBERTa、Electra等预训练模型。下表汇总了目前PaddleNLP支持的各类预训练模型。您可以使用PaddleNLP提供的模型,完成文本分类、序列标注、问答等任务。同时我们提供了众多预训练模型的参数权重供用户使用,其中包含了二十多种中文语言模型的预训练权重。中文的预训练模型有bertbasechinese,bertwwmchinese,bertwwmextchinese,ernie1。0,ernietiny,gpt2basecn,robertawwmext,robertawwmextlarge,rbt3,rbtl3,chineseelectrabase,chineseelectrasmall,chinesexlnetbase,chinesexlnetmid,chinesexlnetlarge,unifiedtransformer12Lcn,unifiedtransformer12Lcnluge等。 更多预训练模型参考:PaddleNLPTransformerAPI。 更多预训练模型finetune下游任务使用方法,请参考:examples。1。5设置FineTune优化策略,模型配置 适用于ERNIEBERT这类Transformer模型的迁移优化学习率策略为warmup的动态学习率。 图4:动态学习率示意图 metricChunkEvaluator(labellistlabelvocab。keys(),suffixTrue)lossfnpaddle。nn。loss。CrossEntropyLoss(ignoreindexignorelabel)optimizerpaddle。optimizer。AdamW(learningrate2e5,parametersmodel。parameters())1。6模型训练与评估 模型训练的过程通常有以下步骤:从dataloader中取出一个batchdata将batchdata喂给model,做前向计算将前向计算结果传给损失函数,计算loss。将前向计算结果传给评价方法,计算评价指标。loss反向回传,更新梯度。重复以上步骤。 每训练一个epoch时,程序将会评估一次,评估当前模型训练的效果。step0forepochinrange(10):foridx,(inputids,tokentypeids,length,labels)inenumerate(trainloader):logitsmodel(inputids,tokentypeids)losspaddle。mean(lossfn(logits,labels))loss。backward()optimizer。step()optimizer。cleargrad()step1print(epoch:dstep:dloss:f(epoch,step,loss))evaluate(model,metric,devloader)paddle。save(model。statedict(),。ernieresultmodeld。pdparamsstep)model。savepretrained(。checkpoint)tokenizer。savepretrained(。checkpoint) 结果:epoch:9step:435loss:0。001102epoch:9step:436loss:0。001224epoch:9step:437loss:0。002693epoch:9step:438loss:0。022898epoch:9step:439loss:0。001355epoch:9step:440loss:0。001069epoch:9step:441loss:0。001204epoch:9step:442loss:0。001223epoch:9step:443loss:0。007524epoch:9step:444loss:0。001363epoch:9step:445loss:0。004732epoch:9step:446loss:0。001559epoch:9step:447loss:0。002389epoch:9step:448loss:0。002210epoch:9step:449loss:0。005183epoch:9step:450loss:0。001259evalprecision:0。994958recall:0。995795f1:0。9953761。7模型预测 训练保存好的模型,即可用于预测。如以下示例代码自定义预测数据,调用predict()函数即可一键预测。predspredict(model,testloader,testds,labelvocab)filepathernieresults。txtwithopen(filepath,w,encodingutf8)asfout:fout。write(。join(preds))Printsomeexamplesprint(Theresultshavebeensavedinthefile:s,someexamplesareshownbelow:filepath)print(。join(preds〔:10〕))Theresultshavebeensavedinthefile:ernieresults。txt,someexamplesareshownbelow:(黑龙江省,A1)(双鸭山市,A2)(尖山区,A3)(八马路与东平行路交叉口北40米,A4)(韦业涛,P)(18600009172,T)(广西壮族自治区,A1)(桂林市,A2)(雁山区,A3)(雁山镇西龙村老年活动中心,A4)(17610348888,T)(羊卓卫,P)(15652864561,T)(河南省,A1)(开封市,A2)(顺河回族区,A3)(顺河区公园路32号,A4)(赵本山,P)(河北省,A1)(唐山市,A2)(玉田县,A3)(无终大街159号,A4)(18614253058,T)(尚汉生,P)(台湾,A1)(台中市,A2)(北区,A3)(北区锦新街18号,A4)(18511226708,T)(蓟丽,P)(廖梓琪,P)(18514743222,T)(湖北省,A1)(宜昌市,A2)(长阳土家族自治县,A3)(贺家坪镇贺家坪村一组临河1号,A4)(江苏省,A1)(南通市,A2)(海门市,A3)(孝威村孝威路88号,A4)(18611840623,T)(计星仪,P)(17601674746,T)(赵春丽,P)(内蒙古自治区,A1)(乌兰察布市,A2)(凉城县,A3)(新建街,A4)(云南省,A1)(临沧市,A2)(耿马傣族佤族自治县,A3)(鑫源路法院对面,A4)(许贞爱,P)(18510566685,T)(四川省,A1)(成都市,A2)(双流区,A3)(东升镇北仓路196号,A4)(耿丕岭,P)(18513466161,T)2。0快递单信息抽取〔三〕:Ernie1。0至ErnieGramCRF改进算法 代码和链接以及项目都在下面链接,fork一下可以直接跑:项目连接:Ernie1。0至ErnieGramCRF改进算法 GRUCRFEvalbegin。。。step16loss:0。0000e00precision:0。9896recall:0。9948f1:0。9922121msstepstep26loss:0。0000e00precision:0。9896recall:0。9948f1:0。9922125msstepstep36loss:20。9767precision:0。9861recall:0。9895f1:0。9878123msstepstep46loss:0。0000e00precision:0。9805recall:0。9869f1:0。9837123msstepstep56loss:0。0000e00precision:0。9782recall:0。9843f1:0。9812122msstepstep66loss:0。0000e00precision:0。9740recall:0。9791f1:0。9765123msstepEvalsamples:192 Ernieepoch:8step:72loss:0。038532evalprecision:0。974124recall:0。981497f1:0。977796epoch:9step:73loss:0。031000epoch:9step:74loss:0。033214epoch:9step:75loss:0。034606epoch:9step:76loss:0。038763epoch:9step:77loss:0。033273epoch:9step:78loss:0。031058epoch:9step:79loss:0。028151epoch:9step:80loss:0。030707evalprecision:0。976608recall:0。983179f1:0。979883 ErnieGramepoch:8step:72loss:0。030066evalprecision:0。990764recall:0。992431f1:0。991597epoch:9step:73loss:0。023607epoch:9step:74loss:0。023326epoch:9step:75loss:0。022730epoch:9step:76loss:0。033801epoch:9step:77loss:0。026398epoch:9step:78loss:0。026028epoch:9step:79loss:0。021799epoch:9step:80loss:0。025259evalprecision:0。990764recall:0。992431f1:0。991597 ERNIECRF〔EVAL〕Precision:0。975793Recall:0。983179F1:0。979472〔TRAIN〕Epoch:9Step:73Loss:0。111980〔TRAIN〕Epoch:9Step:74Loss:0。152896〔TRAIN〕Epoch:9Step:75Loss:0。274099〔TRAIN〕Epoch:9Step:76Loss:0。294602〔TRAIN〕Epoch:9Step:77Loss:0。231813〔TRAIN〕Epoch:9Step:78Loss:0。225045〔TRAIN〕Epoch:9Step:79Loss:0。180734〔TRAIN〕Epoch:9Step:80Loss:0。171899〔EVAL〕Precision:0。975000Recall:0。984020F1:0。979489 ErnieGramCRF〔EVAL〕Precision:0。992437Recall:0。993272F1:0。992854〔TRAIN〕Epoch:9Step:73Loss:0。100207〔TRAIN〕Epoch:9Step:74Loss:0。189141〔TRAIN〕Epoch:9Step:75Loss:0。051093〔TRAIN〕Epoch:9Step:76Loss:0。230366〔TRAIN〕Epoch:9Step:77Loss:0。271885〔TRAIN〕Epoch:9Step:78Loss:0。342371〔TRAIN〕Epoch:9Step:79Loss:0。050146〔TRAIN〕Epoch:9Step:80Loss:0。257951〔EVAL〕Precision:0。990764Recall:0。992431F1:0。991597 结论:CRF在ERNIE上体现作用不大,主要是在传统处理nlp语言上有显著作用,可以避免标注偏置问题。