HTK英文大词汇连续语音识别

本文详述了使用HTK进行英文大词汇连续语音识别的完整步骤,包括预处理、训练、模型调整及测试。在训练过程中遇到了各种问题,如文件格式、发音词典匹配、音素提取等,并逐一解决。尽管识别率较低,但通过不断调试和优化,最终实现了模型的训练。
摘要由CSDN通过智能技术生成

最近实习,跑了一下htk book里面的前三章描述的例子。当然不是完全htk book里面的步骤,因为我有的数据集什么的都不一样。目标也不是一个小的语音拨号系统,而是英文的语音识别。当然了,最终结果出来了之后很低,还有很多过程要走。语音识别,肯定不是我这样小打小闹就可以的。

本文就主要记录我在训练过程中的步骤以及遇到的一些error。

一.已有文件
目前已经准备好的文件有一系列的flac文件还有字典trainprompts, 另外还有一个发音词典lexicon,里面的内容如下:
trainprompts :

2 103-1240-0001 THAT HAD ITS SOURCE AWAY BACK IN THE WOODS OF THE OLD CUTHBERT PLACE IT WAS REPUTED TO BE AN INTRICATE HEADLONG BROOK IN ITS EARLIER COURSE THROUGH THOSE WOODS      WITH DARK SECRETS OF POOL AND CASCADE BUT BY THE TIME IT REACHED LYNDE'S HOLLOW IT WAS A QUIET WELL CONDUCTED LITTLE STREAM
3 103-1240-0002 FOR NOT EVEN A BROOK COULD RUN PAST MISSUS RACHEL LYNDE'S DOOR WITHOUT DUE REGARD FOR DECENCY AND DECORUM IT PROBABLY WAS CONSCIOUS THAT MISSUS RACHEL WAS SITT      ING AT HER WINDOW KEEPING A SHARP EYE ON EVERYTHING THAT PASSED FROM BROOKS AND CHILDREN UP

lexicon :
2 A EY1 # 第一列是单词,后面是发音
3 A”S EY1 Z
4 A’BODY EY1 B AA2 D IY0
5 :A’COURT EY1 K AO2 R T
6 A’D EY1 D
7 A’GHA EY1 G AH0
8 A’GOIN EY1 G OY1 N
9 A’LL EY1 L

其中lexicon是直接给出的,而trainprompts和flac文件都分散在一个一个的小文件里面,需要先进行提取。其中trainprompts提取之后还得将他的路径放到每一行的最前面,至于为什么这样,我只看到所有的资料都是这样搞的,不知道为什么。。。弄好之后的截图是这样的: find . -name “*.txt” | xargs cat > trainprompts

2 /home/liuyan/train/SLR/103-1240-0001 THAT HAD ITS SOURCE AWAY BACK IN THE WOODS OF THE OLD CUTHBERT PLACE IT WAS REPUTED TO BE AN INTRICATE HEADLONG BROOK IN ITS EARLIER COURSE THROUGH THOSE WOODS      WITH DARK SECRETS OF POOL AND CASCADE BUT BY THE TIME IT REACHED LYNDE'S HOLLOW IT WAS A QUIET WELL CONDUCTED LITTLE STREAM
3 /home/liuyan/train/SLR/103-1240-0002 FOR NOT EVEN A BROOK COULD RUN PAST MISSUS RACHEL LYNDE'S DOOR WITHOUT DUE REGARD FOR DECENCY AND DECORUM IT PROBABLY WAS CONSCIOUS THAT MISSUS RACHEL WAS SITT      ING AT HER WINDOW KEEPING A SHARP EYE ON EVERYTHING THAT PASSED FROM BROOKS AND CHILDREN UP
4 /home/liuyan/train/SLR/103-1240-0003 AND THAT IF SHE NOTICED ANYTHING ODD OR OUT OF PLACE SHE WOULD NEVER REST UNTIL SHE HAD FERRETED OUT THE WHYS AND WHEREFORES THEREOF THERE ARE PLENTY OF PEOPLE      IN AVONLEA AND OUT OF IT WHO CAN ATTEND CLOSELY TO THEIR NEIGHBOR'S BUSINESS BY DINT OF NEGLECTING THEIR OWN

vim下使用替换命令就可以了:
:%s/^/TAB/g #每一行的行首添加一个TAB字符

每行的行首都添加一个字符串:%s/^/要插入的字符串

每行的行尾都添加一个字符串:%s/$/要插入的字符串

% 代表针对被编辑文件的每一行进行后续操作
$ 代表一行的结尾处
^ 代表一行的开头处

这些文件最开始我都是放在SLR文件夹里面的,这些文件是已知的,是在SLR网站上下载的,可以自行去下载下来。http://openslr.org/resources.php 。里面有很多SLR,具体是那一个我也不知很清楚,自己去找了。这些文件是老大帮我准备好的。

 lexicon还的加上下面的内容:

