小言_互联网的博客

语音识别之Kaldi:学习GMM-HMM

418人阅读  评论(0)

语音识别之Kaldi

kaldi语音识别理论与实践课程学习。

前面的博客介绍了语音识别的基础知识及原理。现在开始学习实战。以Kaldi框架为基础。

Kaldi是一个有全套的语音识别代码的工具,由Dan Povey博士和捷克的BUT大学联合开发,最早发布于2011年,底层代码使用C++编写,接口采用shell和python,覆盖了统计模型和深度学习方法,操作灵活,易于扩展,开发者更为活跃。

语音识别流程:

目前开源的语料库有:

Kaldi实战

Kaldi官网:KALDI

里面有详细的文档。

  • 下载Kaldi:https://github.com/du-ud/kaldi-cslt.git
    注: 安装kaldi前, 已编译好cuda

  • 下载数据集:(开源数据集thchs30)
    OpenSLR: https://openslr.org/18/

整个流程包括以下几个部分:

数据准备

数据预处理
1.划分为训练集train和测试集test


输入: 数据存储地址
输出: 在当前目录下新生成的 /data 文件夹,里面如下图。train和test里的文件夹名字一样,但内容不一样,不然就是作弊了。

  • wav.scp:音频索引地址
  • text:音频文件对应的文本内容
    这个文本内容中间有一些空格,因为是经过了分词处理
  • utt2spk:每个句子是有哪个说话人说的
  • spk2utt:每个说话人都说了哪些句子

    为什么有后两个文件夹呢?
    因为之前的数据比较稀少,说话人对语音识别性能的影响比较大,可能同一套ASR对这个人识别效果好,对另一个人就不行。现在可以通过某种算法,先提取说话人信息,将该信息从说话人模型中去除,就可以较小不同说话人的影响。但后面随着数据的增多,就不用去除了。

2.生成dict文件夹


dict 文件夹里如下:

去除了lexion里面的一些特殊符号。首先打开看一下:

cd data/dict/
vim lexicon.txt

lexion是一个发音词典,表示每个字的读音,但它的注音和我们的拼音不太一样但也差不多

再看看extra_questions.txt里面的

cd data/dict/
vim extra_questions.txt

将具有相同声调的音归为一行,为了有助于GMM训练时决策树的聚类。如果后面训练别的语种,不知道这些信息的话就把这些文件设为空。

再看看nonsilence_phones.txt里面的

cd data/dict/
vim nonsilence_phones.txt

去除静音音素之外,所有音素的集合。

3.生成lang文件夹
是在dict基础上生成的。
首先在data文件夹下建一个lang文件夹,调用prepare_lang.sh这个脚本,输入是dict文件,输出在lang文件夹下。

里面的两个参数:

第一个考虑到英文的某个单词是另一个单词的前缀或后缀(位置相关),在数据有限的情况下,考虑位置信息提高性能。数据量大的话不用考虑。
第二个就是系统将不认识的词映射到oov里面。

lang文件夹里如下:

  • L.fst:音素到词的映射关系。输入的是音素,输出是词。
cd data/lang
fstprint L.fst | head -n 20

例:第一行
前两个数,表示从0状态跳转到1状态
三四数:输入输出表达的什么东西
第五个数:跳转的概率(先赋予一部分的初始概率)

为了更清楚,加上输入phones和输出words重新打印

cd data/lang
fstprint --osymbols=words.txt --isymbols=phones.txt L.fst | head -n 20

第三列:phone的id
第四列:word的id
第五列:预先赋予的跳转概率(给eps, spokenNoise等这些特殊符号的),下面那些词的概率需要经过声学&语言模型的训练得到的。

  • oov:将不认识的集外词映射到里面去。

  • phones.txt:音素映射表,对每个音素进行编号

  • phones文件夹:用于决策树聚类
    我们看一下里面

cd data/lang
head -n 20 phones.txt

出现下图中间的一个。

数据准备-words、phones与lexicon的关系

  • words.txt:词映射表,对每个词进行编号
    里面的词和发音词典的词基本一一对应(发音词典大概有五万多个词,对应的词表只有四万九千多个,近几年的新词还没包含进去)
cd data/lang
head -n 20 words.txt

  • topo:拓扑图,隐马尔可夫网络HMM
cd data/lang
vim topo

