Viterbi 原理及简单实现
维特比算法:
维特比算法由安德鲁·维特比(Andrew Viterbi) 于1967年提出,用于在数字通信链路中解卷积以消除噪音。 此算法被广泛应用于 CDMA 和 GSM 数字蜂窝网络、拨号调制解调器、卫星、深空通信和 802.11 无线网络中解卷积码。维特比算法是一个特殊但应用最广的动态规划算法。利用动态规划,可以解决任何一个图中的最短路径问题。而维特比算法是针对一个特殊的图—篱笆网络(Lattice)的有向图最短路径问题而提出的。它之所以重要,是因为凡是使用隐含马尔可夫模型描述的问题都可以用它来解码,包括今天的数字通信、语音识别、机器翻译、拼音转汉字、分词等。
算法原理
维特比算法就是所有观测序列中的最优,如下图所示,我们要求从S到E的最优序列,中间有3个时刻,每个时刻都有对应的不同观察的概率。(其实过程类似于求解最短路径)
我们可以想到用暴力算法求解出所有的路径概率,然后找出最优的。但是当观察序列过长或者中间状态过多时会有很高的时间复杂度。这个时候就该viterbi算法出场了。
viterbi算法是每次记录到当前时刻,每个观察标签的最优序列。也就是我们可以将上图中的9个隐含状态看作是A、B、C三个group。以B组中的B1为例,B1只需要记录A几到B1是最优的而不用记录所有的An到B1的路径。如下图使用viterbi算法我们只需要记录其中黄色路径,其它部分的路径都可以不用储存。
Python实现
import numpy as np
def viterbi_decoder(nodes , trans):
"""
## ViterBi 算法求解最优路径
"""
seq_len, num_labels = len(nodes), len(trans)
scores = nodes[0].reshape((-1, 1))
paths = []
for i in range(1, seq_len):
observe = nodes[i].reshape((-1, 1))
M = scores + trans + observe
scores = np.max(M, axis=0).reshape((-1, 1))
idxs = np.max(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