Tüm rehberler
RehberYapay Zeka04 · Inference

LLM Inference
& Quantization.

Modeli küçült, hızlandır, yayınla. GGUF/GGML format, llama.cpp ile CPU inference, Ollama ile lokal sunucu. AWQ ve GPTQ farkları, KV cache ve Flash Attention optimizasyonları.

00 Çıkarım Zorluğu

LLM inference neden bu kadar pahalı ve quantization neden kaçınılmaz bir çözüm haline geldi.

Bir large language model çalıştırmak, her token üretimi için modelin tüm ağırlık matrislerinin bellekte hazır bulunmasını gerektirir. Üstelik bu ağırlıklar her forward pass'te sıfırdan yeniden okunur — hesaplama yapmadan önce RAM/VRAM'den çekilmesi gereken devasa bir veri yüküdür bu.

7 milyar parametreli bir model varsayalım. Her parametre float32 (32 bit = 4 byte) ile saklanıyorsa:

01 7,000,000,000 parametre × 4 byte = 28 GB VRAM
02 float16 (2 byte) → 14 GB VRAM
03 int8 (1 byte)   →  7 GB VRAM
04 int4 (0.5 byte) →  3.5 GB VRAM

Tüketici GPU'larının büyük çoğunluğu 8–24 GB arası VRAM'e sahipken, 70B modeller float32'de 280 GB gerektirir. Quantization bu uçurumu kapatmanın temel yöntemidir.

Throughput ve Latency

Inference performansını değerlendirirken iki metrik kritiktir. Throughput, saniyede üretilen token sayısıdır (tok/s) ve toplu iş yüklerinde önemlidir. Latency (veya time-to-first-token, TTFT), kullanıcının ilk token'ı ne kadar sürede aldığıdır — etkileşimli uygulamalarda baskın metriktir.

Model Parametre FP32 VRAM FP16 VRAM INT4 VRAM Tipik Donanım
Llama-3.1 8B8B32 GB16 GB4.5 GBRTX 3060 (12 GB)
Llama-3.1 70B70B280 GB140 GB40 GB2× A100 80GB
Mistral 7B7B28 GB14 GB4 GBRTX 3070 (8 GB)
Mixtral 8×7B47B aktif: 13B94 GB47 GB26 GB2× RTX 3090
Phi-3 Mini3.8B15 GB7.6 GB2.2 GBLaptop GPU
NOT

VRAM hesaplarına ek olarak KV cache bellek maliyetini de eklemeniz gerekir. Uzun context window'larda (32k, 128k token) KV cache, model ağırlıklarından daha fazla yer kaplayabilir.

01 Quantization Temelleri

Ağırlıkları daha az bit ile temsil etmenin matematiksel temeli ve her düzeyin kalite-boyut değiş tokuşu.

Quantization, bir sürekli değer aralığını daha az bit ile temsil etme işlemidir. Sinir ağlarında ağırlıklar ve/veya aktivasyonlar bu şekilde sıkıştırılır.

Bit Genişliği Hiyerarşisi

FP32 32 bit — IEEE 754 tam kayan nokta, eğitim standardı
FP16 16 bit — yarı hassasiyet, GPU'larda hızlı, mixed precision
BF16 16 bit — Brain Float, FP32 ile aynı üs aralığı, TPU/A100
INT8  8 bit — tam sayı, ~2× sıkıştırma, hafif kalite kaybı
INT4  4 bit — ~4× sıkıştırma, dikkatli seçim gerektirir
INT2  2 bit — deneysel, kalite ciddi biçimde düşer

Symmetric ve Asymmetric Quantization

Symmetric quantization'da sıfır noktası (zero-point) 0'a sabitlenir ve değer aralığı [-max, +max] şeklinde simetrik tutulur. Hesaplama daha basittir. Asymmetric quantization'da ise zero-point serbest bir değer alır; bu durum sıfır merkezli olmayan dağılımlar (örn. ReLU çıktıları) için daha az hata üretir.

Her iki durumda da iki parametre kullanılır:

