kaldi学习

  参考文档:http://www.cnblogs.com/welen/p/7485151.html 

   写在前面,本文虽然对大多数脚本进行了解释,但只是初学者的理解,如果你认为读起来不知所云,建议从 kaldi 官方文档 读起,两边配合理解,可以解决很多看起来好像很难理解的东西。(官方文档地址: http://www.kaldi-asr.org/doc/data_prep.html )

  今天开始了kaldi脚本的学习,首先从kaldi 最简单的demo开始。

  路径: kaldi-trunk/egs/yesno/s5

  运行: ./run.sh

  目前代码:

 1 #!/bin/bash
 2 
 3 #====
 4 # run.sh 的代码会展现清晰的语音处理的过程,目前学习到 数据准备阶段的 prepare_data.sh
 5 #====
 6 
 7 train_cmd="utils/run.pl"
 8 decode_cmd="utils/run.pl"
 9 
10 #====
11 #waves_yesno 用于存储语音文件,检测到本目录不存在,就去指定链接下载语音包
12 #====
13 if [ ! -d waves_yesno ]; then
14   wget http://www.openslr.org/resources/1/waves_yesno.tar.gz || exit 1;
15   # was:
16   # wget http://sourceforge.net/projects/kaldi/files/waves_yesno.tar.gz || exit 1;
17   tar -xvzf waves_yesno.tar.gz || exit 1;
18 fi
19 
20 
21 train_yesno=train_yesno
22 test_base_name=test_yesno
23 
24 #====
25 # -r :rm 命令参数,递归删除
26 # -f :rm 命令参数,递归删除
27 # but I don not know why remove them
28 #====
29 rm -rf data exp mfcc
30 
31 # Data preparation
32 
33 #====
34 # 目前只看到这里
35 #====
36 local/prepare_data.sh waves_yesno
 
 1. local/prepare_data.sh 
#!/bin/bash
#egs/yesno/s5/local/prepare_data.sh

#====
# -p means make all dirs if there is no such dir 
#====
mkdir -p data/local
local=`pwd`/local
scripts=`pwd`/scripts

export PATH=$PATH:`pwd`/../../../tools/irstlm/bin

echo "Preparing train and test data"

#====
#  $1 : shell 命令,指的是文件运行时传进来的第一个参数,自然 $2,$3就指的是第2,3个命令行参数
#         这里 $1 =  waves_yesno
#====
train_base_name=train_yesno
test_base_name=test_yesno
waves_dir=$1



#====
# ls -1 : 所有的文件和目录都单行显示,每个文件或者目录占一行
# > : 指的是重定向输出,后面跟的就是输出到哪一个文件。具体可以查找Linux重定向相关内容 
# 形式: ls [option] > outputfile # 这里是把刚才下载的语音包的所有文件名都提取出来,写进data/local/waves_all.list # 目的是为了保存语音文件的文件名,后面建立语音ID与语音文本的对应还会用到这些文件名 #==== ls -1 $waves_dir > data/local/waves_all.list #==== # 下面几行代码创建的文件(比如waves.test waves.train)都在这个文件夹下面 #==== cd data/local. #==== # waves_all.list 的文件名被分成了两个部分, # 一部分放进了waves.test,用于测试 # 一部分放进了waves.train,用于训练
# 具体代码在下一小节 #==== ../../local/create_yesno_waves_test_train.pl waves_all.list waves.test waves.train #==== # ../../local/create_yesno_wav_scp.pl waves_yesno waves.test > test_yesno_wav.scp # test_yesno_wav.scp 保存的是语音ID 以及 对应的语音文件名 # 就像这样 : 0_0_0_0_1_1_1_1 waves_yesno/0_0_0_0_1_1_1_1.wav # > : 重定向输出。 # ../../local/create_yesno_wav_scp.pl 里面有一个输出语句,输出语句的输出内容被重定向输出到了test_yesno_wav.scp #==== ../../local/create_yesno_wav_scp.pl ${waves_dir} waves.test > ${test_base_name}_wav.scp ../../local/create_yesno_wav_scp.pl ${waves_dir} waves.train > ${train_base_name}_wav.scp #==== # test_yesno.txt 保存的是语音ID以及语音文本的对应关系 # 像这样 : 0_0_1_1_1_1_0_0 NO NO YES YES YES YES NO NO #==== ../../local/create_yesno_txt.pl waves.test > ${test_base_name}.txt ../../local/create_yesno_txt.pl waves.train > ${train_base_name}.txt cp ../../input/task.arpabo lm_tg.arpa cd ../.. # This stage was copied from WSJ example #==== # 大概就是生成了两个文件 # spk2utt 发音人 - 发音id 对应关系 # utt2spk 发音id - 发音人 对应关系 #==== for x in train_yesno test_yesno; do mkdir -p data/$x cp data/local/${x}_wav.scp data/$x/wav.scp cp data/local/$x.txt data/$x/text cat data/$x/text | awk '{printf("%s global ", $1);}' > data/$x/utt2spk utils/utt2spk_to_spk2utt.pl <data/$x/utt2spk >data/$x/spk2utt do

  至此,prepare_data.sh 代码阅读完毕

  目录结构是这样的:

  

  目录结构如下:(来自WELEN的博客)
data
├───train_yesno   训练文件夹
│   ├───text      (发音id 发音文本)
│   ├───utt2spk   (发音id 发音人)
│   ├───spk2utt   (发音人 发音id)
│   └───wav.scp   (发音id 发音文件)
└───test_yesno
    ├───text
    ├───utt2spk
    ├───spk2utt
    └───wav.scp
 
  2. 再看下create_yesno_waves_test_train.pl
  
 1 #!/usr/bin/env perl
 2 
 3 #====
 4 # ARGV[]:perl 的命令行参数数组
 5 # 根据prepare_data.sh 知道三个参数分别是 
 6 # waves_all.list , waves.test , waves.train
 7 #====
 8 $full_list = $ARGV[0];
 9 $test_list = $ARGV[1];
10 $train_list = $ARGV[2];
11 
12 #====
13 # open : perl文件操作函数, 文件操作都是通过文件句柄
14 #     形式: open FILEHANDLE FILENAME
15 # <filehandle> 是文件信息读取运算符,按行读取
16 # 这个循环得到了语音文件的总数,为下一步把文件名分成两部分做准备
17 #====
18 open FL, $full_list;
19 $nol = 0;
20 while ($l = <FL>)
21 {
22     $nol++;
23 }
24 close FL;
25 
26 #====
27 # > : open 函数中对文件的操作方式,具体可以查找网上 perl open函数 相关内容
28 # chomp: 大概的作用就是去掉当前行的末尾的换行符
29 #====
30 $i = 0;
31 open FL, $full_list;
32 open TESTLIST, ">$test_list";
33 open TRAINLIST, ">$train_list";
34 #====
35 # this while(){} shows what this .pl file do:
36 # divide all data into two part,
37 # first part will put in waves.train
38 # the second 30 files' name will put in waves.test
39 #====
40 while ($l = <FL>)
41 {
42     chomp($l);
43     $i++;
44     if ($i <= $nol/2 )
45     {
46         print TRAINLIST "$l
";
47     }
48     else
49     {
50         print TESTLIST "$l
";
51     }
52 }

  3. create_yesno_wav_scp.pl

#!/usr/bin/env perl

#====
# $ARGV[0] = waves_yesno 
# ARGV[1] = waves.test
#====
$waves_dir = $ARGV[0];
$in_list = $ARGV[1];

open IL, $in_list;

#====
# 把语音ID-语音文件的对应关系输出到 对应文件
# final output like this : 0_0_0_0_1_1_1_1 waves_yesno/0_0_0_0_1_1_1_1.wav 
# line 2: 
#        "." :应该只是连接符号,但是不确定,没有查到
#         “/”: 是转义字符,所以full_path应该是这样的:waves_yesno/0_0_0_0_1_1_1_1.wav
# line 3: =~ s/// 是perl的替换符 
#         形式: =~ s/pattern/replacement/[option]
#             具体可以查看网上 perl s/// 操作符的内容
# line 4: print strings will rewrite into test_yesno_wav.scp which have been gave in prepare_data.sh
#====
while ($l = <IL>)
{
    chomp($l);
    $full_path = $waves_dir . "/" . $l;
    $l =~ s/.wav//;
    print "$l $full_path
";
}

  

  4.create_yesno_txt.pl

#!/usr/bin/env perl

#====
# ARGV[0] = waves.test
# in_list = waves.test
#====
$in_list = $ARGV[0];

open IL, $in_list;

#====
# here will replace all 0 as NO  ,all 1 as YES, all — as sapce
# print will rewrite into test_yesno.txt which has been gave in prepare_data.sh
# g : option of =~ s/patterns/replacement/[option]
#     replace all patterns in string as replacement
#====
while ($l = <IL>)
{
    chomp($l);
    $l =~ s/.wav//;
    $trans = $l;
    $trans =~ s/0/NO/g;
    $trans =~ s/1/YES/g;
    $trans =~ s/\_/ /g;
    print "$l $trans
";
}

  5. 阶段性小结 

  5.1

    综上,数据准备阶段的 prepare_data.sh 的工作,主要集中在 egs/yesyno/s5/data 目录,完成的工作基本上可以看做是数据标注,将语音包分成两部分,一部分用于训练,一部分用于测试训练的模型。

    比如 text 文件,就将语音进行了标注,指出每一个语音对应的文字内容。wav.scp 就标注出了语音对应的语音文件。 

  5.2

    数据准备阶段完成的工作包括,

      下载语音包,

      建立必要的工作目录以及文件,

        包括训练使用的目录,

          建立的文件用于建立对应关系便于训练

            发音ID - 发音文本

            发音ID - 发音文件

            发音ID - 发音人

            发音人  - 发音ID

        包括测试使用的目录,

          建立的文件用于建立对应关系便于测试,检查测试结果

            发音ID - 发音文本

            发音ID - 发音文件

            发音ID - 发音人

            发音人  - 发音ID

原文地址:https://www.cnblogs.com/gstblog/p/8933797.html