
我需要什么才能運(yùn)行最先進(jìn)的文本到圖像模型?游戲卡可以完成這項(xiàng)工作嗎?還是我應(yīng)該買一個(gè)高級的 A100?如果我只有 CPU 怎么辦?
為了闡明這些問題,我們提出了不同 GPU 和 CPU 上Stable Diffusion的推理基準(zhǔn)。以下是我們的發(fā)現(xiàn):
許多消費(fèi)級 GPU 可以很好地完成這項(xiàng)工作,因?yàn)镾table Diffusion只需要大約 5 秒和 5 GB 的 VRAM 即可運(yùn)行。
在輸出單張圖像的速度方面,最強(qiáng)大的 Ampere GPU(A100)僅比 3080 快 33%(或 1.85 秒)。
通過將批量大小推至最大值,A100 可以提供 2.5 倍的推理吞吐量(與 3080 相比)。
我們的基準(zhǔn)測試使用文本提示作為輸入并輸出分辨率為 的圖像。我們使用Huggingface 擴(kuò)散器庫中的模型實(shí)現(xiàn),并從速度、內(nèi)存消耗、吞吐量和輸出圖像質(zhì)量方面分析推理性能。我們研究了硬件(GPU 模型、GPU 與 CPU)和軟件(單精度與半精度、pytorch 與 onnxruntime)的不同選擇如何影響推理性能。
作為參考,我們將提供以下 GPU 設(shè)備的基準(zhǔn)測試結(jié)果:A100 80GB PCIe、RTX3090、RTXA5500、RTXA6000、RTX3080、RTX8000。
最后但并非最不重要的一點(diǎn)是,我們很高興看到社區(qū)進(jìn)展如此迅速。例如,“切片注意力”技巧可以進(jìn)一步將 VRAM 成本降低到“低至 3.2 GB”,但推理速度會降低約 10%。我們也期待在不久的將來,一旦ONNX 運(yùn)行時(shí)變得更加穩(wěn)定,就可以使用 CUDA 設(shè)備對其進(jìn)行測試。
速度
下圖展示了使用不同的硬件和精度生成單幅圖像的推理速度,使用(任意)文本提示:“一張宇航員在火星上騎馬的照片”。

Stable Diffusion Text2Image 速度(以秒為單位)
我們發(fā)現(xiàn):
在我們測試的 Ampere GPU 上,生成單個(gè)輸出圖像的時(shí)間范圍3.74為5.59幾秒,包括消費(fèi)者 3080 卡到旗艦 A100 80GB 卡。
半精度可40%將安培 GPU 的時(shí)間減少約,將52%上一代RTX8000GPU 的時(shí)間減少約。
我們認(rèn)為,由于使用了 ,Ampere GPU 的加速比半精度的“較小” TF32。對于不熟悉 的讀者,它是一種格式,已被用作主要深度學(xué)習(xí)框架(如 PyTorch 和 TensorFlow)上 Ampere GPU 的默認(rèn)單精度數(shù)據(jù)類型。由于它是一種真正的格式,因此可以預(yù)期半精度的加速比會更大。
我們在 CPU 設(shè)備上運(yùn)行相同的推理作業(yè),以便了解在 GPU 設(shè)備上觀察到的性能。

Stable Diffusion Text2Image GPU 與 CPU
我們注意到:
GPU 的速度明顯更快——根據(jù)精度,速度可提高一到兩個(gè)數(shù)量級。
onnxruntime可以將 CPU 推理時(shí)間減少約40%到50%,具體取決于 CPU 的類型。
順便提一下,ONNX 運(yùn)行時(shí)目前沒有針對 Hugging Face 擴(kuò)散器的穩(wěn)定CUDA 后端支持,我們在初步測試中也沒有觀察到有意義的加速。我們期待在 ONNX 運(yùn)行時(shí)針對Stable Diffusion進(jìn)行進(jìn)一步優(yōu)化后進(jìn)行更全面的基準(zhǔn)測試。
內(nèi)存
我們還測量了運(yùn)行Stable Diffusion推理的內(nèi)存消耗。

