https://github.com/MoorDev/Tacotron2-Wavenet-Korean-TTS

 

MoorDev/Tacotron2-Wavenet-Korean-TTS

Korean TTS, Tacotron2, Wavenet. Contribute to MoorDev/Tacotron2-Wavenet-Korean-TTS development by creating an account on GitHub.

github.com

지속적으로 기존에 있던 hccho2 님의 Tacotron2의 소스(https://github.com/hccho2/Tacotron2-Wavenet-Korean-TTS)로 수정중이다.
Tensorflow 1.x를 썼기에 그에 따른 구버전 설치 문제가 있었고 (그동안은 tensorflow.contrib 모듈로 인해 1.x 사용이 강제 되었지만 TFA(https://www.tensorflow.org/addons/overview?hl=ko)의 등장으로 2.x로의 포팅이 어렵지 않게 되긴했다.) Python 3.6~3.7 이외에서 오류가 발생하는 문제도 있었다.

하지만 이 코드가 제일 확실한 한국어 Tacotron 소스였고 제일 잘 돌아가는 코드였다. (무엇보다 학습속도가 빨랐다.)
다만 문제는 내가 만든 데이터셋을 적용하려 하니 고생이 많았다는 것.

KSS데이터셋https://www.kaggle.com/bryanpark/korean-single-speaker-speech-dataset 은 테스트하기 제일 좋은 물건이었고 이것을 이용해 만든 모델을 전이시켜서 새로운 목소리로 하는 글도 많이 있었는데 결과물은 어딘가가 계속 부족했다. 즉, 궁극적인 이유는 학습데이터가 부족한것.

그리하여 데이터 증강기법을 음성에 적용하기로 했고 sox의 tempo와 dither 기능을 사용해 목소리의 속도를 미묘하게 바꿔 데이터를 증강하였다. tempo 0.9 0.85 이 둘만 해도 사람 귀에는 크게 거슬리지 않는 소리가 나오며 1.05배도 큰 차이를 못 느낀다. 하지만 dither 기능으로 이 모든 음성은 Mel Spectrogram이 전혀 다른 녀석이 튀어나오며 데이터 증강효과가 발생한다. (하지만 속도만 조절한것이기에 문장자체는 동일하므로 데이터 증강 효과가 없을지도...)

 

#!/bin/bash
find ./audio/ | while read entry
do
    sox "${entry}" "${entry//.wav/_slow.wav}" -V tempo 0.8
done

위 bash 스크립트를 audio 폴더 밖에서 만들어서 실행하면 _slow가 붙은 wav파일이 추가된다. recognition.json파일은 어차피 이 글을 보고 있는 이상 dataset을 만들줄 알고 있다는 의미일테니 길게 설명하지는 않을 것이다. 해당 json파일에 추가된 slow파일 리스트를 추가하면 데이터 증강이 된다. 이 파일을 수정하면 0.8배 0.9배 1.1배(빠르게 만드는 것은 발음이 뭉개지기 때문에 추천하지 않음)데이터 증강을 할 수있다. 이건 응용하는 사람에 따라 다를 것이다.

본래 데이터셋이 말이 좀 빠르다면 0.7배까지도 문제 없을 것으로 생각된다.


그리하여 어느정도 괜찮은 결과는 나왔지만 문제는 데이터의 증가폭이 너무 큰 나머지 학습속도가 무지막지하게 느려졌다. 하지만 뭐.... 결과만 잘나오면 장땡이지.

이외에도 수정한 hparam을 정리한다. hparam.py를 열면 잔뜩 있는데 여기를 수정하면서 학습튜닝하는것이 노가다지만 의외로 재미있다.

griffin_lim_iters = 100,
#기본은 60이며 Mel-spectrogram을 Linear-spectrogram으로 바꾸고 이를 다시 시간영역으로 바꾸는 알고리즘. Wavenet이 등장해서 이걸로 대체하기도 하지만 속도면에서 아직 Griffin-Lim이 나에겐 더 맞는 방식이었다. Iters를 100이상으로 늘리니 조금 더 들어줄만한 음성이 나온다.

main_data_greedy_factor = 0.5,
main_data = ['./data/monika'], # 이곳에 있는 directory 속에 있는 data는 가중치를 'main_data_greedy_factor' 만큼 더 준다.

이 파라미터는 어느 목소리를 메인으로 할 것인가를 결정한다. Multi Speaker 는 말이좋아 multi-speaker지 엄밀히 말해서 부족한 데이터를 대신해 메인이 되는 것을 대량의 데이터가 도와주는 것에 가깝다. greedy_factor를 많이 주면 많이 줄 수록 메인 데이터 위주로 학습을 이뤄지며 보조데이터셋의 학습속도는 떨어진다. 적절한 값을 찾지 않으면 모두 학습이 느려지는 결과를 초래한다. 대신 Overfitting은 잘 이뤄지지 않는다.

silence_threshold = 1,
trim_silence = True, #Whether to clip silence in Audio (at beginning and end of audio only, not the middle)
기본은 0인데 무음부분을 삭제한다. 앞뒤의 무음만 삭제하므로 학습효과를 올려주는 효과가 있다.

Nvidia의 논문에 따르면 앞뒤에 무음이 있으면 Attention이 잘 잡히지 않아 학습속도가 떨어진다고 한다.

일단 이 정도로 파라미터를 수정하고 돌리니 1시간 음성을 3시간으로 뻥튀기 하고 200k STEP이 돌아가는 와중에도 attention은 아직 제대로 안 잡힌다. 그런데 조금씩조금씩 잡혀가는게 1000k쯤되면 문제 없을 듯.

뭔가 300k부터 align이 안 잡히는 것이 보인다. 이건 문제가 있다.
역시 dataset이 문제 아닐까 싶은데 자세히 보니 내 데이터는 stereo로 되어있었다. 혹시 이건가...?

일단 mono로 바꾸기 위해서 wav파일들이 있는 곳에서

find . -name '*.wav' -exec ffmpeg -i '{}' -ac 1 '{}' \;

위 명령을 이용했다. 어떻게든 되겠지.

그리고 https://github.com/carpedm20/multi-speaker-tacotron-tensorflow/issues/4#issuecomment-368457924

 

training이 잘 안됩니다. · Issue #4 · carpedm20/multi-speaker-tacotron-tensorflow

샘플로 주신 prepare_jtbc.sh을 실행해 만든 audio data를 가지고 single speaker로 20만 step이상 학습을 진행했는데도, 여전히 음성이 제대로 안 나옵니다. 문제가 뭔지 알 수가 없습니다. 혹시 제대로 음성

github.com

여기보니 reduction factor를 5로 바꾸니 더 잘 된다는 이야기가 있다. 이유는 여전히 모르겠지만... 일단 손을 대보는 중.

위의 방법이 확실히 효과가 있었다!
Reduction Factor 5
데이터의 Mono화(ffmpeg이용)
데이터 증강(sox이용)

이 3가지가 정답이었다!
물론 아직은 노이즈가 느껴지지만 Align이 확실히 잡힌다

12000Step의 Alignment 상황이다.
Hyper parameter와 데이터증강기술(?)그리고 데이터 셋 정리의 승리

 

 

이제 여기서 pb로 만들고 기타 정리를 더 하면 모바일에서 나만의 TTS를 만들 수 있을지도 모른다

https://github.com/keithito/tacotron/issues/95

 

Freezing and Optimising for Inference · Issue #95 · keithito/tacotron

I've been attempting today to create a frozen graph, and then optimise that graph for inference (to evaluate performance for an embedded device). This model lacks a placeholder node for inferen...

github.com

여기서 원본 코드를 만든 keithito의 말에 의하면 Output Node name은 "model/inference/dense/BiasAdd:0" 이거라고 하니까 ckpt를 pb로 만드는건 어렵지 않을지도

물론 결과물은 Griffin-Lim을 한번 해줘야 하니까 여기서 성능을 꽤 잡아 먹겠지만...

 

대충 이런식으로 하면 bazel로 pb할 수 있다고 한다.

./bazel-bin/tensorflow/tools/graph_transforms/transform_graph \ --in_graph="../TTSDataset_keith/tacotron-60k/freezed.pb" \ --inputs='import/datafeeder/input_queue' \ --outputs='model/inference/dense/BiasAdd:0' \ --out_graph='optimized_ta_keith_60k.pb' \ --transforms='strip_unused_nodes(type=float, shape="1,224,224,3")fold_constants(ignore_errors=true) fold_batch_norms fold_old_batch_norms quantize_weights quantize_nodes sort_by_execution_order' \

 

해보면 대충 뭐..알겠지

,