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

モデル読み込みをlazyにしたい #116

Closed
Hiroshiba opened this issue Apr 16, 2022 · 6 comments
Closed

モデル読み込みをlazyにしたい #116

Hiroshiba opened this issue Apr 16, 2022 · 6 comments

Comments

@Hiroshiba
Copy link
Member

内容

で複数モデルを読み込めるようになりました。
initializeが呼ばれたタイミングで全部loadされています。
実際に製品版では複数のモデルを読み込んでいますが、そのせいでinitializeが遅く(とくにmacでは20秒近くかかる)なっています。

全部loadする必要があるユーザーは珍しく、使わないキャラクターのモデルはloadしなくて良いはずです。
なので、必要になったタイミングでモデルをロードできる設計にしたいです。

Pros 良くなる点

起動が早くなる

Cons 悪くなる点

APIを変えないといけないかも

実現方法

2つあると思います。

1つ目が、forwardするタイミングで、modelがloadされていなかったらloadする方法です。
この方法だとAPIは変わりませんが、forwardしたときに初回だけは遅いという副作用が生じます。

2つ目が、model(もしくはspeaker_id)を指定してmodelをloadするAPIと、load済みかを返すAPIを用意し、毎回エンジンなどから実行してもらう方法です。
この方法はモデルをloadするタイミングをアプリ側で制御できます(例えばキャラが選ばれたタイミングからloadし始めるということもできる)が、APIの変更が生じます。

どっちも実装するのもありかも。

その他

そろそろ4期生が現れてくるタイミングです。
更に起動時間が長くなってしまいそうなので、できればそれまでに実装しておきたいです・・・!

@qwerty2501
Copy link
Contributor

実装難度はかなり高いですが、3案目としてloadを非同期にすることにより体感速度をかなり向上させることができるようになるはずです

Pros 良くなる点

起動が早くなる
かつ初回forward時の遅延も可能な限り軽減できる

Cons 悪くなる点

実装難度が高い

実現方法

まず start_async_load(speaker_id) といった感じの非同期にモデルのloadを開始する関数を作ります。
この関数はloadの開始のみを行いloadが完了していない状態でreturnされるようにします。各speakerのモデルload状態はライブラリ内に保持します。
各forward系関数の内部実装でモデルのload状態を次のように判定します

  • モデルのload開始自体が行われていない -> エラーとして返すか、内部でloadを同期的に実行するただ同期的に実行すると遅くなってしまうのでエラーとして返して start_async_load を事前に呼び出すことを促したほうが良いかも
  • モデルのloadが開始されてるが完了していない -> 完了するまで待機し、完了次第処理を続行する
  • モデルのloadが完了している -> そのまま処理を続行する

2案目のようにload済みか返すAPIを定義しても良いですが、なくてもライブラリ機能は使うことができるかと
start_async_load を各アプリケーションの要所要所で読んでもらうようにします。アプリケーション起動時に全speaker分呼んでもよし、Voicevoxならプロジェクトを読み込んだときあるいは使用するspeakerを新たに追加したときなどに必要な分だけ呼んでもらってもよしでユーザーに対するアプリケーション体験を向上する際にチューニングしやすくします。

既存の initialize についてですが、残すのであれば同期的に呼び出しをするようにしたままにする必要があります。が、新しいアプローチでは使用しないので互換性を気にしないのであれば消してしまっても良いかもです

実装にあたっては各load状態が破壊されないように適切にlockなどを行う必要があると思われるのでかなり難しいです

@qwerty2501
Copy link
Contributor

改めてコード読んでみたのですが、initializeではspeakerのload以外にもやってることがありそうだったので残す必要がありそうですね

@Hiroshiba
Copy link
Member Author

たしかに非同期にできるとさらに使い勝手が上がるかなと思いました!
どうしても非同期に実行したい場合は使う側で行うことも可能だと思うのと、仰る通り実装難度が高そうなので、いったんlazyにするだけでも良いかなと思いました。

@Hiroshiba
Copy link
Member Author

Hiroshiba commented May 4, 2022

こちら、いったん取り組んでみたいと思います!
非同期は置いておいて、とりあえず方針1, 2をどちらも実装する予定です。

@Hiroshiba
Copy link
Member Author

Hiroshiba commented May 4, 2022

↑「forwardするタイミングでmodelがloadされていなかったらloadする」は一旦未実装です。
(コードと仕様が煩雑になる割に需要がそこまで無い気がしたので)

@Hiroshiba
Copy link
Member Author

とりあえず、モデル読み込みを分割できるようになったので、閉じたいと思います!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants