Day17 - 语音辨识神级工具-Kaldi part2

首先介绍的是发音词典处理,我们必须先准备一份发音词典(lexicon),格式会长得像以下的样子。左边就是词,右边则是这个词对应的拼音,不同的拼音系统会产生出不同的拼音结果(ex:Formosa Phonetic Alphabet(ForPA)、汉语拼音、国际音标IPA等)

#lexicon.txt
一两百元 i:1 l j A: N3 p aI3 H A: n2
一两百年 i:1 l j A: N3 p aI3 n j A: n2
一两百万 i:1 l j A: N3 p aI3 w A: n4
一两万 i:1 l j A: N3 w A: n4
一两万元 i:1 l j A: N3 w A: n4 H A: n2
一两周 i:1 l j A: N3 ttss oU1
一两只 i:1 l j A: N3 ttss1
一两项 i:1 l j A: N3 s6 j A: N4
一两颗 i:1 l j A: N3 k_h ax1
一两点 i:4 l j A: N3 t j A: n3

而我们可以使用 local/prepare_dict.sh 这一个script 来处理 lexicon

#local/prepare_dict.sh
source_dir=<lexicon.txt path>
dict_dir=data/local/dict
rm -rf $dict_dir
mkdir -p $dict_dir

rm -f $dict_dir/lexicon.txt
touch $dict_dir/lexicon.txt
cat $source_dir/lexicon.txt > $dict_dir/lexicon.txt
echo "<SIL> SIL"	>> $dict_dir/lexicon.txt

#
# define silence phone
#
rm -f $dict_dir/silence_phones.txt
touch $dict_dir/silence_phones.txt

echo "SIL"	> $dict_dir/silence_phones.txt

#
# find nonsilence phones
#
rm -f $dict_dir/nonsilence_phones.txt
touch $dict_dir/nonsilence_phones.txt

cat $source_dir/lexicon.txt | grep -v -F -f $dict_dir/silence_phones.txt | \
    perl -ane 'print join("\n", @F[1..$#F]) . "\n"; '  | \
    sort -u > $dict_dir/nonsilence_phones.txt

#
# add optional silence phones
#

rm -f $dict_dir/optional_silence.txt
touch $dict_dir/optional_silence.txt
echo "SIL"	> $dict_dir/optional_silence.txt

#
# extra questions
#
rm -f $dict_dir/extra_questions.txt
touch $dict_dir/extra_questions.txt
cat $dict_dir/silence_phones.txt    | awk '{printf("%s ", $1);} END{printf "\n";}'  > $dict_dir/extra_questions.txt || exit 1;
cat $dict_dir/nonsilence_phones.txt | awk '{printf("%s ", $1);} END{printf "\n";}' >> $dict_dir/extra_questions.txt || exit 1;

echo "Dictionary preparation succeeded"
exit 0;

执行这个script後会在 data/local/dict 下产生 lexicon.txt 、optional_silence.txt、nonsilence_phones.txt、silence_phones.txt 这四个档案

接下来是资料集(语料库)的部分,要能够进到kaldi模型中训练的话必须依照kaldi的格式准备出一些档案,其中以下三项是最为重要的:

  • wav.scp: 此档案描述的是每一个句子对应到的音档路径,格式如下
    <utterance-id> <wav-file-path>
    虽然定义上是句子的id,但实际上kaldi并没有明确的定义id的格式,所以如果句子没有另外的id的话直接用档名会 比较方便。
  • utt2spk: 此档案描述的是每一个句子对应的语者(说话的人),格式如下
    <utterance-id> <speaker-id>
    speaker-id 可以简单地用数字来表示。
  • text: 此档案描述的是每一个句子的内容,格式如下
    <utterance-id <transcription>

这三个档案则可以透过local/prepare_data.sh产生,其他的档案像是 spk2utt 可以直接透过 kaldi内建的工具进行转换
utils/utt2spk_to_spk2utt.pl data/train/utt2spk > data/train/spk2utt
spk2gender 则是要看训练的过程中会不会用到性别的资讯。

