StableDiffusion ComfyUI
RunPodではtemplateをComfyUIにすることで自動的にインストールされます
自前環境でもgithubからクローンすればよい

おそらく、
- 8080:FileBrowser
JupyterLabよりファイル移動が楽(ユーザ名:admin, パスワード:adminadmin12) - 8188:ComfyUI
- 8888:JupyterLab
主にターミナルを使用するとき使うと思う
ComfyUIの見た目

workflow
ComfyUI/user/default/workflows/内にある
プロンプト
- 重み
プロンプトの重みはリスト内の位置で管理でき、先頭にあるものほど重みが高く、生成された画像に反映されやすくなります。
タグの重み付け
(prompt: 1.5)
0.5~1.5の範囲で設定
上のパズルピースのマークの"Manager"を押下して、下図のメニューから"Model Manager"を開きます

画像比較
“Manager"メニューから"Custom Nodes Manager"を開いて、rgthree-comfyをインストール
Image Comparer (rgthree)を使って

顔修正
“Manager"メニューから"Custom Nodes Manager"を開いて、ComfyUI Impact PackとComfyUI Impact Subpackをインストール


次に同じ"Manager"メニューから"Model Manager"を開いて、face_yolov8n_v2 (bbox)とViT-B SAM modelをインストール


ここまでやったら、RunPodに行ってReset Podする

追加するのはFaceDetailerとUltralyticsDetectorProviderとSAMLoaderの3つ

オプションの説明
guide_size:領域の短い辺の最小値。guide_size$=512$で、領域が縦500,横400の場合、横が512になり、アスペクト比を維持したまま縦も拡大される。この例なら$500\cdot512/400=640$なので、縦640,横512
$\min(w,h)$$ \begin{align} \min(w,h)&\to x_{guide}\\ \max(w,h)&\to \max(w,h)\cdot \frac{x_{guide}}{\min(w,h)} \end{align} $$ guide_size_for:guide_sizeが判定する領域の定義。bboxは顔の大きさ、crop_regionは顔を含んで大まかに切り取られた領域max_size:guide_sizeによって拡大された長い辺の最大値。先の例で言えば、max_size$=600$なら、縦640でmax_sizeより大きいので600に強制され、縦600,横512となるseed,steps,cfg,sampler_name,scheduler,denoise:K samplerと同じ。denoiseはノイズ除去feather
高解像(UpScaler)
“Manager"メニューから"Model Manager"を開いて、4x-AmimeSharpと4x-UltraSharpとか好きなものをインストール
4倍の解像度に拡大するという意味で4xだと思う

ComfyUIを再起動
VAE decode後にLoad Upscale ModelとUpscale Image (using Model)を噛ませて以下のようにつなぐ

画像からプロンプト推論
“Manager"メニューから"Custom Nodes Manager"を開いて、ComfyUI-Custom-Scriptsをインストール

custom_nodesディレクトリに移動
cd runpod-slim/ComfyUI/custom_nodes
クローン
git clone https://github.com/pythongosssss/ComfyUI-WD14-Tagger
依存モジュールをComfyUI用の仮想環境にインストール
source /workspace/runpod-slim/ComfyUI/.venv-cu128/bin/activate
pip install -r /workspace/runpod-slim/ComfyUI/custom_nodes/ComfyUI-WD14-Tagger/requirements.txt
タグ推論モデルを格納するmodelsディレクトリを作る
mkdir /workspace/runpod-slim/ComfyUI/custom_nodes/ComfyUI-WD14-Tagger/models/
モデルをダウンロード
tokenはここで作る
from huggingface_hub import hf_hub_download, snapshot_download
import os
repo_id="SmilingWolf/wd-eva02-large-tagger-v3"
name="model"
path="/workspace/runpod-slim/ComfyUI/custom_nodes/ComfyUI-WD14-Tagger/models/wd-eva02-large-tagger-v3"
token=""
filepath = hf_hub_download(repo_id=repo_id,filename=f"{name}.safetensors",local_dir=path,token=os.getenv(token))
podを再起動
WD4 Taggerのオプション
- model:使用するモデル(
ComfyUI/custom_nodes/ComfyUI-WD14-Tagger/models/) - threshold:認識したタグを出力する閾値。大きいほど関連性の高いタグが出力される。
- character_threshold:キャラクタータグの閾値。キャラの断定が難しい構図だったり、そもそも学習が足りてないキャラは出ない
ガベルが重い姉御で試した

出力されたタグにキャラクタ名を追加して生成した

