第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > kaldi中文语音识别_基于thchs30(7)

kaldi中文语音识别_基于thchs30(7)

时间:2018-10-25 06:13:17

相关推荐

kaldi中文语音识别_基于thchs30(7)

接上回,mfcc特征咱们暂时看完了,总结一下,此处引用别人的分析:

特征提取

MFCC

compute-mfcc-

Create MFCC feature files.Usage: compute-mfcc-feats [options...] <wav-rspecifier> <feats-wspecifier>

其中参数rspecifier用于读取.wav文件,wspecifier用于写入得到的MFCC特征。典型应用中,特征将被写入到一个大的”archive”文件,同时会写入一个”scp”文件用于随机存取。该程序并未提取delta特征(add-).

其–channel参数用于选择立体声情况(–channel=0, –channel=1).

compute-mfcc-feats --config=conf/mfcc.conf \scp:exp/make_mfcc/train/wav1.scp \ark:/data/mfcc/raw_mfcc_train.1.ark;

第一个参数”scp:…”用于读取exp/make_mfcc/train/wav1.scp指定的文件。第二个参数”ark:…”指示计算得到的特征写入归档文件/data/mfcc/raw_mfcc_train.1.ark。归档文件里的每一句是N(frames)× N(mfcc)的特征矩阵。

MFCC特征的计算是在对象MFCC中的compute方法完成的,计算过程如下:

1.遍历每一帧(通常25ms一帧,10ms滑动)

2.对每一帧

a.提取数据,添加可选扰动,预加重和去直流,加窗

b.计算该点的能量(使用对数能量,而非C0)

c.做FFT并计算功率谱

d.计算每个梅尔频点的能量,共计23个重叠的三角频点,中心频率根据梅尔频域均匀分布。

e.计算对数能量,做离散余弦变换,保留指定的系数个数

f.倒谱系数加权,确保系数处于合理的范围。

三角梅尔频点的上下限由–low-freq和–high-freq决定,通常被分别设置成接近0和奈奎斯特频率。如对于16KHz语音–low-freq=20, –high-freq=7800。

可以使用copy-将特征转换成其它格式。

关于梅尔倒谱系数(MFCC)我们之前讲过,在Kaldi里它本身设置了合理的默认值,同时保留了一部分用户最有可能想调整的选项,如梅尔滤波器的个数,最大和最小截止频率等等.它通常需要读取wav文件或.pcm文件,假如数据源不是wav文件,我们就得使用工具来转化,Kaldi中有的sph2pipe工具能满足一般的情况.

命令工具 compute-mfcc-feats用来计算MFCC特征,若直接运行不带参数的话就会给出一个参数列表.改程序需要两个参数,rspecifier是用来读.wav数据, wspecifier是用来写特征的(就是r 和w啦).典型的用法是,将数据写入一个大的”archive”文件,也写到一个”scp”文件以便随机读取.

MFCC的计算由Mfcc类型的对象完成,它有Compute()函数可以根据波形计算特征.一个完整的MFCC计算如下:

1) 计算出一个文件中帧的数目(通常帧长25ms,帧移10ms)

2) 对每一帧提取数据,可选做Dithering,预加重和去除直流偏移,还可以和加窗函数想成(此处支持多种选项,如Hanmming 窗).

3)计算该点能量(假如用对数能量则没有C0C0).

4) 做快速傅里叶变换(FFT)并计算功率谱.

5)计算每个梅尔滤波器的能量,如23个部分重叠的三角滤波器,其中心在梅尔频域等间距.

6) 计算对数能量病作宇轩变换,根据要求保留系数(如13个).

7) 选做倒谱变;它仅仅是比例变换,确保系数在合理范围内.

上下截止频率根据三角滤波器界定,由选项–low-freq和–high-freq控制,通常分别设置为0Hz和奈奎斯特频率附近,如对16kHz采样的语音设置为–low-freq=20 和 –high-freq=7800。

Kaldi的特征和HTK的特征在很多方面不同,但是几乎所有这些不同归结于有不同的默认值。用选项–htk-compat=true并正确设置参数,能得到同HTK非常接近的特征。一个可能重要的选项是我们不支持能量最大归一化。这是因为Kaldi希望能把无状态方式应用到归一化方法,且希望从原理上计算一帧帧特征仍能给出相同结果。但是程序compute-mfcc-feats里有–subtract-mean选项来提取特征的均值。对每个语音做此操作;每个说话人可以有不同的方式来提取特征均值。(如compute_cmvn_stats.sh,表示倒谱均值和方差归一化)。

