隐马尔可夫模型学习笔记(之二,学习算法)

隐马尔可夫模型的学习,根据训练数据是包括观测序列和状态序列还是只有观测序列,可以分别由监督学习与非监督学习实现。由于监督学习需要使用训练数据,而人工标注训练数据往往代价很高,有时就会利用非监督学习的方法,即Baum-Welch算法(也就是EM算法)。在介绍学习算法之前,先介绍一些概率和期望值的计算。这些计算会成为Baum-Welch算法公式的基础。

一些概率和期望值的计算

利用前向概率和后向概率,可以得到关于单个状态和两个状态概率的计算公式。
1. 给定模型 λ 和观测 O ,在时刻 t 处于状态 q i 的概率。记为

γ t ( i ) = P ( i t = q i | O , λ )

先分解为分数形式
(1) γ t ( i ) = P ( i t = q i , O | λ ) P ( O | λ )

根据前向概率的定义可以做以下变换
α t ( i ) = P ( o 1 , o 2 . . . o t , i t = q t | λ ) = P ( i t = q t | λ ) P ( o 1 , o 2 . . . o t | i t = q t , λ )

后向概率的定义如下
β t ( i ) = P ( o t + 1 , o t + 2 . . . , o T | i t = q t , λ )

将这两者相乘得到
(1) α t ( i ) β t ( i ) = P ( i t = q t | λ ) P ( o 1 , o 2 . . . o t | i t = q t , λ ) P ( o t + 1 , o t + 2 . . . , o T | i t = q t , λ ) (2) = P ( i t = q t | λ ) P ( o 1 , o 2 . . . o T | i t = q t , λ ) (3) = P ( i t = q t | λ ) P ( O | i t = q t , λ ) (2) = P ( i t = q t , O | λ )

以上结果从两者的定义上也很好理解。
对变量 i 在范围 i = 1 , 2 , . . . N 上求和
(3) i = 1 N P ( i t = q t , O | λ ) = P ( O | λ )

将式 ( 2 ) , ( 3 ) 代入 ( 1 ) 可以得到
(4) γ t ( i ) = α t ( i ) β t ( i ) j = 1 N α t ( j ) β t ( j )

2. 给定模型 λ 和观测 O ,在时刻 t 处于状态 q i 且在时刻 t + 1 处于状态 q j 的概率。记为
ξ t ( i , j ) = P ( i t = q i , i t + 1 = q j | O , λ )

通过前向后向概率计算:
ξ t ( i ) = P ( i t = q i , i t + 1 = q j , O | λ ) P ( O | λ ) = P ( i t = q i , i t + 1 = q j , O | λ ) i = 1 N j = 1 N P ( i t = q i , i t + 1 = q j , O | λ )

分子可以用前向后向概率表示
P ( i t = q i , i t + 1 = q j , O | λ ) = α t ( i ) a i j b j ( o t + 1 ) β t + 1 ( j )

ξ t ( i ) 可以表示为
ξ t ( i ) = α t ( i ) a i j b j ( o t + 1 ) β t + 1 ( j ) i = 1 N j = 1 N α t ( i ) a i j b j ( o t + 1 ) β t + 1 ( j )

3. 将 γ t ( i ) ξ t ( i , j ) 对各个时刻求和,可以得到一些有用的期望值。
(1) 观测 O 下,状态 i 出现的期望值
t = 1 T γ t ( i )

将每一个时刻下,出现状态 i 的概率相加
(2) 观测 O 下,由状态 i 转移的期望值
t = 1 T 1 γ t ( i )

能够从状态 i 转移的时刻是 1 , 2... T 1 ,比上一个求和公式少了时刻 T
(3) 观测 O 下,由状态 i 转移到状态 j 的期望值
t = 1 T 1 ξ t ( i , j )

Baum-Welch模型

参数估计公式

·推导的过程,尤其是拉格朗日对偶,我暂时还不十分理解,先直接给出训练方法,公式和代码。Baum-Welch算法(Baum-Welch algorithm),它是EM算法在隐马尔可夫模型学习过程中的具体实现,由Baum和Welch提出。
(1)初始化
对n=0,选取 a i j 0 b j ( k ) 0 π i 0 ,得到模型 λ 0 = ( a i j 0 b j ( k ) 0 π i 0 )
(2)递推。对 n = 1 , 2 , . . .

a i j n + 1 = t = 1 T 1 ξ t ( i , j ) t = 1 T 1 γ t ( i )

b j ( k ) n + 1 = t = 1 , o t = v k T γ t ( j ) t = 1 T γ t ( j )

π i n + 1 = γ 1 ( i )

公式右端按照观测 O = ( o 1 , o 2 , . . . o T ) 和模型 λ n = ( a i j n b j ( k ) n π i n ) 代入计算
(3)终止,得到模型 λ n + 1 = ( a i j n + 1 b j ( k ) n + 1 π i n + 1 )

Baum-Welch算法的Python实现

def baum_welch_train(self, observations, criterion=0.05):
    n_states = self.A.shape[0]
    n_samples = len(observations)

    done = False
    while not done:
        # alpha_t(i) = P(O_1 O_2 ... O_t, q_t = S_i | hmm)
        # Initialize alpha
        alpha = self._forward(observations)

        # beta_t(i) = P(O_t+1 O_t+2 ... O_T | q_t = S_i , hmm)
        # Initialize beta
        beta = self._backward(observations)

        xi = np.zeros((n_states,n_states,n_samples-1))
        for t in range(n_samples-1):
            denom = np.dot(np.dot(alpha[:,t].T, self.A) * self.B[:,observations[t+1]].T, beta[:,t+1])
            for i in range(n_states):
                numer = alpha[i,t] * self.A[i,:] * self.B[:,observations[t+1]].T * beta[:,t+1].T
                xi[i,:,t] = numer / denom

        # gamma_t(i) = P(q_t = S_i | O, hmm)
        gamma = np.sum(xi,axis=1)
        # Need final gamma element for new B
        prod =  (alpha[:,n_samples-1] * beta[:,n_samples-1]).reshape((-1,1))
        gamma = np.hstack((gamma,  prod / np.sum(prod))) #append one more to gamma!!!

        newpi = gamma[:,0]
        newA = np.sum(xi,2) / np.sum(gamma[:,:-1],axis=1).reshape((-1,1))
        newB = np.copy(self.B)

        num_levels = self.B.shape[1]
        sumgamma = np.sum(gamma,axis=1)
        for lev in range(num_levels):
            mask = observations == lev
            newB[:,lev] = np.sum(gamma[:,mask],axis=1) / sumgamma

        if np.max(abs(self.pi - newpi)) < criterion and \
                        np.max(abs(self.A - newA)) < criterion and \
                        np.max(abs(self.B - newB)) < criterion:
            done = 1

        self.A[:],self.B[:],self.pi[:] = newA,newB,newpi

猜你喜欢

转载自blog.csdn.net/s09094031/article/details/80751946