2016-07-29 00:09:36 yinglang19941010 阅读数 1230

HMM处理三种问题,我理解为三种功能
- 给出 O (可观测序列o1 o2 o3… ot),求P(O | hmm)
- 给出 O,求出使P(O, H | hmm)最大的 H (H为与O对应的隐藏层时序序列)
- 给出 O,求出使P(O | hmm) 最大的 hmm(参数调整)

HMM应用于孤立词语音识别流程描述

这里写图片描述

(训练:功能三)
1. 给出a, b, c三个词的音频库(Wa, Wb, Wc),对音频库的所有样本进行特征提取。(这里以mfcc为例),对每一段音频 w 先分成若干帧[w1,w2, w3…wn],对每一帧提取mfcc,获得[mfcc1,mfcc2,mffcc3…mfcc_n]。
2. 对这些mfcc进行聚类处理(比如k-means),获得M个类(类中心),每个类对应一个HMM的可观测层,同时将所有的mfcc进行分类,转化为可观测层的状态,该mfcc归到哪个类就对应哪个可观测状态。(矢量量化)对每一段音频w的mfcc串[mfcc1,mfcc2,mffcc3…mfcc_n],就会获得它的可观测序列[o1, o2, o3…on]
3. 从而获取了词汇 a ,b ,c 的所有O 序列,记为Oa,Ob,Oc;(Ox表示词汇x的所有样本的可观测层序列向量组成的矩阵)
4. 基于上述的HMM的第三个功能,以Oa,Ob,Oc作为条件,分别获得三个HMM,记为HMMa,HMMb,HMMc;

(识别:功能一)

  1. 给出一段孤立词x的音频,对他提取mfcc串,对提取出的mfcc串使用上面聚类的中心进行分类,进而转化为可观测序列记为ox;
  2. 基于HMM的第一个功能,将 ox 输入到HMMa,HMMb,HMMc中获得三个概率,记为Pa,Pb,Pc;
  3. 比较Pa,Pb,Pc,获取最大的Py(y = a 或 b 或 c )
  4. x = y;

HMM + GMM
上述孤立词识别使用的是离散型的HMM,即可观测层的状态个数是有限的(M个中心,所以是M个),因此对于mfcc这种连续的高维特征,必须要做矢量量化,但也因此引入了量化误差,所以提出使用连续性HMM。

首先说明一个概念,其实任何一个隐层状态到可观测状态的概率向量,都可以看成是一个概率分布。所以连续型的HMM把每个隐层状态到可观测层的概率分布都看成是一个GMM分布。

bj(X)=m=1MwjmN(X|μjm,Σjm)

其中N表示高维正态分布(高斯分布)。
X 就直接使用高维特征,比如mfcc。

但是这样带来的问题是,大量的参数引入,使得计算的复杂量很高,同时在数据量不足时,发挥不出优势;所以又提出了半连续型HMM,即:

bj(X)=m=1MwjmN(X|μm,Σm)

也就是所有的bj(X)分布共享一套高斯函数,只是分歧系数w有所不同。

离散HMM简单的代码cpp实现: https://github.com/yinglang/HMMInLab/tree/master/myHMM

2018-05-31 12:30:06 JosephPai 阅读数 3268

1 从语音识别说起

语音识别是什么,通俗来说,就是输入音频,输出识别文字结果。基本方程如下
这里写图片描述
这里写图片描述: 识别结果
W:任一单词(以孤立词举例说明)
O:输入的语音序列(Observation Sequence)

上述方程的变换应用了Bayes Rule.

等式右边是两项乘积,P(W)来自语言模型(Language Model, LM), 常用的模型有 N-gram。 P(O | W)来自于声学模型(Acoustic Model, AM),传统的语音识别系统普遍采用的是基于GMM-HMM的声学模型,其中GMM用于对语音声学特征的分布进行建模,HMM则用于对语音信号的时序性进行建模。具体介绍网上有很多通俗易懂的文章,这里暂不赘述。本文重点讲解声学模型中的解码问题,暂不涉及语言模型。

2 计算P(O | W) —— 解码

P(O | W)可以继续分解如下
P(O | W) = P(A, O | W) 这里写图片描述
其中A表示状态序列,O表示观测序列,a表示转移概率,b表示观测概率
这里写图片描述

如图,上方是状态序列(state sequence)(HMM),下方是观测序列(observation sequence)。我们看到,states之间存在不同的转移方式,每个state针对observation也有不同generate方式。可以想象,通过组合,我们可以得到一个巨大的状态网络。而我们语音识别的任务,通俗来说就是从这个巨大的状态网络中搜索到最佳路径(partial path),也就是最大概率的路径,对应上面公式的argmax。这个搜索匹配的过程在语音识别中叫做解码(decode)。在众多路径中找到最佳路径,一种暴力方法是穷举,但是计算量大到不现实。目前应用的主流方法是Viterbi算法。

