人工知能と親しくなるブログ

人工知能に関するトピックを取り上げるブログです

誰でもわかるStable Diffusion CFGスケールのしくみ

このブログでは人工知能全般について書くつもりでしたが、結局今までStable Diffusionのことばかり書いています。画像生成AIは今とてもホットな話題なのでしばらくはStable Diffusionの記事ばかりになるかもしれません。

※何か解説してほしいことのリクエストあればコメントで教えてください。

 

今回は「CFGスケール」について解説します。

AI画像生成ツールは現在「Stable Diffusion Web UI」をはじめいくつか出回っていますが、どれも「CFGスケール」という設定を持っています。これはいったい何なのでしょう?

Stable Diffusion Web UIにもあるCFGスケール設定
これは一体何?

 

CFGスケールの大ざっぱな説明

Stable Diffusionの解説サイトに書かれているCGFスケールの説明はだいたい以下のようなものです。

  • CFGスケールとは、「生成する画像にプロンプトをどれだけ強く反映するか」を決める値のこと。
  • CFGスケールの値を大きくすればするほど、Stable Diffusionはよりプロンプトの文章に忠実に絵を描こうとする
  • CFGスケールの値が小さいと、Stable Diffusionはよりプロンプトに縛られない創造性の高い絵を描こうとする
  • CFGスケールを高くしすぎると絵のクオリティが下がる
  • CFGスケールを低くしすぎるとプロンプトと違う絵になる

CFGスケールの値は大きすぎても小さすぎてもダメで、最適な値は一般的に「7~10」とされています。また、サンプリングステップ数を上げることによって高CFGスケールでも画像が破綻しづらくなる可能性があります。

絵を生成したいだけなら、この説明だけで十分です。

しかし、具体的なしくみを知りたい方は、以下の解説を読み進めてください。

 

CFGスケールの具体的な説明

解説の前提知識

解説をシンプルにするため以下のような前提を設けます。

  • 解説に出てくる画像はすべて2ドットでできている
  • 画像には色がなく、グレースケールで描かれる
  • 画像生成は「Latent space」でなくピクセルそのままで行われる

普通の画像は512x512ピクセルといったサイズですが、この記事中の「画像」はたったの2ピクセルしかありません。しかも、画像はグレースケールです。

Stable Diffusionは本来は画像を「圧縮」された状態で生成して、最後にデータを「展開」して画像に戻す、という処理をしています。この「圧縮」状態を「Latent space」といいます。しかし本記事の画像は2ピクセルしかないので、「圧縮」せずにピクセルのままの状態(Pixel spaceと呼ばれたりします)で生成を行うことにします。

 

理想の絵を求めてさまようAI

普通「絵を描く」といえば真っ白なキャンバスに色を乗せていく作業のことです。しかしStable Diffusionがやっているのはその逆で、適当な色でゴチャゴチャに塗られたキャンバスから色を取り除いていく作業をしています。最初のゴチャゴチャの色を「ノイズ」と呼びます。

 

今回はもう少し違う見方をしてみましょう。デジタル画像の場合、「色」とは「数字」です。例えばグレースケールでは0は真っ黒、255は真っ白の点を表します。

この数字を使って、2ピクセル画像を「2つの数字を持つベクトル」で表せます。

例えば、[0 0]とはどんな絵でしょう?これは2ピクセルどちらも真っ黒の絵です。[255 255]は真っ白の絵です。[127 127]なら白と黒の中間のグレーの絵に、[0 255]なら左側は真っ黒、右側は真っ白の絵となります。

2ピクセルの絵

 

では、画像を生成します。まずノイズだらけの絵を用意します。適当な数字を選んだら、[8 30]が出てきました。これを初期の「ノイズ絵」とします。ちなみに実際のStable Diffusionではこの適当な数字は「Seed」によって決まります。同じSeedを使えば毎回同じ数字が出てきます。

一方、あなたの描きたい絵は[200 180]だとします。意味の分からない絵ですがあなたにとってはこれが「理想の絵」だと思ってください。

ノイズ絵から理想の絵を生み出す

