一个语音识别例子记录
1.生成四个文件
1.1生成utt.scp文件 [utt-id] [wav-path]
将所有的.wav文件的路径写入文件中
find /CDShare/Data/guangzhou/King-Tem-051/Data/iOS/Wav/ -iname '*.wav' > wav.scp.temp
将路径中/Session0去掉,为了后面方便生成wav_id
sed -i 's/\/Session0//g' wav.scp.temp
将所有wav文件的id写入文件
cat wav.scp.temp | awk -F '/' '{printf("%s_%s\n",$(NF-1),$NF)}' | sed 's/.wav//' | sed 's/Speaker/Speaker_/' > wav_id
先删除wav.scp.tmp文件,因为之前删除了Session0.然后重新生成wav.scp.tmp文件
将utt-id和wav-path合并到一个文件
paste -d' ' wav_id wav.scp.temp> wav.scp
1.2生成text文件 [utt-id] [text-context]
将原始的txt文件拷贝一份到工作目录
cp /CDShare/Data/guangzhou/King-Tem-051/Data/iOS/Script/* script/
将编码转成utf_8
在script
同级目录建立文件夹script_utf8
for x in script/*;
do y=`echo $x |sed 's/script/script_utf8/'`;
iconv -f UTF-16LE -t UTF-8 $x > $y;done
为每个txt文件生成text-id
generate_text_id.sh
#!/bin/bash
file=$1
speaker_id=`basename $file`
#echo $speaker_id
string=`echo $speaker_id | sed 's/.txt//' | sed 's/Speaker/Speaker_/'`
awk -v spk=$string 'NR%2!=0 {printf("%s_%s\n",spk,$1)}' $file> /tmp/${speaker_id}_text_id
awk 'NR%2==0' $file >/tmp/${speaker_id}_text
paste -d ' ' /tmp/${speaker_id}_text_id /tmp/${speaker_id}_text > /tmp/${speaker_id}.tmp
sed 's/\t//g' /tmp/${speaker_id}.tmp | sed 's/\xEF\xBB\xBF//'>/tmp/${speaker_id}
rm /tmp/*.tmp
rm /tmp/*_text
exit 0
for x in script_utf8/*.txt;do ./generate_text_id.sh $x; done
将所有的文件合并
cat /tmp/Speaker*.txt > text
1.3生成utt2spk [utt-id] [spk-id]
cut -d' ' -f 1 text | awk -F '_' '{printf($0 " "$1 "_" $2 "\n")}'>utt2spk
1.4生成spk2utt [spk-id] [utt-id]
链接kaldi
ln -s ~/kaldi/
连接kaldi的工具
ln -s ~/kaldi/egs/wsj/s5/steps/ steps
ln -s ~/kaldi/egs/wsj/s5/utils/ utils
通过kaldi的工具将utt2spk生成spk2utt
./utils/utt2spk_to_spk2utt.pl utt2spk >spk2utt
2.data/lang
生成lexicon
[character/word] [pronunciation]
例子:
早晨 z ao ch en
天气 t ian q i
先获取word-list
2.1去掉标点
2.2分词
找出所有的噪声表示:
cat text | grep -e '<.*>' | awk '{for(x=2;x<=NF;x++){printf("%s\n",$x)}}' | grep -e '<.*>' | sort -u
<FIL/>
<FIL/>
<NON/>
<NON/>
<NPS/>
<NPS/>
<SPK/>
<SPK/>
<STA/>
<FIL/>
<FIL/>^M
<NON/>
<NON/>^M
<NPS/>
<NPS/>^M
<SPK/>
<SPK/>^M
<STA/>
编码格式有问题,用dos2unix转换格式
dos2unix text
发现text中存在空行,需要找出空行,然后删除:
找空行,把空行前面的utt-id输出来:
cat text | gawk '/[A-Za-z0-9_]*\s+$/'>bad_sens.txt
删除空行:
grep -w -vf bad_sens.txt text>tmp_txt
接下来对tmp_txt进行分词:
remove_punc.py
# coding: utf-8
from zhon.hanzi import punctuation
from mmseg import seg_txt
import re
import sys
for line in sys.stdin:
#除去换行
line=line.strip('\n')
#去掉标点
no_puncs=re.sub(ur'[%s]+'% punctuation,'',line.decode('utf-8'))
no_puncs=no_puncs.encode('utf-8')
#分词
#将字符串按照空格转成list
content=no_puncs.split()
#第一个元素是utt-id
out_line=content[0]
#print utt_id
#对剩下的部分进行分词
for i in range(1,len(content)):
#遇到各种噪声的处理
if content[i] =="<FIL/>" or content[i]=="<NON/>" or content[i]=="<NPS/>" or content[i]=="<SPK/>" or content[i]=="<STA/>":
out_line+=" "+content[i]
continue
else:#对不是噪声的部分进行分词处理
for j in seg_txt(content[i]):
out_line+=" "+j
print out_line
将分词的结果存放在文件final_txt中
cat tmp_txt |python remove_punc.py >final_txt
生成word.list(把每一行句子(分词后的)的每一列输出,然后去重)
cat final_txt|awk '{for(i=2;i<=NF;i++){printf("%s\n",$i)}}'|sort -u>word.list
修复处理过程中删除了一些空行,导致之前的几个文件不对应
./utils/data/fix_data_dir.sh data/
把text,utt2spk,spk2utt,wav.scp放在data/all目录下
./utils/data/fix_data_dir.sh data/ #修复文件行数不一致的工具
./utils/data/subset_data_dir.sh data/all 1000 data/test #从data/all中抽取1000条数据,放在test中
构造测试集
原始的数据放在data/all下,测试集放在data/test下面
./utils/data/subset_data_dir.sh --speakers data/all/ 1000 data/test
构造训练集
首先获得test中的speak_id,然后在all/text中进行取反
cut -d ' ' -f1 data/test/spk2utt>speak_id.txt
grep -F -v -f speak_id.txt data/all/text> data/train/text
然后把原始的三个文件复制到train下面,进行修复即可
给训练集生成词汇表:
awk '{for(i=2;i<=NF;i++){print $i}}' data/train/text |grep -v '<.*>' |grep -v '[a-zA-Z]'|sort -u >data/local/words.txt
下载字典:
awk 'NR==144' kaldi/egs/hkust/s5/local/hkust_prepare_dict.sh
wget -P cedict http://www.mdbg.net/chindict/export/cedict/cedict_1_0_ts_utf-8_mdbg.txt.gz
解压:
gunzip XXXX
获取词典
modify_raw_dict.sh
#!/bin/bash
input=$1
cat $input| grep -v '#' | awk -F '/' '{print $1}' |\
perl -e '
while (<STDIN>) {
@A = split(" ", $_);
print $A[1];
for($n = 2; $n < @A; $n++) {
$A[$n] =~ s:\[?([a-zA-Z0-9\:]+)\]?:$1:;
$tmp = uc($A[$n]);
print " $tmp";
}
print "\n";
}
' | sort -k1 || exit 1;
exit 0;
./modify_raw_dict.sh data/local/cedict/cedict_1_0_ts_utf-8_mdbg.txt >data/local/zhongwen.dict
其实这个字典是有问题的,一般的词语是没有问题的,但是词典里面存在这种情况:
如果不做修改的话,words里面很多的词无法匹配获得读音,因为words里面已经不存在标点了,所以现在的任务是把这些长的词语按照标点符号分开。
pre_dict.py
# coding: utf-8
import sys
for line in sys.stdin:
line=line.strip('\n')
if "," in line:
content=line.split(' , ')
c1=content[0].split(',')
l=len(c1)-1
c2=c1[l]
index=c2.index(' ')
print c1[0]+" "+c2[index+1:]
for i in range(1,l):
print c1[i]+" "+content[i]
print c2[:index]+" "+content[l]
elif "、" in line:
content=line.split(' , ')
c1=content[0].split(',')
l=len(c1)-1
c2=c1[l]
index=c2.index(' ')
print c1[0]+" "+c2[index+1:]
for i in range(1,l):
print c1[i]+" "+content[i]
print c2[:index]+" "+content[l]
else:
print line
cat zhongwen.dic |python pre_dict.py
把之前的words.txt中的词在词典中找到
awk 'NR==FNR {dict[$0];next}($1 in dict)' data/local/words.txt data/local/zhongwen.dict >in_words.txt
把words.txt不在词典的要找到
awk 'NR==FNR {dict[$1];next} !($1 in dict)' data/local/zhongwen.dict data/local/words.txt >out_words.txt
会发现一个问题,in_words和out_words的总数大于之前的words.txt,这是因为在获取in_words的时候,是把words当字典,然后扫描zhongwen.dict,zhongwen.dict中的某一条在words中就输出,正是由于zhongwen.dict中存在多音字和声调的问题,比如“啊”这个字在zhongwen.dict中就有四条记录,对应四个读音声调
image.png
其实此时的in_words.txt就是lexicon
生成nonsilence_phones.txt
awk '{for(i=2;i<=NF;i++){print $i}}' lexicon |sort -u>data/local/dict/nonsilence_phones.txt
生成lang
建立四个文件
silence_phones.txt
echo 'SIL' >> data/local/dict/silence_phones.txt
nonsilence_phones.txt
extra_questions.txt
touch data/local/dict/extra_questions.txt
optional_silence.txt
echo 'SIL' >> data/local/dict/optional_silence.txt
lexicon.txt
paste -d ' ' noise_list data/local/dict/silence_phones.txt >>data/local/dict/lexicon
sort -u data/local/dict/lexicon >data/local/dict/lexicon.txt
echo '!SIL SIL' >>data/local/dict/lexicon.txt
运行:
./utils/prepare_lang.sh ~/Desktop/part3/data/local/dict/ '!SIL' ~/Desktop/part3/data/lang_tmp data/lang
提取mfcc
工具 steps/make_mfcc.sh
计算mfcc
compute-mfcc-feats
.scp文件只存放文件的路径,.ark文件存放文件的真实数据
eg:
compute-mfcc-feats scp:wwav.scp ark:1.ark
得到目标文件1.ark
是一个二进制文件
compute-mfcc-feats scp:wwav.scp ark,t:1.ark
得到的目标文件1.ark
是一个文本文件存放的是矩阵
计算这个矩阵的维度:
feat-to-dim ark:1.ark -
mfcc是啥???
并行提取train/test MFCC特征,CMVN
make_mfcc.sh使用例子
首先从test中选择100句
utils/data/subset_data_dir.sh data/test 100 data/foo
建立exp
文件夹,存放输出的log文件
mkdir -p exp
建立.conf
文件
vim conf/mfcc.conf
内容:
--use-energy=false
提取mfcc
./steps/make_mfcc.sh --mfcc-config conf/mfcc.conf data/foo exp/extract_mfcc mfcc
提取的mfcc就放在mfcc
文件夹中
.scp
文件可以直接打开查看,但是.ark
文件是二进制文件,无法打开,可以进行以下转换,转成txt格式copy-feats ark: raw_mfcc_foo.1.ark
//25:53
训练语言模型,ngram工具:srilm
~/kaldi/egs/hkust/s5/local/hkust_train_lms.sh
训练语言模型的一个例子:
cut -d' ' -f2- data/train/text >data/train/text_no_uttid #只能是文本,不能有utt_id
ngram-count -text data/train/text_no_uttid -order 3 -lm data/local/lm
训练monophone
未完待续。。。。