English ver.

Dump U-Net

目次

これは何

U-Net の特徴量を可視化するための stable-diffusion-webui の拡張です。

できること

  1. モデルの途中出力の可視化:U-Net の各ブロックおよびアテンション層の特徴量を可視化する。
  2. 層別プロンプト:U-Net の各ブロックでプロンプトを変更しながら画像を生成する。
  3. 2.でプロンプトを変更したときの U-Net の特徴量の差分を可視化する。

特徴量の抽出

例として以下の画像を使用する。

Model Output Image

Model: waifu-diffusion-v1-3-float16 (84692140)
Prompt: a cute girl, pink hair
Sampling steps: 20
Sampling Method: DPM++ 2M Karras
Size: 512x512
CFG Scale: 7
Seed: 1719471015

U-Net の特徴量画像

たとえば以下のような画像を生成する。

グレースケール出力 OUT11, steps 20, Black/White, Sigmoid(1,0)

カラー出力 OUT11, steps 20, Custom, Sigmoid(1,0), H=(2+v)/3, S=1.0, V=0.5

画面説明

Extract U-Net features
チェックすると U-Net の特徴量抽出が有効になる。
Layers
抽出対象のブロックを指定する。コンマ区切り、ハイフン区切りが使える。IN11-M00-OUT00は繋がっている。
Image saving steps
抽出対象のステップを指定する。
Colorization
出力画像の色を指定する。
Dump Setting
特徴量のバイナリを出力する設定を行う。
Selected Layer Info
Layers で指定したブロックの詳細が出力される。

抽出するブロックの指定方法:

単体指定: IN00
    IN00 から IN11、M00、OUT00 から OUT11 が使える。
複数指定: IN00, IN01, M00
    コンマ `,` で区切って複数のブロックを指定できる。
範囲指定: IN00-OUT11
    ハイフン `-` で区切って範囲を指定できる。
    両端は範囲に含まれる。
    IN11, M00, OUT00 は繋がっている。
範囲指定(ステップ付き): IN00-OUT11(+2)
    範囲指定の後に `(+数字)` と書くとステップを表す。
    +1 と書くと通常の範囲指定と同じ。
    +2 と書くと一つ飛ばしで指定したことになる。
    例えば上記の例は
    IN00, IN02, IN04, IN06, IN08, IN10,
    M00,
    OUT01, OUT03, OUT05, OUT07, OUT09, OUT11
    を指定したことになる。

Colorization

Colorize method
色付けの方法を指定する。
White/Black は特徴量を v として、|v| が大きいピクセルを白、小さいピクセルを黒で表示する。
Red/Bluev が大きいピクセルを赤、小さいピクセルを青で表示する。
Customv の値から RGB もしくは HSL 色空間の値を自由に計算する。
Value transform
特徴量の値は必ずしもそのまま色の指定に使える大きさではない。そのときにピクセル値へ変換するときの変換方法を指定する。
Auto [0,1] は与えられた特徴量の最小値と最大値を使って値を [0,1] に線型変換する。
Auto [-1,1] は同じく [-1,1] に線型変換する。
LinearClamp min./max. を指定して、その範囲を Colorize methodWhite/Black のとき [0,1] に、それ以外のとき [-1,1] に線型変換する。

Sigmoidgainoffset を指定して、v + offsetシグモイド関数で変換する。出力は Colorize methodWhite/Black のとき [0,1] に、それ以外のとき [-1,1] になる。
Color space
Value transform で変換した値 v をピクセル値に変換するコードを書く。v の範囲は Colorize method および Value transform の指定により [0,1] もしくは [-1,1] で与えられる。計算結果は [0,1] でクリップされる。
コードは numpy をグローバル環境として実行される。たとえば、abs(v)numpy.abs(v) の意味になる。

Dump Setting

Dump feature tensors to files
チェックすると U-Net の特徴量をファイルとして書き出す。
Output path
バイナリを出力するディレクトリを指定する。存在しなければ作成される。

抽出画像の例

左から順に、steps=1,5,10 の画像。

  • IN00 (64x64, 320ch) IN00

  • IN05 (32x32, 640ch) IN05

  • M00 (8x8, 1280ch) M00

  • OUT06 (32x32, 640ch) OUT06

  • OUT11 (64x64, 320ch) OUT11

アテンション層の特徴量抽出

画面説明

ほぼ U-Net の特徴量画像 と同じ。

横軸がトークン位置を表す。最初に開始トークン、最後に終了トークンが挿入されているので、間の75枚の画像が各トークンの影響を表す。

縦軸はアテンション層のヘッド。今のモデルでは h=8 なので画像が8つ並ぶことになる。

pink hair はこの層に効いてるのかな?」みたいなことが分かる。

  • IN01 Attention IN01

  • M00 Attention M00

  • OUT10 Attention OUt10

