Dataset Quality Pipeline: MinHash Dedupe + Perplexity Filter + Toxicity + Educational-Value
Garbage in, garbage out. SFT dataset quality pipeline: MinHash LSH for near-duplicates (~30-40% are duplicates), KenLM 5-gram perplexity filter, HateBERT-TR toxicity, FineWeb-style educational-value scorer. Clean 1M-row TR dataset in 25 min on RTX 4090.
Şükrü Yusuf KAYA
34 min read
Advanced🎯 Bu derste
Bir ham TR dataset'in 1M satırı vardı; cookbook pipeline'ından geçince 620K kalır — geri kalan %38 ya duplicate, ya gibberish, ya toksik, ya eğitsel değeri sıfır. Az ama temiz, fazla ama kirli bir dataset'ten çok daha iyi sonuç verir.
1. MinHash LSH — Near-Duplicate Detection#
İki cümle benzer ama tam aynı değil:
- "Türkiye'nin başkenti Ankara'dır."
- "Türkiye'nin başkenti Ankara şehridir."
Cosine similarity 0.95+. Bu örneklerden her ikisini dataset'te tutman model'in aynı şeyi defalarca öğrenmesine neden olur.
MinHash matematiği#
Jaccard similarity:
MinHash: k farklı hash function ile signature → signatures benzer ise Jaccard yüksek.
LSH (Locality-Sensitive Hashing): signature'ları bucket'lara at, aynı bucket'taki çiftleri kontrol et → O(n²) yerine O(n).
|A ∩ B| / |A ∪ B|from datasketch import MinHash, MinHashLSH def shingle(text, k=5): return {text[i:i+k] for i in range(len(text)-k+1)} def minhash(text, num_perm=128): m = MinHash(num_perm=num_perm) for s in shingle(text): m.update(s.encode()) return m # Dataset üzerinde lsh = MinHashLSH(threshold=0.85, num_perm=128) keep = [] for i, row in enumerate(dataset): m = minhash(row["text"]) if not lsh.query(m): lsh.insert(f"id-{i}", m) keep.append(i)
RTX 4090 + 1M TR satır: 8-12 dakika (CPU-bound). %25-40 düşer (TR-Alpaca + OASST-TR mix'inde tipik).
2. KenLM Perplexity Filter#
Spam, gibberish, machine-translated kötü TR'yi yakala. KenLM 5-gram language model TR Wikipedia üzerinde eğit, eşik üstü perplexity → filter out.
import kenlm model = kenlm.LanguageModel("tr_wiki_5gram.binary") def perplexity(text): return 10 ** (-model.score(text, bos=True, eos=True) / len(text.split())) # Eşik: TR Wikipedia üzerinde median 30-60. # > 250 → tipik gibberish (kötü TR, encoding error, repeated chars) filtered = [row for row in dataset if perplexity(row["text"]) < 250]
KenLM binary'sini sıfırdan eğitmek istemiyorsan: repository TR için pre-trained model sağlar.
facebookresearch/cc_net3. Toxicity Filter (TR)#
TR'de toxic content detection için seçenekler:
- HateBERT-TR (BERT-tabanlı, TR fine-tuned)
- Perspective API (Google, multilingual)
- Detoxify TR adaptation
Cookbook'un kuralı: conservative filter — false positive (yanlışlıkla iyi cümleyi atmak) tehlikeli (cinsiyet, ırk konularını taşıyan iyi tartışmalar kaybolabilir). Eşik: HateBERT-TR score > 0.85 → at.
from transformers import pipeline toxic = pipeline("text-classification", model="savasy/bert-base-turkish-cased-toxic") # Batch processing — RTX 4090 ile 1K row/saniye def is_toxic(text): result = toxic(text[:512])[0] # truncate to 512 return result["label"] == "TOXIC" and result["score"] > 0.85
4. Educational-Value Scorer (FineWeb-style)#
HuggingFace FineWeb dataset bir BERT classifier ile her web sayfasına educational value score veriyor (0-5 arası). Cookbook bunu TR adapte etti:
from transformers import AutoTokenizer, AutoModelForSequenceClassification scorer_tok = AutoTokenizer.from_pretrained("dbmdz/bert-base-turkish-cased") scorer = AutoModelForSequenceClassification.from_pretrained("/data/edu_scorer_tr") scorer.cuda().eval() @torch.inference_mode() def edu_score(text): enc = scorer_tok(text, return_tensors="pt", truncation=True, max_length=512).to("cuda") out = scorer(**enc).logits.softmax(-1) return (out * torch.arange(5).float().cuda()).sum().item() # Tipik dağılım: # < 2.0 → çöp (Reddit memes, spam) # 2.0-3.0 → düşük eğitsel (chitchat, opinion) # 3.0-4.0 → orta (Wikipedia, makaleler) # 4.0+ → yüksek (textbook, scientific) # Filter: edu_score >= 2.5
Maliyet: RTX 4090 ile 1M cümleyi ~6 dakika.
python
# === Full quality pipeline — 1M TR row, RTX 4090, ~25 dakika ===from datasets import load_datasetimport time ds = load_dataset("malhajar/turkish-corpus-mixed", split="train")print(f"İlk: {len(ds)} satır")# Tipik: 1.000.000 t0 = time.time() # 1. Dedupe — 8 dakikads = ds.filter(lambda x: not is_duplicate(x["text"], lsh))print(f"Dedupe sonrası: {len(ds)}")# Tipik: ~680.000 (-%32) # 2. Length filter — 1 dakikads = ds.filter(lambda x: 50 < len(x["text"]) < 4000)print(f"Length sonrası: {len(ds)}")# Tipik: ~640.000 # 3. Perplexity — 4 dakikads = ds.filter(lambda x: perplexity(x["text"]) < 250)print(f"PPL sonrası: {len(ds)}")# Tipik: ~620.000 # 4. Toxicity — 5 dakika (RTX 4090)ds = ds.filter(lambda x: not is_toxic(x["text"]))print(f"Toxicity sonrası: {len(ds)}")# Tipik: ~615.000 (-%0.8) # 5. Edu-value — 6 dakika (RTX 4090)ds = ds.filter(lambda x: edu_score(x["text"]) >= 2.5)print(f"Edu sonrası: {len(ds)}")# Tipik: ~470.000 print(f"Toplam {(time.time()-t0)/60:.1f} dakika")print(f"Final: {len(ds)} / 1.000.000 ({len(ds)/10000:.0f}%)") ds.save_to_disk("/data/tr-cleaned")1M TR satır → RTX 4090 ~25 dakika full pipeline
🐛 FMD — 'Quality pipeline'dan geçti ama SFT'de loss yine kötü'
Hipotez: (a) Filtered dataset hâlâ format issues içeriyor (örn. HTML kalıntıları, tag'ler). Çözüm: `bs4.BeautifulSoup` ile HTML strip + `unicodedata.normalize('NFC', ...)`. (b) Dataset balance kötü — %80 forum chat, %20 makale → model casual mode'da kalır. Çözüm: domain-wise sampling (Ders 2.8 — data mixing math). (c) Length distribution sağa eğik — uzun document'lar dominat. Çözüm: truncate veya weight by sqrt(length). Drill: dataset histogram'ını çıkar.
✅ Teslim
- Kendi TR corpus'una full pipeline'ı uygula. 2) Filter rate'ini her stage'de raporla. 3) Sonraki ders: 2.7 — Synthetic Data: Self-Instruct, Evol-Instruct, MAGPIE.
Yorumlar & Soru-Cevap
(0)Yorum yazmak için giriş yap.
Yorumlar yükleniyor...
Related Content
Part 0 — Engineering Foundations
Welcome to the Fine-Tuning Cookbook: System, Stage Taxonomy, and the Reproducibility Contract
Start LearningPart 0 — Engineering Foundations
Reproducibility Stack: Seeds, cuDNN Flags, and Deterministic CUDA — End the 'Works on My Machine' Problem
Start LearningPart 0 — Engineering Foundations