ノイズ絵と理想の絵は数字からできているので、それぞれをグラフに表してみましょう。

ゴール目指して放浪の旅

まるで地図のように見えると思います。

Stable Diffusionがやっているのは、スタート地点(ノイズ絵)からいろいろさまよってゴール(理想の絵)までたどり着くさすらいの旅です*1。この地図上のあちこちには画像が眠っていて、たとえば「ネコの絵ゾーン」があったり「イヌの絵ゾーン」があったりします。Stable Diffusionはある程度の絵の知識を持っているので、「あっちに行けば絵っぽいものがあるかな」というアタリをつけてそっちのほうに向かっていこうとします。しかし、そちらの方向が理想の絵に向かっているとは限りません。そこで、あなたはStable Diffusionに「正しい方向」を教えてやる必要があります。それが「プロンプト」です。ちょうどマップアプリの経路探索と同じようなものです。

 

良いナビと悪いナビ

上で解説した通り、あなたのプロンプトは理想の絵に向かうための「ナビゲーション」になります。その仕組みはこうです。

理想の絵を説明したプロンプトを打ち込むと、Stable Diffusionで使われている「テキストエンコーダー」がそのプロンプトを解読して数字に変換します。Stable Diffusionは変換された数字を見て、現在の位置と照らし合わせて、ゴールがどっちかを推測します。

もしあなたのプロンプトが完璧であれば推測ゴール地点はきっちり[200 180]を指し示すはずですが、そううまくはいきません。もしかしたら[165 140]あたりを指し示すかもしれません。ゴール地点とは程遠いですが、少なくともそちらの方向に向かえばゴールに近づくことはできそうです。それでもゴール地点とは違うので、ちょっとだけそっちの方向に移動して、移動した後にまたナビを見直すことにします。もし現在地と推測ゴールとの距離が[100 80]で、20分の1の距離だけ移動するとしたら、[100/20 80/20] = [5 4]だけ進むことになります。

移動後の地点は少しゴールに近寄っているので、そこでナビを見直したらもう少し正確なゴール地点の推測ができるかもしれません。

こうしてStable Diffusionはゴール地点を目指して少しずつ移動していくのです。

焦らず少しずつ進む

この「目標に向かって移動する」ことをStable Diffusionでは「サンプリング」といいます。「ナビを何回見直すか」を決めるのが「Sampling steps」です。「1度にどれだけ移動するか」を決めるのが「Sampling method」(またはスケジューラー)です。

Sampling methodとSampling steps



一方、Stable Diffusionには「絶対に行ってはいけない方向」を指し示す「悪いナビゲーション」も存在します。それが「ネガティブプロンプト」です。ネガティブプロンプトもテキストエンコーダーに送られ、数字に変換されます。Stable Diffusionはネガティブプロンプトの数字を見て「あっちの方向には行っちゃダメだな」と判断します。

ちなみにネガティブプロンプトが空の場合、「悪いナビゲーション」は何かの絵がありそうな方角を適当に指し示します。何の絵かは分かりませんが、Stable Diffusionが知っている何かです。これが理想の絵である可能性は非常に低いので、やはりその方角も「行ってはいけない方角」です*2

 

CFGスケールはブースター

試しに、悪いナビに従ったらどっちの方向に行くかを計算してみます。次の推測地点は現在地から[1 3]離れた距離を示したとします。すると[1 3]だけ移動することになります。

良いナビの移動距離は(上で計算したように)[5 4]でした。良いナビと悪いナビの移動の差を取ってみると

[5-1 4‐3] = [4 1]

となりました。

この良いナビと悪いナビの移動差が何を意味するかというと、「正しい方向に向かってネガティブプロンプトから離れる移動」、いわば「補正移動」です。良いナビに従う移動だけでなく、この補正移動も行うことで、より正しいゴール位置に向かうことができます。

この「補正移動」をどれくらい行うかを決めるのがCFGスケールなのです。

ピンク矢印は「向かってはいけない場所」へ向かう移動
青矢印は「ゴール地点」へ向かう移動