3 Viterbi算法

Viterbi算法的基础概括成下面三点:

  1. 如果概率最大的路径P(或者说是最短路径)经过某点a,那么这条路径上从起始点s到a的这一段子路径一定是s到a之间的最短路径。否则用s到a的最短路径来替换上述路径,便构成了一条比P更短的路径,矛盾。
  2. 从S到E的路径必定经过第i时刻的某个状态,假定第i时刻有k个状态,那么如果记录了从S到第i个状态的所有k个节点的最短路径,最终的最短路径必经过其中的一条。这样,在任何时刻,只需要考虑非常有限条最短路径即可。
  3. 结合上述两点,假定当我们从状态i进入状态i+1时,从S到状态i上各个节点的最短路径已经找到,并且记录在这些节点上,那么在计算从起点S到前一个状态i所有的k个结点的最短路径,以及从这k个节点到Xi+1,j的距离即可。

    这里写图片描述

上图是一个简单的四个状态HMM应用Viterbi算法的例子。
Viterbi算法的思想是典型的动态规划思想。动态规划相对穷举已经大大减少了计算量,然而面对巨大的网络,我们意识到还是有很多不必要的计算。有些路径的计算过程中概率已经很小,完全偏离了我们要的最佳路径,继续计算这样的路径显然是没有必要的。这个时候就需要剪枝(pruning),剪枝的Viterbi算法其中一个实现叫做Token Passing,著名的语音识别工具箱HTK的解码部分应用的就是这一概念模型。

4 Token Passing Approach

4.1 概念模型

假设每一个HMM的state可以保存一个或多个Token。Token是一个概念上的对象object,它可以在state之间进行传递,一般都是按照箭头指向的方向,所以也叫前传(propagate)。每一个Token携带着它所经过路径的打分score,这个分值一般是log量级的概率和(因为我们要找的是最大概率路径嘛,也就是最高分的路径。)Token的传递是以观测序列的generate为节拍进行。
你可以想象每一条路径都是一条贪吃蛇,token就是蛇的头部的那一节,身体部分就是他所经过的state路径。算法过程大致如下:

初始化(t=0):
    初始state(入口处)的Token的s=0
    其他state的Token的s=-inf
执行过程(t>0):
    复制若干数目Token,并将其传递至所有与该state连接的其他state中,并且对其值做如下操作:  
    在每个state中,比较所有token,留下分值最高的token,抛弃其他所有token(Viterbi剪枝过程)
终态(t=T):
    比较所有终态(final state)的Token,保留其中分数最高的token

该token对应的就是最佳路径的概率。

这里写图片描述

上图是一个Token Passing示意图,过段时间我计划做一个flash或者录一个小视频来更直观的演示这个过程。

4.2 孤立词识别(Isolated Word Recognition)

将Token Passing的思想应用到语音识别的解码过程中,我们首先从孤立词识别引入。一个英文单词音频一般分为三个音素,而一个音素又可以分为若干个状态,这些层级展开一个网络。他们之间的跳转符合隐马尔假设,所以可以应用Viterbi算法进行搜索解码。
单词级的HMM和音素级的HMM都可以直接套用上文的Token Passing模型,实现如下。
这里写图片描述
这里写图片描述

通过这一过程,我们对每一个单词都建立了一个HMM model,为后面的连续词识别奠定了基础。

4.3 连续识别(Connected Word Recognition 或 Continuous Speech Recognition)

连续识别的主要问题在于:

① 音频中词与词之间的分界线(boundary)不明确
② 音频序列中总的单词数目不能确定

应用Token Passing模型,我们可以以上文的孤立词识别为基础,将不同的孤立词模型组合成一个网络,构成复合的语句级别的HMM模型(sentence model),并进行下图所示的抽象。在interface右边是上文提到的孤立词级别的模式匹配模型,在interface右边是语句级别的连续识别匹配,这时候我们就可以不用关注单词级别的具体实现。

这里写图片描述

具体识别过程,即在上文提到的语句级复合HMM中继续应用Token Passing模型(因为我们的目标和之前一样,还是寻找最佳路径)。

这里写图片描述

此外,在连续词识别中,我们还需要对基础的Token Passing进行一些扩展。为了能够准确的记录我们识别出的句子所包含的单词,我们引入一个新的概念Word Link Record(WLR). 顾名思义,这是一条记录,里面存放着记录word link的指针。Token除了携带score信息,还要携带一个path identifier来记录上一个WLR。
在C/C++中,token的数据结构大概会是:

