Çıkarım optimizasyonu, üretimde kullanılan üretken yapay zeka uygulamalarının kritik bir parçasıdır. LLM'leri ölçekte verimli bir şekilde kullanmak zorlu bir iştir ve çıkarımı daha hızlı ve daha ucuz hale getirmek için son yıllarda birçok teknik geliştirilmiştir. Bu makalede bu teknikleri gözden geçirelim.
Büyük dil modellerinin (LLM'ler) tümü, 2017 yılında Vaswani ve arkadaşları tarafından icat edilen transformatör mimarisine dayanmaktadır. Transformatör mimarisi, çeşitli dil görevlerinde üstün doğruluk, az sayıda öğrenme ve insana yakın yetenekler elde eder. Bununla birlikte, genellikle onlarca ila yüz milyarlarca parametre içeren bu temel modellerin eğitilmesi maliyetlidir ve çıkarım sırasında kaynak yoğundur. Çıkarım maliyetleri, büyük girdi verileri nedeniyle önemli işlem gücü gerektiren uzun girdi bağlamlarında artar. Bu durum, özellikle bellek ve hesaplama kaynaklarının yönetiminde verimli çıkarım yapmayı kritik bir zorluk haline getirmektedir.

Daha spesifik olarak, en iyi bilinen LLM'ler, GPT-3, GPT-4, LLaMA, Mistral, DeepSeek, vb. gibi yalnızca kod çözücü LLM'lerdir. Bu modeller nedensel bir modelleme görevi üzerinde önceden eğitilir ve sonraki kelime tahmin edicileri olarak işlev görür. Bir dizi jetonu girdi olarak işlerler ve bir durdurma koşuluna ulaşılana kadar otoregresif olarak takip eden jetonları üretirler.
Yalnızca kod çözücü modellerinde LLM çıkarımı iki temel aşama içerir: ön doldurma aşaması ve kod çözme aşaması. Ön doldurma aşamasında model, ilk yeni belirteci oluşturmak üzere ara durumları (anahtarlar ve değerler) hesaplamak için girdi belirteçlerini işler. Matris-matris işlemine benzeyen bu aşama yüksek oranda paralelleştirilmiştir ve GPU yeteneklerini verimli bir şekilde kullanır. Tersine, kod çözme aşaması, önceki belirteçlerin durumlarına dayanarak her seferinde bir belirteç üretir. Bu matris-vektör işlemi belleğe bağlıdır, çünkü hesaplama hızından ziyade GPU'ya veri aktarımı öncelikle gecikmeyi belirler ve GPU hesaplama gücünün yeterince kullanılmamasına neden olur.
Kod çözme aşamasını optimize etmek, çıkarım zorluklarını ele almak için bir odak noktasıdır. Çözümler arasında verimli dikkat mekanizmalarının geliştirilmesi ve bellek darboğazlarını azaltmak için anahtarların ve değerlerin daha iyi yönetilmesi yer almaktadır. Bu yazı, okuyucuların transformatör mimarisi ve dikkat mekanizmaları hakkında temel bir anlayışa sahip olduğunu varsayarak çıkarım performansını artırmak için pratik yaklaşımları vurgulamaktadır. Bu optimizasyonlar, gerçek dünyadaki LLM dağıtımlarında verimi artırmak ve gecikmeyi azaltmak için çok önemlidir.
LLM'ler arasında farklı belirteçleştiricilerin kullanılması, belirteç karşılaştırılabilirliğini etkileyen bir başka komplikasyondur. Kabaca dört İngilizce karaktere eşdeğer olan belirteçler, belirteçleştiriciye bağlı olarak temsilde değişiklik gösterir ve çıkarım veriminin (örneğin, saniye başına belirteç) doğrudan karşılaştırmalarını yanıltıcı hale getirir. Bu değişkenlik, çıkarım sırasında LLM performansını doğru bir şekilde değerlendirmek ve karşılaştırmak için standartlaştırılmış değerlendirme ölçütlerine duyulan ihtiyacın altını çizmektedir.
Toplu işlem, büyük dil modellerinde (LLM'ler) GPU kullanımını ve verimini artırmak için önemli bir stratejidir. Aynı modeli kullanarak birden fazla isteği aynı anda işleyen toplu iş, model ağırlıklarının bellek maliyetini istekler arasında dağıtarak daha büyük toplu işlerin daha fazla GPU işlem gücünden yararlanmasını sağlar. Bununla birlikte, aşırı büyük gruplar, özellikle anahtar-değer (KV) önbelleğe alma ile ilgili olarak LLM'lerin bellek talepleri nedeniyle bellek taşmasına neden olabileceğinden, toplu iş boyutunun bir sınırı vardır (bu konuda daha sonra daha fazla bilgi verilecektir).

Geleneksel ya da statik gruplamanın sınırlamaları vardır çünkü bir grup içindeki istekler genellikle farklı sayıda tamamlama belirteci üretir ve bu da farklı yürütme sürelerine yol açar. Bu, tüm isteklerin en yavaş olanın tamamlanmasını beklemesine neden olur ve bu da üretim uzunlukları önemli ölçüde değiştiğinde sorunlu olabilir. Bu sorunu çözmek amacıyla, performansı optimize etmek için uçuş sırasında toplu işlem gibi gelişmiş teknikler geliştirilmiştir.
Sürekli gruplama olarak da bilinen uçuş sırasında gruplama, basit chatbot yanıtlarından karmaşık belge özetleme veya kod oluşturmaya kadar değişebilen LLM iş yüklerinin dinamik doğasının getirdiği zorlukların üstesinden gelir. Bu görevler çok farklı boyutlarda çıktılar üretir, bu da istekleri paralel olarak verimli bir şekilde toplu hale getirmeyi ve yürütmeyi zorlaştırır. Statik gruplamanın aksine, uçuş sırasında gruplama, sunucunun tamamlanan dizileri hemen gruptan çıkarmasına ve diğerleri hala devam ederken yeni istekleri işlemeye başlamasına olanak tanır. Bu yaklaşım, gerçek dünya senaryolarında isteklerin değişen yürütme sürelerine uyum sağlayarak GPU kullanımını önemli ölçüde artırır.
Model paralelleştirme, büyük ölçekli makine öğrenimi modellerinin bellek ve hesaplama taleplerini birden fazla GPU'ya dağıtarak yönetmek için kritik bir stratejidir. Bu yaklaşım, tek bir cihazın bellek kapasitesini aşan daha büyük modellerin veya girdi yığınlarının işlenmesine olanak tanıyarak bellek kısıtlamalarının sıkı olduğu durumlarda hem eğitim hem de çıkarım için gerekli hale getirir. Model ağırlıklarını bölmek için her biri model dağılımının farklı yönlerini ele alan boru hattı paralelliği, tensör paralelliği ve dizi paralelliği dahil olmak üzere çeşitli teknikler mevcuttur. Eğitim sırasında daha büyük girdi yığınlarını işlemek için model ağırlıklarını cihazlar arasında çoğaltmaya odaklanan veri paralelliğinin aksine, bu yöntemler hem eğitim hem de çıkarım sırasında bellek ayak izlerini azaltmak için daha uygundur.

Boru hattı paralelliği, modeli dikey olarak sıralı parçalara böler ve her parça ayrı bir cihaza atanmış katmanların bir alt kümesini içerir. Örneğin, dört yönlü bir boru hattı kurulumunda, her cihaz modelin katmanlarının dörtte birini işler ve çıktıları sırayla bir sonraki cihaza aktarır. Bu, cihaz başına bellek gereksinimlerini önemli ölçüde azaltırken, cihazların önceki katmanlardan çıktı beklerken boşta kalabileceği "boru hattı balonları" olarak bilinen verimsizlikleri ortaya çıkarır. Sıralı işleme için girdi yığınlarını daha küçük alt yığınlara bölen mikro harmanlama, ileri ve geri geçişler sırasında boşta kalma süreleri devam ettiğinden bu kabarcıkları azaltabilir ancak tamamen ortadan kaldıramaz.
Tensör paralelliği ise tek tek katmanları, cihazlar arasında bağımsız olarak yürütülebilen daha küçük hesaplama bloklarına yatay olarak parçalar. Bu, özellikle dikkat blokları ve çok katmanlı algılayıcılar (MLP'ler) gibi dönüştürücü bileşenleri için etkilidir; örneğin, farklı dikkat başlıkları paralel hesaplama için ayrı cihazlara atanabilir. Ancak tensör paralelliği, kolayca bölünemeyen ve cihazlar arasında çoğaltılması gereken LayerNorm ve Dropout gibi işlemler için daha az etkilidir, bu da aktivasyonları depolamak için gereksiz bellek kullanımına yol açar. Bu sınırlama, bellek verimliliğini optimize etmek için tamamlayıcı yaklaşımlara duyulan ihtiyacı vurgulamaktadır.
Dizi paralelliği, LayerNorm ve Dropout gibi işlemlerin bellek verimsizliklerini, bunları giriş dizisi boyutu boyunca bölümlendirerek ve dizi öğeleri arasındaki bağımsızlıklarından yararlanarak ele alır. Bu yöntem, gereksiz aktivasyonların bellek ayak izini azaltarak tensör paralelliğinin değerli bir tamamlayıcısı haline gelir. Bu paralelleştirme teknikleri birbirini dışlamaz ve büyük dil modellerini (LLM'ler) daha da optimize etmek için birleştirilebilir. Ek olarak, dikkat modülü için özel optimizasyon stratejileri ölçeklenebilirliği artırabilir ve GPU başına bellek taleplerini azaltarak büyük modeller için daha verimli eğitim ve çıkarım sağlayabilir.
Vaswani ve arkadaşlarının 2017 tarihli *Attention Is All You Need* makalesi, temel taşı öz-dikkat olan Transformer modelini tanıttı. Öz-dikkat, modelin bir cümledeki farklı kelimelerin birbirleriyle olan ilgisini değerlendirmesini sağlayarak doğal dil işleme gibi görevler için bağlamsal anlayışı geliştirir. Makale, özellikle sorgu ve anahtar-değer çiftlerini bir çıktıya eşleyen ölçeklendirilmiş nokta-çarpım dikkat (SDPA) mekanizması aracılığıyla kendi kendine dikkati resmileştirdi ve modern sinir ağlarında çok önemli bir bileşen haline getirdi. İşte dikkat hesaplamalarını optimize etmek için en önemli tekniklerden bazıları:

Çok kafalı dikkat (MHA), her biri sorgu, anahtar ve değer matrislerinin farklı projeksiyonlarına sahip birden fazla dikkat işlemini paralel olarak çalıştırarak SDPA'yı geliştirir. Bu paralel işlemler veya "başlıklar", farklı temsili alt uzaylara odaklanarak modelin girdi anlayışını zenginleştirir. Bu kafalardan elde edilen çıktılar birleştirilir ve doğrusal olarak yansıtılır, her bir kafanın boyutluluğunu azaltarak (örneğin, model boyutunu 8 gibi kafa sayısına bölerek) tek kafalı dikkatle karşılaştırılabilir hesaplama verimliliğini korur.
Çoklu sorgu dikkati (MQA), birden fazla sorgu projeksiyonunu korurken anahtar ve değer projeksiyonlarını birden fazla dikkat kafası arasında paylaşarak çıkarım için MHA'yı optimize eder. Bu, bellek bant genişliği taleplerini ve anahtar-değer (KV) önbelleğinin boyutunu azaltarak daha büyük yığın boyutları ve daha iyi işlem kullanımı sağlar. Bununla birlikte, MQA doğruluğu biraz azaltabilir ve bundan yararlanan modeller, performansı korumak için MQA etkinken eğitim veya ince ayar gerektirir.
Gruplandırılmış sorgu dikkati (GQA), sorgu başlıklarını gruplandırarak ve her grup içinde anahtar-değer projeksiyonlarını paylaşarak MHA ve MQA'yı dengeler ve MQA'ya daha yakın hesaplama verimliliği ile MHA'ya yakın kalite elde eder. Llama 2 70B gibi modeller GQA kullanır ve MHA ile eğitilenler minimum ek eğitimle GQA'ya uyarlanabilir. Hem MQA hem de GQA, KV önbellek bellek taleplerini azaltır, ancak önbellek yönetiminde daha fazla optimizasyon gerekli olmaya devam etmektedir.
FlashAttention, GPU bellek hiyerarşilerinden daha etkili bir şekilde yararlanmak için hesaplamaları yeniden sıralayarak dikkat mekanizmalarını geliştirir. Geleneksel katman katman işlemenin aksine, FlashAttention işlemleri birleştirir ve çıktı matrisinin küçük bölümlerini bir kerede hesaplamak için "döşeme" kullanarak bellek okuma/yazma işlemlerini en aza indirir. Bu I/O farkındalıklı, tam dikkat algoritması, mevcut modellere değişiklik yapmadan sorunsuz bir şekilde entegre olur ve veri hareketini optimize ederek önemli hız artışları sunar.
KV önbelleğe alma, büyük dil modellerinin (LLM'ler) kod çözme aşamasında öz dikkat hesaplamalarının verimliliğini artırmak için kullanılan kritik bir optimizasyon tekniğidir. Bu aşamada, üretilen her bir belirteç, ön doldurma aşaması ve sonraki kod çözme adımları sırasında hesaplananlar da dahil olmak üzere önceki tüm belirteçlerin anahtar (K) ve değer (V) tensörlerine bağlıdır. Her zaman adımında her belirteç için bu tensörleri yeniden hesaplamak yerine, KV önbelleği bunları GPU belleğinde saklar ve hesaplandıkça önbelleğe yeni tensörler ekler. Tipik olarak, modelin her katmanı için ayrı bir KV önbelleği tutulur, bu da gereksiz hesaplamaları önemli ölçüde azaltır ve kod çözme sürecini hızlandırır.

GPU'lardaki LLM'ler için bellek gereksinimleri temel olarak iki bileşenden kaynaklanır: model ağırlıkları ve KV önbelleği. Modelin parametrelerinden oluşan model ağırlıkları önemli bir bellek kaplar; örneğin, 16 bit hassasiyette Llama 2 7B gibi 7 milyar parametreli bir model yaklaşık 14 GB gerektirir. Öte yandan KV önbelleği, yeniden hesaplamayı önlemek için kendi kendine dikkat tensörlerini depolar ve boyutu katman sayısı, dikkat kafaları, kafa boyutları ve hassasiyet gibi faktörlere göre belirlenir. Her bir token için önbellek boyutu 2 * num_layers * (num_heads * dim_head) * precision_in_bytes olarak hesaplanır; burada 2 faktörü hem K hem de V matrislerini hesaba katar. Bir girdi grubu için toplam KV önbellek boyutu, grup boyutu ve sıra uzunluğu ile ölçeklenir ve potansiyel olarak 4.096 sıra uzunluğuna ve 1 grup boyutuna sahip bir Llama 2 7B modeli için ~2 GB gibi önemli boyutlara ulaşır.
KV önbelleğini verimli bir şekilde yönetmek, yığın boyutu ve sıra uzunluğu ile doğrusal büyümesi nedeniyle zorluklar ortaya çıkarır; bu da verimi sınırlayabilir ve uzun bağlamlı girdilerin işlenmesini zorlaştırabilir. Yaygın bir verimsizlik, gerçek girdi boyutuna bakılmaksızın belleğin desteklenen maksimum dizi uzunluğu (örneğin, 2.048 belirteç) için ayrıldığı statik aşırı provizyondan kaynaklanır. Ayrılan alanın büyük bir kısmı genellikle isteğin ömrü boyunca kullanılmadan kaldığı ve değerli GPU bellek kaynaklarını meşgul ettiği için bu durum önemli ölçüde bellek israfına veya parçalanmasına yol açar.
Bu verimsizlikleri gidermek için PagedAttention algoritması, işletim sistemi sayfalamasından esinlenen yeni bir yaklaşım sunar. KV önbelleğini, her biri bellekte bitişik olmayan bir şekilde saklanabilen belirli sayıda jetonu temsil eden sabit boyutlu bloklara böler. Bir blok tablosu bu blokları izler ve dikkat hesaplamaları sırasında gerektiğinde getirir. Yeni belirteçler üretildikçe, ek bloklar dinamik olarak tahsis edilir. Bu yöntem, bitişik tahsis ve aşırı tahsis ihtiyacını ortadan kaldırarak bellek israfını en aza indirir, daha büyük parti boyutlarına olanak tanır ve verimi artırır, böylece LLM'ler için KV önbellek yönetiminde önemli bir ilerleme sağlar.
Bu bölümde, büyük dil modellerinin (LLM'ler) bellek tüketimini azaltmak ve GPU'lardaki performansı artırmak için optimize edilmesine yönelik çeşitli teknikleri tartışıyoruz. Temel yöntemler, her biri model verimliliğinin farklı yönlerini hedefleyen niceleme, seyreklik ve damıtmayı içerir. Bu teknikler model ağırlıklarını değiştirir, GPU donanım hızlandırmasından yararlanır ve bilgiyi daha küçük modellere aktararak daha büyük modellerin performansı korurken sınırlı donanımda çalışmasını sağlar. Bu yöntemler modelin doğruluğunu düşürebilir, bu nedenle dikkatli kullanılmalıdır.
Niceleme, bir modelin ağırlıklarının ve aktivasyonlarının hassasiyetini tipik olarak 32 veya 16 bitten 8 veya daha az bite düşürerek modellerin daha az bellek işgal etmesine ve verileri daha verimli bir şekilde aktarmasına olanak tanır. Ağırlıkları nicelemek, eğitim sonrası sabit yapıları nedeniyle basitken, aktivasyonları nicelemek dinamik aralıklarını genişleten aykırı değerler nedeniyle daha karmaşıktır. LLM.int8() gibi teknikler, belirli aktivasyonlara seçici olarak daha yüksek hassasiyet uygulayarak veya aktivasyonlar için nicelenmiş ağırlıkların dinamik aralığını yeniden kullanarak bunu ele alır, ancak GPU'lar işlemler için ağırlıkları daha yüksek hassasiyete geri dönüştürmeyi gerektirebilir.
Seyreklik, sıfıra yakın model değerlerini budayarak daha az bellek gerektiren seyrek matrisler oluşturmayı içerir. GPU'lar, her dört değerden ikisinin sıfır olarak temsil edilmesi gibi yapılandırılmış seyrekliği destekler ve bu da hesaplamaları hızlandırır. Seyrekliği niceleme ile birleştirmek yürütme hızını daha da artırabilir. Araştırmalar, LLM'ler için en uygun seyrek temsilleri keşfetmeye devam ediyor ve bu da çıkarım hızlarını iyileştirmek için umut verici bir yol olduğunu gösteriyor.
Distilasyon, bilgiyi daha büyük bir "öğretmen" modelinden daha küçük bir "öğrenci" modeline aktararak performansı korurken boyutu sıkıştırır. Örneğin DistilBERT, BERT'e kıyasla %40 boyut küçültme ve %60 hız artışı sağlarken yeteneklerinin %97'sini korur. Distilasyon, öğretmenin çıktılarını taklit etmeyi veya eğitim için öğretmen tarafından oluşturulan verileri kullanmayı içerebilir ve "Adım Adım Distilasyon!" gibi yöntemler verimli öğrenme için gerekçeler içerir. Bununla birlikte, birçok gelişmiş LLM'deki kısıtlayıcı lisanslar, damıtma için uygun öğretmen modellerinin kullanılabilirliğini sınırlamaktadır.
Spekülatif örnekleme veya destekli üretim olarak da bilinen spekülatif çıkarım, GPT tarzı modeller gibi tipik olarak token token metin üreten otoregresif büyük dil modellerinin (LLM'ler) yürütülmesini paralelleştirmek için kullanılan bir yöntemdir. Standart yürütmede, her bir belirteç bağlam için önceki tüm belirteçlere bağlıdır ve n'inci belirteç (n+1)inci belirteçten önce üretilmesi gerektiğinden paralel üretimi imkansız hale getirir. Spekülatif çıkarım, gelecekteki birden fazla jetonu aynı anda tahmin etmek için "daha ucuz" bir taslak model kullanarak bu sorunu çözer, daha sonra bunlar ana model tarafından paralel olarak doğrulanır veya reddedilir ve daha hızlı metin üretimine izin verir.
Süreç, daha az kaynak yoğun bir yöntem kullanarak birkaç belirteçten oluşan bir taslak devamı oluşturmayı ve ardından taslağı spekülatif bağlam olarak kullanan ana model tarafından paralel doğrulamayı içerir. Doğrulama modeli taslak belirteçlerle eşleşirse, bunlar kabul edilir; aksi takdirde, eşleşmeyen belirteçler ve sonraki belirteçler atılır ve süreç yeni bir taslakla tekrarlanır. Taslak belirteçler, birden fazla modelin eğitilmesi, gelecekteki belirteçleri tahmin etmek için önceden eğitilmiş bir model üzerinde birden fazla kafaya ince ayar yapılması veya daha büyük, daha yetenekli bir doğrulama modelinin yanında daha küçük bir taslak modelin kullanılması gibi çeşitli yaklaşımlar kullanılarak oluşturulabilir.
Ayrıştırılmış çıkarım, performans, maliyet ve kaynak kullanımını optimize etmek için hesaplama görevlerinin farklı donanımlara bölündüğü bir tekniktir. Özellikle, ön doldurma ve kod çözme aşamalarını ayırır. Bu aşamaların ayrıştırılmasıyla, her biri hesaplama talepleri için en uygun donanıma atanarak verimlilik ve ölçeklenebilirlik artırılabilir.

Ön doldurma yoğun işlem gerektirir, tüm girdi istemini işlemek ve KV önbellekleri üretmek için önemli matris çarpımları gerektirir. Bu aşama, paralel hesaplamalarda mükemmel olan GPU'lar veya TPU'lar gibi yüksek performanslı donanımlardan yararlanır. Ön doldurma, çıkarım isteği başına tek seferlik bir görev olduğundan, bu tür iş yükleri için optimize edilmiş merkezi, güçlü bir hesaplama düğümüne yüklenebilir. Bu kurulum, büyük istemlerin daha hızlı işlenmesini sağlar ve daha az yetenekli cihazların yükünü azaltır, bu da onu yüksek verimli donanımın mevcut olduğu bulut tabanlı veya veri merkezi ortamları için ideal hale getirir.
Buna karşın, kod çözme belleğe bağlıdır ve büyük ölçüde KV önbelleklerine erişime dayanan yinelemeli belirteç üretimini içerir. Daha az hesaplama gücü gerektirir ancak hızlı bellek erişimine ihtiyaç duyar, bu da onu CPU'lar veya uç cihazlar gibi daha az güçlü, bellek için optimize edilmiş donanımlar için uygun hale getirir. Ayrıştırılmış çıkarım, kod çözme işlemini ayrı bir donanıma (şirket içi sunucular veya uç cihazlar gibi potansiyel olarak son kullanıcıya daha yakın) taşıyarak gecikme süresini ve ağ bant genişliği taleplerini azaltır. Bu ayrıştırma, ön doldurmanın üst düzey bulut sunucularında çalıştığı ve kod çözmenin yerel veya uç cihazlarda gerçekleştiği, kaynak tahsisini optimize eden ve gerçek zamanlı sohbet robotları veya etkileşimli yapay zeka sistemleri gibi uygulamalar için verimli ölçeklendirme sağlayan esnek dağıtım sağlar.
LLM'lerin performansını artırmak için son zamanlarda birçok çıkarım optimizasyon tekniği icat edilmiştir.
Bu teknikleri uygulamak, LLM mimarisini ve kullandığınız donanımı derinlemesine anlamayı gerektirir, bu nedenle genellikle vLLM, TensorRT-LLM, LMDeploy vb. gibi bu teknikleri zaten uygulamış olan mevcut bir çıkarım motorunu kullanmak daha kolaydır. Aslında bu teknikleri NLP Cloud'daki kendi çıkarım motorumuzda uyguladık ve kendi modellerinizi dağıtmak istiyorsanız çıkarım motorları hakkında bir blog yazısı yazdık: buradan okuyabilirsiniz.
Kendi LLM'lerinizi kendiniz dağıtamıyorsanız veya dağıtmak istemiyorsanız, NLP Cloud'u kullanabilir ve üretimde büyük ölçekte hızlı üretken yapay zeka modellerinden yararlanabilirsiniz. NLP Cloud'da hızlı çıkarımı şimdi deneyin!
Genel olarak çıkarım motorları hakkında sorularınız varsa, lütfen bize sormaktan çekinmeyin, tavsiye vermekten her zaman memnuniyet duyarız!
Julien
NLP Cloud'da CTO