LiJian-kaldi搭建在线语音识别系统 资料汇总

感谢视频制作者李健和视频上传者北洋村的热心分享
原视频在:https://www.bilibili.com/video/BV19a4y1h7cB
大家记得三连~

说明

Kaldi的资料比较少,对新手特别不友好,我也是无意中搜到了这个视频的资料,看完确实收获很大,学习的过程一方面是复现出作者的各种模型,另一方面,也想在心中形成kaldi的一个big picture。

但这个视频并无相关的学习资料,另外视频的知识点的索引也不全面,我分享的目的也是希望大家一起搜集资料,互相分享,互相促进,所以这篇文章也会不断更新。

已经搜集的资料在:度盘链接,密码: p2nj
主要包括作者提到的一些资料,有些比较难下载,我这里替大家下载好了:
LiJian-kaldi搭建在线语音识别系统 资料汇总_第1张图片
注意:没有作者的代码源文件和数据集

知识点的笔记

目标:从无到有搭建起中文在线语音识别Demo

P1 准备kaldi的数据文件夹(四个基本文件)

本章节前置知识有:shell的基本工具:grep、sed、awk,linux指令的管道机制,kaldi源代码的基本结构、环境变量配置等,熟悉egs/wsj的utils和steps

本节主要讲述了训练模型前的基本准备,需要准备好四个文件:wav.scp、text、utt2spk和spk2utt,如下表所示:

需要准备的文件 文件的作用 文件内容示例 模式
wav.scp 语音文件id到语音wav文件的映射 sentense_id /path/to/wavfile.wav
text 语音文件id到语音内容的映射 sentense_id 今天天气很好
utt2spk 语音文件id到说话人的id映射 sentense_id speaker_id
spk2utt 说话人的id 到语音文件id的映射 speaker_id sentense_id1 sentense_id2 sentense_id3
  • 其中spk2utt是1对多的关系,其余都是一对一的关系
  • spk2utt可以通过命令得到 ./utils/utt2spk_to_spk2utt.pl utt2spk > spk2utt
  • 一些数据集还需要说话人性别映射(spk2gender)数据
  • 作者比较硬核,直接用linux shell脚本来实现上述文件的制作
  • 因为不同的语音数据集涉及的处理流程不一致,所以我建议这里了解基本原理即可,不必纠结
  • 我个人习惯使用python脚本,python能很方便生成这些文件

P2 准备语言模型相关文件

作者继续准备data/local/dict目录下的文件:

需要准备的文件 文件的作用 文件内容示例 模式
lexicon.txt 发音字典(单词由什么发音音素构成的),有的数据集会提供 你好 n i3 h ao3 (1-4代表声调,5代表轻声)
word.list 单词集合(text出现的单词,已去重) 今天 天气 很好
silence_phones.txt 音素集合(text出现的单词发音,已去重) SIL SPN
nonsilence_phones.txt 音素集合(text出现的单词发音,已去重) ah ao
  • 对P1的text中的每行句子进行分词,分词使用的是python里面的mmseg包
  • lexicon是发音词典,一般数据集会提供,如果不提供需要自己生成,我分享的lexicon.txt就是来自aishell数据集
  • word.list 是把text分词后的单词去重后的集合,经过实测,貌似有些数据集是不需要生成这个的
  • phones.txt 是所有出现的音素集合,按照有无发音可以分成silence_phones和nonsilence_phones
  • 这部分同样可以用python来做,但是kaldi提供了不少脚本,更方便
  • 这节主要讲述分词,生成word.list和phones.txt在下一节(P3)还会提到
  • 部分数据集还需要生成lexiconp.txt,里面包含概率

这里部分效果如下所示:
lexicon.txt:
LiJian-kaldi搭建在线语音识别系统 资料汇总_第2张图片

分词的结果:
LiJian-kaldi搭建在线语音识别系统 资料汇总_第3张图片

P3 数据集划分&建立语言模型&MFCC

本节作者继续讲述训练语言模型需要用的文件,还提到了不少的脚本:

  • kaldi数据划分的脚本(subset_data_dir.sh)
  • 验证训练文件的正确性脚本(fix_data_dir.sh)

然后作者继续生成,data/local/dict 目录下的文件,如下所示:

注意这里只是作者的习惯,有些数据集(aishell)使用了data/local/lang 和data/local/lm 等多个文件夹来保存这些文件)

需要准备的文件 文件的作用 文件内容示例
lexicon 发音字典(单词由什么音素构成的) 你情我愿 n i3 q ing2 uu uo3 vv van4
word.list 单词集合(text出现的单词,已去重) 今天 天气 很好 …
phones.txt 音素集合(text出现的单词发音,已去重) ah ao …
nonesilence_phones.txt 非静音音素集合 不包括下面的silence_phones
silence_phones.txt 静音音素集合 SIL(静音) SPN(有声音但无法识别) NSN(非口语噪声) LAU(笑声)
optional_phones.txt 填充词之间的静音音素 SIL(词间静音)
extra_questions.txt 构建音素的上下文决策树时会遇到的基本问题 这里作者保持该文件为空
  • 准备好上述文件之后,运行指令(utils/prepare_lang.sh)生成需要用到的文件,这个比较重要(定位时间:2:07:10)这一步会生成L.fst文件(decode才需要,训练不需要,下面作者还会解释)
    运行如下指令:
