Dynamic Promptsが便利すぎる件/今さら聞けない画像生成AI

まずは結論から書きます。
Stable Diffusion WebUIの拡張機能「Dynamic Prompts」に用いるWildcardsの相互参照を視覚的に確認できるツールを開発しました。
プログラミング知識のない私でも、ChatGPTを使えば1時間で作れました。
以上の文章が何を意味していのるか理解できる人は、この先は読まなくていいです。記事の末尾にあるGithubのリンクより、ツールをダウンロードしてお試しください。
1. Dynamic Promptsって何?
複数枚の画像をまとめて生成するときに、プロンプトの一部をランダムで変更する拡張機能です。
WebUI Forgeでは、デフォルトでインストールされています。
例えば以下のプロンプトで画像を生成してみましょう。
1girl, classroom,

以上のように、生成されるキャラクターが似通ってしまうことがよくあります。
潜在空間のなかで「教室(classroom)」という概念の近くに、「制服」「銀髪」「肩までの長さの髪」「横顔」などの概念が存在しているからです。
「classroom」という言葉に「引っ張られて」しまうわけです。
色々な髪型のキャラクターをランダムで生成したいときには困りますね。
そこで、Dynamic Promptsを有効にした上で、以下のようにプロンプトを書き換えます。
1girl, classroom, { long hair, | short hair, }

以上のように、ロングヘアとショートヘアが混在するようになりました。
{ プロンプトA | プロンプトB }
これがDynamic Promptsの表記法です。「 { } 」で括られた中から「 | 」で区切られた要素を、ランダムでプロンプトに書き起こします。
今回の場合は要素が2個なので、1:1の比率で(つまり50%ずつの確率で)プロンプトに書き込まれます。
髪の毛の色も指定してみましょう。
1girl, classroom,
{ long hair, | short hair, }
{ black | silver | orange | blue } hair,

銀髪以外にも、黒髪やオレンジ髪、青髪が生成されるようになりました。
あくまでもランダムなので、今回は青髪が多めに出力されています。100枚とか1000枚とか大量に生成すると、大数の法則に従って1/4ずつに近づいていくはずです。

完成した画像のメタデータをPNG Infoで確認すると、プロンプトが書き換えられていることが分かります。
2. Dynamic Promptsの便利な使い方
2-1. 重みづけ
「数値::プロンプト」で、各プロンプトの重みを指定できます。
たとえば次のように書くと、「黒髪:銀髪:オレンジ髪:青髪=7:1:1:1」の比率で生成されるようになります。
1girl, classroom,
{ long hair, | short hair, }
{ 0.7::black | 0.1::silver | 0.1::orange | 0.1::blue } hair,

なお、ここでは合計が「1.0」になるように数字を指定しましたが、そうする必要はありません。私が自分で理解しやすいので合計「1.0」にしているだけで、どんな数字でも機能します。
2-2. 複数選択
先頭に「数値$$」と書くと、指定した個数のプロンプトが抽選されます。
たとえば次のように書いた場合、「立ったポーズ」「カメラ目線」「手に花を持つ」という3つのプロンプトから、ランダムで2つが選択されます。
1girl, classroom,
{ long hair, | short hair, }
{ black | silver | orange | blue } hair,
{ 2$$ standing, | looking at viewer, | holding flower, }

なお、「選択する個数の範囲」を指定することも可能です。
先頭に「最小値-最大値$$」と書きます。
たとえば次のように書けば、「最小1個、最大3個」がランダムで選択されます。
1girl, classroom,
{ long hair, | short hair, }
{ black | silver | orange | blue } hair,
{ 1-3$$ standing, | looking at viewer, | holding flower, }

最小値や最大値を省略することも可能です。
{ -3$$ standing, | looking at viewer, | holding flower, }
{ 1-$$ standing, | looking at viewer, | holding flower, }
なお、複数選択をした場合には各プロンプトはカンマで区切られます。
たとえば{ 2$$ blue | yellow | red }と記載した場合、「blue, yellow」のようにカンマ区切りのプロンプトが作成されます。
(使い道が難しいのですが)このカンマを任意の文字列に変更できます。
先頭に「数値$$ 文字列 $$」と書きます。
{ 2$$ and $$ blue | yellow | red }
たとえば上記のように表記した場合、「blue and yellow」のようなプロンプトが作成されます。AND構文を使いたいときには便利かもしれません。また、Stable Diffusionではカンマの有無で生成結果が大きく変わります。「数値$$ $$」と書くとカンマを省略できるので、この辺りにも応用の道がありそうです。
3. ワイルドカードを使おう!
まずはこんなプロンプトで画像を生成してみましょう。
1girl, classroom, looking at viwer
holding { flower | sword | food }