Stable Diffusion Text2Image 內(nèi)存 (GB)
經(jīng)觀察,所有經(jīng)過測試的 GPU 的內(nèi)存使用情況都是一致的:
7.7 GB運(yùn)行批量大小為 1 的單精度推理大約需要GPU 內(nèi)存。
4.5 GB運(yùn)行批量大小為 1 的半精度推理大約需要GPU 內(nèi)存。
吞吐量
到目前為止,我們已經(jīng)測量了單個(gè)輸入的處理速度,這對于不能容忍哪怕是最小延遲的在線應(yīng)用程序來說至關(guān)重要。但是,一些(離線)應(yīng)用程序可能會關(guān)注“吞吐量”,它衡量在固定時(shí)間內(nèi)處理的數(shù)據(jù)總量。
我們的吞吐量基準(zhǔn)測試將每個(gè) GPU 的批處理大小推至最大值,并測量它們每分鐘可以處理的圖像數(shù)量。最大化批處理大小的原因是讓張量核心保持繁忙,以便計(jì)算可以主導(dǎo)工作負(fù)載,避免任何非計(jì)算瓶頸并最大化吞吐量。
我們在 pytorch 中以半精度運(yùn)行了一系列吞吐量實(shí)驗(yàn),并使用了每個(gè) GPU 可以使用的最大批量大小:

Stable Diffusion文本到圖像吞吐量(圖像/分鐘)
我們注意到:
再次,A100 80GB 表現(xiàn)最佳,且具有最高的吞吐量。
A100 80GB 與其他卡在吞吐量方面的差距可以通過此卡上可使用的最大批量大小較大來解釋。
作為一個(gè)具體的例子,下圖顯示了當(dāng)我們將批處理大小從 1 更改為 28(不會導(dǎo)致內(nèi)存不足錯(cuò)誤的最大值)時(shí),A100 80GB 的吞吐量如何增加。同樣有趣的是,當(dāng)批處理大小達(dá)到某個(gè)值時(shí),吞吐量的增長并不是線性的,而是趨于平穩(wěn),此時(shí) GPU 上的張量核心已飽和,GPU 內(nèi)存中的任何新數(shù)據(jù)都必須排隊(duì)才能獲得自己的計(jì)算資源。

Stable Diffusion Text2Image 批次大小與吞吐量(圖像/分鐘)
自動播報(bào)
Hugging Face 團(tuán)隊(duì)對其擴(kuò)散器代碼進(jìn)行的更新聲稱,刪除自動投射可將 pytorch 的半精度推理速度提高約 25%。
使用自動播報(bào):
with autocast("cuda"):
image = pipe(prompt).images[0]
未使用自動施放:
image = pipe(prompt).images[0]
我們在 NVIDIA RTX A6000 上重現(xiàn)了該實(shí)驗(yàn),并能夠驗(yàn)證速度和內(nèi)存使用方面的性能提升。我們預(yù)計(jì)其他支持半精度的設(shè)備也會有類似的改進(jìn)。

Stable Diffusion-text2image-pytorch-半精度速度

Stable Diffusion-text2image-pytorch-半精度內(nèi)存
綜上所述,請勿將 autocast 與 FP16 結(jié)合使用。
精確
我們很好奇半精度是否會降低輸出圖像的質(zhì)量。為了測試這一點(diǎn),我們修復(fù)了文本提示以及“潛在”輸入,并將它們輸入到單精度模型和半精度模型中。我們以增加的步數(shù)運(yùn)行了 100 次推理。每次運(yùn)行時(shí),都會保存兩個(gè)模型的輸出及其差異圖。

100 步中的單精度與半精度
我們的觀察是,單精度輸出和半精度輸出之間確實(shí)存在明顯差異,尤其是在早期步驟中。差異通常會隨著步驟數(shù)量的增加而減小,但可能不會消失。
有趣的是,這種差異可能并不意味著半精度輸出中存在偽影。例如,在步驟 70 中,下圖顯示半精度沒有在單精度輸出中產(chǎn)生偽影(額外的前腿):

單精度 v 半精度,步驟 70
重復(fù)實(shí)驗(yàn)
您可以使用捷智算平臺自帶的存儲庫來重現(xiàn)本文中呈現(xiàn)的結(jié)果。
設(shè)置
在運(yùn)行基準(zhǔn)測試之前,請確保您已完成存儲庫安裝步驟。
然后您需要設(shè)置 huggingface 訪問令牌:
1、在 Hugging Face 上創(chuàng)建用戶賬戶并生成訪問令牌。
2、將您的 huggingface 訪問令牌設(shè)置為ACCESS_TOKEN環(huán)境變量:
export ACCESS_TOKEN=<hf_...>
用法
啟動benchmark.py腳本以將基準(zhǔn)測試結(jié)果附加到現(xiàn)有的 benchmark.csv 結(jié)果文件:
python ./scripts/benchmark.py
啟動benchmark_quality.py腳本來比較單精度和半精度模型的輸出:
python ./scripts/benchmark_quality.py
備注
由于每次運(yùn)行的文本提示以及“潛在”輸入都是固定的,這相當(dāng)于運(yùn)行 100 步推理,并保存每一步的中間結(jié)果。
