음성인식모델로 음성합성 데이터 만들기 (kaldi 음성 인식 모델 환경 구현)

예전에  multi-speaker-tacotron 을 가지고 음성합성 개발 환경을 구현하는 방법을 소개한적이 있었습니다.

딥러닝 음성합성 multi-speaker-tacotron(tacotron+deepvoice)설치 및 사용법

 

처음에 https://github.com/carpedm20/multi-speaker-tacotron-tensorflow

에 소개된 가이드대로 구글 STT 를 통해 음성에 대한 text 를 자동 인식 시켰는데, 그 결과 정확도가
워낙 좋지 않아 처음에는 재대로 들리는 음성 자체를 얻을 수가 없었습니다.

그래서 그다마 정확도가 높았던 특정 길이 문장 데이터만 선별해서 학습을 하고, 이를 통한 결과로 학습에 사용했던 유사 길이의 문장들을 다시 음성으로 합성하여 학습데이터를 보충하면서 나름 효과를 보긴 했지만,

결국은 최종 원했던 성능의 TTS를 만들기 위해서는 정확하고, 가급적 많은 학습데이터를 확보하는 것이
중요했습니다.

애초 multi-speaker-tacotron-tensorflow deploy 를 시작했던 이유가 개발자께서 세메나에 언급했던
“유인나 목소리로 책 읽어주기” 를 구현해보자는 거였고, 이를 위해 기존 유튜브등에서 유인나 오디오북
음성 구하고, 책 구매하여 열심히 매주말마다 노가다로 audio/text 매핑 작업을 3000~4000 개 정도

학습데이터를 만들어서 이전 글에 소개한 샘플 정도의 결과를 얻을 수 있었습니다.

하지만, 다양하고 복잡한 어휘로 구성된 문장들을 넣었을때 ( 시, 독립선언문, 성경 등등.. ) 많은 한계가

존재하였습니다. 역시 결론은 정확하고 아주 많은 학습데이터가 답이였습니다.

1~2 달 동안 “도 닦는 마음”으로 주말마다 수작업을 하다가 음성 인식 모델로 정확한 TEXT를 뽑아보는데
도전을 하게 되었습니다. 최초 구글 STT 에 워낙 실망을 한터라 이 작업은 크게 생각도 안했었는데
우연한 기회에 음성인식모델인 Kaldi 를 deploy 하고, 음성합성에 사용했던 손석희 데이터를 가지고
음성인식 모델 학습을 시키니 해당 화자의 목소리는 거의 95% 이상의 정확도를 나타내었습니다.
(똑같은 데이터를 구글 STT 에 돌렸을때 70~80% 수준이였는데..)

음성합성과 음성인식 모두 학습데이터를 생성하기 위해 음성과 Text 데이터가 필요한데

일반적으로 범용적인 음성인식기를 만들기 여러명의 화자의 데이터가 필요하지만, 특정인의 음성 합성을 위한 TEXT 데이터를 얻기 위해서는 해당 화자의 음성/텍스트 데이터가 (1000개)정도만 있어도 이것으로 음성인식
학습을 시킨 결과로 훌륭한 STT 결과를 얻을 수 있었습니다.

최종적으로 kaldi 라는 음성인식 모델에 음성합성 학습용으로 만들었던 4000개 정도의 유인나 오디오북 데이터로 음성인식 학습을 시킨 후,
인터넷에서 확보 가능한 모든 유인나 오디오북 음성의 TEXT 를 자동으로 생성하여, 총 30000개 이상의 학습데이터를 만들 수 있었습니다.

아래는 학습 결과로 만든 음성 합성기에 성경책 창세기 부분을 통째로 입력하여 생성한 결과의 일부 입니다.

[유인나 오디오북 음성 합성 결과-성경 창세기 전반부]

특정 화자의 음성, 텍스트 데이터를 일부(N백개~천개정도)가지고 있을 경우, 범용 음성인식기는 아니지만,
해당 화자의 음성 인식률은 충분히 확보 가능하다는 것을 확인하였고, 이를 통해 더 많은 학습데이터 확보가 가능 하다는 것을 경험하였습니다.

