# Klasifikasi token

Token classification memberikan label pada token individual dalam sebuah kalimat. Salah satu tugas token classification yang paling umum adalah Named Entity Recognition (NER). NER berusaha menemukan label untuk setiap entitas dalam kalimat, seperti orang, lokasi, atau organisasi.

Panduan ini akan menunjukkan cara Anda untuk:

1. Lakukan finetuning [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased) pada dataset [WNUT 17](https://huggingface.co/datasets/flaitenberger/wnut_17) untuk mendeteksi entitas baru.
2. Gunakan model yang telah Anda finetune untuk inferensi.

Untuk melihat semua arsitektur dan checkpoint yang kompatibel dengan tugas ini, kami menyarankan untuk memeriksa [halaman tugas](https://huggingface.co/tasks/token-classification).

Sebelum memulai, pastikan Anda telah menginstal semua pustaka yang diperlukan:

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

Kami menyarankan Anda untuk masuk ke akun Hugging Face Anda agar dapat mengunggah dan membagikan model Anda kepada komunitas. Saat diminta, masukkan token Anda untuk masuk:

```py
>>> from huggingface_hub import notebook_login

>>> notebook_login()
```

## Muat dataset WNUT 17

Mulai dengan memuat dataset WNUT 17 dari pustaka 🤗 Datasets:

```py
>>> from datasets import load_dataset

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

Lalu, lihatlah sebuah contoh:

```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', '.']
}
```

Setiap angka dalam `ner_tags` mewakili sebuah entitas. Ubah angka-angka tersebut menjadi nama labelnya untuk mengetahui apa entitas tersebut:

```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",
]
```

Huruf yang mendahului setiap `ner_tag` menunjukkan posisi token dari entitas tersebut:

- `B-` menandakan awal dari sebuah entitas.
- `I-` menunjukkan bahwa token tersebut berada di dalam entitas yang sama (misalnya, token `State` merupakan bagian dari entitas seperti `Empire State Building`).
- `0` menunjukkan bahwa token tersebut tidak sesuai dengan entitas apa pun.

## Pra-pemrosesan

Langkah selanjutnya adalah memuat tokenizer DistilBERT untuk memproses pra-`tokens` field:

```py
>>> from transformers import AutoTokenizer

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

Seperti yang Anda lihat pada contoh field `tokens` di atas, tampaknya input sudah ditokenisasi. Namun, input sebenarnya belum ditokenisasi dan Anda perlu mengatur `is_split_into_words=True` untuk mem-tokenisasi kata-kata menjadi subword. Sebagai contoh:

```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]']
```

Namun, hal ini menambahkan beberapa token khusus `[CLS]` dan `[SEP]` dan tokenisasi subword menciptakan ketidakcocokan antara input dan label. Satu kata yang sesuai dengan satu label kini mungkin dipecah menjadi dua subword. Anda perlu menyelaraskan ulang token dan label dengan cara:

