Türkçe Duygu Analizi Modeli: Hugging Face ile Adım Adım

Makine öğrenmesi modellerini üretim ortamında çalıştırmak, birkaç yıl öncesine kadar ciddi bir altyapı bilgisi gerektiriyordu. Bugün ise Hugging Face sayesinde önceden eğitilmiş modelleri birkaç satır Python koduyla çalıştırabiliyoruz. Bu yazıda, Türkçe metin üzerinde duygu analizi yapan bir sistem kuracağız. Müşteri yorumları, sosyal medya gönderileri veya destek talepleri gibi gerçek dünya verilerini otomatik olarak sınıflandırmak istiyorsanız tam yerindesiniz.

Ortam Hazırlığı ve Gereksinimler

Öncelikle neye ihtiyacımız olduğunu netleştirelim. Bir Python ortamı, Hugging Face kütüphaneleri ve tercihen bir GPU olması işleri hızlandırır ama CPU ile de gayet kullanılabilir sonuçlar alırsınız.

Sistem gereksinimlerimiz şunlar:

  • Python 3.8+: Transformers kütüphanesi eski Python sürümlerini desteklemiyor
  • RAM: Minimum 4GB, 8GB önerilen
  • Disk: Model dosyaları için 1-2GB boş alan
  • GPU (opsiyonel): CUDA destekli NVIDIA kartı işleri 10-20x hızlandırır

Önce sanal ortamımızı oluşturalım. Ben her proje için ayrı bir virtual environment kullanmayı kesinlikle öneriyorum, yoksa paket çakışmaları sizi çıldırtır.

# Sanal ortam oluştur
python3 -m venv turkce-duygu-env

# Aktifleştir (Linux/Mac)
source turkce-duygu-env/bin/activate

# Aktifleştir (Windows)
turkce-duygu-envScriptsactivate

# Pip'i güncelle
pip install --upgrade pip

Şimdi gerekli paketleri kuralım:

# Temel kütüphaneler
pip install transformers torch

# Hugging Face Hub erişimi için
pip install hugging-face-hub

# Veri işleme için
pip install pandas numpy

# API olarak sunmak istiyorsanız
pip install fastapi uvicorn

# Kurulumu doğrula
python -c "import transformers; print(transformers.__version__)"

Eğer GPU kullanacaksanız, torch kurulumunu CUDA versiyonunuza göre ayarlamanız gerekiyor. Hangi CUDA sürümüne sahip olduğunuzu nvidia-smi komutuyla öğrenebilirsiniz.

# CUDA 11.8 için
pip install torch --index-url https://download.pytorch.org/whl/cu118

# CUDA 12.1 için
pip install torch --index-url https://download.pytorch.org/whl/cu121

# GPU'nun görünüp görünmediğini kontrol et
python -c "import torch; print('GPU mevcut:', torch.cuda.is_available())"

Türkçe Model Seçimi

Hugging Face Hub’da binlerce model var ama Türkçe için hepsi uygun değil. Türkçe duygu analizi için birkaç iyi seçenek mevcut. Ben bu yazıda savasy/bert-base-turkish-sentiment-cased modelini kullanacağım. Bu model Türkçe BERT mimarisi üzerine duygu analizi için ince ayar yapılmış (fine-tuned) bir model.

Alternatif modeller arasında şunlar var:

  • saribasmetehan/bert-base-turkish-sentiment-analysis: Daha büyük bir dataset ile eğitilmiş
  • VRLLab/TurkishBERTweet-Lora-SA: Twitter verisi üzerinde özelleştirilmiş
  • dbmdz/bert-base-turkish-cased: Temel Türkçe BERT, ince ayar yapmak isteyenler için

Model seçimi yaparken dikkat etmeniz gereken faktörler:

  • Model kartını okuyun: Hangi veri setiyle eğitilmiş, hangi metrikler elde edilmiş?
  • Download sayısı: Popüler modeller genellikle daha iyi test edilmiştir
  • Son güncelleme tarihi: Eski modeller güncel kütüphanelerle uyumsuz olabilir
  • Etiket şeması: “positive/negative” mi, yoksa 1-5 yıldız gibi çok sınıflı mı?

İlk Model İndirme ve Test

Model indirme işlemi ilk çalıştırmada otomatik gerçekleşiyor. Hugging Face bu dosyaları ~/.cache/huggingface/ dizinine kaydediyor. Disk alanı kısıtlıysa bu dizini önceden kontrol edin.

