Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

通用信息抽取 UIE(Universal Information Extraction)

目录

1. 模型简介

UIE(Universal Information Extraction):Yaojie Lu等人在ACL-2022中提出了通用信息抽取统一框架UIE。该框架实现了实体抽取、关系抽取、事件抽取、情感分析等任务的统一建模,并使得不同任务间具备良好的迁移和泛化能力。为了方便大家使用UIE的强大能力,PaddleNLP借鉴该论文的方法,基于ERNIE 3.0知识增强预训练模型,训练并开源了首个中文通用信息抽取模型UIE。该模型可以支持不限定行业领域和抽取目标的关键信息抽取,实现零样本快速冷启动,并具备优秀的小样本微调能力,快速适配特定的抽取目标。

UIE的优势

  • 使用简单:用户可以使用自然语言自定义抽取目标,无需训练即可统一抽取输入文本中的对应信息。实现开箱即用,并满足各类信息抽取需求

  • 降本增效:以往的信息抽取技术需要大量标注数据才能保证信息抽取的效果,为了提高开发过程中的开发效率,减少不必要的重复工作时间,开放域信息抽取可以实现零样本(zero-shot)或者少样本(few-shot)抽取,大幅度降低标注数据依赖,在降低成本的同时,还提升了效果

  • 效果领先:开放域信息抽取在多种场景,多种任务上,均有不俗的表现。

2. 应用示例

UIE不限定行业领域和抽取目标,以下是一些零样本行业示例:

  • 医疗场景-专病结构化

image

  • 法律场景-判决书抽取

image

  • 金融场景-收入证明、招股书抽取

image

  • 公安场景-事故报告抽取

image

  • 旅游场景-宣传册、手册抽取

image

3. 开箱即用

paddlenlp.Taskflow提供通用信息抽取、评价观点抽取等能力,可抽取多种类型的信息,包括但不限于命名实体识别(如人名、地名、机构名等)、关系(如电影的导演、歌曲的发行时间等)、事件(如某路口发生车祸、某地发生地震等)、以及评价维度、观点词、情感倾向等信息。用户可以使用自然语言自定义抽取目标,无需训练即可统一抽取输入文本中的对应信息。实现开箱即用,并满足各类信息抽取需求

支持多场景信息抽取任务

  • 命名实体识别

    命名实体识别(Named Entity Recognition,简称NER),是指识别文本中具有特定意义的实体。在开放域信息抽取中,抽取的类别没有限制,用户可以自己定义。

    例如抽取的目标实体类型是"时间"、"选手"和"赛事名称", schema构造如下:

    ['时间', '选手', '赛事名称']
    

    预测:

    >>> from pprint import pprint
    >>> from paddlenlp import Taskflow
    
    >>> schema = ['时间', '选手', '赛事名称'] # Define the schema for entity extraction
    >>> ie = Taskflow('information_extraction', schema=schema)
    >>> pprint(ie("2月8日上午北京冬奥会自由式滑雪女子大跳台决赛中中国选手谷爱凌以188.25分获得金牌!")) # Better print results using pprint
    [{'时间': [{'end': 6,
              'probability': 0.9857378532924486,
              'start': 0,
              'text': '2月8日上午'}],
      '赛事名称': [{'end': 23,
                'probability': 0.8503089953268272,
                'start': 6,
                'text': '北京冬奥会自由式滑雪女子大跳台决赛'}],
      '选手': [{'end': 31,
              'probability': 0.8981548639781138,
              'start': 28,
              'text': '谷爱凌'}]}]

    例如抽取的目标实体类型是"肿瘤的大小"、"肿瘤的个数"、"肝癌级别"和"脉管内癌栓分级", schema构造如下:

    ['肿瘤的大小', '肿瘤的个数', '肝癌级别', '脉管内癌栓分级']
    

    在上例中我们已经实例化了一个Taskflow对象,这里可以通过set_schema方法重置抽取目标。

    预测:

    >>> schema = ['肿瘤的大小', '肿瘤的个数', '肝癌级别', '脉管内癌栓分级']
    >>> ie.set_schema(schema)
    >>> pprint(ie("(右肝肿瘤)肝细胞性肝癌(II-III级,梁索型和假腺管型),肿瘤包膜不完整,紧邻肝被膜,侵及周围肝组织,未见脉管内癌栓(MVI分级:M0级)及卫星子灶形成。(肿物1个,大小4.2×4.0×2.8cm)。"))
    [{'肝癌级别': [{'end': 20,
                'probability': 0.9243267447402701,
                'start': 13,
                'text': 'II-III级'}],
      '肿瘤的个数': [{'end': 84,
                'probability': 0.7538413804059623,
                'start': 82,
                'text': '1个'}],
      '肿瘤的大小': [{'end': 100,
                'probability': 0.8341128043459491,
                'start': 87,
                'text': '4.2×4.0×2.8cm'}],
      '脉管内癌栓分级': [{'end': 70,
                  'probability': 0.9083292325934664,
                  'start': 67,
                  'text': 'M0级'}]}]
  • 关系抽取

    关系抽取(Relation Extraction,简称RE),是指从文本中识别实体并抽取实体之间的语义关系,进而获取三元组信息,即<主体,谓语,客体>。

    例如以"竞赛名称"作为抽取主体,抽取关系类型为"主办方"、"承办方"和"已举办次数", schema构造如下:

    {
      '竞赛名称': [
        '主办方',
        '承办方',
        '已举办次数'
      ]
    }
    

    预测:

    >>> schema = {'竞赛名称': ['主办方', '承办方', '已举办次数']} # Define the schema for relation extraction
    >>> ie.set_schema(schema) # Reset schema
    >>> pprint(ie('2022语言与智能技术竞赛由中国中文信息学会和中国计算机学会联合主办,百度公司、中国中文信息学会评测工作委员会和中国计算机学会自然语言处理专委会承办,已连续举办4届,成为全球最热门的中文NLP赛事之一。'))
    [{'竞赛名称': [{'end': 13,
                'probability': 0.7825402622754041,
                'relations': {'主办方': [{'end': 22,
                                      'probability': 0.8421710521379353,
                                      'start': 14,
                                      'text': '中国中文信息学会'},
                                      {'end': 30,
                                      'probability': 0.7580801847701935,
                                      'start': 23,
                                      'text': '中国计算机学会'}],
                              '已举办次数': [{'end': 82,
                                        'probability': 0.4671295049136148,
                                        'start': 80,
                                        'text': '4届'}],
                              '承办方': [{'end': 39,
                                      'probability': 0.8292706618236352,
                                      'start': 35,
                                      'text': '百度公司'},
                                      {'end': 72,
                                      'probability': 0.6193477885474685,
                                      'start': 56,
                                      'text': '中国计算机学会自然语言处理专委会'},
                                      {'end': 55,
                                      'probability': 0.7000497331473241,
                                      'start': 40,
                                      'text': '中国中文信息学会评测工作委员会'}]},
                'start': 0,
                'text': '2022语言与智能技术竞赛'}]}]
  • 事件抽取

    事件抽取 (Event Extraction, 简称EE),是指从自然语言文本中抽取预定义的事件触发词和事件要素,组合为相应的结构化信息。

    例如抽取的目标是"地震"事件的"地震强度"、"时间"、"震中位置"和"震源深度"这些信息,schema构造如下:

    {
      '地震触发词': [
        '地震强度',
        '时间',
        '震中位置',
        '震源深度'
      ]
    }
    

    触发词的格式统一为XX触发词XX表示具体事件类型,上例中的事件类型是地震,则对应触发词为地震触发词

    预测:

    >>> schema = {'地震触发词': ['地震强度', '时间', '震中位置', '震源深度']} # Define the schema for event extraction
    >>> ie.set_schema(schema) # Reset schema
    >>> ie('中国地震台网正式测定:5月16日06时08分在云南临沧市凤庆县(北纬24.34度,东经99.98度)发生3.5级地震,震源深度10千米。')
    [{'地震触发词': [{'text': '地震', 'start': 56, 'end': 58, 'probability': 0.9987181623528585, 'relations': {'地震强度': [{'text': '3.5级', 'start': 52, 'end': 56, 'probability': 0.9962985320905915}], '时间': [{'text': '5月16日06时08分', 'start': 11, 'end': 22, 'probability': 0.9882578028575182}], '震中位置': [{'text': '云南临沧市凤庆县(北纬24.34度,东经99.98度)', 'start': 23, 'end': 50, 'probability': 0.8551415716584501}], '震源深度': [{'text': '10千米', 'start': 63, 'end': 67, 'probability': 0.999158304648045}]}}]}]
  • 评论观点抽取

    评论观点抽取,是指抽取文本中包含的评价维度、观点词。

    例如抽取的目标是文本中包含的评价维度及其对应的观点词和情感倾向,schema构造如下:

    {
      '评价维度': [
        '观点词',
        '情感倾向[正向,负向]'
      ]
    }
    

    预测:

    >>> schema = {'评价维度': ['观点词', '情感倾向[正向,负向]']} # Define the schema for opinion extraction
    >>> ie.set_schema(schema) # Reset schema
    >>> pprint(ie("店面干净,很清静,服务员服务热情,性价比很高,发现收银台有排队")) # Better print results using pprint
    [{'评价维度': [{'end': 20,
                'probability': 0.9817040258681473,
                'relations': {'情感倾向[正向,负向]': [{'probability': 0.9966142505350533,
                                              'text': '正向'}],
                              '观点词': [{'end': 22,
                                      'probability': 0.957396472711558,
                                      'start': 21,
                                      'text': '高'}]},
                'start': 17,
                'text': '性价比'},
              {'end': 2,
                'probability': 0.9696849569741168,
                'relations': {'情感倾向[正向,负向]': [{'probability': 0.9982153274927796,
                                              'text': '正向'}],
                              '观点词': [{'end': 4,
                                      'probability': 0.9945318044652538,
                                      'start': 2,
                                      'text': '干净'}]},
                'start': 0,
                'text': '店面'}]}]
  • 情感倾向分类

    句子级情感倾向分类,即判断句子的情感倾向是“正向”还是“负向”,schema构造如下:

    '情感倾向[正向,负向]'
    

    预测:

    >>> schema = '情感倾向[正向,负向]' # Define the schema for sentence-level sentiment classification
    >>> ie.set_schema(schema) # Reset schema
    >>> ie('这个产品用起来真的很流畅,我非常喜欢')
    [{'情感倾向[正向,负向]': [{'text': '正向', 'probability': 0.9988661643929895}]}]
  • 跨任务抽取

    例如在法律场景同时对文本进行实体抽取和关系抽取,schema可按照如下方式进行构造:

    [
      "法院",
      {
          "原告": [
              "委托代理人",
              "法定代表人"
          ]
      },
      {
          "被告": [
              "委托代理人",
              "法定代表人"
          ]
      }
    ]
    

    预测:

    >>> schema = ['法院', {'原告': '委托代理人'}, {'被告': '委托代理人'}]
    >>> ie.set_schema(schema)
    >>> pprint(ie("北京市海淀区人民法院\n民事判决书\n(199x)建初字第xxx号\n原告:张三。\n委托代理人李四,北京市 A律师事务所律师。\n被告:B公司,法定代表人王五,开发公司总经理。")) # Better print results using pprint
    [{'原告': [{'end': 37,
              'probability': 0.9955972637653154,
              'relations': {'委托代理人': [{'end': 46,
                                      'probability': 0.9835957661618089,
                                      'start': 44,
                                      'text': '李四'}]},
              'start': 35,
              'text': '张三'}],
      '法院': [{'end': 10,
              'probability': 0.9245885500450299,
              'start': 0,
              'text': '北京市海淀区人民法院'}],
      '被告': [{'end': 67,
              'probability': 0.9033652934762237,
              'relations': {'委托代理人': [{'end': 46,
                                      'probability': 0.3863244074945271,
                                      'start': 44,
                                      'text': '李四'}]},
              'start': 64,
              'text': 'B公司'}]}]

多模型选择,满足精度、速度要求

  • 模型选择

    模型 结构
    uie-tiny 6-layers, 768-hidden, 12-heads
    uie-base (默认) 12-layers, 768-hidden, 12-heads
    uie-medical-base 12-layers, 768-hidden, 12-heads
  • 使用UIE-Tiny进行预测

    >>> from paddlenlp import Taskflow
    
    >>> schema = ['时间', '选手', '赛事名称']
    >>> ie = Taskflow('information_extraction', schema=schema, model="uie-tiny")
    >>> ie("2月8日上午北京冬奥会自由式滑雪女子大跳台决赛中中国选手谷爱凌以188.25分获得金牌!")
    [{'时间': [{'text': '2月8日上午', 'start': 0, 'end': 6, 'probability': 0.9492842181233527}], '选手': [{'text': '谷爱凌', 'start': 28, 'end': 31, 'probability': 0.7277186614493836}], '赛事名称': [{'text': '北京冬奥会自由式滑雪女子大跳台决赛', 'start': 6, 'end': 23, 'probability': 0.8751028059367947}]}]

可配置参数说明

  • batch_size:批处理大小,请结合机器情况进行调整,默认为1。
  • model:选择任务使用的模型,默认为uie-base,可选有uie-tinyuie-baseuie-medical-base
  • schema:定义任务抽取目标,可参考示例中对于不同信息抽取任务的schema配置自定义抽取目标。
  • position_prob:模型对于span的起始位置/终止位置的结果概率0~1之间,返回结果去掉小于这个阈值的结果,默认为0.5,span的最终概率输出为起始位置概率和终止位置概率的乘积。

