[English ver. (WIP)](./README_en.md) # Dump U-Net ## 目次 - [Dump U-Net](#dump-u-net) - [1. 目次](#1-%E7%9B%AE%E6%AC%A1) - [2. これは何](#2-%E3%81%93%E3%82%8C%E3%81%AF%E4%BD%95) - [3. できること](#3-%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%93%E3%81%A8) - [4. 特徴量の抽出](#4-%E7%89%B9%E5%BE%B4%E9%87%8F%E3%81%AE%E6%8A%BD%E5%87%BA) - [4.1. U-Net の特徴量画像](#41-u-net-%E3%81%AE%E7%89%B9%E5%BE%B4%E9%87%8F%E7%94%BB%E5%83%8F) - [4.1.1. 画面説明](#411-%E7%94%BB%E9%9D%A2%E8%AA%AC%E6%98%8E) - [4.1.2. Colorization](#412-colorization) - [4.1.3. Dump Setting](#413-dump-setting) - [4.1.4. 抽出画像の例](#414-%E6%8A%BD%E5%87%BA%E7%94%BB%E5%83%8F%E3%81%AE%E4%BE%8B) - [4.2. アテンション層の特徴量抽出](#42-%E3%82%A2%E3%83%86%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%B3%E5%B1%A4%E3%81%AE%E7%89%B9%E5%BE%B4%E9%87%8F%E6%8A%BD%E5%87%BA) - [4.2.1. 画面説明](#421-%E7%94%BB%E9%9D%A2%E8%AA%AC%E6%98%8E) - [4.2.2. 例](#422-%E4%BE%8B) - [5. ブロックごとのプロンプトの変更](#5-%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%81%94%E3%81%A8%E3%81%AE%E3%83%97%E3%83%AD%E3%83%B3%E3%83%97%E3%83%88%E3%81%AE%E5%A4%89%E6%9B%B4) - [5.1. 概要](#51-%E6%A6%82%E8%A6%81) - [5.2. 画面説明](#52-%E7%94%BB%E9%9D%A2%E8%AA%AC%E6%98%8E) - [5.3. 記法](#53-%E8%A8%98%E6%B3%95) - [5.4. 例](#54-%E4%BE%8B) - [5.5. Dynamic Prompts との併用](#55-dynamic-prompts-%E3%81%A8%E3%81%AE%E4%BD%B5%E7%94%A8) - [6. TODO](#6-todo) ## これは何 U-Net の特徴量を可視化するための [stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui) の拡張です。 ## できること 1. モデルの途中出力の可視化:U-Net の各ブロックおよびアテンション層の特徴量を可視化する。 2. 層別プロンプト:U-Net の各ブロックでプロンプトを変更しながら画像を生成する。 3. 2.でプロンプトを変更したときの U-Net の特徴量の差分を可視化する。 ## 特徴量の抽出 例として以下の画像を使用する。 ![Model Output Image](images/00.png) ``` 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)` ![](images/README_00_01_gray.png) カラー出力 `OUT11, steps 20, Custom, Sigmoid(1,0), H=(2+v)/3, S=1.0, V=0.5` ![](images/README_00_01_color.png) #### 画面説明 ![](images/README_00.png)
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 ![](images/README_00_02.png)
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 ![](images/README_00_06.png)
Dump feature tensors to files
チェックすると U-Net の特徴量をファイルとして書き出す。
Output path
バイナリを出力するディレクトリを指定する。存在しなければ作成される。
#### 抽出画像の例 左から順に、`steps=1,5,10` の画像。 - IN00 (64x64, 320ch) ![IN00](images/IN00.jpg) - IN05 (32x32, 640ch) ![IN05](images/IN05.jpg) - M00 (8x8, 1280ch) ![M00](images/M00.jpg) - OUT06 (32x32, 640ch) ![OUT06](images/OUT06.jpg) - OUT11 (64x64, 320ch) ![OUT11](images/OUT11.jpg) ### アテンション層の特徴量抽出 現バージョンではクロスアテンション層の `Q*K` を出力する。 #### 画面説明 ![](images/README_00_07.png) ほぼ [U-Net の特徴量画像](#41-u-net-%E3%81%AE%E7%89%B9%E5%BE%B4%E9%87%8F%E7%94%BB%E5%83%8F) と同じ。 #### 例 横軸がトークン位置を表す。最初に開始トークン、最後に終了トークンが挿入されているので、間の75枚の画像が各トークンの影響を表す。 縦軸はアテンション層のヘッド。今のモデルでは h=8 なので画像が8つ並ぶことになる。 「`pink hair` はこの層に効いてるのかな?」みたいなことが分かる。 - IN01 ![Attention IN01](images/attn-IN01.png) - M00 ![Attention M00](images/attn-M00.png) - OUT10 ![Attention OUt10](images/attn-OUT10.png) ## ブロックごとのプロンプトの変更 ### 概要 内容は以下の記事を参照。 [Stable DiffusionのU-Netでブロックごとに異なるプロンプトを与えて画像生成する(ブロック別プロンプト)](https://note.com/kohya_ss/n/n93b7c01b0547) 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 に変更して生成した画像 となっている。 ### 画面説明 ![](images/README_01.png) ほぼ [U-Net の特徴量画像](#41-u-net-%E3%81%AE%E7%89%B9%E5%BE%B4%E9%87%8F%E7%94%BB%E5%83%8F) と同じ。
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](https://github.com/adieyal/sd-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ブロックにプロンプトを追加してみるテスト](https://gist.github.com/hnmr293/7f240aa5b74c0f5a27a9764fdd9672e2) ## TODO - K, VQK の可視化 - セルフアテンション層の可視化