Giter Site home page Giter Site logo

deepner's Introduction

Chinese-DeepNER-Pytorch

天池中药说明书实体识别挑战冠军方案开源

贡献者:

zxx飞翔的鱼: https://github.com/z814081807

我是蛋糕王:https://github.com/WuHuRestaurant

数青峰:https://github.com/zchaizju

后续官方开放数据集后DeepNER项目会进行优化升级,包含完整的数据处理、训练、验证、测试、部署流程,提供详细的代码注释、模型介绍、实验结果,提供更普适的基于预训练的中文命名实体识别方案,开箱即用,欢迎Star!

(代码框架基于pytorch and transformers, 框架复用性、解耦性、易读性较高,很容易修改迁移至其他NLP任务中)

环境

python3.7
pytorch==1.6.0 +
transformers==2.10.0
pytorch-crf==0.7.2

项目目录说明

DeepNER
│
├── data                                    # 数据文件夹
│   ├── mid_data                            # 存放一些中间数据
│   │   ├── crf_ent2id.json                 # crf 模型的 schema
│   │   └── span_ent2id.json                # span 模型的 schema
│   │   └── mrc_ent2id.json                 # mrc 模型的 schema
│
│   ├── raw_data                            # 转换后的数据
│   │   ├── dev.json                        # 转换后的验证集
│   │   ├── test.json                       # 转换后的初赛测试集
│   │   ├── pseudo.json                     # 转换后的半监督数据
│   │   ├── stack.json                      # 转换后的全体数据
│   └── └── train.json                      # 转换后的训练集
│
├── out                                     # 存放训练好的模型
│   ├── ...           
│   └── ...                                      
│
├── src
│   ├── preprocess                  
│   │   ├── convert_raw_data.py             # 处理转换原始数据
│   │   └── processor.py                    # 转换数据为 Bert 模型的输入
│   ├── utils                      
│   │   ├── attack_train_utils.py           # 对抗训练 FGM / PGD
│   │   ├── dataset_utils.py                # torch Dataset
│   │   ├── evaluator.py                    # 模型评估
│   │   ├── functions_utils.py              # 跨文件调用的一些 functions
│   │   ├── model_utils.py                  # Span & CRF & MRC model (pytorch)
│   │   ├── options.py                      # 命令行参数|   └── trainer.py                      # 训练器
|
├── competition_predict.py                  # 复赛数据推理并提交
├── README.md                               # ...
├── convert_test_data.py                    # 将复赛 test 转化成 json 格式
├── run.sh                                  # 运行脚本
└── main.py                                 # main 函数 (主要用于训练/评估)

使用说明

预训练使用说明

数据转换

注:已提供转换好的数据 无需运行

python src/preprocessing/convert_raw_data.py

训练阶段

bash run.sh

注:脚本中指定的 BERT_DIR 指BERT所在文件夹,需要把 BERT 下载到指定文件夹中

BERT-CRF模型训练
task_type='crf'
mode='train' or 'stack'  train:单模训练与验证stack:5折训练与验证

swa_start: swa 模型权重平均开始的 epoch
attack_train'pgd' / 'fgm' / '' 对抗训练 fgm 训练速度慢一倍, pgd 慢两倍pgd 本次数据集效果明显
BERT-SPAN模型训练
task_type='span'
mode同上
attack_train: 同上
loss_type: 'ce'交叉熵; 'ls_ce'label_smooth; 'focal': focal loss
BERT-MRC模型训练
task_type='mrc'
mode同上
attack_train: 同上
loss_type: 同上

预测复赛 test 文件 (上述模型训练完成后)

注:暂无数据运行,等待官方数据开源后可运行

# convert_test_data
python convert_test_data.py
# predict
python competition_predict.py

赛题背景

任务描述

人工智能加速了中医药领域的传承创新发展,其中中医药文本的信息抽取部分是构建中医药知识图谱的核心部分,为上层应用如临床辅助诊疗系统的构建(CDSS)等奠定了基础。本次NER挑战需要抽取中药药品说明书中的关键信息,包括药品、药物成分、疾病、症状、证候等13类实体,构建中医药药品知识库。

数据探索分析

本次竞赛训练数据有三个特点:

  • 中药药品说明书以长文本居多

- 医疗场景下的标注样本不足

- 标签分布不平衡

核心思路

数据预处理

首先对说明书文本进行预清洗与长文本切分。预清洗部分对无效字符进行过滤。针对长文本问题,采用两级文本切分的策略。切分后的句子可能过短,将短文本归并,使得归并后的文本长度不超过设置的最大长度。此外,利用全部标注数据构造实体知识库,作为领域先验词典。

