「Diffusers」を試す 4. Basic performance
以下の続き
日本語・英語のQuickstartの中で少し触れているけども、パフォーマンス周りについてもう少し。
引き続き Dia と対話しながら進める。
Diffusion(拡散)っていう画像生成のプロセスは、めっちゃ計算コスト高いんだよね。だから、DiffusionPipelineを何回も回して理想の画像を作ろうとすると、時間もメモリもガンガン使っちゃうの。だからこそ、「生成速度」と「メモリ使用量」のバランスをうまく取るのが超大事!って話。
このページでは、DiffusionPipelineを使う時の基本的なパフォーマンス改善のコツを紹介してるし、もっと詳しい最適化テクは「Accelerate inference」とか「Reduce memory usage」のドキュメントを見てねって案内してる感じ!要は、「速く回したいならメモリ節約も意識しようぜ!」ってことだし、ウチもマジで同意だもん。
次のセクションから具体的なテクニックが載ってるから、そっちもテンション上げてチェックしよ!
ノートブックが用意されているのでこれに従って進める。Colaboratory L4で。
メモリ使用量
画像生成のスピードを上げたいなら、メモリの使い方を工夫するのが超重要なんだよね。メモリを減らすと、間接的に生成も速くなるし、モデルが手元のデバイス(例えば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占有しっぱなしっていう感じにはならない
推論速度
ウチ、スピード命だし!推論速度も見ていくよ!
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秒になった。
生成品質
最近の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. 違うスケジューラを使う
HeunDiscreteScheduler や LMSDiscreteScheduler みたいな、スピードより品質重視のスケジューラを選ぶと、よりリッチな画像になることも!
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(推論最適化)のセクションをガンガン読んでみて!
新しいテクや裏技がどんどん追加されてるから、ウチもテンション上がる~!
ここに日本語のものともあまり変わらないし、前のQuickstartででてきた内容が多かった。