ControlNet
promptが文字による制御だとすると、ControlNetは画像による制御
参考:
- ControlNet導入ガイド|基本ノードとモデル選び
- ComfyUIでOpenPose ControlNet SD1.5モデルを使用する方法
“Manager"メニューから"Custom Nodes Manager"を開いて、comfyui_controlnet_auxをインストール

“Manager"メニューから"Model Manager"を開いて、All-in-one ControlNetとかをインストール。Baseモデルを見ながら使ってるチェックポイントに合わせる

ComfyUIを再起動
こんな感じでプロンプトと合流させる

キャニーの部分を他の方法に変えることもできる↓
| Preprocessor | 抽出する情報 | 使う場面 |
|---|---|---|
| Canny | 輪郭(エッジ) | 元画像の形をそのまま反映したい |
| OpenPose | 人物の骨格・ポーズ | ポーズを維持しつつ見た目を変えたい |
| Depth Map | 奥行き・距離情報 | 背景の立体感を残したい |
| M-LSD Lines | 建物の直線構造 | 建築物の形だけ活かしたい |
“ControlNetを適応"ノードのオプション
- 強度:解析画像の影響度。値が大きいほど元画像の形を維持(0.5~1.2辺りが妥当?)
- 開始パーセント:反映開始のタイミング。0.0 が開始時、値が大きいほど後半から適用
- 終了パーセント:反映終了のタイミング。1.0 で生成完了まで反映、短くすると後半は自由生成
開始、終了というのはKサンプラーのステップ数のことだと思われる
ステップ数30で、開始パーセント0.5なら、15ステップ目からControlNetが適応され始める
Canny
輪郭の内側などの調節?
こいつを変更してみる↓

red_eyes, black_hair, slit_pupils, grey shirt
ポジティブをこんなもんにして、ContolNetと組み合わせて生成

OpenPose
プラグインをインストールしたのにOpenPose poseノードが無くて困ったが、バージョンを選びなおしたりPod自体を再起動したら治った
こんな感じ
モデルはall in oneのもの使っているので、変える必要はない

| 入力パラメータ | 説明 | パラメータオプション |
|---|---|---|
| images | 入力画像 | - |
| detect_hand | 手の検出の有無 | enable / disable |
| detect_face | 顔の検出の有無 | enable / disable |
| detect_body | 体の検出の有無 | enable / disable |
| resolution | 出力画像の解像度 | - |
resolutionは縦横で短い方のピクセル数。resolution=512で1640x984なら853x512で出力される
元画像が1024pxくらいあっても512くらいにした方が反映されやすい気がする
本来は元画像と同じくらいの解像度が良いっぽい


ポーズに関するプロンプトを省略してControlNetに丸投げする
1girl, solo, jacket, short_shorts, fang, clear_sky, full_body, upper_teeth, gold_eyes, gold_hair, navel, slit_pupils, grey_shirt, looking_at_viewer
LoRAを適応して絵柄を変えても大体同じポーズになる。
実用としては丸投げするよりもプロンプト側で大まかに同じポーズを指定したほうが近づく

全然画像のポーズが認識できないと感じたら、open-pose-editorなどを使って手作業で作るという手もある
カラーマスク
キャラクターごとに位置、プロンプトを個別指定する
複数キャラを扱うときに使う
参考
“Manager"メニューから"Custom Nodes Manager"を開いて、ComfyUI Inspire Packをインストール

Podを再起動
カラーマスクのみ
Regional Conditioning By Color Mask (Inspire)ノード、条件付け(組み合わせ)ノードを使って下図のようにつなぐ

mask_colorは任意で指定する
Regional Conditioning By Color Mask (Inspire)ノードは以下のように値を変更した
strength(プロンプトの重み):0.7
dilation(カラーマスクのグラデーション、領域拡大):0.0
カラーマスクは色コードを合わせながらペイントなどで作成する
テキトーに塗りつぶしてみた

ベース
3girls, trio, 3d, tracen_school_uniform, general, from above, stage, horse_ears, horse_tail, looking_at_viewer, masterpiece, best quality, amazing quality,
赤
vivlos_\(umamusume\),laugh, long_hair, twintails, purple_eyes, brown_hair,
青
verxina_\(umamusume\), smile, long_hair, blue_hair, purple_eyes,
緑
cheval_grand_\(umamusume\), blush, short_hair, hat,
比較的まともな出力でもあまり良くない
心霊写真みたいになる
顔の距離が近いと、髪型などがまぜこぜになる

カラーマスク+ControlNet
カラーマスク↓

OpenPose↓

数値、プロンプトは同じ
シュバルグランが出てこない

