zoukankan      html  css  js  c++  java
  • 维特比算法 Viterbi

    维特比算法

    • 一种动态规划算法(动态规划 Dynamic Programming,是运筹学的一个分支,是求解决策过程最优化的过程。)

    • 用于寻找最有可能产生观测事件序列的-维特比路径-隐含状态序列

    • 特别是在马尔可夫信息源上下文和隐马尔可夫模型中


     在计算机科学领域,应用动态规划的思想解决的最基本的一个问题就是:寻找有向无环图(篱笆网络Lattice)中两个点之间的最短路径。

    从两个点之间找一条最短的路径,除了遍历完所有路径,还有什么更好的方法?答案:viterbi (维特比)算法。


     

    A→E 的最短路径 

    穷举法(遍历):每条路径需要计算4次加法,共3×3×3=27条路径,共4×27=108次计算。 

    维特比算法需要多少次计算?


    AB

    6,7, 5


    ABC

    C1: 6+5=11,7+4=11,5+4=09,  最终选择A→B3→C1,抛弃其他到C1的路径,长度09
    C2: 6+6=12,7+3=10,5+6=11,  最终选择A→B2→C2,抛弃其他到C2的路径,长度10
    C3: 6+9=15,7+7=14,5+6=11,  最终选择A→B3→C3,抛弃其他到C3的路径,长度11


    A(B)CD

                

    D1:9+7=16,10+5=15,11+5=16,最终选择A→B2→C2→D1,抛弃其他到D1的路径,长度15
    D2:9+8=17,10+4=14,11+7=18,最终选择A→B2→C2→D2,抛弃其他到D2的路径,长度14
    D3:9+3=12,10+3=13,11+6=17,最终选择A→B3→C1→D3,抛弃其他到D3的路径,长度12


    A(BC)DE

                                    

    15+4=19

    14+8=22

    12+5=17

    选择D3

    完整路径: A→B3→C1→D3→E


    计算的次数大约是多少?

    从A到B有3条路径,每一条需要算到每一个C的最短距离,所以是:2(路径加法数)×3(A→B)×3(B→C)=18,

    确定了每一个到C的最短距离,剩下的事情就可以从C开始考虑:每一个C需要确定到每一个D的最短距离:2(路径加法数)×3(C个数)×3(D个数)=18,

    最终再加上D到E的距离:2×3=6

    总计:18+18+3=39

    远远小于穷举法的108次


     

    核心思想:步步为营

    每一步把最短路径找出来,以后就不必再重新计算这一步,节约了时间。

    类似于DB优化中的选择尽量先做,没必要带着一堆没用的数据“负重前行”。


    初始状态:

    P(身体状态=正常)=0.7
    P(身体状态=轻感冒)=0.2
    P(身体状态=重感冒)=0.1


     状态转移矩阵


    发散矩阵


     观测序列:(咳嗽、发烧、拉肚子、活蹦乱跳)


     问题:

    已知观测序列,求这个人的状态序列


    代码解决问题:

    # https://blog.csdn.net/Luzichang/article/details/91365752
    
    import math
    # 状态的样本空间
    states = ('没毛病','轻感冒','重感冒')
    # 观测的样本空间
    observations = ( '活跃', '咳嗽','发烧','腹泻')
    #observations = ( '读书', '读书','读书','读书')
    #observations = ( '打球', '打球','打球','打球')
    #observations = ( '访友', '访友','访友','访友')
    #observations = ( '访友', '访友','读书','访友', '访友','访友','读书')
    # 起始个状态概率
    start_probability = {'没毛病':0.7, '轻感冒':0.2,'重感冒':0.1}
    # 状态转移概率
    transition_probability = {
      '没毛病': {'没毛病':0.7, '轻感冒':0.2,'重感冒':0.1},
      '轻感冒': {'没毛病':0.4, '轻感冒':0.4,'重感冒':0.2},
      '重感冒': {'没毛病':0.2, '轻感冒':0.5,'重感冒':0.3},
    }
    # 状态->观测的发散概率
    emission_probability = {
      '没毛病': { '活跃': 0.7,'咳嗽': 0.1, '发烧': 0.0, '腹泻': 0.2},
      '轻感冒': { '活跃': 0.5,'咳嗽': 0.2, '发烧': 0.2, '腹泻': 0.1},
      '重感冒': { '活跃': 0.3,'咳嗽': 0.2, '发烧': 0.3, '腹泻': 0.2},
    }
    # 计算以E为底的幂
    def E(x):
      #return math.pow(math.e,x)
      return x
     
     
    def display_result(observations,result_m):#较为友好清晰的显示结果
      # 从结果中找出最佳路径
      #print(result_m)
      infered_states = []
      final = len(result_m) - 1
      (p, pre_state), final_state = max(zip(result_m[final].values(), result_m[final].keys()))
      infered_states.insert(0, final_state)
      infered_states.insert(0, pre_state)
      for t in range(final - 1, 0, -1):
        _, pre_state = result_m[t][pre_state]
        infered_states.insert(0, pre_state)
      print(format("Viterbi Result", "=^80s"))
      head = format("观测序列", " ^7s")
      head += format("推断状态", " ^16s")
      for s in states:
        head += format(s, " ^15s")
      print(head)
      print(format("", "-^80s"))
     
      for obs,result,infered_state in zip(observations,result_m,infered_states):
        item = format(obs," ^10s")
        item += format(infered_state," ^18s")
        for s in states:
          item += format(result[s][0]," >12.8f")
          if infered_state == s:
            item += "(*)"
          else:
            item +="   "
     
        print(item)
      print(format("", "=^80s"))
     
     
     
    def viterbi(obs, states, start_p, trans_p, emit_p):
     
      result_m = [{}] # 存放结果,每一个元素是一个字典,每一个字典的形式是 state:(p,pre_state)
                      # 其中state,p分别是当前状态下的概率值,pre_state表示该值由上一次的那个状态计算得到
      for s in states:  # 对于每一个状态
        result_m[0][s] = (E(start_p[s]*emit_p[s][obs[0]]),None) # 把第一个观测节点对应的各状态值计算出来
        #print('11',result_m[0][s])
      for t in range(1,len(obs)):
        result_m.append({})  # 准备t时刻的结果存放字典,形式同上
     
        for s in states: # 对于每一个t时刻状态s,获取t-1时刻每个状态s0的p,结合由s0转化为s的转移概率和s状态至obs的发散概率
                         # 计算t时刻s状态的最大概率,并记录该概率的来源状态s0
                         # max()内部比较的是一个tuple:(p,s0),max比较tuple内的第一个元素值
          result_m[t][s] = max([(E(result_m[t-1][s0][0]*trans_p[s0][s]*emit_p[s][obs[t]]),s0) for s0 in states])
          #print(result_m[t][s])
      return result_m    # 所有结果(包括最佳路径)都在这里,但直观的最佳路径还需要依此结果单独生成,在显示的时候生成
     
     
    if __name__ == "__main__":
        result_m = viterbi( observations,
                            states,
                            start_probability,
                            transition_probability,
                            emission_probability)
        display_result(observations,result_m)

    输出结果如下:

    =================================Viterbi Result=================================
     观测序列        推断状态            没毛病            轻感冒            重感冒      
    --------------------------------------------------------------------------------
        活跃           没毛病          0.49000000(*)  0.10000000     0.03000000
        咳嗽           轻感冒          0.03430000     0.01960000(*)  0.00980000
        发烧           轻感冒          0.00000000     0.00156800(*)  0.00117600
        腹泻           没毛病          0.00012544(*)  0.00006272     0.00007056
    ================================================================================

     结果分析: 

    递推过程,顺向。选择每一步最短路径(最大概率),然后进行下一步。步步为营。

    注意:“每一步的最短路径”不是“最终的最短路径”,“最终的最短路径”是回溯得到的。

    回溯过程,逆向。找到最终结果的最大概率,然后逆流而上,继续找上一步的最大概率,形成一条链路,这条链路就是“最终的最短路径”。


     REF:

     

    ————————————————

    REF:

    https://blog.csdn.net/athemeroy/article/details/79339546

    https://www.zhihu.com/question/20136144

     

     

  • 相关阅读:
    使用SQL Server Management Studio操作replication时,要用机器名登录,不要用IP地址
    SQL Server Replication 总结
    SQL Server 全文索引的硬伤(转载)
    Sqlserver2008及以上使用全文索引排除干扰词 (转载)
    如何恢复VS2013代码实时校验功能
    [VS2013]如何闪开安装VS2013必须要有安装IE10的限制
    C# ASP.NET Webservice调用外部exe无效的解决方法
    nstallShield制作打包程序详解(图)
    VS报错之混合模式程序集是针对“v1.1.4322”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。
    Android之悬浮窗口实现(WindowManager)
  • 原文地址:https://www.cnblogs.com/hbuwyg/p/13247135.html
Copyright © 2011-2022 走看看