今回の例では本来のゴール地点は[200 180]なのですが、ネガティブプロンプトを入れた影響でゴール地点がずれて[210 175]とかになるかもしれません。ネガティブプロンプト要素を絵から取り除くせいで絵が変わってしまうからです。「補正移動」はこのゴール地点を補正する意味合いがあります。

CFGスケールが1のときは、補正は行いません*3

CFGスケールが増えるたびに補正移動にブーストがかかり、一度の移動距離が伸びます。「CFGスケール値-1」の倍数がブーストによる移動距離です。例えば補正移動距離が[4 1]でCFGスケールが値が3の場合、まず良いナビによる移動[5 4]を行って、そこからさらに[4x(3-1) 1x(3-1)] = [8 2]だけ補正移動を行います。

 

CFGスケールの最適値

CFGスケール値はどれくらいの値がいいのかは、どれほどプロンプトを重視したいかによります。上でも書いた通り、適正なCFGスケールは「7~10」とされています。Stable DiffusionのCFGスケールのデフォルト値は7です。「なぜ7なのか?」と思われるかもしれませんが、私にもわかりません…経験的に決められた値のようです。

プロンプトは通常いろいろな要素を詰め込むので、その要素すべてを絵に表現するにはどれか特定の要素だけをゴールにするわけにはいきません。

CFGスケールを上げると良いナビ(つまりプロンプトの指定)の方向に大きく移動するのでプロンプトが反映されやすくなりますが、ブーストをかけすぎるとピーキーになり、移動のたびにプロンプトのいろいろな要素にあちこち振り回されて絵が破綻してしまう可能性があります。「指定に一貫性のある美しいプロンプト」であれば、移動の方角がきれいに定まってCFGスケールを上げても破綻しづらくなるかもしれませんが、プロンプトのテキストが長くなると一貫性を保つのが難しくなります。

逆にCFGスケールを下げすぎるとなかなか理想のエリアに近づけず、プロンプトがあまり反映されないぼんやりした絵になってしまう恐れがあります。「7」というCFGスケール値はプロンプト要素のどれにも近すぎず遠すぎずちょうどいいバランスのようですが、「いまいちプロンプト通りに描いてくれない」と感じたときはCFGスケールを上げてみてもいいでしょう。

個人的な使用感を言うと、ある程度プロンプトを整理して書けばCFGスケールを20あたりまで上げても以外にも破綻なく描いてくれることが多いですが、値を大きくすると色飛びしたり細部がつぶれたりするので、上げるとしても20あたりが限界だと思います。

 

実際の画像生成はもっと複雑

上の例では画像が2ピクセルしかなかったので2次元の地図のように表すことができましたが、実際のStable Diffusionではもっと大きな画像を扱うので、次元数は比べ物にならないほど大きくなります。例えば512x512ピクセルの画像を生成するとき、次元数は16384次元!!これではもはや地図のような図で表すことはできません。

さらに、実際のStable Diffusionでの移動空間は「Latent space」とよばれる「圧縮空間」なので、各次元の数字も単純に「色の濃さ」を表すわけではありません。データを圧縮しないとデータが大きすぎてとてもPCで動かないので、仕方がありません。

しかし、「ナビを頼りに理想の絵に近づいていく」という処理やCFGスケールの基本的な考えは何次元であっても同じです。CFGスケールによって、ネガティブプロンプト画像エリアから離れてプロンプト画像エリアに近づくためのブーストをかけるのです。

 

まとめ

今回はCFGスケールについてまとめました。画像生成の時にはそこまで意識して設定することはないと思いますが、仕組みを知っておけばプロンプト指定と生成画像の関係性をより理解しやすくなるのではないかと思います。

*1:つまり「ノイズだらけの絵からノイズを取る」とは「地図上を移動する」ということです

*2:実際、オリジナルのCFG論文はネガティブプロンプトを想定しておらず、空プロンプトを想定しています

*3:正確には、悪いナビによる移動先を起点として補正移動「のみ」を1回行います。結果的に、良いナビによる移動だけを行ったことと同じになります