struct Token{
    double score;
    struct WRL *path_id;      
    }

在上面的Token Passing基础算法中,我们新增如下过程:

在时间 t ,对每一个完成单词级识别的token(从小网络传递到大网络) do:
    创建一个新的WLR
    WLR包含 <token内容(最大概率), 时间t, 记录路径的path id, 刚刚完成识别的单词model id>
    将token中的path id指向刚刚创建的这条新的WLR
end

这里写图片描述

如图所示,WLR构成的链表结构,记录了所有潜在的boundary信息。例如,t-3时刻很可能是单词two的结尾。
当到达T时刻整个句子识别结束后,我们再通过比较,得到得分最高的token,然后通过该token的path id以及WLR的链表结构可以轻松的回溯得出识别结果。

5 总结

以上就是应用Token Passing模型实现Viterbi算法的具体过程,该模型通俗易懂,有效的解决了连续词识别的问题。泛化能力强,实际上One Pass、Level Building等经典算法都可以看做Token Passing的特殊情况。且易于扩展,譬如我们可以通过保留多个token来评比多条路径(N-best)以提升识别效果。
本文为了做到尽量通俗,有诸多不严谨之处,欢迎批评指正。

Reference:
[1] Young S J, Russell N H, Thornton J H S. Token passing: a simple conceptual model for connected speech recognition systems[M]. Cambridge, UK: Cambridge University Engineering Department, 1989.
[2] Young S, Evermann G, Gales M, et al. The HTK book[J]. Cambridge university engineering department, 2002, 3: 175.
[3] University of Cambridge Engineering Part IIB & EIST Part II Module 4F11: Speech Processing Lecture 11: Continuous Speech Recognition
[4] SGN-24006 Analysis of Audio, Speech and Music Signals lec09
[5] speech.zone

2016-04-04 17:44:16 GarfieldEr007 阅读数 16636

本文简明讲述GMM-HMM在语音识别上的原理,建模和测试过程。这篇blog只回答三个问题:

1. 什么是Hidden Markov Model

HMM要解决的三个问题:

1) Likelihood

2) Decoding

3) Training

2. GMM是神马?怎样用GMM求某一音素(phoneme)的概率?

3. GMM+HMM大法解决语音识别

3.1 识别

3.2 训练

3.2.1 Training the params of GMM

3.2.2 Training the params of HMM



首先声明我是做视觉的不是做语音的,迫于**需要24小时速成语音。上网查GMM-HMM资料中文几乎为零,英文也大多是paper。苦苦追寻终于貌似搞懂了GMM-HMM,感谢语音组老夏(http://weibo.com/ibillxia)提供资料给予指导。本文结合最简明的概括还有自己一些理解应运而生,如有错误望批评指正。


====================================================================



1. 什么是Hidden Markov Model


ANS:一个有隐节点(unobservable)和可见节点(visible)的马尔科夫过程(见详解)。

隐节点表示状态,可见节点表示我们听到的语音或者看到的时序信号。

最开始时,我们指定这个HMM的结构,训练HMM模型时:给定n个时序信号y1...yT(训练样本), 用MLE(typically implemented in EM) 估计参数:

1. N个状态的初始概率

2. 状态转移概率a

3. 输出概率b

--------------

  • 在语音处理中,一个word由若干phoneme(音素)组成;
  • 每个HMM对应于一个word或者音素(phoneme)
  • 一个word表示成若干states,每个state表示为一个音素


用HMM需要解决3个问题:

1). Likelihood: 一个HMM生成一串observation序列x的概率< the Forward algorithm>

其中,αt(sj)表示HMM在时刻t处于状态j,且observation = {x1,...,xt}的概率

aij是状态i到状态j的转移概率,

bj(xt)表示在状态j的时候生成xt的概率,







2). Decoding: 给定一串observation序列x,找出最可能从属的HMM状态序列< the Viterbi algorithm>

在实际计算中会做剪枝,不是计算每个可能state序列的probability,而是用Viterbi approximation:

从时刻1:t,只记录转移概率最大的state和概率。

记Vt(si)为从时刻t-1的所有状态转移到时刻t时状态为j的最大概率

为:从时刻t-1的哪个状态转移到时刻t时状态为j的概率最大;

进行Viterbi approximation过程如下:


然后根据记录的最可能转移状态序列进行回溯:





3). Training: 给定一个observation序列x,训练出HMM参数λ = {aij, bij}  the EM (Forward-Backward) algorithm

这部分我们放到“3. GMM+HMM大法解决语音识别”中和GMM的training一起讲







---------------------------------------------------------------------


2. GMM是神马?怎样用GMM求某一音素(phoneme)的概率?

2.1 简单理解混合高斯模型就是几个高斯的叠加。。。e.g. k=3



fig2. GMM illustration and the probability of x



2.2 GMM for state sequence 

每个state有一个GMM,包含k个高斯模型参数。如”hi“(k=3):

PS:sil表示silence(静音)

fig3. use GMM to estimate the probability of a state sequence given observation {o1, o2, o3}


其中,每个GMM有一些参数,就是我们要train的输出概率参数


fig4. parameters of a GMM

怎么求呢?和KMeans类似,如果已知每个点x^n属于某每类 j 的概率p(j|x^n),则可以估计其参数:

 , 其中 


只要已知了这些参数,我们就可以在predict(识别)时在给定input sequence的情况下,计算出一串状态转移的概率。如上图要计算的state sequence 1->2->2概率:


fig5. probability of S1->S2->S3 given o1->o2->o3








---------------------------------------------------------------------

3. GMM+HMM大法解决语音识别

<!--识别-->

我们获得observation是语音waveform, 以下是一个词识别全过程:

1). 将waveform切成等长frames,对每个frame提取特征(e.g. MFCC), 

2).对每个frame的特征跑GMM,得到每个frame(o_i)属于每个状态的概率b_state(o_i)



fig6. complete process from speech frames to a state sequence


3). 根据每个单词的HMM状态转移概率a计算每个状态sequence生成该frame的概率; 哪个词的HMM 序列跑出来概率最大,就判断这段语音属于该词


宏观图:


fig7. Speech recognition, a big framework

(from Encyclopedia of Information Systems, 2002)




<!--训练-->

好了,上面说了怎么做识别。那么我们怎样训练这个模型以得到每个GMM的参数和HMM的转移概率什么的呢?




①Training the params of GMM

GMM参数:高斯分布参数:

从上面fig4下面的公式我们已经可以看出来想求参数必须要知道P(j|x),即,x属于第j个高斯的概率。怎么求捏?


fig8. bayesian formula of P( j | x )

根据上图 P(j | x), 我们需要求P(x|j)和P(j)去估计P(j|x). 

这里由于P(x|j)和P(j)都不知道,需要用EM算法迭代估计以最大化P(x) = P(x1)*p(x2)*...*P(xn):

A. 初始化(可以用kmeans)得到P(j)

B. 迭代

    E(estimate)-step: 根据当前参数 (means, variances, mixing parameters)估计P(j|x)

    M(maximization)-step: 根据当前P(j|x) 计算GMM参数(根据fig4 下面的公式:)

 , 其中 





②Training the params of HMM

前面已经有了GMM的training过程。在这一步,我们的目标是:从observation序列中估计HMM参数λ;

假设状态->observation服从单核高斯概率分布:,则λ由两部分组成:




HMM训练过程:迭代

    E(estimate)-step: 给定observation序列,估计时刻t处于状态sj的概率 

    M(maximization)-step: 根据重新估计HMM参数aij. 

其中,


E-step: 给定observation序列,估计时刻t处于状态sj的概率 

为了估计, 定义: t时刻处于状态sj的话,t时刻未来observation的概率。即

这个可以递归计算:β_t(si)=从状态 si 转移到其他状态 sj 的概率aij * 状态 i 下观测到x_{t+1}的概率bi(x_{t+1}) * t时刻处于状态sj的话{t+1}后observation概率β_{t+1}(sj)

即:


定义刚才的为state occupation probability,表示给定observation序列,时刻t处于状态sj的概率P(S(t)=sj | X,λ) 。根据贝叶斯公式p(A|B,C) = P(A,B|C)/P(B|C),有:



由于分子p(A,B|C)为


其中,αt(sj)表示HMM在时刻t处于状态j,且observation = {x1,...,xt}的概率

: t时刻处于状态sj的话,t时刻未来observation的概率;

finally, 带入的定义式有:


好,终于搞定!对应上面的E-step目标,只要给定了observation和当前HMM参数 λ,我们就可以估计了对吧 (*^__^*) 






M-step:根据重新估计HMM参数λ:

对于λ中高斯参数部分,和GMM的M-step是一样一样的(只不过这里写成向量形式):


对于λ中的状态转移概率aij, 定义C(Si->Sj)为从状态Si转到Sj的次数,有


实际计算时,定义每一时刻的转移概率为时刻t从si->sj的概率:


那么就有:


把HMM的EM迭代过程和要求的参数写专业点,就是这样的:


PS:这个训练HMM的算法叫 Forward-Backward algorithm。





一个很好的reference:点击打开链接


from: http://blog.csdn.net/abcjennifer/article/details/27346787

2018-01-04 13:47:58 m0_37788308 阅读数 964

