简单理解viterbi算法

部署运行你感兴趣的模型镜像

简介:

viterbi算法其实就是多步骤每步多选择模型的最优选择问题,其在每一步的所有选择都保存了前续所有步骤到当前步骤当前选择的最小总代价(或者最大价值)以及当前代价的情况下前继步骤的选择。依次计算完所有步骤后,通过回溯的方法找到最优选择路径。符合这个模型的都可以用viterbi算法解决。

用以下例子加以说明:

1.题目背景:

从前有个村儿,村里的人的身体情况只有两种可能:健康或者发烧。假设这个村儿的人没有体温计或者百度这种神奇东西,他唯一判断他身体情况的途径就是到村头我的偶像金正月的小诊所询问。月儿通过询问村民的感觉,判断她的病情,再假设村民只会回答正常、头晕或冷。有一天村里奥巴驴就去月儿那去询问了。第一天她告诉月儿她感觉正常。第二天她告诉月儿感觉有点冷。第三天她告诉月儿感觉有点头晕。那么问题来了,月儿如何根据阿驴的描述的情况,推断出这三天中阿驴的一个身体状态呢?为此月儿上百度搜 google ,一番狂搜,发现维特比算法正好能解决这个问题。月儿乐了。

2.已知情况:

隐含的身体状态 = { 健康 , 发烧 }
可观察的感觉状态 = { 正常 , 冷 , 头晕 }
月儿预判的阿驴身体状态的概率分布 = { 健康:0.6 , 发烧: 0.4 }这就是初始状态序列
月儿认为的阿驴身体健康状态的转换概率分布 = {健康->健康: 0.7 ,健康->发烧: 0.3 ,发烧->健康:0.4 ,发烧->发烧: 0.6}
这样就可以列出相应的状态转移矩阵
月儿认为的在相应健康状况条件下,阿驴的感觉的概率分布 = {健康,正常:0.5 ,冷 :0.4 ,头晕: 0.1 ;发烧,正常:0.1 ,冷 :0.3 ,头晕: 0.6 }这样就可以列出相应的观测矩阵
下面就是解决问题了。阿驴连续三天的身体感觉依次是: 正常、冷、头晕 。

3.题目:

已知如上,求:阿驴这三天的身体健康状态变化的过程是怎么样的?即已知观测序列和HMM模型的情况下,求状态序列。

4.过程:

这里写图片描述
最后一天的状态概率分布即为最优路径的概率,即P(最优)=0.01512,这样我们可以得到最优路径的终点,是发烧。这样,我们的状态序列逆推出来了。即为:健康,健康,发烧。

简要的画个图:

这里写图片描述

代码实现:

import math
# 状态的样本空间
states = ('健康', '发热')
# 观测的样本空间
observations = ('正常', '发冷', '发晕')
# 起始个状态概率
start_probability = {'健康': 0.6, '发热': 0.4}
# 状态转移概率
transition_probability = {
  '健康': {'健康': 0.7, '发热': 0.3},
  '发热': {'健康': 0.4, '发热': 0.6},
}
# 状态->观测的发散概率
emission_probability = {
  '健康': {'正常': 0.5, '发冷': 0.4, '发晕': 0.1},
  '发热': {'正常': 0.1, '发冷': 0.3, '发晕': 0.6},
}
# 计算以E为底的幂
def E(x):
  #return math.pow(math.e,x)
  return x


def display_result(observations,result_m):
  """
  较为友好清晰的显示结果
  :param result_m:
  :return:
  """
  # 从结果中找出最佳路径
  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", "=^59s"))
  head = format("obs", " ^10s")
  head += format("Infered state", " ^18s")
  for s in states:
    head += format(s, " ^15s")
  print(head)
  print(format("", "-^59s"))

  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("", "=^59s"))



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) # 把第一个观测节点对应的各状态值计算出来

  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])
  return result_m    # 所有结果(包括最佳路径)都在这里,但直观的最佳路径还需要依此结果单独生成,在显示的时候生成


