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.shaishell_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文件生成一个反向映射,列出每个说话人的所有录音文件。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。