Open Hiroshiba opened 2 years ago
現状(0.9.3)だと、コアを1つのプロセスで複数loadすることができないのがかなり厄介です。 手としては
例えば0.9.3のコアと0.8.0のコアがあったとして、二つともengineからimportするのは難しいのでしょうか それともバイナリは統一して(暗号化された)モデル重みを二つ読み込みたいという考えでしょうか
2つともengineからimportするのが難しいと考えています。 (dllのことをよくわかっていないだけで、簡単に複数importできるのかもしれませんが)
具体的な障壁はどこになるのでしょうか 名称がかぶるのはimportlibで何とかなると思いますが、libtorchあたりを複数ロードするとクラッシュしうるみたいな話でしょうか そういえばpython.dllで立てたpythonインタプリタにnumpy載せると再ロード時にクラッシュするみたいな話があった気がします。このケースではマルチプロセスで何とかしました。やっていることは「プロキシ用のエンジンを起動」に近いですが、サブプロセスを建ててそこで 初めて import coreを行い、メイン(すなわちAPIサーバー)からはPipe で通信します。
具体的な障壁を洗い出すところからになると思います。 importlib等でなんとかなるのですね!
そういえばたしか、 @takana-v さんが実装されたCancelableEngineがすでにプロセス起動だった記憶があります。 どうでしょう、応用として取り組んで頂くことは可能でしょうか・・・? @takana-v
手が空いているので挑戦してみようと思います。 assignをお願いします。 (このリポジトリは権限ないのでassignできませんでした...)
ありがとうございます!! リポジトリに追加し忘れていたので追加してみました、アサインできそうでしょうか・・・?
このリポジトリだけできませんね... とりあえず @Hiroshiba さんの方でassignお願いします。
writeになっていませんでした・・・ assignしました、よろしくおねがいします!!
https://github.com/VOICEVOX/voicevox_engine/pull/214 とコンフリクトしそうなので、マージされ次第進めたいと思います。
windowsでは、core.zipを解凍したものにcore.pyd
を入れて、別プロセスで動かせば起動できそうです。
(linuxは恐らくcore.so
、macは未確認)
これらのファイルをどこで入手するか、要検討です。
エンジンのファイルをコピーすることも可能ですが、将来的にcore.pyx
に変更が入る可能性があるのが懸念点です。
なるほど、つまりバージョンXのcoreを動かすにはバージョンXのcore.pydが必要だけど、core.zipに梱包されていないということでしょうか。 たしかに、そこに課題があることを今把握しました!
core.pyx
を互換性もたせたまま開発するか、core.pyd
も同梱して配布するか、などが考えられるでしょうか。
core.pyx、つまりコアのインターフェイスが互換性なく変更されるときは、きっとエンジン側の処理も変わっており、過去のコアはそもそも使えなくなりそうかもです。 となると、互換性をもたせつつ開発することになると思うので、core.pyxは過去のコアライブラリにも対応し続けるという前提でも良いのかもと思いました。
どうでしょう・・・?
過去バージョンはどこまで対応すればいいでしょう?
などで問題が発生するかもしれません。
インターフェイスが変わっているととても大変ですが、たしか一応インターフェイスは変わっていないんですよね。 残っているdllは全部対応するくらいの意気込みで取り組んで、工数がかかってしまう過去バージョンはそのたびに取捨選択、というのはどうでしょう。
所管として、キャラクターの追加には対応できるようになっていると便利そうです。 スタイルが複数になってからのコアに対応できれば十分満足なのかなという感じです!
ちょっと詰まったので... pythonでは動くのですが、バイナリ化するとinitializeの時にエラーが出ます。 解決にはちょっと時間がかかりそうです。
PytorchStreamReader failed reading zip archive: failed finding central directory
Exception raised fr...
https://github.com/VOICEVOX/voicevox_engine/compare/master...takana-v:multi-core?expand=1
エラー内容的に、libtorchがモデルをロードする際のzip展開に失敗していそうです。
これは当てずっぽうの推測ですが、テストで使われているコアのdllと.binのバージョンが揃っていない可能性があるかもです。
もしvoicevox_dir
とold_voicelib_dir
に同じディレクトリを指定(同じバージョンのコアを利用)した状態で成功するなら、どこかでdllとディレクトリの関係がずれているのかも・・・?と思いました。
バイナリ化した場合、sys.pathを設定してもデフォルトのコアモジュールが読み込まれている気がします。 (0.9.0のコアで試したら動きました) https://nuitka.net/doc/user-manual.html#dynamic-sys-path
解決策がちょっと思いつきませんでした。 dllやsoを直接読み込む(multiprocessingは使わない)方針でチャレンジしてみたいと思います。
Linux版ですが、以下のようなプログラムで複数バージョンのcoreモジュールを扱えそうでした。 Windowsでも同じことができるかもです。
Ubuntu 20.04、Python 3.7.12、製品版0.7.5と0.8.2同梱のコアモジュール(core.so)とコアライブラリ(libcore.so、CPU版)で試しました。 製品版0.9.xはPython 3.8に上がっていて、コアモジュールを作り直す手間があったので試しませんでした...
# main.py
# force nuitka to include numpy
import numpy as np
# ---
from pathlib import Path
import importlib.util as imu
from ctypes import cdll
use_gpu = False
# VOICEVOX 0.7.5
# voicevox_dir (Python module directory)
core_a_root = Path('~/apps/voicevox_cpu-0.7.5/squashfs-root').expanduser()
# preload linked shared library
cdll.LoadLibrary(core_a_root / 'libcore.so')
# load core module
core_a_spec = imu.spec_from_file_location('core', core_a_root / 'core.so')
core_a = imu.module_from_spec(core_a_spec)
core_a_spec.loader.exec_module(core_a)
# voicelib_dir (*.bin, metas.json)
print(core_a_root)
core_a.initialize(core_a_root.as_posix() + '/', use_gpu)
print(core_a.metas())
# VOICEVOX 0.8.2
# voicevox_dir (Python module directory)
core_b_root = Path('~/apps/voicevox_cpu-0.8.2/squashfs-root').expanduser()
# preload linked shared library
cdll.LoadLibrary(core_b_root / 'libcore.so')
# load core module
core_b_spec = imu.spec_from_file_location('core', core_b_root / 'core.so')
core_b = imu.module_from_spec(core_b_spec)
core_b_spec.loader.exec_module(core_b)
# voicelib_dir (*.bin, metas.json)
print(core_b_root)
core_b.initialize(core_b_root.as_posix() + '/', use_gpu)
print(core_b.metas())
# source
python3 main.py
# binary
python3 -m nuitka --standalone --plugin-enable=numpy --follow-import-to=numpy --follow-imports --no-prefer-source-code main.py
$ ./main.dist/main
***/apps/voicevox_cpu-0.7.5/squashfs-root
[{"name":"四国めたん","speaker_uuid":"7ffcb7ce-00ec-4bdc-82cd-45a8889e43ff","styles":[{"id":0,"name":"あまあま"},{"id":2,"name":"ノーマル"},{"id":4,"name":"セクシー"},{"id":6,"name":"ツンツン"}],"version":"0.7.4"},{"name":"ずんだもん","speaker_uuid":"388f246b-8c41-4ac1-8e2d-5d79f3ff56d9","styles":[{"id":1,"name":"あまあま"},{"id":3,"name":"ノーマル"},{"id":5,"name":"セクシー"},{"id":7,"name":"ツンツン"}],"version":"0.7.4"}]
***/apps/voicevox_cpu-0.8.2/squashfs-root
[{"name":"四国めたん","speaker_uuid":"7ffcb7ce-00ec-4bdc-82cd-45a8889e43ff","styles":[{"id":0,"name":"あまあま"},{"id":2,"name":"ノーマル"},{"id":4,"name":"セクシー"},{"id":6,"name":"ツンツン"}],"version":"0.8.0"},{"name":"ずんだもん","speaker_uuid":"388f246b-8c41-4ac1-8e2d-5d79f3ff56d9","styles":[{"id":1,"name":"あまあま"},{"id":3,"name":"ノーマル"},{"id":5,"name":"セクシー"},{"id":7,"name":"ツンツン"}],"version":"0.8.0"}]
下からVOICEVOX-CPU.AppImage.7z.001
をダウンロードして展開、chmod +x
、./VOICEVOX.AppImage --appimage-extract
してsquashfs-root
を取り出せます。
私はdllのラッパーを書いて実装してみました。
https://github.com/takana-v/voicevox_engine/blob/42d91d5c47901739506a9a65f682dc7b2e8cf2db/voicevox_engine/synthesis_engine/core_wrapper.py
これでも一応動いています。
ただ、メインのコアに影響が出てるので、make_synthesis_engine
でcdll.LoadLibrary
する必要がありそうですが...
(プロセスを分けて隔離するのを考えていましたが@aoirint の実装を見てこっちの方がいいと感じました)
@aoirint の実装はコード量が少なくて済むので良さそうに感じました。 このプログラム、AppImage内からはextract不要で動きますか?
@takana-v
AppImage内からはextract不要で動きますか?
AppImageは実行時は/tmp以下にマウントされる(展開されたように見える)ようで、extract不要で動きます。
preset.yaml、話者情報コア移行以前のmetas.json、コア移行後のmetas.json、*.bin
も同様です(書き込みを伴う場合は調べてみないとわからないです..)。
@aoirint の実装と私の実装、どちらでも動きそうですね。 どっちで実装してPR送るか迷ってます。
どういう違いがあるのかわかっていませんでしたが、cython等で作ったcore.so
を使うか使わないかが大きな違いという認識で合っていますか?
であれば、仮に将来coreのインターフェイスが変わった場合、takana-vさんの案だとインターフェイスの分だけ実装や分岐が必要になる一方、aoirintさんの方だと統一で書けるので、aoirintさんの案だと将来的に楽なのかもと感じました。
ちなみに、あまり良くわかってないのですが、numpyへの型変換とかもやってくれるんでしょうか。 さすがにそこはラッパーを書くことになる・・・?
cython等で作ったcore.soを使うか使わないかが大きな違いという認識で合っていますか?
そうですね、私の実装はcoreのpython実装みたいな感じです。 (そのままcoreモジュールの代わりになります)
とりあえずaoirintさんの実装と私の実装は1つ大きな違いがあることに気が付きました。 (昨日はきちんとコード読めてませんでした、申し訳ないです)
aoirintさんの方はVOICEVOXのAppImage(やwindows版だとzip版)があれば動く感じです。
私の方は、VOICEVOX/voicevox_coreで配布されているcore.zipとlibtorchのライブラリが必要です。 2つ以上の過去バージョンを同時に使う時にlibtorchが重複しているのでそれを削減するためにこのような形になっていました。 しかし、onnx版への対応も別途必要になる他、そもそも2つ以上の過去バージョンを使う人は少なそうなのでaoirintさんの実装で良いかと思います。
Mac版では過去コア対応は0.10以降のみになってしまいますが、そもそも過去バージョンを使ったことのあるMacユーザーはほとんどいないので問題ないかと思います。 (ただしMacを持っていないのでMac対応は他の人にお願いすると思います)
おお、なるほどです!! 過去のバージョンのVOICEVOXのzip版が必要、という感じでしょうか。 (できればcore.zipがあるだけで動くようになると最高だなと感じています・・・!)
core.zipに格納されているC++の共有ライブラリ(core.dll, libcore.so, libcore.dylib)をPythonモジュールとして扱うためのラッパー実装を、ENGINE側に持つか、CORE側に持つかということで考えていました。
いまは、Cython実装が(exampleとして)COREのリポジトリにあるので、CORE側が持っています(自動ビルドではこのexampleを使っている)。
takana-vさんがENGINE側に持つ実装(ctypes)を試しそうだったので、 わたしの方では別パターンとしてCORE側に持ったままにした場合の実装(importlib)を試してみた感じです。 Yosshi999さんが言及していたimportlibを使えば解決しそう、というものの実装例になっていると思います。
個人的には、ビルド済みのPythonモジュールはPythonバージョンやプラットフォームへの依存があって扱いにくいので、ENGINE側にラッパーを持つtakana-vさんの実装の方がいいかなと感じています。
VOICEVOXソフトウェアは容量が大きいので、core.zipだけで動作するならば、ほぼ必要最小限のファイルだけダウンロードすれば済むのもよさそうです。
ただライセンス的には、Pythonラッパーの実装がMIT LicenseからLGPLになるので、再利用しにくくなるかもと思いました。 (Cython実装は保守されなくなりそうなので)可能ならvoicevox_core側にも追加されるか、リポジトリを分けるかされているといいかなと感じました...。
(エンジン上では最新のコアも過去のコアも共通の仕組みで扱うことになると思っています)
なるほどです、よくわかりました!!
僕もENGINE側に実装を持つのが良いのかなと感じました。 ここで問題になるのは、coreの依存ライブラリが変更された場合でしょうか。(今やってるonnx化のように) どうにかしてそこを吸収できそうであれば、ENGINE側に実装するtakana-vさんの方法が良いのかなと感じました!
とりあえずエンジン側での実装です。 https://github.com/VOICEVOX/voicevox_engine/compare/master...takana-v:use-ctypes?expand=1
それのバイナリです。 https://github.com/takana-v/voicevox_engine/releases/tag/build-test27
現時点では--old_voicelib_dir
で過去コアを指定すれば動きます。
onnx化したら--model_lib_dir
でlibtorchのパスを指定する必要があります。
このままだとライセンスがLGPLになるので使いにくいですね... なるべくコア側や別の場所(MIT License)に持っていきたいです。
onnx版を見てみると2つ関数が追加されているので、cython実装のcore.pydなどはlibtorch版で使いまわせない可能性が高いです。 別で.pydや.soを用意するのは大変なのでctypesで実装する方向で行きたいと思います。
チェックはできていませんがonnx版対応しました。 https://github.com/takana-v/voicevox_engine/tree/use-ctypes
とりあえずctypes実装についての案です。 ライセンスの関係でctypesのラッパーのファイルの置き場所を考える必要があります。
どれが良さそうでしょう? @Hiroshiba
とりあえずエンジンに実装してしまって、切り出せそうならcoreに置いたり、ライブラリ化したりするのが良いのかなと思いました!
@takana-v さんのプルリクエストがマージされ、過去バージョンのコアが使えるようになりました!!!本当にありがとうございます!!
一旦ここで、実際のユースケースを考えながら、残りの課題があるかを考えてみます。 方法論はいくつもあると思うので、ご意見頂けると幸いです!
はじめに、実際にユーザーが過去のコアを使いたくなったときの工程です。 サイトに過去のコアのダウンロードリストを作るのは良いとして、あと何が必要そうでしょうか。 ちょっと思いついたのをリストアップしてみました。
あとは、サードパーティ向けの案内もあれば、選択UIを用意してくださるかもしれません。
他にですが、近い将来やりたいなと思っていることの1つに、高速版と高品質版のコアを作りたいと思っています。 現状、同じバージョンの複数のコアを利用する手段が(たぶん)無いので、こちらも実装できるとVOICEVOXの戦略が広がってめっっっっちゃ嬉しいです。
とりあえず意見もらえると嬉しいです!! (別issueにすべきとか、根本的なよりよい方法とか、実装上の懸念とか。)
またtakana-vさんにお願いできればと思ってたのですが、takana-vさんあれですね辞書プロジェクトもアサインされてますね。。。
@PickledChair さん、どうでしょう・・・?👀 的確なレビューコメントをされていたので、お声掛けさせて頂いた次第です・・・!
自分が対応できるかどうか考えてみたのですが、いくつかの理由から、他の適任者をまずは考えていただいた方が良いのではないかと思いました(申し訳ないです)。
上記のように理由を述べましたが、認識に誤りがあればご指摘をお願いします。また、上記の理由を考慮しても自分が担当する方が VOICEVOX プロジェクト的に良いという判断がなされた場合は、改めて自分が複数コア対応に関わることを検討したいと思います。
@PickledChair なるほどです!!
まずエンジンに関してですが、たしかに過去のコアを持った過去のエンジンを用意する手も考えられると思います。 ただそのためには複数エンジン対応(とても難しい)の実装のあと、更に過去エンジンAPIの差分の吸収などが必要になったりするので、道のりはむしろ険しいかもです。 一方複数コアはエンジン側の実装が完了しているため(thx @.takana-v)、目標達成が速そうかもです。
不慣れなこと、お忙しいかもしれないこと、とてもよくわかりました。 詳細ありがとうございます!(動画作成に関するアプリケーション、楽しみです)
あ、でしたら、独立している 同バージョンの別エディション?を利用可能にする
をお願いできるととても嬉しいかもです!!!
コア側にコア名とコアUUIDを持たせ、エンジン側のコア管理をコアバージョン+コアUUIDで行う感じを想像しています(もっと良い方法あるかも。。)
高速版エディション・高品質版エディションのコアが搭載できるので、ユーザー体験が増えて色々楽しくなる見込みです。
もしよければ・・・!
@Hiroshiba
ただそのためには複数エンジン対応(とても難しい)の実装のあと、更に過去エンジンAPIの差分の吸収などが必要になったりするので、道のりはむしろ険しいかもです。
そうだったんですね! そこまで見通せていませんでした。複数コア対応の方が早くに完了しそうなんですね。先にお伝えした通り、今すぐに自分が率先してやる余裕はなさそうなのですが、協力できる範囲でお手伝いできればと思います。
あ、でしたら、独立している 同バージョンの別エディション?を利用可能にする をお願いできるととても嬉しいかもです!!!
(Web 系でなく)Python であればまだ馴染みがあるので、こちらのみであれば比較的見通しが立ちやすい印象でした。エディタについても、内蔵エンジンのエディション切り替え設定くらいであれば取り組めそうな気がしています。機能追加の練習にもなると思ったので、担当したいと思います(これまで自分がしてきたのはビルド周りか機能修正のコントリビュートのみでした)。本腰を入れられるのは2月2週目くらいからになりそうですが……。
ありがとうございます!! とりあえずエンジン側にissueを作成してアサインさせていただきました! https://github.com/VOICEVOX/voicevox_engine/issues/303
では引き続き、複数コアをエディタで活用するメインの方を募集をしています・・・!
加えて、「あるキャラだけバージョンアップで増える」みたいなこともありそうです。 キャラAはコア0.XXがlatest、キャラBはコア0.YYがlatest、という状況が考えられます。 それぞれのキャラでlatestが選ばれるような仕組みがあると良さそうに感じました。
こちら、キャラクターごとにモデルが分けられるようになった関係で、そもそもアップデートされる頻度が下がりました。
そのため重要度が下がったので、優先度を少し下げたいと思います。
複数コアの需要ですが、ユーザーの方々の要望を聞いていると、キャラクターごとに過去バージョンを使えると嬉しいのかなと思いました。 (コアごと全部過去バージョンを使うようにすると、新キャラが選べない)
下記issueにて、取り組んでくださる方を募集しています。もしよければ・・・!
そろそろ音声ライブラリの刷新を考え始めています。 このタスクはコア内で複数モデルが持てるようになった関係で一旦は優先度が下がったのですが、過去のバージョンが使えることはやはり需要が高いと思うので、再稼働できればと考えています!
まずは議論ということで・・・一旦考えている設計を書いてみます。
必須:過去のバージョンの音声の利用 できれば:別エディションの音声の利用(高品質版など) できれば:コアをビルトインじゃなくす
エンジンからいろんなバージョンのコアをダウンロードする。 ユーザーディレクトリにある複数のコアを適宜ロードする。 エディションも1つのバージョンだと考える。
/downloadable_libraries
が既存0.14.1
と高速版のfast-0.14.0
があったときとかとりあえず、必須の「過去のバージョンの音声の利用」だけであればそんなに破綻のない設計だと思っています。
voicevox_engine#303 にて実装検討が完了。低コストで実装可能と結論。
実装時には issue#303 を re-open して実装状況を track。
現在「エディション」についての状況を説明します 🙇
もともとは高品質版に取り組むつもりがかなりありました。 その後しばらく経って、優先すべきは品質以上にソングへの展開だと判断し、ソングハミング実装に注力する形になっていきました。
このタイミングでエディション実装の機運が一旦後回しになっていました。 それをこのissueでもっと早く報告するべきでした 🙇
現状はエディションに関して何か注力している方針はありません。 ですが将来的にVOICEVOXが成長した場合、ほぼ必ず別エディションは必要になるだろうと思う、という感じです。
このissueを一旦クローズするべきかどうかはちょっとまだ判断できてません。とりあえず保留させていただければ・・・ 🙇
キャラクターを追加したり、性能をあげようとするたびに、コアのバージョンアップが入ります。 コアが変わるとどうしても声の調整感が変わってしまい、ユーザーにとって少しストレスになってしまいます。 (ユーザーが離れる理由になってしまうのが一番の問題です)
コアを入れ替え可能にすれば、過去のコアも使えるようになります。 結構急ぎめで導入したい機能です。 おそらくコア・エンジン・エディタ全てで対応が必要なため、プロジェクトとして扱っています。