scale (s)Gerçek değer ile tam sayı temsili arasındaki ölçek faktörü: x_real = s × x_int
zero_point (z)Sıfırı karşılayan tam sayı değeri; asymmetric'te sıfır değildir
quantization_math.py
import numpy as np

def quantize_asymmetric(x: np.ndarray, n_bits: int = 8):
    """Asimetrik quantization: scale + zero_point hesapla."""
    x_min, x_max = x.min(), x.max()
    q_min, q_max = 0, 2**n_bits - 1      # int8: 0..255

    scale = (x_max - x_min) / (q_max - q_min)
    zero_point = round(q_min - x_min / scale)
    zero_point = int(np.clip(zero_point, q_min, q_max))

    x_q = np.clip(np.round(x / scale + zero_point), q_min, q_max).astype(np.uint8)
    return x_q, scale, zero_point

def dequantize(x_q: np.ndarray, scale: float, zero_point: int):
    """Quantize edilmiş değeri geri float'a çevir."""
    return scale * (x_q.astype(np.float32) - zero_point)

# Örnek kullanım
weights = np.random.randn(1000).astype(np.float32)
w_q, s, z = quantize_asymmetric(weights)
w_reconstructed = dequantize(w_q, s, z)

error = np.abs(weights - w_reconstructed).mean()
print(f"Ortalama mutlak hata: {error:.6f}")  # ~0.001

PTQ ve QAT

Post-Training Quantization (PTQ), eğitilmiş modeli tekrar eğitmeden quantize eder — hızlı ve pratiktir ancak kalite kaybı daha yüksek olabilir. Quantization-Aware Training (QAT), eğitim sırasında simüle edilmiş quantization uygular; model bu gürültüye adapte olur ve sonuç kalitesi çok daha yüksektir, ancak eğitim maliyeti artar.

YöntemBitPerplexity ArtışıVRAM TasarrufuHız
FP32 (baseline)32
FP1616~0%50%1.5–2×
INT8 (PTQ)8<1%75%2–3×
INT4 GPTQ42–5%87.5%3–4×
INT4 AWQ41–3%87.5%3–4×
INT22>20%93.75%

02 GPTQ — Gradient Tabanlı PTQ

Hessian matrisini kullanarak katman katman hassas quantization yapan GPTQ yöntemi ve AutoGPTQ kütüphanesi.

GPTQ (Generative Pre-trained Transformer Quantization), 2022'de Frantar ve ark. tarafından önerilmiştir. Temel fikir şudur: bir katmanın ağırlıklarını quantize ederken, kalan ağırlıkları bu hatayı telafi edecek şekilde güncelle. Bu güncelleme için Hessian matrisi (ikinci türev bilgisi) kullanılır.

Algoritma Özeti

01 Kalibrasyon verisi ile her katmanın Hessian'ını hesapla
02 Bir lineer katmanı al: W ∈ R^{d_out × d_in}
03 Sütunları soldan sağa quantize et (OBQ algoritması)
04 Her sütun quantize edildikten sonra Cholesky güncelleme
05 Kalan sütunlar hatayı absorbe edecek şekilde güncellenir
06 group_size=128: 128 ağırlık için ortak scale

Group Quantization

Tüm katman için tek bir scale faktörü kullanmak yerine, group_size parametresi ile her 128 ağırlık grubu kendi scale'ine sahip olur. Bu, kaliteyi önemli ölçüde artırır (daha küçük grup = daha iyi kalite, ama daha fazla overhead).

gptq_inference.py
# pip install auto-gptq transformers accelerate
from auto_gptq import AutoGPTQForCausalLM
from transformers import AutoTokenizer

model_name = "TheBloke/Llama-2-7B-GPTQ"

tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoGPTQForCausalLM.from_quantized(
    model_name,
    use_safetensors=True,
    device="cuda:0",
    inject_fused_attention=False,
    bits=4,
    group_size=128,
)

prompt = "Yapay zeka nedir?"
inputs = tokenizer(prompt, return_tensors="pt").to("cuda:0")

output = model.generate(
    **inputs,
    max_new_tokens=200,
    temperature=0.7,
    do_sample=True,
)
print(tokenizer.decode(output[0], skip_special_tokens=True))