4. 轻定制功能

对于简单的抽取目标可以直接使用paddlenlp.Taskflow实现零样本(zero-shot)抽取,对于细分场景我们推荐使用轻定制功能(标注少量数据进行模型微调)以进一步提升效果。下面通过报销工单信息抽取的例子展示如何通过5条训练数据进行UIE模型微调。

代码结构

.
├── utils.py          # 数据处理工具
├── model.py          # 模型组网脚本
├── doccano.py        # 数据标注脚本
├── doccano.md        # 数据标注文档
├── finetune.py       # 模型微调脚本
├── evaluate.py       # 模型评估脚本
└── README.md

数据标注

我们推荐使用数据标注平台doccano 进行数据标注,本示例也打通了从标注到训练的通道,即doccano导出数据后可通过doccano.py脚本轻松将数据转换为输入模型时需要的形式,实现无缝衔接。

原始数据示例:

深大到双龙28块钱4月24号交通费

抽取的目标(schema)为:

schema = ['出发地', '目的地', '费用', '时间']

标注步骤如下:

  • 在doccano平台上,创建一个类型为序列标注的标注项目。
  • 定义实体标签类别,上例中需要定义的实体标签有出发地目的地费用时间
  • 使用以上定义的标签开始标注数据,下面展示了一个doccano标注示例:
  • 标注完成后,在doccano平台上导出文件,并将其重命名为doccano_ext.json后,放入./data目录下。

  • 这里我们提供预先标注好的文件doccano_ext.json,可直接下载并放入./data目录。执行以下脚本进行数据转换,执行后会在./data目录下生成训练/验证/测试集文件。

python doccano.py \
    --doccano_file ./data/doccano_ext.json \
    --task_type "ext" \
    --save_dir ./data \
    --splits 0.1 0.9 0

可配置参数说明:

  • doccano_file: 从doccano导出的数据标注文件。
  • save_dir: 训练数据的保存目录,默认存储在data目录下。
  • negative_ratio: 最大负例比例,该参数只对抽取类型任务有效,适当构造负例可提升模型效果。负例数量和实际的标签数量有关,最大负例数量 = negative_ratio * 正例数量。该参数只对训练集有效,为了保证评估指标的准确性,验证集和测试集默认构造全负例。默认为5。
  • splits: 划分数据集时训练集、验证集所占的比例。默认为[0.8, 0.1, 0.1]表示按照8:1:1的比例将数据划分为训练集、验证集和测试集。
  • task_type: 选择任务类型,可选有抽取和分类两种类型的任务。
  • options: 指定分类任务的类别标签,该参数只对分类类型任务有效。
  • prompt_prefix: 声明分类任务的prompt前缀信息,该参数只对分类类型任务有效。
  • is_shuffle: 是否对数据集进行随机打散,默认为True。
  • seed: 随机种子,默认为1000.

备注:

  • 默认情况下 doccano.py 脚本会按照比例将数据划分为 train/dev/test 数据集
  • 每次执行 doccano.py 脚本,将会覆盖已有的同名数据文件
  • 在模型训练阶段我们推荐构造一些负例以提升模型效果,在数据转换阶段我们内置了这一功能。可通过negative_ratio控制自动构造的负样本比例;负样本数量 = negative_ratio * 正样本数量。
  • 对于从doccano导出的文件,默认文件中的每条数据都是经过人工正确标注的。

