-
Notifications
You must be signed in to change notification settings - Fork 91
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
コードベースを大規模にリファクタリングし、ライブラリ (Python パッケージ) としてほかの Python コードから利用できるように改善 #92
Conversation
…from server_editor.py The logic has not been changed, only renaming, splitting and moving modules on a per-function basis. Existing code will be left in place for the time being to avoid breaking the training code, which is not subject to refactoring this time.
…OX to style_bert_vits2/text_processing/japanese/user_dict/
… definitions and comments
…tyle_bert_vits2/models/ The code has not yet been cleaned up, just moved.
… loaded BERT models/tokenizer and replace all from_pretrained() to load_model/load_tokenizer
…each language to style_bert_vits2/text_processing/(language)/bert_feature.py
… style_bert_vits2/text_processing/__init__.py This was often used in 3 function sets and felt like a wasteful division with few lines.
…VITS2 Since app.py and server_editor.py already exist as alternative Web UI, there is no need to revive webui.py in the future.
I have determined that this is excessive for this project at this time.
"text_processing" is clearer, but the import statement is longer. "nlp" is shorter and makes it clear that it is natural language processing.
pyopenjtalk_worker.initialize() has the side effect of starting another process and should not be executed automatically on import.
…ontinue processing without a worker When using style-bert-vits2 as a library, the requirement to be able to launch it in multiple processes may not be necessary. Also, if the library is embedded and exe-ed using PyInstaller or similar, it is difficult to make pyopenjtalk_worker run in a separate process. Therefore, we changed it so that the worker is used only when it is explicitly initialized.
… clarification and add comments to each method
By executing "hatch run test:test", you can check whether the test passes in all Python 3.9 to 3.12 environments.
Style-Bert-VITS2 has been reported to not work with some PyTorch 2.2 series, but Python 3.12 is only supported in Torch >= 2.2, so Python 3.12 support is not provided for the time being
Enabling type checking with Pylance.
BERT models and tokenizers are already stored and managed in the bert_models module and should not be stored here. In addition, since there may be situations where the user would like to use cpu instead of mps for inference when using it as a library, the automatic switching process to mps was removed.
The Pydantic models in the library are written for Pydantic v2 and will not work with Pydantic v1.
Prebuilt wheels for almost every OS/architecture (except musl) are now available on PyPI, eliminating the need for a build environment. ref: https://pypi.org/project/pyworld-prebuilt/
Pydantic models are more robust and properties can be accessed by dots.
大規模なリファクタリングありがとうございます。 |
#93 にて修正等をしていきますが、とりあえずこのリファクタリングに直結する修正等はこちらで逐次報告していくことにします(認識の違いがあると後々また面倒になりそうなので)(その他の不具合修正等はこちらで行います)。 フォーマットやスタイルについて。いろいろ考えるのが面倒なので、black formatterのデフォルト設定にすべて合わせることにします(特に文字列のクォーテーションがダブルなことやデフォルト引数時の空白無しや最大文字数や空行等) importスタイルを |
@tsukumijima 僭越ながら、私が携わったopenjtalkの別プロセス化について
おっしゃっている通り、pyopenjtalk_worker はあくまで このあたり、うまく分離できると良さそうという直観だけあります。 いずれにしても、とりしまさんが期待するライブラリとして 補足
旧 user_dictの__init__.pyやjapanese.pyでpyopenjtalk_workerのinitializeを呼んでいたこと、 私自身、こういったオープンソース開発はまだ不慣れなので せっかく大変なコード変更をしていただいても、 |
すみません、自分が初めてhatchを知って使い方が分かっていないのはあると思いますが、自分のWindowsのCUDA環境では、環境が作られる際にtorchがおそらくCPU版が入ってしまい、
となり、 |
#92 (comment) に関して続き ご判断されるのはlitaginさんであり、私は通りすがりではありますが
を同時に行うのは根本的に難しいというのを 例えば
またあるいは、
はブランチで区別というのもあるかと思います。 |
@tsukumijima |
デフォルトの |
私は Linux でしか試していないのですが盲点でした…。 hatch は仮想環境作成時、pyproject.toml に記載された依存関係を自動的にインストールします。
私も完全には理解していないのですが、https://pytorch.org/get-started/locally/ を見る限り上記のパターンとなっているようです。 …長くなりましたが、要は Linux ではデフォルトで CUDA 対応版 torch がインストールされるが、Windows ではデフォルトで CPU 対応版 torch がインストールされてしまうことが原因と思われます。 しかも、Poetry などと異なり、pyproject.toml には現状プラットフォームや環境ごとに個別に依存関係を細かく指定することができません (参考) 。 Windows 環境メインで開発されているとのことなので、支障するようであれば一旦コメントアウトしておくのが一番手っ取り早いかと思います。 |
一旦個人的な好みに合わせて書いてしまいましたが、フォーマットについて考えるのが面倒であればデファクトである black に任せてしまうのも十分アリだと思います。
この点私もどうするか悩みましたが、現状のコードでは 現時点で app.py や server_editor.py などの Style-Bert-VITS2 内部のサーバーでは起動前に
私も大規模な変更を避けるためにあえてこの実装にしたのだろうという理解でした。納得です。
実際私もライブラリ用のコードを切り出して別リポジトリで公開しようかとも考えました。ただやはり二重管理になりますし、変更への追従に多大な手間がかかる課題があります(そして面倒になって放棄されうる)。 今回の pyopenjtalk_worker の件に関して言えば、上記方法でライブラリとしての |
あーそこも盲点でした…。 ただ、g2p.py への すべてのエントリーポイントとなるスクリプトに from style_bert_vits2.nlp.japanese import pyopenjtalk_worker
from style_bert_vits2.nlp.japanese.user_dict import update_dict
# ライブラリとしての style-bert-vits2 のうち、自然言語処理関連のモジュールをすべてインポート
from style_bert_vits2.nlp import * # type: ignore
# pyopenjtalk_worker を起動
pyopenjtalk_worker.initialize_worker()
# dict_data/ 以下の辞書データを pyopenjtalk に適用
update_dict() … server_editor.py などで このようにすれば、Style-Bert-VITS2 内部から自然言語処理関連モジュールを import すると自動的に pyopenjtalk_worker が起動され、デフォルト辞書データパスから辞書データが適用されます。 |
大変、ご丁寧なご回答、ありがとうございます。
大変なリファクタリングをしてまでライブラリ化するにあたっては、 initialize_workerの呼び出しによるスイッチの許容や 現状のコードからも明らかなように
と言及しましたように、似たようなことが起こらないかだけ不安ですが、
こちらは、言い訳がましくてすみませんでした。 おそらくオープンソース開発はケースバイケースな |
@tsukumijima
ここの箇所で、ライブラリという概念や通常の使用方法について曖昧にしか知らないのでお聞きしたいのですが、今の状態で また具体的にライブラリとして公開した場合は、どのような使われ方・インストール方法・ユースケースを想定しているのでしょうか? |
すみません、ここも盲点でした… (確かに手元でビルドした sdist は 3.1GB くらいになっちゃってました) 。
ライブラリとしての SBV2 は
以前のコメントで書いた通りですが、使われ方/ユースケースは LLM と組み合わせりした GUI アプリや、独自に実装した音声合成 API サーバーなどが考えられます。 インストール方法は pip や Poetry になります。
bert_models.py の load_model/load_tokenizer() をライブラリユーザーが事前に呼び出す形を想定しています。 このため、ライブラリとしての SBV2 側で新たに配慮いただく必要はありません。 Note bert_models.py の内部で使われている transformers ライブラリの from_pretrained() は、むしろ Hugging Face のリポジトリ名を指定する使い方のほうが一般的で、(Style-)Bert-VITS2 の実装手法はむしろかなりイレギュラーだと思います。 Note Bert-VITS2 でモデルをわざわざローカルに保存している (ついでにハイパーパラメータなどをリポジトリ内に含めている) のも、中国国内からだと Hugging Face へのアクセスが非常に遅い or 金盾で規制されている事が理由だったはずです。 なので日本国内で使う分には、bert/ フォルダや slm/ フォルダを削除して from_pretrained() にローカルのパスではなく Hugging Face のリポジトリ名を渡す形にしてしまっても全く問題ないと思います。(キャッシュディレクトリを統一したければ from_pretrained() に cache_dir を指定すれば良い) Important ここまで書いて、bert_models.load_model/load_tokenizer() に、内部で呼び出す from_pretrained() に渡す用の PS: 上記問題を修正したプルリクエストを出させていただきました。マージしていただければ幸いです。 |
以前から Discord にてお伝えしている通りですが、Style-Bert-VITS2 のコードベースを大規模にリファクタリングし、ライブラリとしてほかの Python コードから利用できるようにしました。
同時に Style-Bert-VITS2 固有のディレクトリ構造に依存しているコードを修正し、ユーザーが
style-bert-vits2
ライブラリの動作をコントローラブルに置けるように改良しました。Note
一例を挙げると、従来のコードでは、モジュールをインポートした瞬間に
AutoTokenizer.from_pretrained()
が実行されてしまっていました。従来のコードはただでさえハードコードされたパスに依存している上、インポートした瞬間に BERT モデル/トークナイザーがロードされてしまいます。この状況では、とても「コントローラブル」であるとは言えません。
特にモデルのロードは重たい処理ですから、ユーザーが明示的に、任意のタイミングでモデルをロードできる形が理想的です。
別途
pip install hatch
で Hatch をインストールした上でhatch build
を実行すると、dist/style_bert_vits2-(version)-py3-none-any.whl
に wheel パッケージ (.whl) が生成されます。この「ライブラリとしての」
style-bert-vits2
を PyPI に公開するかどうかはお任せします。Note
PyPI に公開せずとも、wheel がリリースに公開されていれば pip に wheel の URL を指定してライブラリをインストールできます。また GitHub の URL を
git+https://
のスキームで指定してインストールすることも可能なはずです。良くなること
server_editor.py
/server_fastapi.py
から (ライブラリとして切り出された) コア API を呼び出す形になるため、今までどこがどう引っ付いてるのか分からなかった依存関係が明確化されるstyle-bert-vits2
を組み込んだ CLI 音声合成ツールを作ったりも可能になる悪くなること
リファクタリング方針
以下の方針でリファクタリングを行いました。
(pyproject.toml が配置されているディレクトリ)/(パッケージ名)/
以下に当該パッケージのソースコードが配置されている必要があるstyle_bert_vits2/
以下に切り出したコードのみとし、それ以外のコードは import の変更など最低限の変更にとどめるserver_editor.py
/server_fastapi.py
などもリファクタリングの対象外train_ms.py
のようなクリティカルな影響を与える学習用コードはできるだけそのままにしておきたく…style_bert_vits2
パッケージをインポートしただけで意図せず BERT モデルがロードされてしまう、など変更点
変更点が非常に多いため、一部書き出せていないものがあるかもしれません。
style_bert_vits2/nlp/
以下にコードを集約し、さらに各言語固有の実装をstyle_bert_vits2/nlp/(chinese|english|japanese)
に移動したstyle_bert_vits2/models/
以下に集約したwebui.py
も含まれるstyle_bert_vits2/models/
以下にあるモデル構造が定義されているコードは、私が機械学習に全く精通しておらずコードの内容を全く理解できていないこと、非常に専門的な上に通常ライブラリユーザーは触らないことを鑑み、Docstring の付与を省略したstyle_bert_vits2/
以下のすべてのコードに型ヒントを追加し、型エラーを修正|
は使わず、敢えて Union, Optional を利用している)# type: ignore
を付与して型エラーを抑制した# type: ignore
が付与されている行のコードの型安全性は保証されない__
の prefix をつけるとプライベートになる (参考)get_bert()
をextract_bert_feature()
に変更したりなどstyle_bert_vits2/
以下に切り出した部分を Python パッケージ (wheel) にビルドできるようにしたhatch run test:test
を実行すると自動的に専用の仮想環境が構築され、Python 3.9 〜 3.11 すべてでライブラリが動作するかをテストできるtests/wavs/
に保存されるutils.HParams
を Pydantic モデル (HyperParameters) に移行したことで、特定の型のプロパティが存在することが保証されるようになったbert/
以下に保存されているモデルが利用されるbert/
フォルダに BERT のモデルを保存する構成なのも、中国だと Hugging Face へのアクセスが制限されており openi という中国国内のミラーからダウンロードする必要があったからのはずtransformers
ライブラリの既定のキャッシュディレクトリにキャッシュされる)style-bert-vits2
を含めて exe 化する場合、pyopenjtalk_worker は『Python インタプリタ上で実行されていることを前提に』subprocess.Popen() +python -m
で別プロセスで pyopenjtalk サーバーを起動する設計のため、正常動作しないことが容易に予想されるpyopenjtalk_worker.initialize()
をpyopenjtalk_worker.initialize_worker()
にリネームした上で、明示的にpyopenjtalk_worker.initialize()
を実行しなかった場合は通常の pyopenjtalk にフォールバックするように変更したapp.py
(webui/inference.py
) /server_editor.py
/server_fastapi.py
にはpyopenjtalk_worker.initialize_worker()
を記述してあるため、今まで通り複数プロセスで辞書を共有できるLanguages
の StrEnum で管理するように変更server_editor.py
ではこの Enum が使われていたが、大半のコードでは未だ文字列ベースでの言語判定になっていた.vscode/settings.json
)を追加vscode/extensions.json
) に Python と Pylance を追加した--host 0.0.0.0
を指定するとすべてのネットワークインターフェイスで HTTP サーバーがリッスンされる変更が非常に大規模なこともあり、さすがにこのままフォークを維持していくのは正直かなりつらいです…。
コーディングスタイルが気に入らない箇所などあれば後で遠慮せず修正していただいて構いませんので、まずはマージしていただけると非常に助かります。
今回の変更で何か不明な点があれば、コメントいただければ回答いたします。
お手数おかけしますが、何卒よろしくお願いいたします。