【ML】从HMM到CRF,我学到了什么?


可以略过的前言

朴素贝叶斯

朴素贝叶斯是一个分类模型

朴素贝叶斯基于一个假设:条件独立性假设。这个假设在说,在类别确定的条件下,用于分类的特征是相互独立的.换言之,假设每个特征独立地对分类结果发生影响。

假设,数据中,某个样本特征由F=\{f_1,f_2,...f_n\}表示,该样本被分成第C类的概率由贝叶斯公式:P(C|F) = \frac{P(F|C)P(C)}{P(F)}来估算。

其中:

P(C)是类"先验"(prior) 概率;P(F|C)是样本相对于类标记 C的类条件概率(class-conditional probability) ,或称为"似然" (likelihood); P(F)用于归一化的"证据" (evidence) 因子,对给定样本 ,证据因子 P(F)与类标 记无关,因此估计P(C|F)的问题就转化为如何基于训练数据来估计先验 P(C)和似然 P(F|C);

P(C)可以由当前数据中第C类的数量占比来估计(大数定律)。即:P(C) = 第C类的样本数量/总样本数量。 

P(F|C)因为条件独立的前提,即为P(f_1,f_2,...,f_n|C)=P(f_1|C)*P(f_2|C)*...*P(f_n|C)后者通过简单统计即可求得。

总之,我们利用朴素贝叶斯求解的模型一般形式为:

P(X=x|y=C_k) = P(X^{(1)}=x^{(1)},...,X^{(n)}=x^{(n)}|Y=C_k) =P(C_k)\prod_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=C_k)

马尔可夫模型

HMM是可用于序列到序列的生成模型。常用于分词、机器翻译、语音识别、生物工程方面。

一个分词的应用场景是:比如,我要对文本进行分词,采用'sbme'标注(即对于该句子中的每一个字,其应该被标注成单独的词-s, 还是一个词的开始-b,中间-m,或结尾-e)。如果我们通过数据集D训练得到一个HMM模型H,则对于输入序列\lambda_1,\lambda_2,...,\lambda_n,模型H能根据maxP(o_1,o_2,...,o_n|\lambda_1,\lambda_2,...,\lambda_n)输出最优标注序列,如(['s','b',...,'e'])。

HMM基于两个假设:

1、观测独立性假设

2、齐次马尔科夫假设

这种性质决定了HMM中所有变量的联合概率分布为:

P(x_1,y_1,\cdots,x_n,y_n)=P(y_1)\prod^n_{i=2}P(y_i|y_{i-1})P(x_i|y_i)

推导:

对于估计maxP(o|\lambda)的问题,由贝叶斯公式:P(o|\lambda) = \frac{p(\lambda |o)P(o)}{P(\lambda)},

则原问题转化为maxP(\lambda|o)P(o)

由观测独立性假设,有P(\lambda|o) = P(\lambda_1|o_1) P(\lambda_2|o_2)... P(\lambda_n|o_n)

P(o) = P(o_1)P(o_2|o_1)P(o_3|o_1,o_2)...P(o_n|o_1,o_2,...,o_{n-1})由马尔可夫假设:

P(o) = P(o_1)P(o_2|o_1)P(o_3|o_2)...P(o_n|o_{n-1})

于是,原问题最终化为:P(\lambda|o)P(o)\sim P(\lambda_1|o_1)P(\o_2|o_1)P(\lambda_2|o_2)P(o_3|o_2)....P(\lambda_n|o_{n-1})P(\o_n|o_{n-1})

P(\lambda_k|o_k)发射概率P(o_k|o_{k-1})转移概率

所以HMM是利用状态转移概率和发射概率计算最优解答,这是一个生成模型。

当然穷举是不可能穷举的,试想假设我们有|S| 个可能的状态,而状态序列的长度为 L., 那么我们显然有|S|^L 个可能的序列y. 我们需要Viterbi 算法,一个可以降低复杂度至O(L|S|^2) 的算法。

具体应用:

来模拟一个HMM分词器。我们可以根据统计词典D来统计出各个字的发射概率和各字之间转移概率。

词典D 的形式可参考:词典文件

则HMM分词器的代码为(参考【中文分词系列】 3. 字标注法与HMM模型 - 科学空间|Scientific Spaces):

from collections import Counter
from math import log

hmm_model = {i:Counter() for i in 'sbme'}

# 通过字典估计发射概率
with open('dict.txt', encoding="utf8") as f:  
    for line in f.readlines():
        lines = line.split(' ')
        if len(lines[0]) == 1:
            hmm_model['s'][lines[0]] += int(lines[1])
        else:
            hmm_model['b'][lines[0][0]] += int(lines[1])
            hmm_model['e'][lines[0][-1]] += int(lines[1])
        for m in lines[0][1:-1]:
            hmm_model['m'][m] += int(lines[1])
# 使用了对数概率,防止溢出
# s,b,m,e 分别对应的总对数概率
log_total = {i:log(sum(hmm_model[i].values())) for i in 'sbme'}

