维特比算法C++实现

概述

维特比算法用来解决HMM的预测问题(解码decoding),即已知模型HMM和观测序列 O=(O1,O2,...On) ,求对给定观测序列条件概率 P(I/O) 的最大状态序列 I=(I1,I2,...In) .

维特比算法实际用动态规划的思想来求解HMM模型预测问题。由动态规划原理,最优路径具有这样特性:如果最优路径在时刻t通过结点 It ,那么这一路径从结点 It 到终点 IT 的部分路径,对于所有从 It 到终点 IT 的可能部分路径来说必须是最优的。因为假如不是这样,那么从 It IT 就会有另一条更好的部分路径存在,如果把它和从 I1 It 的的部分路径连起来,就会形成一条比原来更有的路径,这是矛盾的。

因此,基于以上思想,我们只需从时刻 t=1 开始,递推地计算在时刻 t 状态为 i 的各条部分路径的最大概率,直至得到时刻 t=T 状态为 j 的各条路径的最大概率。时刻 t=T 的最大概率即为最优路径的概率 P ,最优路径的终结点 IT 也同时求得。之后,为了找出最优路径的各个节点,从终结点 IT 开始,由后向前逐步求得节点 IT1 ,…, I1 ,得到最优路径 I=(i1,i2,...,iT) .

导入变量 δ ψ ,定义在时刻 t 状态为 i 的所有单个路径 (i1,i2,...,iT) 中概率最大值为

δt(i)=maxi1,i2...it1P(it=i,it1,...i1,Ot,...,O1|λ),i=1,2,...N

由此可得变量 δ 递推公式:

δt+1(i)=maxi1,i2...itP(it+1=i,it,...i1,Ot+1,...,O1|λ)=max0<j<=N[δt(j)aji]bi(Ot+1),i=1,2,...N

定义在时刻 t 状态为 i 的所有单个路径 (i1,i2,...,iT) 中概率最大的路径的 t1 个节点为

ψt(i)=argmax0<j<=N[δt1(j)aji],i=1,2,...N

维特比算法

输入:模型 λ=(A,B,π) 和观测序列 O=(O1,O2,...On)
输出:最优路径 I=(i1,i2,...,iT) .
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[δt1(j)aji]bi(Ot),i=1,2,...N
ψt(i)=max0<j<=N[δt1(j)aji],i=1,2,...N

step3:终止
p=max0<i<=NδT(i)
it=argmax0<i<=N[δT(i)]

step4:最优路径回溯,对 t=T1,T2,...1
it=ψt+1(it+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 << " ";



}

你可能感兴趣的:(基础算法)