Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initializeで全モデルを読み込まなくても良いようにした #124

Merged
merged 10 commits into from
May 9, 2022
Merged

initializeで全モデルを読み込まなくても良いようにした #124

merged 10 commits into from
May 9, 2022

Conversation

Hiroshiba
Copy link
Member

内容

最初に全モデルを読み込まなくても起動できるようにしました。
必要なキャラクターだけloadしたり、必要になったタイミングでloadしたりできるようになります。

関連 Issue

その他

少しリファクタリングが入っているので変更行が少し多めになってしまいました。
リファクタリング箇所だけ別PRにすることも可能です。

Comment on lines -22 to +23
#define NOT_FOUND_ERR "No such file or directory: "
#define FAILED_TO_OPEN_MODEL_ERR "Unable to open model files."
#define FAILED_TO_OPEN_METAS_ERR "Unable to open metas.json."
#define NOT_LOADED_ERR "Model is not loaded."
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

消したのは未使用のエラーメッセージ

Comment on lines +45 to +57
/**
* 3種類のモデルを一纏めにしたもの
*/
struct VVMODEL {
embed::EMBED_RES (*YUKARIN_S)();
embed::EMBED_RES (*YUKARIN_SA)();
embed::EMBED_RES (*DECODE)();
} MODELS_LIST[] = {{YUKARIN_S, YUKARIN_SA, DECODE}};
};
const VVMODEL VVMODEL_LIST[] = {
{YUKARIN_S, YUKARIN_SA, DECODE},
};
} // namespace EMBED_DECL_NAMESPACE
using EMBED_DECL_NAMESPACE::MODELS_LIST;
using EMBED_DECL_NAMESPACE::VVMODEL_LIST;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

今まではMODELS={YUKARIN_S, YUKARIN_SA, DECODE}という命名規則でしたが、話者ごとのmodelsなのかyukarin_s/saなどのmodelsなのか分かりづらかったので、VVMODEL={YUKARIN_S, YUKARIN_SA, DECODE}という形にしました。

session_options.AppendExecutionProvider_CUDA(cuda_options);
#endif
}
}
Copy link
Member Author

@Hiroshiba Hiroshiba May 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use_gpuはSTATUSの初期化時に、cpu_num_threadsはモデルロード時に指定だったのを、どちらも初期化時に指定する形式に変更しました。