local/prepare_data.sh 参考程序如下

# local/prepare_data.sh
#!/bin/bash

set -e -o pipefail

train_dir=<train-data-path>
eval_dir=NER-Trs-Vol1-Eval

. ./path.sh
. parse_options.sh

for x in $train_dir ; do
  if [ ! -d "$x" ] ; then
    echo >&2 "The directory $x does not exist"
  fi
done

if [ -z "$(command -v dos2unix 2>/dev/null)" ]; then
    echo "dos2unix not found on PATH. Please install it manually."
    exit 1;
fi

# have to remvoe previous files to avoid filtering speakers according to cmvn.scp and feats.scp
rm -rf   data/all data/train data/test data/eval data/local/train
mkdir -p data/all data/train data/test data/eval data/local/train


# make utt2spk, wav.scp and text
find $train_dir -name *.wav -exec sh -c 'x={}; y=$(basename -s .wav $x); printf "%s %s\n"     $y $y' \; | dos2unix > data/all/utt2spk
find $train_dir -name *.wav -exec sh -c 'x={}; y=$(basename -s .wav $x); printf "%s %s\n"     $y $x' \; | dos2unix > data/all/wav.scp
find $train_dir -name *.txt -exec sh -c 'x={}; y=$(basename -s .txt $x); printf "%s " $y; cat $x'    \; | dos2unix > data/all/text

# fix_data_dir.sh fixes common mistakes (unsorted entries in wav.scp,
# duplicate entries and so on). Also, it regenerates the spk2utt from
# utt2spk
utils/fix_data_dir.sh data/all

echo "Preparing train and test data"
# test set: JZ, GJ, KX, YX
grep -E "(JZ|GJ|KX|YX)_" data/all/utt2spk | awk '{print $1}' > data/all/cv.spk
utils/subset_data_dir_tr_cv.sh --cv-spk-list data/all/cv.spk data/all data/train data/test

# for LM training
echo "cp data/train/text data/local/train/text for language model training"
cat data/train/text | awk '{$1=""}1;' | awk '{$1=$1}1;' > data/local/train/text

# preparing EVAL set.
find $eval_dir     -name *.wav -exec sh -c 'x={}; y=$(basename -s .wav $x); printf "%s %s\n"     $y $y' \; | dos2unix > data/eval/utt2spk
find $eval_dir     -name *.wav -exec sh -c 'x={}; y=$(basename -s .wav $x); printf "%s %s\n"     $y $x' \; | dos2unix > data/eval/wav.scp
find $eval_dir -name *.txt -exec sh -c 'x={}; y=$(basename -s .txt $x); printf "%s " $y; cat $x'    \; | dos2unix > data/eval/text
utils/fix_data_dir.sh data/eval

echo "Data preparation completed."
exit 0;

明天将会继续介绍神经网路模型训练的部分。

参考资料:

http://kaldi-asr.org/doc/data_prep.html


<<:  好想中乐透啊,Ruby 30 天刷题修行篇第十四话

>>:  【Side Project】 点菜单功能实作 - 前台资料传到後台

Angular 深入浅出三十天:表单与测试 Day16 - Template Driven Forms vs Reactive Forms

这段期间,我们用 Template Driven Forms 与 Reactive Forms 各...

TypeScript 能手养成之旅 Day 6 物件型别-基础物件型别

前言 今天要来介绍物件型别里面的基础物件,或许会想说那除了基础物件型别以外,不是还有 TypeScr...

企业资料通讯Week6 (3) | Transport Layer_婴儿食品版

现在进入了传输层,是OSI(Open Systems Interconnection )模型的第四层...

Day18 React-Router(三)路由跳转

设置好route後,使用react-router-dom提供的方法,在画面上呈现连结跟操作,来让使用...

22 准备完成後跳转到游戏页面

两个人都准备好的时候,要转到游戏画面 我来把准备画面跟游戏分开好了 这样比较不会什麽都塞在同一个 l...