Viterbi算法

维特比算法在机器学习中非常重要,在求解隐马尔科夫和条件随机场的预测问题中均用到了维特比算法。实际上,维特比算法不仅是很多自然语言处理的解码算法,也是现代数字通信中使用最频繁的算法。

以一个简单的隐马尔科夫模型为例, 
这里写图片描述 
x=(x1,x2,...,xN)x=(x1,x2,...,xN)为观测符号,y=(y1,y2,...,yN)y=(y1,y2,...,yN)为隐状态序列,要求的预测问题为: 


(y1,y2,...,yN)=argmaxP(y1,y2,...,yN|x1,x2,...,xN)(y1,y2,...,yN)=argmaxP(y1,y2,...,yN|x1,x2,...,xN) 

依据马尔科夫假设,上式等价于: 

argmaxi=1NP(xi|yi)P(yi|yi1)argmax∏i=1NP(xi|yi)⋅P(yi|yi−1) 

在隐马尔科夫链中,任意时刻t下状态的值是有多个的,以拼音转汉字为例,输入拼音“yike”,可能有的值为一颗、一刻、一棵等等,用符号 yijyij 表示状态 yiyi 的第j个可能值,将状态序列按值展开,就得到了一个篱笆网络,这也是维特比算法求解最优路径的图结构: 

这里写图片描述 

隐马尔科夫的预测问题就是要求图中的一条路径,使得该路径对应的概率值最大。 
对应上图来讲,如果直接求的话,有 3N3N 的组合数,底数3为篱笆网络宽度,指数N为篱笆网络的长度,计算量非常大。维特比利用动态规划的思想来求解概率最大路径(可理解为求图最短路径),使得复杂度正比于序列长度,复杂度为 O(ND2)O(N⋅D2) ,N为长度,D为宽度,从而很好地解决了问题的求解。

维特比算法的基础可以概括为下面三点(吴军:数学之美): 
1、如果概率最大的路径经过篱笆网络的某点,则从开始点到该点的子路径也一定是从开始到该点路径中概率最大的。 
2、假定第i时刻有k个状态,从开始到i时刻的k个状态有k条最短路径,而最终的最短路径必然经过其中的一条。 
3、根据上述性质,我们在计算第i+1状态的最短路径时,只需要考虑从开始到当前的k个状态值的最短路径和当前状态值到第i+1状态值的最短路径即可,如求t=3时的最短路径,等于求t=2时的所有状态结点y2iy2i的最短路径加上t=2到t=3的各节点的最短路径。

为了记录中间变量,引入变量δψδ和ψ。定义t时刻到状态为i的所有结点最大概率值(最短路径): 


δt(i)=maxP(it=i,it1,...,i1,ot,...,o1|λ),i=1,2,...,Nδt(i)=maxP(it=i,it−1,...,i1,ot,...,o1|λ),i=1,2,...,N 

其中, itit 表示最短路径, otot 表示观测符号, λλ 表示模型参数。依据上式可以得出变量 δδ 的递推式: 

δt+1(i)=max[δt(j)aji]bi(ot+1)δt+1(i)=max[δt(j)aji]bi(ot+1) 

i=1,2,...,N;t=1,2,...,T1i=1,2,...,N;t=1,2,...,T−1 。 
表示t时刻处于状态j,t+1时刻转移到状态i且观测到符号 ot+1ot+1 的最大概率。 
定义 ψt(i)ψt(i) 为时刻t到状态为i的概率最大路径的前一个时刻经过的结点,即它保存了最短路径所经过的结点: 

ψt(i)=argmax1jN[δt1(j)aji]ψt(i)=argmax1≤j≤N⁡[δt−1(j)aji] 

使用维特比算法的一个例子(统计学习方法): 
例:给出隐马尔科夫模型参数λ=(A,B,π)λ=(A,B,π)
转移矩阵

A=0.50.30.20.20.50.30.30.20.5A=[0.50.20.30.30.50.20.20.30.5]

观测概率矩阵 
B=0.50.40.70.50.60.3B=[0.50.50.40.60.70.3]

初始状态矩阵 
π=0.20.40.4π=[0.20.40.4]

已知观测序列O=(红,白,红),试求最优状态序列。 
求解过程如下: 
(1)、计算t=1时刻的概率 δ1(i)δ1(i)


δ1(i)=πibi(o1)=πibi()δ1(i)=πibi(o1)=πibi(红) 

