Global Pointer

代码:
总结
利用全局归一化的思路来进行命名实体识别(NER),可以无差别地识别嵌套实体和非嵌套实体,
在非嵌套(Flat NER)的情形下它能取得媲美CRF的效果,而在嵌套( NER)情形它也有不错的效果 。
在理论上,的设计思想就比CRF更合理;
而在实践上,它训练的时候不需要像CRF那样递归计算分母,预测的时候也不需要动态规划,是完全并行的,理想情况下时间复杂度是(1)!
思想
【Global Pointer】Sij作为从i到j的连续片段为实体a的打分
使用上三角矩阵来表示最终的label
损失函数
评价指标
def global_pointer_f1_score(y_true, y_pred):"""给GlobalPointer设计的F1"""y_pred = K.cast(K.greater(y_pred, 0), K.floatx())return 2 * K.sum(y_true * y_pred) / K.sum(y_true + y_pred)
因为的“”,它的和本身就已经是实体级别了,通过 > 0我们就可以知道哪些实体被抽取出来的,然后做个匹配就可以算出各种(实体级别的)指标,达到了训练、评估、预测的一致性 。
相比CRF
CRF(条件随机场,Field)是序列标注的经典设计,由于大多数NER也能转化为序列标注问题,所以CRF也算是NER的经典方法,
如果序列标注的标签数为k,那么逐帧和CRF的区别在于:
前者将序列标注看成是n个k分类问题,后者将序列标注看成是1个kn分类问题 。
这句话事实上也说明了逐帧和CRF用于NER时的理论上的缺点 。怎么理解呢?
逐帧将序列标注看成是n个k分类问题,那是过于宽松了,因为某个位置上的标注标签预测对了,不代表实体就能正确抽取出来了,起码有一个片段的标签都对了才算对;
CRF将序列标注看成是1个kn分类问题,则又过于严格了,因为这意味着它要求所有实体都预测正确才算对,只对部分实体也不给分 。虽然实际使用中我们用CRF也能出现部分正确的预测结果,但那只能说明模型本身的泛化能力好,CRF本身的设计确实包含了“全对才给分”的意思 。
所以,CRF在理论上确实都存在不大合理的地方,而相比之下,则更加贴近使用和评测场景:它本身就是以实体为单位的,并且它设计为一个“多标签分类”问题,这样它的损失函数和评价指标都是实体颗粒度的,哪怕只对一部分也得到了合理的打分 。因此,哪怕在非嵌套NER场景,能取得比CRF好也是“情理之中”的 。
:少点参数,多点效果

Global Pointer

文章插图
有多少种类型的实体,就有多少个Wq,α和Wk,α 。
不妨设Wq,α,Wk,α∈?D×d,那么每新增一种实体类型,我们就要新增2Dd个参数;
而如果用CRF+BIO标注的话,每新增一种实体类型,我们只需要增加2D的参数(转移矩阵参数较少,忽略不计) 。
对于BERT base来说,常见的选择是D=768,d=64,可见的参数量远远大于CRF 。
NER实际上可以分解为“抽取”和“分类”两个步骤,
“抽取”就是抽取出为实体的片段,我们可以用一个打分矩阵就可以完成
“分类”则是确定每个实体的类型 。我们则可以用“特征拼接+Dense层”来完成 。于是我们可以将两项组合起来,作为
“抽取”这部分的参数对所有实体类型都是共享的,因此每新增一种实体类型,我们只需要新增对应的wα∈?2D就行了,即新增一种实体类型增加的参数量也只是2D
然后为了进一步地减少参数量,我们可以用[qi;ki]来代替hi,此时
因此每新增一种实体类型所增加的参数量为4d,由于通常d?D,所以式(3)的参数量往往少于式(2),它就是 最终所用的打分函数 。