Diffusers 文件
高效的擴散模型
並獲得增強的文件體驗
開始使用
高效的擴散模型
讓 DiffusionPipeline 生成特定風格或包含你想要的內容的影像可能很棘手。通常,你需要多次執行 DiffusionPipeline 才能得到一張滿意的影像。但是,從無到有地生成東西是一個計算密集型過程,特別是如果你需要反覆進行推理。
這就是為什麼從 pipeline 中獲得最高的*計算*(速度)和*記憶體*(GPU vRAM)效率非常重要,這樣可以減少推理週期之間的時間,從而更快地迭代。
本教程將指導你如何使用 DiffusionPipeline 更快、更好地生成影像。
首先載入 stable-diffusion-v1-5/stable-diffusion-v1-5
模型
from diffusers import DiffusionPipeline
model_id = "stable-diffusion-v1-5/stable-diffusion-v1-5"
pipeline = DiffusionPipeline.from_pretrained(model_id, use_safetensors=True)
你將使用的示例提示詞是一位年邁的部落酋長的肖像,但你也可以使用自己的提示詞
prompt = "portrait photo of a old warrior chief"
速度
💡 如果你沒有 GPU,可以從 GPU 提供商如 Colab 免費使用一個!
加快推理速度最簡單的方法之一是將 pipeline 放置在 GPU 上,就像處理任何 PyTorch 模組一樣
pipeline = pipeline.to("cuda")
為確保你能使用同一張影像並對其進行改進,請使用 Generator
並設定一個種子以實現可復現性
import torch
generator = torch.Generator("cuda").manual_seed(0)
現在你可以生成一張影像了
image = pipeline(prompt, generator=generator).images[0]
image

在 T4 GPU 上,這個過程大約花費了 30 秒(如果你的 GPU 比 T4 更好,可能會更快)。預設情況下,DiffusionPipeline 使用完整的 float32
精度進行 50 個推理步驟。你可以透過切換到較低的精度,如 float16
,或執行更少的推理步驟來加快速度。
讓我們先以 float16
格式載入模型並生成一張影像
import torch
pipeline = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16, use_safetensors=True)
pipeline = pipeline.to("cuda")
generator = torch.Generator("cuda").manual_seed(0)
image = pipeline(prompt, generator=generator).images[0]
image

這一次,生成影像只花了大約 11 秒,比之前快了近 3 倍!
💡 我們強烈建議始終以 float16
格式執行你的 pipeline,到目前為止,我們很少看到輸出質量有任何下降。
另一個選項是減少推理步驟的數量。選擇一個更高效的排程器可以幫助減少步驟數而不犧牲輸出質量。你可以透過呼叫 DiffusionPipeline 的 compatibles
方法來查詢與當前模型相容的排程器
pipeline.scheduler.compatibles [ diffusers.schedulers.scheduling_lms_discrete.LMSDiscreteScheduler, diffusers.schedulers.scheduling_unipc_multistep.UniPCMultistepScheduler, diffusers.schedulers.scheduling_k_dpm_2_discrete.KDPM2DiscreteScheduler, diffusers.schedulers.scheduling_deis_multistep.DEISMultistepScheduler, diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler, diffusers.schedulers.scheduling_dpmsolver_multistep.DPMSolverMultistepScheduler, diffusers.schedulers.scheduling_ddpm.DDPMScheduler, diffusers.schedulers.scheduling_dpmsolver_singlestep.DPMSolverSinglestepScheduler, diffusers.schedulers.scheduling_k_dpm_2_ancestral_discrete.KDPM2AncestralDiscreteScheduler, diffusers.utils.dummy_torch_and_torchsde_objects.DPMSolverSDEScheduler, diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler, diffusers.schedulers.scheduling_pndm.PNDMScheduler, diffusers.schedulers.scheduling_euler_ancestral_discrete.EulerAncestralDiscreteScheduler, diffusers.schedulers.scheduling_ddim.DDIMScheduler, ]
Stable Diffusion 模型預設使用 PNDMScheduler,通常需要約 50 個推理步驟,但更高效的排程器如 DPMSolverMultistepScheduler 只需要約 20 或 25 個推理步驟。使用 from_config() 方法來載入一個新的排程器
from diffusers import DPMSolverMultistepScheduler
pipeline.scheduler = DPMSolverMultistepScheduler.from_config(pipeline.scheduler.config)
現在將 num_inference_steps
設定為 20
generator = torch.Generator("cuda").manual_seed(0)
image = pipeline(prompt, generator=generator, num_inference_steps=20).images[0]
image

