往期项目回顾:

Paddlenlp之UIE模型实战实体抽取任务【打车数据、快递单】

Paddlenlp之UIE分类模型【以情感倾向分析新闻分类为例】含智能标注方案)

应用实践:分类模型大集成者[PaddleHub、Finetune、prompt]

本项目链接:只需要fork就可以直接复现

Paddlenlp之UIE关系抽取模型【高管关系抽取为例】

0.背景介绍

本项目将演示如何通过小样本样本进行模型微调,完成关系抽取。

数据集情况:
高管数据集demo:

马云浙江省杭州市人,阿里巴巴集团主要创始人之一。现任阿里巴巴集团主席和首席执行官,他是《福布斯》杂志创办50多年来成为封面人物的首位大陆企业家,曾获选为未来全球领袖。
任正非是中国大陆的民营电信设备企业一-华为公司的创始人兼总裁。 他关于企业“危机管理”的理论与实践曾在业内外产生过广泛影响。
马化腾,是腾讯主要创办人之一现担任公司控股董事会主席兼首席执行官。作为深圳土生土长的企业家,他曾在深圳大学主修计算机及应用,于1993年取得深大理学士学位。
李彦宏是百度公司创始人董事长兼首席执行官,全面负责百度公司的战略规划和运营管理,经过多年发展,百度已经牢牢占据中文搜索引擎超过7成的市场份额。
雷军, 2012年8月其投资创办的小米公司正式发布小米手机。
刘强东,江苏省宿迁市宿豫区人,京东商城的CEO。1996年毕业于中国人民大学社会学系。
柳传志,中国著名企业家,投资家,曾任联想控股有限公司董事长、联想集团有限公司董事局主席。

{"id":1845,"text":"马云浙江省杭州市人,阿里巴巴集团主要创始人之一。现任阿里巴巴集团主席和首席执行官,他是《福布斯》杂志创办50多年来成为封面人物的首位大陆企业家,曾获选为未来全球领袖。","entities":[{"id":945,"label":"人名","start_offset":0,"end_offset":2},{"id":946,"label":"公司","start_offset":10,"end_offset":16}],"relations":[{"id":11,"from_id":945,"to_id":946,"type":"高管"}]}
{"id":1846,"text":"任正非是中国大陆的民营电信设备企业一-华为公司的创始人兼总裁。 他关于企业“危机管理”的理论与实践曾在业内外产生过广泛影响。","entities":[{"id":949,"label":"人名","start_offset":0,"end_offset":3},{"id":950,"label":"公司","start_offset":19,"end_offset":23}],"relations":[{"id":13,"from_id":949,"to_id":950,"type":"高管"}]}
{"id":1847,"text":"马化腾,是腾讯主要创办人之一现担任公司控股董事会主席兼首席执行官。作为深圳土生土长的企业家,他曾在深圳大学主修计算机及应用,于1993年取得深大理学士学位。","entities":[{"id":954,"label":"人名","start_offset":0,"end_offset":3},{"id":955,"label":"公司","start_offset":5,"end_offset":7}],"relations":[{"id":16,"from_id":954,"to_id":955,"type":"高管"}]}
{"id":1848,"text":"李彦宏是百度公司创始人董事长兼首席执行官,全面负责百度公司的战略规划和运营管理,经过多年发展,百度已经牢牢占据中文搜索引擎超过7成的市场份额。","entities":[{"id":932,"label":"人名","start_offset":0,"end_offset":3},{"id":933,"label":"公司","start_offset":4,"end_offset":8},{"id":934,"label":"公司","start_offset":25,"end_offset":29}],"relations":[{"id":6,"from_id":932,"to_id":933,"type":"高管"}]}
{"id":1849,"text":"雷军, 2012年8月其投资创办的小米公司正式发布小米手机。","entities":[{"id":941,"label":"人名","start_offset":0,"end_offset":2},{"id":942,"label":"公司","start_offset":17,"end_offset":21}],"relations":[{"id":9,"from_id":941,"to_id":942,"type":"高管"}]}

数据加载

数据标注过程中,关系标注别搞反了,详细看前面文章,标注教学
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.

*separator: 实体类别/评价维度与分类标签的分隔符,该参数只对实体/评价维度级分类任务有效。默认为"##"。

import os
import time
import argparse
import json
import numpy as np from utils_1 import set_seed, convert_ext_examples def do_convert():
set_seed(args.seed) tic_time = time.time()
if not os.path.exists(args.input_file):
raise ValueError("Please input the correct path of doccano file.") if not os.path.exists(args.save_dir):
os.makedirs(args.save_dir) if len(args.splits) != 0 and len(args.splits) != 3:
raise ValueError("Only []/ len(splits)==3 accepted for splits.") if args.splits and sum(args.splits) != 1:
raise ValueError(
"Please set correct splits, sum of elements in splits should be equal to 1."
) with open(args.input_file, "r", encoding="utf-8") as f:
raw_examples = f.readlines() def _create_ext_examples(examples, negative_ratio=0, shuffle=False):
entities, relations = convert_ext_examples(examples, negative_ratio)
examples = [e + r for e, r in zip(entities, relations)]
if shuffle:
indexes = np.random.permutation(len(examples))
examples = [examples[i] for i in indexes]
return examples def _save_examples(save_dir, file_name, examples):
count = 0
save_path = os.path.join(save_dir, file_name)
with open(save_path, "w", encoding="utf-8") as f:
for example in examples:
for x in example:
f.write(json.dumps(x, ensure_ascii=False) + "\n")
count += 1
print("\nSave %d examples to %s." % (count, save_path)) if len(args.splits) == 0:
examples = _create_ext_examples(raw_examples, args.negative_ratio,
args.is_shuffle)
_save_examples(args.save_dir, "train.txt", examples)
else:
if args.is_shuffle:
indexes = np.random.permutation(len(raw_examples))
raw_examples = [raw_examples[i] for i in indexes] i1, i2, _ = args.splits
p1 = int(len(raw_examples) * i1)
p2 = int(len(raw_examples) * (i1 + i2)) train_examples = _create_ext_examples(
raw_examples[:p1], args.negative_ratio, args.is_shuffle)
dev_examples = _create_ext_examples(raw_examples[p1:p2])
test_examples = _create_ext_examples(raw_examples[p2:]) _save_examples(args.save_dir, "train.txt", train_examples)
_save_examples(args.save_dir, "dev.txt", dev_examples)
_save_examples(args.save_dir, "test.txt", test_examples) print('Finished! It takes %.2f seconds' % (time.time() - tic_time)) if __name__ == "__main__":
# yapf: disable
parser = argparse.ArgumentParser() parser.add_argument("--input_file", default="./data/data.json", type=str, help="The data file exported from doccano platform.")
parser.add_argument("--save_dir", default="./data", type=str, help="The path to save processed data.")
parser.add_argument("--negative_ratio", default=5, type=int, help="Used only for the classification task, the ratio of positive and negative samples, number of negtive samples = negative_ratio * number of positive samples")
parser.add_argument("--splits", default=[0.8, 0.1, 0.1], type=float, nargs="*", help="The ratio of samples in datasets. [0.6, 0.2, 0.2] means 60% samples used for training, 20% for evaluation and 20% for test.")
parser.add_argument("--is_shuffle", default=True, type=bool, help="Whether to shuffle the labeled dataset, defaults to True.")
parser.add_argument("--seed", type=int, default=1000, help="random seed for initialization") args = parser.parse_args()
# yapf: enable do_convert()
! python preprocess.py --input_file ./data/gaoguan.jsonl \
--save_dir ./data/ \
--negative_ratio 5 \
--splits 0.85 0.15 0 \
--seed 1000
Converting doccano data...
100%|██████████████████████████████████████████| 8/8 [00:00<00:00, 21358.65it/s]
Adding negative samples for first stage prompt...
100%|██████████████████████████████████████████| 8/8 [00:00<00:00, 88534.12it/s]
Constructing relation prompts...
Adding negative samples for second stage prompt...
100%|██████████████████████████████████████████| 8/8 [00:00<00:00, 24070.61it/s]
Converting doccano data...
100%|██████████████████████████████████████████| 2/2 [00:00<00:00, 25420.02it/s]
Adding negative samples for first stage prompt...
100%|██████████████████████████████████████████| 2/2 [00:00<00:00, 45839.39it/s]
Constructing relation prompts...
Adding negative samples for second stage prompt...
100%|██████████████████████████████████████████| 2/2 [00:00<00:00, 30066.70it/s]
Converting doccano data...
0it [00:00, ?it/s]
Adding negative samples for first stage prompt...
0it [00:00, ?it/s] Save 64 examples to ./data/train.txt. Save 6 examples to ./data/dev.txt.