utils/prepare_lang.sh data/local/dict "!SIL" data/lang_tmp data/lang

data/local/dict就是我们刚才准备好的,data/lang_tmp是临时文件夹,data/lang是生成的文件目录,最终生成的 data/lang文件夹的内容如下所示:(定位时间:2:30:12
LiJian-kaldi搭建在线语音识别系统 资料汇总_第4张图片
生成的文件作者也解释了各个文件的作用,在定位时间:2:29:40
L.fst是lexicon的WFST格式(下一节会介绍), 已经把所有的音素转成了对应关系(解码图),该图的输入:音素组合,输出:词。是后续训练H、C、L解码图的一种,G训练的时候还用不到。
L_disambig.fst 目的是消除歧义,有同音字,加入#进行区分。
oov.txt是词汇表以外的词(Out of Vocabulary Words),oov.int是对应的id
phone.txt 存放了所有的音素和其编号 形如:
typo HMM模型的参数,打开这个文件,我们可以发现静音音素有五个状态,非静音音素只有三个状态

另外:

  • 因为时间原因,作者通过egs/hkust的相关例子(定位时间:2:28:04)解释了整体的训练过程
  • 有了这个文件夹之后,就可以进一步训练模型了:
    训练模型
  • 作者在最后继续介绍了MFCC的使用方法(定位时间:2:33:00),使用的指令为:./steps/make_mfcc.sh --mfcc-config conf/mfcc.conf data/all exp/extract_mfcc mfcc,然而上述是二进制文件,无法直接读取,如果需要读取,可以用命令:copy-feats ark:raw_mfcc_all.1.ark ark,t:readark.txt

下面是MFCC提取的向量,维度是13维:
LiJian-kaldi搭建在线语音识别系统 资料汇总_第5张图片

P3这一节开始接触到了kaldi的HCLG,HCLG是WSFT格式的语音任务相关的表示,对于语音识别中用到的隐马尔科夫模型(H)、发音词典(L)、语言模型(G)以及上下文(C),都可以用 一个加权有限状态接收器(WFST)来表示。

下一节作者也会讲解,这里推荐一些资料供大家预习一下
1、WSFT的学习推荐阅读《Speech Recognition Algorithms Using Weighted Finite-StateTransducer》,这个文件我已经放到分享的文件中,着重了解什么是接收器,什么是转录器
2、 HCLG的学习建议阅读链接,整个HCLG的过程:构建语言模型(G.fst),发音词典模型(L.fst),以及合并的模型(LG.fst和CLG.FST),生成HMM模型(H.fst),最终合并、确定、最小化得到HCLG.fst。我的理解是,通过FST(有限状态转录机)的格式把语音识别各个模块组合到了一起,每组合一次,语音识别的功能就会多一个,方面语音解码的时候使用。

P4 使用srilm训练语言模型&WFST介绍

这一节的重点在怎么训练语言模型和WSFT
(1)语言模型,N-gram的原理可参考这篇博客:链接
(2)WSFT的推荐资料见上一节

知识点快速索引:

  • 使用kaldi并行提取train和test的MFCC,CMVN(倒谱归一化),并通过这个例子了解kaldi的流程
  • 演示kaldi怎么训练一个语言模型,n-gram,工具是srilm (定位时间:1:30:00
  • G.fsat介绍(定位时间:1:52:31
  • WSFT解码图(定位时间:1:54:00
  • 令牌(token passing)讲解:解码时候需要(定位时间:2:33:00

截至目前,已有的重要文件:
data/lang 发音词典(L):
data/local/lm 语言模型(G,只在解码时需要)

G.fst生成指令:LiJian-kaldi搭建在线语音识别系统 资料汇总_第6张图片
G.fst可视化指令:
LiJian-kaldi搭建在线语音识别系统 资料汇总_第7张图片
L.fst可视化指令:
LiJian-kaldi搭建在线语音识别系统 资料汇总_第8张图片
组合L和G的命令:在utils/make_graph
LiJian-kaldi搭建在线语音识别系统 资料汇总_第9张图片

P5 GMM-HMM算法&HCLG过程&训练脚本讲解

GMM+HMM的理论部分我建议学习李航老师的《统计学习方法(第二版)》,主要学习:HMM评价、解码和参数估计问题,视频的话建议学习李琳山老师的数字语音处理,b站上也有相关的视频。kaldi官方也有一个教程(链接)。DTW扩展阅读我推荐看王赟的知乎live,DTW是怎么过渡到GMM的(概率密度代替欧氏距离)。

  • DTW、动态规划算法(时间对齐问题)
  • GMM+HMM算法(定位时间:1:30:00)作者推荐看eecs e6870里面的PPT,见度盘分享4-5课
  • DNN和GMM的区别(定位时间:1:56:00):生成模型和判别模型
  • HCLG的举例过程(定位时间:2:07:00
    H: HMM,包括HMM的定义
    C: context,代表上下文关系
    L: lexicon,发声字典
    G: grammar,语法规则接收器
  • 作者讲解run.sh脚本(建议大家参见thchs30 run.sh即可,下一节刚开始的时候作者继续讲解了一些脚本流程) (定位时间:2:40:00

作者讲解HCLG的时候,一直在找LG.fst的可视化例子,我找了一个:
语料为:

语音 识别 技术
语音 识别 算法 公式
作战 防御 工事

LG.fst可视化为:

体会上图:输入音素,输出是句子

这里再推荐一篇结合kaldi的HCLG的文章:链接

P6 模型训练流程

  • 先训练GMM+HMM,最终会生成final.mdl文件
  • 训练DNN+HMM 大约需要训练三轮
  • 讲解了nnet3以及训练的参数设置(如下图)
    LiJian-kaldi搭建在线语音识别系统 资料汇总_第10张图片
  • 基于Kaldi+GStreamer搭建线上的实时语音识别器(没找到pdf,截图,大家凑活看看,详细的直接到视频的后半部分看吧)LiJian-kaldi搭建在线语音识别系统 资料汇总_第11张图片
    LiJian-kaldi搭建在线语音识别系统 资料汇总_第12张图片
    LiJian-kaldi搭建在线语音识别系统 资料汇总_第13张图片
    下面截图略

P7 模型实际部署过程

这节讲述了怎么使用GStreamer,搭建在安卓和网页上,可不看。

主要配置文件如下(yaml格式):
LiJian-kaldi搭建在线语音识别系统 资料汇总_第14张图片
目录:(这就是部署的时候需要用到的模型文件)
目录
日志:(可以看出效果出来了,但是应该还是需要静一步处理的,最后俩字识别错了)

其他资料

因为作者没有提供自己数据库,我这里找到一个0-10英文发音的教程,教程比较通俗易懂,run.sh流程也不复杂,可以参考:
教程链接、代码链接、中文发音教程链接

实验过程

为了进一步消化作者提到的知识,继续学习LVCSR(大词汇连续语音识别) 相关知识,在kaldi-master/egs/thchs30/有一个清华大学王东老师的中文30小时语音的thchs30例子,基本上覆盖比较全面了,数据集也不大,新手对照run.sh里面练习就行。

也可以从aishell里面挑出10h-20h,练练手,在自己本机上也能快速跑一跑,一般机器估计训练个一天能出结果。

不建议新手参照librispeech学习,我不明白为啥《Kaldi语音识别实战》这本书要用这个数据集!!新手劝退!!这个数据集太大了(语料500小时+,数据集+训练中间文件文件夹轻轻松松就100GB了), 而且训练时间特别长,对机器性能要求也比较高,我用i9+16GB训练了3天都没出结果,最后内存消耗完了,程序被杀死了。我感觉要快速训练出来,肯定要上集群了。

其他建议

  • 建议安装在linux环境或者Mac电脑上,这两个都试过,安装环境非常方便,尽早动手安装,因为安装时间很耗时,第一次安装估计得花费几天时间,顺利的话最起码也要半天时间。最后一步可以用make -j 8 ,这个数字8就是你的cpu物理核心数量,也可以改为4或者其他
  • 如果只是单机运行,记得把cmd.sh中所有的queue改成run,不然会报错
  • 有时候脚本会遇到中断,需要重新运行,run.sh 没有记忆机制,已经跑过的脚本可以在run.sh里面手动注释了,避免再浪费时间跑一次
  • DNN训练是需要GPU的需要找一个能安装nvidia GPU的机器,不然会报错,检测这台机器能不能跑GPU可以运行nvidia-smi指令,可以找老的、带英伟达显卡的笔记本,笔者有一个2012年的笔记本,都能安装nvidia相关的驱动和cuda(最多到cuda9),显存2GB,自己测试足够了。
  • 这个视频虽然2017年,但是流程基本上都覆盖挺全的了,除了P1视频,其他的我觉得还是值得反复看几遍的。
  • 我也是初学kaldi,这方面资料真的太少了,希望大家踊跃交流吧!
  • 比较期待Daniel Povey大神的kaldi-pytorch项目,让熟悉python的人也能快速参与到语音领域。

总之,再次感谢作者分享!

如果有更好的资源和想法,欢迎在留言区讨论、分享,谢谢!

你可能感兴趣的:(kaldi,AI,语音识别,python,机器学习,人工智能)