Transformers documentation
Klasifikasi token
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:
- Lakukan finetuning DistilBERT pada dataset WNUT 17 untuk mendeteksi entitas baru.
- 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.
Sebelum memulai, pastikan Anda telah menginstal semua pustaka yang diperlukan:
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:
>>> from huggingface_hub import notebook_login
>>> notebook_login()Muat dataset WNUT 17
Mulai dengan memuat dataset WNUT 17 dari pustaka 🤗 Datasets:
>>> from datasets import load_dataset
>>> wnut = load_dataset("flaitenberger/wnut_17")Lalu, lihatlah sebuah contoh:
>>> 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:
>>> 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, tokenStatemerupakan bagian dari entitas sepertiEmpire State Building).0menunjukkan bahwa token tersebut tidak sesuai dengan entitas apa pun.
Pra-pemrosesan
Langkah selanjutnya adalah memuat tokenizer DistilBERT untuk memproses pra-tokens field:
>>> 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:
>>> 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 dapat dipecah menjadi dua subword. Anda perlu menyelaraskan ulang token dan label dengan cara:
- Memetakan semua token ke kata yang sesuai dengan metode word_ids.
- Menetapkan label
-100pada token khusus[CLS]dan[SEP]agar diabaikan oleh fungsi loss PyTorch (lihat CrossEntropyLoss). - Hanya memberi label pada token pertama dari sebuah kata. Berikan
-100untuk subtoken lain dari kata yang sama.
Berikut cara membuat fungsi untuk menyelaraskan ulang token dan label, serta memotong urutan agar tidak lebih panjang dari panjang input maksimum DistilBERT:
>>> 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_inputsUntuk menerapkan fungsi prapemrosesan ke seluruh dataset, gunakan fungsi map dari 🤗 Datasets. Anda dapat mempercepat fungsi map dengan mengatur batched=True untuk memproses beberapa elemen dataset sekaligus:
>>> tokenized_wnut = wnut.map(tokenize_and_align_labels, batched=True)Sekarang buat satu batch contoh menggunakan DataCollatorWithPadding. Lebih efisien untuk melakukan padding secara dinamis kalimat hingga panjang terpanjang dalam satu batch saat collation, daripada melakukan padding seluruh dataset hingga panjang maksimum.
>>> from transformers import DataCollatorForTokenClassification
>>> data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer)Evaluasi
Menambahkan metrik selama pelatihan sering kali membantu untuk mengevaluasi kinerja model Anda. Anda dapat dengan cepat memuat metode evaluasi dengan pustaka 🤗 Evaluate. Untuk tugas ini, muat kerangka kerja seqeval (lihat quick tour 🤗 Evaluate untuk mempelajari lebih lanjut tentang cara memuat dan menghitung metrik). Seqeval sebenarnya menghasilkan beberapa skor: precision, recall, F1, dan accuracy.
>>> import evaluate
>>> seqeval = evaluate.load("seqeval")Ambil label NER terlebih dahulu, lalu buat fungsi yang meneruskan prediksi Anda dan label sebenarnya ke compute untuk menghitung skor:
>>> 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:
>>> 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, silakan lihat tutorial dasar di sini!
Anda siap untuk mulai melatih model Anda sekarang! Muat DistilBERT dengan AutoModelForTokenClassification beserta jumlah label yang diharapkan, dan pemetaan label:
>>> 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:
- Definisikan hiperparameter pelatihan Anda di TrainingArguments. Satu-satunya parameter yang wajib diisi adalah
output_diryang menentukan lokasi penyimpanan model Anda. Anda akan mendorong model ini ke Hub dengan mengaturpush_to_hub=True(Anda harus masuk ke Hugging Face untuk mengunggah model Anda). Di akhir setiap epoch, Trainer akan mengevaluasi skor seqeval dan menyimpan checkpoint pelatihan. - Lewatkan argumen pelatihan ke Trainer bersama dengan model, dataset, tokenizer, data collator, dan fungsi
compute_metrics. - Panggil train() untuk melakukan finetuning pada model Anda.
>>> 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() agar semua orang dapat menggunakan model Anda:
>>> trainer.push_to_hub()Untuk contoh yang lebih mendalam tentang cara melakukan finetuning model untuk klasifikasi token, lihat notebook PyTorch yang sesuai.
Inferensi
Bagus, sekarang setelah Anda melakukan finetuning pada model, Anda dapat menggunakannya untuk inferensi!
Ambil beberapa teks yang ingin Anda jalankan inferensinya:
>>> 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(). Buat instans pipeline untuk NER dengan model Anda, lalu berikan teks Anda ke dalamnya:
>>> 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:
>>> 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:
>>> from transformers import AutoModelForTokenClassification
>>> model = AutoModelForTokenClassification.from_pretrained("stevhliu/my_awesome_wnut_model")
>>> with torch.no_grad():
... logits = model(**inputs).logitsDapatkan kelas dengan probabilitas tertinggi, lalu gunakan pemetaan id2label dari model untuk mengubahnya menjadi label teks:
>>> 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']