背景
PyTorch/TensorFlow で書かれた音声スピーチ系ネットワーク(e.g. Tacotron, FastSpeech)をモバイルで推論したい.
TensorFlow-Lite などでは RNN 系などの対応が十分ではないので変換がうまくいかない.
(少なくとも TensorFlow tacotron は .pb から toco での変換は r1.14 時点では失敗する)
libtensorflow を使う手もあるが, やりたいことに対して無駄が多すぎるし, ビルドも手間であり, また libtensorflow は Android には正式対応していない(モバイルでのオフィシャルな対応は tensorflow-lite に移行したっぽい)
libtorch もなかなかうまくいかない(ScriptModule で記述しても一部変換できない op がある)
tvm などの他のモバイル推論に特化したライブラリでも, RNN 系や音声系の対応は(2019 年 9 月時点)行われていないか, 非常に限られた対応となっている.
多少演算に時間がかかったとしても, モバイルで動かしたい.
Tacotron 系
T.B.W.
Transformer 系
使っているネットワーク op はそれほど多いわけではない.
たとえば, PyTorch 実装の FastSpeech(Transformer TTS) https://github.com/xcmyz/FastSpeech では, pytorch の op は
- torch.bmm(batch matmul)
- nn.Softmax
- nn.Conv1d
- nn.Linear
- nn.Dropout
- nn.LayerNorm
- nn.Embedding
- nn.ModuleList
あたりくらいしか使っていない.
waveglow を CUDA だけ(cuDNN は使っているが)で動かしていたりする既存の取り組みがある.
=> C++ で自作したい!
PyTorch
推論(forward, inference)についての実装です.
torch.bmm
行列をまとめて matmul すれば OK
nn.SoftMax, nn.Conv1d, nn.Linear
通常の NN のように実装すればよい. 特に特殊なことはなし.
nn.Embedding
word embedding などに使われる.
実装としては, int の配列([x]
)と重み行列(W
)を受け取り, float の配列(2 次元行列)を返す.
一番簡単なのは, W[x]
な感じで配列ルックアップする.
重み行列が大きく, データが sparse な場合は std::unordered_map
などを使ってルックアップするといいかも?(GPU で動かす場合はハッシュ or 二分木探索とか?)
Chainer では EmbedID
https://docs.chainer.org/en/stable/reference/generated/chainer.links.EmbedID.html に相当. ちなみに Chainer では initialW
が与えられなかった場合, 正規分布の乱数で weight 行列を初期化している.
nn.Dropout
推論の場合はなにもしない(input をそのまま返す)
参考までに, dropout を実装したい場合は,
Chainer と TensorFlow の Dropout 実装メモ
https://qiita.com/syoyo/items/8b459cc5524eff6f54f3
を参考に実装する. PyTorch(ATen での実装) はノイズ(乱数)にベルヌーイ分布を使っている.
nn.LayerNorm
Aten に CPU 実装があるのでそれを参考に推論を実装.
特段特殊なことはしていない.
nn.ModuleList
Module(op)をリストで保持できるようにしたもの.
MultiHeadAttension など
pytorch には nn.MultiheadAttention
が 1.2 からあります(nn.Transformer
も 1.2 から導入). 必要に応じて参考にしましょう.
その他
音声系は, ニューラルネットワークモジュールのほかにも, text の処理や wav の処理, fft などいろいろ周辺のコードも必要です.
librosa 相当や, FFT 処理
nanosnap にご期待ください.
stft
, mfcc
などがあります.
(少なくとも現時点で Tacotron のモバイル実行で必要なものはあるはず)
wav 入出力
nanosnap か, nanosnap でも使っている dr_wav がおすすめ.
inflect
inflect の C++ 実装がほしい(とくに number_to_words
)
ご期待ください.
PyTorch のメモ
nn.init.normal_
など, アンダースコアで終わっている関数は in-place 関数.
PyTorch では in-place 関数の利用は推奨されないが, 乱数などでウェイトを初期化したいときとかは in-place 便利.
What does the underscore suffix in PyTorch functions mean?
https://stackoverflow.com/questions/52920098/what-does-the-underscore-suffix-in-pytorch-functions-mean
参考文献
その他参考になる文献です.
作って理解する Transformer / Attention
https://qiita.com/halhorn/items/c91497522be27bde17ce
TODO
- AMDGraphX あたりでよろしく演算グラフを quantize して最適化する(https://github.com/ROCmSoftwarePlatform/AMDMIGraphX/wiki/Getting-started:-using-the-new-features-of-MIGraphX-0.4#bert-natural-language-processing-nlp-model)
-
Torch model から直接 C++ コードを吐くのはどうか?
- chainer2tflite の参考 : https://qiita.com/syoyo/items/e84d66b2a938843c1594
- Torch JIT やら onnx に吐いてから変換は RNN 系が自動展開されてしまうのでうまくいかなさそう(すくなくとも torch jit はダメだった)