int newpath[][] = new int[state.length][obs.length];// 每次迭代时,定义一个新的存储path,因为每个时间序列的path都依赖于
// 上个序列的path
// 对该时间序列上的每个state节点进行迭代,每个节点都与上个序列的所有state交互
for (int s : state) {
double maxValue = -1.0;
int label = -1;
for (int s0 : state) {// 寻找出备选路径
double viterbiValue = v[t - 1][s0] * trans_p[s0][s] * emit_p[s][obs[t]];
if (viterbiValue > maxValue) {
maxValue = viterbiValue;
label = s0;
// 记录最大概率
v[t][s] = maxValue;
// 记录路径
System.arraycopy(path[label], 0, newpath[s], 0, t);
newpath[s][t] = s;
}
}
}
path = newpath;
}
// 找出最后一个时间序列上的viterbi值最大的state,从而找出最优路径
double maxValue = -1.0;
int label = -1;
for (int s : state) {
if (v[obs.length - 1][s] > maxValue) {
maxValue = v[obs.length - 1][s];
label = s;
}
}
return path[label];
}
}
测试文件:
1 packagecom.nlp.hmm.algorithm.viterbi;2
3
4 public classViterbiTest {5
6 public static voidmain(String[] args) {7 int[] obs = {0,1,2};//0--walk,1--shop,2--clean
8 int[] states = {0,1};//0--rainy,1--sunny
9 double[] start_p = {0.6,0.4};//0.6--rainy,0.4--sunny
10 double[][] trans_p = new double[states.length][states.length];//0--rainy,1--sunny
11 trans_p[0][0] = 0.7;12 trans_p[0][1] = 0.3;13 trans_p[1][0] = 0.4;14 trans_p[1][1] = 0.6;15 double[][] emit_p = new double[states.length][obs.length];//dimension1:rainy 0,sunny 1;dimension2:walk 0 shop 1 clean 2
16 emit_p[0][0] = 0.1;17 emit_p[0][1] = 0.4;18 emit_p[0][2] = 0.5;19 emit_p[1][0] = 0.6;20 emit_p[1][1] = 0.3;21 emit_p[1][2] = 0.1;22 int []path =Viterbi.compute(obs, states, start_p, trans_p, emit_p);23 for (intpa:path){24 System.out.print(pa+" ");25 }26 }27
28 }
输出结果为1,0,0,就是sunny,rainy,rainy。对比了一下,结果没问题,逻辑也没问题。维特比算法和前向搜索算法有着共同点,两者解决的hmm问题不一样。
下面是本人的python实现代码:
import numpy as np
def viterbi(obs,state,start_prob,transition_prob,emit_prob):
vit = np.array(np.zeros(shape = [len(obs),len(state)],dtype = np.float64))
path = np.array(np.zeros(shape = [len(state),len(obs)],dtype = np.int32))
#初始化
for i in range(len(state)):
vit[0,i] = start_prob[i] * emit_prob[i][0]
path[i][0] = state[i]
for t in range(1,len(obs)):
newPath = np.zeros_like(path)
v = np.dot(np.reshape(vit[t-1],[len(state),1]),np.reshape(emit_prob[:,t],[1,len(state)])) * transition_prob
vi = np.max(v,axis = 0)
vit[t,:] = vi[:]
pa = np.argmax(v,axis = 0)
for i in range(len(pa)):
label = pa[i]
newPath[i,:] = path[label,:]
newPath[i][t] = state[i]
path = newPath
return path[np.argmax(vit[len(obs)-1,:]),:]