SENT-END []sil
SENT-START []sil
sil表示silence,静音,[]表示不输出任何东西.

之后在网上下载两个脚本文件prompts2wlist和prompts2mlf,之后会用到,本来这两个脚本文件会在HTKTutorial directory里面,但是我不知道这个东西在那里,所以在网上下载了两个文脚本。

二.单词trainprompts的加工

我们现在来分析一下我们有的两个文件lexicon和trainprompts,看上面的形式也知道,其中lexicon是单词的发音,lexicon里面的第一列是各个单词,后面的列都是单词的不同的发音。trainprompts文件则是单词文本,里面全部都是我们后面要训练的或者说可能识别到的单词,那这就有一个问题了,就是可能trainprompts里面的单词在lexicon里面没有发音,所以我们最开始需要做的事情就是去重新生成一个新的prompts,确保里面的单词在lexicon里面都有发音,也就是里面的单词都能在lexicon的第一列找到。

python脚本如下:

  #!/usr/bin/env python                                                                    
  # -*- coding: utf-8 -*-  

  file1 = open("train", "r").readlines()
  file2 = open("lexicontrain", "r").readlines()

  s = set([])
  for line2 in file2:
      words2 = line2.split()
      for word2 in words2:
          s.add(word2)

 # print s
 # print len(s)

 num = 0
 open("t","w").write("")    #清空train文件

 for line1 in file1:
     words1 = line1.split()
     count = 0
     for word1 in words1:
         if word1 in s:
             count = count + 1

     print count
     print len(words1)
     if count == (len(words1) - 1):
         num = num + 1
         open("t","a").write(line1)

 print num

很简单,就是两个文教操作而已,但是由于不会python,用了很长时间才完成。

三.flac文件转换为wav

