Kaldi数据准备:
需要准备四个文件
1. wav.scp [utt-id] [wav-path] e.g. sen_1 /home/train01_data/sen_1.wav
2. text [utt-id] [text-content] e.g. sen_1 今天天气很好
3. utt2spk [utt-id] [spk-id] e.g. sen_1 speaker_1
4. spk2utt [spk-id] [utt-id] e.g. speaker_1 sen_1
Kaldi有工具,当你已经有文件3时,可自动生成4。
在生成这些文件的过程中,一般会用到awk(适用于按行处理的文件)、Shell、Perl、Python等等工具。
一般公开的或者购买的语音数据集格式一般会所有的语音数据按人分开在一个目录,语音对应的文字文件在一个目录。
首先统计一下共有多少语音(ps:具体过程看不懂问题不大哈,因为没有特别仔细的整理):
find ./wav/ -iname "*.wav" | wc -l
不知道为啥是-iname,而不是-name,希望知道的大佬告知下。
将所有语音的路径放入wav.scp.temp(文件1)。
find /home/train02/Data/guangzhou/King-Tem-051/Data/iOS/Wav -iname '*.wav' > wav.scp.temp
只将音频说话人名字和会话id提取出来:e.g. Speaker_9902_220
#利用wak将文件路径按/划分,取出最后两列,并将最后第二列的Speaker替换为Speaker_,最后一列中部分字符.wav删除掉
cat wav.scp.temp | awk F '/' '{printf("%s_%s\n",$(NF-1),$NF)}' | sed 's|.wav||' |
sed 's|Speaker|Speaker_|' > wav_id
将上述wav_id和wav.scp.temp按行合并,即可得到最终文件1。
#如果想查看合并效果,可用 paste -d' ' wav_id wav.scp.temp | head -n 1
paste -d' ' wav_id wav.scp.temp > wav.scp
当文本文件编码不统一时,更换编码类型:
#对目录中的所有文件进行循环更改文件编码类型
for x in local/data/script/*; do y=`echo $x | sed 's|script|script_utf8'`; iconv -f UTF-16LE -t UTF-8 $x > $y; done
数据集给出的文本文件奇数行为本应读的句子,偶数行为实际读出句子,所以需要将偶数行进行提取。(NR是指当前行一共有多少列)
awk 'NR % 2 == 0' local/data/scrip_utf8/Speaker7305.txt > tmp.txt
然后提取行号:
#将奇数行第一列放入文件中
awk 'NR % 2 != 0 {printf("%s\n", $1)}' local/data/script_utf8/Speaker7305.txt > sen_id_7305.txt
将说话人id和每个人的语句对应起来:
#!/bin/bash
speak_id=$1
string=`echo $speak_id | sed 's|.txt||' | sed 's|Speaker|Speaker_|'`
awk -v spk=$string 'NR % 2 != 0 {printf("%s_%s\n", spk, $1)}' $speak_id
exit 0;
下面这个语句干啥用的不记得了,cut是截取字符串,-d用来定义分隔符,默认为tab键,-f表示需要取得哪个字段。
cut -d ' ' -f 1 text | awk -F '_' '{printf($0 " " $1_$2 "\n")}'
下面开始介绍Kaldi的两个常用工具箱steps和utils,他这里是吧样例wsj数据集中的工具设置为默认环境变量。
steps -> .../kaldi/egs/wsj/s5/steps
utils -> .../kaldi/egs/wsj/s5/utils
利用工具将文件3转成文件4。
./utilus/utt2spk_to_spk2utt.pl utt2spk > spk2utt
在完成这些操作后,还需要将所有句子分词(用开源的工具HTK?,这个数据集文本都是一句一句的,没有分词),还需要准备一个发音词典(数据集自带? 词所对应的发音),同时需要查下是否所有词在发音词典都有,没有就叫未登录词。
Kaldi数据准备之延续 lang/data
Lexicon语音词典(把文字或词组转成它最小的单位,就是一个音素),跟发音有关,汉语就是声韵母,英语就是音标。例如:
[character/word] [pronunciation]
早晨:z ao ch en
天气 t i an q i
把文本统计一下,包含多少词,生成一个word_list,再到网上找一个语音词典,或者你买的。把所有出现的词在词典里查,找到发音,生成一个lexicon的文件。针对这个数据集具体步骤为:
1、先将文本中标点去掉,然后分词统计为word_list。(你直接写个小脚本在某个集合中去匹配,这样子太粗糙,可能匹配到不是最好的,如你,你好,你是谁,你是。可以去网上找分词工具。)
这里用的是开源工具,Python zhon。
#!/usr/bin/env python
import re
import sys
from zhon.hanzi import punctuation
for line in sys.stdin:
line = line.strip('\n')
print re.sub(ur'[%s]+' %punctuation, '', line.decode('utf-8'))
Python代码里是标准输入:
cat text | head -n 10 | python remove_punctuation.py
然后安装分词工具mmseg(是kaldi样例某一个中文数据集用的分词工具)
from mmseg import seg_txt
for w in seg_txt(r"我是李国强我家在东北我有三座金山"):
print w
在分词的过程中要处理一些无法识别的噪声数据,如<noise>,<non>等等。需要将文本中的这些去掉,在去掉这些的过程中发现(首先统计出来有哪些噪声数据),结果有同样的表示如<noise><noise>,但在vim中发现有一个后面加了^M,最后发现是win下面的文件在linux打开所带来的,于是用dos2unix命令将文件格式转换为linux下。
发现有些语句是空行,要把他们找出来
cat text | gawk '/[A-Za-z0-9_]*\s+$/'
# ^除在[]中使用,否则为匹配开头,$是匹配结尾
将text文件中的所有非空行列出来
grep -w -vf bad_sens.txt text | wc -1
# -w是指只能精准匹配
# -f是指以a.txt中每一行为关键字,查找b.txt中匹配的行
# -v是指显示不匹配的内容
当所有都处理完毕时,生成word_list
awk '{for(i=2; i<=NF; i++) printf("%s\n", &i)} text | sort -u > word_list'