VOICEVOX / voicevox_core

無料で使える中品質なテキスト読み上げソフトウェア、VOICEVOXのコア
https://voicevox.hiroshiba.jp/
MIT License
835 stars 115 forks source link

Rust化の追従をしていく #213

Open Hiroshiba opened 1 year ago

Hiroshiba commented 1 year ago

内容

128 の追従タスクを一覧化します。

その他

確認等できたらコメントをお願いします!

qwerty2501 commented 1 year ago

Windows上でcargo testするとエラーになる件issue作りました https://github.com/VOICEVOX/onnxruntime-rs/issues/3

qwerty2501 commented 1 year ago

そういえばopen_jtalkの辞書読み込み時のpathをutf8に変更した影響がengine側に出てるかもですね

Hiroshiba commented 1 year ago

あ~~忘れていました。こちらですね。一覧に書き足します。

Hiroshiba commented 1 year ago

合成結果が以前と同じかどうかをチェックしないとなので、ちょっとタスクを足しました。

PickledChair commented 1 year ago

https://github.com/VOICEVOX/voicevox_core/releases/tag/0.13.0-rust.0 で配布されている製品版コアについて、macOS において

がうまくいくことを確認しました!

Hiroshiba commented 1 year ago

windows版Rustコア試してみました! CPU版とCUDA版は正しく動作していそうでした!

windows DirectMLを試したところ、おそらくGPUを使わずに生成しているっぽい挙動をしていました。 VOICEVOX DirectML zip版のcore.dllとonnxruntime.dllをRust版コアに入れ替えて、GPUモードで生成した感じ、CPU使用率が高まる感じでした。 おそらくGPUを持っていない人でもDirectML版GPUで生成できるはず・・・?

qwerty2501 commented 1 year ago

C++版と挙動が違うってことですかね?

qryxip commented 1 year ago

LinuxのCPU版は動きました(GPU版はC++版もSEGVする状態だったので確認できていません)

Hiroshiba commented 1 year ago

C++版と挙動が違うってことですかね?

ですです! DirectML版でGPUモードで長い文章を生成するとGPUメモリ使用量と使用率が上がるのですが、その挙動がなく代わりにCPUが使われるといった感じです!

qwerty2501 commented 1 year ago

@Hiroshiba RustのDirectMLでCPU使用率が上がる件これが関係してるかもです

~~https://github.com/VOICEVOX/voicevox_core/issues/227#issuecomment-1210155895 ただ、GPU使用率が全く上がってない状態であれば原因は別にありそうですが~~

qwerty2501 commented 1 year ago

改めてコード見た感じだとRust版はこれが抜けてるようなのでそれが原因かも https://github.com/VOICEVOX/voicevox_core/blob/0.12.5/core/src/core.cpp#L98 ただこれ、 dml_provider_factory.h というヘッダーに定義されてるものでいまのonnxruntime-rsにはないものでコード生成から作らないといけなさそうです

qryxip commented 1 year ago

LinuxのGPUですが、古いlibonnxruntimeproviders{cuda,shared}.soを読んでいただけだったのでORT 1.11.1のに入れかえたら普通に動きました。

https://github.com/VOICEVOX/voicevox_core/issues/227#issuecomment-1211047690

Hiroshiba commented 1 year ago

検証ありがとうございます! 認識合ってるか確認なのですが、core.zipにはlibonnxruntime_providers_*.soも一緒に配布したほうが良いって感じで合ってそうでしょうか 👀

qryxip commented 1 year ago

はい。coreのリリースにはWindows版と同様にlibonnxruntime_providers_*.soを同梱した方がよいと思います。

qwerty2501 commented 1 year ago

windowsでDLLコピーせずに動くようにする

これは解決したはず

sevenc-nanashi commented 1 year ago

0.13.0-rustで動作確認してきました。 句読点が無視されてそう。 エディタ生成 コア生成

コア生成のコードはこれです。雰囲気で読めると思います。 https://github.com/sevenc-nanashi/voicevox.rb/blob/main/examples/repl_core.rb

また、複数回生成させるとバグりました。(initialize->voicevox_tts->voicevox_tts) 自分のFFI実装が間違ってる可能性もあります。 https://cdn.discordapp.com/attachments/893889888208977960/1007930899939201074/163828_2.wav

== 初期化中... 完了
> 同じ、文章、です。完全に、同一です。
生成中... 完了:144940バイト、アドレス:3c925f68
> 同じ、文章、です。完全に、同一です。
生成中... 完了:415276バイト、アドレス:e8eed00
qwerty2501 commented 1 year ago