1. Memetakan semua token ke kata yang sesuai dengan metode [word_ids](/docs/transformers/v5.23.0/id/main_classes/tokenizer#transformers.BatchEncoding.word_ids).
2. Menugaskan label `-100` ke token khusus `[CLS]` dan `[SEP]` agar diabaikan oleh fungsi loss PyTorch (lihat [CrossEntropyLoss](https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html)).
3. Hanya memberi label pada token pertama dari sebuah kata. Berikan `-100` untuk subtoken lain dari kata yang sama.

Berikut cara Anda dapat membuat fungsi untuk menyelaraskan ulang token dan label, serta memotong urutan agar tidak lebih panjang dari panjang input maksimum DistilBERT:

```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
```

Untuk menerapkan fungsi prapemrosesan ke seluruh dataset, gunakan fungsi [map](https://huggingface.co/docs/datasets/v5.2.0/en/package_reference/main_classes#datasets.Dataset.map) dari 🤗 Datasets. Anda dapat mempercepat fungsi `map` dengan mengatur `batched=True` untuk memproses beberapa elemen dataset sekaligus:

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

Sekarang buat batch contoh menggunakan [DataCollatorWithPadding](/docs/transformers/v5.23.0/id/main_classes/data_collator#transformers.DataCollatorWithPadding). Lebih efisien untuk *melakukan padding dinamis* kalimat hingga panjang terpanjang dalam batch saat kolasi, daripada melakukan padding seluruh dataset hingga panjang maksimum.

```py
>>> from transformers import DataCollatorForTokenClassification

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

## Evaluasi

Termasuk metrik selama pelatihan sering kali membantu untuk mengevaluasi kinerja model Anda. Anda dapat dengan cepat memuat metode evaluasi dengan pustaka 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index). Untuk tugas ini, muat kerangka kerja [seqeval](https://huggingface.co/spaces/evaluate-metric/seqeval) (lihat [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) 🤗 Evaluate untuk mempelajari lebih lanjut tentang cara memuat dan menghitung metrik). Seqeval sebenarnya menghasilkan beberapa skor: precision, recall, F1, dan accuracy.

```py
>>> import evaluate

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

Ambil label NER terlebih dahulu, lalu buat fungsi yang meneruskan prediksi Anda dan label sebenarnya ke [compute](https://huggingface.co/docs/evaluate/v0.4.6/en/package_reference/main_classes#evaluate.EvaluationModule.compute) untuk menghitung skor:

```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"],
...     }
```

Fungsi `compute_metrics` Anda sudah siap digunakan, dan Anda akan kembali ke fungsi ini saat menyiapkan pelatihan.

## Latih

Sebelum Anda mulai melatih model, buatlah peta dari id yang diharapkan ke label mereka dengan `id2label` dan `label2id`:

```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,
... }
```

Jika Anda belum familiar dengan finetuning model menggunakan [Trainer](/docs/transformers/v5.23.0/id/main_classes/trainer#transformers.Trainer), silakan lihat tutorial dasar [di sini](../training)!

Anda siap untuk mulai melatih model Anda sekarang! Muat DistilBERT dengan [AutoModelForTokenClassification](/docs/transformers/v5.23.0/id/model_doc/auto#transformers.AutoModelForTokenClassification) beserta jumlah label yang diharapkan, dan pemetaan label:

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

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

Pada titik ini, hanya tersisa tiga langkah:

1. Definisikan hiperparameter pelatihan Anda di [TrainingArguments](/docs/transformers/v5.23.0/id/main_classes/trainer#transformers.TrainingArguments). Satu-satunya parameter yang wajib diisi adalah `output_dir` yang menentukan lokasi penyimpanan model Anda. Anda akan mendorong model ini ke Hub dengan mengatur `push_to_hub=True` (Anda harus masuk ke Hugging Face untuk mengunggah model Anda). Di akhir setiap epoch, [Trainer](/docs/transformers/v5.23.0/id/main_classes/trainer#transformers.Trainer) akan mengevaluasi skor seqeval dan menyimpan checkpoint pelatihan.
2. Lewatkan argumen pelatihan ke [Trainer](/docs/transformers/v5.23.0/id/main_classes/trainer#transformers.Trainer) bersama dengan model, dataset, tokenizer, data collator, dan fungsi `compute_metrics`.
3. Panggil [train()](/docs/transformers/v5.23.0/id/main_classes/trainer#transformers.Trainer.train) untuk melakukan finetuning pada model Anda.

```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()
```

Setelah pelatihan selesai, bagikan model Anda ke Hub dengan metode [push_to_hub()](/docs/transformers/v5.23.0/id/main_classes/trainer#transformers.Trainer.push_to_hub) agar semua orang dapat menggunakan model Anda:

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

Untuk contoh yang lebih mendalam tentang cara melakukan finetuning model untuk klasifikasi token, lihat [notebook PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/token_classification.ipynb) yang sesuai.

## Inferensi

Bagus, sekarang setelah Anda melakukan penyesuaian halus pada model, Anda dapat menggunakannya untuk inferensi!

Ambil beberapa teks yang ingin Anda jalankan inferensinya:

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

Cara termudah untuk mencoba model finetune Anda untuk inferensi adalah dengan menggunakannya dalam [pipeline()](/docs/transformers/v5.23.0/id/main_classes/pipelines#transformers.pipeline). Buat instans `pipeline` untuk NER dengan model Anda, lalu berikan teks Anda ke dalamnya:

```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}]
```

Anda juga dapat mereplikasi hasil dari `pipeline` secara manual jika Anda mau:

Tokenisasi teks dan kembalikan tensor PyTorch:

```py
>>> from transformers import AutoTokenizer

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

Lewatkan input Anda ke model dan kembalikan `logits`:

```py
>>> from transformers import AutoModelForTokenClassification

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

Dapatkan kelas dengan probabilitas tertinggi, dan gunakan pemetaan `id2label` model untuk mengubahnya menjadi label teks:

```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']
```