1.语音识别系统的基本结构

这里写图片描述

2.涉及算法

这里写图片描述

3.GMM高斯混合模型

3.1高斯混合模型的基本概念

  高斯混合模型是指具有如下形式的概率分布模型:

p(yθ)=k=1kαkϕ(yθk)

其中,αk是系数,αk0kk=1αk=1ϕ(yθk)是高斯分布密度,θk=(μk,σ2k)
ϕ(yθk)=12πσkexp((yμk)22θ2k)

称为第k个分模型。
  将二变量的混合高斯分布可以推广到多变量的多元混合高斯分布,其联合概率密度函数可写为:
p(x)=k=1Mcm(2π)(D/2)|m|1/2exp[12(xμm)T1m(xμm)]

=Mm=1CmN(x;μm,μm),(Cm>0)

3.2用EM算法解决高斯混合分布问题

  具体EM算法讲解见另一篇博客:《PLSI主题模型》中EM算法的具体讲解部分:
http://blog.csdn.net/m0_37788308/article/details/78115378
  实现EM算法估计高斯混合分布的python代码如下,其中有调用sklearn包进行的估计和直接写的EM算法来估计高斯混合分布。

# -*- coding:utf-8 -*-
#EM算法估计高斯混合分布的参数
import numpy as np
from scipy.stats import multivariate_normal
from sklearn.mixture import GaussianMixture
from mpl_toolkits.mplot3d import Axes3D
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.metrics.pairwise import pairwise_distances_argmin

mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False

if __name__ == '__main__':
    style = 'myself'
    # style = 'sklearn'
    np.random.seed(0)
    mu1_fact = (0, 0, 0)
    cov1_fact = np.diag((1, 2, 3))
    data1 = np.random.multivariate_normal(mu1_fact, cov1_fact, 400)
    mu2_fact = (2, 2, 1)
    cov2_fact = np.array(((1, 1, 3), (1, 2, 1), (0, 0, 1)))
    data2 = np.random.multivariate_normal(mu2_fact, cov2_fact, 100)
    data = np.vstack((data1, data2))
    y = np.array([True] * 400 + [False] * 100)
    # print y
    if style == 'sklearn':
        g = GaussianMixture(n_components=2, covariance_type='full', tol=1e-6, max_iter=1000)
        g.fit(data)
        print '类别概率:\t', g.weights_[0]
        print '均值:\n', g.means_, '\n'
        print '方差:\n', g.covariances_, '\n'
        mu1, mu2 = g.means_
        sigma1, sigma2 = g.covariances_
    else:
        num_iter = 100
        n, d = data.shape
        # 随机指定
        mu1 = np.random.standard_normal(d)
        print mu1
        mu2 = np.random.standard_normal(d)
        print mu2
        mu1 = data.min(axis=0)
        mu2 = data.max(axis=0)
        sigma1 = np.identity(d)
        sigma2 = np.identity(d)
        pi = 0.5
        # EM
        for i in range(num_iter):
            # E Step
            norm1 = multivariate_normal(mu1, sigma1)
            norm2 = multivariate_normal(mu2, sigma2)
            tau1 = pi * norm1.pdf(data)
            tau2 = (1 - pi) * norm2.pdf(data)
            gamma = tau1 / (tau1 + tau2)

            # M Step
            mu1 = np.dot(gamma, data) / np.sum(gamma)
            mu2 = np.dot((1 - gamma), data) / np.sum((1 - gamma))
            sigma1 = np.dot(gamma * (data - mu1).T, data - mu1) / np.sum(gamma)
            sigma2 = np.dot((1 - gamma) * (data - mu2).T, data - mu2) / np.sum(1 - gamma)
            pi = np.sum(gamma) / n
            print i, ":\t", mu1, mu2
        print '类别概率:\t', pi
        print '均值:\t', mu1, mu2
        print '方差:\n', sigma1, '\n\n', sigma2, '\n'

    # 预测分类
    norm1 = multivariate_normal(mu1, sigma1)
    norm2 = multivariate_normal(mu2, sigma2)
    tau1 = norm1.pdf(data)
    tau2 = norm2.pdf(data)

    fig = plt.figure(figsize=(13, 7), facecolor='w')
    ax = fig.add_subplot(121, projection='3d')
    ax.scatter(data[:, 0], data[:, 1], data[:, 2], c='b', s=30, marker='o', depthshade=True)
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_title(u'原始数据', fontsize=18)
    ax = fig.add_subplot(122, projection='3d')

    order = pairwise_distances_argmin([mu1_fact, mu2_fact], [mu1, mu2], metric='euclidean')
    print order
    if order[0] == 0:
        c1 = tau1 > tau2
    else:
        c1 = tau1 < tau2
    c2 = ~c1
    acc = np.mean(y == c1)
    print u'准确率:%.2f%%' % (100*acc)

    ax.scatter(data[c1, 0], data[c1, 1], data[c1, 2], c='r', s=30, marker='o', depthshade=True)
    ax.scatter(data[c2, 0], data[c2, 1], data[c2, 2], c='g', s=30, marker='^', depthshade=True)
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    ax.set_title(u'EM算法分类', fontsize=18)
    plt.suptitle(u'EM算法的实现', fontsize=21)
    plt.subplots_adjust(top=0.90)
    plt.tight_layout()
    plt.show()

4.HMM隐马尔可夫模型

4.1隐马尔可夫的基本概念

  隐马尔可夫模型是关于时序的概率模型,描述有一个隐马尔可夫链随机生成不可观测的状态随机序列,再由各个状态生成一个观测而产生观测随机序列过程。隐马尔可的“隐”字主要体现在隐马尔可夫链随机生成的“状态序列”;每一个状态生成一个观察,称为“观察序列”,观察序列我们是可以看到的,但是“状态序列”就是我们常常难理解的地方。
  隐马尔可夫由“初始概率分布”、“状态转移概率分布”以及“观察概率分布”这三个分布确定。
Q所有可能的状态集合,V是所有可能的观测集合。

Q={q1,q2,...,qN}

V={v1,v2,...,vM}

其中,N是可能的状态数,M是可能的观测序列。I是长度为T的状态序列,O是对应的观测序列。
I={i1,i2,...,ir}

O={o1,o2,...,or}

A是状态转移概率矩阵:
A=[aij]NN

其中,aij=p(it+1=qj|it=qi),i=1,2,...,N;j=1,2,...,N是在时刻t处于状态qi的条件下在时刻t+1转移到状态qj的概率。
B是观测概率矩阵:
A=[bj(k)]NN

其中,
bj(k)=p(ot=vk|it=qj),k=1,2,...,M;j=1,2,...,N

是在时刻t处于状态qj的条件下生成观测v_{k}的概率。
π是初始状态概率向量:
π=(πi)

其中,
πi=p(i1=qi),i=1,2,...,N

是时刻t=1处于状态qi的概率。
隐马尔可夫模型由初始状态概率向量π、状态转移概率矩阵A和观测概率矩阵B决定。πA决定状态序列,B决定观测序列。因此,隐马尔可夫模型λ可以用三元符号表示,即:
λ=(A,B,π)

A,B,π称为隐马尔可夫模型的三要素。

4.2隐马尔可夫的基本假设

从定义可知,隐马尔可夫模型作了两个基本假设:
  (1)齐次马尔科夫性假设,即假设隐藏的马尔科夫链在任意时刻t的状态只依赖与前一时刻的状态,与其他时刻的状态及观测无关,也与时刻t无关。

p(it|it1,ot1,...,i1,o1)=p(it|it1),t=1,2,...,T

  (2)观测独立性假设,即假设任意时刻的观测只依赖于该时刻的马尔科夫链的状态,与其他观测状态无关。
p(ot|iT,oT,iT1,oT1,...,it+1,ot+1,it,it1,ot1,...,i1,o1)=p(ot|it)

4.3HMM的三个基本问题

  (1)概率计算问题。给定模型π=(A,B,π)和观测序列O=(o1,o2,...,oT),计算在模型λ下观测序列O出现的概率p(O|λ)
  (2)学习问题。已知观测序列O=(o1,o2,...,oT),估计模型λ=(A,B,π)参数,使得在该模型下观测序列概率p(O|λ)最大。即用极大似然估计的方法估计参数。
  (3)预测问题。也称为解码问题。已知模型λ=(A,B,π)和观测序列O=(o1,o2,...,oT),求对给定观测序列条件概率p(I|O)最大的状态序列I=(i1,i2,...,iT)。即给定观测序列,求最有可能的对应的状态序列。

5.GMM-HMM如何应用在语音识别上

  解释:这里的语音识别指的是语音的分类,并不是字面意义理解的语音转化为文字。其实这里的语音识别和传统意义上的分类算法一样,通过训练集(train)的训练,对测试集(test)进行分类。只是传统的分类算法输入的是数字数据,而这里的输入的语音。输入的语音信号服从高斯混合分布,也就是隐马尔可夫模型中的第二个问题(学习问题),将语音信号用隐马尔可夫模型中的向前算法(BW算法,也可以理解为EM算法)进行分解,求出隐马尔可夫的三要素(三个参数λ=(A,B,π)),将参数作为识别语音的特征值,从而进行语音的分类识别。

6.问题讲解

