Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
huggingface
GitHub Repository: huggingface/notebooks
Path: blob/main/transformers_doc/ar/pytorch/masked_language_modeling.ipynb
4542 views
Kernel: Unknown Kernel
# Transformers installation ! pip install transformers datasets evaluate accelerate # To install from source instead of the last release, comment the command above and uncomment the following one. # ! pip install git+https://github.com/huggingface/transformers.git

نمذجة اللغة المقنعة (Masked language modeling)

#@title from IPython.display import HTML HTML('<iframe width="560" height="315" src="https://www.youtube.com/embed/mqElG5QJWUg?rel=0&amp;controls=0&amp;showinfo=0" frameborder="0" allowfullscreen></iframe>')

تتنبأ نمذجة اللغة المقنعة برمز مقنع في تسلسل، ويمكن للنموذج الانتباه إلى الرموز بشكل ثنائي الاتجاه. هذا يعني أن النموذج لديه إمكانية الوصول الكاملة إلى الرموز الموجودة على اليسار واليمين. تعد نمذجة اللغة المقنعة ممتازة للمهام التي تتطلب فهمًا سياقيًا جيدًا لتسلسل كامل. BERT هو مثال على نموذج لغة مقنع.

سيوضح لك هذا الدليل كيفية:

  1. تكييف DistilRoBERTa على مجموعة فرعية r/askscience من مجموعة بيانات ELI5.

  2. استخدام نموذج المدرب الخاص بك للاستدلال.

[removed]

لمعرفة جميع البنى والنسخ المتوافقة مع هذه المهمة، نوصي بالتحقق من صفحة المهمة

قبل أن تبدأ، تأكد من تثبيت جميع المكتبات الضرورية:

pip install transformers datasets evaluate

نحن نشجعك على تسجيل الدخول إلى حساب Hugging Face الخاص بك حتى تتمكن من تحميل ومشاركة نموذجك مع المجتمع. عندما تتم مطالبتك، أدخل رمزك لتسجيل الدخول:

from huggingface_hub import notebook_login notebook_login()

تحميل مجموعة بيانات ELI5

ابدأ بتحميل أول 5000 مثال من مجموعة بيانات ELI5-Category باستخدام مكتبة 🤗 Datasets. سيعطيك هذا فرصة للتجربة والتأكد من أن كل شيء يعمل قبل قضاء المزيد من الوقت في التدريب على مجموعة البيانات الكاملة.

from datasets import load_dataset eli5 = load_dataset("eli5_category", split="train[:5000]")

قم بتقسيم مجموعة البيانات train إلى مجموعتي تدريب واختبار باستخدام الدالة train_test_split:

eli5 = eli5.train_test_split(test_size=0.2)

ثم ألق نظرة على مثال:

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

على الرغم من أن هذا قد يبدو كثيرًا، إلا أنك مهتم حقًا بحقل text. ما هو رائع حول مهام نمذجة اللغة هو أنك لا تحتاج إلى تسميات (تُعرف أيضًا باسم المهمة غير الخاضعة للإشراف) لأن الكلمة التالية هي التسمية.

معالجة مسبقة (Preprocess)

#@title from IPython.display import HTML HTML('<iframe width="560" height="315" src="https://www.youtube.com/embed/8PmhEIXhBvI?rel=0&amp;controls=0&amp;showinfo=0" frameborder="0" allowfullscreen></iframe>')

بالنسبة لنمذجة اللغة المقنعة، فإن الخطوة التالية هي تحميل معالج DistilRoBERTa لمعالجة حقل text الفرعي:

from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("distilbert/distilroberta-base")

ستلاحظ من المثال أعلاه، أن حقل text موجود بالفعل داخل answers. هذا يعني أنك ستحتاج إلى استخراج حقل text الفرعي من بنيته المضمنة باستخدام الدالة 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']}

كل حقل فرعي هو الآن عمود منفصل كما هو موضح بواسطة بادئة answers، وحقل text هو قائمة الآن. بدلاً من معالجة كل جملة بشكل منفصل، قم بتحويل القائمة إلى سلسلة حتى تتمكن من معالجتها بشكل مشترك.

هنا أول دالة معالجة مسبقة لربط قائمة السلاسل لكل مثال ومعالجة النتيجة:

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

لتطبيق دالة المعالجة المسبقة على مجموعة البيانات بأكملها، استخدم الدالة 🤗 Datasets map. يمكنك تسريع دالة map عن طريق تعيين batched=True لمعالجة عدة عناصر في وقت واحد، وزيادة عدد العمليات باستخدام num_proc. احذف أي أعمدة غير ضرورية:

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