花の色を変えたいし、剣以外の武器も握らせたいし、食べ物の種類も指定したいですね。
Dynamic Promptsでは「{ }」を多重構造にできるので、こんな感じのプロンプトを書くことができます。
1girl, classroom, looking at viwer
holding
{ flower,
{ blue | yellow | red | purple | pink | white | black } flower,
| weapon,
{ sword, | axe, | mace, | handgun, | rifle, }
| food,
{ apple, | lemon, | meat, }
}

かなりゴチャゴチャしてきましたね。
さらに剣の色を「黒/銀/金」から選択したかったり、リンゴの色を「赤/緑/黄色」から選択したかったりすると……収拾がつかなくなっていきます。
そんなときに役に立つのが「wildcards」です。

たとえば上記のような「花の色を列挙した.txtファイル」を作り、「\stable-diffusion-webui\extensions\sd-dynamic-prompts\wildcards」のフォルダ内に保存します。

そして、次のようなプロンプトを試してみましょう。「__ファイル名__」で、このフォルダに保存した.txtファイルの内容を呼び出すことができます。
1girl, classroom, looking at viwer
holding flower, __FlowerColors__ flower,

この.txtファイルのことを「ワイルドカード」と呼びます。
ワイルドカードの中身には、今まで紹介してきた記法が使えます。

さらに上記の例で分かる通り、ワイルドカードは多重構造にできます。上記の例では、「HoldingObject.txt」というワイルドカードの中に、「FlowerColors.txt」の内容を呼び出しています。
では、「HoldingObject.txt」を試してみましょう。
1girl, classroom, looking at viwer
holding __HoldingObject__


画像のメタデータを確認すると「holding flower, purple flower,」となっており、「HoldingObject.txt」および「FlowerColors.txt」の内容がきちんと読み込まれていると分かります。
以上の機能を組み合わせれば、かなり複雑なプロンプトを生成できるようになります。
1girl, classroom, looking at viwer
__Schoolgirl__
holding __HoldingObject__


問題はここからです。
ワイルドカードはいくらでも多重構造にできるため、カードが増えてくると参照関係が分かりにくくなります。また、循環参照を作ってしまった場合には、上手く機能しなくなります。
したがって、「どのカードがどのカードを参照しているのか」を視覚的に確認できるツールがあると便利なのです。

4. WildcardVisualizer

なので、そういうツールを作りました。
私はプログラミング知識ゼロですが、ChatGPT(GPT-4o)と相談しながら作ったところ、約1時間で完成させることができました。
4-1. インストール方法
上記のGithubのページに飛び、中段あたりにある「Download ZIP」からダウンロードできます。
推奨環境はPython 3.10およびWindows10です。他の環境では動作確認をしていません。
(※とはいえPython 3.10は、Stable Diffusionを動かすためにも必要なので、WebUIで遊んでいる方ならすでにインストール済みだと思います)
4-2. 使い方
- お好みの場所でzipファイルを解凍してください。
- フォルダ内の「run_app.bat」をダブルクリックしてください。これによりコマンドプロンプトが起動し、アプリケーションが起動します。なお、このツールはFlaskというライブラリを使っています。もしもインストールされていない場合には、自動的にインストールされます。
- コマンドプロンプトに「http://127.0.0.1:5000」と表示されたら、起動完了です。ブラウザソフトからこのアドレスを閲覧してください。
- ワイルドカードを保存しているフォルダのパスを「Enter the Wildcard Folder Path:」と書かれた入力欄にコピペしてください。
- 「Run」ボタンを押すとツールが実行されて、ワイルドカードの相互参照の関係が可視化されます。
- アプリケーションを終了するときは、コマンドプロンプトで「Ctrl+C」→「y」→「Enter」と入力してください。
繰り返しになりますが、私はプログラミング知識ゼロです。
Githubのアカウントを開設すること自体、今回が初めてという情報弱者でした。
それでもChatGPTを使えばこの程度のツールなら1時間で作れてしまったのです。
生成AIが世に出てからというもの、パソコンは「何でもできる箱」だったのだと痛感しています。SNSとYouTubeとAPEXで遊ぶためだけの箱ではなかったんですね…
今回のツールをどのようにして作ったのかも、いずれブログ記事にする予定です。
5. 補遺
Dynamic Promptsのワイルドカードには、.txtファイルの他にもYAMLやJSONなどの形式が対応しています。
.txtファイルの場合、ワイルドカードの中で改行を使いにくいという難点があります。改行が「 | 」として認識されて、プロンプトの区切りとして見做されてしまうためです。
その点、YAML形式では改行を自由に使えるので、より柔軟で複雑なワイルドカードを作りたいときには選択肢になるでしょう。
なお、WildcardVisualizerが対応しているのは、現状では .txt形式のみです。