Transformers documentation

Pemodelan bahasa tersembunyi

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.2).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Pemodelan bahasa tersembunyi

Masked language modeling memprediksi token yang dimasker dalam sebuah sekuens, dan model dapat memperhatikan token secara bidireksional. Ini berarti model memiliki akses penuh ke token di sebelah kiri dan kanan. Masked language modeling sangat baik untuk tugas-tugas yang membutuhkan pemahaman kontekstual yang baik dari seluruh sekuens. BERT adalah contoh dari model bahasa ter-masker.

Panduan ini akan menunjukkan cara Anda untuk:

  1. Lakukan finetuning DistilRoBERTa pada subset r/askscience dari dataset ELI5.
  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

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

pip install transformers datasets evaluate

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

>>> from huggingface_hub import notebook_login

>>> notebook_login()

Muat dataset ELI5

Mulai dengan memuat 5000 contoh pertama dari dataset ELI5-Category menggunakan pustaka 🤗 Datasets. Hal ini memberi Anda kesempatan untuk bereksperimen dan memastikan semuanya berfungsi dengan baik sebelum menghabiskan lebih banyak waktu untuk pelatihan pada dataset lengkap.

>>> from datasets import load_dataset

>>> eli5 = load_dataset("dany0407/eli5_category", split="train[:5000]")

Bagi split train dari dataset menjadi set train dan test dengan metode train_test_split:

>>> eli5 = eli5.train_test_split(test_size=0.2)

Lalu, lihatlah sebuah contoh:

>>> eli5["train"][0]
{'q_id': '7h191n',
 'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
 'selftext': '',
 'category': 'Economics',
 'subreddit': 'explainlikeimfive',
 'answers': {'a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
  'text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
   'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
   'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
   'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
  'score': [21, 19, 5, 3],
  'text_urls': [[],
   [],
   [],
   ['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']]},
 'title_urls': ['url'],
 'selftext_urls': ['url']}

Meskipun ini mungkin terlihat banyak, yang benar-benar Anda butuhkan hanyalah field text. Hal menarik dari tugas pemodelan bahasa adalah Anda tidak memerlukan label (juga dikenal sebagai tugas tanpa pengawasan) karena kata berikutnya adalah labelnya.

Pra-pemrosesan

Untuk pemodelan bahasa tersembunyi, langkah selanjutnya adalah memuat tokenizer DistilRoBERTa untuk memproses subfield text:

>>> from transformers import AutoTokenizer

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

Anda akan melihat dari contoh di atas, bahwa field text sebenarnya bersarang di dalam answers. Ini berarti Anda perlu mengekstrak subfield text dari struktur bersarangnya dengan metode flatten:

>>> eli5 = eli5.flatten()
>>> eli5["train"][0]
{'q_id': '7h191n',
 'title': 'What does the tax bill that was passed today mean? How will it affect Americans in each tax bracket?',
 'selftext': '',
 'category': 'Economics',
 'subreddit': 'explainlikeimfive',
 'answers.a_id': ['dqnds8l', 'dqnd1jl', 'dqng3i1', 'dqnku5x'],
 'answers.text': ["The tax bill is 500 pages long and there were a lot of changes still going on right to the end. It's not just an adjustment to the income tax brackets, it's a whole bunch of changes. As such there is no good answer to your question. The big take aways are: - Big reduction in corporate income tax rate will make large companies very happy. - Pass through rate change will make certain styles of business (law firms, hedge funds) extremely happy - Income tax changes are moderate, and are set to expire (though it's the kind of thing that might just always get re-applied without being made permanent) - People in high tax states (California, New York) lose out, and many of them will end up with their taxes raised.",
  'None yet. It has to be reconciled with a vastly different house bill and then passed again.',
  'Also: does this apply to 2017 taxes? Or does it start with 2018 taxes?',
  'This article explains both the House and senate bills, including the proposed changes to your income taxes based on your income level. URL_0'],
 'answers.score': [21, 19, 5, 3],
 'answers.text_urls': [[],
  [],
  [],
  ['https://www.investopedia.com/news/trumps-tax-reform-what-can-be-done/']],
 'title_urls': ['url'],
 'selftext_urls': ['url']}

Setiap subfield kini menjadi kolom terpisah seperti yang ditunjukkan oleh prefiks answers, dan field text kini berupa list. Alih-alih melakukan tokenisasi setiap kalimat secara terpisah, konversikan list tersebut menjadi string agar Anda dapat melakukan tokenisasi secara bersama-sama.

Berikut adalah fungsi pra-pemrosesan pertama untuk menggabungkan daftar string untuk setiap contoh dan melakukan tokenisasi pada hasilnya:

>>> def preprocess_function(examples):
...     return tokenizer([" ".join(x) for x in examples["answers.text"]])

Untuk menerapkan fungsi pra-pemrosesan ini ke seluruh dataset, gunakan metode map dari 🤗 Datasets. Anda dapat mempercepat fungsi map dengan mengatur batched=True untuk memproses beberapa elemen dataset sekaligus, serta meningkatkan jumlah proses dengan num_proc. Hapus kolom apa pun yang tidak Anda butuhkan:

>>> tokenized_eli5 = eli5.map(
...     preprocess_function,
...     batched=True,
...     num_proc=4,
...     remove_columns=eli5["train"].column_names,
... )

Dataset ini berisi urutan token, tetapi beberapa di antaranya lebih panjang dari panjang input maksimum untuk model.

