viterbi算法主要解決已知HMM和觀察序列,找到最可能的隱藏狀態,也就是所說的解碼問題。解碼在語音識別中的應用就是,根據一段聲音序列,找到最有可能對應的文字序列。
html
仍是天氣和水藻的這個例子,咱們運用viterbi算法找出dry,damp,soggy對應的天氣狀況。全部的已知條件和以前那個前向算法都是一直的,不一樣之處就是求解的過程。java
1. 根據初始機率和觀察機率,計算t=0時刻的機率值,保存在delta數組的第一列算法
2. 計算t=i 時刻(i < T)狀態j (j < M)下機率的值,選出最大的機率值maxVal,乘以觀察機率保存到delta數組 中,而後將相應的索引值保存到path數組中。數組
3. 在t = T -1時刻,選出最大的那個機率值,最大機率值保存在prob中,同時用k記下對應的行號,並將k存入list的頭部ide
4. t從 T - 1開始循環到t=1,由於當前t時刻path數組中的值保存的是t-1時刻的行號,所以循環的取出該值,最後就是所要求的隱藏狀態的路徑了。網站
java版viterbi算法:spa
package cn.yunzhisheng.hmm;htm
import java.util.LinkedList;索引
import java.util.List;get
publicclass HMM {
publicint M = 3;
// 轉移矩陣
publicdouble[][] transferMatix = {
{0.500, 0.375, 0.125},
{0.250, 0.125, 0.625},
{0.250, 0.375, 0.375}
};
// 觀察矩陣
publicdouble[][] observationMatix = {
{0.60, 0.20, 0.15, 0.05},
{0.25, 0.25, 0.25, 0.25},
{0.05, 0.10, 0.35, 0.50}
};
// 初始機率
publicdouble[] pi = {0.63, 0.17, 0.20};
public List<Integer> viterbi(int[] seq){
int T = seq.length;
// 保存計算的機率
double [][] delta = newdouble[M][T];
// 保存最佳路徑
int [][] path = newint[M][T];
// 當前機率的值
double val = 0.0;
// 保存當前最大機率的值
double maxVal = 0.0;
// t-1時刻最大機率的索引
int maxIndex = 0;
// t = 0 用初始機率乘以相應觀察矩陣的機率,保存到delta的第一列中
for(int j = 0; j < M; j++){
delta[j][0] = pi[j] * observationMatix[j][seq[0]];
}
for(int t = 1; t < T; t++){
for(int j = 0; j < M; j++){
maxVal = 0.0;
maxIndex= 0;
for(int i = 0; i < M; i++){
val = delta[i][t-1] * transferMatix[i][j];
if(val > maxVal){
// 保存最大機率
maxVal= val;
// 保存t-1時刻的索引
maxIndex = i;
}
}
// 將機率保存在delta數組中
delta[j][t] = maxVal * observationMatix[j][seq[t]];;
path[j][t] = maxIndex;
}
}
// 對最後一列,比較機率,找到最大機率的索引
double prob = 0.0;
int k = 0;
for(int j = 0; j < M; j++){
if(delta[j][T-1] > prob){
prob = delta[j][T-1];
k = j;
}
}
System.out.println("prob=" + prob);
LinkedList<Integer> list = new LinkedList<Integer>();
list.addFirst(k);
int row = k;
for(int t = T-1; t > 0; t--){
int v = path[row][t];
list.addFirst(v);
row = v;
}
return list;
}
publicstaticvoid main(String[] args) {
HMM hmm = new HMM();
// 觀察序列
int [] seq = {0, 2, 3};
// 前向算法
//double p = hmm.forward(seq);
//System.out.println(p);
// 維特比算法
List<Integer> weather = hmm.viterbi(seq);
System.out.println(weather);
}
}
運行結果:
prob=0.01107421875
[0, 1, 2]
即最終的隱藏狀態是:sunny,cloudy,rainy
注:http://www.comp.leeds.ac.uk/roger/HiddenMarkovModels/html_dev/viterbi_algorithm/s3_pg3.html 這個網站計算有問題,它把狀態矩陣給弄反了
個人計算結果和 umdhmm是同樣的,同時手工計算的也是這個結果。