引言
此文不是对预训练模型融入实体信息、知识图谱等类似ERNIE,k-bert这种,而是在拿到bert输出后,突出指定位置信息进去,从而控制判定的结果。
问题
比如这句话:
该报还报道,法国达能集团日前宣布将投资1亿欧元,加强在中国市场的奶粉生产和研发,并表示“我们对中国市场的长期增长能力充满信心”。
谁加强和谁表示呢?是法国达能集团,而不是该报。
主体 | 触发词 | 客体 |
---|---|---|
法国达能集团 | 加强 | 在中国市场的奶粉生产和研发 |
法国达能集团 | 表示 | “我们对中国市场的长期增长能力充满信心” |
那假设,我们在知道触发词
和客体
的情况下,如何从原句中获取主体
呢?
思路
1. 引入其他layer和bert进行concat
这怕是最容易想到的方法了。比如将句子
、触发词
和客体
分别输入到bert,然后将这三者concat。emmm,这也怕是最蠢的方法了。
2. 修改触发词
和客体
所在bert输出索引的权重
比如一句话长度为128,拿到bert输出后为(128, 768)
,假设触发词
和客体
对应的span为(10,12)
和(15, 30)
,那如何手动修改对应span的weight呢??
方法一,直接进行mask_fill,将对应span的值改为比如0
。这种方式,,,emmmm,怎么说呢,看看就行。
方法二,也是操作对应span的weights,但是分成两步,第一是取触发词
的权重,第二是取客体
的权重,各自经过各自的linear,得到新的权重,然后再和bert output做一个交互,意思还是想突出触发词
和客体
的权重。和方法一一样,只不过对应的weight不是0,而是经过反向传播更新后的值。
比如conditional layer norm(对原conditional layer norm做修改了哦)。
伪代码如下:
1 | class NewConditionalLayerNorm(nn.Module): |
关于Conditional Layer Normalization,可看:讯飞2020年事件提取比赛第一名-主客体提取中Conditional Layer Normalization实现方式,难点在于变长罢了。
效果没试,总感觉复杂了些。
另外如果输入的feature个数是变化的,那这种方式就不可行了。
3. 变化标注方式,还是利用bert本身
输入一句话,tokenizer后拿到input_ids
,token_type_ids
, attention_mask
,那其中的token_type_ids
是干嘛的呢?百度下就有结果,说是如果是0
就表示第一句话,如果是1
就表示第二句话。
如果这样的话,那直接将触发词
和客体
的所对应的token_type_ids
置为1
不就又是一种方式么~,试了下效果出奇的不错。准确率嗖嗖的往上。而且还没引入额外的layer,相当拿bert就把这件事情搞定了。
这也是我写这篇文章的动力。。。
实现方式如下:
比如一句话”我们喜欢晴天。”,label设计为如下:
1 | # 假设我们为主语 |
模型就是bert+linear,linear输出hidden_size为2,loss使用binary_cross_entropy
即可。
缺陷嘛就是它没有区分每个feature本身的label。客体就是客体,触发词就是触发词~~
总结
所以通篇看下来,目的是想突出触发词
和客体
的weight,从而提取其对应的主体。前两者不同,那主体也有可能不同。
实现下来呢,如果不区分触发词和客体的话呢,可以使用上面那种方式。如果区分呢,那貌似只能引入新的layer来解决。
bert本身就够大的了,就不能一个预训练模型就能解决这种问题的么?比如下面这种方式:
1 | 预训练模型: |
嘿嘿,现在也有这种,不过坑更大,而且消耗的资源也更多,,,以后有机会再聊。
额外说一句,和本文无关,如果一个任务业界没有相关的研究,那你对这个任务进行建模、训练等,怎么评估这个模型是有效的呢?
- 有一定量的标注数据,这个应该是必不可免的。但是也是操作可能性很低的地方。
- 搭建一个简单的模型,试下基本效果。为后续方式作参考。
- 变换一种建模方式,模型参数尽量行之有效,并且建模方式又足够巧妙。
- 看loss走向和评估指标的变化。
又水了一篇~