TPLinker

7 篇文章 0 订阅
# 笔记
1、长文本划分为短文本的时候,是以模型底层分词的个数来判断的
2、输入的X必须转换成id,输入的Y也必须转换成id,这样X输入得到的结果P才能和Y做比对,所有的模型都是围绕这个根基做转换,确认好X和Y,把这些都转换成id输入模型。
3、只有一个实体全连接层768X2,每个个关系都有对应的全连接层参数768X3
4、随着step加大,w_ent的权重递减,w_rel权重递增。先关注实体,保证实体抽准确,后面关注关系的抽取,由于目前工作原因,更多细节待闲时在进行解读。
5、输入的X就是一个句子的ID拉平组成的句子对,以及滑动拆分得到实体的偏移量信息,输入的tag就是三个东西,主实体和客实体两个实体的实体信息,关系的主实体客实体的头部信息,关系的主实体客实体的尾部信息。([(1, 4, 1), (7, 10, 1)], [(13, 1, 7, 1)], [(13, 4, 10, 1)])


# 修改地方
1、把文件夹tplinker改成tplinker1
2、config.py 77"bert_path": "../../pretrained_models/bert-base-cased",改成
"bert_path": "../pretrained_models/bert-base-cased",
3、config.py 43"batch_size": 6, 改成
"batch_size": 325行改成duie2
第16行,改成whole_span
4、train.py 210/217行
num_workers = 6 改成
num_workers = 0
5、创建extra_data文件夹存储原始百度数据
6、创建ori_data文件夹存储经过第一次处理的数据
7、preprocess文件夹新建trans_duie2.py,把原始数据经过一次处理,做一定的数据清洗
8、preprocess文件夹新建build_data.py,生产可以输入模型的数据,做一定的数据清洗,并且通过正则找到字符偏移
9、build_data_config.yaml
20行,设置为false,1/2/3/7行做好相关的文件夹配置
10、common文件夹的utils.py文件56-63行,增加相关百度数据处理的代码
11、train.py 第5行增加sys.path.append(os.path.split(os.path.abspath(os.path.dirname(__file__)))[0],防止linux运行报错
# CPU换GPU
1、config.py batch_size 2>32
2、train.py num_workers 6>0

# debug记录
1、滑动窗口没20个字符间隔一个起点,每一次都按相同最大长度来取原始数据的的位置索引

信息抽取两大难题:
一、暴露偏差
二、实体重叠、关系重叠
联合抽取的结构化预测双头标注才能同时解决上述两个问题,百度的联合抽取的结构化预测但是序列标注,能解决暴露偏差的问题,不能解决实体重叠和关系重叠的问题。

TPLinker标注,实体的头尾,主客实体的头,主客实体的尾。

解码阶段理解

1、先通过实体矩阵,得到所以的主实体和客实体集合,相当于得到所有的实体,再通过下面的方式准确的组合,弄成头实体尾key的字典,方便后面做查询。
2、通过关系的连个矩阵分别得到,主客实体对的尾的集合和主客实体对的头集合,
3、通过主客实体的头查询前面的字段,得到主客完整的实体,然后通过前面得到的尾实体,删除不满足的主客实体组合。
总结,就是先全实体》全主客实体对》满足要求的主客实体对

在这里插入图片描述
在这里插入图片描述

为什么TPLinker不适合直接用在NER上,而要用TPLinker_plus?

个人理解:讨论这个问题就要先了解最初的TPLinker设计模式,除了HandShaking外,作者还预定义了三大种类型ent, head_rel, tail_rel,每个类型下又有子类型,ent:{"O":0,"ENT-H2T":1}, head_rel:{"O":0, "REL-SH2OH":1, "REL-OH2SH":2}, head_tail:{"O":0, "REL-ST2OT":1, "REL-OT2ST":2}。在模型实际做分类时,三大类之间是独立的。以head_rel为例,其原数据整理得y_true矩阵shape为(batch_size, rel_size, shaking_seq_len),这里rel_size即有多少种关系。模型预测的结果y_pred矩阵shape为(batch_size, rel_size, shaking_seq_len, 3)。可以想象,这样的y_true矩阵已经很稀疏了,只有0,1,2三种标签。而如果换做NER,这样(batch_size, ent_size, shaking_seq_len)的矩阵将更加稀疏(只有0,1两种标签),对于一个(ent_size,shaking_seq_len)的矩阵来说,可能只有12个地方为1,这将导致模型无限地将预测结果都置为0,从而学习失败(事实实验也是这样)。作者在TPLinker中是如何解决这一问题的呢?其实作者用了个小trick回避了这一问题,具体做法是不再区分实体的类型,将所有实体都看作是DEFAULT类型,这样就把y_true压缩成了(batch_size,shaking_seq_len),降低了矩阵的稀疏性。作者对于这一做法的解释是"Because it is not necessary to recognize the type of entities for the relation extraction task since a predefined relation usually has fixed types for its subject and object.",即实体类别信息对关系抽取不太重要,因为每种关系某种程度上已经预定义了实体类型。综上,如果想直接把TPLinker应用到NER上是不合适的。

而TPLinker_plus改变了这一做法,他不再将ent, head_rel, tail_rel当做三个独立任务,而是将所有的关系与标签组合,形成一个大的标签库,只用一个HandShaking矩阵表示句子中的所有关系。举个例子,假设有以下3个关系(或实体类型):主演、出生于、作者,那么其与标记标签EH-ET,SH-OH,OH-SH,ST-OT,OT-ST组合后会产生15种tag,这极大地扩充了标签库。相应的,TPLinker_plus的输入也就变成了(batch_size,shaking_seq_len,tag_size)。这样的改变让矩阵中的非0值相对增多,降低了矩阵的稀疏性。(这只是一方面原因,更加重要原因的请参考问题2)

TPLinker_plus还做了哪些优化?

任务模式的转变:从问题1最后的结论可以看出,TPLinker_plus扩充标签库的同时,也将模型任务由原来的多分类任务转变成了多标签分类任务,即每个句子形成的shaking_seq可以出现多个的标签,且出现的数量不确定。形如
# 设句子的seq_len=10,那么shaking_seq=55
# 标签组合有8种tag_size=8
[
    [0,0,1,0,1,0,1,0],
    [1,0,1,0,0,0,0,1],
    ...
    # 剩下的53行
]
损失函数:对于多标签分类问题,原本的损失函数不再适用。作者使用了一种新的损失函数,关于这个损失函数原理,可以参考苏神的文章将“softmax+交叉熵”推广到多标签分类问题 (先点个star再走呀😁)
TPLinker-NER中几个关键词怎么理解?

对于一个text中含有n个token的情况

shaking_matrix:n*n的矩阵,若shaking_maxtrix[i][j]=1表示从第i个token到第j个token为一个实体。(实际用到的只有上三角矩阵,以为实体的起始位置一定在结束位置前。)
matrix_index:上三角矩阵的坐标,(0,0),(0,1),(0,2)...(0,n-1),(1,1),(1,2)...(1,n-1)...(n-1,n-1)。
shaking_index:上三角矩阵的索引,长度为$\frac{n(n+1)}{2}$,即[0,1,2,...,n(n+1)/2 - 1]
shaking_ind2matrix_ind:将索引映射到矩阵坐标,即[(0,0),(0,1),...,(n-1,n-1)]
matrix_ind2shaking_ind:将坐标映射到索引,即
[[0, 1, 2,    ...,        n-1],
[0, n, n+1, n+2,  ...,  2n-2]
...
[0, 0, 0, ...,  n(n+1)/2 - 1]]
spot:一个实体对应的起止span和类型id,例如实体“北京”在矩阵中起始位置在7,终止位置在9,类型为LOC"(id:3),那么其对应spot为(7, 9, 3)

在这里插入图片描述
输入的seq_hiddens维度是[batch,seq_len, hidden_size],其获得就可以简单看成是一句话经过bert后的编码,这里使用的是transformers这个python包,用的其AutoModel的即train.py下的278行,说白了就是用bert作为底层的encoder,下面假设seq_len是5
在这里插入图片描述
回到HandshakingKernel(上上副图),这里不得不讲一下论文中的优化到上三角,假设我们一句话有5个单词,本来矩阵是55,但是优化后只要上三角就可以啦,其实第一行是5列,第二行就是4列,第三行是3列,第四行是2列,第四行是1列,然后把他们平铺成一个序列即5+4+3+2+1.
从当前往后看即5,4,3,2,1 主要这里是j>=i就是要包括自身,因为自身单独一个单词可能就是一个实体
所以HandshakingKernel主要就是在做这个事情:
(1)代码中144行其实就是一个个遍历行,146行就是从当前取到最后,当是第一行时,ind是0,hidden_each_step维度是[batch,1,hidden_size]代表整句话第一个word的编码,为了进行拼接147行repeat_hiddens在第二个维度进行了复制,维度变成了[batch,5,hidden_size],相当于将当前单词编码复制了5份,visible_hiddens维度就是[batch,5,hidden_size],是从当前单词往后(包括自身)各个单词的编码,现在要计算得到上三角第一行的编码,即150行的shaking_hiddens,将当前单词和其后的各个单词的编码进行concat维度是[batch,5,hidden_size
2],然后151行又过了一个MLP层,转化为了shaking_hiddens [batch,5,hidden_size]
(2)当是上三角第二行时,ind是1,hidden_each_step维度是[batch,1,hidden_size]代表第二个单词的编码,visible_hiddens维度就是[batch,4,seq_len],代表其后的各个单词的编码,为了拼接repeat_hiddens维度是[batch,4,hidden_size]即将hidden_each_step第二个单词复制了4份,shaking_hiddens此时是[batch,4,hidden_size*2],然后151行又过了一个MLP层,转化为了shaking_hiddens[batch,4,hidden_size]
(3)同理当是上三角第三行时,最后shaking_hiddens维度是[batch,3,hidden_size],以此例推
所以163行的shaking_hiddens_list是一个列表,就是记录上三角一行行的编码,当句子有5个单词时,该列表有五个元素,维度分别是:
[batch,5,hidden_size],[batch,4,hidden_size],[batch,3,hidden_size],[batch,2,hidden_size],[batch,1,hidden_size]
161行long_shaking_hiddens在第二个维度进行concat即维度是:[batch,5+4+3+2+1,hidden_size],平铺变成了一个sequence。
long_shaking_hiddens就是公共编码就是shaking_hiddens4ent。

输入的seq_hiddens维度是[batch,seq_len, hiddensize],是一句话经过bert编码过后的值,而HandshakingKernel函数的作用是将矩阵变为上三角矩阵,即本身矩阵为[seq_len * seq_len],在经过函数过后为每一行都减1,最后通过long_shakinghiddens把函数把结果铺平,得到[seq_len+(seq_len -1) + (seq_len -2)…+1],对应了图片部分。

整个函数先是循环每句话中的词,当ind是0时,hidden_each_step代表了循环的每个词的编码[batch,1,hidden_size],visiblehiddens是循环到的这个单词以及之后的单词的编码,维度就是[batch,seq_len,hidden_size],repeat_hiddens对hidden_each_step的第二个维度进行了复制,维度为[batch,seq_len,hidden_size],将当前单词和其后的各个单词的编码进行拼接维度是[batch,seq_len,hidden_size*2]组成上三角矩阵的一行,在经过MLP层后shakinghiddens的维度是[batch,seq_len,hidden_size],之后每一行依次类推。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.项目代码均经过功能验证ok,确保稳定可靠运行。欢迎下载体验!下载完使用问题请私信沟通。 2.主要针对各个计算机相关专业,包括计算机科学、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师、企业员工。 3.项目具有丰富的拓展空间,不仅可作为入门进阶,也可直接作为毕设、课程设计、大作业、初期项目立项演示等用途。 4.当然也鼓励大家基于此进行二次开发。在使用过程中,如有问题或建议,请及时沟通。 5.期待你能在项目中找到乐趣和灵感,也欢迎你的分享和反馈! 【资源说明】 基于Pytorch框架的TPLinker_plus中文命名实体识别python源码+使用说明+模型+数据集.zip 还是和之前其它几种实体识别方式相同的代码模板,这里稍微做了一些修改,主要是在数据加载方面。之前都是预先处理好所有需要的数据保存好,由于tplinker需要更多内存,这里使用DataLoader中的collate_fn对每一批的数据分别进行操作,可以大大减少内存的使用。模型主要是来自这里:[tplinker_plus](https://github.com/Tongjilibo/bert4torch/blob/master/examples/sequence_labeling/task_sequence_labeling_ner_tplinker_plus.py),需要额外了解的知识有:[基于Conditional Layer Normalization的条件文本生成 - 科学空间|Scientific Spaces](https://spaces.ac.cn/archives/7124)和[将“softmax+交叉熵”推广到多标签分类问题 - 科学空间|Scientific Spaces](https://www.spaces.ac.cn/archives/7359)。实现运行步骤如下: - 1、在raw_data下新建一个process.py将数据处理成mid_data下的格式。 - 2、修改部分参数运行main.py,以进行训练、验证、测试和预测。 模型及数据下载地址:链接:https://pan.baidu.com/s/1B-e-MV1lOMQj2ur5MADRww?pwd=he3e 提取码:he3e # 依赖 ``` pytorch==1.6.0 tensorboasX seqeval pytorch-crf==0.7.2 transformers==4.4.0 ``` # 运行 在16GB的显存下都只能以batch_size=2进行运行。。。 ```python python main.py \ --bert_dir="model_hub/chinese-bert-wwm-ext/" \ --data_dir="./data/cner/" \ --log_dir="./logs/" \ --output_dir="./checkpoints/" \ --num_tags=8 \ --seed=123 \ --gpu_ids="0" \ --max_seq_len=150 \ --lr=3e-5 \ --other_lr=3e-4 \ --train_batch_size=2 \ --train_epochs=1 \ --eval_batch_size=8 \ --max_grad_norm=1 \ --warmup_proportion=0.1 \ --adam_epsilon=1e-8 \ --weight_decay=0.01 \ --dropout_prob=0.3 \ ``` ### 结果 ```python precision:0.8806 recall:0.8999 micro_f1:0.8901 precision recall f1-score support TITLE 0.87 0.88 0.87 767 RACE 0.88 0.93 0.90 15 CONT 1.00 1.00 1.00 33 ORG 0.89 0.90 0.89 543 NAME 0.99 1.00 1.00 110 EDU 0.82 0.94 0.88 109 PRO 0.67 0.95 0.78 19

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值