Skip to content

Conversation

@y-chan
Copy link
Member

@y-chan y-chan commented Mar 13, 2022

内容

SynthesisEngine初期化時に、OpenJTalkも同時に初期化するようにし、辞書のロードは後から行える(辞書のロードをしなくてもSynthesisEngine内の関数にアクセスできる)ようにします。
現状のままでも辞書のロードをしなくともSynthesisEngine内の関数にアクセスできますが、OpenJTalk自体や、辞書の読み込み状況などの取り回しが若干面倒だったのと、TODOを解決する目的で、このような変更を加えました。
これによるC APIユーザー側から見た挙動の変化は特にありません。

static std::shared_ptr<OpenJTalk> openjtalk;
static std::unique_ptr<SynthesisEngine> engine;

VoicevoxResultCode voicevox_initialize_openjtalk(const char *dict_path) {
Copy link
Contributor

Choose a reason for hiding this comment

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

この処理内容だと初期化してるのはopenjtalkではなくengineなので関数名変えたほうが良いと思います。

Copy link
Member Author

Choose a reason for hiding this comment

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

確かに...!
まだプレビュービルドしか存在してないですし、APIの互換性を破棄しても大丈夫でしょう...
そもそもやりたいのはopenjtalkの辞書の読み込みなので、初期化というよりも辞書のロードである節を明確化する意味も込めてvoicevox_load_openjtalk_dictionaryとかにすると良いかもと思いました。どうでしょうか?

Copy link
Contributor

Choose a reason for hiding this comment

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

確かにやってることはopenjtalkの辞書読み込みですが、ライブラリユーザー側からすると求めていることってopenjtalkの辞書読み込みではなくengineを使える状態にするではないでしょうか? 🤔
また内部でopenjtalkとengineを生成しているのでその関数名では中の処理を適切に説明できていないと思います。加えて例えばengineで使っている機能が増えて初期化時にやりたいことが増えた場合関数名が限定的にされているため別にその初期化関数を定義しなければならなくなるでしょう。これは呼び出し側でやることが増えてしまうので避けたほうが良いように感じます。

私案ですが以下のような感じの関数が良いかなと思いました。ただこの案だとengine初期化時に必要な引数が増えた場合対応しづらいという問題はありますが。(関数定義が変わってdllを通しての呼び出しだと再コンパイルが必要になるため)

Suggested change
VoicevoxResultCode voicevox_initialize_openjtalk(const char *dict_path) {
VoicevoxResultCode voicevox_initialize_engine(const char *openjtalk_dict_path) {

Copy link
Member Author

@y-chan y-chan Mar 14, 2022

Choose a reason for hiding this comment

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

ライブラリユーザー側からすると求めていることってopenjtalkの辞書読み込みではなくengineを使える状態にするではないでしょうか?🤔

確かに、現状はそうなっていますね。
将来的に、AquesTalkライク記法によるTTS関数などを実装すると、それを実行する際はあらかじめエンジンを初期化して辞書をロードしておくことは不要(今までのvoicevox_tts関数の実装みたく、エンジンがグローバルに存在しなければif文で分岐して初期化するようにすればいい)になるはずなので、voicevox_initialize_engineだと誤解を生んでしまうように思っています(AquesTalkライク記法が使える未来では、全ての場合においてSynthesisEngineの初期化+辞書のロード==engineを使える状態にするではないからです)。

以上のことを踏まえて、voicevox_load_openjtalk_dictionaryといった、辞書の読み込みであることを明確化した関数名にすべきと私は考えているのですが、改めてどうでしょうか...?

Copy link
Contributor

Choose a reason for hiding this comment

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

なるほど辞書読み込まない場合もありえるんですね。

エンジンがグローバルに存在しなければif文で分岐して初期化するようにすればいい

非同期で voicevox_tts が呼ばれた場合二重に初期化されてしまう問題がありますね。きちんとしたSingletonを実装し、lockを適切に行えば解決はできそうですが。

関数名については異論はありません

Copy link
Member Author

Choose a reason for hiding this comment

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

非同期で voicevox_tts が呼ばれた場合二重に初期化されてしまう問題があり

なるほど、確かにありえそうですが、これはまた別のPRに分けるべきですね。
(あまり詳しくないので、できればお任せしたいなと思います👀)

VoicevoxResultCode voicevox_tts(const char *text, int64_t speaker_id, int *output_binary_size, uint8_t **output_wav) {
if (!openjtalk) {
if (!engine || !engine->is_openjtalk_dict_loaded()) {
return VOICEVOX_RESULT_NOT_INITIALIZE_OPEN_JTALK_ERR;
Copy link
Contributor

Choose a reason for hiding this comment

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

ここですがエラーをエンジンの未初期化エラーとOpenJTalkの辞書未読み込みエラーに分けたほうが良いのでは。
また VOICEVOX_RESULT_NOT_INITIALIZE_OPEN_JTALK_ERRについてですがエンジン初期化時にOpenJTalkも初期化されるので不要になってると思うので消したほうが良いように感じました。

Copy link
Member Author

Choose a reason for hiding this comment

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

確かにそうですね...
特に何も考えず既存のコードを流用していましたが、変更してみます...!

Copy link
Member Author

@y-chan y-chan Mar 14, 2022

Choose a reason for hiding this comment

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

少し考えたのですが、最初からSynthesisEngineを初期化しておくのはどうでしょうか...?

static std::unique_ptr<SynthesisEngine> engine = std::make_unique<SynthesisEngine>();

こうすれば、先ほど懸念があった非同期実行時等にSynthesisEngineが2重以上に初期化されることはないでしょうし、エンジンの未初期化エラーを用意する必要もなくなります(辞書が2重以上にロードされる可能性は否めませんが)。

(将来的に実装されるAquesTalkライク記法のTTS関数ではSynthesisEngineは勝手に初期化される仕様にしますが、それだとOpenJTalkを利用する際にエンジン未初期化エラーが出るのは変ですし、SynthesisEngineのみを初期化する関数はそもそも用意してないため、そのような解決策が不明なエラーが出るのはおかしいように思ったのでこのような提案をさせてもらいました)

Copy link
Contributor

@qwerty2501 qwerty2501 Mar 14, 2022

Choose a reason for hiding this comment

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

そのアプローチもありだとは思いますが、SynthesisEngine使ってない場合でもSynthesisEngineが初期化されてしまうのでその分計算リソースとheapリソースが消費されます。
現状voicevox engineだとcore側のSynthesisEngineは使ってないはずなのでその分余分にリソースを消費してしまいます。
また初めから初期化する場合はunique_ptrは不要で以下で良いと思います

static SynthesisEngine engine;

Copy link
Member Author

@y-chan y-chan Mar 14, 2022

Choose a reason for hiding this comment

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

なるほど。確かに使わない際は無駄ではありますね。
個人的な考えとしては、公式のPython実装や任意のサードバーティ実装のエンジンを使うような場合を除いて、ほぼ確実にtts系関数を使うことになるので気にしないかなというのと、メインの機械学習モデルやら辞書やらの方が圧倒的にリソースを食うので、過度にリソースを気にすることはないかなと思っています。
@Hiroshiba どうでしょうか...

Copy link
Contributor

Choose a reason for hiding this comment

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

そうですね。engine初期化済みにするのであればエンジン未初期化エラーは発生し得ないかなと思います。
そもそも私が書いたコードにするのであればengineが未初期化かどうか判定することもできないかと思いますので

Copy link
Member

Choose a reason for hiding this comment

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

ちょっと正確に把握していないのですが、SynthesisEngineの初期化を遅延させるかさせないかは、ぶっちゃけどっちでも良い気がしました!

音声を生成するとき、1秒辺り24000*4B=94KBを必ず消費します。生成するとなるともっと消費します。
おそらくSynthesisEngineの初期化だけなら1KBもかからないので、どっちでも良いと思います。
強いて言うなら今は開発速度を早くしたいので、最初から初期化しちゃうほうが関数が少なく実装コストも少し小さいのかなと思いました!

Copy link
Contributor

Choose a reason for hiding this comment

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

coreの読み込みが少し遅くなっちゃうんですが、そのあたりも問題ないですかね?

Copy link
Member

Choose a reason for hiding this comment

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

遅くなる時間にもよると思います。1秒以内とかなら全然問題ないかと…!

Copy link
Contributor

Choose a reason for hiding this comment

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

多分大丈夫だと思います!

@y-chan y-chan force-pushed the feature/move-openjtalk branch from d9e4bd9 to ad745e1 Compare March 14, 2022 10:22
@y-chan y-chan force-pushed the feature/move-openjtalk branch from ad745e1 to 4e6013a Compare March 14, 2022 10:35
@y-chan
Copy link
Member Author

y-chan commented Mar 15, 2022

リソース周りの問題は一旦そこまで気にしないということで、SynthesisEngineを最初から初期化するようにしました。
エラー周りの処理も修正しておきました。

Copy link
Member

@Hiroshiba Hiroshiba left a comment

Choose a reason for hiding this comment

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

LGTM!!

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.

LGTM

@y-chan
Copy link
Member Author

y-chan commented Mar 15, 2022

御二方からapprove頂いたので、セルフマージします...!

@y-chan y-chan merged commit 55c4e0a into VOICEVOX:cpp-library Mar 15, 2022
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.

4 participants