输出部分展示:

{"content": "网易公司首席架构设计师,丁磊1997年6月创立网易公司,将网易从一个十几个人的私企发展到今天拥有近3000员工在美国公开上市的知名互联网技术企业。", "result_list": [{"text": "丁磊", "start": 12, "end": 14}], "prompt": "人名"}
{"content": "网易公司首席架构设计师,丁磊1997年6月创立网易公司,将网易从一个十几个人的私企发展到今天拥有近3000员工在美国公开上市的知名互联网技术企业。", "result_list": [{"text": "网易公司", "start": 0, "end": 4}, {"text": "网易公司", "start": 23, "end": 27}], "prompt": "公司"}
{"content": "网易公司首席架构设计师,丁磊1997年6月创立网易公司,将网易从一个十几个人的私企发展到今天拥有近3000员工在美国公开上市的知名互联网技术企业。", "result_list": [{"text": "丁磊", "start": 12, "end": 14}, {"text": "丁磊", "start": 12, "end": 14}], "prompt": "网易公司的高管"}
{"content": "李彦宏是百度公司创始人董事长兼首席执行官,全面负责百度公司的战略规划和运营管理,经过多年发展,百度已经牢牢占据中文搜索引擎超过7成的市场份额。", "result_list": [{"text": "李彦宏", "start": 0, "end": 3}], "prompt": "人名"}
{"content": "李彦宏是百度公司创始人董事长兼首席执行官,全面负责百度公司的战略规划和运营管理,经过多年发展,百度已经牢牢占据中文搜索引擎超过7成的市场份额。", "result_list": [{"text": "百度公司", "start": 4, "end": 8}], "prompt": "公司"}
{"content": "李彦宏是百度公司创始人董事长兼首席执行官,全面负责百度公司的战略规划和运营管理,经过多年发展,百度已经牢牢占据中文搜索引擎超过7成的市场份额。", "result_list": [{"text": "李彦宏", "start": 0, "end": 3}], "prompt": "百度公司的高管"}

2.模型训练