GPTQ ile Kendi Modelini Quantize Etmek

gptq_quantize.py
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
from transformers import AutoTokenizer
import torch

pretrained_model_name = "meta-llama/Llama-3.1-8B"
quantized_model_dir = "./llama-3.1-8b-gptq-4bit"

# Quantization konfigürasyonu
quantize_config = BaseQuantizeConfig(
    bits=4,           # 4-bit quantization
    group_size=128,   # 128 ağırlık başına bir scale
    desc_act=False,   # activation ordering (kaliteyi artırır ama yavaşlatır)
)

tokenizer = AutoTokenizer.from_pretrained(pretrained_model_name)
model = AutoGPTQForCausalLM.from_pretrained(
    pretrained_model_name, quantize_config
)

# Kalibrasyon verisi — model kalibrasyon için bu örneklere bakacak
examples = [
    tokenizer("Transformer mimarisi attention mekanizmasını kullanır.",
              return_tensors="pt"),
    tokenizer("Python programlama dili veri biliminde yaygın kullanılır.",
              return_tensors="pt"),
    # ... daha fazla örnek ekleyin (~128 öneri)
]

model.quantize(examples)
model.save_quantized(quantized_model_dir, use_safetensors=True)
tokenizer.save_pretrained(quantized_model_dir)
print(f"Model kaydedildi: {quantized_model_dir}")
NOT

Kalibrasyon verisi kalitesi GPTQ sonuçlarını doğrudan etkiler. Modelin kullanılacağı domain'den örnekler seçin; genel web metni yerine görev-spesifik veri daha iyi sonuç verir.

03 AWQ — Activation-Aware Quantization

Aktivasyon istatistiklerini kullanarak önemli ağırlıkları koruyan AWQ, genellikle GPTQ'ya göre daha iyi kalite sunar.

AWQ (Activation-Aware Weight Quantization), 2023'te Lin ve ark. tarafından önerilmiştir. Gözlem şudur: tüm ağırlıklar eşit önemde değildir. Bazı ağırlık kanallarına karşılık gelen aktivasyonlar çok büyük değerler alır — bu ağırlıkları 4 bit'e düşürmek orantısız hata üretir.

AWQ bu kritik kanalları tespit edip, onlara özgün ölçekleme faktörleri uygular. Bu sayede hassas kanallar korunurken diğerleri agresif quantization'a tabi tutulur.

GPTQ ile Karşılaştırma

