298 MB RAM’de çalışan Stable Diffusion XL 1.0
(github.com/vitoplantamura)- OnnxStream, 512 MB RAM’e sahip Raspberry Pi Zero 2’de Stable Diffusion 1.5 ve SDXL 1.0 Base’i swap eklemeden veya ara sonuçları diske yazmadan çalıştırmayı hedefleyen ultra hafif bir çıkarım kütüphanesidir
- Çıkarım motoru ile
WeightsProviderbileşenini ayırarakDiskNoCache,DiskPrefetch, özel yükleme·önbellekleme·önceden getirme yöntemlerini destekler; ayrıca ağırlıkları doğrudan HTTP üzerinden alıp diske yazmadan işleyebilir - SDXL 1.0 Base, Hugging Face Diffusers 0.19.3 uygulamasından dışa aktarılan ONNX dosyalarını kullanır ve Raspberry Pi Zero 2’de 10 adımlık bir görsel üretimi yaklaşık 11 saat sürer
- SDXL’in VAE decoder’ı FP32’de 4.4 GB RAM kullanır ve bu sorun yalnızca FP16·UINT8 ile kolay çözülemediği için, örtüşen karo çözümleme ve harmanlama ile bellek kullanımı 298 MB’ye düşürülür
- CPU’da OnnxRuntime’a göre en fazla 55 kat daha az bellek kullanırken, bunun karşılığında 0.5~2 kat daha yavaş olabilir; ayrıca batch size 1 ve bazı ONNX operatörleriyle sınırlıdır
OnnxStream’in hedefi ve tasarımı
- OnnxStream, Stable Diffusion 1.5’i Raspberry Pi Zero 2 üzerinde çalıştırma sorununu çözmek amacıyla başlatıldı
- Raspberry Pi Zero 2, 512 MB RAM’e sahip bir mikro bilgisayardır
- Stable Diffusion için genel önerilen minimum RAM/VRAM genellikle 8 GB’dır
- Hedef koşullar: ek swap alanı yok, ara sonuçların diske offload edilmesi yok
- Tipik makine öğrenimi çerçeveleri çıkarım gecikmesini veya iş hacmini önceliklendirdiği için RAM kullanımı kolayca büyüyebilir
- OnnxStream, bellek kullanımını en aza indirmeye odaklanan, küçük ve kolay değiştirilebilir bir çıkarım kütüphanesidir
- Temel yapı, çıkarım motoru ile model ağırlıklarını sağlayan
WeightsProviderbileşeninin ayrılmasıdır- Türetilmiş sınıflar model parametrelerinin yüklenmesi, önbelleklenmesi ve önceden getirilmesi yöntemlerini uygulayabilir
- Özel bir
WeightsProvider, verileri doğrudan HTTP sunucusundan indirip disk okuma·yazma olmadan işleyebilir - Varsayılan uygulamalar
DiskNoCacheveDiskPrefetch’tir
- CPU’da OnnxRuntime’a göre en fazla 55 kat daha az bellek kullanırken yaklaşık 0.5~2 kat daha yavaştır
Stable Diffusion 1.5 çalıştırma
- Stable Diffusion 1.5 örneği, OnnxStream kullanarak farklı VAE decoder hassasiyetleri ile görsel üretir
- Raspberry Pi Zero 2 RAM’ine sığmayan tek bileşen VAE decoder oldu
- Bunun nedeni model içindeki residual connection’lar, büyük tensörler ve büyük convolution işlemleriydi
- Tek hassasiyet ya da yarım hassasiyet tek başına Raspberry Pi Zero 2 RAM’ine sığmadı
- Çözüm 8 bit statik quantization oldu
- W8A8 hassasiyetli VAE decoder görselleri Raspberry Pi Zero 2’de üretildi ve
MAX_SPEEDseçeneği kullanıldığında yaklaşık 1.5 saat sürdü - Karşılaştırma için W16A16 görseller aynı latent kullanılarak PC’de üretildi
Stable Diffusion XL 1.0 Base desteği
- OnnxStream’in Stable Diffusion örneği SDXL 1.0 Base’i destekler, ancak Refiner dahil değildir
- ONNX dosyaları, Hugging Face Diffusers kütüphanesinin SDXL 1.0 uygulamasından dışa aktarılmıştır; kullanılan sürüm 0.19.3’tür
- SDXL 1.0’ın hesaplama maliyeti SD 1.5’e göre çok daha yüksektir
- En büyük fark, 512x512 yerine 1024x1024 görseller üretebilmesidir
- 12 çekirdekli ve 32 GB RAM’li bir PC’de Hugging Face Diffusers ile 10 adımlık bir görsel üretimi 26 dakika sürer
- SDXL için genel önerilen minimum VRAM genellikle 12 GB’dır
- OnnxStream, SDXL 1.0’ı 300 MB’tan az RAM ile çalıştırabildiği için Raspberry Pi Zero 2’de de çalışır
- Ek swap yok
- Çıkarım sırasında diske yazma yok
- Raspberry Pi Zero 2’de 10 adımlık görsel üretimi yaklaşık 11 saat sürer
SDXL’e özel bellek optimizasyonu
- SDXL 1.0 için, SD 1.5’tekine benzer optimizasyon kümesi bazı farklarla uygulanır
- UNET modeli, Raspberry Pi Zero 2’de 300 MB’tan az RAM ile çalışmak için UINT8 dinamik quantization kullanır
- Quantization, büyük ara tensörlerin belirli bir alt kümesiyle sınırlıdır
- SDXL 1.0’ın VAE decoder’ı, SD 1.5’e göre daha zordur
- SDXL 1.0 VAE decoder’ı, SD 1.5 VAE decoder’ından 4 kat daha büyüktür
- OnnxStream’de FP32 hassasiyetle çalıştırıldığında 4.4 GB RAM kullanır
- SD 1.5’te VAE decoder, UINT8 statik quantization ile 260 MB RAM’e kadar indirilebilmişti
- SDXL 1.0 VAE decoder’ında FP16 aritmetiğinde overflow oluşur ve activation değer aralığı geniş olduğu için UINT8 quantization ile yüksek kaliteli görseller elde etmek zordur
- sdxl-vae-fp16-fix gibi FP16 çözümleri olsa da, belleği yarıya indirse bile 2.2 GB ile Raspberry Pi Zero 2 için hâlâ çok büyüktür
- Nihai çözüm, Hugging Face Diffusers’ın VAE decoder uygulamasından esinlenen karo tabanlı çözümleme oldu
- Diffusion sonuç tensörünün shape’i
(1,4,128,128)’dir - Bu, shape’i
(1,4,32,32)olan örtüşen 5x5, toplam 25 tensöre bölünür - Her karo, sol ve üstteki karolarla %25 örtüşür
- Her karonun çözümleme sonucu
(1,3,256,256)tensörüdür ve nihai görselde harmanlanır - Harmanlama kapatılırsa karo sınırları görünür, açıldığında ise nihai sonuçta sınırlar görünmez
- Diffusion sonuç tensörünün shape’i
- Bu yöntemle SDXL VAE decoder’ının RAM kullanımı 4.4 GB’tan 298 MB’a düşer
Desteklenen özellikler ve bağımlılıklar
- OnnxStream, bellek tasarruflu çıkarım için gerekli özellikleri küçük bir pakette sunar
- Çıkarım motoru ile
WeightsProviderayrımı DiskNoCache,DiskPrefetch, özelWeightsProvider- attention slicing
- 8 bit unsigned asymmetric percentile dinamik quantization
- W8A8 unsigned asymmetric percentile statik quantization
- Quantization model kalibrasyonu
- FP16 desteği
- Sık kullanılan 25 ONNX operatörü implementasyonu
- Çıkarım motoru ile
- İşlemler sıralı yürütülür, ancak her operator çok iş parçacıklı çalışır
- Uygulama, tek bir implementasyon dosyası ve başlık dosyası yapısındadır;
XnnPacksınıfı XNNPACK çağrılarını sarmalar - Bazı hızlandırma primitive’leri XNNPACK’e bağlıdır
- MatMul
- Convolution
- element-wise Add/Sub/Mul/Div
- Sigmoid
- Softmax
Performans karşılaştırması ve kısıtlar
- Stable Diffusion üç modelden oluşur
- text encoder: 672 operation, 123 milyon parameter
- UNET: 2050 operation, 854 milyon parameter
- VAE decoder: 276 operation, 49 milyon parameter
- Batch size 1 ile 10 adımlık bir görsel üretimi için şu çalıştırmalar gerekir
- text encoder 2 kez
- UNET 20 kez
- VAE decoder 1 kez
- FP16 UNET temelinde OnnxStream ile OnnxRuntime arasında büyük bellek·süre farkı vardır
- OnnxStream: yaklaşık 0.133 GB, 18.2~19.8 saniye
- OnnxRuntime: 5.085~7.353 GB, 7.28~12.8 saniye
- OnnxStream en fazla 55 kat daha az bellek kullanır ama 0.5~2 kat daha yavaştır
- FP32 text encoder’da OnnxStream 0.147 GB, OnnxRuntime ise 0.641 GB kullanır
- FP32 VAE decoder’da OnnxStream 1.004 GB, OnnxRuntime 1.330~2.026 GB kullanır
- Karşılaştırma sonuçlarına birkaç koşul eşlik eder
- OnnxRuntime’ın ilk çalıştırması,
InferenceSessionyeniden kullanılmadan önce yapılan warm-up çıkarımıdır - OnnxStream eager tasarıma sahip olduğu için warm-up kavramı yoktur; ancak sonraki çalıştırmalar OS’in weights dosyası önbelleğinden faydalanabilir
- OnnxStream şu anda batch size 1 dışındaki girdileri desteklemez
- OnnxRuntime, UNET çalıştırmasında batch size 2 kullanarak diffusion sürecini genel olarak ciddi biçimde hızlandırabilir
- OnnxRuntime’ın
SessionOptionsiçindekiEnableCpuMemArena,ExecutionModedeğişiklikleri testlerde anlamlı fark yaratmamıştır - NCNN, bellek kullanımı ve çıkarım süresi açısından OnnxRuntime’a çok benzerdi
- Test ortamı: Windows Server 2019, 16 GB RAM, 8750H CPU AVX2, 970 EVO Plus SSD, VMWare 8 sanal çekirdek
- OnnxRuntime’ın ilk çalıştırması,
Attention slicing ve quantization
- UNET çalıştırmasında attention slicing ile VAE decoder’ın W8A8 quantization’ı, belleği Raspberry Pi Zero 2’de çalışabilecek seviyeye indirmede kritik oldu
- attention slicing, multi-head attention içinde scaled dot-product attention hesaplanırken tüm
Q @ K^Tmatrisinin materialize edilmesini önler - UNET modelinde attention head sayısı 8 olduğunda tensör shape’leri şöyledir
Q:(8,4096,40)K^T:(8,40,4096)- İlk MatMul sonucu:
(8,4096,4096) - FP32 hassasiyette bu, 512 MB’lik bir tensör olur
- Çözüm,
Qtensörünü dikey olarak bölüp her chunk için attention işlemi yapmaktırQ_slicedshape’i(1,x,40)olurx, 4096’nınonnxstream::Model::m_attention_fused_ops_partsdeğerine bölünmesiyle elde edilir- Varsayılan değer 2’dir ve özelleştirilebilir
- Bu yöntem, FP32 UNET modelinin toplam bellek kullanımını 1.1 GB’tan 300 MB’a düşürür
- FlashAttention daha verimli bir alternatif olabilir; ancak AVX·NEON gibi desteklenen mimarilere özel çekirdekler yazmayı gerektirir ve bu durumda XNNPACK bypass edilmelidir
Model dönüştürme ve çalıştırma yöntemi
- OnnxStream,
path_to_model_folder/model.txtiçinde tanımlanan modeli çalıştırır- Tüm model operation’ları ASCII biçimindeki
model.txtiçinde yer alır - Weights dosyaları aynı klasörde bir dizi
.bindosyası olarak bulunmalıdır
- Tüm model operation’ları ASCII biçimindeki
Modelnesnesinde çeşitli isteğe bağlı parametreler ayarlanabilir- Farklı bir weights provider belirtme
- Quantization model activation clipping range dosyasını okuma·yazma
- Model kalibrasyon modu
- FP16 aritmetiği kullanma
- UINT8 aritmetiği kullanma
- UINT8 dinamik quantization kullanma
- attention slicing’i etkinleştirme
- attention bölme sayısını ayarlama
- ONNX dosyalarını OnnxStream’de kullanmak için
onnx2txt.ipynbnot defteriylemodel.txtve.binweights dosyaları dışa aktarılır - PyTorch
nn.Module’ünü ONNX’e aktarırken bazı koşullar vardırtorch.onnx.exportçağrısındadynamic_axesboş bırakılmalıdır- OnnxStream dinamik shape girişlerini desteklemez
- Dönüştürmeden önce ONNX Simplifier’ın çalıştırılması kuvvetle tavsiye edilir
Derleme ve çalıştırma hazırlığı
- Stable Diffusion örneği Linux, Mac, Windows ve Termux üzerinde derlenebilir
- Windows’ta
Visual Studio Toolsiçindekix64 Native Tools Command Promptkullanılır - Mac’te
brew install cmakeile cmake kurulumu gerekir
- Windows’ta
- Önce XNNPACK derlenmelidir
- XNNPACK fonksiyon prototype’ları her an değişebileceğinden, belirli bir zamana uygun commit’e checkout yapılmasını içeren bir prosedür vardır
- Referans zaman noktası
2023-06-27 00:00öncesindeki master commit’tir
- Ardından OnnxStream deposu clone edilip
src/buildiçinde cmake ile derlenirMAX_SPEED=ONXNNPACK_DIRile XNNPACK clone yolunun belirtilmesi
MAX_SPEEDseçeneği performansı artırabilir, ancak derleme sırasında daha fazla bellek kullanır- Windows’ta yaklaşık %10 performans artışı
- Raspberry Pi’de %50’den fazla performans artışı
- Oluşan çalıştırılabilir dosya düzgün çalışmayabilir; Termux testlerinde sorun görülmüştür
- Sorun yaşanırsa önce
MAX_SPEED=OFFdenenmesi önerilir
- Stable Diffusion 1.5 örnek weights’leri depo Releases bölümünden alınabilir ve boyutu yaklaşık 2 GB’tır
- Stable Diffusion XL 1.0 Base weights’leri Hugging Face üzerinden alınabilir ve boyutu yaklaşık 8 GB’tır
Stable Diffusion örnek seçenekleri
- Örnek çalıştırılabilir dosya, model seçimi, giriş·çıkış, prompt ve çözümleme yöntemini komut satırı seçenekleriyle kontrol eder
--xl: Stable Diffusion 1.5 yerine Stable Diffusion XL 1.0 çalıştırır--models-path: Stable Diffusion model klasörünü belirtir--ops-printf: çıkarım sırasında mevcut operation’ı stdout’a yazdırır--output: çıktı PNG dosyasını belirtir--decode-latents: diffusion’ı atlayıp belirtilen latents dosyasını çözümler--prompt: positive prompt belirtir--neg-prompt: negative prompt belirtir--steps: diffusion step sayısını belirtir--save-latents: diffusion sonrasında latents’i belirtilen dosyaya kaydeder
- Raspberry Pi ve decoder ile ilgili seçenekler de ayrıca sunulur
--decoder-calibrate: yalnızca SD 1.5’te quantized VAE decoder kalibrasyonu--decoder-fp16: yalnızca SD 1.5’te FP16 VAE decoder kullanımı--not-tiled: yalnızca SDXL 1.0’da tiled VAE decoder kullanmama--rpi: modeli Raspberry Pi’de çalışacak şekilde yapılandırma--rpi-lowmem: yalnızca SDXL 1.0’da Raspberry Pi Zero 2 için düşük bellek yapılandırması uygulama
1 yorum
Hacker News yorumları
İlginç. Kilit cümle şu: “OnnxStream, OnnxRuntime’a kıyasla 55 kata kadar daha az bellek kullanırken hız olarak yalnızca 0,5 ila 2 kat daha yavaş olabilir”
Video belleği/bellek kullanımı ile çıkarım süresi arasındaki ödünleşme, yalnızca Raspberry Pi gibi belleği sınırlı durumlarda değil, başka senaryolarda da avantajlı görünüyor
Bu ağırlıkları boşaltma yöntemiyle aynı bellek içinde gerçekten daha büyük batch boyutları işlenebiliyorsa, gecikme artsa bile throughput ciddi biçimde artırılamaz mı diye merak ediyorum
Muhtemelen “1,5~2 kat daha yavaş” yazmak istemişlerdir
Çıkarım genelde “bu model bu sisteme sığıyor mu” eşiğini geçtikten sonra bellek bant genişliğine takıldığı için, daha büyük batch boyutuyla throughput’u artırmada bu tekniğin pek yardımcı olacağını sanmıyorum. Tek bir instance bile bellek denetleyicisini zaten doyuruyor olabilir
Yine de eğitim tarafında işe yarayabilir
11 saat deyince eskiden Amiga 500 üzerinde ray tracing yaptığım günler aklıma geldi. “Final” render kesinlikle gece boyunca çalıştırılan bir işti
Ama kaustikler parlak görünseler de istatistiksel olarak epey nadir olaylar; düzgün elde etmek için render motorunun sınırlarını kaldırıp gece boyunca kendi hâline bırakmak gerekiyor
Sonuç, güzel kaustiklere sahip, becerisi sınırlı bir sanatçının sıradan bir sahne görüntüsü oluyor. Asıl işime devam etsem iyi olacak
O sıralar başka bir hobiye ihtiyacım olduğunu düşünmüştüm. Hemen öncesinde çok yetenekli biri, sahneyi önce OpenGL ile görebilmeyi sağlayan bir render aracı çıkarmıştı. Amiga’da çalışmazdı ama benim makinemde kıl payı çalışıyordu
MBP’de invoke.ai ile Stable Diffusion kullanıyorum; SD parametrelerini daha iyi ayarlamak için bir öneriniz var mı? Aynı prompt ve görünüşte aynı ayarlar, örneğin Euler A gibi aynı model kullanılsa bile internette gördüğüm görüntü kalitesini bir türlü yakalayamıyorum
Temel SD 1.5 için hızlı olduğu gerekçesiyle Volta kullanıyorum: https://github.com/VoltaML/voltaML-fast-stable-diffusion/com...
Gerçekten iyi SD 1.5 görüntü kalitesi, fine-tune edilmiş modelleri, LoRA’yı, ControlNet’i ve diğer güçlendirme özelliklerini bolca kullanmayı gerektiriyor. Örneğin temel görüntüyü yapı için takip ettirmek veya görüntünün belirli bölgelerine ayrı prompt’lar vermek gibi. InvokeAI de aslında çok özellikli ve bu tür güçlendirmelerin çoğu node UI içinde saklı, ama Volta gibi başka UI’lar bunları daha doğrudan gösteriyor
Genellikle etkileyici fine-tune modeller temel ağırlıklara göre çok daha az genel amaçlı oluyor, ama pratik kullanımda bu pek sorun yaratmıyor ve sonuçları oldukça iyileştirebiliyor
Invoke’a veya Nvidia ekran kartına kıyasla daha fazla zaman ve bellek istiyor ama hiç fena değil. Standart 512x768px kaliteli görüntüler 1~2 s/it, Hires Fix kullanılan yüksek kaliteli 1024x1536px görüntüler ise yaklaşık 14~20 s/it sürüyor
Bunu dijital fotoğraf çerçevesine ya da duvara asılan bir tabloya gömüp çalıştırmak gerçekten harika olurdu
https://github.com/rvdveen/epaper-slow-generative-art/
İnanılmaz bir başarı ama görüntü üretmek elbette aşırı uzun sürüyor. README’de 11 saat yazıyor
Örneğin Pi Zero 2’den 100 tane — W olması da şart değil — kullanarak 100 görüntü üretmenin süresi, maliyeti, gereken tüm donanım ve güç ile ortalama bir orta seviye PC gibi bir şeyle karşılaştırmak gibi
Muhtemelen PC yine de kazanır
Zero 2 pratiklikten çok bir meydan okuma için kullanılmış gibi; Pi 4 veya 5 daha iyi bir referans noktası olabilir
Etkileyici
Gerçekten de lambaların ve tost makinelerinin bile üstün zekâ barındıracağı günler yaklaştı
Bu alanı yıllardır takip ediyorum ama son 10 yıl şaşırtıcıydı
“Şaşırtıcıydı” dememin nedeni, son 6~18 aydaki hızlanmanın bambaşka bir seviyede olması
2 yıl sonra neler yapabileceğimizden çok, gelişim hızının daha ne kadar hızlanacağından endişeleniyorum. Ve sonra tekrar, tekrar hızlanacak
Startup kuralım
Bu noktada Stable Diffusion türü teknolojileri regüle etme girişimleri bitmiş sayılmaz mı? Model ve çıkarım altyapısı küçülüp PS2’de bile çalışabilecek seviyeye gelirse, totaliter bir gözetim devleti olmadan bu teknolojiyi engellemek imkânsız görünüyor; böyle bir devlette bile ancak belki mümkün olur
Medya “korsanlığı” ya da fidye yazılımları da aynı
Devletler, tamamen teknik olarak uygulanması mümkün olmayan şeyleri de çok uzun zamandır regüle ediyor
Eğlenceli bir abartı örneği olduğunu biliyorum ama PS2’de çalıştırmak için bundan çok daha fazla küçültmek gerekir
Windows 3.1 için Stable Diffusion çıkacağı günü sabırsızlıkla bekliyorum
Çılgınca. 11 saat sürsün ya da sürmesin, Pi Zero gibi bir donanımda SD’nin çalışabileceğini hiç beklemiyordum