aishell详细脚本解析---kaldi入门实战(1)--数据准备
HELL0 W0R1D 2024-07-26 09:01:01 阅读 57
首先,下载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 TDNNChain Model
3 语音识别原理
4 run.sh
此脚本位于<code>/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>" && exit 1; #检查命令行参数的数量是否不等于1。如果不是,打印使用方法并退出。
res_dir=$1 #将第一个命令行参数(资源路径)赋值给变量res_dir
dict_dir=data/local/dict
mkdir -p $dict_dir
cp $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.txt
echo 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"
exit 0;
对字典准备脚本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 || exit 1;
if [ $# != 2 ]; then
echo "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"
exit 1;
fi
aishell_audio_dir=$1
aishell_text=$2/aishell_transcript_v0.8.txt #加上文件名赋值给aishell_text
train_dir=data/local/train
dev_dir=data/local/dev
test_dir=data/local/test
tmp_dir=data/local/tmp
#定义了训练集、验证集、测试集和临时目录的变量。
mkdir -p $train_dir
mkdir -p $dev_dir
mkdir -p $test_dir
mkdir -p $tmp_dir
if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then #检查音频目录和文本文件是否存在,如果任一不存在,则进入if块。
echo "Error: $0 requires two directory arguments"
exit 1;
fi
find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist #在音频目录下查找所有以.wav结尾的文件,并将结果重定向到临时文件wav.flist(存储路径)
n=`cat $tmp_dir/wav.flist | wc -l`
[ $n -ne 141925 ] && \
echo Warning: expected 141925 data data files, found $n #计算找到的WAV文件数量,并与预期数量比较,如果不相等则打印警告。
grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1;
grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1;
grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1;
rm -r $tmp_dir
# Transcriptions preparation
for dir in $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 -f 1 $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 -f 1 $dir/utt.list $dir/utt2spk_all | sort -u > $dir/utt2spk
utils/filter_scp.pl -f 1 $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文件。
done
mkdir -p data/train data/dev data/test
for f in spk2utt utt2spk wav.scp text; do
cp $train_dir/$f data/train/$f || exit 1;
cp $dev_dir/$f data/dev/$f || exit 1;
cp $test_dir/$f data/test/$f || exit 1;
done
echo "$0: AISHELL data preparation succeeded"
exit 0;
此脚本的主要目的是准备和处理AISHELL数据集,生成语音识别系统所需的一系列数据文件和目录结构。生成了六个文件:
WAV文件列表 (wav.flist):在临时目录中生成一个包含所有WAV文件路径的列表。文件名列表 (utt.list):为每个数据集生成一个文件名列表,文件名不包含.wav扩展名说话人-录音对应文件 (utt2spk 或 utt2spk_all):生成一个将每个录音文件映射到其对应的说话人的文件。录音文件路径映射 (wav.scp 或 wav.scp_all):为每个数据集生成一个文件,列出所有录音文件的路径。转录文本 (text):从原始的转录文件中提取与WAV文件对应的转录文本,并进行排序,生成干净的文本文件。说话人列表 (spk2utt):从utt2spk文件生成一个反向映射,列出每个说话人的所有录音文件。
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。