学习目标:
在本篇我们会讨论维特比算法解码隐藏状态序列 Q Q Q,即给定模型 λ \lambda λ 和观测序列 O O O,求给定观测序列 O O O 条件下,最可能出现的对应的隐藏状态序列 Q ∗ Q^* Q∗。
HMM 模型的解码问题最常用的算法是维特比算法,当然也有其他的算法可以求解这个问题。同时维特比算法是一个通用的求序列最短路径的动态规划算法,也可以用于很多其他问题。
HMM 模型的解码问题即:
给定模型 λ = ( A , B , Π ) \lambda=(A,B,\Pi) λ=(A,B,Π) 和 观测序列 O = o 1 , o 2 , . . . , o T O = o_1,o_2, ..., o_T O=o1,o2,...,oT,求给定观测序列 O O O 条件下,最可能出现的对应的隐藏状态序列 Q ∗ = q 1 ∗ , q 2 ∗ , . . . , q T ∗ Q^*=q^*_1, q^*_2, ..., q^*_T Q∗=q1∗,q2∗,...,qT∗,即 P ( Q ∗ ∣ O ) P(Q^*|O) P(Q∗∣O) 的最大化。
一个可能的近似解法是求出观测序列 O O O 在每个时刻 t t t 最可能的隐藏状态 q t ∗ q^*_t qt∗,然后得到一个近似的隐藏状态序列 Q ∗ = q 1 ∗ , q 2 ∗ , . . . , q T ∗ Q^*=q^*_1, q^*_2, ..., q^*_T Q∗=q1∗,q2∗,...,qT∗。要这样近似求解不难,利用前向后向算法评估观察序列概率的定义:
Q t ∗ = a r g m a x i ≤ i ≤ N ( ˚ i ) t = 1 , 2 , . . . , T Q^*_t = \underset{i \le i \le N}{\mathrm{arg max}} \r(i) \quad t = 1, 2, ..., T Qt∗=i≤i≤Nargmax(˚i)t=1,2,...,T
其中:
近似算法很简单,但是却不能保证预测的状态序列 Q ∗ Q^* Q∗ 整体是最可能的状态序列 Q best Q_{\text{best}} Qbest,因为预测的状态序列 Q ∗ Q^* Q∗ 中某些相邻的隐藏状态 q q q 可能存在转移概率 a i j a_{ij} aij 为 0 的情况。
而维特比算法可以将 HMM 的状态序列作为一个整体来考虑,避免近似算法的问题,下面我们来看看维特比算法进行 HMM 解码的方法。
维特比算法是一个通用的解码算法,是基于动态规划的求序列最短路径的方法。既然是动态规划算法,那么就需要找到合适的局部状态,以及局部状态的递推公式。
在 HMM 中,维特比算法定义了两个局部状态用于递推:
【第一个局部状态 δ t ( q ) \delta_t(q) δt(q)】第一个局部状态是在时刻 t t t 隐藏状态为 q q q 所有可能的状态转移路径 q 1 , q 2 , . . . , q t q_1,q_2, ..., q_t q1,q2,...,qt 中的概率最大值,记为 δ t ( q ) \delta_t(q) δt(q):
δ t ( q ) = max q 1 , q 2 , . . . , q t − 1 P ( q t = q , q 1 , q 2 , . . . , q t − 1 , o t , o t − 1 , . . . , o 1 ∣ λ ) i = 1 , 2 , . . . , N \delta_t(q) = \underset{q_1, q_2, ..., q_{t-1}}{\max}P(q_t = q, q_1, q_2, ..., q_{t-1}, o_t, o_{t-1}, ..., o_1|\lambda) \quad i = 1, 2, ..., N δt(q)=q1,q2,...,qt−1maxP(qt=q,q1,q2,...,qt−1,ot,ot−1,...,o1∣λ)i=1,2,...,N
由 δ t ( q ) \delta_t(q) δt(q) 的定义可以得到 δ \delta δ 的递推表达式:
δ t + 1 ( q ) = max q 1 , q 2 , . . . , q t P ( q t + 1 = q , q 1 , q 2 , . . . , q t , o t + 1 , o t , . . . , o 1 ∣ λ ) = max 1 ≤ j ≤ N [ δ t ( j ) a j i ] b i ( o t + 1 ) \begin{aligned} \delta_{t+1}(q) & = \underset{q_1, q_2, ...,q_t}{\max}P(q_{t+1} = q, q_1, q_2, ..., q_t, o_{t+1}, o_t, ..., o_1 | \lambda)\\ &= \underset{1\le j \le N}{\max}[\delta_t(j)a_{ji}]b_{i}(o_{t+1}) \end{aligned} δt+1(q)=q1,q2,...,qtmaxP(qt+1=q,q1,q2,...,qt,ot+1,ot,...,o1∣λ)=1≤j≤Nmax[δt(j)aji]bi(ot+1)
【第二个局部状态 ψ t ( q ) \psi_t(q) ψt(q)】第二个局部状态由第一个局部状态递推得到。
我们定义在时刻 t t t 隐藏状态为 q q q 的所有单个状态转移路径 ( q 1 , q 2 , . . . , q t − 1 ) (q_1,q_2, ..., q_{t-1}) (q1,q2,...,qt−1) 中概率最大的转移路径中第 t − 1 t-1 t−1 个节点的隐藏状态为 ψ t ( q ) \psi_t(q) ψt(q)。其递推表达式可以表示为:
ψ t ( q ) = argmax 1 ≤ j ≤ N [ δ t − 1 ( j ) a j i ] \psi_t(q) = \underset{1 \le j \le N}{\text{argmax}}[\delta_{t-1}(j)a_{ji}] ψt(q)=1≤j≤Nargmax[δt−1(j)aji]
有了这两个局部状态,我们就可以从时刻 0 一直递推到时刻 T T T,然后利用 ψ t ( i ) \psi_t(i) ψt(i) 记录的前一个最可能的状态节点回溯,直到找到最优的隐藏状态序列。
其中:
维特比算法通过动态规划来求解最优状态序列,具有较高的效率和准确性。
流程如下:
步骤一:初始化局部状态
δ 1 ( q ) = Π i b i ( o 1 ) i = 1 , 2 , . . . , N ψ 1 ( q ) = 0 i = 1 , 2 , . . . , N \begin{aligned} & \delta_1(q) = \Pi_i b_i (o_1) \quad i = 1, 2, ..., N\\ & \psi_1(q) = 0 \quad i = 1, 2, ..., N \end{aligned} δ1(q)=Πibi(o1)i=1,2,...,Nψ1(q)=0i=1,2,...,N
步骤二:进行动态规划递推时刻 t = 2 , 3 , . . . , T t = 2, 3,..., T t=2,3,...,T 的局部状态
δ t ( q ) = max 1 ≤ j ≤ N [ δ t − 1 ( j ) a j i ] b i ( o t ) i = 1 , 2 , . . . , N ψ t ( i ) = argmax 1 ≤ j ≤ N [ δ t − 1 ( j ) a j i ] i = 1 , 2 , . . . , N \begin{aligned} & \delta_t(q) = \underset{1 \le j \le N}{\max}[\delta_{t-1}(j)a_{ji}]b_i(o_t) \quad & i = 1, 2, ..., N\\ & \psi_t(i) = \underset{1 \le j \le N}{\text{argmax}}[\delta_{t-1}(j)a_{ji}] \quad & i = 1, 2, ..., N \end{aligned} δt(q)=1≤j≤Nmax[δt−1(j)aji]bi(ot)ψt(i)=1≤j≤Nargmax[δt−1(j)aji]i=1,2,...,Ni=1,2,...,N
步骤三:计算时刻 T T T 最大的 δ T ( i ) \delta_T(i) δT(i),即为最可能隐藏状态序列出现的概率。计算时刻 T T T 最大的 ψ t ( q ) \psi_t(q) ψt(q),即为时刻 T T T 最可能的隐藏状态。
P ∗ = max 1 ≤ j ≤ N δ T ( i ) q T ∗ = argmax 1 ≤ j ≤ N [ δ T ( q ) ] \begin{aligned} & P^* = \underset{1 \le j \le N}{\max} \delta_T(i)\\ & q^*_T = \underset{1 \le j \le N}{\text{argmax}}[\delta_T(q)] \end{aligned} P∗=1≤j≤NmaxδT(i)qT∗=1≤j≤Nargmax[δT(q)]
步骤四:利用局部状态 ψ t ( i ) \psi_t(i) ψt(i) 开始回溯。对于 t = T − 1 , T − 2 , . . . , 1 t = T - 1, T- 2, ..., 1 t=T−1,T−2,...,1:
q t ∗ = ψ t + 1 ( q t + 1 ∗ ) q^*_t = \psi_{t+1}(q^*_{t+1}) qt∗=ψt+1(qt+1∗)
最终得到最有可能的隐藏状态序列 Q ∗ = q 1 ∗ , q 2 ∗ , . . . , q T ∗ Q^* = q^*_1, q^*_2, ..., q^*_T Q∗=q1∗,q2∗,...,qT∗。
其中:
下面我们仍然用盒子与球的例子来看看 HMM 维特比算法求解。我们的观察集合是:
V = { 红 , 白 } M = 2 \begin{aligned} & V = \{ 红,白 \}\\ & M = 2 \end{aligned} V={红,白}M=2
我们的状态集合是:
Q = { 盒子 1 , 盒子 2 , 盒子 3 } N = 3 \begin{aligned} & Q = \{盒子1, 盒子2, 盒子3\}\\ & N = 3 \end{aligned} Q={盒子1,盒子2,盒子3}N=3
而观察序列 O O O 和状态序列 i i i 的长度为都为 3。
初始状态分布为:
Π = ( 0.2 , 0.4 , 0.4 ) T \Pi = (0.2, 0.4, 0.4)^T Π=(0.2,0.4,0.4)T
状态转移概率分布矩阵 A A A(不可见的,隐含的)为:
A = [ 0.5 0.2 0.3 0.3 0.5 0.2 0.2 0.3 0.5 ] N × N = 3 × 3 A = \begin{bmatrix} 0.5 & 0.2 & 0.3\\ 0.3 & 0.5 & 0.2\\ 0.2 & 0.3 & 0.5 \end{bmatrix}_{N \times N = 3 \times 3} A= 0.50.30.20.20.50.30.30.20.5 N×N=3×3
行表示第几次抽球(从2开始);列表示使用第几个盒子的概率
观测状态概率矩阵 B B B(可见的)为:
B = [ 0.5 0.5 0.4 0.6 0.7 0.3 ] N × M = 3 × 2 B = \begin{bmatrix} 0.5 & 0.5\\ 0.4 & 0.6\\ 0.7 & 0.3 \end{bmatrix}_{N \times M = 3 \times 2} B= 0.50.40.70.50.60.3 N×M=3×2
行代表第几个盒子;列1代表红球的概率,列2代表白球的概率
球的颜色的观测序列:
O = { 红 , 白 , 红 } O = \{红, 白, 红\} O={红,白,红}
按照我们前面的维特比算法,首先需要得到三个隐藏状态在 时刻1 时对应的各自两个局部状态,此时观测状态为 1:
δ 1 ( 1 ) = Π 1 b 1 ( o 1 ) = 0.2 第一个盒子 × 0.5 红球 = 0.1 δ 1 ( 2 ) = Π 2 b 2 ( o 1 ) = 0.4 第二个盒子 × 0.4 红球 = 0.16 δ 1 ( 3 ) = Π 3 b 3 ( o 1 ) = 0.4 第三个盒子 × 0.7 红球 = 0.16 ψ 1 ( 1 ) = ψ 1 ( 2 ) = ψ 1 ( 3 ) = 0 \begin{aligned} & \delta_1(1) = \Pi_1b_1(o_1) = \underset{第一个盒子}{0.2} \times \underset{红球}{0.5} = 0.1\\ & \delta_1(2) = \Pi_2b_2(o_1) = \underset{第二个盒子}{0.4} \times \underset{红球}{0.4} = 0.16\\ & \delta_1(3) = \Pi_3b_3(o_1) = \underset{第三个盒子}{0.4} \times \underset{红球}{0.7} = 0.16\\ & \psi_1(1) = \psi_1(2) = \psi_1(3) = 0 \end{aligned} δ1(1)=Π1b1(o1)=第一个盒子0.2×红球0.5=0.1δ1(2)=Π2b2(o1)=第二个盒子0.4×红球0.4=0.16δ1(3)=Π3b3(o1)=第三个盒子0.4×红球0.7=0.16ψ1(1)=ψ1(2)=ψ1(3)=0
ψ 1 ( 1 ) = ψ 1 ( 2 ) = ψ 1 ( 3 ) = 0 \psi_1(1) = \psi_1(2) = \psi_1(3) = 0 ψ1(1)=ψ1(2)=ψ1(3)=0 是因为初始化设定它们为 0
现在开始递推三个隐藏状态在 时刻2 时对应的各自两个局部状态,此时观测状态为 2:
δ 2 ( 1 ) = max 1 ≤ j ≤ 3 [ δ 1 ( j ) a j 1 ] b 1 ( o 2 ) = max 1 ≤ j ≤ 3 [ 0.1 上一次是盒子 1 × 0.15 盒子 1 → 盒子 1 ‾ 第一种情况 , 0.16 上一次是盒子 2 × 0.3 盒子 2 → 盒子 1 ‾ 第二种情况 , 0.28 上一次是盒子 3 × 0.2 盒子 3 → 盒子 1 ‾ 第三种情况 ] × 0.5 白球 = 0.028 ψ 2 ( 1 ) = 3 最大值对应的索引 ( 从 1 开始 ) δ 2 ( 2 ) = max 1 ≤ j ≤ 3 [ δ 1 ( j ) a j 2 ] b 2 ( o 2 ) = max 1 ≤ j ≤ 3 [ 0.1 上一次是盒子 1 × 0.2 盒子 1 → 盒子 2 ‾ 第一种情况 , 0.16 上一次是盒子 2 × 0.5 盒子 2 → 盒子 2 ‾ 第二种情况 , 0.28 上一次是盒子 3 × 0.3 盒子 3 → 盒子 2 ‾ 第三种情况 ] × 0.6 白球 = 0.0504 ψ 2 ( 2 ) = 3 最大值对应的索引 ( 从 1 开始 ) δ 2 ( 3 ) = max 1 ≤ j ≤ 3 [ δ 1 ( j ) a j 3 ] b 3 ( o 2 ) = max 1 ≤ j ≤ 3 [ 0.1 上一次是盒子 1 × 0.3 盒子 1 → 盒子 3 ‾ 第一种情况 , 0.16 上一次是盒子 2 × 0.2 盒子 2 → 盒子 3 ‾ 第二种情况 , 0.28 上一次是盒子 3 × 0.5 盒子 3 → 盒子 3 ‾ 第三种情况 ] × 0.3 白球 = 0.042 ψ 2 ( 3 ) = 3 最大值对应的索引 ( 从 1 开始 ) \begin{aligned} & \delta_2(1) = \underset{1 \le j \le 3}{\max}[\delta_1(j)a_{j1}]b_1(o_2) = \underset{1 \le j \le 3}{\max}[\underset{第一种情况}{\underline{\underset{上一次是盒子1}{0.1} \times \underset{盒子1\rightarrow盒子1}{0.15}}}, \underset{第二种情况}{\underline{\underset{上一次是盒子2}{0.16} \times \underset{盒子2\rightarrow盒子1}{0.3}}}, \underset{第三种情况}{\underline{\underset{上一次是盒子3}{0.28} \times \underset{盒子3\rightarrow盒子1}{0.2}}}] \times \underset{白球}{0.5} = 0.028\\ & \qquad \psi_2(1) = \underset{最大值对应的索引(从1开始)}{3}\\ & \delta_2(2) = \underset{1 \le j \le 3}{\max}[\delta_1(j)a_{j2}]b_2(o_2) = \underset{1 \le j \le 3}{\max}[\underset{第一种情况}{\underline{\underset{上一次是盒子1}{0.1} \times \underset{盒子1\rightarrow盒子2}{0.2}}}, \underset{第二种情况}{\underline{\underset{上一次是盒子2}{0.16} \times \underset{盒子2\rightarrow盒子2}{0.5}}}, \underset{第三种情况}{\underline{\underset{上一次是盒子3}{0.28} \times \underset{盒子3\rightarrow盒子2}{0.3}}}] \times \underset{白球}{0.6} = 0.0504\\ & \qquad \psi_2(2) = \underset{最大值对应的索引(从1开始)}{3}\\ & \delta_2(3) = \underset{1 \le j \le 3}{\max}[\delta_1(j)a_{j3}]b_3(o_2) = \underset{1 \le j \le 3}{\max}[\underset{第一种情况}{\underline{\underset{上一次是盒子1}{0.1} \times \underset{盒子1\rightarrow盒子3}{0.3}}}, \underset{第二种情况}{\underline{\underset{上一次是盒子2}{0.16} \times \underset{盒子2\rightarrow盒子3}{0.2}}}, \underset{第三种情况}{\underline{\underset{上一次是盒子3}{0.28} \times \underset{盒子3\rightarrow盒子3}{0.5}}}] \times \underset{白球}{0.3} = 0.042\\ & \qquad \psi_2(3) = \underset{最大值对应的索引(从1开始)}{3}\\ \end{aligned} δ2(1)=1≤j≤3max[δ1(j)aj1]b1(o2)=1≤j≤3max[第一种情况上一次是盒子10.1×盒子1→盒子10.15,第二种情况上一次是盒子20.16×盒子2→盒子10.3,第三种情况上一次是盒子30.28×盒子3→盒子10.2]×白球0.5=0.028ψ2(1)=最大值对应的索引(从1开始)3δ2(2)=1≤j≤3max[δ1(j)aj2]b2(o2)=1≤j≤3max[第一种情况上一次是盒子10.1×盒子1→盒子20.2,第二种情况上一次是盒子20.16×盒子2→盒子20.5,第三种情况上一次是盒子30.28×盒子3→盒子20.3]×白球0.6=0.0504ψ2(2)=最大值对应的索引(从1开始)3δ2(3)=1≤j≤3max[δ1(j)aj3]b3(o2)=1≤j≤3max[第一种情况上一次是盒子10.1×盒子1→盒子30.3,第二种情况上一次是盒子20.16×盒子2→盒子30.2,第三种情况上一次是盒子30.28×盒子3→盒子30.5]×白球0.3=0.042ψ2(3)=最大值对应的索引(从1开始)3
继续递推三个隐藏状态在 时刻3 时对应的各自两个局部状态,此时观测状态为 1:
δ 3 ( 1 ) = max 1 ≤ j ≤ 3 [ δ 1 ( j ) a j 1 ] b 1 ( o 3 ) = max 1 ≤ j ≤ 3 [ 0.028 上一次是盒子 1 × 0.5 盒子 1 → 盒子 1 ‾ 第一种情况 , 0.0504 上一次是盒子 2 × 0.3 盒子 2 → 盒子 1 ‾ 第二种情况 , 0.042 上一次是盒子 3 × 0.2 盒子 3 → 盒子 1 ‾ 第三种情况 ] × 0.5 红球 = 0.00756 ψ 3 ( 1 ) = 2 最大值对应的索引 ( 从 1 开始 ) δ 3 ( 2 ) = max 1 ≤ j ≤ 3 [ δ 1 ( j ) a j 2 ] b 2 ( o 3 ) = max 1 ≤ j ≤ 3 [ 0.028 上一次是盒子 1 × 0.2 盒子 1 → 盒子 2 ‾ 第一种情况 , 0.0504 上一次是盒子 2 × 0.5 盒子 2 → 盒子 2 ‾ 第二种情况 , 0.042 上一次是盒子 3 × 0.3 盒子 3 → 盒子 2 ‾ 第三种情况 ] × 0.4 红球 = 0.0504 ψ 3 ( 2 ) = 2 最大值对应的索引 ( 从 1 开始 ) δ 3 ( 3 ) = max 1 ≤ j ≤ 3 [ δ 1 ( j ) a j 3 ] b 3 ( o 3 ) = max 1 ≤ j ≤ 3 [ 0.028 上一次是盒子 1 × 0.3 盒子 1 → 盒子 3 ‾ 第一种情况 , 0.0504 上一次是盒子 2 × 0.2 盒子 2 → 盒子 3 ‾ 第二种情况 , 0.042 上一次是盒子 3 × 0.5 盒子 3 → 盒子 3 ‾ 第三种情况 ] × 0.7 红球 = 0.042 ψ 3 ( 3 ) = 3 最大值对应的索引 ( 从 1 开始 ) \begin{aligned} & \delta_3(1) = \underset{1 \le j \le 3}{\max}[\delta_1(j)a_{j1}]b_1(o_3) = \underset{1 \le j \le 3}{\max}[\underset{第一种情况}{\underline{\underset{上一次是盒子1}{0.028} \times \underset{盒子1\rightarrow盒子1}{0.5}}}, \underset{第二种情况}{\underline{\underset{上一次是盒子2}{0.0504} \times \underset{盒子2\rightarrow盒子1}{0.3}}}, \underset{第三种情况}{\underline{\underset{上一次是盒子3}{0.042} \times \underset{盒子3\rightarrow盒子1}{0.2}}}] \times \underset{红球}{0.5} = 0.00756\\ & \qquad \psi_3(1) = \underset{最大值对应的索引(从1开始)}{2}\\ & \delta_3(2) = \underset{1 \le j \le 3}{\max}[\delta_1(j)a_{j2}]b_2(o_3) = \underset{1 \le j \le 3}{\max}[\underset{第一种情况}{\underline{\underset{上一次是盒子1}{0.028} \times \underset{盒子1\rightarrow盒子2}{0.2}}}, \underset{第二种情况}{\underline{\underset{上一次是盒子2}{0.0504} \times \underset{盒子2\rightarrow盒子2}{0.5}}}, \underset{第三种情况}{\underline{\underset{上一次是盒子3}{0.042} \times \underset{盒子3\rightarrow盒子2}{0.3}}}] \times \underset{红球}{0.4} = 0.0504\\ & \qquad \psi_3(2) = \underset{最大值对应的索引(从1开始)}{2}\\ & \delta_3(3) = \underset{1 \le j \le 3}{\max}[\delta_1(j)a_{j3}]b_3(o_3) = \underset{1 \le j \le 3}{\max}[\underset{第一种情况}{\underline{\underset{上一次是盒子1}{0.028} \times \underset{盒子1\rightarrow盒子3}{0.3}}}, \underset{第二种情况}{\underline{\underset{上一次是盒子2}{0.0504} \times \underset{盒子2\rightarrow盒子3}{0.2}}}, \underset{第三种情况}{\underline{\underset{上一次是盒子3}{0.042} \times \underset{盒子3\rightarrow盒子3}{0.5}}}] \times \underset{红球}{0.7} = 0.042\\ & \qquad \psi_3(3) = \underset{最大值对应的索引(从1开始)}{3}\\ \end{aligned} δ3(1)=1≤j≤3max[δ1(j)aj1]b1(o3)=1≤j≤3max[第一种情况上一次是盒子10.028×盒子1→盒子10.5,第二种情况上一次是盒子20.0504×盒子2→盒子10.3,第三种情况上一次是盒子30.042×盒子3→盒子10.2]×红球0.5=0.00756ψ3(1)=最大值对应的索引(从1开始)2δ3(2)=1≤j≤3max[δ1(j)aj2]b2(o3)=1≤j≤3max[第一种情况上一次是盒子10.028×盒子1→盒子20.2,第二种情况上一次是盒子20.0504×盒子2→盒子20.5,第三种情况上一次是盒子30.042×盒子3→盒子20.3]×红球0.4=0.0504ψ3(2)=最大值对应的索引(从1开始)2δ3(3)=1≤j≤3max[δ1(j)aj3]b3(o3)=1≤j≤3max[第一种情况上一次是盒子10.028×盒子1→盒子30.3,第二种情况上一次是盒子20.0504×盒子2→盒子30.2,第三种情况上一次是盒子30.042×盒子3→盒子30.5]×红球0.7=0.042ψ3(3)=最大值对应的索引(从1开始)3
维特比算法是一种常用的 HMM 解码算法,它基于动态规划来求解最优状态序列。维特比算法定义了两个局部状态 δ t ( q ) \delta_t(q) δt(q) 和 ψ t ( q ) \psi_t(q) ψt(q) 来进行递推。其中, δ t ( q ) \delta_t(q) δt(q) 表示在时刻 t t t 隐藏状态为 q q q 的所有可能的状态转移路径中的概率最大值; ψ t ( q ) \psi_t(q) ψt(q) 表示在时刻 t t t 隐藏状态为 q q q 的所有单个状态转移路径中概率最大的转移路径中第 t − 1 t-1 t−1 个节点的隐藏状态。
在上述的例子中,最后一个时刻的最大概率为 δ 3 ( 3 ) \delta_3(3) δ3(3),这意味着在时刻 3,隐藏状态为 3 的概率最大。因此,我们可以得到 q 3 ∗ = 3 q^*_3 = 3 q3∗=3,即在时刻 3 最可能的隐藏状态为 3。
接下来,我们可以利用局部状态 ψ t ( i ) \psi_t(i) ψt(i) 来回溯得到最优状态序列。由于 ψ 3 ( 3 ) = 3 \psi_3(3)=3 ψ3(3)=3,所以 q 2 ∗ = 3 q^*_2 = 3 q2∗=3;由于 ψ 2 ( 3 ) = 3 \psi_2(3)=3 ψ2(3)=3,所以 q 1 ∗ = 3 q^*_1 = 3 q1∗=3。因此,我们得到了最终的最优状态序列为 { 3 , 3 , 3 } \{3, 3, 3\} {3,3,3}。
维特比算法还是借鉴了动态规划的思想
小结:
流程如下:
步骤一:初始化局部状态
δ 1 ( q ) = Π i b i ( o 1 ) i = 1 , 2 , . . . , N ψ 1 ( q ) = 0 i = 1 , 2 , . . . , N \begin{aligned} & \delta_1(q) = \Pi_i b_i (o_1) \quad i = 1, 2, ..., N\\ & \psi_1(q) = 0 \quad i = 1, 2, ..., N \end{aligned} δ1(q)=Πibi(o1)i=1,2,...,Nψ1(q)=0i=1,2,...,N
步骤二:进行动态规划递推时刻 t = 2 , 3 , . . . , T t = 2, 3,..., T t=2,3,...,T 的局部状态
δ t ( q ) = max 1 ≤ j ≤ N [ δ t − 1 ( j ) a j i ] b i ( o t ) i = 1 , 2 , . . . , N ψ t ( i ) = argmax 1 ≤ j ≤ N [ δ t − 1 ( j ) a j i ] i = 1 , 2 , . . . , N \begin{aligned} & \delta_t(q) = \underset{1 \le j \le N}{\max}[\delta_{t-1}(j)a_{ji}]b_i(o_t) \quad & i = 1, 2, ..., N\\ & \psi_t(i) = \underset{1 \le j \le N}{\text{argmax}}[\delta_{t-1}(j)a_{ji}] \quad & i = 1, 2, ..., N \end{aligned} δt(q)=1≤j≤Nmax[δt−1(j)aji]bi(ot)ψt(i)=1≤j≤Nargmax[δt−1(j)aji]i=1,2,...,Ni=1,2,...,N
步骤三:计算时刻 T T T 最大的 δ T ( i ) \delta_T(i) δT(i),即为最可能隐藏状态序列出现的概率。计算时刻 T T T 最大的 ψ t ( q ) \psi_t(q) ψt(q),即为时刻 T T T 最可能的隐藏状态。
P ∗ = max 1 ≤ j ≤ N δ T ( i ) q T ∗ = argmax 1 ≤ j ≤ N [ δ T ( q ) ] \begin{aligned} & P^* = \underset{1 \le j \le N}{\max} \delta_T(i)\\ & q^*_T = \underset{1 \le j \le N}{\text{argmax}}[\delta_T(q)] \end{aligned} P∗=1≤j≤NmaxδT(i)qT∗=1≤j≤Nargmax[δT(q)]
步骤四:利用局部状态 ψ t ( i ) \psi_t(i) ψt(i) 开始回溯。对于 t = T − 1 , T − 2 , . . . , 1 t = T - 1, T- 2, ..., 1 t=T−1,T−2,...,1:
q t ∗ = ψ t + 1 ( q t + 1 ∗ ) q^*_t = \psi_{t+1}(q^*_{t+1}) qt∗=ψt+1(qt+1∗)
最终得到最有可能的隐藏状态序列 Q ∗ = q 1 ∗ , q 2 ∗ , . . . , q T ∗ Q^* = q^*_1, q^*_2, ..., q^*_T Q∗=q1∗,q2∗,...,qT∗。
其中:
学习目标:
模型参数学习问题 ―― 鲍姆-韦尔奇(Baum-Welch)算法(状态未知),即给定观测序列 O = { o 1 , o 2 , . . . , o T } O = \{o_1,o_2,..., o_T\} O={o1,o2,...,oT},估计模型 λ = ( A , B , Π ) \lambda = (A, B, \Pi) λ=(A,B,Π) 的参数,使该模型下观测序列的条件概率 P ( O ∣ A ) P(O|A) P(O∣A) 最大。
它的解法最常用的是鲍姆-韦尔奇算法,其实就是基于 EM 算法的求解,只不过鲍姆-韦尔奇算法出现的时代,EM 算法还没有被抽象出来,所以被叫为鲍姆-韦尔奇算法。
鲍姆-韦尔奇算法原理既然使用的就是 EM 算法的原理,那么我们需要在 E 步求出联合分布 P ( O , I ∣ λ ) P(O, I | \lambda) P(O,I∣λ) 基于条件概率 P ( I ∣ O , λ ‾ ) P(I|O,\overline{\lambda}) P(I∣O,λ) 的期望,其中 λ ‾ \overline{\lambda} λ 为当前的模型参数;然后在 M 步最大化这个期望,得到更新的模型参数 λ \lambda λ。
首先来看看 E 步,当前模型参数为 λ ‾ \overline{\lambda} λ,联合分布 P ( O , I ∣ λ ) P(O,I|\lambda) P(O,I∣λ) 基于条件概率P ( I ∣ O , λ ‾ ) (I|O, \overline{\lambda}) (I∣O,λ) 的期望表达式为:
L ( λ , λ ‾ ) = ∑ I P ( I ∣ O , λ ‾ ) log P ( O , I ∣ λ ) L(\lambda, \overline{\lambda}) = \sum_I P(I|O, \overline{\lambda})\log P(O, I | \lambda) L(λ,λ)=I∑P(I∣O,λ)logP(O,I∣λ)
在 M 步,我们极大化上式,然后得到更新后的模型参数如下:
λ ‾ = argmax λ ∑ I P ( I ∣ O , λ ‾ ) log P ( O , I ∣ λ ) \overline{\lambda} = \underset{\lambda}{\text{argmax}}\sum_IP(I|O, \overline{\lambda})\log{P(O, I|\lambda)} λ=λargmaxI∑P(I∣O,λ)logP(O,I∣λ)
通过 E 步和 M 步的迭代,直到 λ ‾ \overline{\lambda} λ 收敛。
学习目标:
官网链接:https://hmmlearn.readthedocs.io/en/latest/
pip install hmmlearn==0.2.5
hmmlearn 实现了三种 HMM 模型类,按照观测状态是连续状态还是离散状态,可以分为两类。
GaussianHMM
:高斯隐马尔可夫模型(Gaussian Hidden Markov Model)GMMHMM
:混合高斯隐马尔可夫模型(Gaussian Mixture Hidden Markov Model)MultinomialHMM
:多项式隐马尔可夫模型(Multinomial Hidden Markov Model)
在这里主要介绍我们前面一直讲的关于离散状态的 MultinomialHMM 模型。对于 MultinomialHMM 的模型,使用比较简单。
from hmmlearn import hmm
model = hmm.MultinomialHMM (n_components=1, startprob_prior=1.0,
algorithm='viterbi', random_state=None,
n_iter=10, tol=0.01, verbose=False,
params='ste', init_params='ste')
hmm.MultinomialHMM()
是 hmmlearn
库中的一个类,它用于创建一个具有多项式(离散)发射的隐马尔可夫模型。n_components
:(int)隐含状态个数n_iter
:(int, optional )训练时循环(迭代)最大次数tol
:(float, optional )收敛阈值。如果对数似然的增益低于此值,则 EM 将停止。verbose
:(bool, optional )赋值为 True 时,会向标准输出输出每次迭代的概率(score)与本次init_params
:(string, optional )决定哪些参数会在训练时被初始化。
fit()
decode()
score()
下面我们用我们在前面讲的关于球的那个例子使用 MultinomialHMM 跑一遍。
import numpy as np
from hmmlearn import hmm
# 设定隐藏状态的集合
states = ["box 1", "box 2", "box 3"]
n_states = len(states)
# 设定观察状态的集合
observations = ["red", "white"]
n_observations = len(observations)
# 设定初始状态分布
start_probability = np.array([0.2, 0.4, 0.4])
# 设定状态转移概率分布矩阵
transition_probability = np.array([[0.5, 0.2, 0.3],
[0.3, 0.5, 0.2],
[0.2, 0.3, 0.5]])
# 设定观测状态概率矩阵
emission_probability = np.array([[0.5, 0.5],
[0.4, 0.6],
[0.7, 0.3]])
# 定义模型
model = hmm.MultinomialHMM(n_components=n_states)
# 设定模型参数
model.startprob_ = start_probability # 初始化状态分布
model.transmat_ = transition_probability # 初始化状态转移概率分布矩阵
model.emissionprob_ = emission_probability # 初始化观测状态概率矩阵
现在我们来跑一跑 HMM 问题三:维特比算法的解码过程,使用和之前一样的观测序列来解码,代码如下:
seen = np.array([[0, 1, 0]]).T # 设定观测序列(红白红)
# 维特比模型训练
box = model.predict(seen)
print("球的观测顺序为:", ' → '.join(map(lambda x: observations[x], seen.flatten())))
# 注意:需要使用flatten方法,把seen从二维变成一维
print("最可能的隐藏状态序列为:", ' → '.join(map(lambda x: states[x], box)))
使用
map
函数将seen
中数组的元素 对应observations
中的元素
使用map
函数将box
中数组的元素 对应states
中的元素
球的观测顺序为: red → white → red
最可能的隐藏状态序列为: box 3 → box 2 → box 2
我们再来看看求 HMM 问题一的观测序列的概率的问题,代码如下:
prob = model.score(seen)
print(f"观测序列出现的概率为:{prob}")
观测序列出现的概率为:-2.038545309915233
要注意的是 score
函数返回的是以自然对数为底的对数概率值,我们在 HMM 问题一中手动计算的结果是未取对数的原始概率是 0.13022。对比一下:
import math
prob_true = math.exp(prob)
print(f"观测序列出现的概率为:{prob_true * 100:.3f}%")
观测序列出现的概率为:13.022%