StableDiffusion勉強中...

画像生成の進歩が物凄く、片足突っ込みたくなったので勉強したことなどをここに記す

とりあえず使ってみる

参考資料:猫耳とdiffusersで始めるStable Diffusion入門

環境:windows11
WSLは重いらしい。エミュレータなので仕方なし
GPUがないので(欲しい)、CPUで生成する。時間はかかるが、生成できないわけではない。

MiniConda

install

minicondaをインストールする。anacondaを最小構成にしたもの
理由は環境を移し替えられるから。sageMarkerとかGPUのある環境が使えるようになったときにいちいちやり直す必要がないはず
インストールページ

Usersディレクトリが日本語や空白を含む場合、インストールできないらしいので、その場合はテキトーに別のパスを指定する

install したら、デフォルトのPowerShellでcondaコマンドが使えるようにする
別にAnaconda Promptを使う場合は飛ばしていい
Anaconda Prompt=cmd
Anaconda PowerShell Prompt=PowerShell

Anaconda PowerShell Promptを開いて、

conda init powershell

と打つ
これでデフォのPowerShellでもcondaコマンドが使える

やっぱりやめる場合は

conda init --reverse powershell

起動時に(base)環境に入りたくない場合は

conda config --set auto_activate_base false

condaコマンドは使える。

環境構築

stable_diffusionという名の環境を新規作成する
StableDiffusionはpython 3.10が推奨らしい

conda create -n stable_diffusion python=3.10

環境に入る

conda activate stable_diffusion

(stable_diffusion)が出てくるはず

PyTorchをインストールする

pip3 install torch torchvision --index-url https://download.pytorch.org/whl/cu128

GPUを使用する場合はCUDAバージョンが整合しているか確認する
12.8以降が良いらしい。ここでは使わんけど

その他のモジュールをインストールする

pip install diffusers transformers peft

 diffusers:StableDiffusion が提供するモデルを処理するやつ
Transformers:学習済みモデルをダウンロードして学習するAPIとツールを提供する。diffusersの依存モジュール
peft:Parameter-Efficient Fine-Tuningの略。効率的なファインチューニング手法を実装するやつ

実行

参考元のコードをお借りして、ついでに所要時間を取得する

from diffusers import DiffusionPipeline
import time

start = time.time()

model_id = 'gsdf/Counterfeit-V2.5'
pipe = DiffusionPipeline.from_pretrained(model_id)
prompt = 'jamping girl'
img = pipe(prompt).images[0]
img.save('test.jpg')

end = time.time()
print("Time taken:", end - start, "[s]")

何も指定しないと画像は512×512pxらしい

出力結果

脚がやべえ
モデルの性能なのか男性の出力は微妙。なぜか全員ギター持って出てくる

Time taken: 514.1502532958984 [s]
自環境では512×512pxの画像に7~8分かかるようだ
うーんGPU欲しい
CUDAはNVIDIA専用なのでNVIDIAが無いと使えない

応用

モデル(チェックポイントと言った方が衒学的)を変更してみる
わざわざダウンロードしなくてもgitで読み込めるらしいが、ここではローカルからやってみる
↓使用したモデル
NoobAI-XL (NAI-XL)

モデルのページにDiffusers用のpythonコードがあったので借りる
モデルの拡張子は.safetensors(重みのテンソル?)
ローカルのモデルを指定するときは、フルパスじゃなきゃいけないようだ
pythonで指定するときはwindows特有のバクスラ(\)ではなくスラッシュ(/)なので注意

import torch
import time
from diffusers import StableDiffusionXLPipeline
from diffusers import EulerDiscreteScheduler

start = time.time()

checkpoint = "C:/path/to/noobaiXLNAIXL_vPred10Version.safetensors"

pipe = StableDiffusionXLPipeline.from_single_file(
    checkpoint,
    use_safetensors=True,
    torch_dtype=torch.float16,
    local_files_only=True,
)