import argparse
import time
import os
from functools import partial import paddle
from paddle.utils.download import get_path_from_url
from paddlenlp.datasets import load_dataset
from paddlenlp.transformers import ErnieTokenizer from model import UIE
from utils_1 import set_seed, convert_example, reader, evaluate, create_dataloader, SpanEvaluator from visualdl import LogWriter def do_train():
paddle.set_device(args.device)
rank = paddle.distributed.get_rank()
if paddle.distributed.get_world_size() > 1:
paddle.distributed.init_parallel_env() set_seed(args.seed) hidden_size = 768
url = "https://bj.bcebos.com/paddlenlp/taskflow/information_extraction/uie_base/model_state.pdparams" tokenizer = ErnieTokenizer.from_pretrained('ernie-3.0-base-zh')
model = UIE('ernie-3.0-base-zh', hidden_size) if args.init_from_ckpt is not None:
pretrained_model_path = args.init_from_ckpt
else:
pretrained_model_path = os.path.join(args.model, "model_state.pdparams")
if not os.path.exists(pretrained_model_path):
get_path_from_url(url, args.model) state_dict = paddle.load(pretrained_model_path)
model.set_dict(state_dict)
print("Init from: {}".format(pretrained_model_path))
if paddle.distributed.get_world_size() > 1:
model = paddle.DataParallel(model) train_ds = load_dataset(
reader,
data_path=args.train_path,
max_seq_len=args.max_seq_len,
lazy=False)
dev_ds = load_dataset(
reader,
data_path=args.dev_path,
max_seq_len=args.max_seq_len,
lazy=False) trans_func = partial(
convert_example, tokenizer=tokenizer, max_seq_len=args.max_seq_len) train_data_loader = create_dataloader(
dataset=train_ds,
mode='train',
batch_size=args.batch_size,
trans_fn=trans_func) dev_data_loader = create_dataloader(
dataset=dev_ds,
mode='dev',
batch_size=args.batch_size,
trans_fn=trans_func) optimizer = paddle.optimizer.AdamW(
learning_rate=args.learning_rate, parameters=model.parameters()) criterion = paddle.nn.BCELoss()
metric = SpanEvaluator()
#初始化记录器
writer=LogWriter("./log/scalar_test")
writer1=LogWriter("./log/scalar_test1") loss_list = []
global_step = 0
best_step = 0
best_f1 = 0
tic_train = time.time()
for epoch in range(1, args.num_epochs + 1):
for batch in train_data_loader:
input_ids, token_type_ids, att_mask, pos_ids, start_ids, end_ids = batch
start_prob, end_prob = model(input_ids, token_type_ids, att_mask,
pos_ids)
start_ids = paddle.cast(start_ids, 'float32')
end_ids = paddle.cast(end_ids, 'float32')
loss_start = criterion(start_prob, start_ids)
loss_end = criterion(end_prob, end_ids)
loss = (loss_start + loss_end) / 2.0
loss.backward()
optimizer.step()
optimizer.clear_grad()
loss_list.append(float(loss)) global_step += 1
if global_step % args.logging_steps == 0 and rank == 0:
time_diff = time.time() - tic_train
loss_avg = sum(loss_list) / len(loss_list)
writer.add_scalar(tag="train/loss", step=global_step, value=loss_avg) #记录loss
print(
"global step %d, epoch: %d, loss: %.5f, speed: %.2f step/s"
% (global_step, epoch, loss_avg,
args.logging_steps / time_diff))
tic_train = time.time() if global_step % args.valid_steps == 0 and rank == 0:
# save_dir = os.path.join(args.save_dir, "model_%d" % global_step)
# if not os.path.exists(save_dir):
# os.makedirs(save_dir)
# save_param_path = os.path.join(save_dir, "model_state.pdparams")
# paddle.save(model.state_dict(), save_param_path) precision, recall, f1 = evaluate(model, metric, dev_data_loader)
writer1.add_scalar(tag="train/precision", step=global_step, value=precision)
writer1.add_scalar(tag="train/recall", step=global_step, value=recall)
writer1.add_scalar(tag="train/f1", step=global_step, value=f1) print("Evaluation precision: %.5f, recall: %.5f, F1: %.5f" %
(precision, recall, f1))
if f1 > best_f1:
print(
f"best F1 performence has been updated: {best_f1:.5f} --> {f1:.5f}"
)
best_f1 = f1
save_dir = os.path.join(args.save_dir, "model_best")
save_best_param_path = os.path.join(save_dir,
"model_state.pdparams")
paddle.save(model.state_dict(), save_best_param_path)
tic_train = time.time() if __name__ == "__main__":
# yapf: disable
parser = argparse.ArgumentParser()
#!
parser.add_argument("--batch_size", default=2, type=int, help="Batch size per GPU/CPU for training.")
# parser.add_argument("--batch_size", default=16, type=int, help="Batch size per GPU/CPU for training.")
parser.add_argument("--learning_rate", default=1e-5, type=float, help="The initial learning rate for Adam.")
parser.add_argument("--train_path", default="./data/train.txt", type=str, help="The path of train set.")
parser.add_argument("--dev_path", default="./data/dev.txt", type=str, help="The path of dev set.")
parser.add_argument("--save_dir", default='./checkpoint', type=str, help="The output directory where the model checkpoints will be written.")
parser.add_argument("--max_seq_len", default=512, type=int, help="The maximum input sequence length. "
"Sequences longer than this will be truncated, sequences shorter will be padded.")
#!这里参数决定训练量
parser.add_argument("--num_epochs", default=1, type=int, help="Total number of training epochs to perform.")
# parser.add_argument("--num_epochs", default=100, type=int, help="Total number of training epochs to perform.")
parser.add_argument("--seed", default=1000, type=int, help="Random seed for initialization")
parser.add_argument("--logging_steps", default=1, type=int, help="The interval steps to logging.")
parser.add_argument("--valid_steps", default=2, type=int, help="The interval steps to evaluate model performance.")
#!
parser.add_argument('--device', choices=['cpu', 'gpu'], default="cpu", help="Select which device to train model, defaults to gpu.")
parser.add_argument("--model", choices=["uie-base", "uie-tiny"], default="uie-tiny", type=str, help="Select the pretrained model for few-shot learning.")
#?模型参数初始化路径
parser.add_argument("--init_from_ckpt", default=None, type=str, help="The path of model parameters for initialization.") args = parser.parse_args()
# yapf: enable args.device = paddle.device.get_device() do_train()
!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 50 \
--model "uie-base" \
--seed 1000 \
--logging_steps 10 \
--valid_steps 50 \
--device "gpu"