# test_model.py
from transformers import pipeline, AutoTokenizer, AutoModelForSequenceClassification

print("Model yükleniyor, ilk seferinde birkaç dakika sürebilir...")

# En basit kullanım: pipeline ile
classifier = pipeline(
    "text-classification",
    model="savasy/bert-base-turkish-sentiment-cased",
    tokenizer="savasy/bert-base-turkish-sentiment-cased"
)

# Basit test
test_metinler = [
    "Bu ürün harika, çok memnun kaldım!",
    "Berbat bir deneyimdi, kesinlikle tavsiye etmiyorum.",
    "Fiyatına göre idare eder."
]

for metin in test_metinler:
    sonuc = classifier(metin)
    print(f"Metin: {metin}")
    print(f"Sonuç: {sonuc[0]['label']} (Güven: {sonuc[0]['score']:.3f})")
    print("-" * 50)

Bu kodu çalıştırdığınızda model dosyaları indirilecek ve ilk tahminlerinizi göreceksiniz. Model bir kere indirildiğinde tekrar çalıştırmalarda önbellekten yükleniyor.

Tokenizer’ı Anlamak

Pipeline her şeyi bizden soyutluyor ama gerçek dünyada çoğu zaman daha fazla kontrole ihtiyaç duyarsınız. Tokenizer nasıl çalışıyor, hangi parametreler nereyi etkiliyor, bunu anlamak kritik önem taşıyor.

# tokenizer_demo.py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("savasy/bert-base-turkish-sentiment-cased")

metin = "Bu telefon gerçekten çok iyi, pilinin uzun ömürlü olması en sevdiğim özellik."

# Tokenizasyon işlemi
tokenlar = tokenizer(
    metin,
    padding=True,          # Kısa metinleri doldur
    truncation=True,       # Uzun metinleri kes
    max_length=512,        # BERT'in maksimum token sınırı
    return_tensors="pt"    # PyTorch tensörü döndür
)

print("Token ID'leri:", tokenlar['input_ids'])
print("Attention Mask:", tokenlar['attention_mask'])
print("Token sayısı:", tokenlar['input_ids'].shape[1])

# Tokenları kelimeye çevir
token_listesi = tokenizer.convert_ids_to_tokens(tokenlar['input_ids'][0])
print("nTokenlar:", token_listesi)

Dikkat etmeniz gereken önemli bir nokta: BERT modelleri maksimum 512 token destekler. Uzun müşteri yorumları veya metinler bu sınırı aşabilir. truncation=True parametresi bu sorunu otomatik çözüyor ama metnin sonunu kesiyor, bu da bazı durumlarda anlam kaybına yol açabilir.

Toplu İşlem ve Performans

Gerçek dünyada tek tek metin değil, binlerce metin işleyeceğiniz için toplu işlem (batch processing) öğrenmek şart. Toplu işlem hem belleği daha verimli kullanıyor hem de GPU’dan tam anlamıyla yararlanmanızı sağlıyor.

# batch_processing.py
import pandas as pd
from transformers import pipeline
import time

# Örnek müşteri yorumları dataseti
yorumlar = [
    "Ürün çok kaliteli, paketleme de süperdi.",
    "Kargo çok geç geldi, içinden çıktığı ambalaj ezilmişti.",
    "Fiyat performans açısından gayet iyi.",
    "Kesinlikle tavsiye etmiyorum, para tuzağı.",
    "Rengi fotoğraftaki gibi değil ama yine de beğendim.",
    "Müşteri hizmetleri çok ilgisiz, sorunum çözülmedi.",
    "Harika ürün, tekrar alacağım kesinlikle.",
    "Kalitesi fiyatını karşılamıyor maalesef.",
    "Hızlı kargo, sağlam paketleme, ürün beklentimi karşıladı.",
    "İade etmek istedim, süreci çok zorlaştırdılar."
]

# Pipeline oluştur
classifier = pipeline(
    "text-classification",
    model="savasy/bert-base-turkish-sentiment-cased",
    device=0 if __import__('torch').cuda.is_available() else -1
)

# Tek tek işleme (yavaş)
baslangic = time.time()
tekli_sonuclar = [classifier(yorum)[0] for yorum in yorumlar]
tekli_sure = time.time() - baslangic