Anda sekarang dapat menggunakan fungsi pra-pemrosesan kedua untuk

  • menggabungkan semua sekuens
  • bagikan rangkaian yang telah digabungkan menjadi potongan-potongan lebih pendek yang didefinisikan oleh block_size, yang harus lebih pendek dari panjang input maksimum dan cukup pendek untuk RAM GPU Anda.
>>> block_size = 128


>>> def group_texts(examples):
...     # Concatenate all texts.
...     concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
...     total_length = len(concatenated_examples[list(examples.keys())[0]])
...     # We drop the small remainder, we could add padding if the model supported it instead of this drop, you can
...     # customize this part to your needs.
...     if total_length >= block_size:
...         total_length = (total_length // block_size) * block_size
...     # Split by chunks of block_size.
...     result = {
...         k: [t[i : i + block_size] for i in range(0, total_length, block_size)]
...         for k, t in concatenated_examples.items()
...     }
...     return result

Terapkan fungsi group_texts pada seluruh dataset:

>>> lm_dataset = tokenized_eli5.map(group_texts, batched=True, num_proc=4)

Sekarang buat satu batch contoh menggunakan DataCollatorForLanguageModeling. Lebih efisien untuk melakukan padding secara dinamis kalimat hingga panjang terpanjang dalam satu batch saat collation, daripada melakukan padding seluruh dataset hingga panjang maksimum.

Gunakan token end-of-sequence sebagai token padding dan tentukan mlm_probability untuk secara acak mem-mask token setiap kali Anda mengiterasi data:

>>> from transformers import DataCollatorForLanguageModeling

>>> tokenizer.pad_token = tokenizer.eos_token
>>> data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15)

Latih

Jika Anda belum familiar dengan finetuning model menggunakan Trainer, silakan lihat tutorial dasar di sini!

Anda siap untuk mulai melatih model Anda sekarang! Muat DistilRoBERTa dengan AutoModelForMaskedLM:

>>> from transformers import AutoModelForMaskedLM

>>> model = AutoModelForMaskedLM.from_pretrained("distilbert/distilroberta-base")

Pada titik ini, hanya tersisa tiga langkah:

  1. Definisikan hiperparameter pelatihan Anda di 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).
  2. Lewatkan argumen pelatihan ke Trainer bersama dengan model, dataset, dan data collator.
  3. Panggil train() untuk melakukan finetuning pada model Anda.
>>> training_args = TrainingArguments(
...     output_dir="my_awesome_eli5_mlm_model",
...     eval_strategy="epoch",
...     learning_rate=2e-5,
...     num_train_epochs=3,
...     weight_decay=0.01,
...     push_to_hub=True,
... )

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

>>> trainer.train()

Setelah pelatihan selesai, gunakan metode evaluate() untuk mengevaluasi model Anda dan mendapatkan nilai perplexity-nya:

>>> import math

>>> eval_results = trainer.evaluate()
>>> print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
Perplexity: 8.76

Lalu 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 masked language modeling, lihat notebook PyTorch yang sesuai.

Inferensi

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

Buatlah beberapa teks yang ingin Anda isi oleh model, dan gunakan token khusus <mask> untuk menandai bagian yang kosong:

>>> text = "The Milky Way is a <mask> galaxy."

Cara termudah untuk mencoba model finetune Anda untuk inferensi adalah dengan menggunakannya dalam pipeline(). Buat instans pipeline untuk fill-mask dengan model Anda, lalu berikan teks Anda ke dalamnya. Jika mau, Anda dapat menggunakan parameter top_k untuk menentukan berapa banyak prediksi yang akan dikembalikan:

>>> from transformers import pipeline

>>> mask_filler = pipeline("fill-mask", "username/my_awesome_eli5_mlm_model")
>>> mask_filler(text, top_k=3)
[{'score': 0.5150994658470154,
  'token': 21300,
  'token_str': ' spiral',
  'sequence': 'The Milky Way is a spiral galaxy.'},
 {'score': 0.07087188959121704,
  'token': 2232,
  'token_str': ' massive',
  'sequence': 'The Milky Way is a massive galaxy.'},
 {'score': 0.06434620916843414,
  'token': 650,
  'token_str': ' small',
  'sequence': 'The Milky Way is a small galaxy.'}]

Tokenisasi teks dan kembalikan input_ids sebagai tensor PyTorch. Anda juga perlu menentukan posisi token <mask>:

>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_eli5_mlm_model")
>>> inputs = tokenizer(text, return_tensors="pt")
>>> mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]

Lewatkan input Anda ke model dan kembalikan logits dari token yang dimasker:

>>> from transformers import AutoModelForMaskedLM

>>> model = AutoModelForMaskedLM.from_pretrained("username/my_awesome_eli5_mlm_model")
>>> logits = model(**inputs).logits
>>> mask_token_logits = logits[0, mask_token_index, :]

Kemudian kembalikan tiga token yang dimasker dengan probabilitas tertinggi dan tampilkan:

>>> top_3_tokens = torch.topk(mask_token_logits, 3, dim=1).indices[0].tolist()

>>> for token in top_3_tokens:
...     print(text.replace(tokenizer.mask_token, tokenizer.decode([token])))
The Milky Way is a spiral galaxy.
The Milky Way is a massive galaxy.
The Milky Way is a small galaxy.
Update on GitHub