# 直觉估计或通过词典数据统计出转移概率
# 构建转移矩阵
trans_t = {'ss':0.1,
    'sb':0.7,
    'bm':0.6,
    'be':0.7, 
    'mm':0.3,
    'me':0.7,
    'es':0.2,
    'eb':0.7
 }


import numpy as np
trans = np.zeros((4,4))
for k, v in trans_t.items():
    idx1, idx2 = 'sbme'.index(k[0]),'sbme'.index(k[1])
    trans[idx1][idx2] = log(v)

def viterbi_decode(nodes, trans):
    """
    Viterbi算法求最优路径
    其中 nodes.shape=[seq_len, num_labels],
        trans.shape=[num_labels, num_labels].
    """
    seq_len, num_labels = len(nodes), len(trans)
    scores = nodes[0].reshape((-1, 1))
    paths = []
    # # 递推求解上一时刻t-1到当前时刻t的最优
    for t in range(1, seq_len):
        observe = nodes[t].reshape((1, -1))
        M = scores + trans + observe
        scores = np.max(M, axis=0).reshape((-1, 1))
        idxs = np.argmax(M, axis=0)
        paths.append(idxs.tolist())

    best_path = [0] * seq_len
    best_path[-1] = np.argmax(scores)
    # 最优路径回溯
    for i in range(seq_len-2, -1, -1):
        idx = best_path[i+1]
        best_path[i] = paths[i][idx]
        
    return best_path

def hmm_cut(s):
    # 计算每个字的发射概率
    nodes = [{i:(log(j[t]+1)-log_total[i]) for i,j in hmm_model.items()} for t in s]
    nodes = np.array([list(d.values()) for d in nodes])
    # 通过发射概率和转移概率矩阵,计算最优路径
    tags = viterbi_decode(nodes, trans)
    words = [s[0]]
    for i in range(1, len(s)):
        if 'sbme'[tags[i]] in ['b', 's']:
            words.append(s[i])
        else:
            words[-1] += s[i]
    return words

HMM的不足

HMM只依赖于每一个状态和它对应的观察对象但是序列标注问题不仅和单个词相关,而且和观察序列的长度,单词的上下文,等等相关。

最大熵马尔可夫模型

MEMM是一种判别式有向图模型。相较于HMM由隐藏状态产生输入(观测),MEMM基于输入(观测)产生隐藏状态(condition on observations)。相比于HMM,MEMM更直观,因为目标是预测出隐藏状态,而不是基于隐藏状态来预测观测。

他打破了HMM的观测独立性假设,直接对条件概率建模,用 P(y_i|y_{i-1}, x_i)来代替HMM中的两个条件概率P(y_i|y_{i-1})P(x_i|y_i),它表示在先前状态 y_{i-1} ,观测值 x_i 下得到当前状态 y_i 的概率,即根据前一状态和当前观测。预测当前状态。可以在长距离上得到features。

相比与HMM,MEMM的y_i依旧前一时刻的y_{i-1}有关。但他考虑了(x_i,y_{i-1}) 的共同作用。

具体建模公式如下:

P(y|x)=P(y_1)\prod^n_{i=2}P(y_i|y_{i-1},x_i)

P_{y_{i-1}}(y_i|x_{i})=\frac{1}{Z(x_{i},y_{i-1})}\sum_a^m(\lambda_af_a(x_{i},y_i))

每个这样的分布函数 P_{y_{i-1}}(y_i|x_i)都是一个服从最大熵的指数模型。

这个指数模型让MEMM在 每个状态 (y_{i-1},x_i,y_i) 都做了局部归一化,因而可能会产生标注偏置的问题。

举两个例子:

如图所示,“因为”原本应该是介词词性p,而 MEMM却错误标注其词性为连词c。产生该情况的原因正是一种偏置问题。

原因:“是”存在两个词性,动词v和代词r,包含在状态集合S1中;“因为”包括两个词性,介词p与连词c,包含在状态集合S2中;“事”只有一个词性,名词n,包含在状态集合S3中。由于MEMM对每个状态均定义一个指数模型,因此有:P(n|p)=1, P(n|c)=1, P(p|S1)+P(c|S1)=1; 基于马尔科夫假设,P(S1, p, n)=P(p|S1)*P(n|p)=P(p|S1), 同理,P(S1, c, n)=P(c|S1)*P(n|c)=P(c|S1)。因此S2选择p节点还是c节点只取决于P(p|S1)、P(c|S1),即只与“是”的上下文有关,与“因为”的上下文无关,这即使MEMM产生偏置的一种情况。引自《基于条件随机域的词性标注模型

条件随机场

x=\{x_1,x_2,\cdots,x_n\} 为观测序列,y=\{y_1,y_2,\cdots,y_n\}为对应的标记序列,则条件随机场的目标是对P(y|x) 建模。通常情况下我们讨论的都是链式条件随机场(CRF)。

p(Y|X)为线性条件随机场,则在随机变量X取值为x 的条件下,随机变量Y取值为y的条件概率具有如下形式:

P(y|x)=\frac{1}{Z(x)}exp(\sum_{i,k}\lambda_kt_k(y_{i-1},y_i,x,i)+\sum_{i,l}u_is_l(y_i,x,i))