def example():
  """
  一个可以交互的示例
  """
  result_m = viterbi(observations,
                 states,
                 start_probability,
                 transition_probability,
                 emission_probability)
  display_result(observations,result_m)
  while True:
    user_obs = input("轮到你来输入观测,计算机来推断可能状态\n"
                "使用 'N' 代表'正常', 'C' 代表'发冷','D'代表'发晕'\n"
                "您输入:('q'将退出):")

    if len(user_obs) ==0 or 'q' in user_obs or 'Q' in user_obs:
      break
    else:
      obs = []
      for o in user_obs:
        if o.upper() == 'N':
          obs.append("正常")
        elif o.upper() == 'C':
          obs.append("发冷")
        elif o.upper() == 'D':
          obs.append("发晕")
        else:
          pass
      result_m = viterbi(obs,
                       states,
                       start_probability,
                       transition_probability,
                       emission_probability)
      display_result(obs,result_m)



if __name__ == "__main__":
  example()

运行结果:

这里写图片描述
参考自:
https://www.zhihu.com/question/20136144/answer/154753703
https://www.zhihu.com/question/20136144/answer/239971177
https://www.zhihu.com/question/20136144/answer/132882429

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

维特比算法在自然语言处理领域有多种应用,其原理基于动态规划,以下是详细介绍: ### 应用 - **词性标注**:词性标注是对文本进行语言学分析的重要工具,能帮助计算机理解和处理自然语言文本。通过词性标注,计算机可更准确理解句子结构和含义,实现信息抽取、文本分类、句法分析等自然语言处理任务。它是各类基于文本的机器学习任务(如语义分析、指代消解)的预处理步骤,是自然语言处理中重要的基础性工作[^3]。 - **中文分词**:维特比算法可用于寻找最有可能产生观测事件序列的“维特比路径”隐含状态序列,能解决图中的最短路径问题。在中文分词里,可将输入的文本看作观察序列,分词结果看作隐藏状态序列,从而找到最合理的分词方式[^4]。 - **语音识别**:在语音识别中,维特比算法可用于在隐马尔可夫模型(HMM)中寻找最可能的隐藏状态序列(即最优路径),结合给定的观察序列(语音信号),实现语音到文字的转换[^2]。 ### 原理 维特比算法是一种动态规划算法,用于在隐马尔可夫模型(HMM)中寻找最可能的隐藏状态序列(即最优路径),给定一个观察序列。在隐马尔科夫链中,任意时刻 t 下状态的值有多个,将状态序列按值展开,会得到一个篱笆网(特殊的图——篱笆网络的有向图(Lattice)),这是维特比算法求解最优路径的图结构。隐马尔科夫的预测问题是求图中的一条路径,使该路径对应的概率值最大。若直接求解,组合数非常大,计算量巨大。维特比利用动态规划思想求解概率最大路径(可理解为求图最短路径),使复杂度正比于序列长度,复杂度为 O(N⋅D⋅D),N 为长度,D 为宽度,从而有效解决问题[^2][^4]。 ### 相关技术 - **隐马尔可夫模型(HMM)**:维特比算法常与隐马尔可夫模型结合使用。HMM 是一种统计模型,用于描述一个含有隐含未知参数的马尔可夫过程。在自然语言处理中,可将文本的生成看作一个隐藏状态序列(如词性、分词结果等)生成观察序列(如文本)的过程,通过 HMM 来建模这个过程,再利用维特比算法寻找最优的隐藏状态序列[^2][^4]。 ```python # 以下是一个简单的维特比算法示例(用于词性标注简化版) # 假设已经有了转移概率矩阵、发射概率矩阵等 states = ('N', 'V') # 词性状态,名词和动词 observations = ('dog', 'runs') # 观察序列 start_probability = {'N': 0.6, 'V': 0.4} transition_probability = { 'N': {'N': 0.7, 'V': 0.3}, 'V': {'N': 0.4, 'V': 0.6} } emission_probability = { 'N': {'dog': 0.8, 'runs': 0.2}, 'V': {'dog': 0.1, 'runs': 0.9} } def viterbi(obs, states, start_p, trans_p, emit_p): V = [{}] path = {} # 初始化第一步 for y in states: V[0][y] = start_p[y] * emit_p[y][obs[0]] path[y] = [y] # 递推计算后续步骤 for t in range(1, len(obs)): V.append({}) newpath = {} for y in states: (prob, state) = max((V[t - 1][y0] * trans_p[y0][y] * emit_p[y][obs[t]], y0) for y0 in states) V[t][y] = prob newpath[y] = path[state] + [y] path = newpath # 找到最终的最优路径 (prob, state) = max((V[len(obs) - 1][y], y) for y in states) return path[state] result = viterbi(observations, states, start_probability, transition_probability, emission_probability) print("最优词性标注序列:", result) ```
评论 11
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值