部分训练效果展示:具体输出已折叠

global step 640, epoch: 80, loss: 0.00002, speed: 3.99 step/s
global step 650, epoch: 82, loss: 0.00002, speed: 3.87 step/s
global step 660, epoch: 83, loss: 0.00002, speed: 3.99 step/s
global step 670, epoch: 84, loss: 0.00002, speed: 4.03 step/s
global step 680, epoch: 85, loss: 0.00002, speed: 4.00 step/s
global step 690, epoch: 87, loss: 0.00002, speed: 3.88 step/s
global step 700, epoch: 88, loss: 0.00002, speed: 3.99 step/s
Evaluation precision: 1.00000, recall: 0.85714, F1: 0.92308
global step 710, epoch: 89, loss: 0.00002, speed: 3.99 step/s
global step 720, epoch: 90, loss: 0.00002, speed: 4.00 step/s
global step 730, epoch: 92, loss: 0.00002, speed: 3.86 step/s
global step 740, epoch: 93, loss: 0.00002, speed: 3.97 step/s
global step 750, epoch: 94, loss: 0.00002, speed: 3.99 step/s
global step 760, epoch: 95, loss: 0.00002, speed: 3.99 step/s
global step 770, epoch: 97, loss: 0.00002, speed: 3.86 step/s
global step 780, epoch: 98, loss: 0.00002, speed: 3.98 step/s
global step 790, epoch: 99, loss: 0.00002, speed: 4.00 step/s
global step 800, epoch: 100, loss: 0.00001, speed: 4.00 step/s
Evaluation precision: 1.00000, recall: 0.85714, F1: 0.92308

推荐使用GPU环境,否则可能会内存溢出。CPU环境下,可以修改model为uie-tiny,适当调下batch_size。

增加准确率的话:–num_epochs 设置大点多训练训练

可配置参数说明:
train_path: 训练集文件路径。

dev_path: 验证集文件路径。

save_dir: 模型存储路径,默认为./checkpoint。

learning_rate: 学习率,默认为1e-5。

batch_size: 批处理大小,请结合显存情况进行调整,若出现显存不足,请适当调低这一参数,默认为16。

max_seq_len: 文本最大切分长度,输入超过最大长度时会对输入文本进行自动切分,默认为512。

num_epochs: 训练轮数,默认为100。

model 选择模型,程序会基于选择的模型进行模型微调,可选有uie-base和uie-tiny,默认为uie-base。

seed: 随机种子,默认为1000.

logging_steps: 日志打印的间隔steps数,默认10。

valid_steps: evaluate的间隔steps数,默认100。

device: 选用什么设备进行训练,可选cpu或gpu。

3.模型评估

!python evaluate.py \
--model_path ./checkpoint/model_best \
--test_path ./data/dev.txt \
--batch_size 8 \
--max_seq_len 512
[2022-07-25 00:17:12,509] [    INFO] - We are using <class 'paddlenlp.transformers.ernie.tokenizer.ErnieTokenizer'> to load './checkpoint/model_best'.
W0725 00:17:12.535902 1512 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 10.1
W0725 00:17:12.540369 1512 gpu_resources.cc:91] device: 0, cuDNN Version: 7.6.
[2022-07-25 00:17:16,896] [ INFO] - -----------------------------
[2022-07-25 00:17:16,897] [ INFO] - Class Name: all_classes
[2022-07-25 00:17:16,897] [ INFO] - Evaluation Precision: 1.00000 | Recall: 0.85714 | F1: 0.92308
**model_path**: 进行评估的模型文件夹路径,路径下需包含模型权重文件model_state.pdparams及配置文件model_config.json。

**test_path:** 进行评估的测试集文件。

**batch_size**: 批处理大小,请结合机器情况进行调整,默认为16。

**max_seq_len**: 文本最大切分长度,输入超过最大长度时会对输入文本进行自动切分,默认为512。

**model**: 选择所使用的模型,可选有uie-base, uie-medium, uie-mini, uie-micro和uie-nano,默认为uie-base。

