隐马尔可夫模型(HMM)

隐马尔可夫模型是关于时序的概率模型,描述由一个隐藏的马尔可夫链随机生成不可观测的转态随机序列,再由各个转态生成一个观测而产生观测随机序列的过程。隐藏的马尔可夫链随机生成的状态的序列,称为状态序列;每个状态生成一个观测,而由此产生的观测的随机序列,称为观测序列,序列的每一个位置又可以看作一个时刻。


隐马尔可夫模型由初始概率分布,状态转移概率分布以及观测概率分布确定。

HMM=(A,B,pai)

状态转移概率矩阵A和初始状态概率向量pai确定了隐藏的马尔可夫链,生成不可观测的状态序列。观测概率矩阵B确定了如何从状态生成观测,与状态序列综合确定了如何产生观测序列。


隐马尔可夫模型做了两个基本假设:

(1)齐次马尔可夫性假设,即假设隐藏的马尔可夫链在任意时刻t的状态只依赖于前一时刻状态,与其他时刻的状态及观测无关,也与时刻t无关。

(2)观测独立性假设,即假设任意时刻的观测只依赖于该时刻的马尔可夫链的转态,与其他观测及状态无关。


隐藏马尔可夫模型可以用于标注,这时状态对应着标记,标注问题是给定观测的序列预测其对应的标记序列。可以假设标注问题的数据是由隐马尔可夫模型生成的。这样我们就可以利用隐马尔可夫模型的学习与预测算法进行标注。


隐马尔可夫模型的三个基本问题:

1.概率计算问题。给定模型M=(A,B,pai)和观测序列O=(o1,o2,..on),计算在模型下观测序列O出现的概率
P(O|M)

2.学习问题。已知观测序列O=(o1,o2,..on),估计模型M=(A,B,pai)参数,使得在该模型下观测序列P(O|M)最大。即用极大似然估计的方法估计参数

3.预测问题,也成为解码(decoding)。已知模型M=(A,B,pai)和观测序列O=(o1,o2,..on),求对给定观测序列条件概率P(I|O)最大的状态序列I=(i1,i2,..in).即给定观测序列,求最有可能的对应的状态序列。


概率计算问题:

前向算法:给定隐马尔可夫模型模型M,定义到时刻t部分观测序列为o1,o2,...,ot且状态为qi的概率为前向概率,记做:at(i) = P(o1,o2,...,ot,it=qi|M)

可以递推地求得前向概率at(i)以及观测序列P(O|M)。


后向算法:

后向概率:给定隐马尔可夫模型,定义在时刻t状态为qi的条件下,从t+1到T的部分观测序列为ot+1,ot+2,..oT的概率记做后向概率。


学习算法:

隐马尔可夫模型的学习,根据训练数据是包括观测序列和对应的状态序列还是只有观测序列,可以分别由监督学习与非监督学习实现。


1.监督学习方法

假设已给训练数据包含S个长度相同的观测序列和对应的状态序列{(o1,I1),...,(On,In)},可以用极大似然估计方法来估计隐马尔可夫模型的参数。


2.非监督学习方法

假设给定训练数据只包含S个长度为T的观测序列{(O1,...,Os)}而没有对应的状态序列,目标是学习隐马尔可夫模型M=(A,B,pai)的参数。


预测算法

近似算法和维特比算法。

维特比算法实际是用动态规划解隐马尔可夫模型预测问题,即用动态规划求概率最大路径。

我们只需要从时刻t=1开始,递推地计算在时刻t状态为i的各部分路径的最大概率,直至得到时刻t=T状态为i的各条路径的最大概率。时刻T的最大概率即为最优路径的概率P*,最优路径的终结点iT*也同时得到。之后为了找出最优路径的各个节点,从终结点iT*开始,由后向前逐步求得节点iT-1*,...,i1*,得到最优路径。这就是维特比算法。


java实现代码:

public class Viterbi {
    public static int[] compute(int[] obs, int[] states, double[] start_p, double[][] trans_p, double[][] emit_p)
    {
        double[][] V = new double[obs.length][states.length];
        int[][] path = new int[states.length][obs.length];

        for (int y : states)
        {
            V[0][y] = start_p[y] * emit_p[y][obs[0]];
        }

        for (int t = 1; t < obs.length; ++t)
        {
            for (int y : states)
            {
                double prob = -1, tmp=-1;
                int state = -1;
                for (int y0 : states)
                {
                    double nprob = V[t - 1][y0] * trans_p[y0][y] * emit_p[y][obs[t]];
                    double nstate = V[t-1][y0]*trans_p[y0][y];
                    if (nprob > prob)
                    {
                        prob = nprob;
                    }

                    if(nstate > tmp) {
                        state = y0;
                        tmp = nstate;
                    }

                }

                V[t][y] = prob;
                path[y][t-1] = state;
            }

        }

        double prob = -1;
        int state = 0;
        for (int y : states)
        {
            if (V[obs.length - 1][y] > prob)
            {
                prob = V[obs.length - 1][y];
                state = y;
            }
        }

        int[] ans = new int[obs.length];
        int cnt = obs.length-1;
        ans[cnt--] = state;

        while (cnt >= 0) {
            state = path[state][cnt];
            ans[cnt--] = state;
        }
        return ans;
    }
}


public class Main {
    static enum Weather
    {
        Rainy,
        Sunny,
    }
    static enum Activity
    {
        walk,
        shop,
        clean,
    }

    static int[] states = new int[]{Rainy.ordinal(), Sunny.ordinal()};
    static int[] observations = new int[]{walk.ordinal(), shop.ordinal(), clean.ordinal()};
    static double[] start_probability = new double[]{0.6, 0.4};
    static double[][] transititon_probability = new double[][]{
            {0.7, 0.3},
            {0.4, 0.6},
    };
    static double[][] emission_probability = new double[][]{
            {0.1, 0.4, 0.5},
            {0.6, 0.3, 0.1},
    };

    public static void main(String[] args)
    {
        int[] result = Viterbi.compute(observations, states, start_probability, transititon_probability, emission_probability);
        for (int r : result)
        {
            System.out.print(Weather.values()[r] + " ");
        }
        System.out.println();
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值