其中,Z(x)=\sum_{y}exp(\sum_{i,k}\lambda_kt_k(y_{i-1},y_i,x,i)+\sum_{i,l}u_is_l(y_i,x,i))

t_k,s_l是特征函数,\lambda_k,u_l是权重。

可以看到,相较于MEMM,CRF是无向图模型,全局性的归一化(最大团上的归一化)比于MEMM的局部归一化更优,因而解决了MEMM存在的标注偏置问题。

同时CRF的特征函数定义非常灵活,可以自定义。CRF中的发射概率和HMM的不一样,是p(y|x),(HMM中是p(x|y)).CRF中整个隐藏序列y依赖于整个观察序列x

同样跟着李宏毅老师理解CRF,认识CRF的目标函数:

CRF假设观测序列x和状态序列y 的概率满足 :P(x,y) \propto exp(w \cdot \phi (x,y)),w 将从训练数据中学习得到。

根据联合概率与边缘概率分布之间的关系,我们有P(y|x) = \frac {P(x,y)}{\sum_{​{y}'}P(x,{y}')},而P(x,y) = \frac{exp(w \cdot \phi (x,y))}{R},那么:

\\P(y|x) = \frac{exp(w \cdot \phi (x,y))}{\sum_{​{y}'\in \mathbb{Y}}exp(w \cdot \phi (x,{y}'))}= \frac{exp(w \cdot \phi (x,y))}{Z(x)}。这样,我们就建立了conditional model。{\color{DarkRed} {Z(x)}} 就是全局规范化因子。

为什么:P(x,y) \propto exp(w \cdot \phi (x,y))?他与HMM的函数有多少区别?

我们看HMM的函数:

P(x,y)=P(y_1)\prod^n_{i=2}P(y_i|y_{i-1})P(x_i|y_i)

取log:

logP(x,y)=logP(y_1)+{\color{Orange} \sum^n_{i=2}logP(y_i|y_{i-1})} + {\color{Red} \sum^n_{i=2}logP(x_i|y_i)}

在序列标注中,可以有如下的等价关系:

{\color{Red} \sum^n_{i=2}logP(x_i|y_i) }= \sum_{s,t}{\color{Blue} logP(t|s)} \times {\color{Magenta} N_{s,t}(x,y)}

为什么可以这样子转换,可以看下图的示例:

同理:

{\color{Orange} \sum^n_{i=2}logP(y_i|y_{i-1})} = \sum_{s,{s}'}{\color{Blue} logP({s}'|s)} \times {\color{Magenta} N_{s,{s}'}(x,y)}

那么:

logP(x,y)=logP(y_1)+{\color{Orange} \sum^n_{i=2}logP(y_i|y_{i-1})} + {\color{Red} \sum^n_{i=2}logP(x_i|y_i)}\\= \sum_{s,t}{\color{Blue} logP(t|s)} \times {\color{Magenta} N_{s,t}(x,y)}\\+\sum_{s,{s}'}{\color{Blue} logP({s}'|s)} \times {\color{Magenta} N_{s,{s}'}(x,y)}\\= {\color{Blue} \begin{bmatrix} ... \\ logP(t|s) \\ ... \\ logP({s}'|s) \\ ... \end{bmatrix} }\cdot {\color{Magenta} \begin{bmatrix} ... \\ N_{s,t}(x,y) \\ ... \\ N_{s,{s}'}(x,y) \\ ... \end{bmatrix}}\\={\color{Blue} w} \cdot {\color{Magenta} \phi(x,y)}

所以:P(x,y) \propto exp(w \cdot \phi (x,y))

这里直接引用李宏毅老师的课件转述特征函数的一个计算示例:

 |S|*|S|+2|S|是因为有start 和 end tag。

关于参数的训练:

 CRF比HMM更进一步的,在基于统计的基础上,CRF会调整参数W的值,使之更能fit 数据。

关于bilstmCRF在做序列标注,尤其是NER时,对于CRF的描述,知乎上的回答很中肯:


简单说就是条件随机场可以把label的上下文学出来。lstm加softmax分类的时候只能把特征的上下文关系学出来,label的没学出来。

作者:火华

我理解B-LSTM+CRF模型,所谓在LSTM上面套CRF其实是不严谨的说法,假如这样说,那实际上是两层sequence model了吗。我认为其实是说把LSTM和CRF融合起来。比如LSTM的产出只有发射概率,尽管这个发射概率考虑到了上下文,因为LSTM有门机制,可以记忆或者遗忘前面内容,然后双向,有前有后这样,但是毕竟没有转移概率,像CRF HMM这种,都是结合发射概率和转移概率的。比如在词性标注,最简单BIO这样,有显而易见的规则,就是B-X后面不会有I-Y。所以干脆搞出B-LSTM+CRF,结合发射概率和转移概率这样。实际上后面接的CRF并不是真的CRF,比如它又没有特征模板,它又不接受离散特征,他只是一次Viterbi推导而已。


参考

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半九拾

援助一个bug吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值