首先,下载kaldi,kaldi会包含很多语言模型与声学模型,(关于kaldi下载,可以参考我的另一篇文章:https://blog.csdn.net/qq_57461500/article/details/139840841?spm=1001.2014.3001.5502)本次基于Aishell1数据集的实战也会在kaldi上进行。在本文进行流程的推进时,会尽可能搞懂重要的几个脚本,让我们一起学习吧。
1 简要介绍
总共178小时,400个人讲,其中训练集340个人,测试解20个人,验证集40个人,每个人大概讲三百多句话,每个人讲的话都放在一个文件夹里面。
PS:文件压缩包就有将近17个g,所以我们在设置虚拟机容量时最好设置的大一点,我一般直接设80g,kaldi加数据集就将近45g,还要解压。
2 语音识别模型
在这里简单地介绍一下Aishell1训练时会用到的几个声学模型和语言模型,想要对语音模型进行一个详细的了解,敬请关注我其他的几篇文章,我会对语言模型进行一个梳理。
言归正传,在进行Aishell的训练时
我们会用到的声学模型是
- 3-gram Language Model:3-gram模型是n-gram模型的一种,其中n代表考虑的词的数量。
我们会用到的语言模型是
- Monophone Model (单音素模型)
- Tristone Model (三音素模型)
- LDA+MLLT Model:引入线性判别分析(LDA)和最大似然线性变换(MLLT)来改进特征表示。
- nnet3 TDNN
- Chain Model
3 语音识别原理
4 run.sh
此脚本位于
/path/to/kaldi/egs/aishel/s5
中,是Aishell 1训练中的主脚本,其实我们只需要无脑run就好了,但是对于处于学习中的人们来说,这跟没做也没区别,所以作者在此拆开脚本,尽可能地搞清楚,当然,作者也是处于学习阶段,记录下来也是为了更好地掌握,所以有错误的话欢迎大家指出,也欢迎大佬指出更好的学习方法。
话不多说,我们先看
run.sh
这个脚本的内容
首先是数据准备阶段
在
run.sh
中,这部分的代码是这样的
# Lexicon Preparation,
local/aishell_prepare_dict.sh $data/resource_aishell ||exit 1;# Data Preparation,
local/aishell_data_prep.sh $data/data_aishell/wav $data/data_aishell/transcript ||exit 1;
其中包含两个脚本
aishell_prepare_dict.sh
和
aishell_data_prep.sh
,分别
用于准备字典(将单词映射到音素)和处理音频文件、转录文本,生成所需的数据文件。其中
aishell_prepare_dict.sh
的代码为
#!/usr/bin/env bash shebang行,告诉系统此脚本应用Bash进行# Copyright 2017 Xingyu Na# Apache 2.0. ./path.sh #环境变量脚本 export ...[$#!=1]&&echo"Usage: $0 <resource-path>"&&exit1;#检查命令行参数的数量是否不等于1。如果不是,打印使用方法并退出。res_dir=$1#将第一个命令行参数(资源路径)赋值给变量res_dirdict_dir=data/local/dict
mkdir-p$dict_dircp$res_dir/lexicon.txt $dict_dir#将资源目录下的lexicon.txt文件复制到字典目录。cat$dict_dir/lexicon.txt |awk'{ for(n=2;n<=NF;n++){ phones[$n] = 1; }} END{for (p in phones) print p;}'|\
perl -e'while(<>){ chomp($_); $phone = $_; next if ($phone eq "sil"); m:^([^\d]+)(\d*)$: || die "Bad phone $_"; $q{$1} .= "$phone "; } } foreach $l (values %q) {print "$l\n";}'#cat输出lexicon.txt的内容。#awk读取每一行,将除了第一个字段外的所有字段(假设是音素)存储到一个数组phones中。#perl脚本读取awk的输出,去除静音音素sil,然后根据音素的数字后缀(如果有的话)进行分组,最后输出每个组的音素列表。sort-k1>$dict_dir/nonsilence_phones.txt #对Perl脚本的输出进行排序,并重定向到nonsilence_phones.txtecho sil >$dict_dir/silence_phones.txt #创建一个包含sil的文件silence_phones.txt,表示静音音素。echo sil >$dict_dir/optional_silence.txt #可选静音因素cat$dict_dir/silence_phones.txt |awk'{printf("%s ", $1);} END{printf "\n";}'>$dict_dir/extra_questions.txt
cat$dict_dir/nonsilence_phones.txt | perl -e'while(<>){ foreach $p (split(" ", $_)) { $p =~ m:^([^\d]+)(\d*)$: || die "Bad phone $_"; $q{$2} .= "$p "; } } foreach $l (values %q) {print "$l\n";}'>>$dict_dir/extra_questions.txt
#结合了静音和非静音音素,可能用于构建语音识别系统中的状态聚类或决策树,帮助区分不同的发音状态echo"$0: AISHELL dict preparation succeeded"exit0;
对字典准备脚本
aishell_prepare_dict.sh
进行了逐行的解析,发现此脚本对aishell 1数据集中的lexicon.txt进行了拆分和分类,生成了非静音音素列表 (nonsilence_phones.txt)、静音音素列表 (silence_phones.txt)、可选静音列表 (optional_silence.txt)、额外问题列表 (extra_questions.txt)四个文本文件,组成了字典。
aishell_data_prep.sh
脚本的代码为
#!/usr/bin/env bash# Copyright 2017 Xingyu Na# Apache 2.0. ./path.sh ||exit1;if[$#!=2];thenecho"Usage: $0 <audio-path> <text-path>"#打印脚本的使用方法,即需要两个参数<audio-path> <text-path>echo" $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript"exit1;fiaishell_audio_dir=$1aishell_text=$2/aishell_transcript_v0.8.txt #加上文件名赋值给aishell_texttrain_dir=data/local/train
dev_dir=data/local/dev
test_dir=data/local/test
tmp_dir=data/local/tmp
#定义了训练集、验证集、测试集和临时目录的变量。mkdir-p$train_dirmkdir-p$dev_dirmkdir-p$test_dirmkdir-p$tmp_dirif[!-d$aishell_audio_dir]||[!-f$aishell_text];then#检查音频目录和文本文件是否存在,如果任一不存在,则进入if块。echo"Error: $0 requires two directory arguments"exit1;fifind$aishell_audio_dir-iname"*.wav">$tmp_dir/wav.flist #在音频目录下查找所有以.wav结尾的文件,并将结果重定向到临时文件wav.flist(存储路径)n=`cat $tmp_dir/wav.flist |wc-l`[$n-ne141925]&&\echo Warning: expected 141925 data data files, found $n#计算找到的WAV文件数量,并与预期数量比较,如果不相等则打印警告。grep-i"wav/train"$tmp_dir/wav.flist >$train_dir/wav.flist ||exit1;grep-i"wav/dev"$tmp_dir/wav.flist >$dev_dir/wav.flist ||exit1;grep-i"wav/test"$tmp_dir/wav.flist >$test_dir/wav.flist ||exit1;rm-r$tmp_dir# Transcriptions preparationfordirin$train_dir$dev_dir$test_dir;do#开始准备转录文本,对每个数据集目录执行循环。echo Preparing $dir transcriptions
sed-e's/\.wav//'$dir/wav.flist |awk-F'/''{print $NF}'>$dir/utt.list #使用sed和awk从WAV文件列表中提取文件名(不含扩展名),并将结果写入utt.list(音频编号)sed-e's/\.wav//'$dir/wav.flist |awk-F'/''{i=NF-1;printf("%s %s\n",$NF,$i)}'>$dir/utt2spk_all(音频编号和对应的说话人)
paste -d' '$dir/utt.list $dir/wav.flist >$dir/wav.scp_all #将将utt.list和wav.flist合并,生成wav.scp_all(音频编号和对应的路径)
utils/filter_scp.pl -f1$dir/utt.list $aishell_text>$dir/transcripts.txt #使用filter_scp.pl脚本过滤出对应的转录文本awk'{print $1}'$dir/transcripts.txt >$dir/utt.list #从转录文本中提取第一列,更新utt.list
utils/filter_scp.pl -f1$dir/utt.list $dir/utt2spk_all |sort-u>$dir/utt2spk
utils/filter_scp.pl -f1$dir/utt.list $dir/wav.scp_all |sort-u>$dir/wav.scp
sort-u$dir/transcripts.txt >$dir/text #对转录文本进行排序,生成text文件。
utils/utt2spk_to_spk2utt.pl $dir/utt2spk >$dir/spk2utt #使用utt2spk_to_spk2utt.pl脚本从utt2spk生成spk2utt文件。donemkdir-p data/train data/dev data/test
forfin spk2utt utt2spk wav.scp text;docp$train_dir/$f data/train/$f||exit1;cp$dev_dir/$f data/dev/$f||exit1;cp$test_dir/$f data/test/$f||exit1;doneecho"$0: AISHELL data preparation succeeded"exit0;
此脚本的主要目的是准备和处理AISHELL数据集,生成语音识别系统所需的一系列数据文件和目录结构。生成了六个文件:
- WAV文件列表 (wav.flist):在临时目录中生成一个包含所有WAV文件路径的列表。
- 文件名列表 (utt.list):为每个数据集生成一个文件名列表,文件名不包含.wav扩展名
- 说话人-录音对应文件 (utt2spk 或 utt2spk_all):生成一个将每个录音文件映射到其对应的说话人的文件。
- 录音文件路径映射 (wav.scp 或 wav.scp_all):为每个数据集生成一个文件,列出所有录音文件的路径。
- 转录文本 (text):从原始的转录文件中提取与WAV文件对应的转录文本,并进行排序,生成干净的文本文件。
- 说话人列表 (spk2utt):从utt2spk文件生成一个反向映射,列出每个说话人的所有录音文件。
版权归原作者 HELL0 W0R1D 所有, 如有侵权,请联系我们删除。