Transformers documentation
Önbellekleme stratejileri
Önbellekleme stratejileri
Anahtar-değer (KV) vektörleri, dikkat puanlarını hesaplamak için kullanılır. Otoregresif modellerde, model her seferinde bir token tahmin ettiği için KV puanları her seferinde hesaplanır. Her tahmin, önceki token'lara bağlıdır; bu da modelin her seferinde aynı hesaplamaları gerçekleştirdiği anlamına gelir.
KV cache, bu hesaplamaları saklayarak yeniden hesaplamaya gerek kalmadan yeniden kullanılmasını sağlar. Verimli önbellekleme, hesaplama süresini azalttığı ve yanıt hızlarını artırdığı için model performansını optimize etmede kritik öneme sahiptir. Bir önbelleğin nasıl çalıştığına dair daha ayrıntılı bir açıklama için Caching belgesine bakın.
Transformers, farklı önbellekleme mekanizmalarını uygulayan çeşitli Cache sınıfları sunar. Bu Cache sınıflarından bazıları bellek tasarrufu için optimize edilirken, diğerleri üretim hızını en üst düzeye çıkarmak üzere tasarlanmıştır. Önbellek türlerini karşılaştırmak için aşağıdaki tabloya başvurun ve kullanım durumunuz için en iyi önbelleği seçmenize yardımcı olmak için bu tabloyu kullanın.
| Önbellek Türü | Kayan katmanları destekler | Offload desteği | torch.compile() destekler | Beklenen bellek kullanımı |
|---|---|---|---|---|
| Dinamik Önbellek | Evet | Evet | Hayır | Orta |
| Statik Önbellek | Evet | Evet | Evet | Yüksek |
| Örnekleştirilmiş Önbellek | Hayır | Hayır | Hayır | Düşük |
Bu kılavuz, farklı Cache sınıflarını tanıtır ve bunların üretim için nasıl kullanılacağını gösterir.
Varsayılan önbellek
DynamicCache, tüm modeller için varsayılan önbellek sınıfıdır. Üretim ilerledikçe artan sayıda anahtar ve değeri depolamak için önbellek boyutunun dinamik olarak büyümesine olanak tanır.
Sliding window attention (Mistral, Gemma2,…) veya chunked attention (Llama4) kullanan modellerde, bu dikkat türlerini kullanan katmanlar maksimum boyutlarına (sliding window veya chunk boyutu) ulaştığında önbelleğin büyümesinin duracağını unutmayın.
Önbelleği devre dışı bırakmak için generate() içinde use_cache=False olarak yapılandırın.
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", dtype=torch.float16, device_map="auto")
inputs = tokenizer("I like rock music because", return_tensors="pt").to(model.device)
model.generate(**inputs, do_sample=False, max_new_tokens=20, use_cache=False)Cache sınıfları, modellerin past_key_values parametresine geçilmeden önce de başlatılabilir. Bu, daha ince ayarlı kontrol veya bağlam önbellekleme gibi daha gelişmiş kullanım senaryoları için faydalı olabilir.
Çoğu durumda, önbellek stratejisini cache_implementation parametresinde tanımlamak daha kolaydır.
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, DynamicCache
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", dtype=torch.float16, device_map="auto")
inputs = tokenizer("I like rock music because", return_tensors="pt").to(model.device)
past_key_values = DynamicCache(config=model.config)
out = model.generate(**inputs, do_sample=False, max_new_tokens=20, past_key_values=past_key_values)Sabit boyutlu önbellek
Varsayılan DynamicCache, önbellek boyutu sabit olmadığından, çoğu just-in-time (JIT) optimizasyonundan yararlanmanızı engeller. JIT optimizasyonları, bellek kullanımı pahasına gecikmeyi en aza indirmenizi sağlar. Aşağıdaki tüm önbellek türleri, üretimi hızlandırmak için torch.compile gibi JIT optimizasyonlarıyla uyumludur.
Sabit boyutlu bir önbellek (StaticCache), kv çiftleri için belirli bir maksimum önbellek boyutunu önceden ayırır. Önbelleği değiştirmek zorunda kalmadan, maksimum önbellek boyutuna kadar çıktı üretebilirsiniz. Ancak anahtar/değer durumları için sabit (genellikle büyük) bir boyut, üretim sırasında dikkate katılmaması gereken birçok token'ın fiilen maskelendiği anlamına gelir. Bu nedenle bu yöntem, çözümleme aşamasını kolayca compile etmenizi sağlar, ancak dikkat hesabında token israfına yol açar. Her şeyde olduğu gibi bu da bir ödünleşimdir; daha az veya daha çok benzer uzunluklarda birden fazla diziyle üretim yapıyorsanız çok iyi sonuç verir, ancak örneğin 1 çok büyük dizi ve ardından yalnızca kısa diziler varsa (sabit önbellek boyutu büyük olacağından, kısa diziler için çok fazla israf olacaktır) en iyi sonucu vermeyebilir. Kullanırsanız etkisini anladığınızdan emin olun!
DynamicCache için, kayan pencere dikkati (Mistral, Gemma2,…) veya parçalı dikkati (Llama4) kullanan modellerde, bu dikkat türlerini kullanan katmanlarda önbelleğin, belirtilen maksimum uzunluk daha büyük olsa bile, asla kayan pencere/parça boyutundan büyük olmayacağını unutmayın.
generate() içinde cache_implementation="static" yapılandırmasını ayarlayarak StaticCache özelliğini etkinleştirebilirsiniz. Bu, açgözlü ve örneklem çözme stratejileri için çözümleme aşamasının otomatik compilation işlemi de devreye alır.
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", dtype=torch.float16, device_map="auto")
inputs = tokenizer("Hello, my name is", return_tensors="pt").to(model.device)
out = model.generate(**inputs, do_sample=False, max_new_tokens=20, cache_implementation="static")
tokenizer.batch_decode(out, skip_special_tokens=True)[0]
"Hello, my name is [Your Name], and I am a [Your Profession] with [Number of Years] of"Üretim tensörlerini CPU'da tutun
Neuron ve TPU gibi derleyici arka uçları, modelinizi sabit bir hesaplama grafiğine izler. Üretim döngüsü, her adımda bir token büyüyen tensörleri (çıktı dizisi, attention_mask, position_ids) sürdürür. Hızlandırıcıda bu tensörlerin şekli her değiştiğinde derleyici grafiği yeniden izler ve bu da üretimi yavaşlatır.
generate(), her forward çağrısından hemen önce, yalnızca forward tarafından tüketilen tensörleri model cihazına taşır. Çıktı, girdinin cihazıyla eşleşecek şekilde geri taşınır. Döngünün büyüyen tensör defterini hızlandırıcıdan uzak tutmak için girdilerinizi CPU üzerinde iletin. Derlenmiş grafik kararlı kalır ve çıktı, girdi cihazını takip ettiği için, üretilen çıktı CPU üzerinde kalır.
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B", device_map="auto")
# leave the inputs on CPU instead of calling .to(model.device).
inputs = tokenizer("The French Bread Law states", return_tensors="pt")
# generate runs forward on the model device but returns the output on the input_ids device.
output = model.generate(**inputs, do_sample=False, max_new_tokens=20)
print(output.device)
cpuÖnbellek aktarımı
KV önbelleği belleğin önemli bir bölümünü işgal edebilir ve uzun bağlam üretimi için bir darboğaz haline gelebilir. Bellek verimli önbellekler, hızdan ödün vererek bellek kullanımını azaltmaya odaklanır. Bu, büyük dil modelleri (LLM) için ve donanımınız bellek kısıtlıysa özellikle önemlidir.
Önbelleğin taşınması, model katmanlarından birini hariç tutan KV önbelleğini CPU'ya taşıyarak GPU belleğini tasarruf eder. Modelin katmanlar üzerinde forward tekrarı sırasında GPU'da yalnızca geçerli katman önbelleği tutulur. Bir sonraki katmanın önbelleği asenkron olarak önceden getirilir ve dikkat (attention) hesabı tamamlandıktan sonra geçerli katmanın önbelleği CPU'ya geri gönderilir.
Küçük bir GPU'nuz varsa ve bellek yetersizliği (OOM) hataları alıyorsanız, offloading'i değerlendirmeniz gerekebilir.
Model ve üretim tercihlerinize (bağlam boyutu, üretilen token sayısı, beam sayısı vb.) bağlı olarak, tam cihaz içi önbelleğe kıyasla üretim verimliliğinde küçük bir düşüş fark edebilirsiniz. Bunun nedeni, anahtar/değer durumlarını ileri geri taşımak için bazı işlemlerin gerektirmesidir.
Offload, hem DynamicCache hem de StaticCache için kullanılabilir. Dinamik sürüm için cache_implementation="offloaded", statik sürüm için ise cache_implementation="offloaded_static" yapılandırmasını GenerationConfig veya generate() içinde etkinleştirebilirsiniz.
Ayrıca, offloading=True seçeneğiyle kendi DynamicCache veya StaticCache örneğinizi oluşturabilir ve bu önbelleği generate veya modelinizin forward fonksiyonuna (örneğin dinamik bir önbellek için past_key_values=DynamicCache(config=model.config, offloading=True)) iletebilirsiniz.
Yukarıda bahsedilen 2 Cache sınıfının doğrudan örneklenirken offload_only_non_sliding adlı ek bir seçeneğe sahip olduğunu unutmayın.
Bu ek argüman, kayan pencere/bölüm dikkati kullanan katmanların (varsa) da boşaltılıp boşaltılmayacağını belirler. Bu katmanlar zaten genellikle kısa olduğundan, boşaltma işlemi hız cezasına yol açabileceğinden onları boşaltmaktan kaçınmak daha iyi olabilir. Varsayılan olarak bu seçenek DynamicCache için False, StaticCache için ise True'dür.
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
ckpt = "microsoft/Phi-3-mini-4k-instruct"
tokenizer = AutoTokenizer.from_pretrained(ckpt)
model = AutoModelForCausalLM.from_pretrained(ckpt, dtype=torch.float16, device_map="auto")
inputs = tokenizer("Fun fact: The shortest", return_tensors="pt").to(model.device)
out = model.generate(**inputs, do_sample=False, max_new_tokens=23, cache_implementation="offloaded")
print(tokenizer.batch_decode(out, skip_special_tokens=True)[0])
Fun fact: The shortest war in history was between Britain and Zanzibar on August 27, 1896.Aşağıdaki örnek, bellek yetersiz kaldığında boşaltılmış bir önbelleğe geri dönebileceğinizi gösterir:
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
from accelerate import Accelerator
def resilient_generate(model, *args, **kwargs):
oom = False
device = Accelerator().device
torch_device_module = getattr(torch, device, torch.cuda)
try:
return model.generate(*args, **kwargs)
except torch.OutOfMemoryError as e:
print(e)
print("retrying with cache_implementation='offloaded'")
oom = True
if oom:
torch_device_module.empty_cache()
kwargs["cache_implementation"] = "offloaded"
return model.generate(*args, **kwargs)
ckpt = "microsoft/Phi-3-mini-4k-instruct"
tokenizer = AutoTokenizer.from_pretrained(ckpt)
model = AutoModelForCausalLM.from_pretrained(ckpt, dtype=torch.float16, device_map="auto")
prompt = ["okay "*1000 + "Fun fact: The most"]
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
beams = { "num_beams": 40, "num_return_sequences": 20, "max_new_tokens": 23, "early_stopping": True, }
out = resilient_generate(model, **inputs, **beams)
responses = tokenizer.batch_decode(out[:,-28:], skip_special_tokens=True)Örnekleştirilmiş önbellek
QuantizedCache, KV değerlerini daha düşük bir hassasiyete kuantizeleyerek bellek gereksinimlerini azaltır. QuantizedCache şu anda üç kuantizasyon altyapısını destekler:
hqq, int1, int2, int3, int4 ve int8 veri türlerini destekler.quanto, int2 ve int4 veri türlerini destekler. Bu, varsayılan kuantizasyon arka ucudur.fp8, KV değerlerini 8 bitlik kayan nokta (float8_e4m3fn) olarak saklar. Ek bir bağımlılık gerektirmez ve grup başına değil, tensör başına kuantizasyon yaptığındannbits,axis_key,axis_value,q_group_sizeveresidual_lengthparametrelerini reddeder.
Önbelleğin kuantize edilmesi, bağlam uzunluğu kısa ve önbellek kuantizasyonu etkinleştirilmeden üretim için yeterli GPU belleği mevcut olduğunda gecikmeyi olumsuz etkileyebilir. Bellek verimliliği ile gecikme arasında bir denge bulmaya çalışın.
QuantizedCache özelliğini etkinleştirmek için GenerationConfig içinde cache_implementation="quantized" değerini yapılandırın. Kuantizasyon arka ucu ve varsa ek kuantizasyon parametreleri, generate() fonksiyonuna iletilen cache_config sözlüğünde belirtilir. Bu ek parametreler için varsayılan değerleri kullanmanız önerilir; ancak bellek yetersizliği (out-of-memory) yaşıyorsanız, kalan uzunluğu (residual length) azaltmayı değerlendirebilirsiniz.
hqq arka ucu için axis_key ve axis_value parametrelerini 1 olarak ayarlamayı öneririz.
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", dtype=torch.float16, device_map="auto")
inputs = tokenizer("I like rock music because", return_tensors="pt").to(model.device)
out = model.generate(
**inputs,
do_sample=False,
max_new_tokens=20,
cache_implementation="quantized",
cache_config={
"nbits": 4,
"backend": "hqq",
"axis_key": 1,
"axis_value": 1
}
)
print(tokenizer.batch_decode(out, skip_special_tokens=True)[0])
I like rock music because it's loud and energetic. It's a great way to express myself and relquanto arka ucu için axis_key ve axis_value parametrelerini 0 olarak ayarlamayı öneririz.
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", dtype=torch.float16, device_map="auto")
inputs = tokenizer("I like rock music because", return_tensors="pt").to(model.device)
out = model.generate(
**inputs,
do_sample=False,
max_new_tokens=20,
cache_implementation="quantized",
cache_config={
"nbits": 4,
"backend": "quanto",
"axis_key": 0,
"axis_value": 0
}
)
print(tokenizer.batch_decode(out, skip_special_tokens=True)[0])
I like rock music because it's loud and energetic. It's a great way to express myself and relfp8 arka ucu ek bir parametre almaz ve grup bazlı parametrelerden biri verilirse hata fırlatır.
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-4B-Instruct-2507")
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-4B-Instruct-2507", dtype=torch.float16, device_map="auto")
inputs = tokenizer("I like rock music because", return_tensors="pt").to(model.device)
out = model.generate(**inputs, do_sample=False, max_new_tokens=20, cache_implementation="quantized", cache_config={"backend": "fp8"})
print(tokenizer.batch_decode(out, skip_special_tokens=True)[0])
I like rock music because it is powerful and emotional. I also like classical music because it is elegant and sophisticated. I enjoyEncoder-decoder önbelleği
EncoderDecoderCache, encoder-decoder modelleri için tasarlanmıştır. Hem self-attention hem de cross-attention önbelleklerini yöneterek önceki kv çiftlerinin depolanmasını ve alınmasını sağlar. Encoder ve decoder için ayrı ayrı farklı bir önbellek tipi ayarlanabilir.
Bu önbellek türü herhangi bir kurulum gerektirmez. Yukarıda açıklandığı gibi, model tarafından bağımsız olarak doğrudan kullanılacak 2 Cache etrafındaki basit bir sarmalayıcıdır.
Model-özel önbellekler
Bazı modellerin, diğer hiçbir önbellek sınıfıyla uyumlu olmayan, geçmiş kv çiftlerini veya durumları saklamak için benzersiz bir yöntemi vardır.
Mamba gibi Mamba modelleri, dikkat mekanizması veya kv durumları bulunmadığı için özel bir önbellek gerektirir. Bu nedenle, yukarıdaki Cache sınıflarıyla uyumlu değildir.
Yinelemeli üretim
Önbellek, bir modelle gidip gelen etkileşimin olduğu (sohbet botları) iteratif üretim ayarlarında da çalışabilir. Normal üretimde olduğu gibi, önbellekli iteratif üretim, bir modelin her adımda tüm bağlamı yeniden hesaplamadan devam eden konuşmaları verimli bir şekilde işlemesini sağlar.
Önbellek kullanılarak iteratif üretim için, önce boş bir önbellek sınıfı başlatın ve ardından yeni isteklerinizi girebilirsiniz. sohbet şablonu ile diyalog geçmişini takip edin.
Aşağıdaki örnek Llama-2-7b-chat-hf modelini göstermektedir. Farklı bir sohbet tarzı model kullanıyorsanız, apply_chat_template() mesajları farklı şekilde işleyebilir. Jinja şablonunun nasıl yazıldığına bağlı olarak önemli token'ları kesebilir. Çok modlu sohbet modelleri için görüntü veya ses işleme yöntemlerini öğrenmek üzere iterative chatting with cache kılavuzuna bakın.
Örneğin, bazı modeller akıl yürütme sırasında özel <think> ... </think> jetonlarını kullanır. Bu jetonlar yeniden kodlama sırasında kaybolabilir ve dizinleme sorunlarına yol açabilir. İşleri stabil tutmak için tamamlamalardan ek jetonları manuel olarak kaldırmak veya ayarlamak gerekebilir.
import torch
from transformers import AutoTokenizer,AutoModelForCausalLM, DynamicCache, StaticCache
model_id = "meta-llama/Llama-2-7b-chat-hf"
model = AutoModelForCausalLM.from_pretrained(model_id, dtype=torch.bfloat16, device_map='auto')
tokenizer = AutoTokenizer.from_pretrained(model_id)
user_prompts = ["Hello, what's your name?", "Btw, yesterday I was on a rock concert."]
past_key_values = DynamicCache(config=model.config)
messages = []
for prompt in user_prompts:
messages.append({"role": "user", "content": prompt})
inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt", return_dict=True).to(model.device)
input_length = inputs["input_ids"].shape[1]
outputs = model.generate(**inputs, do_sample=False, max_new_tokens=256, past_key_values=past_key_values)
completion = tokenizer.decode(outputs[0, input_length: ], skip_special_tokens=True)
messages.append({"role": "assistant", "content": completion})Önbelleği kırp
Örneğin, yinelemeli üretim sırasında bir aday devamı reddedildiğinde, önbellekten token'ları geri almak için crop() kullanın. Kaldırılacak token sayısını negatif bir tamsayı olarak iletin.
# Remove the last three tokens from the cache.
past_key_values.crop(-3)Sliding-window ve linear-attention katmanları ilerledikçe geçmiş durumları atar, bu nedenle varsayılan olarak geri dönülecek bir durum yoktur. Bu katmanların bu durumları tutmasını sağlamak için forward pass öncesinde activate_past_recording() çağrın. Bu çağrı yapılmadığında, sliding-window katmanı penceresini doldurduğunda crop bir RuntimeError fırlatır; linear-attention katmanları için ise bu hata anında oluşur.
# Enable this before the forward pass if you need to roll back tokens.
past_key_values.activate_past_recording()crop(0) önbelleği temizlemez. Önbelleğe alınmış diziden hiçbir token kaldırılmaz ve tam dikkat katmanları için hiçbir iş yapmaz. Kayan pencere ve doğrusal dikkat katmanları için, bir sonraki model çağrısında kullanılmayacak önbelleğe alınmış bilgileri atabilir. Bu, tokenleri geri almadan bellek kullanımını azaltır.
cached positions
┌───┬───┬───┬───┬───┬───┐
before crop(-3) │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │
└───┴───┴───┴───┴───┴───┘
╰─────┬─────╯
rolled back
after crop(-3)
┌───┬───┬───┐
full attention │ 0 │ 1 │ 2 │ keeps the whole prefix
└───┴───┴───┘
┌───┐
sliding_window=2 │ 2 │ keeps sliding_window - 1
└───┘Her iki katman artık 3 uzunluğunda bir dizi bildirir ve üretim 3. konumdan devam eder.
0 değeri geçirildiğinde diziden hiçbir token kaldırılmaz. Tam dikkat katmanları için bu bir no-op işlemidir; ancak kayan pencere ve doğrusal dikkat katmanlarında, bir sonraki ileri geçişte okunmayacak olan kayıtlı durumları yine de atar. Bu işlem hiçbir şeyi geri almadan bellek serbest bırakır.
Önbellek doldurun (önek önbellekleme)
Bazı durumlarda, belirli bir önek istemci için bir Cache nesnesini kv çiftleriyle doldurup farklı diziler üretmek için yeniden kullanmak isteyebilirsiniz.
Aşağıdaki örnek bir StaticCache başlatır ve ardından bir başlangıç istemini önbelleğe alır. Artık önceden doldurulmuş istemden birden fazla dizi üretebilirsiniz.
import copy
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, DynamicCache, StaticCache
model_id = "meta-llama/Llama-2-7b-chat-hf"
model = AutoModelForCausalLM.from_pretrained(model_id, dtype=torch.bfloat16, device_map={"": 0})
tokenizer = AutoTokenizer.from_pretrained(model_id)
# Init StaticCache with big enough max-length (1024 tokens for the below example)
# You can also init a DynamicCache, if that suits you better
prompt_cache = StaticCache(config=model.config, max_cache_len=1024)
INITIAL_PROMPT = "You are a helpful assistant. "
inputs_initial_prompt = tokenizer(INITIAL_PROMPT, return_tensors="pt").to(model.device.type)
# This is the common prompt cached, we need to run forward without grad to be able to copy
with torch.no_grad():
prompt_cache = model(**inputs_initial_prompt, past_key_values = prompt_cache).past_key_values
prompts = ["Help me to write a blogpost about travelling.", "What is the capital of France?"]
responses = []
for prompt in prompts:
new_inputs = tokenizer(INITIAL_PROMPT + prompt, return_tensors="pt").to(model.device.type)
past_key_values = copy.deepcopy(prompt_cache)
outputs = model.generate(**new_inputs, past_key_values=past_key_values,max_new_tokens=20)
response = tokenizer.batch_decode(outputs)[0]
responses.append(response)
print(responses)