ブロックごとのプロンプトの変更

概要

内容は以下の記事を参照。

Stable DiffusionのU-Netでブロックごとに異なるプロンプトを与えて画像生成する(ブロック別プロンプト)

Example of Difference map

Example of Difference map

Example of Difference map

Example of Difference map

Model: waifu-diffusion-v1-3-float16 (84692140)
Prompt: a (~: IN00-OUT11: cute; M00: excellent :~) girl
Sampling Method: Euler a
Size: 512x512
CFG Scale: 7
Seed: 3292581281

上の画像は順番に、

  • a cute girl で生成した画像
  • IN00 のみ cute を excellent に変更して生成した画像
  • IN05 のみ cute を excellent に変更して生成した画像
  • M00 のみ cute を excellent に変更して生成した画像

となっている。

画面説明

ほぼ U-Net の特徴量画像 と同じ。

Output difference map of U-Net features between with and without Layer Prompt
ブロックごとのプロンプトが有効の時と無効の時の U-Net の特徴量を比較して差分画像を出力する。

記法

プロンプト中で次に示す特殊な記法を用いることで、ブロックごとのプロンプトを指定できる。

a (~: IN00-OUT11: cute ; M00: excellent :~) girl

この場合、IN00~OUT11 まで(つまり全体)で

a  cute  girl

が使われるが、M00 のみ

a  excellent  girl

が使われることになる。

指定は (~: から :~) までの間で行う。書式は以下の通り。

(~:
    ブロック指定:プロンプト;
    ブロック指定:プロンプト;
    ...
    ブロック指定:プロンプト;
:~)

(~: の後、:~) の前、: の前、; の後は空白を入れてもいい。ただし :プロンプト; の部分の空白はそのまま結果に反映されるので注意。一番最後のプロンプトの後のセミコロンは無くてもいい。

ブロック指定は以下のように行う。おおむね X/Y plot と同じ。なお、範囲が重なっている場合は後に指定したものが優先される。

単体指定: IN00
    IN00 から IN11、M00、OUT00 から OUT11 が使える。
複数指定: IN00, IN01, M00
    コンマ `,` で区切って複数のブロックを指定できる。
範囲指定: IN00-OUT11
    ハイフン `-` で区切って範囲を指定できる。
    両端は範囲に含まれる。
    IN11, M00, OUT00 は繋がっている。
範囲指定(ステップ付き): IN00-OUT11(+2)
    範囲指定の後に `(+数字)` と書くとステップを表す。
    +1 と書くと通常の範囲指定と同じ。
    +2 と書くと一つ飛ばしで指定したことになる。
    例えば上記の例は
    IN00, IN02, IN04, IN06, IN08, IN10,
    M00,
    OUT01, OUT03, OUT05, OUT07, OUT09, OUT11
    を指定したことになる。
その他全て: _ (アンダーバー)
    これは特殊な記号で、優先度は最も低い。
    他のどのブロックにも当てはまらなかった場合、ここで指定したプロンプトが使われる。

いくつか例を挙げる。

1: (~: IN00: A ; IN01: B :~)
2: (~: IN00: A ; IN01: B ; IN02: C :~)
3: (~: IN00: A ; IN01: B ; IN02: C ; _ : D :~)
4: (~: IN00,IN01: A ; M00 : B :~)
5: (~: IN00-OUT11: A ; M00 : B :~)

1: IN00でAを、IN01でBを使う。他のブロックでは何も無し。

2: IN00でAを、IN01でBを、IN02でCを使う。他のブロックでは何も無し。

3: IN00でAを、IN01でBを、IN02でCを使う。他のブロックではDを使う。

4: IN00とIN01でAを、M00でBを使う。他のブロックでは何も無し。

5: IN00からOUT11まで(つまり全体)でAを使う。ただしM00ではBを使う。

Dynamic Prompts との併用

検証には Dynamic Prompts との併用が便利。

たとえば1ブロックでのみプロンプトを変更した際の影響を見たい場合、Dynamic Prompts の Jinja Template を有効にして

{% for layer in [ "IN00", "IN01", "IN02", "IN03", "IN04", "IN05", "IN06", "IN07", "IN08", "IN09", "IN10", "IN11", "M00", "OUT00", "OUT01", "OUT02", "OUT03", "OUT04", "OUT05", "OUT06", "OUT07", "OUT08", "OUT09", "OUT10", "OUT11" ] %}
  {% prompt %}a cute school girl, pink hair, wide shot, (~:{{layer}}:bad anatomy:~){% endprompt %}
{% endfor %}

と指定すると、各ブロックでの「bad anatomy」の効果を調べる……といったことができる。

実際の例:ブロック別プロンプトで特定の1ブロックにプロンプトを追加してみるテスト

TODO

  • セルフアテンション層の可視化