Viterbi-Algorithm(维特比)算法

CSDN博客:皮乾东
知乎:Htrying
微博:Htring的微博
微信公众号:自然语言处理爱好者(ID:NLP_lover)
文章来自:《数学之美》

Viterbi-Algorithm算法

维特比算法是一个特殊但应用最广的动态规划算法。利用动态规划,可以解决任何一个图中的最短路径问题。而维特比算法是针对一个特殊的图-篱笆网了(Lattice)的有向图最短路径问题而提出来的。它之所以重要,是因为凡是使用隐马尔科夫模型描述的问题都可以用它解码,包括当前的数字通信、语音识别、机器翻译、拼音转汉字、分词等。

背景

假定用户(盲打时)输入的拼音时 y1,y2,...,yN y 1 , y 2 , . . . , y N ,对应的汉字是 x1,x2,...,xN x 1 , x 2 , . . . , x N (虽然真正的输入法产品都是以词作为输入单位的,为了便于说明问题及简单起见,以字为单位来解释维特比算法),那么根据当前介绍的工具:

x1,x2,...,xN=ArgMaxxXP(x1,x2,...,xN|y1,y2,...,yN)=ArgMaxxXNi=1P(yi|xi)P(xi|xi1) x 1 , x 2 , . . . , x N = A r g M a x x ∈ X ⁡ P ( x 1 , x 2 , . . . , x N | y 1 , y 2 , . . . , y N ) = A r g M a x x ∈ X ⁡ ∏ i = 1 N P ( y i | x i ) P ( x i | x i − 1 ) (1)

输入的可见序列为 y1,y2,...,yN y 1 , y 2 , . . . , y N ,而产生他们的隐含序列是 x1,x2,...,xN x 1 , x 2 , . . . , x N 。可以用下图描述这样一个过程:
Viterbi-Algorithm(维特比)算法_第1张图片

这是一个相对简单的隐马尔科夫链,没用状态跳跃,也没有自环。 P(xi|xi1) P ( x i | x i − 1 ) 是状态之间的转移概率, P(yi|xi) P ( y i | x i ) 是每个状态的产生概率。现在,这个马尔科夫链的每个状态的输出是固定,但是每个状态的值可以变化。比如输出读音”zhong”的字可以是”中”、”种“等多个字。我们不妨抽象一点,用符号 xij x i j 表示状态 xi x i 的第 j j 个可能的值。如果把每个状态按照不同的值展开,就得到下面这个篱笆网络(Lattice):

Viterbi-Algorithm(维特比)算法_第2张图片
在上图中,每个状态有3个或4个值,当然时间中它们可以有任意个值。

那么从第一个状态到最后一个状态的任何一条路径(Path)都可能产生我们观察到的输出序列Y。当然这些路径的可能性不一样,而我们要做的就是找到最可能的这条路径,并不是很难。但麻烦的是这样的路径组合数非常多,会让序列状态数的增长呈指数式增长。汉语中每个无声调的拼音对应13个左右的国标汉字,假定句子长为10个字,那么这个组合数为 13105×1014 13 10 ∼ 5 × 10 14 这个计算量就相当的大了。因此,需要一个最好能和状态数目成正比的算法,而这个算法在1967年首次提出,即维特比算法。

主要内容

维特比算法基础

1.如果概率最大的路径P(或者说是最短路径)经过某个点,比如下图中的 x22 x 22 ,那么这条路径上从起始点S到 x22 x 22 的这一段路径Q,一定是S到 x22 x 22 之间的最短路径。否则,用S到 x22 x 22 的最短路径R代替Q,便构成了一条比P更短的路径,这就和之前的假设矛盾了。

2.从S到E路径必定经过第i时刻的某个状态,假定第i时刻有k个状态,那么如果记录了从S到i个状态的所有k个节点(所有时刻的所有状态)的最短路径,最终的最短路径必经过其中的一条。这样,在任何时刻,只要考虑非常有限条候选路径即可。

3.结合以上两点,假定当我们从状态i进入到i+1时,从S到i上各个节点的最短路径已经找到,并且记录到这些节点上,那么在计算出从起点S到第i+1状态的某个结点的最短路径时,只要考虑从S到前一个状态i所有的k个节点的最短路径,以及从这k个节点到 xi+1,j x i + 1 , j 的距离即可。
Viterbi-Algorithm(维特比)算法_第3张图片

维特比算法

1.从点S触发,对于第一个状态 x1 x 1 的各个节点,不妨假定有 n1 n 1 个,计算出S到它们的距离 d(S,x1i) d ( S , x 1 i ) ,这里的 x1i x 1 i 表示的是状态1的节点,因为只有一步,所以这些都是S到它们各自的最短路径。

2.(算法的关键)对于第二个状态 x2 x 2 的所有节点,要计算S到它们的最短距离,我们知道,对于特定的节点 x2i x 2 i ,可以经过状态1的 n1 n 1 中的任何一个节点 x1i x 1 i ,当然,对应的路径长度就是 d(S,x2i)=d(S,x1j)+d(x1j,x2i) d ( S , x 2 i ) = d ( S , x 1 j ) + d ( x 1 j , x 2 i ) 。由于j有 n1 n 1 种可能性,我们要一一计算,然后找出最小值。即

d(S,x2i)=minI=1,n1d(S,x1j)+d(x1j,x2i) d ( S , x 2 i ) = m i n I = 1 , n 1 d ( S , x 1 j ) + d ( x 1 j , x 2 i )

这样对于第二个状态的每个节点,需要进行 n1 n 1 次乘法计算。假定这个状态有 n2 n 2 个节点,把S这些节点的距离都计算一遍,就有 O(n1n2) O ( n 1 ⋅ n 2 ) 次计算。

接下来,类似地按照上述方法从第二个状态走到第三个状态,一直走到最好一个状态,就得到了整个网格从头到尾的最短路径。每一步计算的复杂度都和相邻两个状态 Si S i Si+1 S i + 1 各自的节点数目 ni,ni+1 n i , n i + 1 的乘积成正比,即 O(nini+1) O ( n i ⋅ n i + 1 ) 。如果假定这个在这个隐含马尔可夫链中节点最多的状态有D个节点,也就是说整个网格的宽度为D,那么任何一步的复杂度不超过 O(D2) O ( D 2 ) ,由于网格长度是N,所以整个维特比算法的复杂度是 O(ND2) O ( N ⋅ D 2 ) .

回到最初的问题中,计算量基本上是 13×13×10=1690103 13 × 13 × 10 = 1690 ≈ 10 3 ,这样就降低了很大的计算量。

总的来说,无论在语音识别、输入法打字中,输入都是按照流(Stream)的方式进行的,只要处理每个状态的时间比讲话,或者打字速度,那么无论输入有多长,解码过程永远就是实时的。
Viterbi-Algorithm(维特比)算法_第4张图片

你可能感兴趣的:(自然语言处理爱好者)