# Token sınıflandırma

Token sınıflandırma, bir cümledeki bireysel token'lara bir etiket atar. Token sınıflandırma görevlerinin en yaygınlarından biri Adlandırılmış Varlık Tanıma (NER)'dır. NER, bir cümledeki her varlık için kişi, konum veya kuruluş gibi bir etiket bulmaya çalışır.

Bu kılavuz size şunları gösterecektir:

1. Yeni varlıkları tespit etmek için [WNUT 17](https://huggingface.co/datasets/flaitenberger/wnut_17) veri setinde [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased)'yi ince ayarlayın.
2. İnce ayarlanmış modelinizi çıkarım için kullanın.

Bu görevle uyumlu tüm mimarileri ve denetim noktalarını görmek için [görev sayfasını](https://huggingface.co/tasks/token-classification) kontrol etmenizi öneririz.

Başlamadan önce, gerekli tüm kütüphanelerin yüklendiğinden emin olun:

```bash
pip install transformers datasets evaluate seqeval
```

Modelinizi yükleyip toplulukla paylaşabilmeniz için Hugging Face hesabınıza giriş yapmanızı öneririz. İstendiğinde giriş yapmak için token'ınızı girin:

```py
>>> from huggingface_hub import notebook_login

>>> notebook_login()
```

## WNUT 17 veri setini yükle

🤗 Datasets kütüphanesinden WNUT 17 veri setini yükleyerek başlayın:

```py
>>> from datasets import load_dataset

>>> wnut = load_dataset("flaitenberger/wnut_17")
```

Sonra bir örneğe göz atın:

```py
>>> wnut["train"][0]
{'id': '0',
 'ner_tags': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0],
 'tokens': ['@paulwalk', 'It', "'s", 'the', 'view', 'from', 'where', 'I', "'m", 'living', 'for', 'two', 'weeks', '.', 'Empire', 'State', 'Building', '=', 'ESB', '.', 'Pretty', 'bad', 'storm', 'here', 'last', 'evening', '.']
}
```

`ner_tags` içindeki her sayı bir varlığı temsil eder. Varlıkların ne olduğunu bulmak için sayıları etiket adlarına dönüştürün:

```py
>>> label_list = wnut["train"].features[f"ner_tags"].feature.names
>>> label_list
[
    "O",
    "B-corporation",
    "I-corporation",
    "B-creative-work",
    "I-creative-work",
    "B-group",
    "I-group",
    "B-location",
    "I-location",
    "B-person",
    "I-person",
    "B-product",
    "I-product",
]
```

Her `ner_tag`'ın başındaki harf, varlığın token konumunu belirtir:

- `B-`, bir varlığın başlangıcını belirtir.
- `I-`, bir token'ın aynı varlığın içinde yer aldığını belirtir (örneğin, `State` token'ı, `Empire State Building` gibi bir varlığın parçasıdır).
- `0`, token'ın herhangi bir varlığa karşılık gelmediğini belirtir.

## Ön işleme

Bir sonraki adım, `tokens` alanını ön işlemek için bir DistilBERT tokenizer yüklemektir:

```py
>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
```

Yukarıdaki örnekte `tokens` alanını gördünüz; girişin zaten tokenize edilmiş gibi göründüğü anlaşılıyor. Ancak giriş aslında henüz tokenize edilmedi ve kelimeleri alt kelimelere (subword) dönüştürmek için `is_split_into_words=True` değerini ayarlamanız gerekir. Örneğin:

```py
>>> example = wnut["train"][0]
>>> tokenized_input = tokenizer(example["tokens"], is_split_into_words=True)
>>> tokens = tokenizer.convert_ids_to_tokens(tokenized_input["input_ids"])
>>> tokens
['[CLS]', '@', 'paul', '##walk', 'it', "'", 's', 'the', 'view', 'from', 'where', 'i', "'", 'm', 'living', 'for', 'two', 'weeks', '.', 'empire', 'state', 'building', '=', 'es', '##b', '.', 'pretty', 'bad', 'storm', 'here', 'last', 'evening', '.', '[SEP]']
```

Ancak bu, bazı özel jetonlar olan `[CLS]` ve `[SEP]` ekler ve alt kelime (subword) jetonlaştırma, girdi ile etiketler arasında bir uyumsuzluk yaratır. Tek bir etikete karşılık gelen tek bir kelime artık iki alt kelimeye bölünebilir. Jetonları ve etiketleri yeniden hizalamak için şunları yapmanız gerekir:

1. [word_ids](/docs/transformers/main/tr/main_classes/tokenizer#transformers.BatchEncoding.word_ids) yöntemiyle tüm jetonları ilgili kelimelerine eşleme.
2. Özel jetonlar `[CLS]` ve `[SEP]` için `-100` etiketini atayarak PyTorch kayıp fonksiyonu tarafından yok sayılmalarını sağlama (bkz. [CrossEntropyLoss](https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html)).
3. Sadece verilen bir kelimenin ilk token'ını etiketleme. Aynı kelimeden gelen diğer alt token'lara `-100` atama.

DistilBERT'in maksimum giriş uzunluğunu aşmayacak şekilde dizileri kısaltmak ve jetonları ile etiketleri yeniden hizalamak için bir fonksiyon oluşturmanın yolu aşağıdaki gibidir:

```py
>>> def tokenize_and_align_labels(examples):
...     tokenized_inputs = tokenizer(examples["tokens"], truncation=True, is_split_into_words=True)

...     labels = []
...     for i, label in enumerate(examples[f"ner_tags"]):
...         word_ids = tokenized_inputs.word_ids(batch_index=i)  # Map tokens to their respective word.
...         previous_word_idx = None
...         label_ids = []
...         for word_idx in word_ids:  # Set the special tokens to -100.
...             if word_idx is None:
...                 label_ids.append(-100)
...             elif word_idx != previous_word_idx:  # Only label the first token of a given word.
...                 label_ids.append(label[word_idx])
...             else:
...                 label_ids.append(-100)
...             previous_word_idx = word_idx
...         labels.append(label_ids)

...     tokenized_inputs["labels"] = labels
...     return tokenized_inputs
```

Tüm veri setine ön işleme fonksiyonunu uygulamak için 🤗 Datasets [map](https://huggingface.co/docs/datasets/main/en/package_reference/main_classes#datasets.Dataset.map) fonksiyonunu kullanın. `map` fonksiyonunu, veri setinin birden çok öğesini aynı anda işlemek için `batched=True` değerini ayarlayarak hızlandırabilirsiniz:

```py
>>> tokenized_wnut = wnut.map(tokenize_and_align_labels, batched=True)
```

Şimdi [DataCollatorWithPadding](/docs/transformers/main/tr/main_classes/data_collator#transformers.DataCollatorWithPadding) kullanarak örneklerden oluşan bir batch oluşturun. Toplama sırasında cümleleri batch içindeki en uzun uzunluğa *dinamik olarak doldurmak*, tüm veri setini maksimum uzunluğa doldurmaktan daha verimlidir.

```py
>>> from transformers import DataCollatorForTokenClassification

>>> data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer)
```

## Değerlendir

Eğitim sırasında bir metrik kullanmak, modelinizin performansını değerlendirmek için genellikle faydalıdır. 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index) kütüphanesiyle bir değerlendirme yöntemini hızla yükleyebilirsiniz. Bu görev için [seqeval](https://huggingface.co/spaces/evaluate-metric/seqeval) çerçevesini yükleyin (bir metriğin nasıl yükleneceğini ve hesaplanacağını öğrenmek için 🤗 Evaluate [hızlı turuna](https://huggingface.co/docs/evaluate/a_quick_tour) bakın). Seqeval aslında birkaç puan üretir: hassasiyet (precision), geri çağırma (recall), F1 ve doğruluk (accuracy).

```py
>>> import evaluate

>>> seqeval = evaluate.load("seqeval")
```

Önce NER etiketlerini alın, ardından gerçek tahminlerinizi ve gerçek etiketlerinizi [compute](https://huggingface.co/docs/evaluate/main/en/package_reference/main_classes#evaluate.EvaluationModule.compute) fonksiyonuna geçirerek puanları hesaplayan bir fonksiyon oluşturun:

```py
>>> import numpy as np

>>> labels = [label_list[i] for i in example[f"ner_tags"]]

>>> def compute_metrics(p):
...     predictions, labels = p
...     predictions = np.argmax(predictions, axis=2)

...     true_predictions = [
...         [label_list[p] for (p, l) in zip(prediction, label) if l != -100]
...         for prediction, label in zip(predictions, labels)
...     ]
...     true_labels = [
...         [label_list[l] for (p, l) in zip(prediction, label) if l != -100]
...         for prediction, label in zip(predictions, labels)
...     ]

...     results = seqeval.compute(predictions=true_predictions, references=true_labels)
...     return {
...         "precision": results["overall_precision"],
...         "recall": results["overall_recall"],
...         "f1": results["overall_f1"],
...         "accuracy": results["overall_accuracy"],
...     }
```

`compute_metrics` fonksiyonunuz artık hazır ve eğitiminizi yapılandırırken ona geri döneceksiniz.

## Eğit

Modelinizi eğitmeye başlamadan önce, `id2label` ve `label2id` ile beklenen kimliklerin etiketlere eşlenmesini oluşturun:

```py
>>> id2label = {
...     0: "O",
...     1: "B-corporation",
...     2: "I-corporation",
...     3: "B-creative-work",
...     4: "I-creative-work",
...     5: "B-group",
...     6: "I-group",
...     7: "B-location",
...     8: "I-location",
...     9: "B-person",
...     10: "I-person",
...     11: "B-product",
...     12: "I-product",
... }
>>> label2id = {
...     "O": 0,
...     "B-corporation": 1,
...     "I-corporation": 2,
...     "B-creative-work": 3,
...     "I-creative-work": 4,
...     "B-group": 5,
...     "I-group": 6,
...     "B-location": 7,
...     "I-location": 8,
...     "B-person": 9,
...     "I-person": 10,
...     "B-product": 11,
...     "I-product": 12,
... }
```

[Trainer](/docs/transformers/main/tr/main_classes/trainer#transformers.Trainer) ile bir modelin ince ayarını yapma konusunda deneyiminiz yoksa, temel öğreticiyi [burada](../training) inceleyebilirsiniz!

Artık modelinizi eğitmeye başlamak için hazırsınız! [AutoModelForTokenClassification](/docs/transformers/main/tr/model_doc/auto#transformers.AutoModelForTokenClassification) ile DistilBERT'i beklenen etiket sayısı ve etiket eşlemeleriyle birlikte yükleyin:

```py
>>> from transformers import AutoModelForTokenClassification, TrainingArguments, Trainer

>>> model = AutoModelForTokenClassification.from_pretrained(
...     "distilbert/distilbert-base-uncased", num_labels=13, id2label=id2label, label2id=label2id
... )
```

Bu noktada yalnızca üç adım kaldı:

1. Eğitim hiperparametrelerinizi [TrainingArguments](/docs/transformers/main/tr/main_classes/trainer#transformers.TrainingArguments) içinde tanımlayın. Tek zorunlu parametre, modelinizi nereye kaydedeceğinizi belirleyen `output_dir`'dir. Modelinizi Hub'a `push_to_hub=True` ayarlayarak yükleyeceksiniz (modelinizi yüklemek için Hugging Face'e giriş yapmış olmanız gerekir). Her epoch'un sonunda [Trainer](/docs/transformers/main/tr/main_classes/trainer#transformers.Trainer), seqeval skorlarını değerlendirir ve eğitim checkpoint'ini kaydeder.
2. Eğitim argümanlarını, model, veri seti, tokenizer, veri toplayıcı ve `compute_metrics` fonksiyonuyla birlikte [Trainer](/docs/transformers/main/tr/main_classes/trainer#transformers.Trainer)'a iletin.
3. Modelinizi ince ayar yapmak için [train()](/docs/transformers/main/tr/main_classes/trainer#transformers.Trainer.train) çağrın.

```py
>>> training_args = TrainingArguments(
...     output_dir="my_awesome_wnut_model",
...     learning_rate=2e-5,
...     per_device_train_batch_size=16,
...     per_device_eval_batch_size=16,
...     num_train_epochs=2,
...     weight_decay=0.01,
...     eval_strategy="epoch",
...     save_strategy="epoch",
...     load_best_model_at_end=True,
...     push_to_hub=True,
... )

>>> trainer = Trainer(
...     model=model,
...     args=training_args,
...     train_dataset=tokenized_wnut["train"],
...     eval_dataset=tokenized_wnut["test"],
...     processing_class=tokenizer,
...     data_collator=data_collator,
...     compute_metrics=compute_metrics,
... )

>>> trainer.train()
```

Eğitim tamamlandıktan sonra, modelinizi herkesin kullanabilmesi için [push_to_hub()](/docs/transformers/main/tr/main_classes/trainer#transformers.Trainer.push_to_hub) yöntemiyle Hub'a paylaşın:

```py
>>> trainer.push_to_hub()
```

Bir modeli token sınıflandırma için ince ayar yapmanın daha ayrıntılı bir örneği için ilgili [PyTorch defterine](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb) göz atın.

## Çıkarım

Harika, bir model ayarladıktan sonra artık çıkarım için kullanabilirsiniz!

Çıkarım yapmak istediğiniz bazı metin alın:

```py
>>> text = "The Golden State Warriors are an American professional basketball team based in San Francisco."
```

Eğitimini tamamladığınız modeli çıkarım için denemenin en basit yolu, onu bir [pipeline()](/docs/transformers/main/tr/main_classes/pipelines#transformers.pipeline) içinde kullanmaktır. Modelinizi kullanarak NER için bir `pipeline` örneği oluşturun ve metninizi ona iletin:

```py
>>> from transformers import pipeline

>>> classifier = pipeline("ner", model="stevhliu/my_awesome_wnut_model")
>>> classifier(text)
[{'entity': 'B-location',
  'score': 0.42658573,
  'index': 2,
  'word': 'golden',
  'start': 4,
  'end': 10},
 {'entity': 'I-location',
  'score': 0.35856336,
  'index': 3,
  'word': 'state',
  'start': 11,
  'end': 16},
 {'entity': 'B-group',
  'score': 0.3064001,
  'index': 4,
  'word': 'warriors',
  'start': 17,
  'end': 25},
 {'entity': 'B-location',
  'score': 0.65523505,
  'index': 13,
  'word': 'san',
  'start': 80,
  'end': 83},
 {'entity': 'B-location',
  'score': 0.4668663,
  'index': 14,
  'word': 'francisco',
  'start': 84,
  'end': 93}]
```

İsterseniz `pipeline` sonuçlarını manuel olarak da yeniden üretebilirsiniz:

Metni tokenleştirin ve PyTorch tensörlerini döndürün:

```py
>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_wnut_model")
>>> inputs = tokenizer(text, return_tensors="pt")
```

Girdilerinizi modele iletin ve `logits` değerlerini döndürün:

```py
>>> from transformers import AutoModelForTokenClassification

>>> model = AutoModelForTokenClassification.from_pretrained("stevhliu/my_awesome_wnut_model")
>>> with torch.no_grad():
...     logits = model(**inputs).logits
```

En yüksek olasılığa sahip sınıfı alın ve modelin `id2label` eşlemesini kullanarak bunu bir metin etiketine dönüştürün:

```py
>>> predictions = torch.argmax(logits, dim=2)
>>> predicted_token_class = [model.config.id2label[t.item()] for t in predictions[0]]
>>> predicted_token_class
['O',
 'O',
 'B-location',
 'I-location',
 'B-group',
 'O',
 'O',
 'O',
 'O',
 'O',
 'O',
 'O',
 'O',
 'B-location',
 'B-location',
 'O',
 'O']
```

