Stable Diffusionベストプラクティス考察 txt2img編 Part.1


[1.はじめに](#1-はじめに)
[2.変数の特徴と活用方法](#2-変数の特徴と活用方法)
[3.まとめ](#3-まとめ)
[4.おわりに](#4-おわりに)

#  TL;DR
基本的な戦略
1. ランダム×固定seedでの`Prompt engineering`
1. ランダムseedでの`Seed hunting`
1. 固定Seedでの`Prompt engineering`

その際の注意点
- promptの長さは75token以内に
- step数は20程度まで減らして時短
    - 最後は100以上で清書
- 大きなサイズでの生成は予期せぬ複製や見切れを生むため注意
- Scaleはデフォルトでよし


# 1. はじめに

この記事は、Stable Diffusionへの理解を深め、より効率的に使いこなすための方法を考察したものです。
なんとなくpromptを試してみる状態から、少しステップアップできる内容になっていると思います。

一応シリーズ化の予定です。

#### この記事で扱うトピック
1. txt2imgを使う際にユーザーがコントロールできる主な変数は何か
2. それらの変数の持つ意味・影響など、知っておくべき基礎知識は何か
3. 上記2つを踏まえた上で、どの様にtxt2imgを使いこなすことができるか

#### この記事では扱わないトピック
今のところ、どちらもPart.2以降で扱う予定でいます。

1. `Prompt engineering` (promptを改良する具体的なテクニック)
1. sampler


# 2. 変数の特徴と活用方法
`txt2img`における主要な変数を、画像への影響が大きいものから整理します。

|変数|影響度|ポイント|
|:---:|:---:|:---:|
|prompt|★★★★★|長さに制限がある点に注意
|seed|★★★★☆|promptで指定していない要素がどう描かれるかを決定する
|steps|★★☆☆☆|画像の全体的なクオリティーを左右する
|height|★☆☆☆☆|大きな値を設定すると不気味な画像が生まれる要因になる
|width|★☆☆☆☆|同上
|scale|★☆☆☆☆|7~11程度がちょうどいい

[公式リポジトリ](https://github.com/CompVis/stable-diffusion)内のスクリプトを用いた場合、[diffusersライブラリ](https://github.com/huggingface/diffusers)を用いた場合の各変数の設定方法です。

```bash
python scripts/txt2img.py \
    --prompt "a photograph of an astronaut riding a horse" \
    --seed 1024 \
    --ddim_steps 50 \
    --H 512 \
    --W 512 \
    --scale 7.5
```

diffusersライブラリの場合は以下の様に設定します
```python
import torch
from diffusers import StableDiffusionPipeline

generator = torch.Generator("cuda").manual_seed(1024) # seed

pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4", revision="fp16", torch_dtype=torch.float16, use_auth_token=True)  
image = pipe(
    prompt="a photograph of an astronaut riding a horse",
    generator=generator, # seed
    num_inference_steps=50,
    height=512,
    width=512,
).images[0]
```

## Prompt 【★★★★★】
|txt2img.py|diffusers|
|:---:|:---:|
|--prompt|prompt|


### 特徴

#### 曖昧さ

例えばpromptを`football`にして何枚も画像を生成すると、「アメフト」と「サッカー」両方の画像が現れます。
これは、`football`がどちらとも解釈できる**曖昧さ**を持った言葉だからです。
**曖昧さ**の概念は非常に重要で、後述のseedと強く関係しています。

![football.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532021/142feb81-ace9-9f88-a053-07a51de7d8a4.png)


#### CLIPによる制約
promptの長さには制限があります。
promptはOpenAIの[CLIP](https://huggingface.co/docs/transformers/model_doc/clip)を使ってトークン[^2]化されてから処理されます。
このCLIPに制限があり、75トークン以上はカットされてしまいます。
[^2]: tokenの概念に関する詳しい説明は[こちら](https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them)をご覧ください。

要するに、**promptは長すぎてはダメ**ということです。

### 活用方法
実際にpromptが幾つのトークンになるかは[こちら](https://beta.openai.com/tokenizer)から試すことができます。
75を超える場合は削りましょう。
イメージしやすいようにサンプルを載せておきます(2つ目のpromptはピーチ姫が出てきます)。
|token数|prompt|
|:---:|---|
|32|anime kyoto animation key by greg rutkowski night, single white hair girl from behind, in abandoned chapel with overgrown flowers and plants 
|41|Ultra realistic photo, princess peach in the mushroom kingdom, beautiful face, intricate, highly detailed, smooth, sharp focus, art by artgerm and greg rutkowski and alphonse mucha|
|74|A beautiful neon cyberpunk city street at night, apartment, skyscrapers, by alphonse mucha caravaggio monet ,4K resolution, 8K resolution, a lot of Decoration and embellishments, sci-fi, photorealistic, highly detailed, sharp focus, clean 8k, volumetric lighting, octane render, ceramic


## Seed 【★★★★☆】
|txt2img.py|diffusers|default|
|:---:|:---:|:---:|
|--seed|generator|ランダム

diffusersライブラリでseedを設定するときは`torch.Generator`を用います。

```python
import torch

generator = torch.Generator("cuda").manual_seed(1024) # 1024がseed値
image = pipe(
    prompt="a photograph of an astronaut riding a horse",
    generator=generator
).images[0]
```

### 特徴
画像生成に用いられる乱数のようなもので、全く同じpromptでもseedが違えば異なる画像が出力されます。

seedを活用するにあたって重要なのは、次の2つのケースで起きる現象を理解することです。
1. promptを固定し、複数のランダムなseedで画像を生成する
1. seedを固定し、複数の僅かに異なるpromptで画像を生成する

こちらは横軸に同じpromptで、縦軸に同じseedで生成した画像を並べたものです。

![stars.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532021/dcb535a4-ac9b-4974-026c-c23952efb791.png)


#### promptを固定し、複数のランダムなseedで画像を生成する

各promptにおいて、`promptからは確定できない要素`がseedごとの違いに表れていることがわかります。
前述のpromptの**曖昧さ**はこの`promptからは確定できない要素`に含まれます。

こうして生成した画像を比較することで、**prompt単体がどの程度画像を固定するのか、何がseedに左右されているのか**を知ることができます。

|prompt|seedごとの違い|
|---|---|
|stars|「写真かイラストか」「全体的な色」「星の見え方」「地上の様子」など|
|a **`photo`** of stars|~~`「写真かイラストか」`~~ 「全体的な色」「星の見え方」「地上の様子」など|
|a photo of stars, **`purple`**|~~「写真かイラストか」 `「全体的な色」`~~「星の見え方」「地上の様子」など|

#### seedを固定し、複数の僅かに異なるpromptで画像を生成する

seedを固定した上でpromptを少しずつ変え、画像がどの様に変化するのか検証します。
`prompt変更前の画像に存在しなかった要素`が変更後のpromptに含まれている場合でのみ、目に見えた変化が起きていることがわかります。

こうして生成した画像を比較することで、**promptの微妙な違いが与える影響**を知ることができます。

|seed|*`stars`*|a *`photo`* of stars|a photo of stars, *`purple`*|
|:---:|:---:|:---:|:---:|
|1|**紫**の星空の**写真**|ほとんど変化なし|ほとんど変化なし|
|2|星のイラスト|**写真**に変化|**紫**に変化
|3|星のイラスト|**写真**に変化|**紫**に変化
|4|星のイラスト|**写真**に変化|**紫**に変化
|5|星空の**写真**|ほとんど変化なし|**紫**に変化

※表内の値は実際のseed値とは異なりますが、便宜上1~5としています。

### 活用方法

promptの完成度によってseedを固定するかランダムにするかを使い分ける方法です。

#### 完成度Level. 1：ランダム×固定

まずはpromptの持つ特徴を適切に理解することが重要です。
その際、promptのセクションで触れた**曖昧さ**の概念が重要になります。

曖昧な単語や文章を試す際、もしくは曖昧さを検証する際はランダムなseedで複数枚の画像を生成してみましょう。
`stars`という単語を例に上げると、この単語の持つ特徴には「星空の写真」だけでなく「星のイラスト」がありました。
このことは、複数のseedで検証しなければわからなかったことです。

一方で、それほど曖昧でない単語や文章も存在します。
`Greg Rutkowski`、`WLOP`などの作家名や`8k`、`trending on artstation`、`octane render`などのリアルさやディティールに影響しやすいpromptなどがこれにあたります。
画像に現れる物質や構図への影響は比較的小さく、加工アプリのフィルターの様に機能するため、固定seedでも十分に検証できます。

双方のケースを踏まえ、この様に**seedとpromptのマトリクスを組んで検証する**ことを推奨します。
![matrix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532021/c95f625a-6e71-2dd7-4aa5-bc6089257483.png)


#### 完成度Level. 2：ランダム
ある程度promptが定まってくると、構図や配置など`promptでは制御しきれない要素`がわかってきます。
そこで、それらを固定するためにランダムなseedで狙い通りの画像が出るまで生成し続けます。

:::note info
この行為は「Seed hunting」と呼ばれているようです。
:::

#### 完成度Level. 3：固定
いよいよ最終段階です。
Level.2で特定した「アタリのseed」を元に、promptを少しずつ変えて微調整を行います。
あまりうまくいかなければ`Seed hunting`に戻るのも良いでしょう。

:::note warn
特定のseedに対してpromptを過剰に適応させると、他のseedに合わなくなる点に注意してください。
:::

## Steps 【★★☆☆☆】
|txt2img.py|diffusers|default|
|:---:|:---:|:---:|
|--ddim_steps|num_inference_steps|50

### 特徴
stepが多いほど基本的に`より良い結果`が得られますが、その分処理に時間がかかります。
なおtxt2imgはデフォルトの50stepsでも十分な結果が得られるように作られています。

stepsの値を上げることによる`より良い結果`への変化は「構図の変化」と「(非常に広義の)画像クオリティーの向上」にざっくりと分けることができます。
step数1~250までの推移を比べてみましょう。
step数を少しずつ上げていくと、**1~15ほどのstep数の時に構図の変化が、それ以上では画像クオリティーの向上が起きやすい**ということがわかります。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532021/d2d492e4-3365-d229-0b01-626fd6fa8e4f.gif)![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532021/e2e522ba-b98c-ea2b-b637-1f4038132505.gif)

### 活用方法

少ないstep数で画像を量産する場合と、step数を上げて小数枚を生成する場合を使い分けましょう。
後でstep数を上げて綺麗にする(清書する)前提の場合、「何stepで画像を生成するべきか」という問題は「**何stepで構図の変化が収束するか**」という問題に置き換えることができます。
それよりも少ないstep数で生成した画像は、のちにstep数を上げて生成し直した時に構図が変化してしまう可能性があります。
一方で、それよりも多いstepで画像を生成すると無駄な時間が生じてしまいます。

**promptを組み立てる段階では20程度に設定して高速化**、**確定した後に100以上を用いて清書**することを推奨します。


![graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532021/f94c2c7c-0f2e-18a4-3599-9281d7b518ad.png)


:::note warn
構図の変化が1~15stepsで収束しやすいというのはあくまで目安であり、`prompt`、`seed`、特に`sampler`などに左右されることに注意してください。
:::

## Height/Width 【★☆☆☆☆】
|txt2img.py|diffusers|default|
|:---:|:---:|:---:|
|--H|height|512
|--W|width|512

### 特徴
txt2imgは512x512での画像生成に最適化されおり、512x512以上の解像度でも「512x512**ごとに**promptから画像を生成する」という仕様になっています。[^3]
[^3]: [Stable Diffusion Prompt engineering](https://docs.google.com/document/d/1O41qGvE69qnDoaqcdeokCObcRR_4yUUjRCmvPEVd2MU/edit)

その結果、512以上のサイズを指定すると頻繁に予期せぬ「複製」や「見切れ」などが発生します。
512x1728で生成したこちらの画像には3人の女性が現れました。
中心に何か(この例では女性の顔)がある様な画像は、高解像度での生成には不向きです。
![women.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532021/82e6e0c1-44c1-d498-5f1e-40baabc26c52.png)

一方で、この様な背景メインの画像は崩れにくく、大きなサイズでの生成に向いていると言えます。
![bgstars.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532021/af3cebfb-4928-8a64-13c0-1ff624f4350e.png)


### 活用方法

サイズを大幅に上げることで違和感のある画像が生まれてしまう場合、超解像やtxt2imghdなどの使用を検討しましょう。

https://qiita.com/Yasu81126297/items/752df11a1e5e70c8b9fe

## Scale 【★☆☆☆☆】
|txt2img.py|diffusers|default|
|:---:|:---:|:---:|
|--scale|guidance_scale|7.5

### 特徴

ScaleまたはCFGは`画像のクオリティーとpromptへの忠実度のバランス`を表します。
一般的に7~11あたりで最もバランスの取れた画像が生成できます。
![scales-256.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532021/abccfac9-aa7b-4f29-857f-eeb8733e27cb.gif)

:::note warn
こちらも、`prompt`、`seed`、`sampler`などに左右されることに注意してください。
:::

### 活用方法

基本的にはデフォルトのままで問題ありません。

# 3. まとめ

txt2imgにおいて重要な変数は、結局のところ`prompt`と`seed`の2つです。

最適な`prompt`だけでなく、最適な`seed`を見つけることが重要であり、そのための方法の骨組みがseedのセクションで紹介したこちらです。

1. ランダム×固定seedでの`Prompt engineering`
1. ランダムseedでの`Seed hunting`
1. 固定Seedでの`Prompt engineering`

そして、この過程における重要なポイントがこちらです。
- promptの長さは75token以内に
- step数は20程度まで減らして時短
    - 最後は100以上で清書
- 大きなサイズでの生成は予期せぬ複製や見切れを生むため注意
- Scaleはデフォルトでよし

# 4. おわりに

長々とお付き合いいただきありがとうございました！
ご指摘などありましたらコメントいただけると幸いです。

次回はPrompt engineeringの具体的な手法について書こうと思うのですが、なかなかのボリュームになりそうな気がしています。。