Yapay Zekâ
Büyük Dil Modelleri için Bellek Optimizasyonu ve İnce Ayarlama
Büyük dil modelleri (LLM’ler) gibi GPT-4, Bloom ve LLaMA, milyarlarca parametreye ölçeklenerek dikkat çekici yetenekler kazanmıştır. Ancak, bu devasa modelleri çıkarım veya ince ayarlama için dağıtmak, muazzam bellek gereksinimleri nedeniyle zorludur. Bu teknik blogda, çeşitli donanım ayarlarındaki LLM çıkarımı ve ince ayarlaması sırasında bellek tüketimini tahmin etme ve optimize etme tekniklerini keşfedeceğiz.
Bellek Gereksinimlerini Anlama
Bir LLM’yi yüklemek için gereken bellek,主要 olarak parametre sayısı ve parametreleri depolamak için kullanılan sayısal kesinlik tarafından belirlenir. Basit bir kural şudur:
- X milyar parametreli bir modeli yüklemek yaklaşık olarak 4X GB VRAM gerektirir 32-bit kayan nokta kesinliğinde
- X milyar parametreli bir modeli yüklemek yaklaşık olarak 2X GB VRAM gerektirir 16-bit bfloat16/float16 kesinliğinde
Örneğin, 175M parametreli GPT-3 modelini yüklemek yaklaşık olarak bfloat16 kesinliğinde 350GB VRAM gerektirecektir. Bugün itibariyle, en büyük ticari olarak उपलबıl olan GPU’lar gibi NVIDIA A100 ve H100 yalnızca 80GB VRAM sunmaktadır, bu da tensor paralelliği ve model paralelliği tekniklerini gerekli kılmaktadır.
Çıkarım sırasında, bellek ayak izi, model parametreleri ve üretilen geçici aktivasyon tensörleri tarafından domine edilir. Çıkarım sırasında zirve bellek kullanımının yüksek düzeyde bir tahmini, model parametrelerini yüklemek için gereken bellek ve aktivasyonlar için belleğin toplamıdır.
Çıkarım Belleğini Nicelendirme
OctoCode modelini kullanarak çıkarım için bellek gereksinimlerini nicelendirelim, bu model yaklaşık 15 milyar parametre içerir ve bfloat16 formatındadır (~ 31GB). Transformers kütüphanesini kullanarak modeli yükleyeceğiz ve metin oluşturacağız:
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
import torch
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder",
torch_dtype=torch.bfloat16,
device_map="auto",
pad_token_id=0)
tokenizer = AutoTokenizer.from_pretrained("bigcode/octocoder")
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
prompt = "Soru: Python'da baytları gigabayta dönüştürmek için bir fonksiyon yazınız.\n\nCevap:"
result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):]
def bytes_to_gigabytes(bytes):
return bytes / 1024 / 1024 / 1024
bytes_to_gigabytes(torch.cuda.max_memory_allocated())
Çıktı:
29.0260648727417Zirve GPU bellek kullanımı yaklaşık 29GB’dir, bu da bfloat16 formatındaki model parametrelerini yüklemek için我们的 31GB’lik tahminimizle uyumludur.
Çıkarım Belleğini Nicelendirme ile Optimizasyon
Bfloat16, LLM’leri eğitmek için yaygın olarak kullanılan kesinliktir, ancak araştırmacılar, model ağırlıklarını daha düşük kesinlikli veri türlerine (8-bit tam sayılar veya 4-bit tam sayılar) nicelendirdiklerinde, metin oluşturma gibi çıkarım görevleri için önemli bir bellek kullanımını azaltabileceğini ve minimal bir doğruluk kaybı ile karşılaşabileceğini bulmuşlardır.
OctoCode modelinin 8-bit ve 4-bit nicelendirmesinden kaynaklanan bellek tasarrufunu görelim:
</div>
# 8-bit nicelendirme
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", load_in_8bit=True,
pad_token_id=0)
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):]
bytes_to_gigabytes(torch.cuda.max_memory_allocated())</pre>
Çıktı:
15.219234466552734
# 4-bit nicelendirme
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", load_in_4bit=True,
low_cpu_mem_usage=True, pad_token_id=0)
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):]
bytes_to_gigabytes(torch.cuda.max_memory_allocated())
Çıktı:
9.5435743331909188-bit nicelendirme ile bellek gereksinimi 31GB’den 15GB’ye düşerken, 4-bit nicelendirme ile 9.5GB’ye düşer! Bu, 15M parametreli OctoCode modelini tüketici GPU’ları gibi RTX 3090 (24GB VRAM) üzerinde çalıştırma olanağı sağlar.
Ancak, daha agresif nicelendirme gibi 4-bit’in bazen 8-bit veya bfloat16 kesinliğine kıyasla doğrulukta bir bozulmaya neden olabileceğini unutmayın. Kullanıcılar, kullanım durumları için bellek tasarrufu ve doğruluk arasında bir denge kurmalıdır.
Nicelendirme, LLM dağıtımını bulut örnekleri, kenar cihazları veya hatta cep telefonları gibi kaynak kısıtlı ortamlara ermögeyen bir tekniktir ve bunu önemli ölçüde bellek ayak izini azaltarak sağlar.
İnce Ayar için Bellek Tahmini
Nicelendirme主要 olarak verimli çıkarım için kullanılırken, tensor paralelliği ve model paralelliği gibi teknikler, büyük dil modellerinin eğitimi veya ince ayarlanması sırasında bellek gereksinimlerini yönetmek için önemlidir.
İnce ayar sırasında zirve bellek tüketimi, genellikle çıkarıma kıyasla 3-4 kat daha yüksektir ve aşağıdaki ek bellek gereksinimlerinden kaynaklanır:
- Gradyan
- Optimizasyon durumları
- Geri yayma için depolanan ileri geçiş aktivasyonları
Muhafazakar bir tahmindir ki, X milyar parametreli bir LLM’yi ince ayarlamak için yaklaşık olarak 4 * (2X) = 8X GB VRAM gerektirir bfloat16 kesinliğinde.
Örneğin, 7M parametreli LLaMA modelini ince ayarlamak için yaklaşık olarak 7 * 8 = 56GB VRAM gerektirecektir her GPU için bfloat16 kesinliğinde. Bu, mevcut GPU’ların bellek kapasitesini aşar ve dağıtılmış ince ayar tekniklerini gerekli kılar.
Dağıtılmış İnce Ayar Teknikleri
GPU bellek kısıtlamalarını aşmak için büyük modellerin dağıtılmış ince ayarlanması için çeşitli yöntemler önerilmiştir:
- Veri Paralelliği: Klasik veri paralelliği yaklaşımı, tüm modeli birden fazla GPU’ya çoğaltır ve eğitim veri partilerini böler ve dağıtır. Bu, eğitim süresini GPU sayısı ile doğrusal olarak azaltır, ancak her bir GPU’daki zirve bellek gereksinimini azaltmaz.
- ZeRO Stage 3: Veri paralelliğinin gelişmiş bir biçimi, model parametrelerini, gradyanlarını ve optimizasyon durumlarını GPU’lar arasında böler. Bu, her bir GPU’da yalnızca gerekli paylaşılan verileri tutarak klasik veri paralelliğine kıyasla belleği azaltır.
- Tensor Paralelliği: Modeli çoğaltmak yerine, tensor paralelliği model parametrelerini satırlara veya sütunlara böler ve bunları GPU’lar arasında dağıtır. Her bir GPU, paylaşılan bir parametre, gradyan ve optimizasyon durumu kümesiyle çalışır, bu da önemli bellek tasarrufuna yol açar.
- Pipeline Paralelliği: Bu teknik, model katmanlarını farklı GPU’lar veya işçiler arasında böler, her bir cihaz bir katman kümesini yürütür. Aktivasyonlar işçiler arasında geçirilir, bu da zirve belleği azaltırken iletişim yükünü artırır.
Bu dağıtılmış yöntemler için bellek kullanımını tahmin etmek zorlu bir iştir, çünkü parametreler, gradyanlar, aktivasyonlar ve optimizasyon durumlarının dağılımı tekniklere göre değişir. Ayrıca, transformer gövdesi ve dil modeli başlığı gibi farklı bileşenler, farklı bellek ayırma davranışları gösterebilir.
LLMem Çözümü
Araştırmacılar, LLMem adlı bir çözüm önerdiler, bu çözüm, LLM’lerin dağıtılmış ince ayarlanması için GPU bellek tüketimini birden fazla GPU’da doğru bir şekilde tahmin eder.
LLMem, hesaplamadan önce parametreleri birleştirmeyi (ZeRO Stage 3), geri yayma sırasında çıktı toplama (tensor paralelliği) ve transformer gövdesi ve dil modeli başlığı için farklı bellek ayırma stratejilerini dikkate alır.
Deneysel sonuçlar, LLMem’in tek bir GPU’da LLM’lerin ince ayarlanması için zirve GPU bellek kullanımını %1.6’ya varan hata oranlarıyla tahmin edebileceğini gösterir, bu da mevcut en iyi DNNMem’in %42.6’lık ortalama hata oranını aşar. Dağıtılmış ince ayar yöntemlerini birden fazla GPU’da milyarlarca parametreli LLM’ler için uygularken, LLMem %3.0’lık ortalama hata oranına ulaşır.











