一个语音识别例子记录

2018-12-23  本文已影响0人  习惯了千姿百态

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

未完待续。。。。

上一篇下一篇

猜你喜欢

热点阅读