تحتوي مجموعة البيانات هذه على تسلسلات رمزية، ولكن بعضها أطول من الطول الأقصى للمدخلات للنموذج.

يمكنك الآن استخدام دالة معالجة مسبقة ثانية لـ:

  • تجميع جميع التسلسلات

  • تقسيم التسلسلات المجمّعة إلى أجزاء أقصر محددة بـ block_size، والتي يجب أن تكون أقصر من الحد الأقصى لطول المدخلات ومناسبة لذاكرة GPU.

block_size = 128 def group_texts(examples): # تجميع جميع النصوص. concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()} total_length = len(concatenated_examples[list(examples.keys())[0]]) # نتجاهل الجزء المتبقي الصغير، يمكننا إضافة الحشو إذا كان النموذج يدعمه بدلاً من هذا الإسقاط، يمكنك # تخصيص هذا الجزء حسب احتياجاتك. if total_length >= block_size: total_length = (total_length // block_size) * block_size # تقسيمها إلى أجزاء بحجم 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

طبق دالة group_texts على مجموعة البيانات بأكملها:

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

الآن، قم بإنشاء دفعة من الأمثلة باستخدام DataCollatorForLanguageModeling. من الأكثر كفاءة أن تقوم بـ الحشو الديناميكي ليصل طولها إلى أطول جملة في الدفعة أثناء التجميع، بدلاً من حشو مجموعة البيانات بأكملها إلى الطول الأقصى.

استخدم رمز نهاية التسلسل كرمز الحشو وحدد mlm_probability لحجب الرموز عشوائياً كل مرة تكرر فيها البيانات:

from transformers import DataCollatorForLanguageModeling tokenizer.pad_token = tokenizer.eos_token data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15)

التدريب (Train)

[removed]

إذا لم تكن على دراية بتعديل نموذج باستخدام Trainer, ألق نظرة على الدليل الأساسي هنا!

أنت مستعد الآن لبدء تدريب نموذجك! قم بتحميل DistilRoBERTa باستخدام AutoModelForMaskedLM:

from transformers import AutoModelForMaskedLM model = AutoModelForMaskedLM.from_pretrained("distilbert/distilroberta-base")

في هذه المرحلة، تبقى ثلاث خطوات فقط:

  1. حدد معلمات التدريب الخاصة بك في TrainingArguments. المعلمة الوحيدة المطلوبة هي output_dir والتي تحدد مكان حفظ نموذجك. ستقوم بدفع هذا النموذج إلى Hub عن طريق تعيين push_to_hub=True (يجب أن تكون مسجلاً الدخول إلى Hugging Face لتحميل نموذجك).

  2. قم بتمرير معلمات التدريب إلى Trainer مع النموذج، ومجموعات البيانات، ومجمّع البيانات.

  3. قم باستدعاء train() لتعديل نموذجك.

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, tokenizer=tokenizer, ) trainer.train()

بمجرد اكتمال التدريب، استخدم طريقة evaluate() لتقييم النموذج والحصول على مقياس الحيرة:

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

ثم شارك نموذجك على Hub باستخدام طريقة push_to_hub() حتى يتمكن الجميع من استخدام نموذجك:

trainer.push_to_hub()
[removed]

لمثال أكثر تفصيلاً حول كيفية تعديل نموذج للنمذجة اللغوية المقنعة، ألق نظرة على الدفتر المقابل دفتر PyTorch أو دفتر TensorFlow.

الاستدلال

رائع، الآن بعد أن قمت بتعديل نموذج، يمكنك استخدامه للاستدلال!

جهّز بعض النصوص التي تريد أن يملأ النموذج الفراغات فيها، واستخدم الرمز الخاص <mask> للإشارة إلى الفراغ:

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

أبسط طريقة لتجربة نموذجك المعدل للاستدلال هي استخدامه في pipeline(). قم بإنشاء كائن pipeline لملء الفراغ مع نموذجك، ومرر نصك إليه. إذا أردت، يمكنك استخدام معلمة top_k لتحديد عدد التنبؤات التي تريد إرجاعها:

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

قم بتجزئة النص وإرجاع input_ids كمتجهات PyTorch. ستحتاج أيضًا إلى تحديد موضع رمز <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]

قم بتمرير المدخلات إلى النموذج وإرجاع logits للرمز المقنع:

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, :]

ثم قم بإرجاع الرموز الثلاثة المقنعة ذات الاحتمالية الأعلى وطباعتها:

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.