参考内で使っていたCN-posetestは適当なラフでポーズ指定できる
ここでは棒立ちだが
プロンプトと値を調節すると少しだけましになったか?
3girls, trio, 3d, tracen_school_uniform, sky, grass,v_sisters, horse_ears, horse_tail, horse girl, looking_at_viewer, masterpiece, best quality, amazing quality,
strength:0.55
verxina_\(umamusume\), smile, blue_hair, purple_eyes,
strength:0.75
(cheval_grand_\(umamusume\): 1.4), brown hair, blue_eyes, streaked hair, peaked_cap, ears through headwear
strength:0.75
vivlos_\(umamusume\),laugh, twintails, purple_eyes, brown_hair,

立ち位置の固定はできるがキャラクターのビジュアルが混ざるのであまり良くない
プロンプトコントロール
“Manager"メニューから"Custom Nodes Manager"を開いて、ComfyUI Prompt Controlをインストール
インストール後Manager内では未インストールと表示される
githubからインストールしたほうがよい
cloneしてComfyUIのvenvに入ってpip insatall -r requirements.txt
Podを再起動
v2.1.3~v3.0.0-beta.3を使う場合、ソースコードにバグがあるので手動で修正する
Issue
comfyui-prompt-control/prompt_control/attention_couple_ppm.py
119行目と146行目の以下の条件文を置き換える
if self.kv["k"] is None
↓
if len(self.kv["k"]) == 0
こんな感じでつなぐ
プロンプト内でLoRAを指定できるのでLoRAを読み込むノードが要らないが、LoRAを変更したときの読み込みが少し遅い

プロンプトの記法
A1111に近い記法で書ける。A1111使えばというのは野暮
参考元に書いてあること日本語にしただけ
スケジューリング式
一単語の中で以下のように書く
a [red:blue:0.5] cat
これは、推論ステップ中にプロンプトを変更する式で、
0.5は割合を示す
つまり、30ステップの推論であれば、前半の15ステップはa red cat、
後半の15ステップはa blue catとなる
なお、2以上の値を設定すれば割合ではなくステップ数で切り替えられえる
a [red:blue:2] catなら2ステップ目からa blue catに切り替わる
a [red::0.5] catのようになにも入れなけばa red cat→a catとなる
逆の場合はa [:red:0.5] catだが、a [red:0.5] catと、手前のコロンを省略してもよい
入れ子構造も可能で、以下の場合なら0%~50%までa red cat、50%~70%までa blue cat、70%~100%までa catに変化していく
a [red:[blue::0.7]:0.5] cat
ただ、以下の複数個用の構文を使用したほうが分かりやすい
a [red:blue::0.5,0.7] cat
以下のように記述すると交互にプロンプトが変化する
10%ごとにプロンプトがaとbで切り替わる
[a|b:0.1]
LoRA読み込み
プロンプト内でLoRAを読み込むには、以下のように記述する
ファイル名を指定する。拡張子は付けても付けなくても可
末尾にある1はLoRAの重み
<lora:examplelora:1>
“loras"ディレクトリ内のexamplelora.safetensorが読み込まれる
“loras/sdxl/sdxlexample.safetensor"のような子ディレクトリに格納されたファイルも再帰的に読み込まれるため、pathの記述は不要
ただし、同じファイル名のloraがあった場合、先に見つかった方が読み込まれる
それを避けたい場合はファイル名を重複しないようにするか、以下のようにpathで指定する(“loras"ディレクトリからの相対パス)
<lora:sdxl/sdxlexample:1>
以下のようにスケジューリングも可能
推論ステップの半分までpartialoraが適応される
[<lora:partialora:1>::0.5]
プロンプトの重み付け
重みの記述がない場合、重みは1
重みが0の場合、完全に無視される
以下のように記述する
(dog :1.5), (cat :2)
関数の組み合わせ
2つ以上の関数を使う場合はANDを使って連結する
スタイル
以下のように記述する
STYLE(comfy, length)
引数1(重みの解釈)
comfycomfy++compeldown_weightA1111perp
引数2(正規化)- 引数なし
lengthmean
デフォルトはSTYLE(comfy)
COUPLE
x軸範囲でプロンプトを変化させる
sky, grass,
FILL()
COUPLE(0 0.2)
1girl, solo, vivlos_\(umamusume\),
long_hair, twintails, purple_eyes, brown_hair,
laugh, standing
COUPLE(0.45 0.55)
1girl, solo, verxina_\(umamusume\),
long_hair, blue_hair, purple_eyes,
smile, standing
COUPLE(0.8 1.0)
1girl, solo, cheval_grand_\(umamusume\),
short_hair, blue_eyes, hat,
blush, standing

LoRAをそれぞれに適応させればマイナーキャラもいけたり(調整は必要だが)