里面有两个HMM网络,一个是普通音素的,一个是静音音素的。
下图从2到218就是phone的id, 然后是HMM的三个跳转状态和一个输出状态。
1是静音音素的编号,可以看到有5个状态,

非静音跳转状态图:

特征提取

目前常见的两种特征。一般MFCC特征用于GMM训练,FBANK特征用于DNN训练。

MFCC和FBank特征提取原理:

先删除残留文件夹,新建两个目录,将训练集和测试集复制进去。
提取MFCC及FBank特征,并计算其均值和方差。

计算MFCC命令

. ./path.sh
compute-mfcc-feats

比如:参数1和2就是降采样和升采样。这些选项可以放到.conf配置文件里面。

生成如下目录:

cd data/mfcc/train
ls

查看MFCC:

. ./path.sh
cd data/mfcc/train/data
copy-feats ark:raw_mfcc_train.1.ark ark,t:train.1.ark.txt
vim train.1.ark.txt

行:帧数,一帧为一行
列:维度,MFCC特征默认13维

以A02_000音频为例:

然后看下均值方差,是按每个说话人提取的

. ./path.sh
cd data/mfcc/train/data
copy-feats ark:cmvn_train.ark ark,t:cmvn_train.ark.txt
copy-feats --binary=false ark:cmvn_train.ark ark:cmvn_train.ark.txtvim train.1.ark.txt

行:均值总和、方差总和

查看log:
kaldi的log非常全,索引对不上,采样不一致等问题都有。

cd data/mfcc/train/log/
vim make_mfcc_train.1.log

GMM训练

整体过程:
共有5大模块,可分为10小步。每两步一个模块。
1.先训练一个单音素模型;2.对齐
3.再训练一个三音素模型;4.对齐
5.用lda等算法重估GMM模型; 6.对齐

mono单音素模型训练

命令如下,

steps/train_mono.sh --boost-silence 1.25 --nj 10 --cmd
"run.pl" data/mfcc/train data/lang exp/mono

参数:
–boost-silence:静音音素权重设置,1.25 一般不用改
–nj 10:就是用10个线程(小于等于训练集中说话人数量)
run.pl:在本机跑

输入1: MFCC数据 ( data/mfcc/train)
输入2: lang (data/lang)
输出: 单音素模型(exp/mono)

具体流程:

  • 模型初始化:有GMM模型的均值、方差,和隐马尔可夫的转移矩阵。随机生成,其实也不是真正随机,用了训练集的部分特征。

  • 制作graph:需要输入上一步初始化的模型,lang文件中的L.fst,词表,以及训练集中的标注文本。生成结果是一个从句子到音素的fst压缩包,是训练集中每一个音频对应的文本标签生成的,一个文本标签生成一个fst。(句子-词-字-拼音-音素-HMM中的状态)

  • 等对齐:均匀对齐。现在要将MFCC特征和fst对应起来。
    黄色是MFCC特征,每条是一帧,一帧是13维。
    要与下面的fst对齐。(只画到音素级别)

    什么是均匀对齐?就是假如现在是4个音素,对应100帧,那就平分,每个音素对100/4=25帧。统计这25帧的均值和方差,就是一个高斯模型了。
    后面还有三音素模型(考虑了协同发音):

    但存在一个问题:本来有两百多个音素,但考虑了前后协同发音,就成了200* 200* 200个了,这个数量太大了。
    解决办法:决策树聚类(将具有相近发音的音素归为一类,集中训练)

  • 模型重估:现在已经统计了全部数据的特征,也通过对齐知道了每帧对应的状态,以及每个状态的跳转概率。基于这些信息对模型进行重估。

  • 对齐信息:用重估后的统计量和前面的fst生成新的对齐信息。注意,此时不是均匀对齐了,此时过程可理解为一个模型对训练集的解码过程,把每帧特征放到每个状态对应的GMM里算概率,得到每个状态的后验概率,概率最大的音素作为这一帧对应的音素。
    此时可能第一个音素20帧,第二个音素28帧等等。

  • 统计计算:计算每个音素跳转的次数占全部跳转次数的比例。得到每个状态的跳转概率,又进行模型重估,重复该过程(重复次数可以自己设置,默认40次)。

跑完代码生成的东西:
在mono文件夹里