Baseline: BERT-CRF

  • Baseline 细节
    • 预训练模型:选用 UER-large-24 layer[1],UER在RoBerta-wwm 框架下采用大规模优质中文语料继续训练,CLUE 任务中单模第一
    • 差分学习率:BERT层学习率2e-5;其他层学习率2e-3
    • 参数初始化:模型其他模块与BERT采用相同的初始化方式
    • 滑动参数平均:加权平均最后几个epoch模型的权重,得到更加平滑和表现更优的模型
  • Baseline bad-case分析

优化1:对抗训练

  • 动机:采用对抗训练缓解模型鲁棒性差的问题,提升模型泛化能力
  • 对抗训练是一种引入噪声的训练方式,可以对参数进行正则化,提升模型鲁棒性和泛化能力
    • Fast Gradient Method (FGM):对embedding层在梯度方向添加扰动
    • Projected Gradient Descent (PGD) [2]:迭代扰动,每次扰动被投影到规定范围内

优化2:混合精度训练(FP16)

  • 动机:对抗训练降低了计算效率,使用混合精度训练优化训练耗时
  • 混合精度训练
    • 在内存中用FP16做存储和乘法来加速
    • 用FP32做累加避免舍入误差
  • 损失放大
    • 反向传播前扩大2^k倍loss,防止loss下溢出
    • 反向传播后将权重梯度还原

优化3:多模型融合

  • 动机:baseline 错误集中于歧义性错误,采用多级医学命名实体识别系统以消除歧义性

  • 方法:差异化多级模型融合系统

    • 模型框架差异化:BERT-CRF & BERT-SPAN & BERT-MRC
    • 训练数据差异化:更换随机种子、更换句子切分长度(256、512)
    • 多级模型融合策略
  • 融合模型1——BERT-SPAN

    • 采用SPAN指针的形式替代CRF模块,加快训练速度
    • 以半指针-半标注的结构预测实体的起始位置,同时标注过程中给出实体类别
    • 采用严格解码形式,重叠实体选取logits最大的一个,保证准确率
    • 使用label smooth缓解过拟合问题

  • 融合模型2——BERT-MRC
    • 基于阅读理解的方式处理NER任务
      • query:实体类型的描述来作为query
      • doc:分句后的原始文本作为doc
    • 针对每一种类型构造一个样本,训练时有大量负样本,可以随机选取30%加入训练,其余丢弃,保证效率
    • 预测时对每一类都需构造一次样本,对解码输出不做限制,保证召回率
    • 使用label smooth缓解过拟合问题
    • MRC在本次数据集上精度表现不佳,且训练和推理效率较低,仅作为提升召回率的方案,提供代码仅供学习,不推荐日常使用

  • 多级融合策略
    • CRF/SPAN/MRC 5折交叉验证得到的模型进行第一级概率融合,将 logits 平均后解码实体
    • CRF/SPAN/MRC 概率融合后的模型进行第二级投票融合,获取最终结果

优化4:半监督学习

  • 动机:为了缓解医疗场景下的标注语料稀缺的问题, 我们使用半监督学习(伪标签)充分利用未标注的500条初赛测试集
  • 策略:动态伪标签
    • 首先使用原始标注数据训练一个基准模型M
    • 使用基准模型M对初赛测试集进行预测得到伪标签
    • 将伪标签加入训练集,赋予伪标签一个动态可学习权重(图中alpha),加入真实标签数据**同训练得到模型M’

- tips:使用多模融合的基准模型减少伪标签的噪音;权重也可以固定,选取需多尝试哪个效果好,本质上是降低伪标签的loss权重,是缓解伪标签噪音的一种方法。

其他无明显提升的尝试方案

  • 取BERT后四层动态加权输出,无明显提升
  • BERT 输出后加上BiLSTM / IDCNN 模块,过拟合严重,训练速度大大降低
  • 数据增强,对同类实体词进行随机替换,以扩充训练数据
  • BERT-SPAN / MRC 模型采用focal loss / dice loss 等缓解标签不平衡
  • 利用构造的领域词典修正模型输出

最终线上成绩72.90%,复赛Rank 1,决赛Rank 1

Ref

[1] Zhao et al., UER: An Open-Source Toolkit for Pre-training Models, EMNLP-IJCNLP, 2019. [2] Madry et al., Towards Deep Learning Models Resistant to Adversarial Attacks, ICLR, 2018.

deepner's People

Contributors

