Dil modelleri, girdi metni token’ları dahil olmak üzere önceki tüm token’ları göz önünde bulundurarak bir sonraki token’ı tahmin ederek metin oluşturur. Önceki token’ların anahtar ve değer bileşenleri, sonraki token setinin üretilmesinde tarihsel bağlam olarak görev alır. Bu anahtar-değer (KV) bileşenlerini önbellekte tutmak, maliyetli yeniden hesaplamalarla karşılaşmadan daha yüksek bir verimlilik sağlar. Ancak, KV önbelleği, dil modelinin boyutu, toplu istek sayısı ve dizi bağlam uzunlukları ile doğru orantılı olarak büyüyerek bellek gereksinimlerini artırır.
NVIDIA TensorRT-LLM, bellek büyüklüğü ile hesaplama maliyetini dengelemenin zorlayıcı mücadelesine yönelik bir dizi KV önbellek optimizasyonu sunar. TensorRT-LLM, NVIDIA GPU’lar üzerinde birçok popüler büyük dil modeli (LLM) için en ileri düzeyde çıkarım desteği sağlayan açık kaynaklı bir kütüphanedir. TensorRT-LLM KV önbellek optimizasyonları arasında sayfalı KV önbelleği, kuantize edilmiş KV önbelleği, dönme tamponu KV önbelleği ve KV önbellek yeniden kullanımı gibi birkaç önemli özellik bulunmaktadır.
Bu yazıda, TensorRT-LLM’ye yeni eklenen iki yüksek düzey özellik üzerinde daha derinlemesine duracağız. Bu özellikler, KV önbelleği üzerinde daha ince ayar kontrolü sağlar ve KV önbelleğinin üst uygulamalarda kullanılmasına yönelik görünürlük sunar, örneğin KV önbelleği bilinçli yönlendirme için.
Öncelik Tabanlı KV Önbellek İhlali
Bir LLM isteği tamamlandığında, bu isteklere ait KV önbellek blokları saklanır. KV önbelleğinin sınırlı boyutu nedeniyle, bazı önbelleğe alınmış blokların yeni diziler için yer açmak amacıyla ihraç edilmesi gerekebilir. Varsayılan olarak, ihraç işlemi en son kullanılan (LRU) politikası takip eder.
struct TokenRangeRetentionConfig {
# Bu aralığın başlangıcı
start: int
# Aralığın sonu. Dizinin sonuna kadar uzatmak için null olarak ayarlayın
end: optional<int>
# Aralığa atanan öncelik seviyesi. 0->100
priority: int
# Bu önceliğin ne kadar süre geçerli olacağı
duration: optional<int>
}
# İsteğe bağlı parametre, yürütücü isteğine
struct KvCacheRetentionConfig {
# Bağlamdaki öncelik atamaları listesi
ranges: list<TokenRangeRetentionConfig>
# Decode token’lar için atanan öncelik
decode_priority: optional<int>
# Decode önceliğinin ne kadar süre geçerli olacağı
decode_duration: optional<int>
}
Öncelik tabanlı ihraç API’si, LLM dağıtıcılarına iş yüklerini bilme becerisi ile yeniden kullanım fırsatlarını artırma yönünde bilgi sağlama olanağı sunar. Örneğin, dağıtıcı, sistem mesajına karşılık gelen blokların mümkün olduğunca uzun süre önbellekte kalmasını isteyebilir veya düşük geçikme süreli isteklerde bulunan blokların daha yüksek öncelikle geçerli olmasını sağlayabilir (Şekil 1).
Her istekte, kullanıcı belirli token aralıkları için bir öncelik ve süre değeri belirtebilir, ayrıca çözme (decode) aşamasında ayrılan bloklar için öncelik ve süre de tanımlayabilir. Bir token aralığı için öncelik seviyesi, yeniden kullanım süresi boyunca geçerli olur veya bu aralığa karşılık gelen bloklar ihraç edilene kadar geçerli kalır.
Blokların ihraç edilmesinde TensorRT-LLM, tokenların öncelik seviyelerini dikkate alır. Örneğin, 500 token’lık bir sistem mesajı içeren bir istekte, token aralığını [0, 500) maksimum öncelik ile ayarlayabilirsiniz. Bu durumda, bu token’lara karşılık gelen önbellek blokları yalnızca gerçekten zorunlu olduğunda ihraç edilir. Alternatif olarak, eğer bir aralığın yeniden kullanılmayacağını biliyorsanız, bu bloklara en düşük önceliği vererek öncelikle bu blokların ihraç edilmesini sağlayabilirsiniz.
Bu yeni uygulama ayrıca, en köklü bloklara daha fazla ağırlık vererek, öncelik seviyeleri ayarlanmamış olsa dahi küçük bir performans artışı sağlar. İçsel karşılaştırmalarımız, öncelik tabanlı ihraç uygulamasının önbellek vurma oranını %20 oranında artırdığını ve bu oranın iş yüküne bağlı olarak değiştiğini ortaya koymaktadır.
# Öncelik tabanlı ihraç kullanım örnekleri
#Örnek 1: Tek seferlik istekte bulunma
KvCacheRetentionConfig(
[TokenRangeRetentionConfig(start=0, end=null, priority=0)],
decode_priority=0
)
#Örnek 2: Yüksek Öncelikli sistem mesajı
KvCacheRetentionConfig(
[TokenRangeRetentionConfig(start=0, end=1000, priority=100)]
)
#Örnek 3: 30 saniye süreyle bağlam bloklarını ve 10 saniye süreyle çözümleme bloklarını tutma
KvCacheRetentionConfig(
[TokenRangeRetentionConfig(start=0, end=null, priority=100, duration=30s)],
decode_priority=100, decode_duration=10s)
KV Önbellek Olay API’si
Büyük ölçekli LLM destekli uygulamalarda, dağıtıcılar genellikle gelen istekleri dağıtmak için bir modelin birden fazla sunum örneğini tahsis eder. Bu durum, yeni isteklerin hangi örnekte işleneceğini sorgulatır. İstekler genellikle yük dengeleme amacıyla yönlendirilir, böylece etkin kullanım ve hızlı yanıt sağlanır. Ancak, herhangi bir örneğin KV önbellek boyutu, yeni iş yükünü kabul etme kapasitesini temsil eder.
Bununla birlikte, yük temelli yönlendirme her zaman en iyi seçim olmayabilir. Eğer bir örnek oldukça az yüklenmişse ve önceden bir isteğin anahtar ve değerini hesaplayıp önbelleğe almışsa, bu isteği bu örneğe yönlendirmek daha verimli olabilir. KV önbellek olay API’si, istek yönlendirme sistemlerinin hangi örneklerin blokları önbelleğe aldığını ya da ihraç ettiğini takip etmesine olanak tanır, böylece daha akıllı yeniden kullanım sağlanır ve performans artırılır.
TensorRT-LLM Yürütücü API’si, KV önbelleğindeki güncellemeleri takip etmek için bir yöntem sunar.
struct KVCacheEvent {
event_id: long // Artan otomatik olay kimliği
data: variant<CreatedData, StoredData, RemovedData, UpdatedData>
}
struct StoredBlockData {
blockHash: id // Bloğun benzersiz kimliği.
tokens: list<Token>
loraId: id
cacheLevel: int // Bloğun önbellek seviyesi (0 veya 1, birincil veya ikincil)
priority: int // Bu bloğun öncelik seviyesi
}
struct StoredData {
parentHash: optional<id> // Saklanan blokların dizisinin üst öğesi.
blocks: list<StoredBlockData> // Saklanan blokların listesi
}
struct RemovedData {
blockHashes: list<id> // Kaldırılan blokların hash’leri
}
# Dahili olay önbelleğinin maksimum boyutunu ayarlama. Varsayılan değer 0 (olay yok)
kv_cache_config = KvCacheConfig(event_buffer_max_size=16384)
executor_config = ExecutorConfig(kv_cache_config)
executor = Executor(executor_config)
# Olay yöneticisini al
eventManager = executor.getKvCacheEventManager()
# Yeni olaylar için bekleyin. Döndüğünde, dahili olay kuyruğunu otomatik olarak temizler. İsteğe bağlı bir zaman aşımı değeri verebilirsiniz. Bu zaman aşımında önceki olay yoksa, boş bir liste döner.
events = eventManager.getLatestEvents()
Bir önbellek bloğu yeniden kullanım için saklandığında, kaldırıldığında veya güncellendiğinde bir olay yayımlanır. Bu olaylar, uygulamalar tarafından gerçek zamanlı olarak tüketilebilir ve TensorRT-LLM KV önbelleğinin mevcut durumunun sonuçta tutarlı bir görünümünü elde etmeye yardımcı olabilir. Bu durum, önbellek yeniden kullanım fırsatlarını takip etmek için oldukça faydalıdır. Bu etkinlikler, tek bir yürütücü ölçeğinde hangi isteklerin daha fazla yeniden kullanım içereceğini tahmin etmek ya da birçok yürütücüyü kapsayarak KV’ye duyarlı yönlendirme ve zamanlama kararları almak amacıyla bir araya getirilebilir (Şekil 2).
Öncelik tabanlı ihraç ve olay tabanlı yönlendirme gibi KV önbellek yeniden kullanım ve yönetiminde sağlanan bu yeni özelliklerle birlikte, TensorRT-LLM, KV önbelleğini yönetmenizi sağlayan ince ayar kontrolleri sunar. Bu sayede iş yüklerinizin bilgilerini daha etkili bir şekilde kullanarak KV önbellek yönetimini optimize edebilirsiniz.
Özet
NVIDIA TensorRT-LLM, generatif AI uygulamalarınızı NVIDIA destekli altyapı üzerinde verimli bir şekilde dağıtmanız için bir dizi optimizasyon sunmaktadır. Bu optimizasyonlar, aynı donanımda önemli hız artışları ve daha iyi önbellek yeniden kullanımı sağlar. Sonuç olarak, daha az kaynak kullanarak aynı iş yükünü sunma imkanı tanır, enerji maliyetlerini azaltır ve toplam sahip olma maliyetini iyileştirir.