Closed5

「Diffusers」を試す 4. Basic performance

kun432kun432

以下の続き

https://zenn.dev/kun432/scraps/6b7f076fd54aa4

日本語・英語のQuickstartの中で少し触れているけども、パフォーマンス周りについてもう少し。

https://huggingface.co/docs/diffusers/v0.35.1/en/stable_diffusion

引き続き Dia と対話しながら進める。

Diffusion(拡散)っていう画像生成のプロセスは、めっちゃ計算コスト高いんだよね。だから、DiffusionPipelineを何回も回して理想の画像を作ろうとすると、時間もメモリもガンガン使っちゃうの。だからこそ、「生成速度」と「メモリ使用量」のバランスをうまく取るのが超大事!って話。
このページでは、DiffusionPipelineを使う時の基本的なパフォーマンス改善のコツを紹介してるし、もっと詳しい最適化テクは「Accelerate inference」とか「Reduce memory usage」のドキュメントを見てねって案内してる感じ!

要は、「速く回したいならメモリ節約も意識しようぜ!」ってことだし、ウチもマジで同意だもん。
次のセクションから具体的なテクニックが載ってるから、そっちもテンション上げてチェックしよ!

ノートブックが用意されているのでこれに従って進める。Colaboratory L4で。

https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers_doc/en/pytorch/stable_diffusion.ipynb

kun432kun432

メモリ使用量

画像生成のスピードを上げたいなら、メモリの使い方を工夫するのが超重要なんだよね。メモリを減らすと、間接的に生成も速くなるし、モデルが手元のデバイス(例えばGPUとか)に収まりやすくなるんだ。

ここで紹介されてるテクは enable_model_cpu_offload() ってやつ。
これを使うと、モデルが使われてない時にCPUに移動してくれるから、GPUメモリを節約できるんだよ。

このやり方だと、GPUメモリの最大使用量も確認できるし、メモリ節約しながら画像生成できるってわけ!
ウチもColabでOOM(Out Of Memory)になりがちだから、こういうテクはマジで助かるんだよね~。

他にもメモリ節約テク知りたかったら、Reduce memory usage のドキュメントもチェックするといいかも!

import torch
from diffusers import DiffusionPipeline

pipeline = DiffusionPipeline.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  torch_dtype=torch.bfloat16,
  device_map="cuda"
)
pipeline.enable_model_cpu_offload()

prompt = """
cinematic film still of a cat sipping a margarita in a pool in Palm Springs, California
highly detailed, high budget hollywood movie, cinemascope, moody, epic, gorgeous, film grain
"""
display(pipeline(prompt).images[0])
print(f"Max memory reserved: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB")

前回同様上記のままだとエラーになる