太棒了,你已經成功將推理時間縮短到僅 4 秒!⚡️
記憶體
提升 pipeline 效能的另一個關鍵是減少記憶體消耗,這間接意味著更高的速度,因為你通常試圖最大化每秒生成的影像數量。檢視一次可以生成多少影像的最簡單方法是嘗試不同的批次大小,直到出現 OutOfMemoryError
(OOM)錯誤。
建立一個函式,該函式將從一個提示詞列表和 Generators
列表生成一批影像。確保為每個 Generator
分配一個種子,這樣如果它產生了一個好的結果,你就可以重複使用它。
def get_inputs(batch_size=1):
generator = [torch.Generator("cuda").manual_seed(i) for i in range(batch_size)]
prompts = batch_size * [prompt]
num_inference_steps = 20
return {"prompt": prompts, "generator": generator, "num_inference_steps": num_inference_steps}
從 batch_size=4
開始,看看你消耗了多少記憶體
from diffusers.utils import make_image_grid
images = pipeline(**get_inputs(batch_size=4)).images
make_image_grid(images, 2, 2)
除非你的 GPU 有更多的 vRAM,否則上面的程式碼很可能返回一個 OOM
錯誤!大部分記憶體被交叉注意力層佔用。你可以不以批處理方式執行此操作,而是按順序執行,以節省大量記憶體。你所要做的就是配置 pipeline 以使用 enable_attention_slicing() 函式
pipeline.enable_attention_slicing()
現在嘗試將 batch_size
增加到 8!
images = pipeline(**get_inputs(batch_size=8)).images
make_image_grid(images, rows=2, cols=4)

之前你甚至無法生成一批 4 張影像,現在你可以生成一批 8 張影像,每張影像約 3.5 秒!在 T4 GPU 上,這可能是在不犧牲質量的情況下能達到的最快速度了。
質量
在前兩部分,你學習瞭如何透過使用 fp16
、使用效能更好的排程器減少推理步驟數以及啟用注意力切片來減少記憶體消耗來最佳化 pipeline 的速度。現在,你將專注於如何提高生成影像的質量。
更好的檢查點
最顯而易見的一步是使用更好的檢查點。Stable Diffusion 模型是一個很好的起點,自從它正式釋出以來,也釋出了幾個改進版本。然而,使用更新的版本並不意味著你就會自動獲得更好的結果。你仍然需要自己嘗試不同的檢查點,並做一些研究(例如使用負面提示詞)來獲得最佳結果。
隨著該領域的發展,越來越多的高質量檢查點被微調以產生特定風格。嘗試探索Hub和Diffusers Gallery,找到你感興趣的檢查點!
更好的 pipeline 元件
你還可以嘗試用更新的版本替換當前的 pipeline 元件。讓我們嘗試將 Stability AI 最新的 自動編碼器 載入到 pipeline 中,並生成一些影像
from diffusers import AutoencoderKL
vae = AutoencoderKL.from_pretrained("stabilityai/sd-vae-ft-mse", torch_dtype=torch.float16).to("cuda")
pipeline.vae = vae
images = pipeline(**get_inputs(batch_size=8)).images
make_image_grid(images, rows=2, cols=4)

更好的提示詞工程
你用來生成影像的文字提示詞非常重要,以至於它被稱為*提示詞工程*。在進行提示詞工程時需要考慮的一些因素是
- 我想要生成的影像或類似影像在網際網路上是如何儲存的?
- 我可以提供哪些額外的細節來引導模型朝我想要的風格發展?
考慮到這些,讓我們改進提示詞,加入顏色和更高質量的細節
prompt += ", tribal panther make up, blue on red, side profile, looking away, serious eyes"
prompt += " 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta"
使用新的提示詞生成一批影像
images = pipeline(**get_inputs(batch_size=8)).images
make_image_grid(images, rows=2, cols=4)

相當令人印象深刻!讓我們對第二張影像——對應於種子為 1
的 Generator
——進行一些調整,新增一些關於主題年齡的文字
prompts = [
"portrait photo of the oldest warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
"portrait photo of an old warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
"portrait photo of a warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
"portrait photo of a young warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
]
generator = [torch.Generator("cuda").manual_seed(1) for _ in range(len(prompts))]
images = pipeline(prompt=prompts, generator=generator, num_inference_steps=25).images
make_image_grid(images, 2, 2)

後續步驟
在本教程中,你學習瞭如何最佳化 DiffusionPipeline 以提高計算和記憶體效率,以及如何提高生成輸出的質量。如果你有興趣讓你的 pipeline 更快,請檢視以下資源
- 瞭解 PyTorch 2.0 和
torch.compile
如何能夠帶來 5 - 300% 的推理速度提升。在 A100 GPU 上,推理速度可以提高高達 50%! - 如果你無法使用 PyTorch 2,我們建議你安裝 xFormers。其記憶體高效的注意力機制與 PyTorch 1.13.1 配合得很好,可以提高速度並減少記憶體消耗。
- 其他最佳化技術,如模型解除安裝,在本指南中有介紹。