axinc-ai / ailia-models

The collection of pre-trained, state-of-the-art AI models for ailia SDK
2.04k stars 325 forks source link

ADD vallex #1236

Closed kyakuno closed 1 year ago

kyakuno commented 1 year ago

音声変換付きTTS https://github.com/Plachtaa/VALL-E-X

kyakuno commented 1 year ago

当初はボコーダにもencodecが使われていたがvocosに置き換わった。

kyakuno commented 1 year ago

解説記事1 https://www.techno-edge.net/article/2023/08/28/1812.html

kyakuno commented 1 year ago

解説記事2 https://zenn.dev/kun432/scraps/ca42215a5f9bc6

kyakuno commented 1 year ago

純粋なボイスチェンジャーではなく、TTSにボイス特性を与えられるような構成。ボイスチェンジャー的に使う場合は、WhisperでTextに変換後に、TTSする。

kyakuno commented 1 year ago

pyopenjtalkのwindows向けのprebuilt binary https://zenn.dev/syoyo/articles/4f6962247adfb6

kyakuno commented 1 year ago

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で波形にしている。

kyakuno commented 1 year ago

原理的には学習不要で推論だけで、ボイスチェンジャー含めて実装できそう。

kyakuno commented 1 year ago

ONNX変換の作業ブランチ https://github.com/axinc-ai/VALL-E-X

kyakuno commented 1 year ago

decoderはkv_cacheを使用しているため、whisperと同様に最大長で固定してONNXにエクスポート可能にする。

kyakuno commented 1 year ago

ar_decoder.onnxは605MB。

kyakuno commented 1 year ago

vocosはbackboneの後段のheadでstftを使っているため、後段のheadは除外してexportする必要がある。

kyakuno commented 1 year ago

ar_decoderとvocosはonnxに変換できた。 残りはAudioTokenizerで、  self.codec.encode(wav.to(self.device)) が呼ばれる。

kyakuno commented 1 year ago

kv_cacheの最大長は暫定で1024。 https://storage.googleapis.com/ailia-models/vall-e-x/ar_decoder.onnx https://storage.googleapis.com/ailia-models/vall-e-x/audio_embedding.onnx https://storage.googleapis.com/ailia-models/vall-e-x/vocos.onnx https://storage.googleapis.com/ailia-models/vall-e-x/encodec.onnx

kyakuno commented 1 year ago

BPETokenizerはロジックだけなので、後は、サンプルコードを作ればつながりそうな気はする。

kyakuno commented 1 year ago

narのエクスポートで下記のエラーになる。 'aten::unflatten' to ONNX opset version 15 is not supported.

kyakuno commented 1 year ago

torch_nightly=torch 2.1.0.dev20230722でエクスポートできるとのこと。

kyakuno commented 1 year ago

pip3 uninstall torch pip3 install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cpu で入れる。 2.2.0.dev20230910 が入った。

kyakuno commented 1 year ago

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

kyakuno commented 1 year ago

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

kyakuno commented 1 year ago

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.になる。

kyakuno commented 1 year ago

エクスポート時に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
kyakuno commented 1 year ago

原因のコード。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)
kyakuno commented 1 year ago

下記を書き換えると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)
kyakuno commented 1 year ago

RTX3080でkv_cacheの固定・非固定の速度差が大きいのが少し気になる。(処理時間は学習・推論)

kv_cache固定 processing time 829ms + 19157ms kv_cache非固定 processing time 546ms + 1985ms

kyakuno commented 1 year ago

TokenEmbeddingのweightもONNXにエキスポートが必要。

kyakuno commented 1 year ago

PositionEmbeddingにも学習可能パラメータのalphaが含まれるのでダンプする必要がある。

kyakuno commented 1 year ago

prefix_modeは常に1が使われる。学習時の設定の予感。

kyakuno commented 1 year ago

macOSでkv_cacheの固定化有効だとVALL-E EOS [240 -> 479]のトークン数で、torch = 40353ms、ailia = 33921ms。 kv_cacheの固定化無効(master)だとtorch = 38395ms。 ailia SDK 1.2.15。

kyakuno commented 1 year ago

ailia SDK 1.2.16 betaだとVALL-E EOS [240 -> 446]のトークン数でailia = 32071ms。 1.2.15と1.2.16は同じくらいの速度。

kyakuno commented 1 year ago

RTX3080だとTorchが1985msに対して、ailiaが28384msで速度差が大きい。 nar_decoderは高速みたいなので、ar_decoderに何か問題がありそう。

kyakuno commented 1 year ago

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
kyakuno commented 1 year ago

RTX3080のtorch単体で、kv_cacheの固定化をしないと1985msで、kv_cacheの固定をすると2233ms。

kyakuno commented 1 year ago

毎回、CUDAのハンドルの作り直しが発生している?

kyakuno commented 1 year ago

まだtorch依存を外せていないために競合しているのが要因な可能性もある。

kyakuno commented 1 year ago

onnxruntime gpuだと12510msで走る。

kyakuno commented 1 year ago

multinominalとargmaxの違いについて。multinominalは確率分布に応じてサンプリングする。 https://stackoverflow.com/questions/61581774/what-is-the-point-of-multinomial-vs-argmax-evaluation-of-accuracy

kyakuno commented 1 year ago

numpyのmultinominal。 https://runebook.dev/ja/docs/numpy/reference/random/generated/numpy.random.multinomial