(1)在浏览博客中,如果有不理解的地方可以参考视频讲解资料。视频讲解资料链接为:http://v.youku.com/v_show/id_XMzMzMzE1NTY2OA==.html?qq-pf-to=pcqq.c2c
(2)需要《GMM-HMM在语音识别中的应用》的python代码,可以留下邮箱地址。

7.参考文献

[1]李航. 统计学习方法[M]. 清华大学出版社:李航, 2012. 171-189

2018-09-30 10:17:11 chinatelecom08 阅读数 4076

简介

  • 本文实现了一个基于HMM-GMM的独立词识别模型,数据集有限,训练数据为独立词,为10类。训练样本100个,测试样本10个,测试集上能够达到90%的识别率。
  • 直接下载项目到本地,运行.py文件就可以得到下面的结果,成功执行:
训练集:
识别得到结果:
 ['1', '10', '2', '3', '4', '5', '6', '7', '8', '10', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '5', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '10', '1', '10', '2', '4', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '10', '1', '10', '2', '3', '4', '5', '6', '7', '8', '10', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9']
原始标签类别:
 ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9']
识别率: 0.94
测试集:
识别得到结果:
 ['1', '10', '2', '3', '4', '5', '6', '7', '8', '3']
原始标签类别:
 ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']
 识别率: 0.9

基础准备

原理部分需要了解hmm-gmm在语音识别中的工作原理是什么,特别要理解一个hmm-gmm模型对应一个孤立词这个概念,弄清楚非常重要。
不过你即使不算很明白其中的含义,也可以成功的执行项目,可以在原理和代码中反复思考传统模型的实现原理。
这部分网上讲的很多,这里不再赘述。

python建模

数据预处理

首先,进行数据预处理,输入为训练集路径或者测试集路径wavpath

# -----------------------------------------------------------------------------------------------------
'''
&usage:		准备所需数据
'''
# -----------------------------------------------------------------------------------------------------
# 生成wavdict,key=wavid,value=wavfile
def gen_wavlist(wavpath):
	wavdict = {}
	labeldict = {}
	for (dirpath, dirnames, filenames) in os.walk(wavpath):
		for filename in filenames:
			if filename.endswith('.wav'):
				filepath = os.sep.join([dirpath, filename])
				fileid = filename.strip('.wav')
				wavdict[fileid] = filepath
				# 获取文件的类别
				label = fileid.split('_')[1]
				labeldict[fileid] = label
	return wavdict, labeldict

查看wavdict和labeldict的数据内容,以test为例,其中音频的类别为文件名后面的数字:
数据格式

wavdict, labeldict = gen_wavlist('test_data')
print(wavdict, labeldict)

输出文件路径和标注类别:

wavdict:
{'1_1': 'test_data\\1_1.wav', '1_10': 'test_data\\1_10.wav', '1_2': 'test_data\\1_2.wav', '1_3': 'test_data\\1_3.wav', '1_4': 'test_data\\1_4.wav', '1_5': 'test_data\\1_5.wav', '1_6': 'test_data\\1_6.wav', '1_7': 'test_data\\1_7.wav', '1_8': 'test_data\\1_8.wav', '1_9': 'test_data\\1_9.wav'}
labeldict:
{'1_1': '1', '1_10': '10', '1_2': '2', '1_3': '3', '1_4': '4', '1_5': '5', '1_6': '6', '1_7': '7', '1_8': '8', '1_9': '9'}

特征提取

我们直接调包python_speech_features实现mfcc,偷懒做法,这样看起来代码比较简洁,如果需要深入了解算法可以自己coding实现。

# pip install python_speech_features ,不行的话百度一下
from python_speech_features import mfcc
# 特征提取,feat = compute_mfcc(wadict[wavid])
def compute_mfcc(file):
	fs, audio = wavfile.read(file)
	# 这里我故意fs/2,有些类似减小step,不建议这样做,投机取巧做法
	mfcc_feat = mfcc(audio, samplerate=(fs/2), numcep=26)
	return mfcc_feat

搭建孤立词模型

我们利用hmmlearn工具包搭建hmm-gmm,可以提前了解一下hmmlearn的使用方法

  • 首先,需要初始化10个独立的hmm-gmm模型,分别对应十个独立词,主要是初始化一个hmm-gmm模型的集合 self.models
class Model():
	def __init__(self, CATEGORY=None, n_comp=3, n_mix = 3, cov_type='diag', n_iter=1000):
		super(Model, self).__init__()
		self.CATEGORY = CATEGORY
		self.category = len(CATEGORY)
		self.n_comp = n_comp
		self.n_mix = n_mix
		self.cov_type = cov_type
		self.n_iter = n_iter
		# 关键步骤,初始化models,返回特定参数的模型的列表
		self.models = []
		for k in range(self.category):
			model = hmm.GMMHMM(n_components=self.n_comp, n_mix = self.n_mix, 
								covariance_type=self.cov_type, n_iter=self.n_iter)
			self.models.append(model)

各个参数的意义:

	CATEGORY:	所有标签的列表
	n_comp:		每个孤立词中的状态数
	n_mix:		每个状态包含的混合高斯数量
	cov_type:	协方差矩阵的类型
	n_iter:		训练迭代次数
  • 然后,用同一种类的数据训练特定的模型。
	# 模型训练
	def train(self, wavdict=None, labeldict=None):
		for k in range(10):
			subdata = []
			model = self.models[k]
			for x in wavdict:
				if labeldict[x] == self.CATEGORY[k]:
					mfcc_feat = compute_mfcc(wavdict[x])
					model.fit(mfcc_feat)
  • 最后,对待测试的数据分别用十个模型打分,选出得分最高的为识别结果。
	# 使用特定的测试集合进行测试
	def test(self, wavdict=None, labeldict=None):
		result = []
		for k in range(self.category):
			subre = []
			label = []
			model = self.models[k]
			for x in wavdict:
				mfcc_feat = compute_mfcc(wavdict[x])
				# 生成每个数据在当前模型下的得分情况
				re = model.score(mfcc_feat)
				subre.append(re)
				label.append(labeldict[x])
			# 汇总得分情况
			result.append(subre)
		# 选取得分最高的种类
		result = np.vstack(result).argmax(axis=0)
		# 返回种类的类别标签
		result = [self.CATEGORY[label] for label in result]
		print('识别得到结果:\n',result)
		print('原始标签类别:\n',label)
		# 检查识别率,为:正确识别的个数/总数
		totalnum = len(label)
		correctnum = 0
		for i in range(totalnum):
		 	if result[i] == label[i]:
		 	 	correctnum += 1 
		print('识别率:', correctnum/totalnum)
  • 你也可以保存和载入模型
	# 利用external joblib保存生成的hmm模型
	def save(self, path="models.pkl"):
		joblib.dump(self.models, path)
		
	# 利用external joblib载入保存的hmm模型
	def load(self, path="models.pkl"):
		self.models = joblib.load(path)

模型的训练和测试

利用上面搭建的模块对模型进行训练和测试,完整项目包括数据在hmm-gmm声学模型,下载下来可以直接运行,如果对你有帮助的话,有账户求star啊。

# 准备训练所需数据
CATEGORY = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
wavdict, labeldict = gen_wavlist('training_data')
testdict, testlabel = gen_wavlist('test_data')
print(testdict, testlabel)
# 进行训练和测试
models = Model(CATEGORY=CATEGORY)
models.train(wavdict=wavdict, labeldict=labeldict)
models.save()
models.load()
models.test(wavdict=wavdict, labeldict=labeldict)
models.test(wavdict=testdict, labeldict=testlabel)

识别结果:

训练集:
识别得到结果:
 ['1', '10', '2', '3', '4', '5', '6', '7', '8', '10', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '5', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '10', '1', '10', '2', '4', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '10', '1', '10', '2', '3', '4', '5', '6', '7', '8', '10', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9']
原始标签类别:
 ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9', '1', '10', '2', '3', '4', '5', '6', '7', '8', '9']
识别率: 0.94
测试集:
识别得到结果:
 ['1', '10', '2', '3', '4', '5', '6', '7', '8', '3']
原始标签类别:
 ['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']
 识别率: 0.9

hmmlearn安装报错

该工具包安装很可能报错。
可以尝试去https://www.lfd.uci.edu/~gohlke/pythonlibs/#hmmlearn下载对应你电脑版本的文件,我的是64位,python36。
然后cd到你下载的文件的目录下,执行:

pip install hmmlearn‑0.2.1‑cp36‑cp36m‑win_amd64.whl

就可以安装成功了。

一些想法

  • 由于基于python的hmm-gmm语音识别模型较少,网上竟然没找到好使的代码,无奈下只能自己查资料写了一个小样。
  • 目前该项目只是一个demo,数据也较少,后续希望能够增加一些连续语音识别模型,搞成一个传统模型的语音识别系统。
  • 有兴趣的老哥可以查看我的另一个基于深度学习的中文识别系统ch_speech_recognition

整理不易,转载请注明出处https://blog.csdn.net/chinatelecom08
该项目github地址:https://github.com/audier/my_hmm_gmm_speech_recognition

Hmm在语音识别中的应用(一)

博文 来自: quheDiegooo

语音识别-HMM

阅读数 997

没有更多推荐了,返回首页