更多不同类型任务(关系抽取、事件抽取、评价观点抽取等)的标注规则及参数说明,请参考doccano数据标注指南

模型微调

通过运行以下命令进行模型微调:

python finetune.py \
    --train_path "./data/train.txt" \
    --dev_path "./data/dev.txt" \
    --save_dir "./checkpoint" \
    --learning_rate 1e-5 \
    --batch_size 16 \
    --max_seq_len 512 \
    --num_epochs 100 \
    --model "uie-base" \
    --seed 1000 \
    --logging_steps 10 \
    --valid_steps 100 \
    --device "gpu"

可配置参数说明:

  • train_path: 训练集文件路径。
  • dev_path: 验证集文件路径。
  • save_dir: 模型存储路径,默认为./checkpoint
  • learning_rate: 学习率,默认为1e-5。
  • batch_size: 批处理大小,请结合显存情况进行调整,若出现显存不足,请适当调低这一参数,默认为16。
  • max_seq_len: 文本最大切分长度,输入超过最大长度时会对输入文本进行自动切分,默认为512。
  • num_epochs: 训练轮数,默认为100。
  • model: 选择模型,程序会基于选择的模型进行模型微调,可选有uie-baseuie-tiny,默认为uie-base
  • seed: 随机种子,默认为1000.
  • logging_steps: 日志打印的间隔steps数,默认10。
  • valid_steps: evaluate的间隔steps数,默认100。
  • device: 选用什么设备进行训练,可选cpu或gpu。

模型评估

通过运行以下命令进行模型评估:

python evaluate.py \
    --model_path "./checkpoint/model_best" \
    --test_path "./data/dev.txt" \
    --batch_size 16 \
    --max_seq_len 512

评估方式说明:采用单阶段评价的方式,即关系抽取、事件抽取等需要分阶段预测的任务对每一阶段的预测结果进行分别评价。验证/测试集默认会利用同一层级的所有标签来构造出全部负例。

可配置参数说明:

  • model_path: 进行评估的模型文件夹路径,路径下需包含模型权重文件model_state.pdparams及配置文件model_config.json
  • test_path: 进行评估的测试集文件。
  • batch_size: 批处理大小,请结合显存情况进行调整,若出现显存不足,请适当调低这一参数,默认为16。
  • max_seq_len: 文本最大切分长度,输入超过最大长度时会对输入文本进行自动切分,默认为512。
  • model: 选择所使用的模型,可选有uie-baseuie-tiny,默认为uie-base

定制模型一键预测

paddlenlp.Taskflow装载定制模型,通过task_path指定模型权重文件的路径,路径下需要包含训练好的模型权重文件model_state.pdparams

>>> from pprint import pprint
>>> from paddlenlp import Taskflow

>>> schema = ['出发地', '目的地', '费用', '时间']
# 设定抽取目标和定制化模型权重路径
>>> my_ie = Taskflow("information_extraction", schema=schema, task_path='./checkpoint/model_best')
>>> pprint(my_ie("城市内交通费7月5日金额114广州至佛山"))
[{'出发地': [{'end': 17,
           'probability': 0.9975287467835301,
           'start': 15,
           'text': '广州'}],
  '时间': [{'end': 10,
          'probability': 0.9999476678061399,
          'start': 6,
          'text': '7月5日'}],
  '目的地': [{'end': 20,
           'probability': 0.9998511131226735,
           'start': 18,
           'text': '佛山'}],
  '费用': [{'end': 15,
          'probability': 0.9994474579292856,
          'start': 12,
          'text': '114'}]}]

Few-Shot实验

我们在互联网、医疗、金融三大垂类自建测试集上进行了实验:

金融医疗互联网
0-shot5-shot0-shot5-shot0-shot5-shot
uie-tiny41.1164.5365.4075.7278.3279.68
uie-base46.4370.9271.8385.7278.3381.86

0-shot表示无训练数据直接通过paddlenlp.Taskflow进行预测,5-shot表示基于5条标注数据进行模型微调。实验表明UIE在垂类场景可以通过少量数据(few-shot)进一步提升效果。

5.CCKS比赛

为了进一步探索通用信息抽取的边界,我们举办了CCKS 2022 千言通用信息抽取竞赛评测(2022/03/30 - 2022/07/31)。

References