**debug**: 是否开启debug模式对每个正例类别分别进行评估,该模式仅用于模型调试,默认关闭。

4.结果预测

#关系抽取
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) #将每行数据插入data中
return data data_input=openreadtxt('./input/test.txt') schema = {"公司":"高管"}
few_ie = Taskflow('information_extraction', schema=schema, batch_size=16,task_path='./checkpoint/model_best') results=few_ie(data_input) with open("./output/result.txt", "w+",encoding='UTF-8') as f: #a : 写入文件,若文件不存在则会先创建再写入,但不会覆盖原文件,而是追加在文件末尾
for result in results:
line = json.dumps(result, ensure_ascii=False) #对中文默认使用的ascii编码.想输出真正的中文需要指定ensure_ascii=False
f.write(line + "\n") print("数据结果已导出")
for idx, text in enumerate(data_input):
print(data_input[idx],results[idx])

输入文件展示:

黄峥,1980年出生于浙江杭州,拼多多公司创始人,本科毕业于浙江大学、硕士学位毕业于威斯康星大学麦迪逊分校。
哔哩哔哩公司的创始人是徐逸,徐逸是最早的哔哩哔哩创始人,但一直在幕后,没有特别公开。曾经是Acfun弹幕网的会员,然后模仿Acfun建立了自己的网站,现在是董事。

输出展示:

黄峥,1980年出生于浙江杭州,拼多多公司创始人,本科毕业于浙江大学、硕士学位毕业于威斯康星大学麦迪逊分校。
{'公司': [{'text': '拼多多', 'start': 16, 'end': 19, 'probability': 0.935215170074585, 'relations': {'高管': [{'text': '黄峥', 'start': 0, 'end': 2, 'probability': 0.9996391253586268}]}}]}
哔哩哔哩公司的创始人是徐逸,徐逸是最早的哔哩哔哩创始人,但一直在幕后,没有特别公开。曾经是Acfun弹幕网的会员,然后模仿Acfun建立了自己的网站,现在是董事。 {'公司': [{'text': '哔哩哔哩公司', 'start': 0, 'end': 6, 'probability': 0.7246855227849665, 'relations': {'高管': [{'text': '徐逸', 'start': 11, 'end': 13, 'probability': 0.9985462800938478}]}}]}

5总结

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

UIE的优势

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

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

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

本人本次主要通过关系抽取这个案例分享给大家,使demo项目更佳完善,感兴趣同学可以试试跨任务抽取、以及多实体、多关系抽取

目前我已经在开源数据集测评了 F1在85%–90%之间,比较看数据集难度整体符合预期,这块有问题的可以留言。

本人博客:https://blog.csdn.net/sinat_39620217?type=blog

