Viterbi算法
Viterbi 算法是一种动态规划(Dynamic Programming)算法,主要用于在隐马尔可夫模型(Hidden Markov Model, HMM)中寻找最可能的隐藏状态序列(即最优路径),使得该序列能够生成观测到的输出序列。
一、背景:隐马尔可夫模型(HMM)
HMM 包含以下要素:
- 状态集合 \(S = \{s_1, s_2, ..., s_N\}\):隐藏的、不可直接观测的状态。
- 观测集合 $ O = {o_1, o_2, ..., o_T}$:可以观测到的输出序列(长度为 T)。
- 初始状态概率 $ \pi = \{\pi_i\} $:系统在时刻 1 处于状态 $ s_i $ 的概率。
- 状态转移概率矩阵 $ A = [a_{ij}] $:从状态 $ s_i $ 转移到 $ s_j $ 的概率。
- 观测概率矩阵(发射概率)$ B = [b_j(k)] $:在状态 $ s_j $ 下观测到 $ o_k $ 的概率。
二、Viterbi 算法目标
给定观测序列 $ O = (o_1, o_2, ..., o_T) $ 和 HMM 参数 $ (\pi, A, B) $,求最可能的隐藏状态路径 \[ Q^* = (q_1^*, q_2^*, ..., q_T^*) \],使得:
\[ Q^* = \arg\max_{Q} P(Q | O; \lambda) \]
其中 $ = (\pi, A, B) $ 是 HMM 的参数。
由于直接枚举所有可能路径(共 $ N^T $ 条)计算量过大,Viterbi 算法通过动态规划在 $ O(N^2 T) $ 时间内高效求解。
三、Viterbi 算法步骤
1. 初始化(t = 1)
对每个状态 $ s_i ( i = 1, ..., N $):
\[ \delta_1(i) = \pi_i \cdot b_i(o_1) \] \[ \psi_1(i) = 0 \]
- $ \delta_t(i) $:时刻 t 时,以状态 $ s_i $ 结尾的最大路径概率。
- $ \psi_t(i) $:记录时刻 t 时,使路径概率最大的前一状态(用于回溯)。
2. 递推(t = 2 到 T)
对每个时刻 $ t = 2, ..., T $,对每个状态 $ s_j $:
\[ \delta_t(j) = \max_{1 \le i \le N} \left[ \delta_{t-1}(i) \cdot a_{ij} \right] \cdot b_j(o_t) \] \[ \psi_t(j) = \arg\max_{1 \le i \le N} \left[ \delta_{t-1}(i) \cdot a_{ij} \right] \]
3. 终止
\[ P^* = \max_{1 \le i \le N} \delta_T(i) \] \[ q_T^* = \arg\max_{1 \le i \le N} \delta_T(i) \]
4. 回溯(路径重构)
对 $ t = T-1, T-2, ..., 1 $:
\[ q_t^* = \psi_{t+1}(q_{t+1}^*) \]
最终得到最优状态序列 \[ Q^* = (q_1^*, q_2^*, ..., q_T^*) \]
四、举例说明(简化)
假设:
- 状态:Rainy (R), Sunny (S)
- 观测:Walk, Shop, Clean
- 观测序列:[Walk, Shop, Clean]
给定 HMM 参数后,Viterbi 算法会计算每一步每个状态的最大概率路径,并记录回溯指针,最终输出最可能的天气序列,例如 [Sunny, Rainy, Rainy]。
五、应用场景
- 语音识别(将声学信号映射到音素序列)
- 自然语言处理(词性标注、命名实体识别)
- 生物信息学(基因序列分析)
- 通信(解卷积、纠错码)
六、注意事项
Viterbi 找的是最可能的单一路径,不是所有路径的期望或平均。
若概率值非常小,建议使用对数概率避免浮点下溢:
将乘法转为加法: \[ \log \delta_t(j) = \max_i \left[ \log \delta_{t-1}(i) + \log a_{ij} \right] + \log b_j(o_t) \]
下面是一个 Python 实现 Viterbi 算法 的完整示例,适用于隐马尔可夫模型(HMM)。
我们将用一个经典的例子:天气预测(隐藏状态)和人的活动(观测值)。
🌦️ 问题设定
- 隐藏状态(Hidden
States):
['Rainy', 'Sunny'] - 观测值(Observations):
['walk', 'shop', 'clean'] - 观测序列:
['walk', 'shop', 'clean'] - 目标:找出最可能的天气序列(如
['Sunny', 'Rainy', 'Rainy'])
🔧 HMM 参数定义
1 | # 隐藏状态 |
✅ Viterbi 算法实现(使用对数概率避免下溢)
1 | import math |
🧪 使用示例
1 | if __name__ == "__main__": |
输出示例: 1
2观测序列: ['walk', 'shop', 'clean']
最可能的隐藏状态序列: ['Sunny', 'Rainy', 'Rainy']