아래는 유인나나 손석희 목소리 인식에 사용했던 한국어 음성인식 모델인 kaldi (kaldi-zeroth project)를
deploy 하면서 kaldi 설치 및 학습 과정을 정리했던 내용입니다. 적은 노가다로 많은 음성합성 데이터를 얻고자 하시는 여러분들께서 참고하시면 도움이 되실듯 합니다.

 

=====================================================================================

KALDI 음성 인식 개발 환경 구현하기

작성자 : 서진우 (alang@clunix.com)

운영체제 버전 : CentOS 7.x (g++ 버전은 4.8.x)
Python 버전 : python 3.6.1

 

// 운영체제 레벨에서 필요한 라이브러리나 유틸 패키지를 설치 한다.

# yum install atlas atlas-devel flac sox unzip parallel curl

// 사용하고자 하는 python 환경 설정 적용하시고, 필요한 python package module 을 설치합니다.

# source /APP/DeepLn/profile.d/python36.sh

# python -m pip install JPype1-py3

;; python 2.7 일 경우 pip install JPype1

python -m pip install konlpy
python -m pip install morfessor

// kaldi 소스를 다운 받습니다.

# mkdir -p /APP/DeepLn

# cd /APP/DeepLn

# git clone https://github.com/kaldi-asr/kaldi.git

# mv kaldi kaldi-5.3

# cd kaldi-5.3/tools
# ./extras/check_dependencies.sh
# ./extras/check_dependencies.sh: all OK.

// kaldi 의 기본 python 버전은 2.7 임. 기본 python 버전을 3.x 변경하고 싶은 경우

# touch /APP/DeepLn/kaldi-5.3/tools/python/.use_default_python

# make -j 4

kaldi 에 필요한 tools 을 자동으로 다운 받고 compile 한다. 다만,
srilm 의 경우 라이선스 문제가 있어 직접 다운로드를 받아 설치해야 한다.

http://www.speech.sri.com/projects/srilm/download.html

# cp srilm-1.7.2.tar.gz ~kaldi/tools

# cd ~kaldi/tools
# mv srilm-1.7.2.tar.gz srilm.tgz

# ./install_srilm.sh

# git clone https://github.com/irstlm-team/irstlm.git
# tar czvf irstlm.tgz irstlm/
# rm -rf irstlm/

# extras/install_irstlm.sh

환경 설정 profile 생성

# vi env.sh
———————————————–
export PATH=/APP/DeepLn/kaldi-5.3/tools/python:${PATH}
export IRSTLM=/APP/DeepLn/kaldi-5.3/tools/irstlm
export PATH=${PATH}:${IRSTLM}/bin
export LIBLBFGS=/APP/DeepLn/kaldi-5.3/tools/liblbfgs-1.10
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}:${LIBLBFGS}/lib/.libs
export SRILM=/APP/DeepLn/kaldi-5.3/tools/srilm
export PATH=${PATH}:${SRILM}/bin:${SRILM}/bin/i686-m64

##추가
export PATH=${PATH}:/APP/DeepLn/kaldi-5.3/tools/openfst-1.6.5/bin
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}:/APP/DeepLn/kaldi-5.3/tools/openfst-1.6.5/lib
————————————————-

cp env.sh /APP/DeepLn/profile.d/kaldi_env.sh

source env.sh

# cd ../src

// 사용할 cuda 버전과 맞아야 함.
./configure –shared –cudatk-dir=/usr/local/cuda-<version>

vi kaldi.mk
//debug level을 변화
-g O0 -DKALDI_PARANOID”를 enable 하면 가장 디버깅하기 쉬운 바이너리가 생성
-O0를 -O1로 바꾸면 디버깅이 가능하면서도 빠른 속도의 바이너리가 생성
“-g -O0 -DKALDI_PARANOID” 옵션은 디버깅은 되지 않지만 더 속도가 빠름
“-g -O0 -DKALDI_PARANOID”를 “-O2 -DNDEBUG”나 “-O3 -DNDEBUG”로

//정밀도 변경

결과의 정밀성을 위해 double precision으로 바꾸고 싶으면, -DKALDI_DOUBLEPRECISION=0 옵션을 1

//경고 감춤
OpenFst 코드에서 signed-unsigned 비교 경고를 내는데, CXXFLAGS에 -Wno-sign-compare를 추가

make clean
make depend -j 2
make -j 2