Paddlenlp之UIE关系抽取模型【高管关系抽取为例】的更多相关文章

  1. 树状结构Java模型、层级关系Java模型、上下级关系Java模型与html页面展示

    树状结构Java模型.层级关系Java模型.上下级关系Java模型与html页面展示 一.业务原型:公司的组织结构.传销关系网 二.数据库模型 很简单,创建 id 与 pid 关系即可.(pid:pa ...

  2. 人工智能论文解读精选 | PRGC:一种新的联合关系抽取模型

    NLP论文解读 原创•作者 | 小欣   论文标题:PRGC: Potential Relation and Global Correspondence Based Joint Relational ...

  3. [信息抽取]基于ERNIE3.0的多对多信息抽取算法:属性关系抽取

    [信息抽取]基于ERNIE3.0的多对多信息抽取算法:属性关系抽取 实体关系,实体属性抽取是信息抽取的关键任务:实体关系抽取是指从一段文本中抽取关系三元组,实体属性抽取是指从一段文本中抽取属性三元组: ...

  4. Flask-ORM-数据库的对象关系映射模型-备忘

    ORM对象关系映射模型的特点: 优点 : 只需要面向对象编程, 不需要面向数据库编写代码. 对数据库的操作都转化成对类属性和方法的操作. 不用编写各种数据库的sql语句. 实现了数据模型与数据库的解耦 ...

  5. django模型中的关系对应

    显然,关系数据库的力量在于将表相互关联.Django提供了定义三种最常见的数据库关系类型的方法:多对一,多对多和一对一. 在说明之前,首先来理解一下这三个概念: 多对一: 两个集合a,b;集合a中的多 ...

  6. jeecms系统使用介绍——jeecms中的内容、栏目、模型之间的关系

    转载:https://blog.csdn.net/dongdong9223/article/details/76578120 jeecms是一款很不错的cms产品,之前在文章<基于Java的门户 ...

  7. odoo 开发入门教程系列-模型之间的关系(Relations Between Models)

    模型之间的关系(Relations Between Models) 上一章介绍了为包含基本字段的模型创建自定义视图.然而,在任何真实的业务场景中,我们都需要不止一个模型.此外,模型之间的链接是必要的. ...

  8. asp.net core系列 26 EF模型配置(实体关系)

    一.概述 EF实体关系定义了两个实体互相关联起来(主体实体和依赖实体的关系,对应数据库中主表和子表关系). 在关系型数据库中,这种表示是通过外键约束来体现.本篇主要讲一对多的关系.先了解下描述关系的术 ...

  9. 【scikit-learn】交叉验证及其用于參数选择、模型选择、特征选择的样例

     内容概要¶ 训练集/測试集切割用于模型验证的缺点 K折交叉验证是怎样克服之前的不足 交叉验证怎样用于选择调节參数.选择模型.选择特征 改善交叉验证 1. 模型验证回想¶ 进行模型验证的一个重要目 ...

  10. Linux加载DTS设备节点的过程(以高通8974平台为例)

    DTS是Device Tree Source的缩写,用来描述设备的硬件细节.在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码, ...

随机推荐

  1. 原创内容屡屡被盗?从源头对资源盗用说NO

    在这个信息化的时代,资源被盗用是一件很让人厌恶,但又很常见的事.比如,之前郭敬明的小说<梦里花落知多少>剽窃庄羽小说<圈里圈外>一事,虽然郭敬明通过个人微博向庄羽道歉,并表示& ...

  2. 0.o?让我看看怎么个事儿之SpringBoot自动配置

    学习 SpringBoot 自动配置之前我们需要一些前置知识点: Java注解,看完就会用 学会@ConfigurationProperties月薪过三千 不是银趴~是@Import! @Condit ...

  3. 广州|阿里云 Serverless 技术实战营邀你来玩!

    活动简介 "Serverless 技术实战与创新沙龙 " 是一场以 Serverless 为主题的开发者活动,活动受众以关注Serverless 技术的开发者.企业决策人.云原生领 ...

  4. 运行vue项目时报错“ValidationError: Progress Plugin Invalid Options”

    https://blog.csdn.net/M_Nobody/article/details/123135041?spm=1001.2101.3001.6650.1&utm_medium=di ...

  5. Liunx运维(四)-文本处理三剑客:grep、sed、awk

    文档目录: 一.grep:文本过滤工具 二.sed:字符流编辑器 三.awk:文本分析工具 ---------------------------------------分割线:正文--------- ...

  6. java基础-java面向对象-02-day09

    目录 1. 封装 2. 继承 2.1 什么是方法的重写 2.2 super 2.3 object详解 2.4 equals方法 3. 多态 4. final修饰符 5.抽象类 6. 接口 7. 内部类 ...

  7. hello world 的并发实现

    本篇文章将介绍 hello world 的并发实现,其中涉及到的知识有: 并发与并行 GPM 调度系统 并发与并行 并发不是并行.并发是同时管理很多事情,这些事情可能只做了一半就被暂停做别的事情了.而 ...

  8. google浏览器网页截取全屏

    本想在谷歌浏览器滚动截取网页全屏,没有找到好的方法,在网上找到一个快捷键,未曾使用过,特地记录下: 第一步:按F12打开 第二步:window:Ctrl + Shift + P mac:command ...

  9. 调整PR界面字体大小

    1.问题 界面字体太大或者太小,看得不舒服 2.解决问题 按住ctrl+F12,调出如下工作台 选择Debug Datatbase View 其中找到AdobeCleanFontSize,并修改 重启 ...

  10. ONVIF网络摄像头(IPC)客户端开发—最简RTSP客户端实现

    前言: 网上对于RTSP协议客户端的表述和实现非常不清晰,在实际使用中,FFMPEG和live555这些软件已经实现了RTSP客户端和服务端的所有功能,但是它们并没有将RTSP协议独立出来,通过看li ...