# Toplu işleme (hızlı)
baslangic = time.time()
toplu_sonuclar = classifier(yorumlar, batch_size=8)
toplu_sure = time.time() - baslangic

print(f"Tekli işleme süresi: {tekli_sure:.2f} saniye")
print(f"Toplu işleme süresi: {toplu_sure:.2f} saniye")
print(f"Hızlanma: {tekli_sure/toplu_sure:.1f}x")

# Sonuçları DataFrame'e aktar
df = pd.DataFrame({
    'yorum': yorumlar,
    'duygu': [s['label'] for s in toplu_sonuclar],
    'guven_skoru': [round(s['score'], 4) for s in toplu_sonuclar]
})

print("n--- Analiz Sonuçları ---")
print(df.to_string(index=False))
print(f"nPositive: {len(df[df['duygu']=='positive'])}")
print(f"Negative: {len(df[df['duygu']=='negative'])}")

REST API Olarak Sunmak

Duygu analizi modelini sadece script olarak çalıştırmak yerine bir API servisi haline getirmek çok daha kullanışlı. Bu sayede diğer uygulamalarınız bu servisi kullanabilir. FastAPI ile bunu yapmak oldukça basit.

# api_server.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from transformers import pipeline
import torch
from typing import List
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI(
    title="Türkçe Duygu Analizi API",
    description="Türkçe metinler için duygu analizi servisi",
    version="1.0.0"
)

# Model global olarak yükle (her request'te yükleme çok yavaş)
logger.info("Model yükleniyor...")
classifier = pipeline(
    "text-classification",
    model="savasy/bert-base-turkish-sentiment-cased",
    device=0 if torch.cuda.is_available() else -1
)
logger.info("Model hazır!")

class TextInput(BaseModel):
    metin: str
    
class BatchInput(BaseModel):
    metinler: List[str]

class SentimentResult(BaseModel):
    metin: str
    duygu: str
    guven: float
    pozitif_mi: bool

@app.get("/health")
async def health_check():
    return {"status": "healthy", "gpu": torch.cuda.is_available()}

@app.post("/analiz", response_model=SentimentResult)
async def tek_metin_analiz(input_data: TextInput):
    if len(input_data.metin.strip()) < 3:
        raise HTTPException(status_code=400, detail="Metin çok kısa")
    
    sonuc = classifier(input_data.metin)[0]
    return SentimentResult(
        metin=input_data.metin,
        duygu=sonuc['label'],
        guven=round(sonuc['score'], 4),
        pozitif_mi=sonuc['label'].lower() == 'positive'
    )

@app.post("/toplu-analiz")
async def toplu_analiz(input_data: BatchInput):
    if len(input_data.metinler) > 100:
        raise HTTPException(status_code=400, detail="Maksimum 100 metin gönderilebilir")
    
    sonuclar = classifier(input_data.metinler, batch_size=16)
    
    return {
        "toplam": len(input_data.metinler),
        "pozitif_sayisi": sum(1 for s in sonuclar if s['label'].lower() == 'positive'),
        "negatif_sayisi": sum(1 for s in sonuclar if s['label'].lower() == 'negative'),
        "sonuclar": [
            {
                "metin": metin,
                "duygu": sonuc['label'],
                "guven": round(sonuc['score'], 4)
            }
            for metin, sonuc in zip(input_data.metinler, sonuclar)
        ]
    }

API’yi başlatmak için:

# Geliştirme modunda çalıştır
uvicorn api_server:app --host 0.0.0.0 --port 8000 --reload

# Üretim modunda (birden fazla worker ile)
uvicorn api_server:app --host 0.0.0.0 --port 8000 --workers 2

# API'yi test et
curl -X POST "http://localhost:8000/analiz" 
  -H "Content-Type: application/json" 
  -d '{"metin": "Bu ürün gerçekten harika!"}'

# Sağlık kontrolü
curl http://localhost:8000/health

API dokümantasyonuna http://localhost:8000/docs adresinden erişebilirsiniz. FastAPI bunu otomatik olarak oluşturuyor.

Gerçek Dünya Senaryosu: E-Ticaret Yorum Analizi

Teorik örnekler yeterli, şimdi gerçek bir senaryo yapalım. Diyelim ki bir e-ticaret platformundasınız ve CSV formatında müşteri yorumlarınız var. Bu yorumları toplu analiz edip ürün bazında duygu skoru çıkarmak istiyorsunuz.