ÖzellikGPTQAWQ
KalibrasyonHessian (yavaş)Aktivasyon istatistikleri (hızlı)
Kalite (INT4)İyiGenellikle daha iyi
Quantization hızıYavaş (saatler)Hızlı (dakikalar)
Hardware supportCUDA, CPUCUDA, Metal, CPU
Popüler HF modellerTheBloke/*-GPTQTheBloke/*-AWQ
group_sizeAyarlanabilirVarsayılan 128
awq_inference.py
# pip install autoawq transformers
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

model_name = "TheBloke/Llama-2-7B-AWQ"

tokenizer = AutoTokenizer.from_pretrained(
    model_name, trust_remote_code=True
)
model = AutoAWQForCausalLM.from_quantized(
    model_name,
    fuse_layers=True,      # kernel fusion → daha hızlı inference
    trust_remote_code=True,
    safetensors=True,
)

# Basit metin üretimi
prompt = "[INST] Makine öğrenmesini kısaca açıkla. [/INST]"
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")

with torch.no_grad():
    outputs = model.generate(
        **inputs,
        max_new_tokens=256,
        do_sample=True,
        temperature=0.8,
        top_p=0.95,
    )

response = tokenizer.decode(
    outputs[0][inputs["input_ids"].shape[1]:],
    skip_special_tokens=True
)
print(response)

Kendi Modelini AWQ ile Quantize Etmek

awq_quantize.py
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

model_path = "meta-llama/Llama-3.1-8B-Instruct"
quant_path = "./llama-3.1-8b-awq"

quant_config = {
    "zero_point": True,   # asymmetric quantization
    "q_group_size": 128,
    "w_bit": 4,
    "version": "GEMM",     # GEMM veya GEMV (düşük batch için GEMV)
}

model = AutoAWQForCausalLM.from_pretrained(
    model_path, low_cpu_mem_usage=True
)
tokenizer = AutoTokenizer.from_pretrained(
    model_path, trust_remote_code=True
)

model.quantize(tokenizer, quant_config=quant_config)
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)

04 GGUF/GGML Format

llama.cpp'nin kullandığı GGUF formatı, tek dosyada model metadata ve ağırlıkları birleştirir; CPU inference için optimize edilmiştir.

GGUF (GPT-Generated Unified Format), Georgi Gerganov tarafından geliştirilmiş ve llama.cpp ekosisteminin temel dosya formatıdır. Önceki GGML formatının yerini almıştır. GGUF, model metadata'sını (tokenizer, hiper parametreler, quantization konfigürasyonu) ve ağırlıkları tek bir dosyada saklar.

GGUF Quantization Tipleri

TipBit/Ağırlık7B Dosya BoyutuKaliteÖneri
Q2_K~2.5 bit~2.7 GBDüşükYalnızca bellek çok kısıtlıysa
Q3_K_M~3.3 bit~3.5 GBOrta-düşükÇok kısıtlı sistem
Q4_K_M~4.5 bit~4.8 GBİyiGenel kullanım için tavsiye
Q5_K_M~5.5 bit~5.7 GBÇok iyiKalite/boyut dengesi
Q6_K~6.6 bit~6.1 GBMükemmele yakınYüksek kalite gerektiriyorsa
Q8_08 bit~7.7 GBNeredeyse kayıpsızVRAM yeterliyse
F1616 bit~14 GBKayıpsızGeliştirme/test

İsimlerdeki K harfi k-quant (karma bit derinliği) anlamına gelir: bazı katmanlar daha yüksek bit ile korunur. M "medium" yani orta büyüklük demektir (S = small, L = large da mevcuttur).

HuggingFace Hub'dan GGUF İndirmek

download_gguf.sh
# pip install huggingface_hub
huggingface-cli download \
    TheBloke/Llama-2-7B-Chat-GGUF \
    llama-2-7b-chat.Q4_K_M.gguf \
    --local-dir ./models \
    --local-dir-use-symlinks False
download_gguf.py
from huggingface_hub import hf_hub_download

model_path = hf_hub_download(
    repo_id="bartowski/Llama-3.2-3B-Instruct-GGUF",
    filename="Llama-3.2-3B-Instruct-Q4_K_M.gguf",
    local_dir="./models",
)
print(f"İndirildi: {model_path}")
NOT

HuggingFace Hub'da GGUF modelleri genellikle TheBloke, bartowski veya lmstudio-community organizasyonları tarafından yayınlanmaktadır. Orijinal model adına -GGUF ekleyerek arama yapabilirsiniz.

05 llama.cpp ile CPU Inference

Saf C/C++ ile yazılmış llama.cpp, tüketici donanımlarında LLM inference için en verimli CPU çözümüdür.

llama.cpp, Georgi Gerganov tarafından geliştirilmiş, bağımlılık gerektirmeyen saf C/C++ LLM inference motorudur. CPU inference için SIMD optimizasyonları (AVX2, AVX-512, ARM NEON) içerir; aynı zamanda CUDA, Metal, OpenCL ve Vulkan backend'lerini destekler.

Derleme ve Kurulum

build.sh
# Kaynak kodu indir
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp

# CPU-only derleme
cmake -B build
cmake --build build --config Release -j $(nproc)

# CUDA ile derleme
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release -j $(nproc)

# macOS Metal ile derleme
cmake -B build -DGGML_METAL=ON
cmake --build build --config Release -j $(nproc)

Komut Satırı Inference

llama_cli.sh
# Tek seferlik sorgu
./build/bin/llama-cli \
    -m ./models/llama-3.2-3b-q4_k_m.gguf \
    -p "Transformer mimarisi nedir?" \
    -n 200 \      # max token sayısı
    --threads 8   # CPU thread sayısı

# İnteraktif sohbet modu
./build/bin/llama-cli \
    -m ./models/llama-3.2-3b-q4_k_m.gguf \
    -i \               # interactive mode
    -c 4096 \         # context window
    --threads 8 \
    --temp 0.7 \      # temperature
    --top-p 0.9 \    # nucleus sampling
    --top-k 40       # top-k sampling

Python Binding ile Kullanım

llama_python.py
# pip install llama-cpp-python
# CUDA: CMAKE_ARGS="-DGGML_CUDA=on" pip install llama-cpp-python
from llama_cpp import Llama

llm = Llama(
    model_path="./models/llama-3.2-3b-q4_k_m.gguf",
    n_ctx=4096,         # context window uzunluğu
    n_threads=8,        # CPU thread sayısı (fiziksel çekirdek)
    n_gpu_layers=0,     # GPU'ya yüklenen katman: 0=CPU-only, -1=tümü
    verbose=False,
)

# Basit tamamlama
output = llm(
    "Makine öğrenmesi nedir? Kısaca açıkla:",
    max_tokens=256,
    temperature=0.7,
    top_p=0.9,
    top_k=40,
    stop=["\n\n", "###"],
    echo=False,
)
print(output["choices"][0]["text"])

# Chat completion (OpenAI uyumlu)
response = llm.create_chat_completion(
    messages=[
        {"role": "system", "content": "Sen yardımcı bir asistansın."},
        {"role": "user", "content": "Türkiye'nin başkenti neresidir?"},
    ],
    temperature=0.1,
    max_tokens=128,
)
print(response["choices"][0]["message"]["content"])
n_ctxBağlam penceresi uzunluğu (token sayısı). Büyük değerler daha fazla RAM kullanır.
n_threadsKullanılacak CPU thread sayısı. Hyperthreading hariç fiziksel çekirdek sayısına eşit tutun.
n_gpu_layersGPU'ya offload edilecek katman sayısı. -1 tüm katmanları GPU'ya yükler.
temperatureÖrnekleme sıcaklığı. 0 = deterministik, 1 = çeşitli. Genellikle 0.1–0.9 arası.
top_pNucleus sampling: olasılık toplamı bu eşiği geçen en küçük token kümesinden örnekle.
top_kYalnızca en yüksek k olasılıklı token'dan örnekle. top_p ile birlikte kullanılabilir.

GPU Offloading

GPU'nuz modelin tamamını barındırmaya yetmiyorsa hibrit mod kullanabilirsiniz: bir kısım katmanı GPU'ya, kalanı CPU'ya yükleyin. n_gpu_layers=20 gibi bir değer deneyerek VRAM'i ne kadar doldurduğunu gözlemleyin.

hybrid_offload.py
llm = Llama(
    model_path="./models/llama-3.1-8b-q4_k_m.gguf",
    n_ctx=2048,
    n_threads=6,
    n_gpu_layers=20,   # 20 katman GPU'ya (RTX 3060 8GB için uygun)
    n_batch=512,        # prompt işleme batch boyutu
)

06 Ollama — Lokal Model Sunucusu

Ollama, LLM modellerini Docker benzeri bir deneyimle indirip çalıştırmanı sağlayan lokal model yönetim platformudur.

Ollama, llama.cpp üzerine inşa edilmiş bir model sunucu ve yönetim aracıdır. Docker'ın imaj sistemi gibi, modelleri "pull" ederek indirip "run" ile başlatırsınız. Otomatik GPU/CPU algılama, model versiyon yönetimi ve REST API ile hem geliştirme hem üretim için uygundur.

Kurulum ve Temel Komutlar

ollama_cli.sh
# Linux/macOS kurulumu
curl -fsSL https://ollama.com/install.sh | sh

# Model indir ve çalıştır
ollama pull llama3.2
ollama run llama3.2

# Diğer faydalı komutlar
ollama list                   # indirilen modelleri listele
ollama show llama3.2          # model bilgilerini göster
ollama rm llama3.2             # modeli sil
ollama ps                     # çalışan modelleri listele
ollama serve                  # sunucuyu manuel başlat (genelde otomatik)

REST API

Ollama varsayılan olarak http://localhost:11434 adresinde bir REST API sunar. OpenAI uyumlu endpoint'ler de mevcuttur.

ollama_api.sh
# Generate endpoint
curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Yapay zeka nedir?",
  "stream": false
}'

# Chat endpoint (OpenAI uyumlu)
curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama3.2",
    "messages": [{"role": "user", "content": "Merhaba!"}]
  }'

Modelfile ile Özel Model Tanımı

Modelfile
# Temel model
FROM llama3.2

# Sistem prompt'u
SYSTEM """Sen Türkçe konuşan, yardımsever bir teknik asistansın.
Cevaplarında her zaman kod örnekleri ver ve açık bir dil kullan."""

# Parametreler
PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER top_k 40
PARAMETER num_ctx 4096

# Sohbet şablonu (opsiyonel)
TEMPLATE """<|system|>
<|end|>
<|user|>
<|end|>
<|assistant|>
<|end|>"""
create_model.sh
# Modelfile'dan özel model oluştur
ollama create teknik-asistan -f ./Modelfile
ollama run teknik-asistan

Python ile Ollama API

ollama_python.py
# pip install ollama
import ollama

# Basit sorgu
response = ollama.chat(
    model="llama3.2",
    messages=[
        {"role": "user", "content": "Python'da decorators ne işe yarar?"}
    ]
)
print(response["message"]["content"])

# Streaming yanıt
for chunk in ollama.chat(
    model="llama3.2",
    messages=[{"role": "user", "content": "Fibonacci serisini açıkla"}],
    stream=True,
):
    print(chunk["message"]["content"], end="", flush=True)

# OpenAI uyumlu istemci ile
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama",   # herhangi bir değer olabilir
)

response = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Merhaba!"}],
)
print(response.choices[0].message.content)

07 KV Cache ve Flash Attention

Inference verimliliğini dramatik biçimde artıran iki temel optimizasyon: KV cache ve IO-aware Flash Attention.

KV Cache Nedir?

Transformer'ın attention mekanizması, her token için Key ve Value matrislerini hesaplar. Autoregressive üretimde (bir seferde bir token üretme), önceki token'ların K ve V değerleri değişmez — bunları yeniden hesaplamak gereksiz iştir. KV cache, bu değerleri bellekte saklayarak her adımda yalnızca yeni token'ın K/V'sini hesaplar.

KV cache olmadan: Her token üretiminde tüm geçmiş token'lar için K,V hesapla → O(n²) maliyet
KV cache ile:   Yalnızca yeni token K,V hesapla, önbellekten oku → O(n) maliyet

Ancak KV cache bellek maliyeti yüksektir: bir 7B model için 2048 token context window'da birkaç GB yer kaplayabilir.

PagedAttention (vLLM)

PagedAttention, işletim sistemlerinin sanal bellek sayfalama konseptini KV cache'e uygular. Cache bloklara (page) ayrılır; bu sayede bellek fragmantasyonu önlenir ve farklı uzunluktaki istek grupları daha verimli işlenir.

Flash Attention

Standart attention hesaplaması büyük ara matrisleri HBM (yüksek bant genişlikli bellek, GPU'nun ana VRAM'i) üzerine yazar ve geri okur. Flash Attention, tüm attention hesaplamasını SRAM (on-chip, çok hızlı ama küçük) üzerinde gerçekleştirir; HBM okuma/yazma sayısını dramatik biçimde azaltır.

Standart: Q,K,V → HBM'e yaz → S=QK^T okuyup yaz → P=softmax(S) yaz → O=PV yaz
Flash:    Q,K,V → küçük bloklar halinde SRAM'e al → hepsini SRAM'de hesapla → tek seferde HBM'e yaz
flash_attention.py
# pip install flash-attn --no-build-isolation
# (CUDA 11.8+ ve PyTorch 2.0+ gerektirir)
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model_name = "meta-llama/Llama-3.1-8B-Instruct"

# Flash Attention 2 ile model yükle
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    attn_implementation="flash_attention_2",   # anahtar parametre
    device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# Bellek kullanımını karşılaştır
def measure_memory(model, prompt, max_new_tokens=100):
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    torch.cuda.reset_peak_memory_stats()
    _ = model.generate(**inputs, max_new_tokens=max_new_tokens)
    peak_mem = torch.cuda.max_memory_allocated() / 1e9
    return peak_mem

mem = measure_memory(model, "Transformer nedir?")
print(f"Peak memory (Flash Attn 2): {mem:.2f} GB")
DİKKAT

Flash Attention 2 yalnızca CUDA GPU'larında çalışır ve derlenmiş bir C++ uzantısı gerektirir. Kurulum için CUDA toolkit'in sisteminizde yüklü olması şarttır. CPU ya da Metal backend kullanıyorsanız bu parametreyi kaldırın.

08 vLLM ile Production Serving

PagedAttention ve continuous batching ile yüksek throughput LLM servisini sağlayan vLLM, üretim ortamlarının tercihi.

vLLM, UC Berkeley'den araştırmacılar tarafından geliştirilen yüksek performanslı LLM inference ve serving motorudur. Temel inovasyonu olan PagedAttention, KV cache kullanımını 2–4× daha verimli hale getirir; continuous batching ise gelen istekleri dinamik olarak gruplayarak GPU'yu meşgul tutar.

Kurulum ve Sunucu Başlatma

vllm_server.sh
# pip install vllm
# OpenAI uyumlu API sunucusu başlat
python -m vllm.entrypoints.openai.api_server \
    --model meta-llama/Llama-3.1-8B-Instruct \
    --dtype bfloat16 \
    --max-model-len 8192 \
    --tensor-parallel-size 1 \      # GPU sayısı
    --gpu-memory-utilization 0.90 \ # VRAM kullanım oranı
    --port 8000

Python Client

vllm_client.py
from openai import OpenAI

# vLLM OpenAI uyumlu endpoint
client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="vllm",
)

response = client.chat.completions.create(
    model="meta-llama/Llama-3.1-8B-Instruct",
    messages=[
        {"role": "system", "content": "Sen yardımcı bir asistansın."},
        {"role": "user", "content": "Attention mekanizmasını açıkla."},
    ],
    max_tokens=512,
    temperature=0.7,
)
print(response.choices[0].message.content)

# Toplu istek örneği (throughput testi)
import time

prompts = [
    "Python nedir?",
    "Makine öğrenmesi nedir?",
    "Transformer ne anlama gelir?",
    "GPU neden AI için önemlidir?",
]

start = time.time()
responses = []
for p in prompts:
    r = client.chat.completions.create(
        model="meta-llama/Llama-3.1-8B-Instruct",
        messages=[{"role": "user", "content": p}],
        max_tokens=128,
    )
    responses.append(r)

elapsed = time.time() - start
total_tokens = sum(r.usage.completion_tokens for r in responses)
print(f"Toplam: {total_tokens} token | Süre: {elapsed:.2f}s | Throughput: {total_tokens/elapsed:.1f} tok/s")

Tensor Parallelism

Birden fazla GPU'ya sahipseniz --tensor-parallel-size ile model ağırlıklarını GPU'lara dağıtabilirsiniz. 70B gibi büyük modeller için 4× veya 8× GPU gerekebilir.

Throughput Karşılaştırması

MotorDonanımThroughput (tok/s)Latency (TTFT)Notlar
HuggingFace (vanilla)A100 80GB~40–60~800msbatch_size=1, FP16
vLLMA100 80GB~150–250~200mscontinuous batching, PagedAttn
llama.cpp (CPU)32-core CPU~15–25~2sQ4_K_M, 8 thread
llama.cpp (GPU)RTX 4090~80–120~300msQ4_K_M, tam GPU offload
OllamaRTX 4090~70–100~350msllama.cpp backend
NOT

Throughput değerleri, model boyutuna, batch size'a, prompt uzunluğuna ve donanım konfigürasyonuna göre önemli ölçüde değişir. Bu değerler Llama 3.1 8B için yaklaşık referans değerlerdir.