デマこい!

「デマこいてんじゃねえ!」というブログの移転先です。管理人Rootportのらくがき帳。

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

このエントリーをはてなブックマークに追加
Share on Tumblr

 まずは結論から書きます。

 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ずつに近づいていくはずです。

「{ long hair, | short hair, } { black | silver | orange | blue } hair,」と書かれた箇所から抽選が行われて、「long hair, orange hair,」になっている。

 完成した画像のメタデータ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__
  

 問題はここからです。

 ワイルドカードはいくらでも多重構造にできるため、カードが増えてくると参照関係が分かりにくくなります。また、循環参照を作ってしまった場合には、上手く機能しなくなります。

 したがって、「どのカードがどのカードを参照しているのか」を視覚的に確認できるツールがあると便利なのです。

Wildcardsがこのくらいまで増えると、人間の記憶力ではどれがどれを参照していたのか覚えきれなくなり、管理できなくなる。

 

 

4. WildcardVisualizer

 なので、そういうツールを作りました。

 私はプログラミング知識ゼロですが、ChatGPT(GPT-4o)と相談しながら作ったところ、約1時間で完成させることができました。

 

4-1. インストール方法

github.com

 

 上記のGithubのページに飛び、中段あたりにある「Download ZIP」からダウンロードできます。

 推奨環境はPython 3.10およびWindows10です。他の環境では動作確認をしていません。

(※とはいえPython 3.10は、Stable Diffusionを動かすためにも必要なので、WebUIで遊んでいる方ならすでにインストール済みだと思います)

 

4-2. 使い方
  1. お好みの場所でzipファイルを解凍してください。
  2. フォルダ内の「run_app.bat」をダブルクリックしてください。これによりコマンドプロンプトが起動し、アプリケーションが起動します。なお、このツールはFlaskというライブラリを使っています。もしもインストールされていない場合には、自動的にインストールされます。
  3. コマンドプロンプトに「http://127.0.0.1:5000」と表示されたら、起動完了です。ブラウザソフトからこのアドレスを閲覧してください。
  4. ワイルドカードを保存しているフォルダのパスを「Enter the Wildcard Folder Path:」と書かれた入力欄にコピペしてください。
  5. 「Run」ボタンを押すとツールが実行されて、ワイルドカードの相互参照の関係が可視化されます。
  6. アプリケーションを終了するときは、コマンドプロンプトで「Ctrl+C」→「y」→「Enter」と入力してください。

 

 

 

 繰り返しになりますが、私はプログラミング知識ゼロです。

 Githubのアカウントを開設すること自体、今回が初めてという情報弱者でした。

 それでもChatGPTを使えばこの程度のツールなら1時間で作れてしまったのです。

 生成AIが世に出てからというもの、パソコンは「何でもできる箱」だったのだと痛感しています。SNSYouTubeとAPEXで遊ぶためだけの箱ではなかったんですね…

 

 今回のツールをどのようにして作ったのかも、いずれブログ記事にする予定です。

 

 

5. 補遺

 Dynamic Promptsのワイルドカードには、.txtファイルの他にもYAMLJSONなどの形式が対応しています。

 .txtファイルの場合、ワイルドカードの中で改行を使いにくいという難点があります。改行が「 | 」として認識されて、プロンプトの区切りとして見做されてしまうためです。

 その点、YAML形式では改行を自由に使えるので、より柔軟で複雑なワイルドカードを作りたいときには選択肢になるでしょう。

 なお、WildcardVisualizerが対応しているのは、現状では .txt形式のみです。