Rust側のテストコードでも確認しました。なんかサイズが増えているっぽい?

    #[rstest]
    #[async_std::test]
    async fn voicevox_tts_loop_works() {
        let internal = Internal::new_with_mutex();
        internal.lock().unwrap().initialize(false, 0, true).unwrap();
        let open_jtalk_dic_dir = download_open_jtalk_dict_if_no_exists().await;
        internal
            .lock()
            .unwrap()
            .voicevox_load_openjtalk_dict(open_jtalk_dic_dir.to_str().unwrap())
            .unwrap();
        let text = "同じ、文章、です。完全に、同一です。";
        let first_tts_wav = internal.lock().unwrap().voicevox_tts(text, 1).unwrap();
        assert_ne!(0, first_tts_wav.len());

        for i in 0..3 {
            let wav = internal.lock().unwrap().voicevox_tts(text, 1).unwrap();
            assert_eq!(first_tts_wav.len(), wav.len(), "index:{i}");
        }
    }

結果

> cargo test -- voicevox_tts_loop_works
   Compiling voicevox_core v0.1.0 (/home/qwerty2501/projects/qwerty2501/voicevox_core/crates/voicevox_core)
    Finished test [unoptimized + debuginfo] target(s) in 6.15s
     Running unittests src/lib.rs (target/debug/deps/core-0c73abe9c87fb1c8)

running 1 test
test internal::tests::voicevox_tts_loop_works ... FAILED

failures:

---- internal::tests::voicevox_tts_loop_works stdout ----
-------------- TEST START --------------
thread 'internal::tests::voicevox_tts_loop_works' panicked at 'assertion failed: `(left == right)`: index:0

Diff < left / right > :
<164396
>477740

', crates/voicevox_core/src/internal.rs:747:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    internal::tests::voicevox_tts_loop_works

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 72 filtered out; finished in 6.58s
qwerty2501 commented 1 year ago

ちょっとconfigure.pyについて考えていることがあるのでコメントに残しておきます

  1. configure.py修正前にreleasesにcuda,directmlの全部入り版のzipも提供するようにしたほうが良いと思います。そうすればconfigure.pyの処理は指定したものをダウンロードして展開するだけになるので処理の簡略化ができますし、configure.pyを使わない人に対しても環境を用意する手間を省けるようにできます。
  2. 1に対応してreleasesでダウンロードするだけで良くなった場合、configure.pyは必要なのだろうか?とちょっと思ってます。またダウンロード用のscriptを提供するにしてもpythonが環境にない人のためにunix系はsh, Windowsにはpowershellのスクリプトを提供したほうが良いのではないでしょうか。2つスクリプトをメンテする必要が出てきますが、1に対応していればダウンロードしてファイル展開する程度の処理なのでそこまでメンテ性が悪くないと思います。特にWindowsについてはpythonをインストールしていない人はそれなりにいると思いますので
Hiroshiba commented 1 year ago

提案ごもっともだと思います。手軽に使えるようにするためには、エンジンやエディタと同様に、全部入りを配布するのが手っ取り早いと思います。

cuda,directmlの全部入り版のzip

releasesに載せられるファイルの最大である2GBを超す可能性があり、分割が必要で結構リリースが複雑になります。 実際linuxのエンジンは1GBごとに分割してリリースしています。

discordでは避けたい旨を伝えたかもですが、7zにして配布すればそこまで手間ではないかもと思いました!

追記:あ、でもディストリビューションごとに×3個とかになると、releasesに大量にファイルが並んで結局使い勝手が落ちるかもですね・・・。 ダウンロードスクリプトのほうが使い勝手が良い気がしてきました。。

qwerty2501 commented 1 year ago

cudaがサイズ大きいのでcudaを特別扱いし、サイズが許容できないサイズになりそうであればcoreが入ったzipとcuda関連のライブラリが入ったzipに分けるで良いような気がします。 7zにするとユーザーの使い勝手もあまりよくなさそうですし。 cuda版分けることになったらダウンロードスクリプトあったほうが良さそうですね。

Hiroshiba commented 1 year ago

CUDAをダウンロード形式にすると、あと別パッケージが必要なのはDirectMLだけなので、そっちもダウンロードで良いかもとちょっと思いました・・・!

qwerty2501 commented 1 year ago

DirectMLについてはかなりサイズが小さそう?なので一緒にダウンロードで良いかなと思ってます

qwerty2501 commented 1 year ago

@Hiroshiba cudaのzip分けるか分けないか判断する参考にしたいのですが、具体的にどの程度のサイズを超えたら分けたほうが良いと考えてますか?

Hiroshiba commented 1 year ago

1.3GBくらいを超えると怖い(避けたい)、1.5GB超えるとだいぶ怖い、という感覚です。

そういえば、CUDA版が必要なのはlinuxだけかなと思うのですが、linuxだとたしかaptとかyumでCUDA入れられるはずです。 同梱するよりパッケージ管理ツールでインストールしてもらったほうがユーザー的には試しやすいかもとちょっと思いました。

qwerty2501 commented 1 year ago

同梱させる場合でもこれまで通りのcoreとonnxruntimeのみのzipもmin版として提供させます。これはDirectML版でも同様

qwerty2501 commented 1 year ago

既存のものでcuda関連のもの含めてzip化してみたんですが余裕で1.5GB超えたんでやはり分けたほうが良さそうです

Hiroshiba commented 1 year ago

おーーー・・・なるほどです! 検証たすかります!!

qwerty2501 commented 1 year ago

DirectMLについてはGPU使えるようになった?はずなのでどなたか確認お願いします

Hiroshiba commented 1 year ago

DirectMLについてはGPU使えるようになった?はずなのでどなたか確認お願いします

確認してみたところ、エラーが発生したっぽいので報告します。

Exception: modelデータ読み込み中にOnnxruntimeエラーが発生しました,Failed to create session: Error calling ONNX Runtime C function and failed to convert error message to UTF-8 というエラーでした。 (python exampleを用いています。)

Hiroshiba commented 1 year ago

CUDA版でも試してみたところ、こんな感じのエラーが表示されました。

Exception: modelデータ読み込み中にOnnxruntimeエラーが発生しました,Failed to create session options: Error calling ONNX Runtime C function: OrtSessionOptionsAppendExecutionProvider_Cuda: Failed to load shared library

一応、同じディレクトリ内にあるdllの一覧はこちらです。

$ ls *.dll
core.dll*         onnxruntime_providers_cuda.dll*    onnxruntime_providers_tensorrt.dll*
onnxruntime.dll*  onnxruntime_providers_shared.dll*

(追記)あ!これ普通にCUDA系のdllがないからなだけかも・・・。

qwerty2501 commented 1 year ago

Exception: modelデータ読み込み中にOnnxruntimeエラーが発生しました,Failed to create session: Error calling ONNX Runtime C function and failed to convert error message to UTF-8 というエラーでした。

エラーメッセージの取得に失敗してるようなのでまずそこを直してなぜ失敗してるかわかるようにしないといけないかもです

今わかってることを整理すると、 ここ でエラーが発生しているということはわかっています。またこの実装ですが他のort 呼び出しと違って OrtApiから呼び出しを行っていないです。他のAPIだと このように OrtApiオブジェクトから呼び出しを行っています。 しかしなぜ OrtSessionOptionsAppendExecutionProvider_DML は OrtApiオブジェクトから呼び出しを行っていないかというと、自動生成したコードでは OrtApi中にOrtSessionOptionsAppendExecutionProvider_DMLが含まれていなかったためです。(OrtApiは自動生成したコードです)

CUDA版についてはdllが足りないかもですね ちなみにDirectML版ではdll隣に置いてあげて確認してました?

qryxip commented 1 year ago

and failed to convert error message to UTF-8 (IntoStringError)についてはCP932案件でしょうかね...?

qwerty2501 commented 1 year ago

@qryxip そのあたりは ここ のCStringからStringに変換する際のエラーなので単純に無効なデータ渡されたらこのエラーが出るようです。 CP932かもしれませんが statusからResultに変換する際のGetErrorMessage で無効なデータが返されているだけかもしれません。

qryxip commented 1 year ago

エラーメッセージをdbg!するのを用意してみました。これでメッセージが何なのかはわかるはずだと思います。

https://github.com/qryxip/onnxruntime-rs/commit/b8f9aad523e412a270e3a0e53cd61c9f65e5f93d

voicevox_core/crates/voicevox_core/Cargo.toml:

 derive-getters = "0.2.0"
 derive-new = "0.5.9"
 once_cell = "1.10.0"
-onnxruntime = { git = "https://github.com/VOICEVOX/onnxruntime-rs.git", version = "0.1.0" }
+onnxruntime = { git = "https://github.com/qryxip/onnxruntime-rs.git", rev = "b8f9aad523e412a270e3a0e53cd61c9f65e5f93d" }
 serde = { version = "1.0.143", features = ["derive"] }
 serde_json = "1.0.83"
 thiserror = "1.0.32"
Hiroshiba commented 1 year ago

DirectML版が動かない件について調べたところ、対応するDirectML.dllがなかったため発生していたエラーなようでした。 python example内に対応するDirectML.dllを配置し、CDLL(str(Path("DirectML.dll").resolve(strict=True)))を追加して明示的に読み込むことで普通に実行できました!

UTF-8エラーが出る周りに関してもうちょっと調べてみました。 まず、DirectML.dllがtarget/debug/depsにない場合はRustのテストももちろん落ちるのですが、そのときのload_modelのエラーはこんな感じで、UTF-8に無関係そうに見えました。(見やすいように改行しています)

thread 'publish::tests::is_model_loaded_works::case_1' panicked at 'called 
`Result::unwrap()` on an `Err` value: LoadModel(SourceError(Failed to create session: 
Error calling ONNX Runtime C function: Exception during initialization: ))', 
crates\voicevox_core\src\publish.rs:612:57

じゃあなんでpython上でcore.dllを使う形だとエラーが出るのかですが・・・actionsやwindows環境といった要因が絡んでややこしいのと、python上で動かさない限りエラーは出ない気がするのと、もうエラーが出る原因がわかったのとで、まあ調査しなくてもいいかなという気持ちが正直なところです・・・!

qwerty2501 commented 1 year ago

まあ動いたんでいいんじゃないですか