目次
こんにちは.高山です.
先日こちらの記事で,Stable Diffusion 関連のツールを Docker 環境にインストール手順を紹介しました.
利用する上では特に問題無いのですが,先日のインストール手順は Gradio のバージョンを Stable Diffusion web UI に合わせているため,最新版の Kohya's GUI が使えないという問題点がありました.
そこで今回の記事では,Gradio v3.50.2 環境で各ツールが動作するように改修する方法を紹介したいと思います.
更新履歴 (大きな変更のみ記載しています)
- 2024/09/18: カテゴリを変更しました
- 2024/09/17: タグを更新しました
1. 全体の環境構築手順のおさらい
細かい改修方法に入る前に,先日紹介した全体の環境構築方法をおさらいしたいと思います.
図1に全体の環境構築手順を示します.
大まかな流れとしては,Docker 上に Python3.10 の仮想環境を構築し,各ツールのインストールを行うという手順になります.
今回はこれらの手順は完了しているという前提で話をさせていただきたいと思います.
2. 問題点の整理
2.1 最新版 Kohya's GUI は Gradio v.3.41.2 では動作しない
改修の前に現在のインストール状況が抱えている問題点を確認します.
まず最初に,Gradio v3.41.2 環境での Kohya's GUI の挙動を確認してみます.
下記のコードで Kohya's GUI を最新版に更新します.
cd ~/sd_apps/kohya_ss
git checkout -b main v23.0.15
下記のコマンドでツールを起動させます.
python3 kohya_gui.py
起動後にブラウザにアクセスすると,図2の起動画面が表示されます.
一見問題無く動作しそうに見えますが,データセットのディレクトリ操作を行うと,下記のエラーが発生します.
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/home/takayaman/py310/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 407, in run_asgi
result = await app( # type: ignore[func-returns-value]
File "/home/takayaman/py310/lib/python3.10/site-packages/fastapi/routing.py", line 180, in serialize_response
return jsonable_encoder(response_content)
...
File "/home/takayaman/py310/lib/python3.10/site-packages/fastapi/encoders.py", line 287, in jsonable_encoder
encoded_value = jsonable_encoder(
...
File "/home/takayaman/py310/lib/python3.10/site-packages/fastapi/encoders.py", line 318, in jsonable_encoder
if isinstance(obj, classes_tuple):
File "/usr/lib/python3.10/abc.py", line 119, in __instancecheck__
return _abc_instancecheck(cls, instance)
RecursionError: maximum recursion depth exceeded in comparison
エラーの原因は掴めていませんが,発生時点はこのコミットからのようです.
修正の中身は廃止対象になっている古い処理の更新が主なので,単純に古い Gradio に存在したバグなのかもしれません.
何はともあれ,下記のコマンドで Gradio を更新するとKohya's GUI のエラーは解消され,正常起動するようになります.
pip3 install gradio==3.50.2
2.2 Stable Diffusion web UI は Gradio v3.50.2 では動作しない
一方,Stable Diffusion web UI の方はどうでしょうか?
Gradio v3.50.2 環境における Stable Diffusion web UI の挙動を確認します.
下記のコマンドでツールを起動させます.
cd ~/sd_apps/stable-diffusion-webui
python3 webui.py
起動するとコンソールに下記のメッセージが表示されます.
No module 'xformers'. Proceeding without it.
=============================================================================
You are running gradio 3.50.2.
The program is designed to work with gradio 3.41.2.
Using a different version of gradio is extremely likely to break the program.
Reasons why you have the mismatched gradio version can be:
- you use --skip-install flag.
- you use webui.py to start the program instead of launch.py.
- an extension installs the incompatible gradio version.
Use --skip-version-check commandline argument to disable this check.
=============================================================================
Loading weights [6ce0161689] from /home/takayaman/sd_apps_stable_gradio3412/stable-diffusion-webui/models/Stable-diffusion/v1-5-pruned-emaonly.safetensors
Running on local URL: http://127.0.0.1:7860
Creating model from config: /home/takayaman/sd_apps_stable_gradio3412/stable-diffusion-webui/configs/v1-inference.yaml
Applying attention optimization: Doggettx... done.
To create a public link, set `share=True` in `launch()`.
Startup time: 7.4s (import torch: 2.4s, import gradio: 0.6s, setup paths: 0.9s, initialize shared: 0.1s, other imports: 0.2s, load scripts: 0.3s, create ui: 0.6s, gradio launch: 2.2s).
Model loaded in 2.9s (load weights from disk: 0.8s, create model: 0.5s, apply weights to model: 1.1s, load textual inversion embeddings: 0.2s, calculate empty prompt: 0.2s).
Gradio のバージョンに対する警告を除けば問題は無さそうに見えますが,実際にブラウザでアクセスすると図3に示すように Loading 表示で固まってしまいます.
ブラウザのデバッグツールを開くと (見えづらくてすみません),GUI 周りで Javascript からエラーが生成されています.
ここから,改修の際は GUI 周りのコードに当たりをつけて,ロードを妨げているコンポーネントを一つずつ探していき,エラー箇所を絞っていきました.
3. エラー箇所の修正
結論から言いますと,Gradio v3.50.2 では下記のモジュールが上手く処理できないようです.
(該当コードの箇所はコードブロックのコメントに記入しています)
# modules/ui_components.py
# Lines 70-85
class DropdownMulti(FormComponent, gr.Dropdown):
"""Same as gr.Dropdown but always multiselect"""
def __init__(self, **kwargs):
super().__init__(multiselect=True, **kwargs)
def get_block_name(self):
return "dropdown"
class DropdownEditable(FormComponent, gr.Dropdown):
"""Same as gr.Dropdown but allows editing value"""
def __init__(self, **kwargs):
super().__init__(allow_custom_value=True, **kwargs)
def get_block_name(self):
return "dropdown"
上記のクラスは Gradio のクラスを特定の設定値でラップしているだけなので,Gradio のクラスを直接呼び出すように修正します.
(修正箇所はコードブロックのコメントに記入しています)
# modules/shared_options.py
# Line 305-309
# "quicksettings_list": OptionInfo(["sd_model_checkpoint"], "Quicksettings list", ui_components.DropdownMulti, lambda: {"choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that appear at the top of page rather than in settings tab").needs_reload_ui(),
# "ui_tab_order": OptionInfo([], "UI tab order", ui_components.DropdownMulti, lambda: {"choices": list(shared.tab_names)}).needs_reload_ui(),
# "hidden_tabs": OptionInfo([], "Hidden UI tabs", ui_components.DropdownMulti, lambda: {"choices": list(shared.tab_names)}).needs_reload_ui(),
# "ui_reorder_list": OptionInfo([], "UI item order for txt2img/img2img tabs", ui_components.DropdownMulti, lambda: {"choices": list(shared_items.ui_reorder_categories())}).info("selected items appear first").needs_reload_ui(),
# "gradio_theme": OptionInfo("Default", "Gradio theme", ui_components.DropdownEditable, lambda: {"choices": ["Default"] + shared_gradio_themes.gradio_hf_hub_themes}).info("you can also manually enter any of themes from the <a href='https://huggingface.co/spaces/gradio/theme-gallery'>gallery</a>.").needs_reload_ui(),
# ↓
"quicksettings_list": OptionInfo(["sd_model_checkpoint"], "Quicksettings list", gr.Dropdown, lambda: {"multiselect": True, "choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that appear at the top of page rather than in settings tab").needs_reload_ui(),
"ui_tab_order": OptionInfo([], "UI tab order", gr.Dropdown, lambda: {"multiselect": True, "choices": list(shared.tab_names)}).needs_reload_ui(),
"hidden_tabs": OptionInfo([], "Hidden UI tabs", gr.Dropdown, lambda: {"multiselect": True, "choices": list(shared.tab_names)}).needs_reload_ui(),
"ui_reorder_list": OptionInfo([], "UI item order for txt2img/img2img tabs", gr.Dropdown, lambda: {"multiselect": True, "choices": list(shared_items.ui_reorder_categories())}).info("selected items appear first").needs_reload_ui(),
"gradio_theme": OptionInfo("Default", "Gradio theme", gr.Dropdown, lambda: {"allow_custom_values": True, "choices": ["Default"] + shared_gradio_themes.gradio_hf_hub_themes}).info("you can also manually enter any of themes from the <a href='https://huggingface.co/spaces/gradio/theme-gallery'>gallery</a>.").needs_reload_ui(),
# Line 332
# "infotext_skip_pasting": OptionInfo([], "Disregard fields from pasted infotext", ui_components.DropdownMulti, lambda: {"choices": shared_items.get_infotext_names()}),
# ↓
"infotext_skip_pasting": OptionInfo([], "Disregard fields from pasted infotext", gr.Dropdown, lambda: {"choices": shared_items.get_infotext_names(), "multiselect": True}),
# Line 380-381
# 'postprocessing_enable_in_main_ui': OptionInfo([], "Enable postprocessing operations in txt2img and img2img tabs", ui_components.DropdownMulti, lambda: {"choices": [x.name for x in shared_items.postprocessing_scripts()]}),
# 'postprocessing_operation_order': OptionInfo([], "Postprocessing operation order", ui_components.DropdownMulti, lambda: {"choices": [x.name for x in shared_items.postprocessing_scripts()]}),
# ↓
'postprocessing_enable_in_main_ui': OptionInfo([], "Enable postprocessing operations in txt2img and img2img tabs", gr.Dropdown, lambda: {"multiselect": True, "choices": [x.name for x in shared_items.postprocessing_scripts()]}),
'postprocessing_operation_order': OptionInfo([], "Postprocessing operation order", gr.Dropdown, lambda: {"multiselect": True, "choices": [x.name for x in shared_items.postprocessing_scripts()]}),
# extensions-builtin/extra-options-section/scripts/extra_options_section.py
# Line 72-73
# "extra_options_txt2img": shared.OptionInfo([], "Settings for txt2img", ui_components.DropdownMulti, lambda: {"choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that also appear in txt2img interfaces").needs_reload_ui(),
# "extra_options_img2img": shared.OptionInfo([], "Settings for img2img", ui_components.DropdownMulti, lambda: {"choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that also appear in img2img interfaces").needs_reload_ui(),
# ↓
"extra_options_txt2img": shared.OptionInfo([], "Settings for txt2img", gr.Dropdown, lambda: {"multiselect": True, "choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that also appear in txt2img interfaces").needs_reload_ui(),
"extra_options_img2img": shared.OptionInfo([], "Settings for img2img", gr.Dropdown, lambda: {"multiselect": True, "choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that also appear in img2img interfaces").needs_reload_ui(),
これらを修正後は,Stable Diffusion web UI が正常に起動するようになります.
4. (おまけ) Deprecation箇所の修正
現在の Stable Diffusion web UI には廃止予定になっているコードが含まれています.
動作には直接影響ありませんが,今後のメモとして修正箇所を記載しておきます.
(修正箇所はコードブロックのコメントに記入しています)
# modules/extras.py
# Line 330
# return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], "Checkpoint saved to " + output_modelname]
# ↓
return [*[gr.Dropdown(choices=sd_models.checkpoint_tiles()) for _ in range(4)], "Checkpoint saved to " + output_modelname]
# modules/infotext_utils.py
# Line 506
# return gr.Dropdown.update(value=vals_pairs, choices=vals_pairs, visible=bool(vals_pairs))
# ↓
return gr.Dropdown(value=vals_pairs, choices=vals_pairs, visible=bool(vals_pairs))
# modules/ui.py
# Line 256
# fn=lambda x: gr.Dropdown.update(visible=bool(x)),
# ↓
fn=lambda x: gr.Dropdown(visible=bool(x)),
# modules/ui_checkpoint_merger.py
# Line 25
# return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"]
# ↓
return [*[gr.Dropdown(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"]
# modules/ui_common.py
# Line 152
# return gr.File.update(value=fullfns, visible=True), plaintext_to_html(f"Saved: {filenames[0]}")
# ↓
return gr.File(value=fullfns, visible=True), plaintext_to_html(f"Saved: {filenames[0]}")
# modules/ui_extensions.py
# Line 72
# return gr.Dropdown.update(value=new_value, choices=new_choices), f"<span>Saved current webui/extension state to \"{filename}\"</span>"
# ↓
return gr.Dropdown(value=new_value, choices=new_choices), f"<span>Saved current webui/extension state to \"{filename}\"</span>"
# Line 417
# return url, code, gr.CheckboxGroup.update(choices=tags), '', ''
# ↓
return url, code, gr.CheckboxGroup(choices=tags), '', ''
# modules/ui_prompt_styles.py
# Line 49
# return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=negative_prompt), gr.Dropdown.update(value=[])]
# ↓
return [gr.Textbox(value=prompt), gr.Textbox(value=negative_prompt), gr.Dropdown(value=[])]
# scripts/xyz_grid.py
# Line 498
# return (gr.Button.update(visible=has_choices), gr.Textbox.update(visible=not has_choices or csv_mode, value=axis_values),
# ↓
return (gr.Button(visible=has_choices), gr.Textbox(visible=not has_choices or csv_mode, value=axis_values),
今回は Stable Diffusion 関連ツールを Gradio v3.50.2 環境にインストールするための改修方法を紹介しましたが,如何でしたでしょうか?
エラーが修正できるとうれしいですね (^^).
勢い込んで Stable Diffusion web UI のリポジトリに Pull リクエスト (改修を取り込んでくれるように依頼することです) を送ろうかな,と思ったのですが,どうやら最新版の Gradio v4 へ対応する予定のようですね.
残念ながらこの改修の賞味期限はあまりないようですが (先に確認しろよという話ですが...(^^;)),本記事で供養できたので良しとします.
今回紹介した話が,これから生成AI を試してみようとお考えの方に何か参考になれば幸いです.