# eticaret_analiz.py
import pandas as pd
import numpy as np
from transformers import pipeline
import torch
import json
from datetime import datetime

def duygu_analiz_sistemi(csv_dosyasi: str, cikti_dosyasi: str):
    """
    E-ticaret yorumlarını toplu analiz eder
    CSV formatı: urun_id, urun_adi, yorum, tarih
    """
    
    print(f"Veri yükleniyor: {csv_dosyasi}")
    df = pd.read_csv(csv_dosyasi, encoding='utf-8')
    print(f"Toplam yorum sayısı: {len(df)}")
    
    # Model yükle
    device = 0 if torch.cuda.is_available() else -1
    classifier = pipeline(
        "text-classification",
        model="savasy/bert-base-turkish-sentiment-cased",
        device=device,
        batch_size=32
    )
    
    # Boş ve çok kısa yorumları filtrele
    df = df.dropna(subset=['yorum'])
    df = df[df['yorum'].str.len() >= 10]
    print(f"Filtreleme sonrası yorum sayısı: {len(df)}")
    
    # Toplu analiz
    print("Duygu analizi yapılıyor...")
    yorumlar = df['yorum'].tolist()
    sonuclar = classifier(yorumlar, truncation=True, max_length=512)
    
    # Sonuçları DataFrame'e ekle
    df['duygu'] = [s['label'] for s in sonuclar]
    df['guven_skoru'] = [round(s['score'], 4) for s in sonuclar]
    df['pozitif_mi'] = df['duygu'].str.lower() == 'positive'
    
    # Ürün bazında özet
    urun_ozeti = df.groupby('urun_id').agg(
        urun_adi=('urun_adi', 'first'),
        toplam_yorum=('yorum', 'count'),
        pozitif_yorum=('pozitif_mi', 'sum'),
        ortalama_guven=('guven_skoru', 'mean')
    ).reset_index()
    
    urun_ozeti['pozitif_oran'] = (
        urun_ozeti['pozitif_yorum'] / urun_ozeti['toplam_yorum'] * 100
    ).round(1)
    
    # Riskli ürünleri belirle (negatif oran yüksek olanlar)
    riskli_urunler = urun_ozeti[urun_ozeti['pozitif_oran'] < 40]
    
    # Rapor oluştur
    rapor = {
        "analiz_tarihi": datetime.now().isoformat(),
        "toplam_yorum": len(df),
        "genel_pozitif_oran": round(df['pozitif_mi'].mean() * 100, 1),
        "riskli_urun_sayisi": len(riskli_urunler),
        "riskli_urunler": riskli_urunler['urun_adi'].tolist()
    }
    
    print("n--- Analiz Raporu ---")
    print(f"Toplam yorum: {rapor['toplam_yorum']}")
    print(f"Genel pozitif oran: %{rapor['genel_pozitif_oran']}")
    print(f"Dikkat gerektiren ürün: {rapor['riskli_urun_sayisi']}")
    
    # Sonuçları kaydet
    df.to_csv(cikti_dosyasi, index=False, encoding='utf-8')
    
    with open(cikti_dosyasi.replace('.csv', '_rapor.json'), 'w', encoding='utf-8') as f:
        json.dump(rapor, f, ensure_ascii=False, indent=2)
    
    print(f"nSonuçlar kaydedildi: {cikti_dosyasi}")
    return df, urun_ozeti

# Örnek kullanım
if __name__ == "__main__":
    df, ozet = duygu_analiz_sistemi("yorumlar.csv", "analiz_sonuclari.csv")

Model Önbellekleme ve Yönetimi

Sunucu ortamında model yönetimi önemli bir konu. Modeller büyük dosyalar ve her seferinde internetten indirmek istemiyorsunuz. Özellikle CI/CD pipeline’larında bu kritik.

# Hugging Face CLI ile model indir ve yerel kaydet
pip install huggingface_hub

# Modeli yerel dizine indir
python -c "
from huggingface_hub import snapshot_download
snapshot_download(
    repo_id='savasy/bert-base-turkish-sentiment-cased',
    local_dir='/opt/modeller/turkce-duygu',
    local_dir_use_symlinks=False
)
print('Model indirildi!')
"