wuhurestaurant avatar z814081807 avatar zchaizju avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

deepner's Issues

滑动平均swa

Great work!
能否简单介绍下“swa”的作用呢?另外请教下项目里面使用“swa”是否有明显的效果提升?

请问这个错误是什么原因造成的啊

Traceback (most recent call last):
File "main.py", line 213, in
training(args)
File "main.py", line 134, in training
train_base(opt, train_examples, dev_examples)
File "main.py", line 44, in train_base
train(opt, model, train_dataset)
File "D:\Documents\PycharmProjects\extraction\DeepNER-master\src\utils\trainer.py", line 219, in train
swa(swa_raw_model, opt.output_dir, swa_start=opt.swa_start)
File "D:\Documents\PycharmProjects\extraction\DeepNER-master\src\utils\functions_utils.py", line 83, in swa
model_path_list = get_model_path_list(model_dir)
File "D:\Documents\PycharmProjects\extraction\DeepNER-master\src\utils\functions_utils.py", line 74, in get_model_path_list
key=lambda x: (x.split('/')[-3], int(x.split('/')[-2].split('-')[-1])))
File "D:\Documents\PycharmProjects\extraction\DeepNER-master\src\utils\functions_utils.py", line 74, in
key=lambda x: (x.split('/')[-3], int(x.split('/')[-2].split('-')[-1])))
IndexError: list index out of range

pseudo_nums == 0或1的问题

看大佬的代码中,如果pseudo_nums == 1的时候训练速度好像慢一点,想问下大佬pseudo_nums 的值为0还是为1是如何确定的?

需要多大的显存 1080ti 爆显存了

RuntimeError: CUDA out of memory. Tried to allocate 384.00 MiB (GPU 0; 11.00 GiB total capacity; 9.52 GiB already allocated; 124.50 MiB free; 9.54 GiB reserved in total by PyTorch)

训练和预测不一致问题

mrc方法中的问题

  1. 训练时候构造query+context作为输入; 但是你预测时候就是context作为输入;
  2. 预测代码np.argmax()是多分类吧,那你一句话里面只能出现一个实体吗?

实体知识库&&SWA滑动平均

1、您好!请问这个实体知识库在模型预测后使用(直接进行检索匹配)的话,是不是会造成高召回、低准确的问题呢?就比如一个实体有多个类型,那么在匹配的时候是如何选择给定哪种类型呢?如何避免这种问题?
2、项目中使用的“SWA滑动平均”有什么推荐的参考资料嘛?
期待您的回复,谢谢!

生成BIO标注数据集

请教您一下,怎样生成BIO数据集。您的代码是转化后直接输入到Bert的。您是采取截断方式,也就是大于最大长度就直接截断了吗?不知您是否可以开源一个生成类似BIO标注数据的代码。

span训练

请问span模型的loss大概要训练到多少,为啥好难训,是参数设置的不对嘛?

关于伪标签的一些问题

您好,感谢您的开源,想问一下伪标签的获取过程是否代码里有提供呢?这个伪标签是否是one hot label?请问一般如果提供测试集然后目标是在该测试集上获取不错的分数,可以直接对测试集打上伪标签吗?伪标签这方面知识比较匮乏,如果过于简单还请见谅。希望得到您的回复!

关于pytorch-crf

我在其他序列标注任务使用pytorch-crf时发现训练速度明显变慢(相比于简单使用softmax,训练时间几乎翻倍),请问你们在使用pytorch-crf时遇到过这种情况吗

关于词汇表以及load_model_and_parallel函数的问题

  1. (注意:需人工将 vocab.txt 中两个 [unused] 转换成 [INV] 和 [BLANK]),这个需要一定替换吗?不替换会报错吗?
  2. 目前训练阶段没有问题,在进行crf_evaluation时:
    load_model_and_parallel时会报错,尝试了多次其中错误有时候不太一样,有以下三种:
    第一种:
/anaconda3/lib/python3.8/site-packages/torch/nn/functional.py", line 1676, in linear
    output = input.matmul(weight.t())
RuntimeError: CUDA error: CUBLAS_STATUS_EXECUTION_FAILED when calling `cublasSgemm( handle, opa, opb, m, n, k, &alpha, a, lda, b, ldb, &beta, c, ldc)`
01/09/2021 11:03:23 - INFO - wandb.internal.internal -   Internal process exited

第二种:

anaconda3/lib/python3.8/site-packages/torch/nn/functional.py", line 1678, in linear
    output += bias
