00 NLP Neden LLM Değil? — Hız, Maliyet, Yorumlanabilirlik
GPT-4 her NLP görevi için ideal değildir. Gecikme, maliyet ve gizlilik kısıtları çoğu zaman daha küçük, özelleşmiş modelleri zorunlu kılar.
LLM'ler olağanüstü yetenekler sunar ama gerçek dünya sistemlerinde kritik dezavantajları vardır. Gecikme: GPT-4 API çağrısı ortalama 2-10 saniye sürerken spaCy pipeline 1 milisaniyenin altında sonuç döner — müşteri hizmetleri otomasyonunda bu fark kabul edilemez. Maliyet: 1 milyon token işlemek GPT-4 ile ~$10 maliyetliyken spaCy yerel çalışır ve sıfır marginal maliyet taşır. Gizlilik: tıbbi veya hukuki belgeler harici API'ye gönderilemez; GDPR ve KVKK uyumluluğu yerel modeli zorunlu kılar. Determinizm: LLM çıktısı stokastiktir; NER ve sınıflandırma için %100 tekrar üretilebilirlik kritiktir.
Hangi durumda LLM yerine spaCy? Etiketlenmiş veriye sahipseniz ve görev tanımlıysa (NER, sınıflandırma, bağımlılık ayrıştırma), spaCy her zaman daha hızlı ve ucuz olacaktır. LLM sadece sıfır çekimli (zero-shot) senaryolar, yaratıcı metin üretimi veya çok adımlı akıl yürütme gerektiren görevler için vazgeçilmezdir.
| Kriter | GPT-4 API | spaCy (CPU) | spaCy + Transformer |
|---|---|---|---|
| Gecikme (belge) | 2–10 s | <1 ms | 10–50 ms |
| Maliyet (1M token) | ~$10 | ~$0 (yerel) | ~$0 (yerel) |
| Özelleştirme | Zor (fine-tune) | Kolay (etiket + eğit) | Kolay |
| Yorumlanabilirlik | Düşük | Yüksek | Orta |
| Gizlilik | Dış API | Yerel | Yerel |
"LLM mi spaCy mi?" sorusunun cevabı veriye bağlıdır. 500+ etiketlenmiş örnek varsa spaCy fine-tune edin. Sıfır örnek varsa LLM ile birkaç haftalık veri toplayın, ardından spaCy'ye geçin — hem hız hem maliyet optimize edilir.
01 spaCy Pipeline Mimarisi — Tokenizer, Tagger, Parser, NER
spaCy, modüler bileşen zinciri (pipe) ile metin işler; her bileşen Doc nesnesini zenginleştirir ve bağımsız olarak devre dışı bırakılabilir.
spaCy'nin temel soyutlaması Doc nesnesidir: tokenlar, span'lar ve onlara bağlı her türlü linguistik anotasyon bu nesnede yaşar. Pipeline, sırayla çalışan bileşenler zinciridir. Hazır modeller (en_core_web_sm/md/lg/trf) şunları içerir: tokenizer (kurallara dayalı, dil-bağımlı, exception'larla zenginleştirilmiş), tagger (part-of-speech), morphologizer, parser (bağımlılık ağacı), ner (adlandırılmış varlık tanıma), senter (cümle sınırı tespiti). Tok2Vec veya Transformer katmanı paylaşımlı temsil üretir; üstteki görev başlıkları (task heads) bu temsili kullanır.
import spacy
from spacy.language import Language
# ── Model yükleme ────────────────────────────────────────────
nlp = spacy.load("tr_core_news_lg")
print(nlp.pipe_names)
# ['tok2vec', 'morphologizer', 'parser', 'ner', 'attribute_ruler', 'lemmatizer']
print(nlp.meta["name"], nlp.meta["version"])
# ── Tek belge işleme ─────────────────────────────────────────
doc = nlp("Ankara'daki TBMM dün gece toplandı.")
for token in doc:
print(f"{token.text:15s} POS={token.pos_:8s} DEP={token.dep_:10s} LEMMA={token.lemma_}")
for ent in doc.ents:
print(f"ENT: {ent.text!r:30s} [{ent.start_char}:{ent.end_char}] LABEL={ent.label_}")
# ── Batch işleme (nlp.pipe) ──────────────────────────────────
texts = ["Birinci metin burada.", "İkinci metin de burada."] * 500
docs = list(nlp.pipe(texts, batch_size=64, n_process=4))
# ── Seçici bileşen çalıştırma ─────────────────────────────────
# Parser ve NER atla — sadece tokenization + POS
doc_fast = nlp(text, disable=["parser", "ner"])
# ── Özel bileşen ekleme ──────────────────────────────────────
@Language.component("domain_normalizer")
def domain_normalizer(doc):
"""Alanına özel normalizasyon."""
for token in doc:
if token.text.lower() in {"tbmm", "meclis"}:
token.ent_type_ = "ORG"
return doc
nlp.add_pipe("domain_normalizer", last=True)
# ── Pipeline bilgisi ─────────────────────────────────────────
for name, component in nlp.pipeline:
print(f"{name:20s} {type(component).__name__}")
02 Custom NER — Training Data Formatı, DocBin, Model Eğitimi
spaCy v3'te NER eğitimi config tabanlıdır; DocBin ikili formatı büyük veri setlerini verimli saklar ve eğitim tekrar üretilebilirliği sağlar.
spaCy v3, spacy train CLI komutu ve config.cfg dosyasıyla tüm hiperparametreleri yönetir. Eğitim verisi önce Example nesnelerine, ardından DocBin ikili formatına dönüştürülür — JSON veya JSONL yerine DocBin %10-50 daha az disk ve bellek kullanır. Annotation formatı: her metin için karakter offset başlangıç/bitiş çifti ve etiket listesi. Örtüşen entity'lere izin verilmez; bunun için SpanCategorizer kullanılır.
import spacy, random, json
from spacy.tokens import DocBin
from spacy.training import Example
# ── Annotation formatı ───────────────────────────────────────
TRAIN_DATA = [
("Fatih Aras şirketi terk etti.", {"entities": [(0, 10, "KISI")]}),
("Turkcell yeni ürün lansmanı yaptı.", {"entities": [(0, 8, "SIRKET")]}),
("Ankara'da büyük fırtına yaşandı.", {"entities": [(0, 6, "LOKASYON")]}),
("Arçelik Almanya'ya ihracat yaptı.", {"entities": [(0, 6, "SIRKET"),
(7, 14, "LOKASYON")]}),
]
# ── DocBin oluşturma ─────────────────────────────────────────
nlp_blank = spacy.blank("tr")
def make_docbin(data, output_path):
db = DocBin()
skipped = 0
for text, annotations in data:
doc = nlp_blank.make_doc(text)
ents = []
for start, end, label in annotations["entities"]:
span = doc.char_span(start, end, label=label,
alignment_mode="contract")
if span is None:
skipped += 1
else:
ents.append(span)
doc.ents = ents
db.add(doc)
print(f"Oluşturuldu: {len(data)} belge, {skipped} span atlandı")
db.to_disk(output_path)
random.shuffle(TRAIN_DATA)
split = int(len(TRAIN_DATA) * 0.8)
make_docbin(TRAIN_DATA[:split], "corpus/train.spacy")
make_docbin(TRAIN_DATA[split:], "corpus/dev.spacy")
# ── Config oluştur (terminal) ────────────────────────────────
# python -m spacy init config configs/config.cfg \
# --lang tr --pipeline ner --optimize efficiency
# ── Eğitim (terminal) ────────────────────────────────────────
# python -m spacy train configs/config.cfg \
# --output training/ \
# --paths.train corpus/train.spacy \
# --paths.dev corpus/dev.spacy \
# --gpu-id 0
# ── Değerlendirme ────────────────────────────────────────────
nlp_ner = spacy.load("training/model-best")
from spacy.scorer import Scorer
scorer = Scorer()
examples = []
for text, annots in TRAIN_DATA[split:]:
pred = nlp_ner(text)
ref = nlp_blank.make_doc(text)
ents = [ref.char_span(s, e, l) for s, e, l in annots["entities"]]
ref.ents = [e for e in ents if e]
examples.append(Example(pred, ref))
scores = scorer.score(examples)
print(f"NER F1={scores['ents_f']:.3f} P={scores['ents_p']:.3f} R={scores['ents_r']:.3f}")
Az veriyle başlıyorsanız (100-500 örnek), bir transformer tabanlı modeli başlangıç noktası alın ve sadece NER katmanını ince ayar yapın: config'de initialize.vectors alanını doldurarak transfer learning uygulayın. Sıfırdan eğitmeye göre 5-10 kat daha az veri gerektirir.
03 Metin Sınıflandırma — TextCategorizer & BERT Distil
spaCy TextCategorizer basit CNN'den transformer tabanlı BERT'e kadar tek veya çok etiketli sınıflandırma sunar; hız/doğruluk dengesi config ile ayarlanır.
TextCategorizer iki modda çalışır: exclusive_classes (tek etiket, softmax çıkış) ve multilabel (çok etiket, sigmoid çıkış). Mimari seçeneği config'de belirlenir: bow (Bag of Words, çok hızlı, baseline), simple_cnn, ensemble (bow + cnn), veya transformer tabanlı. spacy-transformers paketi ile DistilBERT veya herhangi bir HuggingFace modeli entegre edilebilir; bu durum genellikle doğruluğu %5-15 artırır ama gecikmeyi 20-50x artırır.
import spacy
from spacy.tokens import DocBin
import random
# ── Veri formatı: cats dict ───────────────────────────────────
REVIEWS = [
("Ürün çok kaliteliydi, tekrar alırım.", {"POSITIVE": 1.0, "NEGATIVE": 0.0}),
("Kargo geç geldi, memnun değilim.", {"POSITIVE": 0.0, "NEGATIVE": 1.0}),
("Fiyat için idare eder.", {"POSITIVE": 0.3, "NEGATIVE": 0.7}),
("Harika bir ürün, kesinlikle tavsiye ederim!", {"POSITIVE": 1.0, "NEGATIVE": 0.0}),
]
# ── DocBin oluşturma ─────────────────────────────────────────
nlp_blank = spacy.blank("tr")
def cats_to_docbin(data, path):
db = DocBin()
for text, cats in data:
doc = nlp_blank.make_doc(text)
doc.cats = cats
db.add(doc)
db.to_disk(path)
random.shuffle(REVIEWS)
split = int(len(REVIEWS) * 0.8)
cats_to_docbin(REVIEWS[:split], "textcat_train.spacy")
cats_to_docbin(REVIEWS[split:], "textcat_dev.spacy")
# ── Config: DistilBERT entegrasyonu ──────────────────────────
# configs/textcat_trf.cfg:
# [components.transformer]
# factory = "transformer"
# [components.transformer.model]
# @architectures = "spacy-transformers.TransformerModel.v3"
# name = "dbmdz/distilbert-base-turkish-cased"
# [components.textcat]
# factory = "textcat"
# [components.textcat.model]
# @architectures = "spacy-transformers.TextCatWithReducer.v1"
# ── Tahmin ───────────────────────────────────────────────────
nlp_cat = spacy.load("./output_textcat/model-best")
reviews = ["Çok güzel.", "Berbat ürün.", "Fiyat performans iyi."]
for doc in nlp_cat.pipe(reviews, batch_size=32):
label = max(doc.cats, key=doc.cats.get)
print(f"{doc.text!r:35s} → {label} ({doc.cats[label]:.2f})")
# ── Sınıflandırma raporu ─────────────────────────────────────
from sklearn.metrics import classification_report
y_true, y_pred = [], []
for doc in nlp_cat.pipe([r[0] for r in REVIEWS[split:]]):
pred_label = max(doc.cats, key=doc.cats.get)
y_pred.append(pred_label)
y_true = [max(r[1], key=r[1].get) for r in REVIEWS[split:]]
print(classification_report(y_true, y_pred))
04 Bilgi Çıkarımı — Relation Extraction & Coreference
NER'in ötesinde varlıklar arasındaki ilişkileri ve zamir referanslarını tespit etmek bilgi grafiği oluşturmak için kritiktir.
Relation Extraction (RE), iki entity arasındaki anlamsal ilişkiyi sınıflandırır: "Apple, Tim Cook'u CEO olarak atadı" → (Apple, ÜST_YÖNETİCİ, Tim Cook). spaCy doğrudan bir RE bileşeni sunmasa da özel bileşen veya bağımlılık ağacından kural tabanlı çıkarım yapılabilir. Coreference Resolution, "Ahmet markete gitti. O çok yorgundu" cümlesinde "O" → "Ahmet" eşlemesi yapar; coreferee kütüphanesi Türkçe dahil birçok dili destekler.
import spacy
nlp = spacy.load("tr_core_news_lg")
# ── Bağımlılık tabanlı ilişki çıkarımı ──────────────────────
def extract_kisi_sirket(doc):
"""Kişi-Şirket ilişkisini bağımlılık ağacından çıkar."""
relations = []
for ent in doc.ents:
if ent.label_ == "PER":
head = ent.root.head
for other in doc.ents:
if other.label_ in ("ORG", "SIRKET"):
if other.root == head or other.root.head == head:
relations.append({
"subject": ent.text,
"relation": head.lemma_,
"object": other.text,
})
return relations
doc = nlp("Turkcell CEO'su Murat Erkan yeni stratejiyi açıkladı.")
for r in extract_kisi_sirket(doc):
print(r)
# ── Coreferee kurulumu ───────────────────────────────────────
# pip install coreferee
# python -m coreferee install tr
import coreferee
nlp_coref = spacy.load("tr_core_news_lg")
nlp_coref.add_pipe("coreferee")
doc2 = nlp_coref(
"Mehmet dün önemli bir toplantıya gitti. O çok hazırlıklıydı ve başarılı oldu."
)
for chain in doc2._.coref_chains:
tokens = [doc2[m[0]] for m in chain]
print("Referans zinciri:", [t.text for t in tokens])
# ── Bilgi grafiği oluşturma ──────────────────────────────────
import networkx as nx
G = nx.DiGraph()
texts = ["Arçelik İstanbul'da üretim yapıyor.",
"Koç Holding Arçelik'e sahiptir."]
for doc in nlp.pipe(texts):
for ent in doc.ents:
G.add_node(ent.text, label=ent.label_)
for rel in extract_kisi_sirket(doc):
G.add_edge(rel["subject"], rel["object"],
relation=rel["relation"])
print(f"Düğüm: {G.number_of_nodes()}, Kenar: {G.number_of_edges()}")
05 Dependency Parsing — token.head, token.dep_, displaCy
Bağımlılık ağacı cümledeki sözdizimsel ilişkileri temsil eder ve kural tabanlı bilgi çıkarımı için güçlü bir yapı sağlar.
Dependency parsing her tokena bir kök (head) ve bir ilişki etiketi (dep_) atar. Cümledeki asıl fiil genellikle ROOT olur. Temel Türkçe bağımlılık etiketleri: nsubj (özne), obj (nesne), obl (dolaylı nesne/edat öbeği), advmod (zarf belirteci), amod (sıfat belirteci). token.subtree özelliği, bir tokenın tüm bağımlı alt ağacına erişim sağlar.
import spacy
from spacy import displacy
nlp = spacy.load("tr_core_news_lg")
doc = nlp("Mehmet dün İstanbul'da önemli bir toplantıya katıldı.")
# ── Token bağımlılıkları ─────────────────────────────────────
for t in doc:
print(
f"{t.text:15s}"
f" HEAD={t.head.text:15s}"
f" DEP={t.dep_:12s}"
f" POS={t.pos_}"
)
# ── Konu-Yüklem-Nesne çıkarımı ───────────────────────────────
def extract_svo(doc):
"""ROOT fiiline bağlı özne ve nesne çiftlerini bul."""
svos = []
for token in doc:
if token.dep_ == "ROOT":
subj = None
obj = None
for child in token.children:
if "subj" in child.dep_:
subj = " ".join(t.text for t in child.subtree())
elif "obj" in child.dep_:
obj = " ".join(t.text for t in child.subtree())
svos.append({"subj": subj, "verb": token.lemma_, "obj": obj})
return svos
print(extract_svo(doc))
# ── displaCy görselleştirme ──────────────────────────────────
html = displacy.render(doc, style="dep", jupyter=False,
options={"compact": True, "distance": 100})
with open("dep_tree.html", "w", encoding="utf-8") as f:
f.write(html)
# ── Cümle bölütleme ─────────────────────────────────────────
doc_multi = nlp("İlk cümle burada bitti. İkincisi başladı. Üçüncüsü de var.")
for i, sent in enumerate(doc_multi.sents, 1):
print(f"Cümle {i}: {sent.text!r}")
06 Kural Tabanlı NLP — Matcher, PhraseMatcher, EntityRuler
Makine öğrenmesi yetersiz kaldığında kural tabanlı desenler — özellikle ürün kodları, ilaç adları, yasal terimler — çok daha güvenilirdir ve sıfır eğitim verisi gerektirir.
Matcher, token seviyesinde desen eşleştirme yapar; POS, morfoloji, lemma, metin ve regex kriterlerini birleştirebilir. PhraseMatcher, büyük sözlüklerle çalışırken Matcher'dan 10-100x daha hızlıdır; kümeleştirilmiş hash tablosu kullanır. EntityRuler, eşleşen desenleri doğrudan entity olarak işaretler; NER modelinden önce veya sonra pipeline'a eklenebilir. Önce kural, sonra ML mantığı genellikle en iyi sonucu verir.
import spacy
from spacy.matcher import Matcher, PhraseMatcher
from spacy.pipeline import EntityRuler
nlp = spacy.load("tr_core_news_lg")
# ── Matcher: token desenleri ─────────────────────────────────
matcher = Matcher(nlp.vocab)
# Şirket adı + hukuki form
pattern_sirket = [
{"POS": "PROPN", "OP": "+"},
{"TEXT": {"REGEX": r"(A\.Ş\.|Ltd\.|Inc\.|GmbH)"}}
]
# TL/para miktarı
pattern_para = [
{"LIKE_NUM": True},
{"TEXT": {"IN": ["TL", "₺", "USD", "EUR", "$"]}}
]
matcher.add("SIRKET_PATTERN", [pattern_sirket])
matcher.add("PARA", [pattern_para])
doc = nlp("Acme A.Ş. 5.000 TL yatırım aldı.")
for match_id, start, end in matcher(doc):
print(f"{nlp.vocab.strings[match_id]}: {doc[start:end].text!r}")
# ── PhraseMatcher: büyük sözlük ──────────────────────────────
phrase_matcher = PhraseMatcher(nlp.vocab, attr="LOWER")
ilaç_listesi = ["parol", "aspirin", "ibuprofen", "amoksisilin"]
phrase_matcher.add("İLAÇ", [nlp.make_doc(t) for t in ilaç_listesi])
doc2 = nlp("Doktor Parol ve Ibuprofen yazdı.")
for match_id, s, e in phrase_matcher(doc2):
print(f"İlaç tespit: {doc2[s:e].text}")
# ── EntityRuler: kurallı entity ──────────────────────────────
ruler = nlp.add_pipe("entity_ruler", before="ner")
ruler.add_patterns([
{"label": "URUN_KODU",
"pattern": [{"TEXT": {"REGEX": r"[A-Z]{2}-\d{4,6}"}}]},
{"label": "MARKA", "pattern": "Apple"},
{"label": "MARKA", "pattern": "Samsung"},
{"label": "MARKA", "pattern": "Arçelik"},
])
doc3 = nlp("TS-123456 kodlu Apple ürünü piyasaya çıktı.")
for ent in doc3.ents:
print(f"{ent.text!r}: {ent.label_}")
07 spaCy Projeleri & Prodigy
spaCy Projects, konfigürasyon tabanlı ML pipeline yönetimi sunar; Prodigy aktif öğrenme destekli annotation aracıdır ve her ikisi de ekip üretkenliğini büyük ölçüde artırır.
spaCy Projects (project.yml), bir NLP projesindeki tüm adımları (veri hazırlama, eğitim, değerlendirme, paketleme) açıkça tanımlar ve tekrar üretilebilirliği garantiler. spacy project run train komutu bağımlılıkları kontrol eder, yalnızca değişen adımları yeniden çalıştırır. Prodigy, Explosion'ın ticari annotation aracıdır: aktif öğrenme ile modelin en emin olmadığı örnekleri önce gösterir, böylece aynı bütçeyle daha iyi model elde edilir.
title: "Türkçe Haber NER"
description: "Kişi, şirket ve lokasyon çıkarımı"
vars:
lang: "tr"
train: "corpus/train.spacy"
dev: "corpus/dev.spacy"
directories: ["assets", "corpus", "configs", "training", "metrics"]
commands:
- name: "convert"
help: "Ham JSONL → DocBin"
script:
- "python scripts/convert.py assets/data.jsonl corpus/"
deps: ["assets/data.jsonl"]
outputs: ["corpus/train.spacy", "corpus/dev.spacy"]
- name: "train"
help: "Model eğit"
script:
- "python -m spacy train configs/config.cfg --output training/ --paths.train ${vars.train} --paths.dev ${vars.dev}"
deps: ["configs/config.cfg", "${vars.train}", "${vars.dev}"]
outputs: ["training/model-best"]
- name: "evaluate"
help: "Dev seti değerlendirme"
script:
- "python -m spacy evaluate training/model-best ${vars.dev} --output metrics/scores.json"
deps: ["training/model-best", "${vars.dev}"]
outputs: ["metrics/scores.json"]
- name: "package"
help: "Pip paketi oluştur"
script:
- "python -m spacy package training/model-best packages/ --name tr_haber_ner --version 1.0.0"
# Prodigy aktif öğrenme NER döngüsü
# 1. Mevcut modelle tahmin yap, annotator düzeltir
prodigy ner.correct haber_ner tr_core_news_lg \
assets/haberler.jsonl --label KISI,SIRKET,LOKASYON
# 2. Onaylananlarla modeli güncelle
prodigy train ./models/v1 haber_ner --lang tr --component ner \
--n-iter 10
# 3. Güncel modelle tekrar → çevrim döngüsü
prodigy ner.correct haber_ner_v2 ./models/v1/model-best \
assets/yeni_haberler.jsonl --label KISI,SIRKET,LOKASYON
# 4. Birden fazla annotator — anlaşmazlıkları analiz et
prodigy review haber_ner_reviewed haber_ner --view-id ner
08 Üretim İçin Optimizasyon — batch_size, n_process, GPU
Yüksek throughput için spaCy'nin paralel işleme ve GPU desteğinden maksimum fayda sağlanmalıdır; ihtiyaç duyulmayan bileşenlerin devre dışı bırakılması önemli kazanım sağlar.
Üretimdeki kritik performans kararları: batch_size — nlp.pipe(texts, batch_size=512) ile belge grupları işlenirken CPU cache kullanımı optimize edilir. n_process — çok işlemcili CPU için; IPC overhead nedeniyle çok fazla artırmak ters etki yaratır, genellikle 4-8 optimaldır. disable — ihtiyaç duyulmayan bileşenler devre dışı bırakılmalıdır. GPU için spacy[cuda12x] kurulumu ve transformer modelleri büyük batch'lerde dramatik hızlanma sağlar.
import spacy, time
# ── Gereksiz bileşenleri kapat ───────────────────────────────
nlp_full = spacy.load("tr_core_news_lg")
nlp_ner = spacy.load("tr_core_news_lg",
disable=["parser", "senter"])
texts = ["Büyük haber metni burada."] * 10_000
# ── Benchmark karşılaştırması ────────────────────────────────
for label, model, kw in [
("tam pipeline, n_process=1", nlp_full, {"batch_size": 64}),
("ner only, n_process=1", nlp_ner, {"batch_size": 512}),
("ner only, n_process=4", nlp_ner, {"batch_size": 512, "n_process": 4}),
]:
t0 = time.perf_counter()
docs = list(model.pipe(texts, **kw))
dt = time.perf_counter() - t0
print(f"{label}: {dt:.1f}s ({len(texts)/dt:.0f} doc/s)")
# ── GPU kullanımı ────────────────────────────────────────────
# pip install spacy[cuda12x]
if spacy.prefer_gpu():
print("GPU aktif")
# ── DocBin ile araç arası veri paylaşımı ─────────────────────
from spacy.tokens import DocBin
db = DocBin(attrs=["ENT_TYPE", "ENT_IOB", "LEMMA"])
for doc in nlp_ner.pipe(texts[:100], batch_size=64):
db.add(doc)
db.to_disk("processed.spacy")
# Yükle — NLP tekrar çalıştırmadan
db2 = DocBin().from_disk("processed.spacy")
for doc in db2.get_docs(nlp_ner.vocab):
_ = doc.ents # hazır, hesaplama yok
09 spaCy vs Transformers — Ne Zaman Hangisi?
Her araç belirli senaryolar için optimize edilmiştir; doğru seçim görevin doğasına, veri büyüklüğüne ve gecikme kısıtlarına bağlıdır.
spaCy, yapısal NLP görevleri için tasarlanmıştır: tokenization, POS tagging, dependency parsing, NER, text classification. Hafızası düşük, hızlı ve üretim için optimize edilmiştir. Hugging Face Transformers ise dil anlama görevleri için: soru yanıtlama, metin üretimi, semantik benzerlik, zero-shot sınıflandırma. spacy-transformers paketi transformer embedding'i spaCy pipeline'ına entegre eder — her iki dünyanın avantajı tek çatı altında toplanır.
| Görev | spaCy | Transformers | Öneri |
|---|---|---|---|
| NER (etiketli veri var) | Çok iyi | İyi | spaCy |
| Metin sınıflandırma | İyi (hızlı) | Çok iyi | Gecikme → spaCy; doğruluk → BERT |
| Soru yanıtlama | Zayıf | Çok iyi | Transformers |
| Dependency parsing | Çok iyi | Zayıf | spaCy |
| Semantik benzerlik | Orta | Çok iyi | Sentence-Transformers |
| Batch NER (1M belge) | Çok iyi | Yavaş | spaCy (n_process) |
| Zero-shot sınıflandırma | Yok | Çok iyi | Transformers |
Üretim sisteminde katmanlı mimari kullanın: ilk geçişte hızlı spaCy pipeline ile yapısal analiz (NER, bağımlılık), ardından yalnızca belirsiz veya kritik belgeler transformer modeline gönderilir. Bu yaklaşım hem hız hem doğruluk açısından optimal dengeyi sağlar ve infra maliyetini %60-80 düşürebilir.