即求t=1时刻观测到红球,对应的状态i可能是1,2,3的概率,可解得 
δ1(1)=0.2×0.5=0.1,δ1(1)=0.2×0.5=0.1,  
δ1(2)=0.4×0.4=0.16,δ1(2)=0.4×0.4=0.16,  
δ1(3)=0.4×0.7=0.28δ1(3)=0.4×0.7=0.28  
(2)、计算t=2时刻的概率 δ2(i)psi2(i)δ2(i)和psi2(i) ,根据前面 δ,ψδ,ψ 定义来求: 
δ2(1)=max1j3[δ1(j)aj1]bi(o2)δ2(1)=max1≤j≤3⁡[δ1(j)aj1]bi(o2)  
=max{0.1×0.5×0.5,0.16×0.3×0.5,0.28×0.2×0.5}=max{0.1×0.5×0.5,0.16×0.3×0.5,0.28×0.2×0.5}  
=0.028=0.028  
ψ2(1)=3ψ2(1)=3  
同样可求, 
δ2(2)=0.0504,ψ2(2)=3δ2(2)=0.0504,ψ2(2)=3  
δ2(3)=0.042,ψ2(3)=3δ2(3)=0.042,ψ2(3)=3  
(3)、计算t=3时刻的概率 δ3(i)psi3(i)δ3(i)和psi3(i)  
计算过程与t=2时刻的计算过程相同,可得: 
δ3(1)=0.00756,ψ3(1)=2δ3(1)=0.00756,ψ3(1)=2  
δ3(2)=0.01008,ψ3(2)=2δ3(2)=0.01008,ψ3(2)=2  
δ3(3)=0.0147,ψ3(3)=3δ3(3)=0.0147,ψ3(3)=3  
(4)、根据最短路径回溯找到所经过的结点 
由(3)可知,t=3时,最短路径对应的最大概率为0.0147,为上一时刻t=2时结点3到达当前结点3所得到的概率; 
t=2时,由 ψ2(3)=3ψ2(3)=3 可知,最短路径由上一时刻t=1时结点3到当前结点3; 

综上,可得到当观测序列为(红,白,红)时最可能对应的状态序列为(3,3,3)。




维特比算法viterbi的简单实现 python版

1、Viterbi是隐马尔科夫模型中用于确定(搜索)已知观察序列在HMM;下最可能的隐藏序列。Viterb采用了动态规划的思想,利用后向指针递归地计算到达当前状态路径中的最可能(局部最优)路径。

2、代码:

import numpy as np
# -*- codeing:utf-8 -*-
__author__ = 'youfei'

#   隐状态
hidden_state = ['sunny', 'rainy']

#   观测序列
obsevition = ['walk', 'shop', 'clean']


#   根据观测序列、发射概率、状态转移矩阵、发射概率
#   返回最佳路径
def compute(obs, states, start_p, trans_p, emit_p):
    #   max_p(3*2)每一列存储第一列不同隐状态的最大概率
    max_p = np.zeros((len(obs), len(states)))

    #   path(2*3)每一行存储上max_p对应列的路径
    path = np.zeros((len(states), len(obs)))

    #   初始化
    for i in range(len(states)):
        max_p[0][i] = start_p[i] * emit_p[i][obs[0]]
        path[i][0] = i

    for t in range(1, len(obs)):
        newpath = np.zeros((len(states), len(obs)))
        for y in range(len(states)):
            prob = -1
            for y0 in range(len(states)):
                nprob = max_p[t-1][y0] * trans_p[y0][y] * emit_p[y][obs[t]]
                if nprob > prob:
                    prob = nprob
                    state = y0
                    #   记录路径
                    max_p[t][y] = prob
                    for m in range(t):
                        newpath[y][m] = path[state][m]
                    newpath[y][t] = y

        path = newpath

    max_prob = -1
    path_state = 0
    #   返回最大概率的路径
    for y in range(len(states)):
        if max_p[len(obs)-1][y] > max_prob:
            max_prob = max_p[len(obs)-1][y]
            path_state = y

    return path[path_state]


state_s = [0, 1]
obser = [0, 1, 2]

#   初始状态,测试集中,0.6概率观测序列以sunny开始
start_probability = [0.6, 0.4]

#   转移概率,0.7:sunny下一天sunny的概率
transititon_probability = np.array([[0.7, 0.3], [0.4, 0.6]])

#   发射概率,0.4:sunny在0.4概率下为shop
emission_probability = np.array([[0.1, 0.4, 0.5], [0.6, 0.3, 0.1]])

result = compute(obser, state_s, start_probability, transititon_probability, emission_probability)

for k in range(len(result)):
    print(hidden_state[int(result[k])])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

3、运行结果

"C:\Program Files\Python35\python.exe" E:/软件工具/untitled/viterbi/viterbi.py
rainy
sunny
sunny

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/youfefi/article/details/74276546

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值