core/src/core.h Show resolved Hide resolved
core/src/core.h Outdated
* @return 成功したらtrue、失敗したらfalse
* @detail
* 何度も実行可能。use_gpuを変更して実行しなおすことも可能。
* 最後に実行したuse_gpuに従って他の関数が実行される。
*/
VOICEVOX_CORE_API bool initialize(bool use_gpu, int cpu_num_threads = 0);
VOICEVOX_CORE_API bool initialize(bool use_gpu, int cpu_num_threads = 0, bool load_all_models = true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#122 の通りCではデフォルト引数が使えないので使用は避けたほうが良いです。
次にデフォルト引数をつかっても関数のシグネチャは bool initialize(bool,int,bool) になってしまうためABI互換性が破壊されると思います。互換性を保つことを意図してるのであればinitiaize関数の宣言はこのままにし、新しい名前のinitialize関数を定義したほうが良いでしょう
互換性保たない方針にするのであればこれについてもprefix voicevox をつけたほうが良いと思います。

Copy link
Member Author

@Hiroshiba Hiroshiba May 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

名前の違う似た動作をするinitialize関数が2つあると混乱しそうなので避けたいです。
引数が1つ、2つ、3つの関数をそれぞれ定義するのが良いのかなと感じました。
別PRでも良さそうですが、どうでしょう…?👀

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

実はCにはoverloadがないんですよ。initializeは extern "C" 内に宣言されてるのでそれをやろうとするとコンパイルエラーになるはずです

Copy link
Member Author

@Hiroshiba Hiroshiba May 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

なんと・・・。
じゃあ・・・互換性を捨てますか・・・。

今回はvoicevox_のprefixを付けることで別関数を定義できますが、今後引数が増えるたびに考える必要があって開発が大変そうです。
コアを利用するニーズを加味して、引数を増やしたときの互換性は考えない(再コンパイルが必要な)ようにする方針で進めようかと思いました。

(以前もABI互換性などで議論があった記憶がありますが、もしそのときの判断と異なっていそうであればコメントいただけると助かります。)

voicevox_prefixを付けるのは別のPRで行いたいと思います!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ABI互換性は捨ててよいとは思いますが、コードをなるべく書き換えないように努めたほうが良さそうですね。リファクタリングの範疇になりますが。
リファクタリングといえば、initialize等古い関数は戻り値をboolではなくVoicevoxResultCodeに変えたい気持ちはありますね。これをすることによって last_error_message関数への依存を減らせますし

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VoicevoxResultCode統一、良さそうです!

Copy link
Contributor

@qwerty2501 qwerty2501 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

local変数にOrt::SessionをmoveしてしまうとSessionの所有権がlocal変数に対して移動してしまうのでscopeを抜ける際にそのlocal変数にあるSessionが開放されてしまうので次にそのmodelのSessionを使用する際に何らかの問題が発生する恐れがあるためmoveはしないほうが良いです
おそらくOrt::Sessionがコピー不可であるためこのようにしていると思いますが、コピー不可になっているのはそれなりの理由があります。

core/src/core.cpp Outdated Show resolved Hide resolved
core/src/core.cpp Outdated Show resolved Hide resolved
core/src/core.cpp Outdated Show resolved Hide resolved
Comment on lines +84 to +100
Status(int model_count, bool use_gpu, int cpu_num_threads)
: memory_info(Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU)) {
yukarin_s_list = std::vector<std::optional<Ort::Session>>(model_count);
yukarin_sa_list = std::vector<std::optional<Ort::Session>>(model_count);
decode_list = std::vector<std::optional<Ort::Session>>(model_count);

session_options.SetInterOpNumThreads(cpu_num_threads).SetIntraOpNumThreads(cpu_num_threads);
if (use_gpu) {
#ifdef DIRECTML
session_options.DisableMemPattern().SetExecutionMode(ExecutionMode::ORT_SEQUENTIAL);
Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_DML(session_options, 0));
#else
const OrtCUDAProviderOptions cuda_options;
session_options.AppendExecutionProvider_CUDA(cuda_options);
#endif
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C++ではコンストラクタ内で例外が発生するとclass及びstructのfieldで確保されているリソースが開放されないためメモリリーク等の問題が起きます。そのためC++でのコンストラクタでは基本的にfieldの初期化のみ程度に留めるべきです。
Ort系の処理では例外が発生する可能性があるためこの処理はコンストラクタで行うべきではないでしょう。
そのためこのコンストラクタの処理をstaticメンバ関数にしたほうが望ましいです

Copy link
Member Author

@Hiroshiba Hiroshiba May 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

なるほどです。
まあエラーが出たらそもそもこのライブラリが動かない(のでプロセスキルするはず)ので、そこまで気にしなくても良いのかなと思いました・・・!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

コンストラク内の例外でメモリリークが発生してしまうのはデストラクタが呼ばれないからで、例外処理をきちんと書いていればメモリリークは起きません。
コンストラクタ外でメモリ確保をしても例外処理を書かなければメモリリークになるので、エラーハンドリングをしっかりしないなら何処に書いても変わらないと思われます。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

コンストラク内の例外でメモリリークが発生してしまうのはデストラクタが呼ばれないからで、例外処理をきちんと書いていればメモリリークは起きません。

はい。正確にはデストラクタが呼ばれないですね。

コンストラクタ外でメモリ確保をしても例外処理を書かなければメモリリークになるので、エラーハンドリングをしっかりしないなら何処に書いても変わらないと思われます。

今回のケースだとリソースは各classのデストラクタで管理されているのでコンストラクタ外で処理を書けば例外が発生した場合各classのデストラクタが呼び出されるのでメモリリークは発生しないはずですね。
これが例えばStatusのフィールドで明示的に管理するリソースがあって、Status自身のデストラクタで開放しているのであればメモリリークする可能性はありますが。今回はStatus classとして明示的にデストラクタで開放してるフィールドは無いようなので
コンストラクタ外で処理を書けばメモリリークにはならないはずですが、Hihoさんがおっしゃるとおりライブラリが動かかないのでそもそもここを気にしてもあまり意味がないというのはあります。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

すみませんコンストラクタ周りの仕様についてちょっと勘違いしていたらしく、そもそもこの実装のままでも各フィールドのデストラクタは呼ばれそうです...?
https://clown.cube-soft.jp/entry/20110320/1300596620

コンストラクタで例外が発生した場合,そのクラス自体のデストラクタは実行されませんが,(初期化の終了した)メンバ変数のデストラクタは実行されます.したがって,例えば new でメモリを確保するようなメンバ変数の場合は,スマート・ポインタで保持しておく事によってその部分のリソース開放が自動的に行われ,リソースの開放忘れのかなりの部分を防ぐ事ができます.

このままにするとのことだったのであまり意味のない情報ですが

@Hiroshiba
Copy link
Member Author

@Yosshi999 さん、@Oyaki122 さん、もしよかったらレビューいただけると心強いです・・・!

@qwerty2501 qwerty2501 mentioned this pull request May 9, 2022
@Hiroshiba
Copy link
Member Author

多分大丈夫だと思うのでマージします!

@Hiroshiba Hiroshiba merged commit c66081e into VOICEVOX:main May 9, 2022
@Hiroshiba Hiroshiba deleted the モデル読み込みをlazyにする branch May 9, 2022 15:10
PickledChair pushed a commit that referenced this pull request Jul 24, 2022
* デフォルト引数はC言語では使えないのでC++のみに有効になるように変更した (#122)

本当はデフォルト引数を消したかったが、使ってる人がいる可能性があるためC++で使ってる場合はそのままにするように修正した

* initializeで全モデルを読み込まなくても良いようにした (#124)

* load_model関数を切り出す

* load_modelとis_model_loadedを足した

* 使われてないエラーメッセージを消去

* Update core/src/core.cpp

Co-authored-by: qwerty2501 <[email protected]>

* Update core/src/core.cpp

Co-authored-by: qwerty2501 <[email protected]>

* Update core/src/core.cpp

Co-authored-by: qwerty2501 <[email protected]>

* pythonのラッパーの型を変更

* load_all_models追加

* return true

Co-authored-by: qwerty2501 <[email protected]>

* workflow_dispatchでもビルド開始可能に (#127)

* ビルド時にREADMEファイルを追加する (#131)

* append unit testing framework (#121)

* Catch2をプロジェクト導入して参考となる1ケースを追加した

* リリース用ビルドにはテストビルドは不要のため無効化する変数を追加した

* テストコードの短縮化を行った

* READMEにテスト実行方法を追加

* テストをビルドするかどうかのフラグをデフォルトOFFにした

* テストをビルドするかどうかのフラグを変更したことによりREADMEを修正

* MSVCに対して足りないオプションを追加

- utf8文字列でコンパイルするように指定
- C++20を明示的に指定
- __cplusplusの値を利用中のC++のバージョンに合わせるように指定(ないとC++98相当になるとか)

* Configがリリースの場合のみに最適化オプションを指定するように修正

* オプションの指定を短くまとめた

* coreの標準ライブラリもバージョンアップした

* compile optionsの修正

* Catch2にもCXX_STANDARD 20を追加

* Windows環境でビルドできるように設定を修正

#121 (comment)

* format 効いてしまっていたところを修正

* static castやnullopt比較をやめ、value関数などを使うようにする (#118)

* use value and has value

* remove has_value

* coreのビルド時にバージョン情報がちゃんと
入るようにする

* hotfix イントネーションの推論をCPUで行うように (#146)

* python example for 0.12, update FFI (#138)

* .gitignore open_jtalk_dic in example (#148)

* .gitignore open_jtalk_dic in example

* modify: example/python/.gitignore

* C++サンプルコードへのリンクを追加 (#142)

* C++サンプルコードへのリンクを追加

* #readme

* Update README.md

* コード署名できるようにする (#164)

* コード署名

* build_util

* artifact/

* a

* remove

* inputのbooleanは文字列として渡ってくるので判定を修正 (#166)

* inputのbooleanは文字列として渡ってくるので判定を修正

* 修正もれ

Co-authored-by: Hiroshiba <[email protected]>
Co-authored-by: Yuto Ashida <[email protected]>
Co-authored-by: Yosshi999 <[email protected]>
Co-authored-by: nebocco <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants