前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Paddlenlp之UIE关系抽取模型【高管关系抽取为例】

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

作者头像
汀丶人工智能
发布2022-12-21 16:56:34
1.4K0
发布2022-12-21 16:56:34
举报
文章被收录于专栏:NLP/KGNLP/KG

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

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

0.背景介绍

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

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

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

代码语言:javascript
复制
{"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: 实体类别/评价维度与分类标签的分隔符,该参数只对实体/评价维度级分类任务有效。默认为"##"。

代码语言:javascript
复制
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()
代码语言:javascript
复制
! python preprocess.py --input_file ./data/gaoguan.jsonl \
    --save_dir ./data/ \
    --negative_ratio 5 \
    --splits 0.85 0.15 0 \
    --seed 1000 
代码语言:javascript
复制
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.

输出部分展示:

代码语言:javascript
复制
{"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.模型训练

代码语言:javascript
复制
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()
代码语言:javascript
复制
!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"

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

代码语言:javascript
复制
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.模型评估

代码语言:javascript
复制
!python evaluate.py \
    --model_path ./checkpoint/model_best \
    --test_path ./data/dev.txt \
    --batch_size 8 \
    --max_seq_len 512
代码语言:javascript
复制
[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
代码语言:javascript
复制
**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.结果预测

代码语言:javascript
复制
#关系抽取
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])

输入文件展示:

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

输出展示:

代码语言:javascript
复制
黄峥,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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-08-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0.背景介绍
  • 数据加载
  • 2.模型训练
  • 3.模型评估
  • 4.结果预测
  • 5总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档