// valgrind를 통해 테스트를 실행하여 메모리 누수를 확인
make valgrind

// cuda memory 누수 확인
make cudavalgrind

 

// yesno 테스트 (기본 테스트)

kaldi 측에서 튜토리얼 용도로 ‘yes’와 ‘no’만 구분하는 음성인식 예제를 제공한다.
DB도 따로 준비할 필요 없이 인식 실험 스크립트를 실행하면 DB 다운로드를 자동으로
진행하여 언어모델을 생성히고, 음향모델 생성, 인식 실험까지 진행한다.

cd ~kaldi/egs
cd yesno
tree
———-
.
|– README.txt
|– s5
| |– conf
| | |– mfcc.conf
| | `– topo_orig.proto
| |– input
| | |– lexicon.txt
| | |– lexicon_nosil.txt
| | |– phones.txt
| | `– task.arpabo
| |– local
| | |– create_yesno_txt.pl
| | |– create_yesno_wav_scp.pl
| | |– create_yesno_waves_test_train.pl
| | |– prepare_data.sh
| | |– prepare_dict.sh
| | |– prepare_lm.sh
| | `– score.sh -> ../steps/score_kaldi.sh
| |– path.sh
| |– run.sh
| |– steps -> ../../wsj/s5/steps
| `– utils -> ../../wsj/s5/utils
`– tree_1.txt

6 directories, 17 files
—-

cd s5
./run.sh

.
.
local/score.sh: scoring with word insertion penalty=0.0,0.5,1.0
%WER 0.00 [ 0 / 232, 0 ins, 0 del, 0 sub ] exp/mono0a/decode_test_yesno/wer_10_0.0

 

// 홈디렉토리에서 작업하기

kaldi 의 egs에 있는 기본 example 을 이용할 경우 예제 별 실행 scripts 가
대부분 kaldi 설치 경로를 기존으로 상대 경로로 지정되어 있다.

만일 root 권한이 없이 관리자가 설치한 kaldi 를 이용해야 하는 경우 자신의 홈디렉토리에 작업 모델을
놓고, 몇가지 환경을 맞춰야 한다.

mkdir -p $HOME/kaldi_example/egs

cd kaldi_example
ln -sf /APP/DeepLn/kaldi/tools .
ln -sf /APP/DeepLn/kaldi/src .
cp -a /APP/DeepLn/kaldi/egs/yesno egs

cd egs/yesno/s5
ln -sf /APP/DeepLn/kaldi/egs/wsj/s5/steps steps
ln -sf /APP/DeepLn/kaldi/egs/wsj/s5/utils utils

sh run.sh

// 다른 예제 실습 –  small_krs

자세한 설명은..
https://hyungwonsnotebook.blogspot.kr/2017/07/kaldi-tutorial-for-korean-model-part-1.html

/home 밑에 small_krs.zip 데이터파일 download ..
https://drive.google.com/open?id=0B9lwe_GFwe2oY196NUJ4NFlPb0k

cd /home/alang
unzip small_krs.zip

# cd $HOME/kaldi_example/egs

# git clone https://github.com/hyung8758/kaldi_tutorial

# cd kaldi_tutorial/
# mkdir generated/

# local/krs_prep_data.sh /home/small_krs/test/ generated/
# ls generated
segments spk2utt text textraw utt2spk wav.scp

;; 데이터 디렉토리 구조는는 아래와 같아야함.

data_dir/train/<화자>/<wav파일>

 

# vi run.sh
###
kaldi=/APP/DeepLn/kaldi-5.3
source=/home/alang/kaldi_example/small_krs
.
.
### Number of jobs.
# 화자수에 따라 결정
# small_krs 는 화자수가 2명밖에 없는 작은 모델임.
train_nj=2
decode_nj=2

### CMD
train_cmd=utils/run.pl
decode_cmd=utils/run.pl
#train_cmd=utils/queue.pl
#decode_cmd=utils/queue.pl

### train
train_mono=1
train_tri1=1
train_tri2=1
train_tri3=1
train_dnn=0 -> dnn 적용할려면 1

114 번째줄 ..

. path.sh $kaldi
change to
. ./path.sh $kaldi

# sh run.sh

정상적으로 완료되면 아래와 같이 종료된다.
.
.

steps/decode.sh –scoring-opts –num-threads 1 –skip-scoring false –acwt 0.083333 –nj 2 –cmd utils/run.pl –beam 10.0 –model exp/tri3/final.alimdl –max-active 2000 exp/tri3/graph data/train exp/tri3/decode.si
decode.sh: feature type is lda
local/score.sh –cmd utils/run.pl data/train exp/tri3/graph exp/tri3/decode.si
local/score.sh: scoring with word insertion penalty=0.0,0.5,1.0
steps/decode_fmllr.sh: feature type is lda
steps/decode_fmllr.sh: getting first-pass fMLLR transforms.
steps/decode_fmllr.sh: doing main lattice generation phase
steps/decode_fmllr.sh: estimating fMLLR transforms a second time.
steps/decode_fmllr.sh: doing a final pass of acoustic rescoring.
local/score.sh –cmd utils/run.pl data/train exp/tri3/graph exp/tri3/decode
local/score.sh: scoring with word insertion penalty=0.0,0.5,1.0
END TIME: (수)
PROCESS TIME: linux 00:01:26 sec
======================================================================
RESULTS
======================================================================
Displaying results
Displaying results
result.txt is newly generated in log.
Reporting results…
RESULT REPORT ON… 2019. 05. 08. (수) 16:08:48 KST

TRIPHONE3 (LDA + MLLT + SAT)
======================================================================

DECODE
– BEST : WER 0.28 [ 3 / 1082, 0 ins, 2 del, 1 sub ]
– PATH : exp/tri3/decode/wer_15_0.0

======================================================================

결과는 exp 디렉토리 내에 저장된다.

일단 small_krs 데이터의 경우 데이터가 너무 작아서 gpu 나 후속 decoding 작업들을 모두 수행하기에
한계가 있음.

 

아래는 음성 인식 학습을 완료한 결과로 음성 인식기를 만들때 필요한 decoder 생성 연습을 할때 사용한
예제입니다.

// voxforge 예제 테스트 하기

$ cp <kaldi_path>/egs/voxforge $HOME/kadi_example/egs
$ cd $HOME/kadi_example/egs/voxforge
$ vi path.sh

export DATA_ROOT=”$HOME/kadi_example/egs/voxforge/s5/voxforge”

sh path.sh

mkdir $HOME/kadi_example/egs/voxforge/s5/voxforge
./getdata.sh

du -sh voxforge/
25G voxforge/

which readlink

cd /APP/DeepLn/kaldi-5.3/toos
./extras/install_sequitur.sh

cd ~/egs/voxforge $HOME/kadi_example/egs/voxforge
vi ./local/voxforge_prepare_dict.sh
sequitur=$KALDI_ROOT/tools/sequitur-g2p

vi cmd.sh

export train_cmd=”run.pl –mem 2G”
export decode_cmd=”run.pl –mem 4G”
export mkgraph_cmd=”run.pl –mem 8G”

./path.sh && ./run.sh

 

최종 특정화자의 음성 인식 학습에 사용한 모델인 kaldi-zeroth 입니다.

https://github.com/goodatlas/zeroth

한국어 음성인식 프로젝트로 유명하더군요.
// kaldi-zeroth 테스트

$ cp -a $KALDI_ROOT/egs/zeroth_korean .
$ cd zeroth_korean/s5
$ mkdir zeroth_db
$ cd zeroth_db
$ wget https://storage.googleapis.com/zeroth_project/zeroth_korean.tar.gz .
$ tar xzvf zeroth_korean.tar.gz

$ mkdir ../data/local/lm -p
$ mv zeroth* ../data/local/lm

$ cd ..

$ ln -sf /APP/DeepLn/kaldi-5.3/egs/wsj/s5/steps .
$ ln -sf /APP/DeepLn/kaldi-5.3/egs/wsj/s5/utils .

$ vi path.sh

// 전처리 과정에서 python3 을 사용함.

export KALDI_ROOT=/APP/DeepLn/kaldi-5.3
[ -f $KALDI_ROOT/tools/env.sh ] && . $KALDI_ROOT/tools/env.sh

vi run.sh

db_dir=<path>/zeroth_korean/s5/zeroth_db
.
# 아래주석
#if [ $stage -le 0 ]; then
# download the data.
# local/download_and_untar.sh $db_dir
#fi

zeroth 는 기본적으로 GE스케줄링 분산처리(queue.pl)로 작업이 수행된다.
기본 설정에 ram_free 란 complex를 이용하는데, 이는 현재 Linux 환경의 SGE에서
기본적으로 사용하지 않는 complex 이다. 아래와 같이 mem_free 로 변경한
queue.conf 파일을 생성한다.

vi conf/queue.conf
# Default configuration
command qsub -V -v PATH -cwd -S /bin/bash -j y
option mem=* -l mem_free=$0
option mem=0 # Do not add anything to qsub_opts
option num_threads=* -pe smp $0
option num_threads=1 # Do not add anything to qsub_opts
option max_jobs_run=* -tc $0
default gpu=0
option gpu=0
option gpu=* -l gpu=$0 -q gpu.q

일반 기본적으로 해석 장비의 core 수는 최소 16core 이상 보유한 단일 서버 1대 이상이 필요하며,
그보다 자원이 작을 경우는

nj=16 부분을 줄여준다. (nj=8)

sh run.sh

해석 과정이 워낙 길다 보니 (2~3일) 중간에 한번 오류가 발생되어 재시작 할려면 시간 소비가 심히다.
특히 전처리 부분이..로그를 보고 정상적으로 완료된 과정을 재시작 시 넘어갈 수 있게 해야한다.

run.sh 스크립트를 열어보면 최 상단에 stage=0 이 있다. 이 부분을 재시작할 stage 단계에 맞게 조정한다.

// 완료된 결과로 decoder 만들기

$ mkdir -p online_demo/ ; cd online_demo
$ mkdir bin
$ mkdir -p model/chain
$ cd modle
$ cp -a <kaldi_zeroth_s5_path>/exp/chain/tdnn1a_sp_online chain
$ cp -a <kaldi_zeroth_s5_path>/exp/chain/tree_a chain

$ cd chain/tdnn1a_sp_online
$ rm -rf decode_*test_clean ivector_extractor

$ cd ../tree_a
$ rm -rf *.gz q log

$ cd online_demo/bin

$ vi speech2txt

#!/bin/sh

MODEL_PATH=/home/alang/kaldi_example/egs/zeroth_korean/online_demo

WAV_FILE=”$1″

cd $PWD
echo ${1} $1 > .decode.scp

/APP/DeepLn/kaldi-5.3/src/online2bin/online2-wav-nnet3-latgen-faster –online=true –frame-subsampling-factor=3 –config=${MODEL_PATH}/model/chain/tdnn1a_sp_online/conf/online.conf –min-active=200 –max-active=7000 –beam=15.0 –lattice-beam=6.0 –acoustic-scale=1.0 –word-symbol-table=${MODEL_PATH}/model/chain/tree_a/graph_tgsmall/words.txt ${MODEL_PATH}/model/chain/tdnn1a_sp_online/final.mdl ${MODEL_PATH}/model/chain/tree_a/graph_tgsmall/HCLG.fst ‘ark:cat .decode.scp|’ ‘scp:cat .decode.scp|’ ‘ark:/dev/null’ &> .decode.log && grep “^$1” .decode.log | sed -e “s/$1/$1 : /g”

$ chmod 755 speech2txt

// speech2txt 명령 뒤에 wav 파일을 arg 로 입력하면 해당 wav 음성파일의 TEXT 를 확인할 수 있다.

$ speech2txt  <wavfile_path>

 

========================================================================================

아래는 최종적으로 개발한 kaldi decoder 로 유인나 음성 파일에 대한 TEXT 를 생성하는 영상입니다.

952 views

 

참고로 오른쪽 터미널창 내용은 정확한 실제 wav 파일의 TEXT 내용입니다.

아무래도 kaldi-zeroth 에서 이용한 형태소 분석과 언어모델등의 한계로 띄어쓰기등이 이상한 부분은
있지만, 대략 10여개의 패턴에 대해 자동으로 치환하는 후처리를 해주니 크게 문제되진 않았습니다.

이상입니다.

서진우

슈퍼컴퓨팅 전문 기업 클루닉스/ 상무(기술이사)/ 정보시스템감리사/ 시스존 블로그 운영자

You may also like...

페이스북/트위트/구글 계정으로 댓글 가능합니다.