scheduler_args = {"prediction_type": "v_prediction", "rescale_betas_zero_snr": True}
pipe.scheduler = EulerDiscreteScheduler.from_config(pipe.scheduler.config, **scheduler_args)
#pipe.enable_xformers_memory_efficient_attention()
#pipe = pipe.to("cuda")

prompt = """masterpiece, best quality,artist:john_kafka,artist:nixeu,artist:quasarcake, chromatic aberration, film grain, horror \(theme\), limited palette, x-shaped pupils, high contrast, color contrast, cold colors, arlecchino \(genshin impact\), black theme,  gritty, graphite \(medium\)"""
negative_prompt = "nsfw, worst quality, old, early, low quality, lowres, signature, username, logo, bad hands, mutated hands, mammal, anthro, furry, ambiguous form, feral, semi-anthro"


image = pipe(
    prompt=prompt,
    negative_prompt=negative_prompt,
    width=512,
    height=512,
    num_inference_steps=1,
    guidance_scale=5,
    generator=torch.Generator().manual_seed(42),
).images[0]

image.save("output.png")

print("Time taken:", time.time() - start)

本元のコードではxformersというモジュールをつかってpipe.enable_xformers_memory_efficient_attention()でメモリ効率化するらしいが、CPUではこれができないので、コメントアウトした

1ステップの推論に30分かかった

runpod

runpodはGPUを提供しているサービス
使用時間で課金額が増える
セッションを閉じても残るストレージは月額料金(30GBで2.1ドル=335円/月)

setup

RTX4090を選択した

Runpod Pytorch 2.4.0はその名の通りPytorch 2.4.0が最初からインストールされている
右のSpotはPodが中断される可能性がある代わりに安価
基本的にJupyter Notebookを使うのが一番楽なのでチェックをつけておく

Volume DiskはPodを終了すると全て消滅するが無料
Network Volumeは特定のディレクトリが保持される代わりに月額を請求する

少し待って、Jupyter Labを押下

以下のようなページに飛ばされる

/workspace以外はTerminateすると消えるので、必ず/workspace内で作業する
JupyterLabなら自動的に/workspace内に移動してる

一応Terminateの横の三点リーダから保持するディレクトリを決められる

Terminalを選択して、python環境を作成してアクティベート

python3 -m venv venv
source venv/bin/activate

pyTorchは既に入っているので、その他のモジュールをインストール(GPUが使えるので、xformersを追加)

pip install diffusers transformers peft xformers

pythonファイルを作成

touch test.py

左のリボンにtest.pyが表示されるので、選択して編集

実行

コードはこんな感じ
.to()の中にcudaを設定すればGPUを使用して生成する

from diffusers import DiffusionPipeline
import time

start = time.time()

model_id = 'gsdf/Counterfeit-V2.5'
device = 'cuda'
pipe = DiffusionPipeline.from_pretrained(model_id).to(device)
prompt = 'girl'
img = pipe(prompt).images[0]
img.save('test.jpg')

end = time.time()
print("Time taken:", end - start, "[s]")

CUDAについてターミナル上で以下を実行して確認する

python -c "import torch; print(torch.cuda.is_available())"

CUDAが使える場合はTrue

CUDAバージョン確認

python -c "import torch; print(torch.version.cuda)"

出力結果

Time taken: 4.945405960083008 [s]

は、はやい


モデルを変えてみる
huggingfaceのnoobai-XL-1.0を使ってみる

推奨パラメータ↓

  • CFG: 5~6
  • ステップ: 25~30
  • サンプリング方法:オイラー a
  • 解像度:総面積は約 1024x1024。
    • 最適な選択肢:768x1344、832x1216、896x1152、1024x1024、1152x896、1216x832、1344x768
import torch
import time
from diffusers import StableDiffusionXLPipeline
from diffusers import EulerAncestralDiscreteScheduler

start = time.time()

checkpoint = "Laxhar/noobai-XL_v1.0"

pipe = StableDiffusionXLPipeline.from_pretrained(
    checkpoint,
    torch_dtype=torch.float16
)

pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config)
pipe.enable_xformers_memory_efficient_attention()
pipe = pipe.to("cuda")
pipe.vae.to(torch.float16)

