Closed kyakuno closed 1 year ago
当初はボコーダにもencodecが使われていたがvocosに置き換わった。
純粋なボイスチェンジャーではなく、TTSにボイス特性を与えられるような構成。ボイスチェンジャー的に使う場合は、WhisperでTextに変換後に、TTSする。
pyopenjtalkのwindows向けのprebuilt binary https://zenn.dev/syoyo/articles/4f6962247adfb6
audioのtokenizeにはencodecを使用している。 https://github.com/Plachtaa/VALL-E-X/blob/master/data/tokenizer.py textのtokenizeにはopenjtalkとbpeを使用している。 textとaudioのtokenからdecoderループでmel spectrumを生成し、vocosで波形にしている。
原理的には学習不要で推論だけで、ボイスチェンジャー含めて実装できそう。
ONNX変換の作業ブランチ https://github.com/axinc-ai/VALL-E-X
decoderはkv_cacheを使用しているため、whisperと同様に最大長で固定してONNXにエクスポート可能にする。
ar_decoder.onnxは605MB。
vocosはbackboneの後段のheadでstftを使っているため、後段のheadは除外してexportする必要がある。
ar_decoderとvocosはonnxに変換できた。 残りはAudioTokenizerで、 self.codec.encode(wav.to(self.device)) が呼ばれる。
BPETokenizerはロジックだけなので、後は、サンプルコードを作ればつながりそうな気はする。
narのエクスポートで下記のエラーになる。 'aten::unflatten' to ONNX opset version 15 is not supported.
torch_nightly=torch 2.1.0.dev20230722でエクスポートできるとのこと。
pip3 uninstall torch pip3 install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cpu で入れる。 2.2.0.dev20230910 が入った。
nar_decoderもエクスポートできた。引数iでレイヤー0〜6を指定できるようにした。
https://storage.googleapis.com/ailia-models/vall-e-x/nar_decoder.onnx https://storage.googleapis.com/ailia-models/vall-e-x/nar_predict_layers.onnx
nar_decoderにエクスポート時と違うShapeを与えるとエラーになる。
ailia.core.AiliaInvalidLayerException: code: -10 (Incorrect layer parameter. [broken or unsupported AI model file])
+ error detail : Layer:/nar_decoder/layers.0/self_attn/Reshape_4_output_0(Reshape) Error:The input size doesn't match the output size (input_shape=(345,1,1024) (stride:(1024,1024,1)), output_shape=(346,16,64) (stride:(1024,64,1))).
調べてみると、nar_decoderが使用しているMultiheadAttentionでDynamicShapeを使用しても、StaticなReshapeが生成されるのは既知の問題のようである。 https://github.com/pytorch/pytorch/issues/99701
dropoutが0.1なので、why_not_fast_path = f"dropout was {self.dropout}, required zero"で、torch._native_multi_head_attentionではなく、F.multi_head_attention_forwardが使われている。
dropoutを0にすると、torch._native_multi_head_attentionになり、Exporting the operator 'aten::_native_multi_head_attention' to ONNX opset version 15 is not supported.になる。
エクスポート時にverboseをすると、原因となった元コードの場所がわかると教えてもらった。
%/nar_decoder/layers.0/self_attn/Unsqueeze_6_output_0 : Long(1, strides=[1], device=cpu) = onnx::Unsqueeze[onnx_name="/nar_decoder/layers.0/self_attn/Unsqueeze_6"](%/nar_decoder/layers.0/self_attn/Cast_1_output_0, %onnx::Unsqueeze_805), scope: models.vallex.VALLE::/modules.transformer.TransformerEncoder::nar_decoder/modules.transformer.TransformerEncoderLayer::layers.0/modules.activation.MultiheadAttention::self_attn
%/nar_decoder/layers.0/self_attn/Concat_3_output_0 : Long(3, strides=[1], device=cpu) = onnx::Concat[axis=0, onnx_name="/nar_decoder/layers.0/self_attn/Concat_3"](%/nar_decoder/layers.0/self_attn/Constant_19_output_0, %/nar_decoder/layers.0/self_attn/Unsqueeze_5_output_0, %/nar_decoder/layers.0/self_attn/Unsqueeze_6_output_0), scope: models.vallex.VALLE::/modules.transformer.TransformerEncoder::nar_decoder/modules.transformer.TransformerEncoderLayer::layers.0/modules.activation.MultiheadAttention::self_attn # /usr/local/lib/python3.11/site-packages/torch/nn/functional.py:5346:0
%/nar_decoder/layers.0/self_attn/Reshape_4_output_0 : Float(*, *, *, strides=[1024, 64, 1], requires_grad=0, device=cpu) = onnx::Reshape[allowzero=0, onnx_name="/nar_decoder/layers.0/self_attn/Reshape_4"](%/nar_decoder/layers.0/self_attn/Gather_4_output_0, %/nar_decoder/layers.0/self_attn/Concat_3_output_0), scope: models.vallex.VALLE::/modules.transformer.TransformerEncoder::nar_decoder/modules.transformer.TransformerEncoderLayer::layers.0/modules.activation.MultiheadAttention::self_attn # /usr/local/lib/python3.11/site-packages/torch/nn/functional.py:5346:0
%/nar_decoder/layers.0/self_attn/Transpose_3_output_0 : Float(*, *, *, strides=[64, 1024, 1], requires_grad=0, device=cpu) = onnx::Transpose[perm=[1, 0, 2], onnx_name="/nar_decoder/layers.0/self_attn/Transpose_3"](%/nar_decoder/layers.0/self_attn/Reshape_4_output_0), scope: models.vallex.VALLE::/modules.transformer.TransformerEncoder::nar_decoder/modules.transformer.TransformerEncoderLayer::layers.0/modules.activation.MultiheadAttention::self_attn # /usr/local/lib/python3.11/site-packages/torch/nn/functional.py:5346:0
%/nar_decoder/layers.0/self_attn/Constant_20_output_0 : Long(1, strides=[1], requires_grad=0, device=cpu) = onnx::Constant[value={351}, onnx_name="/nar_decoder/layers.0/self_attn/Constant_20"](), scope: models.vallex.VALLE::/modules.transformer.TransformerEncoder::nar_decoder/modules.transformer.TransformerEncoderLayer::layers.0/modules.activation.MultiheadAttention::self_attn
原因のコード。site-packages/torch/nn/functional.py:5346:0。
if static_k is None:
k = k.view(k.shape[0], bsz * num_heads, head_dim).transpose(0, 1)
下記を書き換えるとReshapeの問題を修正できた。
if static_k is None:
#k = k.view(k.shape[0], bsz * num_heads, head_dim).transpose(0, 1) # original
k = k.view(src_len, bsz * num_heads, head_dim).transpose(0, 1)
if static_v is None:
#v = v.view(v.shape[0], bsz * num_heads, head_dim).transpose(0, 1) # original
v = v.view(src_len, bsz * num_heads, head_dim).transpose(0, 1)
RTX3080でkv_cacheの固定・非固定の速度差が大きいのが少し気になる。(処理時間は学習・推論)
kv_cache固定 processing time 829ms + 19157ms kv_cache非固定 processing time 546ms + 1985ms
TokenEmbeddingのweightもONNXにエキスポートが必要。
PositionEmbeddingにも学習可能パラメータのalphaが含まれるのでダンプする必要がある。
prefix_modeは常に1が使われる。学習時の設定の予感。
macOSでkv_cacheの固定化有効だとVALL-E EOS [240 -> 479]のトークン数で、torch = 40353ms、ailia = 33921ms。 kv_cacheの固定化無効(master)だとtorch = 38395ms。 ailia SDK 1.2.15。
ailia SDK 1.2.16 betaだとVALL-E EOS [240 -> 446]のトークン数でailia = 32071ms。 1.2.15と1.2.16は同じくらいの速度。
RTX3080だとTorchが1985msに対して、ailiaが28384msで速度差が大きい。 nar_decoderは高速みたいなので、ar_decoderに何か問題がありそう。
ar_decoderはMatMulがメインで、MatMulなのにそこまで速度差が出るのは少し不思議。
====Profile(Grouped by LayerType)====
LayerType TotalPredictTime(Average)[us] TimeRatio[%]
MatMul_DNN 36957 29.76
Gather 14913 12.01
ScatterND 13808 11.12
Transpose_DNN 12095 9.74
Slice 10533 8.48
Eltwise_DNN 10262 8.26
Slice_DNN 3777 3.04
Concat 3183 2.56
MeanVarianceNormalization_DNN 2938 2.37
Eltwise 2511 2.02
Unsqueeze 2272 1.83
Expand_DNN 1907 1.54
Expand 1774 1.43
Softmax_DNN 1710 1.38
Reshape_DNN 1000 0.81
Where 995 0.80
ReLU_DNN 987 0.79
Reshape 868 0.70
Shape 661 0.53
Range 515 0.41
Squeeze 453 0.36
Gather_DNN 74 0.06
====Profile(Summary)====
Predict Average Time[us]:124195 Variance:938637217 N:201
RTX3080のtorch単体で、kv_cacheの固定化をしないと1985msで、kv_cacheの固定をすると2233ms。
毎回、CUDAのハンドルの作り直しが発生している?
まだtorch依存を外せていないために競合しているのが要因な可能性もある。
onnxruntime gpuだと12510msで走る。
multinominalとargmaxの違いについて。multinominalは確率分布に応じてサンプリングする。 https://stackoverflow.com/questions/61581774/what-is-the-point-of-multinomial-vs-argmax-evaluation-of-accuracy
音声変換付きTTS https://github.com/Plachtaa/VALL-E-X