xcmyz's FastSpeech を CPU で推論して text-to-speech する(+ SqueezeWave で高音質化)

漢なら xcmyz's FastSpeech https://github.com/xcmyz/FastSpeech を CPU で推論(text-to-speech)したいですよね! やりましょう!

できました.

https://github.com/xcmyz/FastSpeech/pull/41

自前 fork に推論専用(matplotlib でプロット部分を消しただけですが) branch `infer` もあります.

https://github.com/syoyo/FastSpeech/tree/infer

## セットアップ

conda で Python3.7 環境を作り,
pytorch 1.3.1 CPU 版をインストールするとします.

pip で FastSpeech 動かすように install します.

```
$ pip install librosa inflect unidecode

# (optional) 本来推論したいだけであれば不要であるもの
$ pip install matplotlib soundfile
```

あとは FastSpeech の README にあるように, pretrained model を配置して synthesis.py すれば音声がよろしく生成されます.

GPU 版と CPU 版とで結果を聴き比べてみましたが, 特段差分はなさそうでした(本当は生成された音声の波形の diff をとるとよいところですが).
 
### 速度について

`I'am happy to see you again` を Threadripper 1950X で生成すると, fastspeech(transformer)で 0.1 秒, griffin-lim 変換で 0.9 秒くらいでした. waveglow は 9 秒くらい(つまり fastspeech + waveglow で 9.1 秒くらい). 比較用の Tacotron2 + waveglow は 12 秒くらいでした.

CPU 版は thread 実行されているため, コア数に比例します. たとえば i9-9900K(8 コア)では 20 秒くらいかかりました.

ちなみに Ryzen9 3950X でも試しましたが, 処理時間は Threadripper 1950X とほぼ同じでした. 2020 年 1 月 17 日時点では, 1950X は中古で 3~4 万円くらいで買えるので, CPU で FastSpeech 推論する場合は 1950X がコスパがよさそうです.

CUDA(2080 Ti)では, だいたい 1950X に比べ 8~10 倍くらい高速でした(waveglow 処理 tacotron2 + waveglow が 1~2 秒くらい). ただ, fastspeech 部分は CPU よりも 2~3 倍くらい遅くなりました. カーネル起動などのコストですかね. 


とりあえずお手軽にそこそこいい感じの品質で TTS で音声生成したいとか, サーバーで TTS 処理したいとか, いろいろな環境で動かしたい(サーバーレス実行したいとか, macOS で動かしたい(今後 macOS で CUDA 対応は打ち切られますし)とか)を考えると, CPU で実行できるのはいろいろ利点があります.

あとは, 処理時間のほとんどが waveglow です(GPU では fp16 などの高速化が効いているようですね). WaveFlow や 
 SqueezeWave https://github.com/tianrengao/SqueezeWave など, この部分をより軽量なものにしたら CPU 推論もアドバンテージがあるかもしれません.

ただ, やはり GPU は速いので, 使えるのであれば GPU 使ったほうがよいところですね.

### ROCm では...

ROCm 3.0 で, VEGA56 で動くの確認しました. 初期化で MIOpen カーネルのコンパイルなどで 30~40 秒ほど時間かかるのですが, waveglow 推論自体は 4~5 秒で終わりました(一部, inverse 計算などで CPU に戻らないといけないものがあり, そこがボトルネックかも).
Radeon VII では現状 IntTensor 作るところでエラーになりました(int16, fp16 周りの問題?).

VEGA56 は 2020 年 1 月 17 日現在, 新品でも税込み 3 万円くらいで投げ売りされているので, バッチでたくさん TTS したい場合には活用できるかもしれません. 

### 音声品質について

fastspeech + waveglow は Tacotron2 + waveglow に比べノイズはある感じですが, 抑揚などは fastspeech のほうが自然な感じがします. ぜひみなさんもいろいろ音声生成して聴き比べてください.

### Windows 10 64bit でも動きます

windows では, 明示的に追加で `pip install soundfile` が必要ですが(そうしないと librosa の呼び出しあたりで libsndfile64bit.dll が見つからないエラーが出る),
Windows 10 64bit + Python3 + Miniconda + PyTorch 1.3.1 で問題なく動くことを確認しました.

PyTorch のポータビリティ素晴らしいですね.

### SqueezeWave を使う.

WaveGlow での無駄な計算を減らしたり, 軽量化することで演算量を減らして高速に mel -> wav 生成できる SqueezeWave があります.

SqueezeWave の公開コードは CUDA にハードコードされていますが, CPU 対応が出ていました.

https://github.com/tianrengao/SqueezeWave/issues/6

Patch の著者による fastspeech(CPU) + SqueezeWave(CPU) があります!

https://github.com/alokprasad/fastspeech_squeezewave

"Let’s go out to the airport. The plane landed ten minutes ago." の mel から SqueezeWave での wav 生成は,

Ryzen5 1400X で 128L で 1.1 secs, 128S で 0.33 secs くらいでした.
モバイルでもそれなりの速度で動きそうですね!

libtorch mobile では, 現在 XNNPACK 対応が進んでいますので, 

CPU で浮動小数点精度で推論むけ XNNPACK のメモ
https://qiita.com/syoyo/items/79400663f2d79b5f5943

XNNPACK 対応したら(pytorch mobile 1.5?), 実用レベルで on device で neural text to speech ができそうな気がします!

## TODO

* 抑揚や感情をより制御できるっぽい Mellotron を試す https://github.com/NVIDIA/mellotron
* ROCm PyTorch(AMD GPU)で推論して速度を確認する.
* libtorch で C++ と Android で動かす(現状, FastSpeech モデルについては LengthRegularizer あたりで torchscript 変換でエラーが出る. コードの整理と型付けが必要)
* ESPNet https://github.com/espnet/espnet の TTS を試す(日本語 TTS あり. セットアップが面倒そうであるが...)
* **優秀な若人さまが, FastSpeech CPU 実行と SqueezeWave CPU 実行をお極めなさることで, 人類史上最速で neural text-to-speech の頂点に立ち, 至高の Neural TTS 若人さまへと昇華なされるスキーム**を確立する旅に出たい