prompt = "masterpiece, best quality, newest, absurdres, highres, safe, girl"
negative_prompt = "nsfw, worst quality, old, early, low quality, lowres, signature, username, logo, bad hands, mutated hands, mammal, anthro, furry, ambiguous form, feral, semi-anthro"

image = pipe(
    prompt=prompt,
    negative_prompt=negative_prompt,
    width=768,
    height=1344,
    num_inference_steps=28,
    guidance_scale=5,
).images[0]

image.save("out.png")

print("Time taken:", time.time() - start)

出力結果

どことなくBlueArchive

Time taken: 7.345957517623901
これでもなかなか速い


PixAiっぽいやつ
てかPixAiのモデルの大本は多分これ
animagine-xl-4.0

推奨のプロンプト記法が決まっているので、それに従った方が良い

import torch
from diffusers import EulerAncestralDiscreteScheduler
from diffusers import StableDiffusionXLPipeline
import time
import os

def unique(ext):
	filename = "1." + ext
    if not os.path.exists(filename):
        return filepath
    base, extension = os.path.splitext(filepath)
    counter = 1
    new_filepath = filepath
    while os.path.exists(new_filepath):
        try:
            new_filepath = f"{base[:-1]}{int(base[-1]) + counter}{extension}"
        except (ValueError, IndexError):
            new_filepath = f"{base}_{counter}{extension}"
        counter += 1
    return new_filepath

start = time.time()

pipe = StableDiffusionXLPipeline.from_pretrained(
    "cagliostrolab/animagine-xl-4.0",
    torch_dtype=torch.float16,
    use_safetensors=True,
    custom_pipeline="lpw_stable_diffusion_xl",
    add_watermarker=False
)
pipe.to('cuda')

pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(
    pipe.scheduler.config
)

prefix = """
1girl/,
character arima kana,
from oshi no ko,
year 2025,
rating safe,
everything else in any order and end with quality enhancement
"""

prompt = "looking at viewer, smile, outdoors, night"

quality = "masterpiece, high score, great score, absurdres, best quality"

negative_prompt = "lowres, bad anatomy, bad hands, text, error, missing finger, extra digits, fewer digits, cropped, worst quality, low quality, low score, bad score, average score, signature, watermark, username, blurry"

image = pipe(
    prefix + prompt + quality,
    negative_prompt=negative_prompt,
    width=832,
    height=1216,
    guidance_scale=5,
    num_inference_steps=28
).images[0]

image.save(filename.unique("png"))

print("Time taken:", time.time() - start)

prefixはプロンプトの先頭につけた方がよい指示。主に画像全体の内容を書く

  • 被写体
    数字で人数、スラッシュで分ける
    例:1girl/1boy/1other
  • キャラクター
    キャラクター名を指定する
    例:character [ここにキャラの英名]
  • シリーズ
    キャラクターの作品名を指定する
    例:from [ここにキャラの英名]
  • 年代
    画風の年代を設定する
    例:year [西暦]
  • レーティング
    画像の年齢制限を指定
    - safe:全年齢
    - sensitive:R15くらい
    - nsfw:R18
    - explicit:制限なし。グロテスクも含む
    例:rating [レーティング]

キャラクターやシリーズはワイルドカード一覧などある
character.txt
characterfull.txt

everything else in any order and end with quality enhancement
は直訳すると、「その他すべては順不同で、最後に品質向上タグで終わる」
このプロンプトによってprefixpromptqualityの順での記述が読み取りやすくなるもの

promptはPixAiっぽく書けばよい
PixAiで公開されている生成イラストのプロンプトを読んでみるとよい

qualityは画質や絵の上手さを指定する
上手なイラストを生成したいなら基本的に変える必要はない

公式に書いてあるが、解像度の推奨

向き 寸法 アスペクト比
正方形 1024 x 1024 1:1
横長 1152 x 896 9:7
1216 x 832 3:2
1344 x 768 7:4
1536 x 640 12:5
縦長 896 x 1152 7:9
832 x 1216 2:3
768 x 1344 4:7
640 x 1536 5:12