RuntimeError: CUDA error: device-side assert triggered
01/09/2021 10:21:48 - INFO - wandb.internal.internal -   Internal process exited

第三种:
context_layer = context_layer.permute(0, 2, 1, 3)acontiguous() RuntimeError: CUDA error: device-side assert triggered

我Google查了这个bug,给的比较多的答案是:label的索引有问题,因为数据集不是天池的数据集,想问下如果标注数据中没有S这个标签会导致出错吗(BMES);另外一个答案是GPU OOM,想问下如果单卡的话会不会出现这个问题:

01/09/2021 11:03:13 - INFO - src.utils.trainer -   Saving model & optimizer & scheduler checkpoint to ./out/roberta_wwm_wd_crf/checkpoint-1005
01/09/2021 11:03:16 - INFO - src.utils.functions_utils -   Load model from ./out/roberta_wwm_wd_crf/checkpoint-603/model.pt
01/09/2021 11:03:17 - INFO - src.utils.functions_utils -   Load model from ./out/roberta_wwm_wd_crf/checkpoint-804/model.pt
01/09/2021 11:03:17 - INFO - src.utils.functions_utils -   Load model from ./out/roberta_wwm_wd_crf/checkpoint-1005/model.pt
01/09/2021 11:03:18 - INFO - src.utils.functions_utils -   Save swa model in: ./out/roberta_wwm_wd_crf/checkpoint-100000
01/09/2021 11:03:21 - INFO - src.utils.trainer -   Train done
../../bert/torch_roberta_wwm/vocab.txt
01/09/2021 11:03:21 - INFO - src.preprocess.processor -   Convert 738 examples to features
Truncation was not explicitly activated but `max_length` is provided a specific value, please use `truncation=True` to explicitly truncate examples to max length. Defaulting to 'longest_first' truncation strategy. If you encode pairs of sequences (GLUE-style) with the tokenizer you can select this strategy more precisely by providing a specific strategy to `truncation`.
01/09/2021 11:03:22 - INFO - src.preprocess.processor -   Build 738 features
['0']
cuda:0
01/09/2021 11:03:22 - INFO - src.utils.functions_utils -   Load ckpt from ./out/roberta_wwm_wd_crf/checkpoint-201/model.pt
01/09/2021 11:03:23 - INFO - src.utils.functions_utils -   Use single gpu in: ['0']
Traceback (most recent call last):
  File "main.py", line 215, in <module>
    training(args)
  File "main.py", line 136, in training
    train_base(opt, train_examples, dev_examples)
  File "main.py", line 78, in train_base
    tmp_metric_str, tmp_f1 = crf_evaluation(model, dev_info, device, ent2id)
  File "/home/quincyqiang/Projects/Water-Conservancy-KG/DeepNER/src/utils/evaluator.py", line 150, in crf_evaluation
    for tmp_pred in get_base_out(model, dev_loader, device):
  File "/home/quincyqiang/Projects/Water-Conservancy-KG/DeepNER/src/utils/evaluator.py", line 22, in get_base_out

从上面的错误可以看出来,前面直接加载了checkpoint-603,checkpoint-804等,但是下面同时进行checkpoint-201评估,是不是前面加载了会导致后面内存不足?

Why the total loss increase suddenly and rapidly when training the base crf ?

train crf
bert lr 2e-5
other lr 2e-3
epoch 10

The total loss decrease in the first 5 epoch. The loss is about 20.
But suddenly the loss increase rapidly to about 10000.

Use 'get_linear_schedule_with_warmup' the lr should be smaller and smaller. But this phenomenon seems to disappear when I change the schedule. I don't understand why the loss increases.

多卡

你好,请问这个项目能用多卡跑吗

在nn.CrossEntropyLoss(reduction='none')中的问题

在训练中:loss.backward()会报错:
grad can be implicitly created only for scalar outputs
意思是nn.CrossEntropyLoss(reduction='none')这里计算的损失是每一个token的,返回的是一个张量loss,而loss.backward()中的loss需要一个标量,请问存在这种问题吗?

关于baseline的运行结果

请教一下,请问按照现在项目中的run.sh运行的出来的结果,f1-score大约应该是多少?由于显存上限,我只修改了train_batch_size=10,但在dev上的f1只有0.113,感觉不太对。
截图_20223904013945

程序退出

我使用cpu进行训练,但是在trainer.py的第136行:
loss=model(**batch_data)[0]
程序异常退出了。

我用的参数:
gpu_ids=-1
bert_type='roberta_wwm'
mode='train'
task_type='crf'
loss_type='ls_ce'