final.occs:简单理解为全局统计量,每个音素对应几个状态的信息
aligz:每迭代一次,对齐信息跟新一次
fst.
.gz:训练集中每条语音对应的文本信息(句子-词-字-拼音-音素-HMM中的状态)都在这里面

final模型查看

声学模型不能直接代开看,用kaldi自带的命令打开:

gmm-copy --binary=false final.mdl final.mdl.txt


1-23行是HMM的拓扑图。7-10行是音素编号为2-218的HMM,其状态有3个。16-21行是音素编号为1的HMM,其状态有5个,也就是静音音素。24行是决策树聚类数,656类。

为什么是656类呢?

左图:25-29行是中间一列0-4(静音),剩下的都是0,1,2。
右图:第一列共218个音素,第二列状态,第三列决策树聚类数。

静音是5个状态,剩下都是3状态:217* 3+5=656,说明把每个状态都分成了一类。

后面还有如下信息:

MFCC维度39:因为作了一阶二阶差分(13+13+13)
Weigh两个:说明是两个单高斯组成的GMM
均值39列,方差39列

GCONSTS的超参是什么呢?

W权重,后面是标准的高斯。取出了与x无关的项,提前计算好,这样后面就可以减少计算量。

final.occs查看

show-transitions phones.txt final.mdl final.occs > final.occs.txt

对每个HMM的描述

以前5行为例,描述状态1到1(自环),2,3,4的过程。

提特征按帧级别提的,
训练也是按帧级别训练的,
训练的结果是什么?

对齐信息查看

. ./path.sh
ali-to-phones

里面是每个phone的对齐信息

每个phone-id对应的音素是什么?

cd exp/mono
gunzip -c ali.1.gz | ali-to-phones --per-frame=true final.mdl ark:- ark,t:- | ../../utils/int2sym.pl -f 2- phones.txt

每帧特征对应的音素,

每个音素持续的时间是多久?

gunzip -c ali.1.gz | ali-to-phones --ctm-output=true final.mdl ark:- -| ../../utils/int2sym.pl -f 5 phones.txt

以A02_000为例:

文本内容:
绿 是 阳春 烟 景 大块 文章 的 底色 四月 的 林 峦 更是 绿 得 鲜活 秀媚 诗意 盎然

比如:前0.87s都是静音段,绿这个字lv4,从0.87s到0.1s,持续了0.1+0.2s=0.3s。可以用音频播放软件看看对的准不准。

网格信息查看

cd exp/mono
gunzip fsts.1.gz
fstcopy ark:fsts.1 ark,t:fsts.1.txt

存的词、字、音素、状态之间的映射关系,跳转关系

决策树

cd exp/mono
tree-info tree

里面有三行信息:

context-width:单音素模型就是1,三音素就是3
central-position:单音素就是0,三音素就是1(0,1,2,看到1就是中间位置)

画出决策树:

cd exp/mono
draw-tree phones.txt tree | dot -Gsize=8,10.5 -Tps | ps2pdf - tree.pdf


静音的HMM有5个状态,其他都是3个。

log分析:

用于检查错误

init.log:模型初始化时产生的
compile.log:fst时产生的
align.log:对齐时产生的

这样,就完成了下图流程中的第1,2,3步。

同样的方法,进行第4步:

训练aligh_si.sh

steps/align_si.sh --boost-silence 1.25 --nj 10 --cmd "run.pl"
data/mfcc/train data/lang exp/mono exp/mono_ali

此时:

查看mono_ali.sh生成内容:

cd mono_ali
gunzip -c ali.1.gz | ali-to-phones --ctm-output=true final.mdl
ark:- -| ../../utils/int2sym.pl -f 5 phones.txt


对齐信息和之前一样,说明单音素模型迭代没有效果,就这样了,需要新的算法来提升模型对齐能力。

GMM训练-对比mono_ali、 tri4b_ali对齐信息
A02_000文本:
绿 是 阳春 烟 景 大块 文章 的 底色 四月 的 林 峦 更
mono tri4b 是 绿 得 鲜活 秀媚 诗意 盎然

mono_ali: sox A2_0.wav part.wav trim 0.87 0.3

tri4b_ali : sox A2_0.wav part.wav trim 0.86 0.29


此时对齐的时间不一样了。


转载:https://blog.csdn.net/qq_36002089/article/details/128216320
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场