再回到run.sh中

我们看到

for x in train dev test; do

#make mfcc 生成mfcc

steps/make_mfcc.sh --nj $n --cmd "$train_cmd" data/mfcc/$x exp/make_mfcc/$x mfcc/$x || exit 1; #调用steps/make_mfcc.sh ,$n是cpu的并发数,--cmd "$train_cmd"是 训练的cmd ,它调用的是 cmd.sh中设置的train_cmd ,data/mfcc/$x 是每个数据的目录,exp/make_mfcc/$x,mfcc/$x 这些都是目录的参数

#compute cmvn 计算cmvn

steps/compute_cmvn_stats.sh data/mfcc/$x exp/mfcc_cmvn/$x mfcc/$x || exit 1;

done

接下来是CMVN(Cepstral mean and variance normalization)倒谱均值和方差归一化

倒谱均值和方差归一化包括归一化原始倒谱的均值和方差,通常给出零均值,单位方差倒谱,基于每个话语或每个说话者。 我们提供代码来支持这个,以及一些示例脚本,但我们并不特别推荐使用它。 一般而言,我们更喜欢基于模型的方法来进行均值和方差归一化; 例如,我们的线性VTLN(LVTLN)代码也学习平均偏移,指数变换(ET)的代码执行对角CMLLR变换,其具有与倒谱平均值和方差归一化相同的功效(通常应用于完全扩展的特征除外)。对于非常快速的操作,可以使用具有基于电话的语言模型的非常小的模型来应用这些方法,并且我们的一些示例脚本证明了这一点。 在特征提取代码中还有能力在每个语句的基础上减去平均值(compute-mfcc-feats 和 compute-plp-feats 减去平均值)。

为了支持每个话语和每个说话者的均值和方差归一化,我们提供了程序compute-cmvn-stats和apply-cmvn。默认情况下,程序compute-cmvn-stats将计算均值和方差归一化的足够统计量,作为矩阵(格式不是很重要;请参阅代码以获取详细信息),并将写出这些统计索引的表 通过话语id。如果给出-spk2utt选项,它将在每个说话者的基础上写出统计信息(警告:在使用此选项之前,读取在随机访问模式下读取存档时避免内存膨胀,因为此选项会导致输入功能 以随机访问模式读取)。程序“apply-cmvn”读入特征和倒谱均值和方差统计; 如果应用了-utt2spk选项,则默认情况下,每个语句都会对统计信息进行索引,或者每个说话者都会对其进行索引。 它在均值和方差归一化后写出了特征。 这些程序尽管有名字,但并不关心这些特征是否由倒谱或其他任何东西组成; 它只是将它们视为矩阵。 当然,提供给compute-cmvn-stats和apply-cmvn的功能必须具有相同的维度。

我们注意到它可能与特征转换代码的整体设计更加一致,提供一个版本的compute-cmvn-stats,可以写出平均值和方差,将变换归一化为泛型仿射变换(格式与 CMLLR转换),以便它们可以由程序transform-feats应用,并根据需要使用compose-transforms与其他转换组合。 如果需要,我们可以提供这样的程序,但由于我们不将均值和方差归一化视为任何配方的重要部分,我们还没有这样做。

倒谱均值和方差归一化

该归一化通常是为了获得基于说话人或者基于说话语句的零均值,单位方差归一化特征倒谱。但是并不推荐使用这个方法,而是使用基于模型的均值和方差归一化,如Linear VTLN(LVTLN)。可以使用基于音素的小语言模型进行快速归一化。特征提取代码compute-mfcc-/compute-plp-同样提供了–substract-mean选项获得零均值特征。如果要获得基于说话人或者基于句子的均值和方差归一化特征,可以使用

compute-cmvn-或者apply-程序。

compute-cmvn-将会计算均值和方差需要的所有统计量,并将这些统计信息以矩阵的形式写入到table中。

compute-cmvn-stats --spk2utt=ark:data/train/train.1k/spk2utt \scp:data/train.1k/feats.scp \ark:exp/mono/cmvn.ark;