# Yerel modeli kullan (internet bağlantısı gerektirmez)
python -c "
from transformers import pipeline
classifier = pipeline(
    'text-classification',
    model='/opt/modeller/turkce-duygu'
)
print(classifier('Harika bir ürün!'))
"

# Önbellek dizinini değiştir (varsayılan: ~/.cache/huggingface)
export HF_HOME=/data/huggingface_cache
export TRANSFORMERS_CACHE=/data/transformers_cache

# Mevcut önbellekteki modelleri listele
ls ~/.cache/huggingface/hub/

# Önbellek boyutunu kontrol et
du -sh ~/.cache/huggingface/

Üretim Ortamı için Systemd Servisi

API’nizi sunucu yeniden başladığında otomatik olarak ayağa kaldırmak için systemd servisi oluşturabilirsiniz.

# /etc/systemd/system/duygu-analiz.service dosyasını oluştur
sudo nano /etc/systemd/system/duygu-analiz.service

Dosya içeriği:

[Unit]
Description=Türkçe Duygu Analizi API Servisi
After=network.target
Wants=network-online.target

[Service]
Type=simple
User=appuser
Group=appuser
WorkingDirectory=/opt/duygu-analiz
Environment="PATH=/opt/duygu-analiz/venv/bin"
Environment="HF_HOME=/opt/modeller/cache"
ExecStart=/opt/duygu-analiz/venv/bin/uvicorn api_server:app --host 0.0.0.0 --port 8000 --workers 2
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
# Servisi etkinleştir ve başlat
sudo systemctl daemon-reload
sudo systemctl enable duygu-analiz
sudo systemctl start duygu-analiz

# Durumu kontrol et
sudo systemctl status duygu-analiz

# Logları izle
sudo journalctl -u duygu-analiz -f

Sık Karşılaşılan Sorunlar

Kurulum ve kullanım sırasında karşılaşabileceğiniz durumlar ve çözümleri:

  • CUDA out of memory hatası: Batch size’ı küçültün. 32’den 8’e indirmek genellikle sorunu çözüyor. Alternatif olarak torch.cuda.empty_cache() çağrısı yapabilirsiniz.
  • Tokenizer uyumsuzluğu: Model ve tokenizer’ın aynı kaynaktan geldiğinden emin olun. Pipeline kullanırken bu otomatik yönetiliyor.
  • Yavaş inference: CPU kullanıyorsanız torch.no_grad() context manager’ı kullanın, gereksiz gradient hesaplamalarını önler.
  • Model indirme hatası: Proxy arkasındaysanız HTTPS_PROXY environment variable’ını ayarlayın ya da modeli başka bir makinede indirip transfer edin.
  • UnicodeDecodeError: CSV dosyalarını encoding='utf-8-sig' ile açmayı deneyin, BOM karakteri sorun çıkarabiliyor.
  • Uzun metin sorunu: 512 token sınırını aşan metinleri parçalara bölüp her parça için tahmin alın, sonra çoğunluk oyu veya ortalama kullanın.

Sonuç

Hugging Face ile Türkçe duygu analizi sistemi kurmak göründüğünden çok daha erişilebilir bir hale geldi. Bu yazıda ortam kurulumundan başlayıp üretim seviyesinde bir API servisine kadar her adımı ele aldık. Birkaç kritik noktayı aklınızda tutun.

İlk olarak model seçimi her şeyi belirliyor. Kullanım alanınıza göre doğru modeli seçmek, sonraki tüm adımları kolaylaştırıyor. E-ticaret yorumları için eğitilmiş bir model, sosyal medya analizi için farklı sonuçlar verebilir.

İkinci olarak üretim ortamında modeli global seviyede yükleyin, her request’te yeniden yüklemeyin. Bu basit optimizasyon gecikme sürenizi dramatik biçimde düşürüyor.

Son olarak toplu işlemi daima tercih edin. Tek tek tahmin almak yerine batch processing hem GPU’yu hem CPU’yu çok daha verimli kullanmanızı sağlıyor.

Sonraki adım olarak kendi verilerinizle fine-tuning yapmayı düşünebilirsiniz. Genel amaçlı modeller iyi bir başlangıç noktası sağlıyor, ancak sektörünüze özgü kelimeler ve ifadeler için özelleştirilmiş modeller çok daha yüksek doğruluk oranı sunuyor. Bunu da ilerleyen yazılarda ele alacağız.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir