--- language: - tr tags: - named-entity-recognition - ner - turkish - bert - deprem - disaster - token-classification - earthquake license: apache-2.0 base_model: dbmdz/bert-base-turkish-cased datasets: - custom metrics: - f1 - precision - recall model-index: - name: bert-turkish-deprem-ner results: - task: type: token-classification name: Named Entity Recognition metrics: - type: f1 value: 0.9702 name: F1 (Stacked 17k) - type: precision value: 0.9680 name: Precision - type: recall value: 0.9724 name: Recall --- # BERT Türkçe Deprem Tweet NER Modeli Deprem tweetlerinden kritik bilgileri otomatik olarak çıkarmak için **SFT + Pseudo-Labeling (Stacking Ensemble)** yöntemiyle fine-tune edilmiş NER modeli. - **Base model:** dbmdz/bert-base-turkish-cased - **Eğitim:** 500 altın standart → LLM pseudo-labeling → 17.000 Stacked veri seti - **Veri seti:** 6 Şubat 2023 Türkiye-Suriye depremi tweet'leri - **Dil:** Türkçe ## Desteklenen Etiketler | Etiket | Açıklama | Örnek | |--------|----------|-------| | `LOC` | Konum / Adres | Hatay Antakya Armutlu Sokak | | `PER` | Kişi adı | Murat Filazoğlu | | `PHONE` | Telefon numarası | 0539 218 3976 | | `NEED` | İhtiyaç / Talep | battaniye, jeneratör | | `ORG` | Kurum / Organizasyon | AFAD, Kızılay | | `LINK` | URL bağlantısı | https://t.co/... | ## ⚠️ Önemli Not: Ön-İşleme (Tokenization) Bu model eğitilirken metinler standart BERT tokenizer'ı ile değil, özel olarak **NLTK TweetTokenizer** kullanılarak kelimelere ayrılmıştır. Bu sayede `@kullanici_adi`, `https://...` gibi ifadeler ve telefon numaraları parçalanmadan tek bir bütün olarak ele alınır. Hugging Face'in standart `pipeline` fonksiyonu metni agresif bir şekilde parçaladığı için URL'lerde ve kurumsal etiketlerde bölünmeler yaşatabilir. **Tam ve doğru performans almak için aşağıdaki özel çıkarım (inference) kodunu kullanmanız tavsiye edilir.** ## Kullanım Aşağıdaki kod bloğu, modelin eğitildiği formata uygun olarak metni işler, etiketleri birleştirir ve güven skorlarıyla (score) birlikte döndürür: ```python import torch import nltk from nltk.tokenize import TweetTokenizer from transformers import AutoTokenizer, AutoModelForTokenClassification # 1. NLTK TweetTokenizer'ı başlat (Link ve etiketleri korumak için gerekli) nltk.download('punkt', quiet=True) tknzr = TweetTokenizer(preserve_case=True, strip_handles=False, reduce_len=False) # 2. Modeli ve Tokenizer'ı Hugging Face'den yükle repo_id = "nypgd/bert-turkish-deprem-ner" tokenizer = AutoTokenizer.from_pretrained(repo_id) model = AutoModelForTokenClassification.from_pretrained(repo_id) model.eval() id2label = model.config.id2label # 3. Özel Tahmin Fonksiyonu def extract_entities(text): original_tokens = tknzr.tokenize(text) if not original_tokens: return [] inputs = tokenizer(original_tokens, is_split_into_words=True, return_tensors="pt", truncation=True) with torch.no_grad(): logits = model(**inputs).logits predictions = torch.argmax(logits, dim=2)[0] word_ids = inputs.word_ids() token_tags = [] token_logit_idx = [] prev_word_idx = None for sub_pos, (pred_id, word_idx) in enumerate(zip(predictions, word_ids)): if word_idx is None: continue if word_idx != prev_word_idx: token_tags.append(id2label[pred_id.item()]) token_logit_idx.append(sub_pos) prev_word_idx = word_idx # Entity Birleştirme (Noktalama işaretlerini atlama mantığıyla) SKIP_TOKENS = {',', '-', ':', '.', '/', '(', ')'} entities = [] current_ent = None for i, (token, tag) in enumerate(zip(original_tokens, token_tags)): if tag == 'O' and current_ent and token in SKIP_TOKENS: continue if tag == 'O': if current_ent: entities.append(current_ent) current_ent = None continue ent_type = tag[2:] score_val = round(torch.softmax(logits[0, token_logit_idx[i]], dim=-1).max().item(), 4) if tag.startswith('B-'): if current_ent: entities.append(current_ent) current_ent = {"entity_group": ent_type, "word": token, "score": score_val, "start": i, "end": i + 1} elif tag.startswith('I-') and current_ent and current_ent["entity_group"] == ent_type: current_ent["word"] += " " + token current_ent["end"] = i + 1 current_ent["score"] = round(min(current_ent["score"], score_val), 4) else: if current_ent: entities.append(current_ent) current_ent = {"entity_group": ent_type, "word": token, "score": score_val, "start": i, "end": i + 1} if current_ent: entities.append(current_ent) return entities # 4. Test Edelim text = """ @AFADTurkiye ve Ahbap ekipleri, Gaziantep İslahiye Yeni Mahalle Karanfil Sokak No:5 adresinde 7 kişi enkaz altında mahsur kaldı. Acil ısıtıcı, çadır ve çocuk maması gerekiyor. Saha sorumlusu Ayşe Yurt iletişim: 0533 123 45 67. Konum ve detaylı bilgi için: https://t.co/yardimadresi """ results = extract_entities(text) for ent in results: etiket = f"[{ent['entity_group']}]" print(f"{etiket:<9} {ent['word']} (score: {ent['score']:.4f})") print("[") for i, ent in enumerate(results): virgul = "," if i < len(results) - 1 else "" print(f" {ent}{virgul}") print("]") # Formatlı Çıktı ─────────────────────────────────────────────────────────────────────────────────── [ORG] @AFADTurkiye (score: 0.9999) [ORG] Ahbap (score: 0.9996) [LOC] Gaziantep İslahiye Yeni Mahalle Karanfil Sokak No 5 (score: 0.9999) [NEED] ısıtıcı (score: 0.9999) [NEED] çadır (score: 0.9999) [NEED] çocuk maması (score: 0.9997) [PER] Ayşe Yurt (score: 0.9993) [PHONE] 0533 123 45 67 (score: 0.9998) [LINK] https://t.co/yardimadresi (score: 0.9999) ─────────────────────────────────────────────────────────────────────────────────── # Ham Çıktı (Tek satırlık liste formatı) [ {'entity_group': 'ORG', 'word': '@AFADTurkiye', 'score': 0.9999, 'start': 0, 'end': 1}, {'entity_group': 'ORG', 'word': 'Ahbap', 'score': 0.9996, 'start': 2, 'end': 3}, {'entity_group': 'LOC', 'word': 'Gaziantep İslahiye Yeni Mahalle Karanfil Sokak No 5', 'score': 0.9999, 'start': 5, 'end': 14}, {'entity_group': 'NEED', 'word': 'ısıtıcı', 'score': 0.9999, 'start': 23, 'end': 24}, {'entity_group': 'NEED', 'word': 'çadır', 'score': 0.9999, 'start': 25, 'end': 26}, {'entity_group': 'NEED', 'word': 'çocuk maması', 'score': 0.9997, 'start': 27, 'end': 29}, {'entity_group': 'PER', 'word': 'Ayşe Yurt', 'score': 0.9993, 'start': 33, 'end': 35}, {'entity_group': 'PHONE', 'word': '0533 123 45 67', 'score': 0.9998, 'start': 37, 'end': 41}, {'entity_group': 'LINK', 'word': '[https://t.co/yardimadresi](https://t.co/yardimadresi)', 'score': 0.9999, 'start': 48, 'end': 49} ]