在实际情况下,受不同麦克风及音频通道的影响,会导致相同音素的特征差别比较大,通过CMVN可以得到均值为0,方差为1的标准特征。均值方差可以以一段语音为单位计算,但更好的是在一个较大的数据及上进行计算,这样识别效果会更加robustness。Kaldi中计算均值和方差的代码在compute-cmvn-, 归一化在apply-。

我们下面来看看compute-cmvn-stats.sh中的内容

# Compute cepstral mean and variance statistics per speaker.

# We do this in just one job; it's fast.

# This script takes no options.

计算每个发言者的倒频谱均值和方差统计数据。我们只用一个工作来做这个; 它很快。这个脚本没有选项。

# Note: there is no option to do CMVN per utterance. The idea is

# that if you did it per utterance it would not make sense to do

# per-speaker fMLLR on top of that (since you'd be doing fMLLR on

# top of different offsets). Therefore what would be the use

# of the speaker information? In this case you should probably

# make the speaker-ids identical to the utterance-ids. The

# speaker information does not have to correspond to actual

# speakers, it's just the level you want to adapt at.

注意:没有选项可以根据每段话语进行CMVN。 也就是,如果你按照每段话语进行CMVN,那么在每个说话者上进行fMLLR是没有意义的(因为你将在不同的偏移量之上进行fMLLR)。 那么说话者信息的用途是什么? 在这种情况下,您应该使说话者ID与话语-id相同。 说话者信息不必与实际说话者相对应,它只是您想要适应的级别。

echo "$0 $@" # Print the command line for logging #打印命令行日志

将后面的注释掉,我们运行./run.sh,看一下

图中的打印就是echo打印出来的,继续

fake=false # If specified, can generate fake/dummy CMVN stats (that won't normalize) #如果指定,可以生成假的/虚拟的CMVN统计(不会规范化)

fake_dims= # as the "fake" option, but you can generate "fake" stats only for certain

# dimensions. #作为“假”选项,但您只能为某些维度生成“假”统计数据

two_channel=false #应该是双通道的意思

这块应该是传送一些参数,但是这些参数在实际运行run.sh中并没有传递,我们加入一些打印验证一下

if [ "$1" == "--fake" ]; then

echo "--fake"

fake=true

shift

fi

if [ "$1" == "--fake-dims" ]; then

echo "--fake-dims"

fake_dims=$2

shift

shift

fi

if [ "$1" == "--two-channel" ]; then

echo "--two-channel"

two_channel=true

shift

fi

我们运行之后发现没有打印,说明并没有调用这里,我们继续

-lt 表示小于$# 表示这个程序的参数个数-gt 表示大于

if [ $# -lt 1 ] || [ $# -gt 3 ]; then

echo "Usage: $0 [options] <data-dir> [<log-dir> [<cmvn-dir>] ]";

echo "e.g.: $0 data/train exp/make_mfcc/train mfcc"

echo "Note: <log-dir> defaults to <data-dir>/log, and <cmvn-dir> defaults to <data-dir>/data"

echo "Options:"

echo " --fakegives you fake cmvn stats that do no normalization."

echo " --two-channel is for two-channel telephone data, there must be no segments "

echo " file and reco2file_and_channel must be present. It will take"

echo " only frames that are louder than the other channel."

echo " --fake-dims <n1:n2> Generate stats that won't cause normalization for these"

echo " dimensions (e.g. 13:14:15)"

exit 1;

fi

我们运行之后发现没有打印,说明并没有调用这里,我们继续

if [ -f path.sh ]; then . ./path.sh; fi #如果存在path.sh 则调用./path.sh

我们在path.sh中加入一些打印看看是否是调用了

我们发现确实是调用了,我们看到是在运行run.sh是要用到的环境变量,在这里重新在设置一下.

data=$1 #将第一个参数赋值到data

if [ $# -ge 2 ]; then #-ge表示大于等于$# 表示这个程序的参数个数

echo "----$2"

logdir=$2 #将第二个参数赋值到logdir

else

logdir=$data/log

fi

if [ $# -ge 3 ]; then

echo "----$3"

cmvndir=$3#将第三个参数赋值到cmvndir

else

cmvndir=$data/data

fi

为了判断调用流程,我们加入一些打印信息,运行./run.sh,显示

说明这两处都调用了,也就说明logdir和cmvndir都被赋了相应的值。我们接着继续

# make $cmvndir an absolute pathname. #这块是调用perl脚本来创建目录,给cmvndir一个绝对路径名称

cmvndir=`perl -e '($dir,$pwd)= @ARGV; if($dir!~m:^/:) { $dir = "$pwd/$dir"; } print $dir; ' $cmvndir ${PWD}`

# use "name" as part of name of the archive. #使用“名称”作为文件名称的一部分

name=`basename $data`

创建两个目录

mkdir -p $cmvndir || exit 1;

mkdir -p $logdir || exit 1;

我们接着继续

required="$data/feats.scp $data/spk2utt" #将两个文件赋值给required

for f in $required; do #循环遍历两个文件 检测是否存在这两个文件

if [ ! -f $f ]; then

echo "make_cmvn.sh: no such file $f"

exit 1;

fi

done

我们继续,以下是先后判断$fake、$two_channel、"$fake_dims"是否为空;三个条件,三个条件都不满足,运行下面的else

if $fake; then

dim=`feat-to-dim scp:$data/feats.scp -`

! cat $data/spk2utt | awk -v dim=$dim '{print $1, "["; for (n=0; n < dim; n++) { printf("0 "); } print "1";

for (n=0; n < dim; n++) { printf("1 "); } print "0 ]";}' | \

copy-matrix ark:- ark,scp:$cmvndir/cmvn_$name.ark,$cmvndir/cmvn_$name.scp && \

echo "Error creating fake CMVN stats. See $logdir/cmvn_$name.log." && exit 1;

elif $two_channel; then

! compute-cmvn-stats-two-channel $data/reco2file_and_channel scp:$data/feats.scp \

ark,scp:$cmvndir/cmvn_$name.ark,$cmvndir/cmvn_$name.scp \

2> $logdir/cmvn_$name.log && echo "Error computing CMVN stats (using two-channel method). See $logdir/cmvn_$name.log." && exit 1;

elif [ ! -z "$fake_dims" ]; then

! compute-cmvn-stats --spk2utt=ark:$data/spk2utt scp:$data/feats.scp ark:- | \

modify-cmvn-stats "$fake_dims" ark:- ark,scp:$cmvndir/cmvn_$name.ark,$cmvndir/cmvn_$name.scp && \

echo "Error computing (partially fake) CMVN stats. See $logdir/cmvn_$name.log" && exit 1;

else

echo"----test" #我们加入一些打印判断流程

! compute-cmvn-stats --spk2utt=ark:$data/spk2utt scp:$data/feats.scp ark,scp:$cmvndir/cmvn_$name.ark,$cmvndir/cmvn_$name.scp \

2> $logdir/cmvn_$name.log && echo "Error computing CMVN stats. See $logdir/cmvn_$name.log" && exit 1;

fi

在实际输出中已经输出了"----test",所以证明进入了这里

这里的意思是如果compute-cmvn-stats这个命令执行成功并且没有标准错误,就不会在exp/mfcc_cmvn/cmn_train.log中记录错误日志,如果执行不成功,则在这个文件中输出信息。我们看一下exp/mfcc_cmvn/cmn_train.log

其中记录了这个命令执行的具体参数信息,同时在/opt/kaldi/egs/thchs30/s5/mfcc/train下还会生成两个文件

ark为二进制文件,scp为记录ark位置,其实与mfcc生成文件的方法是一样的。我们继续

接下来是拷贝cmvn_train.scp文件到

cp $cmvndir/cmvn_$name.scp $data/cmvn.scp || exit 1;

wc命令是统计命令,如文件的字符数等,wc -l是统计行数

-ne 表示 不等于

nc=`cat $data/cmvn.scp | wc -l`#统计$data/cmvn.scp文件行数

nu=`cat $data/spk2utt | wc -l`#统计$data/spk2utt文件行数

if [ $nc -ne $nu ]; then #实际上就是如果$data/cmvn.scp文件行数 不等于$data/spk2utt文件行数

echo "$0: warning: it seems not all of the speakers got cmvn stats ($nc != $nu);"#打印它看起来不是所有的说话者都得到了cmvn处理

[ $nc -eq 0 ] && exit 1; #如果$data/cmvn.scp文件行数-eq等于0就退出

fi

echo "Succeeded creating CMVN stats for $name" #打印成功创建CMVN统计

未完待续。。。。。。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。