İçeriğe geç
edumintsBlog
LLM4 dk okuma

Bir LLM Sunucusunun Kaç Kullanıcıyı Barındırabileceğine Neden Ağırlıklar Değil de KV Önbelleği Karar Verir?

Kaynak: dev.to

Paylaş
İçindekiler 4 başlık

fp16 formatındaki 7B parametreli bir model, ağırlıkları (weights) için GPU belleğinde 13.5 GB yer kaplar. 80 GB'lık bir kartta bu durum yaklaşık 66 GB boş alan bırakır ki bu ilk bakışta oldukça yeterli görünür. Ancak 4.096 token bağlam (context) uzunluğuna sahip yaklaşık 30 kullanıcıda bellek tamamen dolar ve belleği dolduran şey ağırlıklar değil, KV önbelleğidir (KV cache).

Bu yazıda işin matematiğini inceleyeceğiz. Tüm sayılar Llama-2-7B mimarisine sahip bir model içindir: 32 katman, 32 dikkat başlığı (attention heads), 128 başlık boyutu (head dimension) ve fp16.

Önbellek Neyi Saklar?#

Sadece kod çözücü (decoder-only) bir model, her ileri geçişte (forward pass) bir token üretir. Yeni token'ın sorgusu (query), daha önceki tüm token'ların anahtar (key) ve değerlerine (value) dikkat (attention) göstermelidir. Önbellek olmadan, her geçişte tüm önek (prefix) için bu anahtar ve değerler baştan hesaplanır.

Nedensel maske (causal mask), yeniden kullanımı güvenli kılan unsurdur. Önceki token'lar sonrakileri göremez; bu nedenle yeni bir token eklemek önceden hesaplanmış anahtar ve değerleri asla değiştirmez. Model bunları bir kez hesaplayıp saklayabilir ve her adımda katman başına yalnızca bir yeni anahtar satırı ile bir yeni değer satırı ekler.

Tasarruf muazzamdır. 5 token'lık bir istem (prompt) ve üretilen 64 token ile her şeyi yeniden hesaplamak katman başına 2.336 anahtar/değer projeksiyonuna mal olur. Önbellek ile bu sayı 68'dir; yani yaklaşık 34 kat daha az. Dikkat mekanizması yine de her adımda önbellekteki tüm anahtarları okur; dolayısıyla önbellek dikkat maliyetinin kendisini değil, yeniden hesaplanan projeksiyonları ortadan kaldırır.

Maliyeti Nedir?#

Tek bir token için önbellek maliyeti şu formülle hesaplanır:

2 (K ve V) × katmanlar × kv_başlıkları × başlık_boyutu × bayt = 2 × 32 × 32 × 128 × 2 = 524.288 bayt ≈ 0.5 MiB

Token başına yarım megabayt hızla büyür:

  • 4.096 Bağlam, 1 Batch: 2.1 GB KV önbelleği
  • 32.768 Bağlam, 1 Batch: 17.2 GB KV önbelleği
  • 4.096 Bağlam, 32 Batch: 68.7 GB KV önbelleği

Tek bir 32K token'lık konuşma, kendi önbelleği için modelin ağırlıklarına kıyasla daha fazla belleğe ihtiyaç duyar. Üstelik ağırlıkların bedeli bir kez ödenirken, önbellek bedeli her dizi (sequence) için ayrı ayrı ödenir. Bu nedenle bir sunucunun aynı anda işleyebileceği kullanıcı sayısı, kabaca boş belleğin tek bir dizinin önbellek boyutuna bölünmesiyle bulunur: Aktivasyonlar ve çalışma zamanı tamponları öncesinde 66.5 GB / 2.1 GB ≈ 30 adet 4.096 token'lık dizi.

Batching (Gruplama) Neden Bu Kadar Önemli?#

Üretim (generation) iki aşamadan oluşur. Prefill (Ön doldurma) aşaması, tüm istemi aynı anda modelden geçirir; böylece bellekten okunan her ağırlık baytı istemdeki tüm token'lar için iş yapar. Decode (Kod çözme) aşaması ise adımda bir token üretir ve okunan her ağırlık baytı yalnızca o tek token için çalışır. Decode aşaması hesaplama gücüyle değil, bellek bant genişliğiyle sınırlıdır.

Çözüm batching kullanmaktır: Ağırlıkların tek bir okuması gruptaki tüm dizilere hizmet eder. Ancak eklenen her dizi kendi KV önbelleğini getirir; bu yüzden batch boyutunu ve dolayısıyla toplam işlem hacmini (throughput) sınırlayan şey önbellek boyutudur.

Modeller Bunu Nasıl Küçültür?#

Üretim ortamlarında Ölçeklendirme ve Optimizasyon yaparken kullanılan her teknik, formüldeki bir terimi azaltır:

  • Daha az KV başlığı: Multi-query attention (Shazeer, 2019) tüm sorgu başlıkları arasında tek bir anahtar/değer başlığını paylaşır. Grouped-query attention (Ainslie vd., 2023) ise birkaç grup kullanır. 32 yerine 8 KV başlığı ile aynı 7B model, 30 yerine yaklaşık 123 adet 4.096 token'lık diziyi sığdırabilir. Llama 2 70B modelinde 8 KV başlığı kullanılırken, 7B modeli 32 başlığın tamamını korur.
  • Daha az bayt: Önbelleği int8 formatında saklamak boyutu tekrar yarıya indirir ve 8 KV başlığıyla küçük bir doğruluk maliyeti karşılığında kapasiteyi yaklaşık 247 diziye çıkarır.
  • Daha az token: Kayan pencere (sliding window) yalnızca en son token'ları tutar. Örneğin Mistral 7B, 4.096 token'lık bir pencere kullanır.
  • Daha az israf: vLLM içinde kullanılan PagedAttention (Kwon vd., 2023), her dizi için maksimum uzunluğu önceden ayırmak yerine önbelleği sabit boyutlu bloklarda saklar; böylece belleğin boş kalmasını önler.

Mühendislik açısından pratik çıkarım şudur: İlk ve üçüncü yöntemler eğitim öncesinde veya sırasında yapılan mimari seçimlerdir. Ancak önbellek niceleme (cache quantization) ve sayfalama (paging) doğrudan sunum (serving) aşamasında uygulanarak mevcut donanım kapasitesini katlayabilir.

Kaynak ve atıf

Bu yazı, dev.to üzerinde yayımlanan içerikten yararlanılarak Edumints tarafından yapay zekâ desteğiyle Türkçe hazırlandı. Ayrıntılar ve yazarların kendi anlatımı için orijinaline bakabilirsin:

  • dev.to/andika_rachman_aa62526318/why-the-kv-cache-not-the-weights-decides-how-many-users-an-llm-server-can-hold-31o0