接下来就要将flac文件转化成wav文件了,找了半天才找到一个对的命令:
flac -d ./flac/*.flac
我将上面的所有分散的flac拿出来存储在一个名叫flac的文件夹里面,上面的命令执行完之后在flac文件夹里面就生成了相应的wav文件,拿出来就好了。find ./LibriSpeech/ -name *.flac -exec cp {} ./flac/ \;

注意:上面的那个命令其实是不对的,虽然确实可以将flac文件转换为wav文件,但是在后面wav继续转换成mfc的时候就出问题了,报错说这个wav文件不是pcm编码格式的所以不行,然后我查找了很久才发现了一个新的方法就是使用ffmpeg命令ffmpeg -i in.flac out.wav

  #!/bin/bash

  for FILE in ./*.flac
  do
  ffmpeg -i "$FILE" "${FILE%.*}.wav";
  done

写成了这样的一个脚本,就最终完成了,好苦恼,这样的一个问题搞了一下午。。。

接下来生成wlist文件,使用下面的命令行:
perl scripts/prompts2wlist SLR/trainprompts config/wlist
这样就在config目录下生成了wlist文件。部分如下表:

3 ABANDONED
4 ABANDONING
5 ABANDONMENT
6 ABATED
7 ABATEMENT
8 ABATEMENTS
9 ABBE

这个文件里面有很多单词,大概几万个。

注意,需要在lexicon词典中添加:
1 SENT-END [] sil
2 SENT-START [] sil
这两句,然后按字典排序好就可以了。

然后就可以使用下面的命令,

HDMan -m -w ./config/wlist -g ./data/global.ded -n ./data/monophones1 -l ./dict/dlog ./dict/dict1 ./data/lexicon.txt 

得到音素文件monophones1,日志文件dlog,发音字典文件dict。其中需要在monophones1结尾添加一个sil。
为了避免在日志文件dlog里面有warning,在names和lexicon.txt的目录下建立文件names.ded和lexicon.txt.ded,内容为空就可以了。

monophones1生成:
注意:
上面的是按照书上的做法来的,但是其实应该是有错误的,不知道是方法的错误还是书上本身有错误。生成的monophones1是有问题的,用上面的方法我的monophones1只有40个单词,但其实发音因素是有70个的,加上添加的sp一共有71个。所以我就换了一种方法,直接根据lexcion词典来提取monophones1里面的音标,我们知道lexcion里面是所有单词的发音集合,其中每一行的第一个是单词,后面的都是它的发音,所以我们只要想办法将所有单词后面的发音都提取出来,然后排序去重就可以了。

这样的话,上面的wlist也不用了,我怀疑wlist那里可能有问题。现在不用这个东西了,哈哈。

不知道怎么弄,应该是要写脚本的,但是我现在还不会脚本,所以就瞎搞用了这样一个命令cut。

cat lexicon |cut -d ' ' -f 2-10        #可以提取出mono文件里面的第2-10列
cat lexicon |cut -d ' ' -f 1           #可以提取出mono文件里面的第1列

就是用的上面的命令来生成mono的,反正是瞎搞。最终monoptones后面再添加一个sp,一共71个音标。

PS : 直接这样perl scripts/prompts2wlist data/lexcion.txt monophones1
也可以生成有70个单词的 monophones1,应该是下载的prompts2wlist脚本的原因,不管怎样,反正monophones1是有了。

通过下面的命令生成单词级注音文件words.mlf:

perl ./scripts/prompts2mlf words.mlf ./SLR/trainprompts 

然后通过下面的命令生成单词级注音文件phones.mlf:

HLEd -T 1 -l '*' -d ./dict/dict1 -i phones.mlf ./data/mkphones0.led ./labels/words.mlf

因为上面的过程可能有错误,所以这里就不用生成的dict1文件了,直接使用lexcion.txt就可以了。

HLEd -T 1 -l '*' -d ./data/lexicon.txt -i phones.mlf ./data/mkphones0.led ./labels/words.mlf

特征提取配置文件wav2mfc.config

# Coding parameter
    TARGETKIND = MFCC_0_D_A
    TARGETRATE = 100000.0
    SAVECOMPRESSED = T
    SAVEWITHCRC = T
    WINDOWSIZE = 250000.0
    USEHAMMING = T
    PREEMCOEF = 0.97
    NUMCHANS = 26
    CEPLIFTER = 22
    NUMCEPS = 12
    ENORMALISE = F
    SOURCEFORMAT = wav         #需要加上这一句,表明是从wav转化成mac文件的

现在需要自己去生成codetr.scp文件,由wav生成mfc的时候需要用到。
首先find /home/liuyan/train/wav/ -path "*.wav" > codetr0.scp
这时候生成了文件codetr0.scp,里面存储的是wav文件的绝对路径,如下:

   2 /home/liuyan/train/wav/103-1240-0001.wav
   3 /home/liuyan/train/wav/103-1240-0002.wav
   4 /home/liuyan/train/wav/103-1240-0003.wav
   5 /home/liuyan/train/wav/103-1240-0004.wav
   6 /home/liuyan/train/wav/103-1240-0005.wav
   7 /home/liuyan/train/wav/103-1240-0006.wav
   8 /home/liuyan/train/wav/103-1240-0007.wav
   9 /home/liuyan/train/wav/103-1240-0008.wav
  10 /home/liuyan/train/wav/103-1240-0009.wav

然后想办法生成文件codetr1.scp,里面的内容如下:

   2 /home/liuyan/train/mfc/103-1240-0001.mfc
   3 /home/liuyan/train/mfc/103-1240-0002.mfc
   4 /home/liuyan/train/mfc/103-1240-0003.mfc
   5 /home/liuyan/train/mfc/103-1240-0004.mfc
   6 /home/liuyan/train/mfc/103-1240-0005.mfc
   7 /home/liuyan/train/mfc/103-1240-0006.mfc
   8 /home/liuyan/train/mfc/103-1240-0007.mfc
   9 /home/liuyan/train/mfc/103-1240-0008.mfc
  10 /home/liuyan/train/mfc/103-1240-0009.mfc

然后使用这样的命令 diff codetr0.scp codetr1.scp -y > codetr.scp 比较他么的不同输出到同一个文件夹里面,瞎搞一下就成了我们需要的格式了,如下:

2 /home/liuyan/train/wav/103-1240-0001.wav                /home/liuyan/train/mfc/103-1240-0001.mfc
   3 /home/liuyan/train/wav/103-1240-0002.wav                /home/liuyan/train/mfc/103-1240-0002.mfc
   4 /home/liuyan/train/wav/103-1240-0003.wav                /home/liuyan/train/mfc/103-1240-0003.mfc
   5 /home/liuyan/train/wav/103-1240-0004.wav                /home/liuyan/train/mfc/103-1240-0004.mfc
   6 /home/liuyan/train/wav/103-1240-0005.wav                /home/liuyan/train/mfc/103-1240-0005.mfc
   7 /home/liuyan/train/wav/103-1240-0006.wav                /home/liuyan/train/mfc/103-1240-0006.mfc
   8 /home/liuyan/train/wav/103-1240-0007.wav                /home/liuyan/train/mfc/103-1240-0007.mfc
   9 /home/liuyan/train/wav/103-1240-0008.wav                /home/liuyan/train/mfc/103-1240-0008.mfc
  10 /home/liuyan/train/wav/103-1240-0009.wav                /home/liuyan/train/mfc/103-1240-0009.mfc

PS : 还是要学习一门脚本语言,不然这样用shell命令瞎搞还是很烦人的,很多命令需要自己在那里查很久,决定学习python了。

下面使用命令:

HCopy -T 1 -C ./data/wav2mfc.config -S ./config/codetr.scp

就可以在对应的文件里面生成mfc文件了。

定义一个原始的HMM模型文件proto如下:

1 ~o <VecSize> 39 <MFCC_0_D_A>                                                                                                                                                                         
  2 ~h "proto"
  3 <BeginHMM>
  4   <NumStates> 5
  5   <State> 2
  6     <Mean> 39
  7       0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
  8     <Variance> 39
  9       1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值