CRF原理和代码实现

        CRF常用在序列标注任务中,是找出一个隐藏状态序列,使得在该隐藏状态(简称状态)序列下对应的观测序列出现的概率最大,本质上是一个token分类问题。以常见的中文NER任务为例,需要找出每一个中文字符对应的状态标签(BIOS标签体系),即隐藏在每一个观测字符之后的状态,也即给每一个字符做分类。

        既然是给字符(token)做分类,很自然地会想到LSTM,BERT等特征提取器。

假定表征一个中文序列的tensor的形状为(batch_size, sequence_length, hidden_size),

经过一个特征提取器之后,形状变为(batch_size, sequence_lenght, d_model),

再经过一步矩阵变换,可以将形状变为(batch_size, sequence_length, label_size),

最后经过一步softmax函数,可以将每个位置的token对应的类别标签的概率计算出来。

        到此为止,已经实现了token的分类,可以看到即使不用CRF,也可以完成token的分类任务。事实上,只用BERT模型的NER任务也得到了很好的结果。加上CRF可以为模型再加上一层限制条件,避免出现一些不合理的情况,比如I-LOC出现在了B-PER之后。

        下面我们就来看一下CRF是如何来实现这些限制的。

        我们还是从易于理解的HMM模型说起,CRF结构和参数可以与HMM进行类比。在HMM中有2个重要的假设,齐次马尔科夫假设和观测独立假设,可解释为当前隐藏状态只与前一时刻的隐藏状态相关,当前时刻的观测只与当前时刻的隐藏状态相关。模型涉及的3个参数可以表示为(π, A, B), 分别为初始时刻状态π,状态之间的转移矩阵A,状态到观测之间的发射矩阵B。模型解决的主要问题是,已知观测序列,求隐藏状态。(HMM另外两个问题是求序列概率和求模型参数)。

        CRF没有采用HMM的两个假设,而是采用了另外计算(假设)方式,马尔科夫性和无向图最大团概率计算模型。马尔科夫性可以表示为,节点(随机变量)之间没有边连接则概率无关(成对马尔科夫性)。最大团概率模型可表示为,多个随机变量取值的概率,等于概率图上所有最大团随机变量势函数的乘积。

        我们这里用的条件随机场是线性链条件随机场,由此可以将模型进一步简化,将最大团限定在两个节点之间,即线性链条件随机场中的一个最大团只包括两个节点,可以是和状态转移相关(yi-1, yi)的节点,或者是发射相关(yi,xi)的节点,由此,线性链条件随机场的参数化模型可以表示为

        Z(x)是归一化函数,t和s是特征函数,取值范围为 {0, 1}两个元素的集合,代表连个节点之间有没有边相连(没有边连接时,取值为0,可以限制不合理结果的出现)。λ和μ为权重值。

        另外两种表示形式为向量表示(也可以称为简化表示),和矩阵表示。其中向量表示是将参数和特征分别统一起来,用w(包含λ和μ)和f(包含t和s)来表示。理解矩阵表示时,可以只考虑状态之间的转移矩阵来方便理解。

        理解了马尔科夫性,最大团概率计算,线性链等概念之后,CRF模型应该也可以理解了。现在我们来看一下代码的实现。在BERT-NER-pytorch的代码中有这样几行代码,(参考BERT-NER-Pytorch/crf.py at master · lonePatient/BERT-NER-Pytorch · GitHub

def _compute_score(self, emissions, tags, mask)

         …

         score = self.start_transitions[tags[0]]  # score.shape = (batch_size)

         score += emission[0, torch.arange(batch_size), tags[0]]

         for i in range(1, seq_length):

                   score += self.transitions[tags[i-1], tags[i]] * mask[i]

                   score += emission[i, torch.arange(batch_size), tags[i]]* mask[i]

         …

        到这里计算训练模式下标签状态未归一化概率(log prob)已经结束了,代码实现如此简洁。我们来看一下函数中各个参数及其形状,看能不能和我们之前提到的CRF参数化表示形式对应上(mask和一个batch内的长度相关,为简化讨论先不考虑了)。

        tags: (seq_len, batch_size)  # seq_first, 训练时的状态标签

        start_transitions: (num_tags)

        transitions: (num_tags, num_tags)

        emissions: (seq_len, batch_size, num_tags)  # seq_first

        这里start_transitions 和transions矩阵相对容易理解。start_transition和初始状态相关,

transitions矩阵里面的值代表了状态之间的转移分数。但是观测值在哪里?通过CRF模型得到的观测值不应该是最后一个维度为词表大小的tensor吗?这里需要注意的是,观测值也是tag(或者说并没有教科书意义上的观测值),tag代表token的类别,而不是token本身。这和我们通常认为的,发射矩阵的形状应当为(num_tags, vocab_size)是不一样的。

        这里的emissions不再是一个固定的矩阵,而是由BERT模型产生的,所以CRF层只需要学习start_transitions和transitions。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
显象(场景/需求): CRF(条件随机场)模型常用于自然语言处理领域的序列标注任务,如命名实体识别、词性标注和句法分析等。这些任务的场景是在文本中识别出特定实体或给词汇赋予正确的标签,从而进行后续的信息提取和分析。 真象(内涵/实体/概念/术语): CRF是一种概率图模型,用于描述观测序列和隐藏状态序列之间的条件概率分布。在CRF中,观测序列是输入文本的序列,隐藏状态序列是待预测的标签序列。特征函数描述了观测序列和隐藏状态序列之间的关系,转移特征描述了隐藏状态序列之间的转移关系。 特征(结构/实例/原理/技术): CRF模型的实现过程可以包括以下几个步骤: 1. 特征选择:根据任务需求选择合适的特征函数。特征函数可以基于规则或通过机器学习方法得到。 2. 参数估计:利用训练数据来估计模型中的参数。常用的方法有最大似然估计和正则化方法。例如,可以使用随机梯度下降算法来最大化条件对数似然函数,更新模型参数。 3. 解码:在给定观测序列情况下,找到最可能的隐藏状态序列。常用的解码算法有维特比算法和前向-后向算法。例如,维特比算法可以通过动态规划求解出最优路径。 现象(功能/评价): CRF模型的功能是对输入的文本序列进行准确的标注,即预测每个词语所属的标签。它能够有效地利用上下文信息,提高序列标注的准确性。CRF模型在命名实体识别、词性标注和句法分析等任务上取得了良好的效果,并被广泛应用于自然语言处理领域。 变化(组合/流程): 在实际应用中,CRF模型可以与其他技术进行组合,以进一步提高性能。例如,可以将CRF模型与深度学习方法结合,利用深度学习模型提取更丰富的特征表示。流程方面,CRF模型的一般流程包括特征选择、参数估计和解码等步骤。具体流程可以根据实际需求进行调整和优化。 通过以上解释,你应该对CRF模型的原理实现有了更详尽的了解。具体的代码实现可以参考开源的机器学习库,如CRF++、sklearn-crfsuite和pytorch-crf等。这些库提供了CRF模型的基本实现,并且可以根据具体任务需求进行调整和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值