维特比算法用来解决HMM的预测问题(解码decoding),即已知模型HMM和观测序列 O=(O1,O2,...On) ,求对给定观测序列条件概率 P(I/O) 的最大状态序列 I=(I1,I2,...In) .
维特比算法实际用动态规划的思想来求解HMM模型预测问题。由动态规划原理,最优路径具有这样特性:如果最优路径在时刻t通过结点 I∗t ,那么这一路径从结点 I∗t 到终点 I∗T 的部分路径,对于所有从 I∗t 到终点 I∗T 的可能部分路径来说必须是最优的。因为假如不是这样,那么从 I∗t 到 I∗T 就会有另一条更好的部分路径存在,如果把它和从 I∗1 到 I∗t 的的部分路径连起来,就会形成一条比原来更有的路径,这是矛盾的。
因此,基于以上思想,我们只需从时刻 t=1 开始,递推地计算在时刻 t 状态为 i 的各条部分路径的最大概率,直至得到时刻 t=T 状态为 j 的各条路径的最大概率。时刻 t=T 的最大概率即为最优路径的概率 P∗ ,最优路径的终结点 I∗T 也同时求得。之后,为了找出最优路径的各个节点,从终结点 I∗T 开始,由后向前逐步求得节点 IT−1∗ ,…, I∗1 ,得到最优路径 I∗=(i∗1,i∗2,...,i∗T) .
导入变量 δ 和 ψ ,定义在时刻 t 状态为 i 的所有单个路径 (i∗1,i∗2,...,i∗T) 中概率最大值为
由此可得变量 δ 递推公式:
定义在时刻 t 状态为 i 的所有单个路径 (i∗1,i∗2,...,i∗T) 中概率最大的路径的 t−1 个节点为
输入:模型 λ=(A,B,π) 和观测序列 O=(O1,O2,...On)
输出:最优路径 I∗=(i∗1,i∗2,...,i∗T) .
step1:初始化
δ1(i)=πibi(O1),i=1,2,...N
ψ1(i)=0,i=1,2,...N
step2:递推,对 t=2,3,...T
δt=max0<j<=N[δt−1(j)aji]bi(Ot),i=1,2,...N
ψt(i)=max0<j<=N[δt−1(j)aji],i=1,2,...N
step3:终止
p∗=max0<i<=NδT(i)
i∗t=argmax0<i<=N[δT(i)]
step4:最优路径回溯,对 t=T−1,T−2,...1
i∗t=ψt+1(i∗t+1)
#include
#include
#include
using namespace std;
int main()
{
double pi[3] = { 0.2, 0.4, 0.4 };
double C[3][3] = { 0.5, 0.2, 0.3, 0.3, 0.5, 0.2, 0.2, 0.3, 0.5 };
double E[3][2] = { 0.5, 0.5, 0.4, 0.6, 0.7, 0.3 };
string output[4] = { "R", "W", "R","W" };
int state[3] = { 1, 2, 3 };
int row = 3;
int column = 3;
//开辟数组空间
double **delta = new double *[row];
int **path = new int *[row];
int i, j,k;
for (i = 0; i < 3; i++)
{
delta[i] = new double[3];
path[i] = new int[3];
}
//将输出状态转为数组
int outnum[4];
for (i = 0; i < row; i++)
{
if (output[i] == "R")
outnum[i] = 0;
else if (output[i] == "W")
outnum[i] = 1;
}
//初始化
for (i = 0; i < column; i++)
{
path[i][0] = 0;
delta[i][0] = pi[i] * E[i][0];
cout << delta[i][0] << endl;
}
//递归
for (j = 1; j < row; j++)//序列遍历,矩阵列遍历
{
for (k = 0; k < column; k++)//状态遍历
{
double pro = 0;
int sta = 0;
for (i = 0; i < column; i++)//矩阵行遍历
{
double temp = delta[i][j - 1] *C[i][k]* E[k][outnum[j]] ;//delta[i][j-1]*转移概率*发射概率
cout << delta[i][j - 1] << " " << E[k][outnum[j]] << endl;
cout << temp << endl;
if (temp > pro)
{
pro = temp;
sta = i;//记录路径信息
}
}
delta[k][j] = pro;
path[k][j]= sta;
}
}
//终止,找到概率最大值
double max = 0;
int sta = 0;
for (i = 0; i < column; i++)
{
if (delta[i][row - 1] > max)
{
max = delta[i][row - 1];
sta = i;
}
}
//回溯,找到最大路径及其对应的状态值
list<int> listPath;
listPath.push_back(sta+1);
for (j = row - 1; j > 0; j--)
{
sta = path[sta][j];
listPath.push_back(sta+1);
}
//输出
cout << "max probability: " << max << endl;
list<int> ::iterator itepath;
for (itepath = listPath.begin(); itepath != listPath.end(); itepath++)
cout << *itepath << " ";
}