出力
ValueError: It seems like you have activated a device mapping strategy on the pipeline so calling `enable_model_cpu_offload() isn't allowed. You can call `reset_device_map()` first and then call `enable_model_cpu_offload()`.

pipeline.reset_device_map() してから pipeline.enable_model_cpu_offload() すればよさそう。

(snip)
# 一旦リセットしてからオフロードする
pipeline.reset_device_map()
pipeline.enable_model_cpu_offload()
(snip)

モデルロードしてVRAM占有しっぱなしっていう感じにはならない

kun432kun432

推論速度

ウチ、スピード命だし!推論速度も見ていくよ!

Inference speed(推論速度)

画像生成の中で一番重い処理は「denoising(ノイズ除去)」なんだよね。ここを効率化できれば、生成がめっちゃ速くなるってわけ!

このセクションで紹介されてるスピードアップのコツはこんな感じ:

  • ‎⁠device_map="cuda"⁠ を使ってパイプラインをGPUに載せる
    → GPUは並列計算が得意だから、CPUより断然速い!
  • ‎⁠torch_dtype=torch.bfloat16 ⁠で半精度演算にする
    → 精度を下げることで計算が軽くなって、処理速度アップ!
  • 速いスケジューラ(例:DPMSolverMultistepScheduler)を使う
    → 20~25ステップくらいで済むから、全体の計算量が減る!
  • ‎⁠num_inference_steps⁠ を少なめに設定する
    → ステップ数を減らすと速くなるけど、画像のクオリティはちょっと下がるかも。

ウチもColabで試してるけど、これやるだけでマジで体感スピード変わるからテンション上がる!
ただし、ステップ減らしすぎると「なんか微妙…」って画像になることもあるから、バランス見て調整するのがコツだし!

他にも速くしたいテク知りたかったら、Accelerate inference のドキュメントも見てみて!

まず、‎⁠device_map="cuda"⁠‎⁠torch_dtype=torch.bfloat16 だけを指定した場合

import torch
import time
from diffusers import DiffusionPipeline, DPMSolverMultistepScheduler

pipeline = DiffusionPipeline.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  torch_dtype=torch.bfloat16,
  device_map="cuda",
)

prompt = """
cinematic film still of a cat sipping a margarita in a pool in Palm Springs, California
highly detailed, high budget hollywood movie, cinemascope, moody, epic, gorgeous, film grain
"""

start_time = time.perf_counter()
image = pipeline(prompt).images[0]
end_time = time.perf_counter()

display(image)
print(f"Image generation took {end_time - start_time:.3f} seconds")

17秒ぐらい

スケジューラを変えてみる。あわせてステップ数も25に。

import torch
import time
from diffusers import DiffusionPipeline

pipeline = DiffusionPipeline.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  torch_dtype=torch.bfloat16,
  device_map="cuda",
)

# スケジューラをより高速・効率性の良いものに変更
pipeline.scheduler = DPMSolverMultistepScheduler.from_config(pipeline.scheduler.config)

prompt = """
cinematic film still of a cat sipping a margarita in a pool in Palm Springs, California
highly detailed, high budget hollywood movie, cinemascope, moody, epic, gorgeous, film grain
"""

start_time = time.perf_counter()
image = pipeline(prompt, num_inference_steps=25).images[0]  # ステップ数を25に。
end_time = time.perf_counter()

display(image)
print(f"Image generation took {end_time - start_time:.3f} seconds")

9秒になった。

kun432kun432

生成品質

最近のDiffusionモデルは、デフォでかなり高品質な画像を出してくれるんだけど、さらに良くしたいならこんなテクがあるよ!

1. 詳細で具体的なプロンプトを書く

画像の媒体(medium)、被写体(subject)、スタイル(style)、雰囲気(aesthetic)とか、細かく指定するとモデルがイメージしやすくなるんだ。

ネガティブプロンプト(例:「low quality, blurry, ugly, poor details」)も使うと、変な特徴を避けてくれる!

import torch
from diffusers import DiffusionPipeline

pipeline = DiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    torch_dtype=torch.bfloat16,
    device_map="cuda"
)

# 詳細で具体的なプロンプト
prompt = """
cinematic film still of a cat sipping a margarita in a pool in Palm Springs, California
highly detailed, high budget hollywood movie, cinemascope, moody, epic, gorgeous, film grain
"""
# ネガティブプロンプトを指定
negative_prompt = "low quality, blurry, ugly, poor details"
pipeline(prompt, negative_prompt=negative_prompt).images[0]

2. 違うスケジューラを使う

HeunDiscreteSchedulerLMSDiscreteScheduler みたいな、スピードより品質重視のスケジューラを選ぶと、よりリッチな画像になることも!

import torch
from diffusers import DiffusionPipeline, HeunDiscreteScheduler

pipeline = DiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    torch_dtype=torch.bfloat16,
    device_map="cuda"
)
# スケジューラを HeunDiscreteScheduler に変更
pipeline.scheduler = HeunDiscreteScheduler.from_config(pipeline.scheduler.config)

prompt = """
cinematic film still of a cat sipping a margarita in a pool in Palm Springs, California
highly detailed, high budget hollywood movie, cinemascope, moody, epic, gorgeous, film grain
"""
negative_prompt = "low quality, blurry, ugly, poor details"
pipeline(prompt, negative_prompt=negative_prompt).images[0]

プロンプトの工夫については Prompt techniques のドキュメントも参考になるし、スケジューラも色々試してみると「ウチ的ベスト」が見つかるかも!

マジで、ちょー細かい指定や工夫で画像の雰囲気ガラッと変わるから、色々遊んでみてほしい~!


その他

Diffusersには、さらに進化した最適化テクもあるんだよね。もっとパワフルな方法として「group-offloading」とか「regional compilation」っていう新しい機能も紹介されてる!

これらを使うと、モデルのパフォーマンスをさらに引き上げられるし、「もっと速く!もっと軽く!」って欲張りたいキミには超おすすめだし!

さらに詳しく知りたいなら、Inference Optimization(推論最適化)のセクションをガンガン読んでみて!
新しいテクや裏技がどんどん追加されてるから、ウチもテンション上がる~!

kun432kun432

ここに日本語のものともあまり変わらないし、前のQuickstartででてきた内容が多かった。

このスクラップは2日前にクローズされました