是一定要用gpu吗,还是我的安装有问题?
tensorflow 2.4.1
torch 1.8.1+cpu
transformers 4.4.2

competition_predict 问题

里面的那个 RAW_DATA_DIR = raw_data_random 。这个 raw_data_random 是什么文件,看代码是 Test 和 Stack 存放的文件夹?
但是这些文件在训练的时候放在 raw_data 里。 这里变成 raw_data_random 是有其他数据?

损失函数的问题

您好,我直接使用您的模型进行训练,但是模型的损失函数只增不减,最后达到nan,请问这是什么原因呢?torch==1.11.0,

关于“产生了不该有的截断”

首先感谢作者的开源代码! 我在利用其他NER任务进行您的模型训练的过程中,在选择训练mrc模型,当max_seq_len设置512,自己定义的query设定的最大长度为100个字符(因此修改了processor = NERProcessor(opt.max_seq_len-103),不知是否正确),其输出大量的'产生了不该有的截断',请问如何理解'产生了不该有的截断'呢?会对模型的训练产生如何的影响?期待您的回答!

请问MRC代码可以做嵌套命名实体识别吗

我把自己的带有嵌套的数据转为相应的格式,使用MRC那一块进行训练,发现出来的效果F1有67,但是并不知道这个MRC能否处理嵌套情况?另外如果想要做嵌套命名实体识别,有没有大佬对代码进行改进的呢

评价指标

代码里的评价指标是计算了每一类的F1之后按照类别加权平均了,这是microF1吗?
microF1不应该是统计所有样本的tp,fp,fn然后再算吗?

原始数据的形式

从阿里那里拿到的原始数据格式已经变成这样的了。想知道一开始的数据格式形式。
image

span解码

您好 我看到readme中提到span解码过程中使用的是严格编码过程 嵌套得实体取概率最大的 我在解码代码中看到还是可能出现一个end对应多个start的情况。

训练精度的问题

首先感谢作者大佬开源这么好的模型架构,但是我在实验自己做过的一份数据集时,出现了一些问题,我在这份数据集上之前用bert4keras,使用Nezha+crf可以做到68的F1,这里使用本架构中的robert-wwm+crf只做到了62的F1,我仔细对比了我的数据集格式和架构中的数据集格式,包括标签命名和对应,但还是找不到问题所在,据我所知,roberta和Nezha应该不会造成这么大的区别,我采取的BIO标注和本架构的BIES标注也应该不会造成这么大差距,包括我第一次运行代码时,也出现了损失先下降后急速上升的情况,在将学习都变小之后,这种情况消失了,但是效果还是不好,因为我对此了解不够深,还是希望能请教一下,大佬您觉得可能会有哪一部分的影响导致效果不好呢?如果大佬您还有想问的细节可以加我的微信:xckkcxxck,十分希望能指导一下,🙏谢谢

求伪标签过程

求大牛提供一下伪标签的处理过程. 想知道 500 条测试数据是如何被标注的, 跪求 ! !!!!!

把batch_size调成6 F1值只有0.13了

In step 272:
[MIRCO] precision: 0.0000, recall: 0.0000, f1: 0.0000

In step 544:
[MIRCO] precision: 0.2668, recall: 0.0088, f1: 0.0160

In step 816:
[MIRCO] precision: 0.3403, recall: 0.0183, f1: 0.0340

In step 1088:
[MIRCO] precision: 0.3746, recall: 0.0263, f1: 0.0487

In step 1360:
[MIRCO] precision: 0.3832, recall: 0.0597, f1: 0.0994

In step 1632:
[MIRCO] precision: 0.3413, recall: 0.0727, f1: 0.1162

In step 1904:
[MIRCO] precision: 0.2666, recall: 0.0772, f1: 0.1148

In step 2176:
[MIRCO] precision: 0.2869, recall: 0.0841, f1: 0.1250

In step 2448:
[MIRCO] precision: 0.2785, recall: 0.0944, f1: 0.1365

In step 2720:
[MIRCO] precision: 0.2690, recall: 0.0906, f1: 0.1314

In step 100000:
[MIRCO] precision: 0.2824, recall: 0.0845, f1: 0.1260

Max f1 is: 0.1364805133924134, in step 2448

这是我跑出来的结果,除了没有修改vocab.txt里的uncase其他设置都没变,batch_size24直接oom了。

半监督学习

请问有没有半监督代码?woxia我想看看伪标签怎么实现的
image

loss不收敛

Loss优化到一定程度后突然上升, 一直上升到几万, 可能是什么原因呢.(没有修改代码)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.