اذهب إلى المحتوى

البحث في الموقع

المحتوى عن 'huggingface'.

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المحتوى


التصنيفات

  • الإدارة والقيادة
  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • السلوك التنظيمي في المؤسسات
  • عالم الأعمال
  • التجارة والتجارة الإلكترونية
  • نصائح وإرشادات
  • مقالات ريادة أعمال عامة

التصنيفات

  • مقالات برمجة عامة
  • مقالات برمجة متقدمة
  • PHP
    • Laravel
    • ووردبريس
  • جافاسكربت
    • لغة TypeScript
    • Node.js
    • React
    • Vue.js
    • Angular
    • jQuery
    • Cordova
  • HTML
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • لغة C#‎
    • ‎.NET
    • منصة Xamarin
  • لغة C++‎
  • لغة C
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • لغة Rust
  • برمجة أندرويد
  • لغة R
  • الذكاء الاصطناعي
  • صناعة الألعاب
  • سير العمل
    • Git
  • الأنظمة والأنظمة المدمجة

التصنيفات

  • تصميم تجربة المستخدم UX
  • تصميم واجهة المستخدم UI
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب GIMP
    • كريتا Krita
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • مقالات DevOps عامة
  • خوادم
    • الويب HTTP
    • البريد الإلكتروني
    • قواعد البيانات
    • DNS
    • Samba
  • الحوسبة السحابية
    • Docker
  • إدارة الإعدادات والنشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
    • ريدهات (Red Hat)
  • خواديم ويندوز
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • شبكات
    • سيسكو (Cisco)

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح
  • مبادئ علم التسويق

التصنيفات

  • مقالات عمل حر عامة
  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • العمل الحر المهني
    • العمل بالترجمة
    • العمل كمساعد افتراضي
    • العمل بكتابة المحتوى

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

  • الأقسام
    • أسئلة البرمجة
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات

التصنيفات

  • كتب ريادة الأعمال
  • كتب العمل الحر
  • كتب تسويق ومبيعات
  • كتب برمجة
  • كتب تصميم
  • كتب DevOps

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

تاريخ الانضمام

  • بداية

    نهاية


المجموعة


النبذة الشخصية

تم العثور على 18 نتائج

  1. سنتعرف في هذا المقال على الصنف Trainer في مكتبة المحولات Transformers ضمن منصة Hugging Face، ونوضح طريقة الاستفادة منه في تدريب النماذج اللغوية الكبيرة، كما سنتعرف أيضًا على أصناف عديدة تفيدنا في تحسين وتسريع عملية التدريب. ما هو الصنف Trainer الصنف Trainer هو أداة تُسهّل تدريب النماذج المبنية باستخدام باي تورش PyTorch في مكتبة المحولات Transformers. فبدلًا من أن نضطر لكتابة الشيفرة الخاصة بتدريب النموذج من البداية، يتيح لنا هذا الصنف تمرير العناصر الأساسية مثل النموذج Model، والمُرمِّز Tokenizer، ومجموعة البيانات Dataset، ودالة التقييم Evaluation Function، ومعاملات التدريب الفائقة Hyperparameters، والبدء بعدها بالتدريب بسرعة دون الحاجة للتعامل مع الكثير من التفاصيل والإعدادات يدويًا، كما أن الصنف Trainer قابل للتخصيص وبإمكاننا تعديل إعداداته بما يوافق احتياجاتنا. توفر مكتبة Transformers أيضًا الصنف Seq2SeqTrainer الذي يساعدنا في مهام تتطلب تحويل سلسلة نصية إلى سلسلة نصية أخرى مثل الترجمة أو التلخيص. يوجد أيضًا الصنف SFTTrainer من مكتبة TRL التي تغلِّف الصنف Trainer وهي مُحسَّنة لتدريب النماذج اللغوية مثل Llama-2 و Mistral باستخدام تقنيات الانحدار التلقائي Autoregressive التي تُمكِّن النموذج اللغوي من توليد النصوص بناءً على تسلسل الكلمات السابقة، مما يُحسن أداءه، ويدعم الصنف SFTTrainer أيضًا ميزات أخرى مثل Sequence Packing و LoRA وQuantization و DeepSpeed للتوسّع بكفاءة إلى أيّ حجم نموذج نحتاجه، مما يجعله مثاليًا لتدريب النماذج اللغوية المتقدمة. ملاحظة: يُستحسن الاطلاع على توثيق Trainer لمعرفة المزيد حول الأصناف المختلفة ومتى نستخدم كل منها، فالصنف Trainer هو الخيار الأكثر تنوعًا ويناسب مجموعة واسعة من المهام، والصنف Seq2SeqTrainer مناسب لمهام تتطلب حويل تسلسل نصي إلى تسلسل نصي آخر كالترجمة والتلخيص، أما الصنف SFTTrainer فهو مناسب لتدريب النماذج اللغوية المتقدمة. قبل البدء باستخدام الصنف Trainer، لنتأكد من تثبيت مكتبة Accelerate المفيدة لتفعيل وتشغيل تدريب نماذج باي تورش PyTorch في البيئات الموزعة بسرعة من خلال الأمر التالي: pip install accelerate # للترقية pip install accelerate --upgrade سنوفر في الفقرات التالية نظرة عامة على الصنف Trainer وطريقة استخدامه في مكتبة المحوّلات Transformers. الاستخدام الأساسي للصنف Trainer يتضمن الصنف Trainer الشيفرة البرمجية الموجودة في حلقة تدريب أساسية، والتي تتضمن ما يلي: إجراء خطوة تدريب لحساب الخسارة حساب التدرجات Gradients باستخدام التابع backward تحديث الأوزان بناءً على التدرجات تكرار هذه العملية حتى الوصول إلى عدد محدَّد مسبقًا من دورات التدريب Epochs يجرّد الصنف Trainer هذه الشيفرة حتى لا نضطر إلى القلق بشأن كتابة حلقة تدريب يدويًا في كل مرة، أو إذا كنا مبتدئين في استخدام إطار عمل PyTorch وإجراء عملية التدريب من خلاله، فما علينا سوى توفير المكوّنات الأساسية المطلوبة للتدريب كالنموذج ومجموعة البيانات، وسيتولى الصنف Trainer التعامل مع الأمور الأخرى نيابة عنا. في حال أردنا تحديد خيارات التدريب فيمكننا العثور عليها في الصنف TrainingArguments. لنحدّد مثلًا مكان حفظ النموذج في المعامل output_dir ودفع النموذج إلى مستودع Hub بعد التدريب باستخدام المعامل push_to_hub=True كما يلي: from transformers import TrainingArguments training_args = TrainingArguments( output_dir="your-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, ) بعد إنشاء training_args علينا تمريره للصنف Trainer إلى جانب النموذج، ومجموعة البيانات، والمُعالِج المسبق لمجموعة البيانات إذ يمكن أن يكون هذا المُعالِج مرمِّزًا أو مستخرج ميزات أو معالج صور حسب نوع بياناتنا، كذلك علينا تمرير مجمِّع بيانات ودالة لحساب المقاييس التي نريد تتبعها أثناء التدريب، ثم نستدعي التابع train()‎ لبدء التدريب كما يلي: from transformers import Trainer trainer = Trainer( model=model, args=training_args, train_dataset=dataset["train"], eval_dataset=dataset["test"], tokenizer=tokenizer, data_collator=data_collator, compute_metrics=compute_metrics, ) trainer.train() نقاط التحقق Checkpoints يحفظ الصنف Trainer نقاط التحقق Checkpoints الخاصة بنموذجنا في المجلد المحدد في المعامل output_dir الخاص بالصنف TrainingArguments، حيث سنجد نقاط التحقق محفوظة في المجلد الفرعي checkpoint-000 وتقابل الأرقام في النهاية خطوة التدريب، ويُعَد حفظ نقاط التحقق مفيدًا لاستئناف التدريب لاحقًا. # الاستئناف من نقطة التحقق الأخيرة trainer.train(resume_from_checkpoint=True) # الاستئناف من نقطة تحقق مُحدَّدة محفوظة في مجلد الخرج trainer.train(resume_from_checkpoint="your-model/checkpoint-1000") يمكننا حفظ نقاط التحقق الخاصة بنموذجنا، ولكن حالة المُحسِّن لن تُحفَظ افتراضيًا في مستودع Hub، فكي نحفظها يجب علينا ضبط المعامل push_to_hub=True في الصنف TrainingArguments لإيداعها Commit ودفعها إلى المستودع. فيما يلي بعض الخيارات الأخرى التي يمكننا استخدامها لتحديد كيفية حفظ نقاط التحقق وإعدادها من خلال المعامل hub_strategy. يدفع الخيار hub_strategy="checkpoint"‎ أحدث نقطة تحقق إلى مجلد فرعي باسم last-checkpoint ، والذي يمكننا استئناف التدريب منه يدفع الخيار hub_strategy="all_checkpoints"‎ جميع نقاط التحقق إلى المجلد المحدَّد في المعامل output_dir، حيث سنرى نقطة تحقق واحدة لكل مجلد في مستودع النموذج عند استئناف التدريب من نقطة تحقق محفوظة سابقًا، يحاول الصنف Trainer أن يحتفظ بنفس حالة الأرقام العشوائية RNG التي كانت في وقت الحفظ، سواء في Python أو NumPy أو PyTorch. ولكن بسبب بعض الإعدادات الافتراضية في باي تورش PyTorch، قد لا تكون الأرقام العشوائية هي نفسها عند استئناف التدريب. فإذا كنا نرغب في جعل كل شيء يحدث بنفس الطريقة تمامًا في كل مرة، يمكن تعديل بعض الإعدادات لجعل التدريب ينفذ دومًا بنفس الطريقة، لكن يجب أن نضع بالحسبان أن هذا قد يجعل التدريب أبطأ قليلاً، ويمكن الرجوع إلى دليل التحكم في العشوائية في PyTorch لمطالعة هذه الإعدادات التي يتوجب تفعيلها لتحقيق ذلك. تخصيص الصنف Trainer صُمِّم الصنف Trainer ليكون سهل الاستخدام والوصول، وهو يتميز أيضًا بسهولة التخصيص، إذ يمكننا إنشاء أصناف فرعية للعديد من توابع الصنف وتعديلها لدعم الوظيفة التي نريدها دون الحاجة إلى إعادة كتابة حلقة التدريب بالكامل من الصفر كي تتوافق مع هذه الوظيفة، وتتضمن هذه التوابع ما يلي: ينشئ التابع get_train_dataloader()‎ صنف DataLoader للتدريب ينشئ التابع get_eval_dataloader()‎ صنف DataLoader للتقييم ينشئ التابع get_test_dataloader()‎ صنف DataLoader للاختبار يسجّل التابع log()‎ معلومات حول الكائنات المختلفة التي تراقب التدريب يستخدم التابع create_optimizer_and_scheduler()‎ لإعداد المحسّن optimizer ومُجَدوِل معدل التعلم learning rate scheduler، ويمكن التخصيص أيضًا باستخدام التابعين create_optimizer()‎ و create_scheduler()‎ يحسب التابع compute_loss()‎ الخسارة على دفعة من دخل التدريب يجري التابع training_step()‎ خطوة التدريب يجري التابع prediction_step()‎ خطوة التنبؤ والاختبار يقيّم التابع evaluate()‎ النموذج ويعيد مقاييس التقييم يجري التابع predict()‎ تنبؤات على مجموعة الاختبار باستخدام المقاييس إذا كانت التسميات Labels متاحة يمكننا مثلًا تخصيص التابع compute_loss()‎ لاستخدام خسارة موزونة weighted loss كما يلي: from torch import nn from transformers import Trainer class CustomTrainer(Trainer): def compute_loss(self, model, inputs, return_outputs=False): labels = inputs.pop("labels") # تمرير أمامي outputs = model(**inputs) logits = outputs.get("logits") # حساب الخسارة المخصَّصة لثلاثة تسميات توضيحية بأوزان مختلفة loss_fct = nn.CrossEntropyLoss(weight=torch.tensor([1.0, 2.0, 3.0], device=model.device)) loss = loss_fct(logits.view(-1, self.model.config.num_labels), labels.view(-1)) return (loss, outputs) if return_outputs else loss دوال رد النداء Callbacks يوجد خيار آخر لتخصيص الصنف Trainer وهو استخدام دوال رد النداء Callbacks، لا تُغيّر هذه الدوال في حلقة التدريب نفسها، بل تراقب حالة الحلقة وتنفذ بعض الإجراءات مثل التوقف المبكر عن التنفيذ، أو تسجيل النتائج استنادًا إلى الحالة الحالية، وبالتالي لا يمكن استخدام دالة رد نداء لتنفيذ شيءٍ مخصص كتعريف دالة خسارة مخصَّصة باستخدامها، بل يجب في هذه الحالة إنشاء صنف فرعي وتعديل التابع compute_loss()‎ ضمنه. على سبيل المثال، يمكننا إضافة دالة رد نداء للتوقف المبكر بعد 10 خطوات في حلقة التدريب على النحو التالي: from transformers import TrainerCallback class EarlyStoppingCallback(TrainerCallback): def __init__(self, num_steps=10): self.num_steps = num_steps def on_step_end(self, args, state, control, **kwargs): if state.global_step >= self.num_steps: return {"should_training_stop": True} else: return {} ثم نمرّرها إلى المعامل callback الخاص بالصنف Trainer كما يلي: from transformers import Trainer trainer = Trainer( model=model, args=training_args, train_dataset=dataset["train"], eval_dataset=dataset["test"], tokenizer=tokenizer, data_collator=data_collator, compute_metrics=compute_metrics, callback=[EarlyStoppingCallback()], ) التسجيل Logging يمكننا من خلال ضبط مستوى التسجيل Logging التحكم في كمية وتفاصيل المعلومات المسجلة أثناء تنفيذ الشيفرات البرمجية، وهذا يساعدنا في تتبع الأداء واكتشاف الأخطاء بشكل فعال حسب الحاجة. يُضبَط الصنف Trainer على المستوى logging.INFO افتراضيًا والذي يبلّغ عن الأخطاء والتحذيرات والمعلومات الأساسية الأخرى، وتُضبَط نسخة الصنف Trainer في البيئات الموزعة على المستوى logging.WARNING الذي يبلّغ عن الأخطاء والتحذيرات فقط. يمكننا تغيير مستوى التسجيل باستخدام المعاملات log_level و log_level_replica في الصنف TrainingArguments. كما يمكن ضبط إعداد مستوى السجل لكل جهاز من خلال استخدام المعامل log_on_each_node لتحديد استخدام مستوى السجل على كل جهاز أو على الجهاز الرئيسي فقط إذا كنا نعمل في بيئة تحتوي على أجهزة متعددة. ملاحظة1: من المفيد مطالعة توثيق واجهة برمجة التطبيقات الخاصة بالتسجيل Logging للحصول على مزيد من المعلومات حول مستويات التسجيل المختلفة ودور كل منها. ملاحظة2: يحدّد الصنف Trainer مستوى السجل بطريقة منفصلة لكل جهاز في التابع Trainer.__init__()‎ المسؤول عن تهيئة كائن التدريب، لذا قد نرغب في التفكير في ضبط مستوى السجل مبكرًا في حال استخدمنا دوال مكتبة المحوّلات Transformers الأخرى قبل إنشاء الكائن. يمكن مثلًا ضبط الشيفرة البرمجية الرئيسية لاستخدام مستوى السجل نفسه وفقًا لكل جهاز كما يلي: logger = logging.getLogger(__name__) logging.basicConfig( format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", datefmt="%m/%d/%Y %H:%M:%S", handlers=[logging.StreamHandler(sys.stdout)], ) log_level = training_args.get_process_log_level() logger.setLevel(log_level) datasets.utils.logging.set_verbosity(log_level) transformers.utils.logging.set_verbosity(log_level) trainer = Trainer(...) استخدمنا مجموعات مختلفة من المعاملات log_level و log_level_replica لضبط ما يُسجَّل على كل جهاز، حيث إذا كان لدينا جهاز واحد، فنستخدم ما يلي: my_app.py ... --log_level warning --log_level_replica error ونضيف المعامل log_on_each_node 0 للبيئات متعددة الأجهزة كما يلي: my_app.py ... --log_level warning --log_level_replica error --log_on_each_node 0 # الضبط للإبلاغ عن الأخطاء فقط my_app.py ... --log_level error --log_level_replica error --log_on_each_node 0 تقنية NEFTune تقنية NEFTune هي طريقة لتحسين أداء النموذج أثناء التدريب عن طريق إضافة ضجيج Noise إلى البيانات المستخدمة لتدريب النموذج. وما نعنيه بالضجيج هنا إضافة بعض التغييرات العشوائية إلى البيانات للمساعدة في تحسين قدرة النموذج على التعميم وعدم حفظ التفاصيل الزائدة التي قد تؤدي إلى مشكلات في الأداء، فعند استخدام NEFTune، يجري تعديل طبقة التضمين أي التمثيل الرياضي للبيانات داخل النموذج بإضافة الضجيج إليها، مما يساعد في تدريب النموذج بمرونة أكبر. يمكننا تفعيل هذه التقنية في الصنف Trainer من خلال ضبط المعامل neftune_noise_alpha داخل الصنف TrainingArguments، فهذا المعامل يحدد مقدار الضجيج الذي سيُضاف إلى طبقة التضمين أثناء التدريب كما في المثال التالي: from transformers import TrainingArguments, Trainer training_args = TrainingArguments(..., neftune_noise_alpha=0.1) trainer = Trainer(..., args=training_args) بعد الانتهاء من التدريب، تُعطَّل تقنية NEFTune لاستعادة الطبقة الأصلية للتضمين بدون أي تعديلات عشوائية وتجنب أيّ سلوك غير متوقّع. استراتيجية التدريب GaLore إسقاط التدرج منخفض الرتبة Gradient Low-Rank Projection -أو GaLore اختصارًا- هي استراتيجية تدريب منخفضة الرتبة وتتميز بكفاءة في استخدام الذاكرة وتسمح بالتعلم الكامل للمعاملات، ولكنها أكثر كفاءة في استخدام الذاكرة من طرق التكيف منخفضة الرتبة التقليدية مثل LoRA. توفر هذه الاستراتيجية أداءً جيدًا باستخدامها ذاكرة أقل، مما يجعلها خيارًا ممتازًا للاستخدام في تدريب النماذج الكبيرة، قبل البدء باستخدام GaLore، علينا التأكد من تثبيت المستودع الرسمي الخاص بها باستخدام الأمر التالي: pip install galore-torch نحتاج بعد ذلك إلى تحديد كيفية تحسين النموذج بشكل دقيق وإضافة بعض الخيارات التي تحدد طريقة التحسين وأيضًا تحديد الوحدات المستهدفة التي نريد تعديلها، حيث نضيف الخيارات ["galore_adamw", "galore_adafactor", "galore_adamw_8bit"] في المعامل optim مع المعامل optim_target_modules الذي يمكن أن يكون قائمة من السلاسل النصية أو التعابير النمطية Regex أو مسارًا كاملًا مطابقًا لأسماء وحدات النموذج المستهدفة التي نريد تكييفها أثناء عملية التدريب. فيما يلي مثال لسكربت لتدريب نموذج باستخدام مكتبة GaLore، لكن علينا التأكّد من استخدام الأمر التالي أولًا قبل تشغيل السكربت pip install trl datasets وفيما يلي السكربت المطلوب: import torch import datasets import trl from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM train_dataset = datasets.load_dataset('imdb', split='train') args = TrainingArguments( output_dir="./test-galore", max_steps=100, per_device_train_batch_size=2, optim="galore_adamw", optim_target_modules=["attn", "mlp"] ) model_id = "google/gemma-2b" config = AutoConfig.from_pretrained(model_id) tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_config(config).to(0) trainer = trl.SFTTrainer( model=model, args=args, train_dataset=train_dataset, dataset_text_field='text', max_seq_length=512, ) trainer.train() يمكننا تمرير الوسطاء الإضافية التي تدعمها GaLore من خلال تمرير المعامل optim_args كما يلي: import torch import datasets import trl from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM train_dataset = datasets.load_dataset('imdb', split='train') args = TrainingArguments( output_dir="./test-galore", max_steps=100, per_device_train_batch_size=2, optim="galore_adamw", optim_target_modules=["attn", "mlp"], optim_args="rank=64, update_proj_gap=100, scale=0.10", ) model_id = "google/gemma-2b" config = AutoConfig.from_pretrained(model_id) tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_config(config).to(0) trainer = trl.SFTTrainer( model=model, args=args, train_dataset=train_dataset, dataset_text_field='text', max_seq_length=512, ) trainer.train() يمكن مطالعة المزيد عن هذه طريقة GaLore في المستودع الأصلي. يمكننا حاليًا تدريب الطبقات الخطية فقط باستخدام طريقة GaLore التي تستخدم طريقة التفكك منخفض الرتبة Low-Rank Decomposition، بينما ستظل الطبقات المتبقية تًدرّب وتُحسَّن بالطريقة التقليدية. وسنلاحظ أن عملية التحضير لبدء التدريب تستغرق بعض الوقت مثلًا 3 دقائق لنموذج 2B على NVIDIA A100 ولكن يجب أن يعمل التدريب بسلاسة بعد ذلك. يمكننا أيضًا إجراء تحسين على مستوى الطبقة من خلال إضافة الكلمة layerwise إلى نهاية اسم المحسِّن كما يلي: import torch import datasets import trl from transformers import TrainingArguments, AutoConfig, AutoTokenizer, AutoModelForCausalLM train_dataset = datasets.load_dataset('imdb', split='train') args = TrainingArguments( output_dir="./test-galore", max_steps=100, per_device_train_batch_size=2, optim="galore_adamw_layerwise", optim_target_modules=["attn", "mlp"] ) model_id = "google/gemma-2b" config = AutoConfig.from_pretrained(model_id) tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_config(config).to(0) trainer = trl.SFTTrainer( model=model, args=args, train_dataset=train_dataset, dataset_text_field='text', max_seq_length=512, ) trainer.train() نلاحظ أن التحسين على مستوى الطبقة Layer-wise Optimization تجريبي بعض الشيء ولا يدعم توزيع البيانات Distributed Data Parallel أو DDP اختصارًا، وبالتالي عند استخدام هذا النوع من التحسين فقد تتمكن من تشغيل التدريب على وحدة معالجة رسومية GPU واحدة فقط. محسّن LOMO محسّن LOMO هو أداة تُستخدم لتحسين النماذج اللغوية الكبيرة عندما تكون الموارد محدودة، وهو يساعد على تقليل استخدام الذاكرة أثناء التدريب. يُعد AdaLomo نوعًا من محسنات LOMO، وهو يعتمد على تقنية التعلم التكيفي Adaptive Learning لتحديث المعاملات بكفاءة، مما يعزز الأداء مع الحفاظ على استهلاك منخفض للذاكرة. يعمل محسّن LOMO عن طريق دمج حساب التدرج وتحديث المعاملات في خطوة واحدة، مما يساعد على تسريع عملية التدريب وتقليل الحاجة إلى الذاكرة. المحسنات المتاحة في LOMO هي lomo و adalomo . ملاحظة: يُوصَى باستخدام محسّن AdaLomo بدون تفعيل خيار حساب تدرجات النموذج grad_norm للحصول على أداء أفضل وإنتاجية أعلى. نثبّت أولًا LOMO من مستودع Pypi باستخدام الأمر التالي: pip install lomo-optim أو نثبّته من المصدر باستخدام الأمر التالي: pip install git+https://github.com/OpenLMLab/LOMO.git. فيما يلي سكربت بسيط يوضح كيفية صقل نموذج google/gemma-2b مع مجموعة بيانات IMDB بدقة كاملة: import torch import datasets from transformers import TrainingArguments, AutoTokenizer, AutoModelForCausalLM import trl train_dataset = datasets.load_dataset('imdb', split='train') args = TrainingArguments( output_dir="./test-lomo", max_steps=1000, per_device_train_batch_size=4, optim="adalomo", gradient_checkpointing=True, logging_strategy="steps", logging_steps=1, learning_rate=2e-6, save_strategy="no", run_name="lomo-imdb", ) model_id = "google/gemma-2b" tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_pretrained(model_id, low_cpu_mem_usage=True).to(0) trainer = trl.SFTTrainer( model=model, args=args, train_dataset=train_dataset, dataset_text_field='text', max_seq_length=1024, ) trainer.train() مكتبة Accelerate والصنف Trainer يعتمد الصنف Trainer على مكتبة Accelerate، والتي هي مكتبة لتدريب نماذج PyTorch بسهولة في البيئات الموزعة مع دعم التكاملات Integrations مثل FullyShardedDataParallel -أو FSDP اختصارًا- و DeepSpeed. ملاحظة: يمكن مطالعة المزيد حول استراتيجيات تجزئة FSDP أو FSDP Sharding وتفريغ وحدة المعالجة المركزية CPU Offloading وغير ذلك باستخدام الصنف Trainer في دليل FSDP. يمكننا استخدام مكتبة Accelerate مع الصنف Trainer من خلال تشغيل أمر accelerate.config لإعداد التدريب لبيئة التدريب الخاصة بنا، حيث ينشئ هذا الأمر ملف config_file.yaml الذي سيُستخدَم عند تشغيل سكربت التدريب. فيما يلي مثلًا بعض عمليات الضبط النموذجية التي يمكننا إعدادها: عند استخدام DistributedDataParallel: compute_environment: LOCAL_MACHINE distributed_type: MULTI_GPU downcast_bf16: 'no' gpu_ids: all machine_rank: 0 # تغيير الرتبة حسب الجهاز main_process_ip: 192.168.20.1 main_process_port: 9898 main_training_function: main mixed_precision: fp16 num_machines: 2 num_processes: 8 rdzv_backend: static same_network: true tpu_env: [] tpu_use_cluster: false tpu_use_sudo: false use_cpu: false عند استخدام FSDP: compute_environment: LOCAL_MACHINE distributed_type: FSDP downcast_bf16: 'no' fsdp_config: fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP fsdp_backward_prefetch_policy: BACKWARD_PRE fsdp_forward_prefetch: true fsdp_offload_params: false fsdp_sharding_strategy: 1 fsdp_state_dict_type: FULL_STATE_DICT fsdp_sync_module_states: true fsdp_transformer_layer_cls_to_wrap: BertLayer fsdp_use_orig_params: true machine_rank: 0 main_training_function: main mixed_precision: bf16 num_machines: 1 num_processes: 2 rdzv_backend: static same_network: true tpu_env: [] tpu_use_cluster: false tpu_use_sudo: false use_cpu: false عند استخدام DeepSpeed: compute_environment: LOCAL_MACHINE deepspeed_config: deepspeed_config_file: /home/user/configs/ds_zero3_config.json zero3_init_flag: true distributed_type: DEEPSPEED downcast_bf16: 'no' machine_rank: 0 main_training_function: main num_machines: 1 num_processes: 4 rdzv_backend: static same_network: true tpu_env: [] tpu_use_cluster: false tpu_use_sudo: false use_cpu: false عند استخدام DeepSpeed مع إضافة Accelerate: compute_environment: LOCAL_MACHINE deepspeed_config: gradient_accumulation_steps: 1 gradient_clipping: 0.7 offload_optimizer_device: cpu offload_param_device: cpu zero3_init_flag: true zero_stage: 2 distributed_type: DEEPSPEED downcast_bf16: 'no' machine_rank: 0 main_training_function: main mixed_precision: bf16 num_machines: 1 num_processes: 4 rdzv_backend: static same_network: true tpu_env: [] tpu_use_cluster: false tpu_use_sudo: false use_cpu: false يُعَد أمر accelerate_launch الطريقة الموصَى بها لتشغيل سكربت التدريب على نظام موزع باستخدام مكتبة Accelerate والصنف Trainer مع المعاملات المُحدَّدة في الملف config_file.yaml الذي يُحفَظ في مجلد ذاكرة التخزين المؤقت للمكتبة Accelerate ويُحمَّل تلقائيًا عند تشغيل أمر accelerate_launch. يمكننا مثلًا تشغيل سكربت التدريب run_glue.py مع ضبط FSDP كما يلي: accelerate launch \ ./examples/pytorch/text-classification/run_glue.py \ --model_name_or_path google-bert/bert-base-cased \ --task_name $TASK_NAME \ --do_train \ --do_eval \ --max_seq_length 128 \ --per_device_train_batch_size 16 \ --learning_rate 5e-5 \ --num_train_epochs 3 \ --output_dir /tmp/$TASK_NAME/ \ --overwrite_output_dir ويمكن تحديد المعاملات من الملف config_file.yaml في سطر الأوامر كما يلي: accelerate launch --num_processes=2 \ --use_fsdp \ --mixed_precision=bf16 \ --fsdp_auto_wrap_policy=TRANSFORMER_BASED_WRAP \ --fsdp_transformer_layer_cls_to_wrap="BertLayer" \ --fsdp_sharding_strategy=1 \ --fsdp_state_dict_type=FULL_STATE_DICT \ ./examples/pytorch/text-classification/run_glue.py --model_name_or_path google-bert/bert-base-cased \ --task_name $TASK_NAME \ --do_train \ --do_eval \ --max_seq_length 128 \ --per_device_train_batch_size 16 \ --learning_rate 5e-5 \ --num_train_epochs 3 \ --output_dir /tmp/$TASK_NAME/ \ --overwrite_output_dir ويمكن مطالعة المقال الخاص بتشغيل سكربتات Accelerate على منصة Huggingface لمعرفة المزيد حول أمر accelerate_launch وعمليات الضبط المخصَّصة. الخاتمة وصلنا لختام مقالنا الذي وضحنا فيه استخدام صنف التدريب Trainer من مكتبة Transformers وتعرفنا على طريقة استخدامه وإعداد البيانات والنماذج ومعاملات التدريب التي سيستخدمها، كما ناقشنا أهم المزايا التي يقدمها هذا الصنف والتي تجعله خيارًا مثاليًا لتسريع تدريب النماذج وتحسين أدائها. ننصحكم بتجربة التقنيات التي شرحناها في هذا المقال والاستفادة منها في تحسين مشاريع الذكاء الاصطناعي. ترجمة -وبتصرّف- للقسم Trainer من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: استخدام قوالب الدردشة Chat Templates للنماذج اللغوية الكبيرة LLMs إنشاء بنية مخصصة لنماذج Transformers في Hugging Face تعرف على مكتبة المحوّلات Transformers من منصة Hugging Face مشاركة نموذج ذكاء اصطناعي على منصة Hugging Face
  2. نشرح في هذا المقال قوالب الدردشة Chat Templates واستخدامها في النماذج اللغوية الكبيرة LLMs، فالدردشة تعتمد على محادثات مكونة من سلسلة رسائل متعددة بدلاً من النصوص المنفصلة كما هو الحال في النماذج اللغوية التقليدية، كما تحتوي كل رسالة في المحادثة على دور محدد مثل المستخدم User أو المساعد Assistant، بالإضافة إلى محتوى نص الرسالة، وبالتالي نحتاج إلى طريقة منظمة لتحويلها لصيغة تُمكّن النموذج Model من فهمها ومعالجتها بشكل صحيح وإنتاج استجابات ملائمة لها. تتمثل وظيفة القوالب Chat Templates في تحويل هذه المحادثات إلى تنسيق يمكن للنموذج Model تحليله وفهمه بطريقة مناسبة تمامًا كما هو الحال في عملية الترميز Tokenization. وتُعدّ القوالب جزءًا أساسيًا من عملية التحضير للنموذج فهي تعمل كآلية تنظم تحويل المحادثات المكونة من قوائم من الرسائل مثل رسائل المستخدم وردود المساعد، إلى سلسلة نصية واحدة متكاملة ومُهيَّأة بطريقة تناسب متطلبات النموذج، مما يضمن فهم النموذج للمدخلات بشكل صحيح ومعالجتها بكفاءة. مثال على قالب الدردشة باستخدام نموذج BlenderBot لنوضّح مثال على استخدام قالب دردشة باستخدام النموذج BlenderBot الذي يحتوي على قالب افتراضي بسيط مهمته إضافة مسافة أو فراغ بين الرسائل المتبادلة والمنفصلة عن بعضها لتصبح عبارة عن سلسلة نصية واحدة يستطيع النموذج معالجتها بسهولة، بدلاً من التعامل مع كل رسالة بشكل منفصل: from transformers import AutoTokenizer # تحميل المحول tokenizer = AutoTokenizer.from_pretrained("facebook/blenderbot-400M-distill") # إعداد المحادثة chat = [ {"role": "user", "content": "مرحبًا، كيف حالك؟"}, {"role": "assistant", "content": "أنا بخير. كيف يمكنني مساعدتك اليوم؟"}, {"role": "user", "content": "أريد أن أظهر كيفية عمل قوالب الدردشة!"}, ] # تطبيق قالب الدردشة tokenizer.apply_chat_template(chat, tokenize=False) سنلاحظ بعدها اختصار المحادثة بأكملها في سلسلة نصية واحدة. وإذا استخدمنا الإعداد الافتراضي tokenize=True، فستخضع هذه السلسلة النصية لتحويل وستُرمَّز هذه السلسلة النصية بشكل وحدات ترميز tokens. ملاحظة: وحدات الترميز tokens هي الأجزاء الأصغر من النص التي يمكن للنموذج معالجتها. مثال على قالب الدردشة باستخدام نموذج Mistral-7B-Instruct لنستخدم الآن مثالًا أكثر تعقيدًا وهو النموذج mistralai/Mistral-7B-Instruct-v0.1 للمحادثة ونوضح كيفية استخدام قالب دردشة مختلف يختلف عن النموذج البسيط السابق BlenderBot. from transformers import AutoTokenizer # تحميل المحول tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1") # إعداد المحادثة chat = [ {"role": "user", "content": "مرحبًا، كيف حالك؟"}, {"role": "assistant", "content": "أنا بخير. كيف يمكنني مساعدتك اليوم؟"}, {"role": "user", "content": "أريد أن أشرح كيفية عمل قالب الدردشة!"}, ] # تطبيق قالب الدردشة بدون ترميز بشكل tokens formatted_chat = tokenizer.apply_chat_template(chat, tokenize=False) # طباعة النتيجة print(formatted_chat) نلاحظ هنا أن المرمِّز أضاف رموز التحكم [INST] و ‎[/INST]‎ هذه المرة للإشارة إلى بداية ونهاية رسائل المستخدم دون استخدامها مع رسائل المساعد، تساعد هذه الرموز النموذج على فهم الرسائل بشكل أفضل لأنها تتماشى مع الطريقة التي تدرب عليها، حيث دُرِّب النموذج الحالي باستخدام هذه الرموز على عكس النموذج BlenderBot. طريقة استخدام قوالب الدردشة قوالب الدردشة سهلة الاستخدام، فلاستخدامها ليس علينا سوى إنشاء قائمة بالرسائل مع مفاتيح الدور role والمحتوى content، ثم تمريرها إلى التابع apply_chat_template()‎، وسنحصل على خرج جاهز للاستخدام. يُفضَّل أيضًا استخدام add_generation_prompt=True لإضافة موجِّه توليد Generation Prompt عند استخدام قوالب الدردشة كدخل لتوليد النموذج. فيما يلي مثال لتجهيز الدخل للتابع model.generate()‎ باستخدام النموذج المساعد Zephyr: from transformers import AutoModelForCausalLM, AutoTokenizer # تعيين نقطة التحقق checkpoint = "HuggingFaceH4/zephyr-7b-beta" tokenizer = AutoTokenizer.from_pretrained(checkpoint) model = AutoModelForCausalLM.from_pretrained(checkpoint) # قد ترغب باستخدام تنسيق bfloat16 أو الانتقال إلى وحدة معالجة الرسومات GPU هنا # إعداد الرسائل messages = [ { "role": "system", "content": "أنت روبوت دردشة ودود ترد دائمًا بأسلوب القراصنة", }, {"role": "user", "content": "كم عدد الطائرات المروحية التي يمكن للإنسان تناولها في وجبة واحدة؟"}, ] # تطبيق قالب الدردشة وتحويله لشكل ملائم للنموذج tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt") # طباعة النص المستخرج بعد فك الترميز print(tokenizer.decode(tokenized_chat[0])) سيؤدي ذلك إلى الحصول على سلسلة نصية بتنسيق الدخل الذي يتوقعه النموذج Zephyr كما يلي: <|system|> أنت روبوت دردشة ودود يرد دائمًا بأسلوب القراصنة </s> <|user|> كم عدد الطائرات المروحية التي يمكن للإنسان تناولها في جلسة واحدة؟ </s> <|assistant|> نسّقنا الدخل ليناسب النموذج Zephyr وذلك على النحو التالي: <|system|>: يحدد أن المساعد هو روبوت دردشة ودود ويجب أن يجيب دائمًا بأسلوب القراصنة <|user|>: يحدد أن المستخدم يطرح السؤال <|assistant|>: يحدد الموضع الذي سيظهر فيه رد المساعد يمكننا الآن استخدام النموذج لتوليد استجابة لسؤال المستخدم كما يلي: outputs = model.generate(tokenized_chat, max_new_tokens=128) print(tokenizer.decode(outputs[0])) وسنحصل على النتيجة التالية: <|system|> أنت روبوت دردشة ودود يرد دائمًا بأسلوب القراصنة </s> <|user|> كم عدد الطائرات المروحية التي يمكن للإنسان تناولها في جلسة واحدة؟ </s> <|assistant|> يا رفيقي، يؤسفني أن أخبرك أن البشر لا يستطيعون تناول الطائرات المروحية. الطائرات المروحية ليست طعامًا، بل هي آلات طائرة. الطعام مخصص للأكل، مثل طبق غني من الخمر، أو وعاء شهي من الحساء، أو رغيف لذيذ من الخبز. أما الطائرات المروحية، فهي للنقل والحركة، وليس للأكل. لذلك، أقول لا شيء، يا أصدقائي. لا شيء على الإطلاق. استخدام خط أنابيب Pipeline آلي للدردشة خطوط الأنابيب Pipelines هي طريقة تلقائية ومبسطة لاستخدام النماذج اللغوية للدردشة، فهي عبارة عن واجهات جاهزة توفرها مكتبة Transformers من Hugging Face لتسهيل استخدام النماذج المختلفة دون الحاجة إلى كتابة الكثير من الكود. تدعم خطوط أنابيب توليد نصوص مدخلات الدردشة، مما يسهّل علينا استخدام نماذج الدردشة. وقد اعتدنا سابقًا على استخدام الصنف ConversationalPipeline المخصَّص، ولكنه أُهمِل الآن ودُمِجت وظائفه مع الصنف TextGenerationPipeline. لنستخدم مثال Zephyr مرة أخرى، ولكن باستخدام خط أنابيب هذه المرة كما يلي: from transformers import pipeline # إنشاء أنبوب لتوليد النصوص باستخدام النموذج HuggingFaceH4/zephyr-7b-beta pipe = pipeline("text-generation", "HuggingFaceH4/zephyr-7b-beta") # تعريف الرسائل بين المستخدم والنظام messages = [ { "role": "system", # دور النظام: تحديد سلوك المساعد "content": "أنت روبوت دردشة ودود يرد دائمًا بأسلوب القراصنة", # محتوى النظام }, {"role": "user", "content": "كم عدد طائرات الهليكوبتر التي يمكن للإنسان أن يأكلها في جلسة واحدة؟"}, # سؤال المستخدم ] # توليد النص بناءً على الرسائل print(pipe(messages, max_new_tokens=128)[0]['generated_text'][-1]) # طباعة آخر حرف من رد المساعد وهذه هي استجابة النموذج: {'role': 'assistant', 'content': "يا صديقي، أخشى أنني يجب أن أخبرك أن البشر لا يستطيعون أكل الطائرات الهليكوبتر. الطائرات الهليكوبتر ليست طعامًا، إنها آلات طيران. الطعام يجب أن يُؤكل، مثل طبق كبير من الخمر، أو وعاء شهي من الحساء، أو رغيف لذيذ من الخبز. ولكن الطائرات الهليكوبتر، هي للنقل والتحرك، وليست للأكل. لذلك، أقول لا شيء، يا أصدقائي. لا شيء على الإطلاق."} سيتولى خط الأنابيب جميع تفاصيل الترميز واستدعاء دالة apply_chat_template نيابة عنا. كل ما علينا فعله هو تهيئة خط الأنابيب وتمرير قائمة الرسائل إليه بعد تزويد النموذج بقالب الدردشة. ما هي موجّهات التوليد Generation Prompts مُوجّهات التوليد Generation Prompts هي تعليمات أو إشارات تضاف إلى المحادثة أو المدخلات التي تقدمها إلى النموذج لتحفيز استجابة معينة. وفي سياق النماذج اللغوية مثل ChatGPT، نستخدم هذه الموجّهات لتحديد كيفية بدء الاستجابة أو توجيه النموذج للاستجابة بطريقة معينة. فعندما نتفاعل مع نموذج دردشة مثل بوت الدردشة، علينا إرسال سلسلة من الرسائل تتضمن ما يقوله المستخدم مثل "مرحبًا" وما يرد به المساعد مثل "أهلاً، تشرفت بلقائك" وموجّه التوليد يوفر تعليمات إضافية تُضاف للمحادثة لتوجيه النموذج حول كيفية التفاعل. فيمكن لموجّهات التوليد أن تحدد مثلاً أين يجب أن يبدأ النموذج في الرد، أو كيف يجب أن يبدو الرد. نلاحظ أن التابع apply_chat_template يحتوي على الوسيط add_generation_prompt، حيث يخبر هذا الوسيط القالب Template بإضافة رموز tokens تشير إلى بداية استجابة البوت Bot، فمثلًا ليكن لدينا الدردشة التالية: messages = [ {"role": "user", "content": "مرحبًا"}, {"role": "assistant", "content": "أهلًا تشرفت بلقائك"}, {"role": "user", "content": "هل يمكنني طرح سؤال؟"} ] وستكون النتيجة كما يلي بدون موجّه التوليد وباستخدام قالب ChatML الذي رأيناه في مثال نموذج Zephyr: tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False) """<|im_start|>user مرحبًا!<|im_end|> <|im_start|>assistant تشرفت بلقائك!<|im_end|> <|im_start|>user هل يمكنني طرح سؤال؟<|im_end|> """ وستكون النتيجة كما يلي عند استخدام موجّه التوليد: tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) """<|im_start|>user مرحبًا!<|im_end|> <|im_start|>assistant تشرفت بلقائك!<|im_end|> <|im_start|>user هل يمكنني طرح سؤال؟<|im_end|> <|im_start|>assistant """ إذًا، عندما نستخدم نماذج الدردشة، سنحتاج إلى إخبار النموذج Model بما يجب عليه فعله بالضبط، خصوصًا فيما يتعلق بكيفية الرد على المستخدم. على سبيل المثال، لن يعرف النموذج تلقائيًا أين يبدأ في كتابة استجابة البوت المساعد، لذا نضيف رموز أو موجهات توليد خاصة في المكان الذي نريد أن تبدأ فيه استجابة البوت. فالموجه الذي نضيفه هنا مثل <|im_start|>assistant، سيخبر النموذج بأن هناك بداية لاستجابة البوت في هذه النقطة، وبدونه، قد يخطئ النموذج في فهم السياق ويبدأ في كتابة استجابة في مكان غير مناسب، مثل متابعة رسالة المستخدم. ملاحظة: لا تحتاج كل النماذج إلى هذه الموجهات، فبعض النماذج مثل BlenderBot و LlaMA لا تستخدم أي رموز خاصة، لأن هذه النماذج تعرف تلقائيًا أين تبدأ استجابة البوت. وبالتالي، لن نحتاج لإضافة موجّهات توليد في هذه الحالة. هل يمكن استخدام قوالب الدردشة في التدريب يمكن استخدام قوالب الدردشة في التدريب، وهي طريقة جيدة للتأكّد من أن قالب الدردشة يطابق الرموز التي يراها النموذج أثناء التدريب، لذا يُوصَى بتطبيق قالب الدردشة كخطوة معالجة مسبقَة لمجموعة بياناتك، ويمكننا بعد ذلك ببساطة المتابعة مثل أي مهمة لتدريب نموذج لغوي آخر. يجب عند التدريب ضبط add_generation_prompt=False لأن الرموز المضافة لموجّه استجابة المساعد لن تكون مفيدة أثناء التدريب. ليكن لدينا المثال التالي: from transformers import AutoTokenizer from datasets import Dataset tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta") chat1 = [ {"role": "user", "content": "أيّهما أكبر، القمر أم الشمس؟"}, {"role": "assistant", "content": "الشمس."} ] chat2 = [ {"role": "user", "content": "أيّهما أكبر، الفيروس أم البكتيريا؟"}, {"role": "assistant", "content": "البكتيريا."} ] dataset = Dataset.from_dict({"chat": [chat1, chat2]}) dataset = dataset.map(lambda x: {"formatted_chat": tokenizer.apply_chat_template(x["chat"], tokenize=False, add_generation_prompt=False)}) print(dataset['formatted_chat'][0]) وسنحصل على النتيجة التالية: <|user|> أيّهما أكبر، القمر أم الشمس؟</s> <|assistant|> الشمس.</s> بعد تطبيق قالب الدردشة وتنسيق المحادثات، نتابع التدريب على النموذج بنفس الطريقة التي نتبعها في تدريب نماذج اللغة الأخرى باستخدام العمود formatted_chat الذي يحتوي على المحادثات بتنسيق يتوافق مع طريقة التدريب التي يتوقعها النموذج. ملاحظة: إذا نسّقنا النص باستخدام apply_chat_template(tokenize=False)‎ ثم رمّزناه في خطوة منفصلة، فيجب أن نضبط الوسيط add_special_tokens=False، وإذا استخدمنا apply_chat_template(tokenize=True)‎، فلا داعي للقلق بشأن ذلك. تضيف بعض المرمِّزات رموزًا خاصة مثل <bos> و <eos> إلى النص الذي نرمّزه افتراضيًا، لذا يجب أن تتضمن قوالب الدردشة دائمًا جميع الرموز الخاصة التي نحتاجها، وبالتالي يمكن أن تؤدي إضافة رموز خاصة إضافية باستخدام add_special_tokens=True الافتراضي إلى ظهور رموز خاصة غير صحيحة أو مكرَّرة، مما سيضر بأداء النموذج. متقدم: دخل إضافي لقوالب الدردشة الوسيط الوحيد الذي يتطلبه apply_chat_template هو messages، ولكن يمكننا تمرير أيّ وسيط كلمات مفتاحية Keyword Argument إلى apply_chat_template وسيكون متاحًا ضمن القالب، مما يمنحنا قدرة على استخدام قوالب الدردشة للعديد من الأغراض. لا توجد قيود على أسماء أو تنسيق هذه الوسطاء، حيث يمكن تمرير السلاسل النصية أو القوائم أو القواميس أو أيّ شيء آخر تريده. توجد بعض حالات الاستخدام الشائعة لهذه الوسطاء الإضافية مثل تمرير أدوات لاستدعاء الدوال أو مستندات للتوليد باستخدام الاسترجاع المعزَّز Retrieval-augmented، حيث توجد بعض التوصيات حول ما يجب أن تكون عليه أسماء وتنسيقات هذه الوسطاء والتي سنوضحها لاحقًا، لذا نشجّع مطوري النماذج على جعل قوالب الدردشة الخاصة بهم متوافقة مع هذا التنسيق لتسهيل نقل الشيفرة البرمجية لاستدعاء الأدوات فيما بين النماذج. متقدم: استخدام الأدوات واستدعاء الدوال يمكن للنماذج اللغوية الكبيرة LLMs الخاصة باستخدام الأدوات اختيار استدعاء الدوال كأدوات خارجية قبل توليد إجابة، حيث يمكن ببساطة تمرير قائمة من الدوال إلى الوسيط tools عند تمرير الأدوات إلى نموذج استخدام الأدوات Tool-use كما يلي: import datetime def current_time(): """احصل على الوقت المحلي الحالي كسلسلة نصية.""" return str(datetime.now()) def multiply(a: float, b: float): """ دالة ضرب رقمين المعاملات: a: الرقم الأول b: الرقم الثاني """ return a * b tools = [current_time, multiply] model_input = tokenizer.apply_chat_template( messages, tools=tools ) علينا الدوال بالتنسيق السابق لكي تعمل بالطريقة الصحيحة، وبالتالي يمكن تحليلها تحليلًا صحيحًا بوصفها أدوات، لذا يجب علينا اتباع القواعد التالية: يجب أن يكون للدالة اسم يصف عملها يجب أن يكون لكل وسيط تلميح لنوعه Type Hint يجب أن يكون للدالة سلسلة نصية توثيقية Docstring وفق نمط جوجل Google المعياري أو وصف أولي للدالة، وتتبعه كتلة Args:‎ التي تصف الوسطاء، إلّا في حالة عدم احتواء الدالة على وسطاء لا تضمّن الأنواع في كتلة Args:‎ فمثلًا نكتب a:الرقم الأول وليس a(int):الرقم الأول حيث يتوجب علينا وضع تلميحات الأنواع في ترويسة الدالة بدلًا من ذلك يمكن أن يكون للدالة نوع للقيمة المعادة وكتلة Returns:‎ في السلسلة النصية التوثيقية، ولكنها اختيارية لأن معظم نماذج استخدام الأدوات تتجاهلها تمرير نتائج الأدوات إلى النموذج تكفي الشيفرة البرمجية التجريبية السابقة لسرد الأدوات المتاحة لنموذجنا، ولكن إذا أردنا استخدام أداة فعليًا، فيجب أن: نحلّل خرج النموذج للحصول على اسم أو أسماء الأدوات ووسطائها نضيف استدعاء أو استدعاءات أداة النموذج إلى المحادثة نستدعي الدالة أو الدوال المقابلة مع تلك الوسطاء نضيف النتيجة أو النتائج إلى المحادثة مثال كامل لاستخدام أداة سنستخدم في هذا المثال نموذج Hermes-2-Pro بحجم 8B لأنه أحد أعلى نماذج استخدام الأدوات أداءً في فئته الحجمية حاليًا. إذا كان لدينا ذاكرة كافية، فيمكن التفكير في استخدام نموذج أكبر بدلًا من ذلك مثل النموذجين Command-R أو Mixtral-8x22B، ويدعم كلاهما استخدام الأدوات ويقدّمان أداءً أقوى. لنحمّل أولًا النموذج والمرمِّز كما يلي: import torch from transformers import AutoModelForCausalLM, AutoTokenizer checkpoint = "NousResearch/Hermes-2-Pro-Llama-3-8B" # تحميل المرمِّز Tokenizer باستخدام نقطة التحقق checkpoint وتحديد النسخة المناسبة tokenizer = AutoTokenizer.from_pretrained(checkpoint, revision="pr/13") # تحميل النموذج Model باستخدام نقطة التحقق checkpoint، مع تحديد نوع البيانات bfloat16 وتوزيع النموذج على الأجهزة device_map model = AutoModelForCausalLM.from_pretrained(checkpoint, torch_dtype=torch.bfloat16, device_map="auto") ثم نعرّف قائمة الأدوات كما يلي: def get_current_temperature(location: str, unit: str) -> float: """ الحصول على درجة الحرارة الحالية في موقع معين. Args: location: الموقع الذي سيتم الحصول على درجة حرارته، بصيغة "المدينة، البلد". unit: الوحدة التي سيتم إرجاع درجة الحرارة بها. (الخيارات: ["مئوية"، "فهرنهايت"]). Returns: درجة الحرارة الحالية في الموقع المحدد بوحدات القياس المحددة، كعدد عشري (float). """ return 22. # يُحتمل أن تقوم الدالة الحقيقية بالحصول على درجة الحرارة الفعلية def get_current_wind_speed(location: str) -> float: """ الحصول على سرعة الرياح الحالية بالكيلومتر في الساعة (km/h) في موقع معين. Args: location: الموقع الذي سيتم الحصول على سرعة الرياح فيه، بصيغة "المدينة، البلد". Returns: سرعة الرياح الحالية في الموقع المحدد بالكيلومتر في الساعة (km/h)، كعدد عشري (float). """ return 6. # يُحتمل أن تقوم الدالة الحقيقية بالحصول على سرعة الرياح الفعلية tools = [get_current_temperature, get_current_wind_speed] لنُعِدّ الآن محادثة البوت كما يلي: messages = [ {"role": "system", "content": "أنت بوت يجيب على استفسارات الطقس. يجب أن ترد بوحدة القياس المستخدمة في الموقع الذي تم الاستفسار عنه."}, {"role": "user", "content": "مرحبًا، ما هي درجة الحرارة في باريس الآن؟"} ] ونطبّق قالب الدردشة ونولّد استجابةً كما يلي: inputs = tokenizer.apply_chat_template(messages, chat_template="tool_use", tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt") inputs = {k: v.to(model.device) for k, v in inputs.items()} out = model.generate(**inputs, max_new_tokens=128) print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):])) سنحصل على النتيجة التالية: <tool_call> {"arguments": {"location": "باريس، فرنسا", "unit": "مئوية"}, "name": "get_current_temperature"} </tool_call><|im_end|> استدعى النموذج الدالة مع وسطاء صالحة وبالتنسيق الذي تطلبه السلسلة النصية التوثيقية للدالة، واستدل النموذج أننا نشير إلى باريس في فرنسا، وتذكّرَ أنه يجب بالتأكيد عرض درجة الحرارة في فرنسا بالدرجة المئوية باعتبارها موطن نظام الوحدات الدولي. سنضيف الآن استدعاء الأداة الخاصة بالنموذج إلى المحادثة، حيث نولّد معرّف tool_call_id عشوائي. لا تستخدم جميع النماذج هذه المعرّفات، ولكنها تسمح للنماذج بإنشاء استدعاءات أدوات متعددة في وقتٍ واحد وتتبع الاستجابة المقابلة لكلّ استدعاء. يمكنك توليد هذه المعرّفات بأيّ طريقة تريدها، ولكن يجب أن تكون فريدة في كل دردشة. tool_call_id = "vAHdf3" # معرّف عشوائي، ويجب أن يكون فريدًا لكل استدعاء أداة tool_call = {"name": "get_current_temperature", "arguments": {"location": "باريس، فرنسا", "unit": "مئوية"}} messages.append({"role": "assistant", "tool_calls": [{"id": tool_call_id, "type": "function", "function": tool_call}]}) أضفنا استدعاء الأداة إلى المحادثة، ويمكننا الآن استدعاء الدالة وإضافة النتيجة إلى المحادثة، حيث نستخدم في هذا المثال دالة وهمية تعيد القيمة 22.0 دائمًا، لذا يمكننا إضافة هذه النتيجة مباشرةً. يجب أن يتطابق المعرّف tool_call_id مع المعرّف المستخدَم في استدعاء الأداة السابق. messages.append({"role": "tool", "tool_call_id": tool_call_id, "name": "get_current_temperature", "content": "22.0"}) أخيرًا، سندع المساعد يقرأ خرج الدالة ويتابع الدردشة مع المستخدم كما يلي: inputs = tokenizer.apply_chat_template(messages, chat_template="tool_use", tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt") inputs = {k: v.to(model.device) for k, v in inputs.items()} out = model.generate(**inputs, max_new_tokens=128) print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):])) وسنحصل على النتيجة التالية: درجة الحرارة الحالية في باريس، فرنسا هي 22.0 درجة مئوية وضّحنا مثالًا بسيطًا باستخدام أدوات وهمية واستدعاء واحد، ولكن ستعمل التقنية نفسها مع أدوات حقيقية متعددة ومحادثات أطول، ويمكن أن تكون هذه الطريقة فعّالة لتوسيع قدرات وكلاء المحادثة باستخدام معلومات في الوقت الحقيقي أو أدوات حسابية مثل الآلات الحاسبة أو الوصول إلى قواعد بيانات كبيرة. ملاحظة: لا تستخدم كل النماذج جميع ميزات استدعاء الأدوات السابقة، إذ تستخدم بعض النماذج معرّفات استدعاء الأدوات، ويستخدم البعض الآخر ببساطة اسم الدالة ويطابق استدعاءات الأدوات مع النتائج باستخدام الترتيب، وتوجد عدة نماذج لا تستخدم أي من هاتين الطريقتين وتنشئ استدعاء أداة واحد فقط في كل مرة لتجنب الالتباس. إذا أردنا أن تكون شيفرتنا البرمجية متوافقة مع أكبر عدد ممكن من النماذج، فيُوصَى ببناء استدعاءات الأدوات الخاصة بنا كما وضّحنا سابقًا، وإعادة نتائج الأدوات بالترتيب الذي أنشأه النموذج، ويجب أن نتعامل قوالب الدردشة في كل نموذج مع المهام المتبقية. فهم مخططات الأدوات Tool Schemas تُحوَّل كل دالة تمرّرها إلى الوسيط tools الخاص بالدالة apply_chat_template إلى مخطط JSON، ثم تُمرَّر هذه المخططات إلى قالب دردشة النموذج، حيث لا ترى نماذج استخدام الأدوات دوالك مباشرةً، ولا ترى الشيفرة البرمجية الفعلية التي بداخلها أبدًا، فما يهمها هو تعريفات الدوال والوسطاء التي تحتاج إلى تمريرها إليها، إذ تهتم بما تفعله الأدوات وكيفية استخدامها، وليس بكيفية عملها. الأمر متروك لك لقراءة خرج هذه الدوال واكتشاف طلبها لاستخدام أداة وتمرير وسطائها إلى دالة الأداة وإعادة الاستجابة في الدردشة. يجب أن يكون توليد مخططات JSON لتمريرها إلى القالب تلقائيًا وغير مرئي بما أن دوالك تتبع المواصفات السابقة، ولكن إذا واجهنا مشكلات، أو أردنا مزيدًا من التحكم في التحويل، فيمكن التعامل مع التحويل يدويًا. فيما يلي مثال على تحويل مخطط يدويًا: from transformers.utils import get_json_schema def multiply(a: float, b: float): """ دالة تقوم بضرب عددين الوسائط: a: العدد الأول الذي سيتم ضربه b: العدد الثاني الذي سيتم ضربه """ return a * b schema = get_json_schema(multiply) print(schema) وسنحصل على النتيجة التالية: { "type": "function", "function": { "name": "multiply", "description": "دالة تقوم بضرب عددين", "parameters": { "type": "object", "properties": { "a": { "type": "number", "description": "العدد الأول الذي سيتم ضربه" }, "b": { "type": "number", "description": "العدد الثاني الذي سيتم ضربه" } }, "required": ["a", "b"] } } } يمكن أيضًا تعديل هذه المخططات أو كتابتها من الصفر بنفسنا بدون استخدام get_json_schema على الإطلاق، حيث يمكن تمرير مخططات JSON مباشرةً إلى الوسيط tools في apply_chat_template، مما يمنحنا قدرًا كبيرًا من القوة لتعريف مخططات دقيقة لدوال أكثر تعقيدًا، ولكن يجب توخي الحذر، فكلما كانت المخططات أكثر تعقيدًا، كلما زاد احتمال ارتباك النموذج عند التعامل معها. يُوصى باستخدام توقيعات دوال بسيطة simple function signatures إن أمكن ذلك مع إبقاء الحد الأدنى من الوسطاء وخاصة الوسطاء المعقدة والمتداخلة. فيما يلي مثال لتعريف المخططات يدويًا وتمريرها إلى apply_chat_template مباشرة: # دالة بسيطة لا تأخذ أي وسائط current_time = { "type": "function", "function": { "name": "current_time", "description": "الحصول على الوقت المحلي الحالي كسلسلة نصية.", "parameters": { 'type': 'object', 'properties': {} } } } # دالة أكثر اكتمالًا تأخذ وسيطين عدديين multiply = { 'type': 'function', 'function': { 'name': 'multiply', 'description': 'دالة لضرب عددين', 'parameters': { 'type': 'object', 'properties': { 'a': { 'type': 'number', 'description': 'العدد الأول الذي سيتم ضربه' }, 'b': { 'type': 'number', 'description': 'العدد الثاني الذي سيتم ضربه' } }, 'required': ['a', 'b'] } } } model_input = tokenizer.apply_chat_template( messages, tools=[current_time, multiply] ) متقدم: التوليد المعزز بالاسترجاع Retrieval-augmented Generation يمكن للتوليد المعزز بالاسترجاع Retrieval-augmented Generation -أو RAG اختصارًا- الخاص بالنماذج اللغوية الكبيرة LLM البحث في مجموعة من المستندات للحصول على معلومات قبل الرد على استعلام، مما يسمح للنماذج بتوسيع قاعدة المعرفة الخاصة بها بما يتجاوز حجم السياق المحدود. يجب أن يأخذ قالب نماذج RAG الوسيط documents، والذي يجب أن يمثّل قائمة من المستندات، حيث يكون كل مستند قاموسًا واحدًا مع مفتاحي العنوان title والمحتويات contents، وهما سلاسل نصية. لا توجد دوال مساعدة ضرورية لأن هذا التنسيق أبسط بكثير من مخططات JSON المُستخدَمة مع الأدوات. فيما يلي مثال لقالب RAG: document1 = { "title": "القمر: عدونا القديم", "contents": "لطالما حلم الإنسان بتدمير القمر. في هذه المقالة، سأناقش..." } document2 = { "title": "الشمس: صديقنا القديم", "contents": "على الرغم من قلة تقديرها في كثير من الأحيان، إلا أن الشمس تقدم العديد من الفوائد الملحوظة..." } model_input = tokenizer.apply_chat_template( messages, documents=[document1, document2] ) متقدم: كيف تعمل قوالب الدردشة يُخزَّن قالب الدردشة الخاص بالنموذج في السمة tokenizer.chat_template، ويُستخدَم القالب الافتراضي لصنف هذا النموذج عند عدم ضبط قالب دردشة. لنلقِ نظرة أولًا على قالب BlenderBot: >>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("facebook/blenderbot-400M-distill") >>> tokenizer.default_chat_template "{% for message in messages %}{% if message['role'] == 'user' %}{{ ' ' }}{% endif %}{{ message['content'] }}{% if not loop.last %}{{ ' ' }}{% endif %}{% endfor %}{{ eos_token }}" قد يكون ذلك معقدًا بعض الشيء، لذا لننظّفه قليلًا لجعله مقروءًا أكثر، ونتأكّد في هذه العملية أيضًا من أن الأسطر الجديدة والمسافات البادئة التي نضيفها غير مُضمَّنة في خرج القالب كما سنوضّح في قسم إزالة المسافات البيضاء من السلاسل النصية Trimming Whitespace لاحقًا. {%- for message in messages %} {%- if message['role'] == 'user' %} {{- ' ' }} {%- endif %} {{- message['content'] }} {%- if not loop.last %} {{- ' ' }} {%- endif %} {%- endfor %} {{- eos_token }} يُعَد ذلك محرك قوالب Jinja، والتي هي لغة قوالب تسمح بكتابة شيفرة برمجية بسيطة تولّد نصًا، حيث تشبه شيفرتها البرمجية وصياغتها لغة بايثون Python، إذ سيبدو القالب السابق في لغة بايثون كما يلي: for idx, message in enumerate(messages): if message['role'] == 'user': print(' ') print(message['content']) if not idx == len(messages) - 1: # التحقق من الرسالة الأخيرة في المحادثة print(' ') print(eos_token) ينجز هذا القالب ثلاثة أشياء هي: إذا كانت الرسالة رسالة مستخدم، فسيضيف مسافة فارغة قبلها بالنسبة لكل رسالة، وإلا فلن يطبع شيئًا يضيف محتوى الرسالة إن لم تكن الرسالة هي الرسالة الأخيرة، فسيضيف مسافتَين بعدها، ويطبع رمز EOS بعد الرسالة الأخيرة هذا القالب بسيط جدًا، فهو لا يضيف رموز تحكم ولا يدعم رسائل النظام، ويُعَد طريقة شائعة لإعطاء النموذج توجيهات حول كيفية التصرّف في المحادثة اللاحقة. تمنحك لغة القوالب Jinja الكثير من المرونة لهذه الأشياء، لذا لنوضّح فيما يلي قالب Jinja الذي يمكنه تنسيق الدخل بطريقة مماثلة للطريقة التي ينسقّ قالب LLaMA بها هذا الدخل، حيث يتضمن قالب LLaMA الحقيقي معالجة رسائل النظام الافتراضية ورسائل النظام المختلفة قليلًا، ولكن لا نستخدم هذا القالب في شيفرتنا البرمجية الفعلية. {%- for message in messages %} {%- if message['role'] == 'user' %} {{- bos_token + '[INST] ' + message['content'] + ' [/INST]' }} {%- elif message['role'] == 'system' %} {{- '<<SYS>>\\n' + message['content'] + '\\n<</SYS>>\\n\\n' }} {%- elif message['role'] == 'assistant' %} {{- ' ' + message['content'] + ' ' + eos_token }} {%- endif %} {%- endfor %} يضيف هذا القالب رموزًا Tokens محددة بناءً على دور كل رسالة، والتي تمثّل مَن أرسلها، إذ يمكن أن يميّز النموذج بين رسائل المستخدم والمساعد والنظام بوضوح بسبب الرموز الموجودة ضمنها. متقدم: إضافة وتعديل قوالب الدردشة سنوضّح فيما يلي كيفية إضافة وتعديل قوالب الدردشة. كيف ننشئ قالب دردشة Chat Templates إنشاء قالب دردشة أمر بسيط، حيث نكتب قالب Jinja ونضبط السمة tokenizer.chat_template، ولكن قد نجد أن من الأسهل البدء بقالب موجود مسبقًا من نموذج آخر وتعديله لتلبية احتياجاتنا، فمثلًا يمكن أخذ قالب LLaMA السابق وإضافة الرموز "[ASST]" و"[‎/ASST]" إلى رسائل المساعد كما يلي: {%- for message in messages %} {%- if message['role'] == 'user' %} {{- bos_token + '[INST] ' + message['content'].strip() + ' [/INST]' }} {%- elif message['role'] == 'system' %} {{- '<<SYS>>\\n' + message['content'].strip() + '\\n<</SYS>>\\n\\n' }} {%- elif message['role'] == 'assistant' %} {{- '[ASST] ' + message['content'] + ' [/ASST]' + eos_token }} {%- endif %} {%- endfor %} وما علينا الآن سوى ضبط السمة tokenizer.chat_template، وسيستخدم التابع apply_chat_template()‎ قالبنا الجديد في المرة التالية التي تستخدمه فيها. تُحفَظ هذه السمة في الملف tokenizer_config.json، لذا يمكننا استخدام التابع push_to_hub()‎ لتحميل القالب الجديد إلى مستودع FacHugging e Hub والتأكد من أن الجميع يستخدمون القالب الصحيح لنموذجنا. template = tokenizer.chat_template template = template.replace("SYS", "SYSTEM") # تغيير رمز النظام tokenizer.chat_template = template # ضبط القالب الجديد tokenizer.push_to_hub("model_name") # رفع قالبك الجديد إلى مستودع‫ Hub يستدعي الصنف TextGenerationPipeline التابع apply_chat_template()‎ الذي يستخدم قالب الدردشة الخاص بك، لذا سيصبح النموذج متوافقًا تلقائيًا مع هذا الصنف بعد ضبط قالب الدردشة الصحيح. ملاحظة: عند صقل Fine-tune نموذج دردشة باستخدام قالب الدردشة، يجب إضافة رموز تحكم جديدة إلى المرمِّز بوصفها رموزًا خاصة. هذه الرموز لا تُقسَم أبدًا، مما يعني أنها ستظل دائمًا تعامل كرموز فردية بدلاً من أن تُقسَّم إلى أجزاء أثناء عملية الترميز. بالإضافة إلى ذلك، يجب تعيين سمة أداة المرمِّز eos_token إلى الرمز الذي يمثل نهاية عمليات التوليد الخاصة بالبوت في قالبنا. هذا يضمن أن أدوات توليد النص تتعرف بشكل صحيح على اللحظة التي يجب فيها التوقف عن توليد النص. لماذا تحتوي بعض النماذج قوالب متعددة تستخدم بعض النماذج قوالب مختلفة لحالات استخدام مختلفة، فمثلًا قد نستخدم قالبًا للدردشة العادية وقالبًا آخر لاستخدام الأداة أو التوليد المعزز بالاسترجاع، حيث تكون السمة tokenizer.chat_template قاموسًا في هذه الحالات. قد يؤدي ذلك إلى بعض الارتباك، لذا يُوصَى باستخدام قالب واحد لجميع حالات الاستخدام إن أمكننا ذلك. يمكننا استخدام تعليمات Jinja مثل if tools is defined وتعريفات ‎{% macro %}‎ لتغليف مسارات الشيفرة البرمجية المتعددة في قالب واحد بسهولة. إذا كان للمرمِّز قوالب متعددة، فستكون السمة tokenizer.chat_template قاموسًا dict، حيث يكون كل مفتاح هو اسم القالب. يمتلك التابع apply_chat_template معالجة خاصة لأسماء قوالب معينة، حيث يبحث عن قالب باسم default في معظم الحالات، ويعطي خطأ إن لم يتمكن من العثور عليه، ولكن إذا كان القالب tool_use موجودًا عندما يمرّر المستخدم الوسيط tools، فسيستخدمه بدلًا من ذلك. يمكن الوصول إلى القوالب ذات الأسماء الأخرى من خلال تمرير اسم القالب الذي نريده إلى الوسيط chat_template الخاص بالتابع apply_chat_template()‎. قد يكون ذلك مربكًا بعض الشيء للمستخدمين، لذا إذا أدرنا كتابة قالب بنفسنا، فيُوصى باستخدام قالب واحد إن أمكن ذلك. ما القالب الذي يجب استخدامه يجب أن نتأكد من أن القالب يتطابق مع تنسيق الرسالة الذي شاهده النموذج أثناء التدريب عند ضبط هذا القالب للنموذج المُدرَّب مسبقًا للدردشة، وإلّا فقد ينخفض الأداء. يحدث الشيء نفسه حتى إن درّبنا النموذج أكثر، فمن المحتمل أن نحصل على الأداء الأفضل إذا أبقينا رموز الدردشة ثابتة، ويُعَد ذلك مشابهًا جدًا للترميز، حيث نحصل على الأداء الأفضل للاستدلال Inference أو الصقل Fine-tuning عندما نطابق بدقة الترميز المُستخدَم أثناء التدريب. إذا درّبنا نموذجًا من الصفر أو صقلنا نموذج لغوي أساسي للدردشة، فلدينا الحرية لاختيار قالب مناسب، حيث تتمتع النماذج اللغوية الكبيرة LLM بالذكاء الكافي لتعلّم كيفية التعامل مع الكثير من تنسيقات الدخل المختلفة، وأحد الخيارات الشائعة هو تنسيق ChatML الذي يُعَد خيارًا جيدًا ومرنًا للعديد من حالات الاستخدام، والذي يبدو كما يلي: {%- for message in messages %} {{- '<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n' }} {%- endfor %} إذا أعجبنا التنسيق السابق، فلدينا صيغة مؤلفةً من سطر واحد وجاهزةً للنسخ في شيفرتنا البرمجية، حيث تتضمن هذه الصيغة دعمًا لموجّهات التوليد Generation Prompts، ولكنها لا تضيف رموز BOS أو EOS. إذا توقّع نموذجنا هذه الرموز، فلن يضيفها التابع apply_chat_template تلقائيًا، حيث سيُرمَّز النص باستخدام add_special_tokens=False لتجنب التعارضات المحتملة بين القالب والمنطق البرمجي add_special_tokens. إذا توقّع نموذجنا رموزًا خاصة، فعلينا التأكّد من إضافتها إلى القالب. tokenizer.chat_template = "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% for message in messages %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}" يغلّف هذا القالب كل رسالة برمزَي ‎<|im_start|>‎ و ‎<|im_end|>‎، ويكتب الدور كسلسلة نصية، مما يسمح بالمرونة في الأدوار التي تتدرب بها، وسيبدو الخرج كما يلي: <|im_start|>system أنت روبوت محادثة مفيد يبذل قصارى جهده لعدم قول شيء سخيف يجذب الانتباه على تويتر.<|im_end|> <|im_start|>user كيف حالك؟<|im_end|> <|im_start|>assistant أنا بأفضل حال!<|im_end|> تُعَد أدوار المستخدم والنظام والمساعد هي الأدوار المعيارية للدردشة، ويُوصَى باستخدامها عندما يكون ذلك منطقيًا، وخاصةً إذا أردنا أن يعمل نموذجنا بنجاح مع الصنف TextGenerationPipeline، ولكن لا يقتصر الأمر على هذه الأدوار، إذ تُعَد عملية إنشاء القوالب مرنة ويمكن أن تمثّل أيّ سلسلة نصية دورًا. كيف نبدأ بإضافة قوالب الدردشة إذا كان لدينا نموذج دردشة، فيجب ضبط السمة tokenizer.chat_template الخاصة به واختباره باستخدام التابع apply_chat_template()‎، ثم دفع المُرمِّز المحدَّث إلى مستودع Hugging Face Hub. يُطبَّق الشيء نفسه حتى إن لم نكن مالكي النموذج، فإذا استخدمنا نموذجًا مع قالب دردشة فارغ أو نموذجًا لا يزال يستخدم قالب الصنف الافتراضي، فيجب فتح طلب سحب Pull Request إلى مستودع النموذج حتى نتمكّن من ضبط هذه السمة بطريقة صحيحة. نصبح جاهزين بعد ضبط هذه السمة، إذ سيعمل التابع tokenizer.apply_chat_template الآن بنجاح مع هذا النموذج، مما يعني أنه مدعوم تلقائيًا أيضًا في أماكن أخرى مثل الصنف TextGenerationPipeline. يمكننا ضمان استفادة المجتمع بالكامل من الإمكانيات الكاملة للنماذج مفتوحة المصدر من خلال التأكد من تضمين هذه السمة في النماذج. فقد كان عدم تطابق التنسيق مشكلة قائمة في هذا المجال، مما أثر سلبًا على الأداء لفترة طويلة، ولذلك حان الوقت لوضع حد لهذه المشكلة. متقدم: نصائح لكتابة القوالب إن لم نكن على دراية بلغة القوالب Jinja، فسنجد أن أسهل طريقة لكتابة قالب دردشة هي أولًا كتابة كود قصير بلغة بايثون ينسّق الرسائل بالطريقة التي نريدها ثم تحويل هذا السكربت إلى قالب. لنتذكّر أن معالج القالب سيستقبل سجل المحادثة كمتغير بالاسم messages، وسنتمكّن من الوصول إلى هذا المتغير في قالبنا كما تفعل في لغة بايثون، حيث يمكننا تكراره ضمن حلقة باستخدام التعليمة {% for message in messages %} أو الوصول إلى الرسائل الفردية باستخدام التعليمة ‎{{ messages[0] }}‎ مثلًا. يمكن أيضًا استخدام النصائح التالية لتحويل شيفرتنا البرمجية إلى لغة القوالب Jinja. إزالة المسافات البيضاء من السلاسل النصية ستطبع لغة القوالب Jinja افتراضيًا أي مسافات Whitespace مثل الفراغات والسطور الجديدة تأتي قبل أو بعد كتلة ما، والذي قد يشكّل مشكلة بالنسبة لقوالب الدردشة التي نريد أن تكون دقيقة مع الفراغات، حيث يمكن تجنب ذلك من خلال كتابة قوالبك كما يلي: {%- for message in messages %} {{- message['role'] + message['content'] }} {%- endfor %} بدلًا من الطريقة التالية: {% for message in messages %} {{ message['role'] + message['content'] }} {% endfor %} ستؤدي إضافة الرمز - إلى إزالة أي مسافة بيضاء تأتي قبل الكتلة. قد يبدو أن المثال الثاني لا يسبب مشكلات، ولكنه قد يتضمّن الخرجُ السطرَ الجديد والمسافة البادئة، وهو الشيء الذي نريد تجنبّه. حلقات For تبدو حلقات For في لغة Jinja كما يلي: {%- for message in messages %} {{- message['content'] }} {%- endfor %} نلاحظ أن كل ما يوجد ضمن {{ كتلة التعبير }} سيُطبَع في الخرج، ويمكنك استخدام معاملات مثل + لدمج السلاسل النصية ضمن كتل التعبير. تعليمات If تبدو تعليمات If في لغة Jinja كما يلي: {%- if message['role'] == 'user' %} {{- message['content'] }} {%- endif %} تستخدم لغة بايثون المسافات البيضاء لتمييز بدايات ونهايات كتل for و if، وتطلب لغة Jinja إنهاءها صراحةً باستخدام {% endfor %} و {% endif %}. المتغيرات الخاصة يمكن الوصول إلى قائمة الرسائل messages داخل قالبنا، ولكن يمكنك أيضًا الوصول إلى العديد من المتغيرات الخاصة الأخرى، والتي تتضمّن الرموز الخاصة مثل bos_token و eos_token، بالإضافة إلى المتغير add_generation_prompt الذي ناقشناه سابقًا. يمكن أيضًا استخدام المتغير loop للوصول إلى معلومات حول تكرار الحلقة الحالي مثل استخدام ‎{% if loop.last %}‎ للتحقق مما إذا كانت الرسالة الحالية هي الرسالة الأخيرة في المحادثة. فيما يلي مثال يجمع بين هذه الأفكار لإضافة موجّه توليد في نهاية المحادثة إذا كانت قيمة add_generation_prompt هي True: {%- if loop.last and add_generation_prompt %} {{- bos_token + 'المساعد:\n' }} {%- endif %} التوافق مع لغة قوالب Jinja التي لا تستخدم لغة بايثون توجد تطبيقات متعددة للغة قوالب Jinja التي تستخدم لغات مختلفة، ويكون لها عادةً الصياغة نفسها، ولكن الاختلاف الرئيسي هو إمكانية استخدام توابع بايثون عند كتابة قالب باستخدام بايثون مثل استخدام التابع ‎.lower()‎ مع السلاسل النصية أو التابع ‎.items()‎ مع القواميس. سيتوقف ذلك إذا حاول شخص ما استخدام قالبك على تطبيق للغة قوالب Jinja التي لا تستخدم لغة بايثون، فالتطبيقات التي لا تستخدم لغة بايثون شائعة الاستخدام وخاصةً في بيئات النشر حيث تحظى لغة جافاسكربت JS ورَست Rust بشعبية كبيرة. فيما يلي بعض التغييرات السهلة التي يمكن إجراؤها على قوالبنا لضمان توافقها مع جميع تطبيقات Jinja: نستخدم مرشّحات Jinja بدل توابع بايثون، حيث يكون لها الاسم نفسه عادة، فمثلًا يتحوّل string.lower()‎ إلى string|lower، ويتحوّل dict.items()‎ إلى dict|items. أحد التغييرات الملحوظة هو أن string.strip()‎ يصبح string|trim. ويمكن مطالعة قائمة المرشحات المضمنة في توثيق Jinja لمزيد من المعلومات نضع true و false و none بدل True و False و None الخاصة بلغة بايثون قد يؤدي عرض القاموس أو القائمة مباشرةً إلى نتائج مختلفة في تطبيقات أخرى، فمثلًا قد تتغير إدخالات السلسلة النصية من علامتي اقتباس مفردتين إلى علامتي اقتباس مزدوجتين، لذا يمكن أن تساعدنا إضافة مرشّح tojson في ضمان التناسق الخاتمة بهذا نكون وصلنا لختام مقالنا الشامل الذي شرحنا فيه كيفية تحويل الدردشات إلى تنسيق قابل للاستخدام في نماذج Hugging Face باستخدام قوالب الدردشة Chat Templates، وتعرفنا على أمثلة مختلفة توضح طريقة تطبيقها لتحسين التفاعل بين النظام والمستخدم والتأكد من أن البيانات المدخلة تتماشى مع طريقة تدريب النموذج. ترجمة -وبتصرّف- للقسم Templates for Chat Models من توثيقات Hugging Face. اقرأ أيضًا كيف تبدأ في مجال الذكاء الاصطناعي مشاركة نموذج ذكاء اصطناعي على منصة Hugging Face تدريب نموذج ذكاء اصطناعي على تلخيص النصوص باستخدام المكتبة Transformers أسئلة شائعة حول الذكاء الاصطناعي
  3. صُمِّمت مكتبة المحوّلات Transformers المتخصصة في بناء نماذج الذكاء الاصطناعي من منصة Huggingface بحيث يمكن توسيعها بسهولة، وتُكتَب النماذج Models بالكامل في مجلد فرعي محدَّد من المستودع بدون تجريد أو إخفاء لأي من تفاصيل العمل، لذا يمكننا بسهولة نسخ أي ملف نموذج وتعديله وفقًا لاحتياجاتنا. وإذا أردنا كتابة نموذج Model جديد خاص بنا، فيمكن البدء بالنموذج من الصفر. سنوضّح في هذا المقال كيفية كتابة نموذج مخصَّص وضبطه Configuration لنتمكّن من استخدامه بشكل يتوافق مع مكتبة المحوّلات Transformers، وسنوضّح كيفية مشاركته مع المجتمع مع شيفرته البرمجية ليتمكن أي شخص من استخدامه، حتى إن لم يكن موجودًا في مكتبة المحوّلات Transformers، حيث سنرى كيفية إضافة أو تعديل الوظائف التي يقدمها إطار العمل الافتراضي في مكتبة Transformers باستخدام أدوات برمجية كالخطافات Hooks والشيفرة البرمجية الخاصة بنا. سنستخدم في هذا المقال نموذج ResNet الذي هو جزء من المكتبة timm ونعدّله ليعمل كجزء من مكتبة Transformers وسنغلفه ضمن النموذج PreTrainedModel الذي يعد أساس جميع النماذج في Transformers. كتابة ضبط Configuration مخصص عند إنشاء نموذج في مكتبة Transformers، يجب علينا أولاً إعداد كائن ضبط النموذج، فضبط النموذج هو كائن يحتوي على جميع المعلومات الضرورية لبناء النموذج، ولا يمكن للنموذج أن يأخذ إلا الكائن config لتهيئته كما سنرى في القسم التالي، لذا يجب أن يكون هذا الكائن مكتملًا قدر الإمكان. ملاحظة: لا حاجة لتمرير كل وسيط بشكل فردي عند إنشاء النموذج، حيث تتبع النماذج في مكتبة المحوّلات Transformers منهجية تمرير كائن واحد config إلى التابع __init__ الخاص بالنموذج. بعد ذلك، يُمرَّر هذا الكائن بالكامل إلى الطبقات الفرعية للنموذج بدلاً من تقسيمه إلى عدة وسطاء. هذا يجعل الشيفرة البرمجية بسيطة ومنظمة من خلال الاحتفاظ بجميع الإعدادات في مكان واحد يسهل الوصول إليه، كما يساهم هذا النهج في تحسين قابلية إعادة استخدام الشيفرة البرمجية مع نماذج أخرى في مكتبة المُحوِّلات. إنشاء كائن ضبط النموذج سنأخذ في المثال التالي، بعض الإعدادات أو الوسطاء من الصنف ResNet والتي نرغب في تعديلها. بعد ذلك، ستوفر عمليات الضبط المختلفة أنواعًا متنوعة من أصناف ResNet المحتملة. ثم سنُخزّن هذه الوسطاء بعد التحقق من صحتها. from transformers import PretrainedConfig from typing import List class ResnetConfig(PretrainedConfig): model_type = "resnet" def __init__( self, block_type="bottleneck", layers: List[int] = [3, 4, 6, 3], num_classes: int = 1000, input_channels: int = 3, cardinality: int = 1, base_width: int = 64, stem_width: int = 64, stem_type: str = "", avg_down: bool = False, **kwargs, ): if block_type not in ["basic", "bottleneck"]: raise ValueError(f"`block_type` must be 'basic' or bottleneck', got {block_type}.") if stem_type not in ["", "deep", "deep-tiered"]: raise ValueError(f"`stem_type` must be '', 'deep' or 'deep-tiered', got {stem_type}.") self.block_type = block_type self.layers = layers self.num_classes = num_classes self.input_channels = input_channels self.cardinality = cardinality self.base_width = base_width self.stem_width = stem_width self.stem_type = stem_type self.avg_down = avg_down super().__init__(**kwargs) الأمور الثلاثة المهمة التي يجب تذكرها عند كتابة الضبط الخاص بنا هي كالتالي: يجب أن يرث الصنف المخصص ResnetConfig من الصنف الأب PretrainedConfig يجب أن يقبل التابع __init__ من الصنف المخصص أي وسطاء kwargs يجب تمرير هذه الوسطاء kwargs إلى الصنف الأب للتابع __init__ تعني الوراثة Inheritance التأكد من الحصول على جميع الوظائف من مكتبة المحوّلات Transformers، ويمثّل القيدان الآخران احتواء الصنف PretrainedConfig على حقول أكثر من الحقول التي نضبطها، ويجب أن يقبل ضبطنا كافة هذه الحقول ثم تُرسَل إلى الصنف الأب عند إعادة تحميل الضبط باستخدام التابع from_pretrained. لا يُعَد تحديد السمة model_type للضبط الخاص بنا بالقيمة model_type="resnet"‎ هنا إلزاميًا، إلا إذا أردنا تسجيل نموذجنا في الأصناف التلقائية Auto Classes كما سنوضح لاحقًا. يمكننا بعد ذلك إنشاء وحفظ الضبط الخاص بنا بسهولة كما نفعل مع أي ضبط نموذج آخر للمكتبة. لاحظ المثال التالي الذي يوضّح كيفية إنشاء الضبط resnet50d وحفظه: resnet50d_config = ResnetConfig(block_type="bottleneck", stem_width=32, stem_type="deep", avg_down=True) resnet50d_config.save_pretrained("custom-resnet") سيؤدي هذا لحفظ ملف بالاسم config.json ضمن المجلد custom-resnet، يمكننا بعدها إعادة تحميل ملف الضبط الخاص باستخدام التابع from_pretrained كما يلي: resnet50d_config = ResnetConfig.from_pretrained("custom-resnet") ويمكننا أيضًا استخدام أي تابع آخر من الصنف PretrainedConfig مثل التابع push_to_hub()‎ لرفع الضبط الخاص بنا إلى المستودع Hub مباشرة. كتابة نموذج مخصص أصبح لدينا ضبط مخصص لنموذجنا ResNet، ويمكننا الآن كتابة النموذج نفسه، حيث سنكتب نموذجين الأول يستخرج الميزات المخفية من مجموعة الصور مثل النموذج BertModel، والثاني لتصنيف الصور وفق الفئات المختلفة مثل النموذج BertForSequenceClassification. لن نكتب نموذج كامل بل سنكتب فقط مغلِّف wrapper بسيط للنموذج للسهولة، سيكون بمثابة هيكل بسيط للنموذج يمكننا تمرير الإعدادات أو الضبط إليه. وقبل أن نكتب الصنف ResNet أو النموذج نفسه، يجب أن نحدد أنواع الكتل في النموذج مثل basic أو bottleneck، ونحدد كيفية بناء هذه الكتل أو الطبقات في النموذج. بمجرد تحديد هذه الأمور، سنستخدم الضبط الذي حددناه سابقًا لتمرير هذه الإعدادات إلى الصنف ResNet لإنشاء النموذج بناءً على هذه الإعدادات. from transformers import PreTrainedModel from timm.models.resnet import BasicBlock, Bottleneck, ResNet from .configuration_resnet import ResnetConfig BLOCK_MAPPING = {"basic": BasicBlock, "bottleneck": Bottleneck} class ResnetModel(PreTrainedModel): config_class = ResnetConfig def __init__(self, config): super().__init__(config) block_layer = BLOCK_MAPPING[config.block_type] self.model = ResNet( block_layer, config.layers, num_classes=config.num_classes, in_chans=config.input_channels, cardinality=config.cardinality, base_width=config.base_width, stem_width=config.stem_width, stem_type=config.stem_type, avg_down=config.avg_down, ) def forward(self, tensor): return self.model.forward_features(tensor) الآن، سنعدّل التابع forward فقط بالنسبة للنموذج ResNet المخصص لتصنيف الصور، فهذا التابع يتعامل مع البيانات المدخلة، ويحدد كيف تتم معالجتها عبر طبقات النموذج للحصول على النتيجة المطلوبة، سنجري التعديل كما يلي: import torch class ResnetModelForImageClassification(PreTrainedModel): config_class = ResnetConfig def __init__(self, config): super().__init__(config) block_layer = BLOCK_MAPPING[config.block_type] self.model = ResNet( block_layer, config.layers, num_classes=config.num_classes, in_chans=config.input_channels, cardinality=config.cardinality, base_width=config.base_width, stem_width=config.stem_width, stem_type=config.stem_type, avg_down=config.avg_down, ) def forward(self, tensor, labels=None): logits = self.model(tensor) if labels is not None: loss = torch.nn.cross_entropy(logits, labels) return {"loss": loss, "logits": logits} return {"logits": logits} نلاحظ في كلتا الحالتين كيف ورثنا الصنف PreTrainedModel واستدعينا تهيئة الصنف الأب باستخدام الضبط config كما يحدث عندما نكتب وحدة torch.nn.Module عادية في PyTorch. ولا يُعَد السطر الذي يضبط config_class إلزاميًا، إلا إذا أردنا تسجيل نموذجنا في الأصناف التلقائية Auto Classes أي عندما نرغب بأن نتيح لمنصة Hugging Face تحديد النموذج تلقائيًا بناءً على الضبط كما سنوضح لاحقًا. ملاحظة: إذا كان نموذجنا مماثلًا لنموذج آخر موجود مسبقًا في المكتبة Transformers، فيمكن إعادة استخدام الضبط الخاص بهذا النموذج نفسه. يمكن جعل نموذجنا يعيد أي مخرجات نريدها، ولكن ستؤدي إعادة قاموس Dictionary كما فعلنا مع الصنف ResnetModelForImageClassification مع تضمين الخسارة عند تمرير التسميات التوضيحية Labels إلى جعل نموذجك قابلًا للاستخدام مباشرة في الصنف Trainer. يُعدّ استخدام تنسيق خرج آخر جيدًا طالما أنك تخطط لاستخدام حلقة تدريب خاصة بك أو أي مكتبة أخرى للتدريب. أصبح لدينا صنف النموذج الخاص بنا، فلننشئ الآن نموذجًا كما يلي: resnet50d = ResnetModelForImageClassification(resnet50d_config) يمكننا استخدام أي تابع من توابع الصنف PreTrainedModel مثل التابع save_pretrained()‎ أو push_to_hub()‎، حيث سنستخدم التابع الثاني في القسم التالي وسنرى كيفية دفع أوزان النموذج باستخدام الشيفرة البرمجية الخاصة بنموذجنا، ولكن لنحمّل أولًا بعض الأوزان المدرَّبة مسبقًا في نموذجنا. يمكن أن ندرّب نموذجنا المخصّص على بياناتنا الخاصة في حالة استخدامه بشكل مخصص، ولكن سنستخدم في هذا المقال النسخة المدرَّبة مسبقًا من الضبط resnet50d، وبما أن نموذجنا يحتوي على مغلِّف فقط، فسيكون من السهل نقل هذه الأوزان كما يلي: import timm pretrained_model = timm.create_model("resnet50d", pretrained=True) resnet50d.model.load_state_dict(pretrained_model.state_dict()) لنوضّح الآن كيفية التأكد من حفظ شيفرة النموذج البرمجية عند تنفيذ التابع save_pretrained()‎ أو push_to_hub()‎. تسجيل النموذج في الأصناف التلقائية Auto Classes إذا أردنا كتابة مكتبة توسّع المكتبة Transformers، فقد نرغب في توسيع الأصناف التلقائية لتضمين نموذجنا الخاص، ويختلف ذلك عن دفع الشيفرة البرمجية إلى المستودع Hub، إذ سيحتاج المستخدمون لاستيراد مكتبتنا هذه للحصول على النموذج المخصَّص على عكس تنزيل شيفرة النموذج البرمجية تلقائيًا من المستودع Hub. إذا احتوى الضبط على السمة model_type التي تختلف عن أنواع النماذج الموجودة مسبقًا واحتوت أصناف نموذجنا على سمات config_class الصحيحة، فيمكن إضافتها إلى الأصناف التلقائية كما يلي: from transformers import AutoConfig, AutoModel, AutoModelForImageClassification AutoConfig.register("resnet", ResnetConfig) AutoModel.register(ResnetConfig, ResnetModel) AutoModelForImageClassification.register(ResnetConfig, ResnetModelForImageClassification) نلاحظ أن الوسيط الأول المُستخدَم عند تسجيل ضبطنا المخصص في الصنف التلقائي AutoConfig يجب أن يتطابق مع السمة model_type لضبطنا المخصص، ويجب أن يتطابق الوسيط الأول المُستخدَم عند تسجيل النماذج المخصَّصة في أي صنف نموذج تلقائي مع السمة config_class لتلك النماذج. إرسال الشيفرة البرمجية للمستودع علينا التأكّد أولًا من تعريف نموذجنا الكامل في ملف بايثون ‎.py، حيث يمكن الاعتماد على الاستيراد النسبي لبعض الملفات الأخرى طالما أن جميع الملفات موجودة في المجلد نفسه، فالوحدات الفرعية لهذه الميزة غير مدعومة حتى الآن. سنعرّف في مثالنا ملف modeling_resnet.py وملف configuration_resnet.py في مجلد ضمن مجلد العمل الحالي resnet_model، ويحتوي ملف الضبط على الشيفرة البرمجية الخاصة بالصنف ResnetConfig، ويحتوي ملف النموذج على الشيفرة البرمجية الخاصة بالصنفين ResnetModel و ResnetModelForImageClassification. . └── resnet_model ├── __init__.py ├── configuration_resnet.py └── modeling_resnet.py يمكن أن يكون الملف ‎__init__.py فارغًا، لكنه موجود لتتمكّن لغة بايثون من اكتشاف إمكانية استخدام resnet_model كوحدة Module مما يعني أنه يمكن استيراد المكونات والملفات من هذا المجلد في برامج بايثون أخرى. ملاحظة1: إذا أردنا نسخ ملفات النموذج من المكتبة إلى مشروعنا الخاص، فيجب استبدال جميع تعليمات الاستيراد النسبية في أعلى الملف واستيرادها مباشرة من حزمة transformers. ملاحظة2: تُعدّ واجهة التطبيقات البرمجية API هذه تجريبية وقد تحتوي على بعض التغييرات في الإصدارات اللاحقة. بإمكاننا إعادة استخدام أو إنشاء صنف فرعي لضبط أو لنموذج موجود مسبقًا، ويمكن مشاركة نموذجنا مع المجتمع من خلال استيراد نموذج وضبط ResNet أولًا من الملفات التي أنشأناها كما يلي: from resnet_model.configuration_resnet import ResnetConfig from resnet_model.modeling_resnet import ResnetModel, ResnetModelForImageClassification بعد ذلك، علينا إخبار المكتبة بأننا نريد نسخ ملفات الشيفرة البرمجية لتلك الكائنات عند استخدام التابع save_pretrained وتسجيلها بطريقة صحيحة في صنف تلقائي محدّد وخاصةً بالنسبة للنماذج، لذا ننفّذ التعليمات التالية: ResnetConfig.register_for_auto_class() ResnetModel.register_for_auto_class("AutoModel") ResnetModelForImageClassification.register_for_auto_class("AutoModelForImageClassification") نلاحظ أنه لا حاجة لتحديد صنف تلقائي للضبط Config، إذ يوجد صنف تلقائي واحد فقط له هو AutoConfig، ولكن يختلف الأمر بالنسبة للنموذج Model، فالنماذج في مكتبة المحولات Transformers قد تُستَخدم في مهام مختلفة مثل توليد النصوص، أو الترجمة أو تصنيف الصور، لذا يتوجب علينا تحديد الصنف التلقائي المناسب بناءً على نوع النموذج والمهمة التي يؤديها. عندما نريد جعل نموذجنا الخاص قابلاً للاستخدام في مكتبة Transformers وتسجيله ضمن النماذج التلقائية مثل AutoModel, AutoConfig، يجب استخدام التابعregister_for_auto_class()‎ لتسجيل النموذج بشكل صحيح، وإذا كنا نفضل استخدام الشيفرة البرمجية الموجودة على المستودع Hub من مستودع آخر، فلن تحتاج لاستدعاء هذا التابع. يمكننا تعديل الملف config.json مباشرة باستخدام البنية التالية في الحالات التي يوجد فيها أكثر من صنف تلقائي: "auto_map": { "AutoConfig": "<your-repo-name>--<config-name>", "AutoModel": "<your-repo-name>--<config-name>", "AutoModelFor<Task>": "<your-repo-name>--<config-name>", }, لننشئ بعد ذلك الضبط والنماذج كما فعلنا سابقًا: resnet50d_config = ResnetConfig(block_type="bottleneck", stem_width=32, stem_type="deep", avg_down=True) resnet50d = ResnetModelForImageClassification(resnet50d_config) pretrained_model = timm.create_model("resnet50d", pretrained=True) resnet50d.model.load_state_dict(pretrained_model.state_dict()) لنتأكّد الآن من تسجيل الدخول لإرسال النموذج إلى المستودع Hub، لذا نشغّل الأمر التالي في الطرفية Terminal: huggingface-cli login أو نكتب من تطبيق المفكرة ما يلي: from huggingface_hub import notebook_login notebook_login() يمكن بعد ذلك رفع النموذج إلى فضاء الأسماء Namespace الخاص بحسابنا على Hugging Face كما يلي: resnet50d.push_to_hub("custom-resnet50d") ترفع التعليمة النموذج resnet50d إلى المستودع Hugging Face Hub باسم custom-resnet50d وتجعل النموذج متاحًا لاستخدامه مباشرة في المنصة Hugging Face. حيث تُنسَخ ملفات ‎.py للنموذج وللضبط بالإضافة إلى أوزان النموذج والضبط بتنسيق json في المجلد custom-resnet50d وستُرفَع النتيجة للمستودع Hub، ويمكننا التحقق من النتيجة في مستودع النماذج على منصة Huggingface. وللمزيد حول طريقة الدفع إلى المستودع Hub ننصح بمطالعة مقال مشاركة نموذج ذكاء اصطناعي على منصة Hugging Face . استخدام نموذج مع شيفرة برمجية مخصصة يمكن استخدام أي ضبط أو نموذج أو مرمِّز Tokenizer مع ملفات الشيفرة البرمجية المخصَّصة في مستودعها باستخدام الأصناف التلقائية والتابع from_pretrained، حيث تُفحَص جميع الملفات والشيفرات البرمجية المرفوعة إلى المستودع Hub بحثًا عن البرامج الضارة، ولمزيد من التفاصيل يُنصَح بمطالعة توثيق أمان Hub، ويجب أيضًا مراجعة شيفرة النموذج والتحقق من كاتبها لتجنّب تنفيذ شيفرة برمجية ضارة. سنضبط القيمة trust_remote_code=True لاستخدام نموذج مع شيفرة برمجية مخصصة كما يلي: from transformers import AutoModelForImageClassification model = AutoModelForImageClassification.from_pretrained("sgugger/custom-resnet50d", trust_remote_code=True) يُفضَّل أيضًا تمرير قيمة تعمية الإيداع Commit Hash إلى سمة المراجعة revision للتأكّد من أن كاتب النماذج لم يُحدّث الشيفرة البرمجية ببعض الأسطر الجديدة الضارة. commit_hash = "ed94a7c6247d8aedce4647f00f20de6875b5b292" model = AutoModelForImageClassification.from_pretrained( "sgugger/custom-resnet50d", trust_remote_code=True, revision=commit_hash ) نلاحظ وجود زر لنسخ قيمة تعمية الإيداع commit hash يمكننا من خلاله نسخ التعديل بسهولةعند تصفح سجل الإيداعات الخاص بمستودع النماذج الموجود على Hugging Face Hub. الخلاصة شرحنا في مقال اليوم كيفية كتابة نموذج مخصَّص وضبطه وطريقة استخدامه في مكتبة المحوّلات Transformers، كما شرحنا كيفية مشاركته مع المجتمع على مستودع Hugging Face Hub ليتمكّن أي شخص من استخدامه. ترجمة -وبتصرّف- للقسم Building custom models من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: استخدام مكتبة المرمزات Tokenizers في منصة Hugging Face استخدام وكلاء مكتبة المحولات Transformers Agents في الذكاء الاصطناعي التوليدي تدريب المًكيَّفات PEFT Adapters بدل تدريب نماذج الذكاء الاصطناعي بالكامل استخدام التدريب الموزع ومكتبة Accelerate لتسريع تدريب نماذج الذكاء الاصطناعي
  4. توفر مكتبة Transformers من منصة Hugging Face العديد من الأدوات المفيدة لبناء وتشغيل النماذج اللغوية الحديثة. ومن بين هذه الأدوات الصنف AutoClass لتحميل النماذج مسبقة التدريب بسهولة، حيث يحمّل AutoClass الإعدادات والأوزان المدربة مسبقًا بما يتناسب مع بنية النموذج، لكن هناك بعض الحالات التي قد نحتاج فيها لتحكم أكبر في معاملات النموذج، وإنشاء نموذج مخصص دون الاعتماد على الصنف AutoClass، وهو ما سنوضحه في هذا المقال. أهمية بناء نموذج مخصص يستدل الصنف AutoClass في مكتبة المحوّلات Transformers على بنية النموذج تلقائيًا ويحمّل الضبط Configuration والأوزان المدربة مسبقًا، حيث يوصى باستخدام هذا الصنف لإنتاج شيفرة برمجية مستقلة عن نقاط التحقق Checkpoint، ولكن يمكن للمستخدمين الذين يريدون مزيدًا من التحكم في معاملات النموذج المحددة إنشاء نموذج مخصص باستخدام مكتبة المحولات Transformers من بعض الأصناف الأساسية فقط. يمكن أن يكون ذلك مفيدًا لأي شخص مهتم بدراسة أو تدريب أو تجربة نموذج من مكتبة Transformers من منصة Huggingface، لذا سنتعمق أكثر في إنشاء نموذج مخصص بدون الصنف AutoClass، حيث سنتعلم كيفية: تحميل ضبط النموذج وتخصيصه إنشاء بنية نموذج إنشاء مرمِّز Tokenizer للنص إنشاء معالج صور للمهام البصرية إنشاء مستخرج ميزات للمهام الصوتية إنشاء معالج مهام متعددة الوسائط الضبط Configuration يمثّل الضبط Configuration السمات Attributes المحدَّدة للنموذج، حيث يكون لكل ضبط خاص بالنموذج سمات مختلفة، فمثلًا تحتوي جميع نماذج معالجة اللغات الطبيعية NLP على السمات hidden_size و num_attention_heads و num_hidden_layers و vocab_size وتحدّد هذه السمات عدد رؤوس الانتباه Attention Heads أو الطبقات المخفية التي سنبني نموذجًا باستخدامها. يمكن مطالعة على سمات النموذج DistilBERT من خلال الوصول إلى صنف الضبط DistilBertConfig كما يلي: >>> from transformers import DistilBertConfig >>> config = DistilBertConfig() >>> print(config) DistilBertConfig { "activation": "gelu", "attention_dropout": 0.1, "dim": 768, "dropout": 0.1, "hidden_dim": 3072, "initializer_range": 0.02, "max_position_embeddings": 512, "model_type": "distilbert", "n_heads": 12, "n_layers": 6, "pad_token_id": 0, "qa_dropout": 0.1, "seq_classif_dropout": 0.2, "sinusoidal_pos_embds": false, "transformers_version": "4.16.2", "vocab_size": 30522 } يعرض الصنف DistilBertConfig جميع السمات الافتراضية المستخدمة لبناء النموذج DistilBertModel الأساسي، وتكون جميع السمات قابلة للتخصيص، مما يعطينا مساحة للتجريب، فمثلًا يمكننا تخصيص نموذج افتراضي بهدف: تجربة دالة تنشيط مختلفة باستخدام المعامل activation استخدام نسبة تسرب Dropout Ratio أعلى لاحتمالات الانتباه باستخدام المعامل attention_dropout >>> my_config = DistilBertConfig(activation="relu", attention_dropout=0.4) >>> print(my_config) DistilBertConfig { "activation": "relu", "attention_dropout": 0.4, "dim": 768, "dropout": 0.1, "hidden_dim": 3072, "initializer_range": 0.02, "max_position_embeddings": 512, "model_type": "distilbert", "n_heads": 12, "n_layers": 6, "pad_token_id": 0, "qa_dropout": 0.1, "seq_classif_dropout": 0.2, "sinusoidal_pos_embds": false, "transformers_version": "4.16.2", "vocab_size": 30522 } ملاحظة: معدل التسرب Dropout Ratio هو تقنية مفيدة في تدريب الشبكات العصبية تساعد على منع الإفراط في التكيّف من خلال تعطيل بعض الخلايا العصبية عشوائيًا أثناء التدريب، وهذا يزيد قدرة النموذج على التعميم ويجعله أكثر قدرة على التعامل مع بيانات جديدة. يمكننا تعديل سمات النموذج المدرَّب مسبقًا في الدالة from_pretrained()‎ كما يلي: >>> my_config = DistilBertConfig.from_pretrained("distilbert/distilbert-base-uncased", activation="relu", attention_dropout=0.4) يمكننا حفظ ضبط النموذج باستخدام الدالة save_pretrained()‎ بعد الانتهاء منه كما يلي، ويُخزَّن ملف الضبط الخاص بنا كملف JSON في مجلد الحفظ المحدَّد: >>> my_config.save_pretrained(save_directory="./your_model_save_path") يمكننا إعادة استخدام ملف الضبط من خلال تحميله باستخدام الدالة from_pretrained()‎ كما يلي: >>> my_config = DistilBertConfig.from_pretrained("./your_model_save_path/config.json") ملاحظة: يمكننا أيضًا حفظ ملف الضبط الخاص بنا على هيئة قاموس Dictionary أو حتى كمجرد فرق بين سمات الضبط المخصصة وسمات الضبط الافتراضية. يمكن الاطلاع على توثيق الضبط على منصة Huggingface لمزيد من التفاصيل. النموذج Model سننشئ الآن نموذجًا، حيث يحدّد النموذج أو كما يشار إليه أحيانًا باسم البنية Architecture ما تفعله كل طبقة وما هي العمليات التي تحدث، وتُستخدَم السمات مثل num_hidden_layers من الضبط لتحديد هذه البنية. تتشارك جميع النماذج في الصنف الأساسي PreTrainedModel وبعض التوابع المشتركة مثل تغيير حجم تضمينات الإدخال وتقليم Pruning رؤوس الانتباه الذاتي Self-attention Heads أو تقليل الأجزاء غير الضرورية أو الفائضة من النموذج لتحسين كفاءته. تكون جميع النماذج أيضًا إما الصنف الفرعي torch.nn.Module أو tf.keras.Model أو flax.linen.Module، وهذا يعني أن النماذج متوافقة مع استخدام كل إطار عمل خاص بها. في حال كنا نستخدم إطار العمل بايتورش Pytorch نحمّل سمات الضبط المخصصة الخاصة بنا في النموذج كما يلي: >>> from transformers import DistilBertModel >>> my_config = DistilBertConfig.from_pretrained("./your_model_save_path/config.json") >>> model = DistilBertModel(my_config) مما يؤدي لإنشاء نموذج مع قيم عشوائية بدل أوزان مُدرَّبة مسبقًا، ولكننا لن نتمكّن من استخدام هذا النموذج استخدامًا مفيدًا حتى ندرّبه. فالتدريب عملية مكلفة وتستغرق وقتًا طويلًا، لذا يُفضَّل استخدام نموذج مدرب مسبقًا للحصول على نتائج أفضل وأسرع مع استخدام جزء بسيط فقط من الموارد المطلوبة للتدريب، لذا سننشئ نموذجًا مدربًا مسبقًا باستخدام الدالة from_pretrained()‎ كما يلي: >>> model = DistilBertModel.from_pretrained("distilbert/distilbert-base-uncased") يُحمَّل ضبط النموذج الافتراضي تلقائيًا عند تحميل الأوزان المُدرَّبة مسبقًا إذا وفرت مكتبة المحوّلات Transformers هذا النموذج، ولكن لا يزال بإمكاننا وضع سماتنا الخاصة مكان بعض أو جميع سمات ضبط النموذج الافتراضي إذا أردنا ذلك كما يلي: >>> model = DistilBertModel.from_pretrained("distilbert/distilbert-base-uncased", config=my_config) وفي حال استخدمنا إطار العمل تنسرفلو TensorFlow، فحمّل سمات الضبط المخصصة في النموذج كما يلي: >>> from transformers import TFDistilBertModel >>> my_config = DistilBertConfig.from_pretrained("./your_model_save_path/my_config.json") >>> tf_model = TFDistilBertModel(my_config) مما يؤدي إلى إنشاء نموذج مع قيم عشوائية بدلًا من أوزان مُدرَّبة مسبقًا، ولكن لن نتمكّن من استخدام هذا النموذج استخدامًا مفيدًا حتى ندربه. إذ يُعَد التدريب عملية مكلفة وتستغرق وقتًا طويلًا، لذا يُفضّل استخدام نموذج مدرّب مسبقًا للحصول على نتائج أفضل وأسرع مع استخدام جزء بسيط فقط من الموارد المطلوبة للتدريب، لذا سننشئ نموذجًا مدربًا مسبقًا باستخدام الدالة from_pretrained()‎ كما يلي: >>> tf_model = TFDistilBertModel.from_pretrained("distilbert/distilbert-base-uncased") يُحمَّل ضبط النموذج الافتراضي تلقائيًا عند تحميل الأوزان المُدرَّبة مسبقًا إذا وفّرت مكتبة المحوّلات Transformers هذا النموذج، ولكن لا يزال بإمكاننا وضع سماتنا الخاصة مكان بعض أو جميع سمات ضبط النموذج الافتراضي إذا أردنا ذلك كما يلي: >>> tf_model = TFDistilBertModel.from_pretrained("distilbert/distilbert-base-uncased", config=my_config) رؤوس النماذج Model heads أصبح لدينا نموذج DistilBERT أساسي يعطي الحالات المخفية Hidden States التي تُمرَّر كدخل إلى رأس النموذج لإنتاج الخرج النهائي. توفر مكتبة المحوّلات Transformers رأس نموذج مختلف لكل مهمة طالما أن النموذج يدعم المهمة، أي لا يمكنك استخدام النموذج DistilBERT لمهمة التحويل من تسلسل إلى آخر Sequence-to-Sequence مثل مهمة الترجمة. في حال استخدمنا إطار العمل Pytorch مع مكتبة Transformers، فإن النموذج DistilBertForSequenceClassification مثلًا هو نموذج DistilBERT أساسي مع رأس لتصنيف التسلسل، وهو بمثابة طبقة خطية فوق الخرج المجمَّع. إذًا سننشئ هذا النموذج كما يلي: >>> from transformers import DistilBertForSequenceClassification >>> model = DistilBertForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased") يمكننا إعادة استخدام نقطة التحقق السابقة بسهولة لمهمة أخرى من خلال التبديل إلى رأس نموذج مختلف، حيث يمكنك استخدام رأس النموذج DistilBertForQuestionAnswering بالنسبة لمهمة الإجابة على سؤال كما يلي، إذ يشبه رأس الإجابة على سؤال رأس تصنيف التسلسل باستثناء أنه طبقة خطية فوق خرج الحالات المخفية: >>> from transformers import DistilBertForQuestionAnswering >>> model = DistilBertForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased") وإذا كنا تستخدم إطار العمل تنسرفلو TensorFlow، فإن النموذج TFDistilBertForSequenceClassification مثلًا هو نموذج DistilBERT أساسي مع رأس لتصنيف التسلسل، والذي يُعَد طبقة خطية فوق الخرج المجمَّع. إذًا لننشئ هذا النموذج كما يلي: >>> from transformers import TFDistilBertForSequenceClassification >>> tf_model = TFDistilBertForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased") يمكننا إعادة استخدام نقطة التحقق السابقة بسهولة لمهمة أخرى من خلال التبديل إلى رأس نموذج مختلف، حيث يمكننا استخدام رأس النموذج TFDistilBertForQuestionAnswering بالنسبة لمهمة الإجابة على سؤال كما يلي، إذ يشبه رأس الإجابة على سؤال رأس تصنيف التسلسل باستثناء أنه طبقة خطية فوق خرج الحالات المخفية: >>> from transformers import TFDistilBertForQuestionAnswering >>> tf_model = TFDistilBertForQuestionAnswering.from_pretrained("distilbert/distilbert-base-uncased") المرمّز Tokenizer الصنف الأساسي الأخير الذي نحتاجه قبل استخدام نموذج للبيانات النصية هو المرمّز tokenizer لتحويل النص الأولي إلى موترات Tensors، حيث يوجد نوعان من المرمّزات يمكنك استخدامهما مع مكتبة المحولات Transformers هما: PreTrainedTokenizer وهو تنفيذ لغة بايثون Python للمرمّز PreTrainedTokenizerFast: هو مرمّز من مكتبة Tokenizer ويستند إلى لغة رست Rust، وتكون سرعة هذا النوع من المرمّزات ملحوظة وخاصة أثناء الترميز الدفعي Batch Tokenization بسبب تنفيذه باستخدام لغة رست. ويقدّم المرمِّز السريع توابع إضافية مثل ربط الإزاحة Offset Mapping الذي يربط الرموز Tokens بكلماتها أو محارفها الأصلية. يدعم هذان المرمِّزان التوابع الشائعة مثل التشفير وفك التشفير وإضافة رموز جديدة وإدارة الرموز الخاصة. ملاحظة: لا تدعم جميع النماذج المرمِّز السريع، لذا ألقِ نظرة على الجدول الموجود في مقال مكتبة المحوّلات Transformers من منصة Hugging Face للتحقق من دعم النموذج للمرمِّز السريع. يمكنك إنشاء مرمّز من ملف المفردات vocabulary الخاص بنا كما يلي لإنشاء خاص مرمّز بنا: >>> from transformers import DistilBertTokenizer >>> my_tokenizer = DistilBertTokenizer(vocab_file="my_vocab_file.txt", do_lower_case=False, padding_side="left") يجب أن نتذكر أن المفردات القادمة من المرمّز المخصَّص ستكون مختلفة عن المفردات التي يولّدها مرمّز النموذج المُدرَّب مسبقًا، لذا سنحتاج لاستخدام مفردات نموذج مدرب مسبقًا إذا استخدمنا نموذج مُدرَّب مسبقًا، وإلّا لن يكون للدخل أي معنى. لننشئ مرمّز باستخدام مفردات نموذج مدرب مسبقًا باستخدام الصنف DistilBertTokenizer كما يلي: >>> from transformers import DistilBertTokenizer >>> slow_tokenizer = DistilBertTokenizer.from_pretrained("distilbert/distilbert-base-uncased") ولننشئ مرمّز سريع باستخدام الصنف DistilBertTokenizerFast كما يلي: >>> from transformers import DistilBertTokenizerFast >>> fast_tokenizer = DistilBertTokenizerFast.from_pretrained("distilbert/distilbert-base-uncased") ملاحظة: سيحاول الصنف AutoTokenizer افتراضيًا تحميل مرمّز سريع، ولكن يمكنك تعطيل هذا السلوك من خلال ضبط القيمة use_fast=False في الدالة from_pretrained. معالج الصور Image Processor يعالج معالج الصور المدخلات البصرية، وهو يرث الصنف ImageProcessingMixin الأساسي، ويمكن استخدامه من خلال إنشاء معالج صور مرتبط بالنموذج الذي تستخدمه، فمثلًا يمكننا إنشاء صنف ViTImageProcessor افتراضي كما يلي، إذا كنا نستخدم النموذج ViT أو المحوّل البصري Vision Transformer لتصنيف الصور: >>> from transformers import ViTImageProcessor >>> vit_extractor = ViTImageProcessor() >>> print(vit_extractor) ViTImageProcessor { "do_normalize": true, "do_resize": true, "image_processor_type": "ViTImageProcessor", "image_mean": [ 0.5, 0.5, 0.5 ], "image_std": [ 0.5, 0.5, 0.5 ], "resample": 2, "size": 224 } ملاحظة: إن لم نكن نريد تخصيص أيّ شيء، فما علينا سوى استخدام التابع from_pretrained لتحميل معاملات معالج الصور الافتراضية للنموذج. لنعدّل الآن أحد معاملات الصنف ViTImageProcessor لإنشاء معالج الصور المخصَّص كما يلي: >>> from transformers import ViTImageProcessor >>> my_vit_extractor = ViTImageProcessor(resample="PIL.Image.BOX", do_normalize=False, image_mean=[0.3, 0.3, 0.3]) >>> print(my_vit_extractor) ViTImageProcessor { "do_normalize": false, "do_resize": true, "image_processor_type": "ViTImageProcessor", "image_mean": [ 0.3, 0.3, 0.3 ], "image_std": [ 0.5, 0.5, 0.5 ], "resample": "PIL.Image.BOX", "size": 224 } العمود الفقري Backbone تتكون نماذج الرؤية الحاسوبية من العمود الفقري Backbone والعنق Neck والرأس Head، حيث يستخرج العمود الفقري الميزات Features من صورة الدخل، ويجمع العنق الميزات المستخرجة ويحسّنها، ويُستخدم الرأس للمهمة الرئيسية مثل اكتشاف الكائنات. دعنا نبدأ بتهيئة العمود الفقري في ضبط النموذج ونحدد تحميل أوزان مدرَّبة مسبقًا أو تحميل أوزان مُهيَّأة عشوائيًا، ثم يمكننا تمرير ضبط النموذج إلى الرأس. إذا أردنا مثلًا تحميل العمود الفقري ResNet في النموذج MaskFormer باستخدام رأس تقسيم أجزاء الصورة كما يلي: <hfoptions id="backbone"> <hfoption id="pretrained weights"> فيجب ضبط القيمة use_pretrained_backbone=True لتحميل أوزان ResNet المدرَّبة مسبقًا للعمود الفقري كما يلي: from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation config = MaskFormerConfig(backbone="microsoft/resnet-50", use_pretrained_backbone=True) # ضبط العمود الفقري والعنق model = MaskFormerForInstanceSegmentation(config) # الرأس وإذا أردنا تحميل العمود الفقري ResNet في النموذج MaskFormer باستخدام رأس تقسيم أجزاء الصورة كما يلي: </hfoption> <hfoption id="random weights"> فيجب ضبط القيمة use_pretrained_backbone=False لتهيئة العمود الفقري ResNet عشوائيًا كما يلي: from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation config = MaskFormerConfig(backbone="microsoft/resnet-50", use_pretrained_backbone=False) # ضبط العمود الفقري والعنق model = MaskFormerForInstanceSegmentation(config) # الرأس يمكن أيضًا تحميل ضبط العمود الفقري بطريقة منفصلة ثم تمريره إلى ضبط النموذج كما يلي: from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation, ResNetConfig backbone_config = ResNetConfig() config = MaskFormerConfig(backbone_config=backbone_config) model = MaskFormerForInstanceSegmentation(config) تُحمَّل نماذج المكتبة timm ضمن نموذج كما يلي باستخدام القيمة use_timm_backbone=True أو باستخدام الصنف TimmBackbone والصنف TimmBackboneConfig: </hfoption> </hfoptions id="timm backbone"> لذا سنستخدم القيمة use_timm_backbone=True و use_pretrained_backbone=True لتحميل أوزان timm المدرَّبة مسبقًا للعمود الفقري كما يلي: from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation config = MaskFormerConfig(backbone="resnet50", use_pretrained_backbone=True, use_timm_backbone=True) # ضبط العمود الفقري والعنق model = MaskFormerForInstanceSegmentation(config) # الرأس ولنضبط الآن القيمة use_timm_backbone=True و use_pretrained_backbone=False لتحميل العمود الفقري timm المهيَّأ عشوائيًا كما يلي: from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation config = MaskFormerConfig(backbone="resnet50", use_pretrained_backbone=False, use_timm_backbone=True) # ضبط العمود الفقري والعنق model = MaskFormerForInstanceSegmentation(config) # الرأس يمكننا أيضًا تحميل ضبط العمود الفقري واستخدامه لإنشاء الصنف TimmBackbone أو تمريره إلى ضبط النموذج، حيث ستحمّل الأعمدة الفقرية Timm الأوزان المدرَّبة مسبقًا افتراضيًا، لذا سنضبط القيمة use_pretrained_backbone=False لتحميل الأوزان المُهيَّأة عشوائيًا كما يلي: from transformers import TimmBackboneConfig, TimmBackbone backbone_config = TimmBackboneConfig("resnet50", use_pretrained_backbone=False) # إنشاء صنف العمود الفقري backbone = TimmBackbone(config=backbone_config) # إنشاء نموذج باستخدام العمود الفقري‫ timm from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation config = MaskFormerConfig(backbone_config=backbone_config) model = MaskFormerForInstanceSegmentation(config) مستخرج الميزات Feature Extractor يعالج مستخرج الميزات المدخلات الصوتية، وهو يرث الصنف FeatureExtractionMixin الأساسي، ويمكن أن يرث أيضًا الصنف SequenceFeatureExtractor لمعالجة المدخلات الصوتية. لننشئ الآن مستخرج ميزات مرتبط بالنموذج الذي تستخدمه مثل إنشاء صنف Wav2Vec2FeatureExtractor افتراضي كما يلي إذا كنت تستخدم النموذج Wav2Vec2 لتصنيف الأصوات: >>> from transformers import Wav2Vec2FeatureExtractor >>> w2v2_extractor = Wav2Vec2FeatureExtractor() >>> print(w2v2_extractor) Wav2Vec2FeatureExtractor { "do_normalize": true, "feature_extractor_type": "Wav2Vec2FeatureExtractor", "feature_size": 1, "padding_side": "right", "padding_value": 0.0, "return_attention_mask": false, "sampling_rate": 16000 } ملاحظة: إن لم نكن نرغب بتخصيص أيّ شيء، فما علينا سوى استخدام التابع from_pretrained لتحميل معاملات مستخرج الميزات الافتراضية الخاصة بالنموذج. لنعدّل الآن أحد معاملات الصنف Wav2Vec2FeatureExtractor لإنشاء مستخرج الميزات المخصَّص الخاص بنا كما يلي: >>> from transformers import Wav2Vec2FeatureExtractor >>> w2v2_extractor = Wav2Vec2FeatureExtractor(sampling_rate=8000, do_normalize=False) >>> print(w2v2_extractor) Wav2Vec2FeatureExtractor { "do_normalize": false, "feature_extractor_type": "Wav2Vec2FeatureExtractor", "feature_size": 1, "padding_side": "right", "padding_value": 0.0, "return_attention_mask": false, "sampling_rate": 8000 } المعالج Processor تقدم مكتبة المحوِّلات Transformers صنف المعالج الذي يغلِّف أصناف المعالجة مثل مستخرج الميزات والمرمِّز في كائن واحد بالنسبة للنماذج التي تدعم المهام متعددة الوسائط. لنستخدم مثلًا الصنف Wav2Vec2Processor لمهمة التعرّف التلقائي على الكلام Automatic Speech Recognition أو ASR اختصارًا، والتي تحوّل الصوت إلى نص، لذا ستحتاج إلى مستخرج ميزات ومرمّز. لننشئ أولًا مستخرج ميزات للتعامل مع المدخلات الصوتية كما يلي: >>> from transformers import Wav2Vec2FeatureExtractor >>> feature_extractor = Wav2Vec2FeatureExtractor(padding_value=1.0, do_normalize=True) ثم ننشئ مرمّز للتعامل مع المدخلات النصية كما يلي: >>> from transformers import Wav2Vec2CTCTokenizer >>> tokenizer = Wav2Vec2CTCTokenizer(vocab_file="my_vocab_file.txt") ثم ندمج مستخرج الميزات والمرمّز في الصنف Wav2Vec2Processor كما يلي: >>> from transformers import Wav2Vec2Processor >>> processor = Wav2Vec2Processor(feature_extractor=feature_extractor, tokenizer=tokenizer) الخلاصة يمكننا إنشاء أي من النماذج التي تدعمها مكتبة المحولات Transformers من منصة Huggingface باستخدام صنفين أساسيين للضبط والنموذج وصنف إضافي للمعالجة المسبَقة مثل مرمِّز أو معالج صور أو مُستخرج ميزات أو معالج، وتكون هذه الأصناف الأساسية قابلة للضبط، مما يسمح لنا باستخدام السمات المحدَّدة التي نريدها، ويمكن بسهولة إعداد نموذج للتدريب أو تعديل نموذج مُدرَّب مسبقًا لصقله Fine-tune. ترجمة -وبتصرّف- للقسم Create a custom architecture من توثيقات Hugging Face. اقرأ أيضًا تثبيت مكتبة المحوّلات Transformers ما هي منصة Hugging Face للذكاء الاصطناعي مشاركة نموذج ذكاء اصطناعي على منصة Hugging Face بناء روبوتات للعب الألعاب باستخدام طريقة التعلم المعزز ومشتقاتها باستخدام مكتبة TensorFlow بناء شبكة عصبية للتعرف على الأرقام المكتوبة بخط اليد باستخدام مكتبة TensorFlow
  5. نشرح في هذا المقال كيفية استخدام مكتبة ترميز النصوص Tokenizers التي توفرها منصة Hugging Face ونشرح طريقة استخدامها لتقسيم النصوص إلى رموز أو وحدات صغيرة تسمى Tokens، كما نوضح الخطوات المتبعة لإنشاء مقسِّم نصوص باستخدام خوارزمية ترميز زوج البتات Byte Pair Encoding التي توفرها المكتبة ونشرح طريقة استخدامه وتدريبه على بيانات مخصصة. إنشاء مرمز نصوص سنستخدم الصنف PreTrainedTokenizerFast من المكتبة Tokenizers التابعة لمنصة Hugging Face والتي توفر لنا العديد من التوابع لترميز النصوص بسرعة وكفاءة، كما تتيح لنا إمكانية تحميل المُرمِّزات التي أنشأناها بسهولة للعمل داخل مكتبة المحولات Transformers، مما يسهل دمجها مع النماذج اللغوية. لنفهم أساسيات بناء مرمِّز مخصص باستخدام مكتبة Tokenizers من أجل تخصيصه لبيانات محددة أو تطبيقات خاصة، بدلاً من الاعتماد على مرمزات جاهزة قد لا تكون مثالية لجميع الحالات. لنبدأ أولًا بإنشاء مرمِّز تجريبي كما يلي قبل الدخول بالتفاصيل: >>> from tokenizers import Tokenizer >>> from tokenizers.models import BPE >>> from tokenizers.trainers import BpeTrainer >>> from tokenizers.pre_tokenizers import Whitespace >>> tokenizer = Tokenizer(BPE(unk_token="[UNK]")) >>> trainer = BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"]) >>> tokenizer.pre_tokenizer = Whitespace() >>> files = [...] >>> tokenizer.train(files, trainer) أصبح لدينا الآن مُرمِّز مُدرَّب على الملفات التي حددناها والتي تحتوي على النصوص المستخدمة لتدريب المرمِّز، وبالتالي يمكننا الاستمرار في استخدامه في وقت التشغيل أو حفظه في ملف JSON لإعادة استخدامه لاحقًا. التحميل المباشر من كائن المرمز لنوضح الآن كيف يمكننا الاستفادة من كائن المرمِّز الذي أنشأناه في الفقرة السابقة داخل مكتبة المحوّلات Transformers المخصصة لمعالجة اللغات الطبيعية NLP، حيث يسمح الصنف PreTrainedTokenizerFast بإنشاء نسخ جديدة بسهولة من خلال قبول نسخة كائن المرمِّز tokenizer كوسيط كما يلي: >>> from transformers import PreTrainedTokenizerFast >>> fast_tokenizer = PreTrainedTokenizerFast(tokenizer_object=tokenizer) ويمكن الآن استخدام هذا الكائن مع جميع التوابع المشتركة بين مرمِّزات مكتبة المحوّلات Transformers والتي تساعد في تحويل النصوص إلى تمثيلات قابلة للاستخدام في النماذج اللغوية، مما يسهل عملية التدريب والتنبؤ باستخدام نماذج المحوّلات المختلفة. تحميل المرمز من ملف JSON يمكن تحميل مرمَّز من ملف JSON من خلال حفظ المرمِّز أولًا كما يلي: >>> tokenizer.save("tokenizer.json") يمكننا بعد ذلك تمرير المسار الذي حفظنا فيه هذا الملف إلى تابع التهيئة الخاص بهذا الصنف PreTrainedTokenizerFast باستخدام المعامل tokenizer_file كما يلي: >>> from transformers import PreTrainedTokenizerFast >>> fast_tokenizer = PreTrainedTokenizerFast(tokenizer_file="tokenizer.json") ويمكن الآن استخدام هذا الكائن مع جميع التوابع المشتركة بين مرمِّزات مكتبة المحوِّلات Transformers. استخدام النماذج متعددة اللغات Multilingual Models للاستدلال توفر مكتبة المحوِّلات Transformers العديد من النماذج متعددة اللغات، وهي نماذج مدربة على بيانات متعددة اللغات ويمكنها التعامل مع نصوص بلغات مختلفة، يختلف استخدام هذه النماذج في الاستدلال والتنبؤ وتحليل النصوص عن النماذج التي تدعم لغة واحدة فقط في بعض الأحيان، ومع ذلك، يمكن استخدام معظم النماذج متعددة اللغات بنفس طريقة استخدام النماذج أحادية اللغة. على سبيل المثال، يمكننا استخدام نموذج مثل bert/bert-base-multilingual-uncased من جوجل بنفس طريقة استخدام النماذج أحادية اللغة، لكننا سنركز في الفقرات التالية على شرح النماذج متعددة اللغات التي يختلف استخدامها عن استخدام النماذج أحادية اللغة لإجراء عمليات الاستدلال. نموذج XLM يحتوي نموذج XLM متعدد اللغات على عشر نقاط تحقق Checkpoints مختلفة تمثل حالات مختلفة من تدريب النموذج، وتكون نقطة واحدة منها فقط أحادية اللغة بينما تتعامل النقاط التسع الأخرى مع لغات متعددة، ويمكن تقسيم هذه النقاط التسع إلى فئتين هما: نقاط التحقق التي تستخدم تضمينات اللغة Language Embeddings للتمييز بين اللغات المختلفة ونقاط التحقق التي لا تستخدم هذه التضمينات. ملاحظة: التضمينات اللغوية Language Embeddings هي طريقة لتحويل الكلمات والجمل إلى أرقام يمكن للنماذج الحاسوبية التعامل معها، الهدف منها هو جعل الحاسوب قادرًا على فهم اللغة البشرية ومعاني الكلمات بناءً على سياقها، فكلما كانت الكلمات ذات معاني مشابهة، ستكون تضميناتها العددية أقرب لبعضها وتستخدم في مجال الترجمة الآلية وتصنيف النصوص وتحليل المشاعر. نماذج XLM التي تستخدم تضمينات اللغة تستخدم نماذج XLM التالية تضمينات اللغة لتحديد اللغة المستخدمة في الاستدلال: FacebookAI/xlm-mlm-ende-1024 لنمذجة اللغة المقنّعة Masked Language Modeling، ويدعم اللغتين الإنجليزية والألمانية FacebookAI/xlm-mlm-enfr-1024 لنمذجة اللغة المقنّعة، ويدعم الإنجليزية والفرنسية FacebookAI/xlm-mlm-enro-1024 لنمذجة اللغة المقنّعة، ويدعم الإنجليزية والرومانية FacebookAI/xlm-mlm-xnli15-1024 لنمذجة اللغة المقنعة، ويعمل مع مجموعة اللغات المدرجة في مجموعة بيانات XNLI FacebookAI/xlm-mlm-tlm-xnli15-1024 لنمذجة اللغة المقنعة والترجمة، ويعمل مع لغات XNLI FacebookAI/xlm-clm-enfr-1024 لنمذجة اللغة السببية Causal Language Modeling ويعمل مع اللغة الإنجليزية والفرنسية FacebookAI/xlm-clm-ende-1024 لنمذجة اللغة السببية ويعمل مع اللغتين الإنجليزية والألمانية يُمثَّل تضمين اللغة على شكل موتر Tensor وهو بنية على شكل مصفوفة متعددة الأبعاد لها نفس حجم بنية input_ids المُمرَّرة إلى النموذج، وتعتمد القيم الموجودة في هذه الموترات على اللغة المستخدمة وتحددها السمات التالية lang2id و id2lang الخاصة بالمرمّز. ملاحظة: نمذجة اللغة السببية Causal Language Modeling هي نوع من نماذج تعلم الآلة تهدف إلى فهم وتوليد النصوص بناء على الترتيب السببي للكلمات، في هذا النوع من النمذجة يتنبأ النموذج بالكلمة التالية في تسلسل الكلمات بناءً على الكلمات التي جاءت قبلها فقط وليس بعدها. أي يتعامل النموذج مع النص بشكل أحادي الاتجاه من اليسار لليمين ويتوقع الكلمة التالية بناءً على الكلمات السابقة لها. على سبيل المثال لترميز الجملة "Wikipedia was used to" باستخدام المرمِّز Tokenizer وتحويلها لتسلسل من الأرقام التعريفية IDs التي يمكن للنموذج معالجتها سنحمّل بداية نقطة تحقق نموذج FacebookAI/xlm-clm-enfr-1024: >>> import torch >>> from transformers import XLMTokenizer, XLMWithLMHeadModel >>> tokenizer = XLMTokenizer.from_pretrained("FacebookAI/xlm-clm-enfr-1024") >>> model = XLMWithLMHeadModel.from_pretrained("FacebookAI/xlm-clm-enfr-1024") تحتوي السمة lang2id الخاصة بالمرمِّز على اللغات المدعومة في النموذج ومعرّفاتها IDs، كما في المثال التالي: >>> print(tokenizer.lang2id) {'en': 0, 'fr': 1} لننشئ بعد ذلك الدخل التالي: >>> input_ids = torch.tensor([tokenizer.encode("Wikipedia was used to")]) # حجم الدفعة هو 1 ثم نضبط معرّف اللغة على القيمة "en" ونستخدمه لتحديد تضمين اللغة وهو موتر tensor يحتوي على القيمة 0 التي تمثل معرّف اللغة الإنجليزية، ويجب أن يكون له نفس حجم البنية input_ids. >>> language_id = tokenizer.lang2id["en"] # 0 >>> langs = torch.tensor([language_id] * input_ids.shape[1]) # torch.tensor([0, 0, 0, ..., 0]) >>> # ‫نعيد تشكيله ليكون بحجم (batch_size, sequence_length) >>> langs = langs.view(1, -1) # ‫أصبح الآن بالشكل ‎[1, sequence_length]‎ (حجم الدفعة هو 1) ويمكنك الآن تمرير البنية input_ids وتضمين اللغة إلى النموذج من أجل فهم النص وتحليله كما يلي: >>> outputs = model(input_ids, langs=langs) سيؤدي تنفيذ السكربت run_generation.py إلى توليد نص مع تضمينات اللغة باستخدام نقاط تحقق xlm-clm. نماذج XLM التي لا تستخدم تضمينات اللغة لا تتطلب نماذج XLM التالية تضمينات اللغة أثناء الاستدلال إذ يستطيع النموذج فهم اللغة التي يتعامل معها بدون الحاجة إلى معرّف اللغة وهي: FacebookAI/xlm-mlm-17-1280 لنمذجة اللغة المقنّعة ويدعم 17 لغة FacebookAI/xlm-mlm-100-1280 لنمذجة اللغة المقنّعة ويدعم 100 لغة تستخدم هذه النماذج تمثيلات الجمل المُعمَّمة Generic Sentence Representations، على عكس نقاط تحقق نموذج XLM السابقة. نموذج BERT يمكن استخدام نماذج BERT التالية للمهام متعددة اللغات: google-bert/bert-base-multilingual-uncased لنمذجة اللغة المقنعة وتوقع الجملة التالية، تدعم 102 لغة google-bert/bert-base-multilingual-cased لنمذجة اللغة المقنعة وتوقع الجملة التالية، وتدعم 104 لغات لا تتطلب هذه النماذج تضمينات اللغة أثناء الاستدلال، فهي تحدِّد اللغة من السياق وتستدل عليها وفقًا لذلك. نموذج XLM-RoBERTa يمكن استخدام نماذج XLM-RoBERTa التالية للمهام متعددة اللغات: FacebookAI/xlm-roberta-base لنمذجة اللغة المقنعة، وتدعم 100 لغة FacebookAI/xlm-roberta-large لنمذجة اللغة المقنعة، وتدعم 100 لغة دُرِّب نموذج XLM-RoBERTa على 2.5 تيرابايت من بيانات CommonCrawl المُنشَأة والمُنظَّفة حديثًا وذلك في 100 لغة، ويحقق هذا النموذج تحسينات كبيرة بالمقارنة مع النماذج متعددة اللغات الصادرة سابقًا مثل mBERT أو XLM في المهام النهائية مثل التصنيف Classification والوسم أو تحديد التسميات تسلسليًا Sequence Labeling والإجابة على الأسئلة Question Answering. نموذج M2M100 يمكن استخدام نماذج M2M100 التالية للترجمة متعددة اللغات: facebook/m2m100_418M للترجمة facebook/m2m100_1.2B للترجمة لنحمّل مثلًا نقطة تحقق النموذج facebook/m2m100_418M للترجمة من الصينية إلى الإنجليزية، حيث يمكنك ضبط لغة المصدر في المرمِّز كالتالي: >>> from transformers import M2M100ForConditionalGeneration, M2M100Tokenizer >>> en_text = "Do not meddle in the affairs of wizards, for they are subtle and quick to anger." >>> chinese_text = "不要插手巫師的事務, 因為他們是微妙的, 很快就會發怒." >>> tokenizer = M2M100Tokenizer.from_pretrained("facebook/m2m100_418M", src_lang="zh") >>> model = M2M100ForConditionalGeneration.from_pretrained("facebook/m2m100_418M") ونرمِّز النص كما يلي: >>> encoded_zh = tokenizer(chinese_text, return_tensors="pt") يفرض النموذج M2M100 أن يكون معرّف اللغة المستهدفة هو أول Token مُولَّد لترجمته إلى اللغة المستهدفة، لذا نضبط المعرّف forced_bos_token_id على القيمة en في التابع generate للترجمة إلى اللغة الإنجليزية كما يلي: >>> generated_tokens = model.generate(**encoded_zh, forced_bos_token_id=tokenizer.get_lang_id("en")) >>> tokenizer.batch_decode(generated_tokens, skip_special_tokens=True) 'Do not interfere with the matters of the witches, because they are delicate and will soon be angry.' النموذج MBart يمكن استخدام نماذج MBart التالية للترجمة متعددة اللغات: facebook/mbart-large-50-one-to-many-mmt للترجمة الآلية متعددة اللغات من لغة إلى عدة لغات، ويدعم 50 لغة facebook/mbart-large-50-many-to-many-mmt للترجمة الآلية متعددة اللغات من عدة لغات إلى عدة لغات، ويدعم 50 لغة facebook/mbart-large-50-many-to-one-mmt للترجمة الآلية متعددة اللغات من عدة لغات إلى لغة واحدة، ويدعم 50 لغة facebook/mbart-large-50 للترجمة متعددة اللغات، ويدعم 50 لغة facebook/mbart-large-cc25 للترجمة الآلية متعددة اللغات، ويعمل مع 25 لغة لنحمّل مثلًا نقطة تحقق النموذج facebook/mbart-large-50-many-to-many-mmt لترجمة اللغة الفنلندية إلى اللغة الإنجليزية، ويمكنك ضبط لغة المصدر في المرمِّز كما يلي: >>> from transformers import AutoTokenizer, AutoModelForSeq2SeqLM >>> en_text = "Do not meddle in the affairs of wizards, for they are subtle and quick to anger." >>> fi_text = "Älä sekaannu velhojen asioihin, sillä ne ovat hienovaraisia ja nopeasti vihaisia." >>> tokenizer = AutoTokenizer.from_pretrained("facebook/mbart-large-50-many-to-many-mmt", src_lang="fi_FI") >>> model = AutoModelForSeq2SeqLM.from_pretrained("facebook/mbart-large-50-many-to-many-mmt") ونرمِّز النص كما يلي: >>> encoded_en = tokenizer(en_text, return_tensors="pt") يفرض النموذج MBart معرّف اللغة المستهدفة بوصفه أول رمز مُولَّد لترجمته إلى اللغة المستهدفة، لذا اضبط المعرّف forced_bos_token_id على القيمة en في التابع generate للترجمة إلى اللغة الإنجليزية كما يلي: >>> generated_tokens = model.generate(**encoded_en, forced_bos_token_id=tokenizer.lang_code_to_id["en_XX"]) >>> tokenizer.batch_decode(generated_tokens, skip_special_tokens=True) "Don't interfere with the wizard's affairs, because they are subtle, will soon get angry." إذا أدرتَ استخدام نقطة تحقق النموذج facebook/mbart-large-50-many-to-one-mmt، فلن تحتاج إلى فرض معرّف اللغة المستهدفة بوصفه أول رمز مُولَّد، وإلّا فسيبقى الاستخدام نفسه مع النماذج الأخرى. الخلاصة تعلمنا في هذا المقال كيفية استخدام مكتبة المرمزات Tokenizers من منصة Hugging Face، والتي تتيح تقسيم النصوص إلى رموز أو وحدات صغيرة Token. كما تناولنا طريقة إنشاء مرمِّز باستخدام أسلوب BPE وتدريبه على بيانات مخصصة. وشرحنا كيفية استخدام المرمِّز المُدرَّب داخل مكتبة المحولات Transformers وكيفية حفظه لإعادة استخدامه. واستعرضنا النماذج مثل XLM وBERT و XLM-RoBERTa التي تدعم تحليل النصوص بلغات متعددة وتستخدم لتطبيقات متنوعة مثل الترجمة والتنبؤ وتحليل النصوص. اقرأ أيضًا جولة سريعة للبدء مع مكتبة المحوّلات Transformers تعرف على مكتبة المحوّلات Transformers من منصة Hugging Face مشاركة نموذج ذكاء اصطناعي على منصة Hugging Face تثبيت مكتبة المحوّلات Transformers
  6. نناقش في مقال اليوم النماذج اللغوية الكبيرة LLMs وهي صاحبة الدور الرئيسي في توليد النصوص، فهي تتكون من نماذج ذكاء اصطناعي كبيرة من نوع المحولات transformer، ومُدَرَّبة مُسبقًا على مهمة التنبؤ بالكلمة التالية أو token التالي من أي مُوجه يعطى لها، فهي إذًا تتنبأ بكلمات فردية بمقدار كلمة واحدة في كل مرة، لذا فإن توليد الجمل الكاملة سيحتاج تقنيةً أوسع تسمى توليد الانحدار الذاتي autoregressive generation. ويُعرَّف توليد الانحدار الذاتي بأنه إجراءٌ استدلالي متكرر مع الزمن، يستدعي نموذج LLM مراتٍ متكررة وفي كل مرة يُمرر له المخرجات التي وَلَّدها في المرة السابقة كمدخلات وهكذا، وبطبيعة الحالة يحتاح إلى مدخلات ابتدائية نقدمها له ليستخدمها في الاستدعاء الأول للنموذج، وتوفر مكتبة المحولات Transformers تابعًا خاصًا لهذا الغرض هو generate()‎، يعمل جميع النماذج ذات الإمكانات التوليدية generative. نسعى في هذا المقال لتحقيق ثلاثة أهداف رئيسية: شرح كيفية توليد نص باستخدام نموذج لغوي كبير LLM الإضاءة على بعض المخاطر الشائعة لتتجنبها اقتراح بعض المصادر التي ستساعدك على تحقيق أقصى استفادة ممكنة من نماذج LLMs تأكد في البداية من تثبيت المكتبات الضرورية للعمل قبل أن نبدأ بالتفاصيل، وذلك وفق التالي: pip install transformers bitsandbytes>=0.39.0 -q توليد النص يأخذ النموذج اللغوي المُدَرَّب على النمذجة اللغوية السببية سلسلة من الرموز النصية كمدخلات inputs ويرجع بناءً عليها التوزع الاحتمالي للرمز التالي المتوقع، ألقِ نظرة على الصورة التوضيحية التالية: أما عن كيفية اختيار الرمز التالي من هذا التوزع الاحتمالي الناتج، فهي تختلف حسب الحالة، فقد تكون بسيطةً تتمثل بانتقاء الرمز الأكثر احتمالية من ضمن رموز التوزع الاحتمالي، أو معقدة لدرجة نحتاج معها لتطبيق عشرات التحويلات قبل الاختيار، وبصرف النظر عن طريقة الاختيار فإننا سنحصل بعد هذه المرحلة على رمز جديد نستخدمه في التكرار التالي أو الاستدعاء التالي للنموذج كما هو موضح في الصورة التالية لتوليد الانحدار الذاتي: تستمر عملية توليد الكلمات حتى نصل إلى أحد شروط التوقف التي يُحددها النموذج، ويتعلم النموذج متى ينبغي أن يرجع رمز نهاية السلسلة (EOS) الذي يُعدّ الإنهاء المثالي لعملية توليد النص، وفي حال لم يرجع النموذج هذا الرمز فسيظل العمل مستمرًا لحين الوصول إلى الحد الأقصى المسموح به من الرموز. إذًا فلديك أمرين مهمين ينبغي أن تهتم بهما ليعمل نموذجك التوليدي بالطريقة المرجوة، الأمر الأول هو كيفية اختيار الرمز التالي من بين رموز التوزع الاحتمالي، والأمر الثاني هو تحديد شرط إنهاء التوليد، تُضبط هذه الإعدادات في ملف إعدادات التوليد GenerationConfig الخاص بكل نموذج توليدي، يُحَمَّل هذا الملف مع النموذج وهو يتضنت معاملاتٍ افتراضية مناسبة له. لنبدأ الآن بالتطبيق العملي، حَمِّل أولًا النموذج كما يلي: >>> from transformers import AutoModelForCausalLM >>> model = AutoModelForCausalLM.from_pretrained( "mistralai/Mistral-7B-v0.1", device_map="auto", load_in_4bit=True ) استخدمنا في الاستدعاء from_pretrained السابق معاملين device_map و load_in_4bit: يضمن المعامل device_map أن حمل النموذج سيتوزع تلقائيًا على وحدات GPU المتاحة. يساعد المعامل load_in_4bit على تقليل استخدام الموارد الحاسوبية إلى أقصى حد ممكن عبر تطبيق التكميم الديناميكي 4 بت. توجد طرق أخرى عديدة لتهيئة نموذج LLM عند تحميله، عرضنا إحداها في الأمر السابق، وهي أساسية وبسيطة. نحتاج الآن لمعالجة النص معالجةً مسبقة قبل إدخاله للنموذج وذلك باستخدام المُرَمِّز Tokenizer وهو نوع المعالجة المناسب للنصوص كما تعلمنا في مقال المعالجة المُسبقة للبيانات قبل تمريرها لنماذج الذكاء الاصطناعي: >>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left") >>> model_inputs = tokenizer(["A list of colors: red, blue"], return_tensors="pt").to("cuda") سيُخَزَّن خرج المُرَمِّز (وهو عبارة عن النص المُرَمَّز وقناع الانتباه attention mask) في المتغير model_inputs، ويوصى عادةً بتمرير بيانات قناع الانتباه ما أمكن ذلك للحصول على أفضل النتائج، رغم أن التابع generate()‎ سيسعى لتخمين قيمة قناع الانتباه عند عدم تمريره. ملاحظة: قناع الانتباه attention mask هو أداة تساعد النموذج اللغوي على معرفة الأجزاء المهمة في النص الذي يعالجه وتجاهل الأجزاء غير المهمة كرموز الحشو التي تُضاف لجعل طول النصوص موحدًا. يوجه هذا القناع النموذج ليركز فقط على الكلمات الفعلية في النص ويهمل الرموز لا تعني شيئًا للحصول على نتائج دقيقة. بعد انتهاء الترميز يُستدعى التابع generate()‎ الذي سيُرجع الرموز tokens المتنبأ بها، والتي ستتحول إلى نص قبل إظهارها في خرج النموذج. >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] 'A list of colors: red, blue, green, yellow, orange, purple, pink,' ننوه أخيرًا إلى أنك لست مضطرًا لتمرير مدخلاتك إلى النموذج على شكل جمل مفردة، جملة واحدة في كل مرة، إذ يمكنك تجميع أكثر من جملة وتمريرها بهيئة دفعات batches مع استخدام الحشو padding لجعلها متساوية الطول، كما في المثال التالي، يزيد هذا الأسلوب من إنتاجية النموذج ويقلل الزمن والذاكرة المستهلكين: >>> tokenizer.pad_token = tokenizer.eos_token # لا تملك معظم النماذج اللغوية الكبيرة رمزًا للحشو افتراضيًا >>> model_inputs = tokenizer( ["A list of colors: red, blue", "Portugal is"], return_tensors="pt", padding=True ).to("cuda") >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True) ['A list of colors: red, blue, green, yellow, orange, purple, pink,', 'Portugal is a country in southwestern Europe, on the Iber'] إذًا ببضع أسطر برمجية فقط استفدنا من أحد النماذج اللغوية الكبيرة LLM واستطعنا توليد نصوص مكلمة للجمل التي أعطيناها للنموذج. بعض المشكلات المحتمل وقوعها لا تناسب القيم الافتراضية لمعاملات النماذج التوليدية جميع المهام فلكل مشروع خصوصيته، والاعتماد عليها قد لا يعطينا نتائج مرضية في العديد من حالات الاستخدام، سنعرض لك أشهرها مع طرق تجنبها: لنبدأ أولًا بتحميل النموذج والمُرَمِّز ثم نتابع بقية أجزاء الشيفرة ضمن الأمثلة تباعًا: >>> from transformers import AutoModelForCausalLM, AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1") >>> tokenizer.pad_token = tokenizer.eos_token # لا تمتلك معظم النماذج اللغوية الكبيرة رمزًا للحشو افتراضيًا >>> model = AutoModelForCausalLM.from_pretrained( "mistralai/Mistral-7B-v0.1", device_map="auto", load_in_4bit=True ) توليد خرج أطول أو أقصر من اللازم يُرجع التابع generate عشرين tokens كحد أقصى افتراضيًا، طالما أننا لم نحدد ما يخالف ذلك في ملف إعدادات التوليد Generation-config، ولكن ما ينبغي الانتباه له أن نماذج LLMs وخاصة النماذج من نوع decoder models مثل GPT و CTRL تُرجع مُوجَّه الدخل input prompt أيضًا مع كل خرج تعطيه، لذا ننصحك بتحديد الحد الأقصى لعدد الـ tokens الناتجة يدويًا، وعدم الاعتماد على الحد الافتراضي، وذلك ضمن المتغير max_new_tokens المرافق لاستدعاء generate، ألقِ نظرة على المثال التالي ولاحظ الفرق في الخرج بين الحالتين، الحالة الافتراضية، وحالة تحديد العدد الأقصى للرموز الناتجة: >>> model_inputs = tokenizer(["A sequence of numbers: 1, 2"], >>> return_tensors="pt").to("cuda") # الحالة الافتراضية الحد الأقصى لعدد الرموز الناتجة هو 20 رمز >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] 'A sequence of numbers: 1, 2, 3, 4, 5' # عند ضبط قيمة المتغير الذي سيحدد العدد الأقصى للرموز الناتجة >>> generated_ids = model.generate(**model_inputs, max_new_tokens=50) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] 'A sequence of numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,' نمط توليد غير مناسب افتراضيًا يختار التابع generate الرمز الأكثر احتمالية من بين الرموز الناتجة في كل تكرار ما لم نحدد طريقة مغايرة للاختيار في ملف إعدادات التوليد GenerationConfig، يسمى هذا الأسلوب الافتراضي فك التشفير الشره greedy decoding، وهو لا يناسب المهام الإبداعية التي تستفيد من بعض العينات، مثل: بناء روبوت دردشة لمحادثة العملاء أو كتابة مقال متخصص، لكنه من ناحية أخرى يعمل جيدًا مع المهام المستندة إلى المدخلات، نحو: التفريغ الصوتي والترجمة وغيره، لذا اضبط المتغير على القيمة do_sample=True في المهام الإبداعية، كما يبين المثال التالي الذي يتضمن ثلاث حالات: >>> # استخدم هذا السطر إذا رغبت بالتكرار الكامل >>> from transformers import set_seed >>> set_seed(42) >>> model_inputs = tokenizer(["I am a cat."], return_tensors="pt").to("cuda") >>> # LLM + فك التشفير الشره = مخرجات متكررة ومملة >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] 'I am a cat. I am a cat. I am a cat. I am a cat' >>> # مع تفعيل أخذ العينات، تصبح المخرجات أكثر إبداعًا >>> generated_ids = model.generate(**model_inputs, do_sample=True) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] 'I am a cat. Specifically, I am an indoor-only cat. I' الحشو في الجانب الخاطئ ذكرنا سابقًا أنك عندما تقوم بإدخال جمل أو نصوص ذات أطوال مختلفة للنموذج، فقد تحتاج إلى جعل هذه المدخلات بطول موحد ليتمكن النموذج من معالجتها بشكل صحيح من خلال إضافة رموز الحشو (padding tokens) التي تجعل جميع المدخلات بطول متساوٍ. لكن النماذج اللغوية الكبيرة LLMs هي بنى لفك التشفير فقط decoder-only فهي تكرر الإجراءات نفسها على مدخلاتك، لكنها غير مُدَرَّبة على الاستمرار بالتكرار على رموز الحشو، لذا عندما تكون مدخلاتك مختلفة الأطوال وتحتاج للحشو لتصبح بطول موحد، فاحرص على إضافة رموز الحشو على الجانب الأيسر left-padded (أي قبل بداية النص الحقيقي) ليعمل التوليد بطريقة سليمة، وتأكد من تمرير قناع الانتباه attention mask للتابع generate حتى لا تترك الأمر للتخمين: >>> # المُرَمِّز المستخدم هنا يحشو الرموز على الجانب الأيمن افتراضيًا، والسلسلة النصية الأولى هي >>> # السلسلة الأقصر والتي تحتاج لحشو، وعند حشوها على الجانب الأيمن سيفشل النموذج التوليدي في التنبؤ بمنطقية >>> model_inputs = tokenizer( ["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt" ).to("cuda") >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] '1, 2, 33333333333' >>> # لاحظ الفرق عند تعديل الحشو ليصبح على الجانب الأيسر >>> tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left") >>> tokenizer.pad_token = tokenizer.eos_token # Most LLMs don't have a pad token by default >>> model_inputs = tokenizer( ["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt" ).to("cuda") >>> generated_ids = model.generate(**model_inputs) >>> tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] '1, 2, 3, 4, 5, 6,' مُوجَّهات خاطئة يتراجع أداء بعض النماذج عندما لا نمرر لها مُوجَّهات input prompt بالتنسيق الصحيح الذي يناسبها، يمكنك الحصول على مزيد من المعلومات عن طبيعة الدخل المتوقع للنماذج مع كل مهمة بالاطلاع على دليل المُوجَّهات في نماذج LLMs على منصة Hugging Face، ألقِ نظرة على المثال التالي الذي عن استخدام نموذج LLM للدردشة باستخدام قوالب الدردشة: >>> tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-alpha") >>> model = AutoModelForCausalLM.from_pretrained( "HuggingFaceH4/zephyr-7b-alpha", device_map="auto", load_in_4bit=True ) >>> set_seed(0) >>> prompt = """How many helicopters can a human eat in one sitting? Reply as a thug.""" >>> model_inputs = tokenizer([prompt], return_tensors="pt").to("cuda") >>> input_length = model_inputs.input_ids.shape[1] >>> generated_ids = model.generate(**model_inputs, max_new_tokens=20) >>> print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0]) "I'm not a thug, but i can tell you that a human cannot eat" >>> # لم يتبع النموذج تعليماتنا هنا فهو لم يرد على السؤال كما ينبغي أن يرد أي شخص عنيف >>> # سنقدم الآن دخلًا أفضل يناسب النموذج باستخدام قوالب الدردشة، ونرى الفرق النتيجة >>> set_seed(0) >>> messages = [ { "role": "system", "content": "You are a friendly chatbot who always responds in the style of a thug", }, {"role": "user", "content": "How many helicopters can a human eat in one sitting?"}, ] >>> model_inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to("cuda") >>> input_length = model_inputs.shape[1] >>> generated_ids = model.generate(model_inputs, do_sample=True, max_new_tokens=20) >>> print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0]) 'None, you thug. How bout you try to focus on more useful questions?' >>> # كما تلاحظ فقد تغير أسلوب الرد واتبع تعليماتنا بطريقة أفضل فكان رده أقرب للأسلوب المطلوب مصادر مفيدة للاستفادة من نماذج LLMs ستحتاج لتعميق معرفتك بالنماذج اللغوية الكبيرة (LLMs) إذا رغبت بتحقيق أقصى استفادة منها، وإليك بعض الأدلة المفيدة من منصة Hugging Face المتخصصة في المجال: أدلة الاستخدام المتقدم للتوليد Generating دليل استراتيجيات توليد النصوص باستخدام الذكاء الاصطناعي الذي يساعدك في تعلم كيفية التحكم بتوابع توليد مختلفة، وضبط مخرجاتها، وملفات الإعدادات الخاصة بها. دليل لاستخدام قوالب الدردشة مع نماذج LLMs. دليل LLM prompting يتضمن الأساسيات وأفضل الممارسات في كتابة المُوجَّهات. توثيقات واجهة برمجة التطبيقات API لكل من ملف إعدادات التوليد GenerationConfig و التابع ()generate و الأصناف clasess المرتبطة مع المعالجة المسبقة والعديد من الأمثلة التوضيحية. أشهر نماذج LLMs النماذج مفتوحة المصدر التي تُركِّز على الجودة Open LLM Leaderboard. النماذج التي تهتم بالإنتاجية Open LLM-Perf Leaderboard. أدلة حول تحسين السرعة والإنتاجية وتقليل استخدام الذاكرة دليل تحسين السرعة والذاكرة في نماذج LLMs. دليل التكميم Quantization باستخدام تقنيات مثل bitsandbytes و autogptq، لتخفيض متطلبات استخدام الذواكر. مكتبات مرتبطة بالنماذج اللغوية الكبيرة المكتبة text-generation-inference، وهي بمثابة خادم إنتاج جاهز للعمل مع نماذج LLMs. المكتبة optimum، وهي امتداد لمكتبة المحوّلات Transformers تساعدك في تحسين استخدام مكونات الحاسوب وموارده. كما تساعدك دورة الذكاء الاصطناعي من أكاديمية حسوب في فهم طريقة التعامل مع النماذج اللغوية الكبيرة LLMs وربط الذكاء الاصطناعي مع تطبيقاتك المختلفة، كما يمكنك الحصول على معلومات مفيدة من دروس ومقالات قسم الذكاء الاصطناعي على أكاديمية حسوب. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن الخلاصة وصلنا إلى ختام المقال وقد عرضنا فيه طريقة استخدام النماذج اللغوية الكبيرة LLMs لتوليد النصوص الطويلة تلقائيًا من نص بسيط مُدخل، مع بيان بعض المخاطر الشائعة التي تعترض مستخدميها وكيفية تجنبها، بالإضافة لتعداد أشهر نماذج LLM، وبعض المصادر الموثوقة لمن يريد تعلمها بتعمقٍ أكبر. ترجمة -وبتصرف- لقسم Generation with LLMs من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: استخدام وكلاء مكتبة المحولات Transformers Agents في الذكاء الاصطناعي التوليدي تدريب المًكيَّفات PEFT Adapters بدل تدريب نماذج الذكاء الاصطناعي بالكامل بناء تطبيق بايثون يجيب على أسئلة ملف PDF باستخدام الذكاء الاصطناعي تطوير تطبيق 'اختبرني' باستخدام ChatGPT ولغة جافاسكربت مع Node.js مصطلحات الذكاء الاصطناعي للمبتدئين
  7. نعرفكم في مقال اليوم على كيفية استخدام مكتبة المحولات Transformers في مهام الذكاء الاصطناعي التوليدي مثل توليد الصور أو تحويل النص إلى كلام أو الإجابة عن أسئلة متعلقة بالمستندات حيث يوفر الإصدار v4.29.0 من مكتبة المحوّلات Transformers واجهة برمجة تطبيقات API اختبارية لعناصر مفيدة في الذكاء الاصطناعي التوليدي هي الوكلاء Agents والأدوات Tools، وسنناقشها بالتفصيل في فقراتنا التالية. يمكنك العمل مع هذه الواجهة البرمجية API من رابط مخصص لها على جوجل كولاب Google Colab، وهي تُركز على مهام فهم اللغة الطبيعية (اللغة البشرية)، فيعمل الوكيل agent على تفسير أوامر اللغة الطبيعية المعُطاة له مستخدمًا مجموعة من الأدوات الأساسية التي توفرها المكتبة؛ تحتاج لأن تبدأ عملك بتصميم الوكيل وتحديد أدواته المناسبة لمشروعك، ويمكنك في أي لحظة توسيع نطاق التصميم ليشمل أدواتٍ إضافية أنشأها وشاركها مطورون آخرون على مجتمع Hugging Face. سنعرض بعضًا من الأمثلة عمّا يمكنك تحقيقه باستخدام هذه الواجهة البرمجية API، وستلاحظ قوتها في المهام متعددة الأنماط multimodal، لذا سنبدأ أمثلتنا بتجربتها في مهام توليد الصور وقراءة النصوص صوتيًا. ألقِ نظرة على الأمر التالي فهو يوجه طلبًا مكتوبًا باللغة الإنكليزية للوكيل Agent ويطلب منه وضع تسمية توضيحية أو عنوان للصورة المعطاة له: agent.run("Caption the following image", image=image) لاحظ أن دخل الوكيل صورة والخرج تسمية توضيحية تناسبها: الدخل الخرج A beaver is swimming in the water الآن لنطلب من الوكيل Agent قراءة التسمية التوضيحية السابقة، سنمررها له ضمن text: agent.run("Read the following text out loud", text=text) وسيكون الدخل والخرج كما يلي: الدخل الخرج A beaver is swimming in the water ملف صوتي يقرأ النص باللغة الطبيعية وهي في مثالنا الإنجليزية tts_example.wav لنجرب أيضًا تمرير مستند document للوكيل Agent ونطرح عليه سؤالًا عن مضمون المستند: agent.run( "In the following `document`, where will the TRRF Scientific Advisory Council Meeting take place?", document=document, ) في هذه الحالة سيكون الدخل والخرج كما يلي: الدخل الخرج صورة المستند نص يتضمن الإجابة عن السؤال المستنتجة من المستند أكمل معنا قراءة المقال لتعرف الأساسيات، ثم ادخل إلى بيئة Google Colab الخاصة بالمكتبة وجرب بعض المهام بنفسك حتى تتقن التعامل معها. مقدمة سريعة الخطوة الأولى هي إدراج الوكيل الذي نود استخدامه بتعليمة agent.run، والوكيل هو نموذج لغوي كبير (LLM) يمكنك الحصول عليه من مصادر متنوعة، فمكتبة المحوّلات Transformers مثلًا تدعم النماذج اللغوية الخاصة بمنصات openAI و BigCode و OpenAssistant؛ تتمتع نماذج openAI بكفاءة أعلى من البقية لكنها بالمقابل غير مجانية إذ يتطلب استخدام واجهتها البرمجية مفتاحًا خاصًا "openAI API key"، أما نماذج منصتي BigCode و OpenAssistant فالوصول إليها متاح مجانًا عبر منصة Hugging Face يمكنك استخدامها بسهولة. لنُثَبِّت في البداية امتداد مكتبة المحوّلات الخاص بالوكلاء agents قبل تثبيت بقية الاعتماديات: pip install transformers[agents] تعتمد خطوتنا التالية على نوع المنصة التي سنستخدم نماذجها. إذا رغبت باعتماد نماذج OpenAI فثَبِّت الاعتمادية openai لتتمكن من استخدامها وإنشاء المثيل OpenAiAgent ليكون وكيلًا: pip install openai يمكنك الآن إدراج الوكيل OpenAiAgent كما يلي: from transformers import OpenAiAgent agent = OpenAiAgent(model="text-davinci-003", api_key="<your_api_key>") أما إذا رغبت باستخدام نماذج BigCode أو OpenAssistant، فعليك في البداية تسجيل الدخول إلى منصة Hugging Face لتحصل على صلاحية الوصول إلى واجهة API الاستدلالية التي توفرها Hugging Face لهذه النماذج: from huggingface_hub import login login("<YOUR_TOKEN>") وبعدها أدرج الوكيل agent: from transformers import HfAgent # Starcoder agent = HfAgent("https://api-inference.huggingface.co/models/bigcode/starcoder") # StarcoderBase # agent = HfAgent("https://api-inference.huggingface.co/models/bigcode/starcoderbase") # OpenAssistant # agent = HfAgent(url_endpoint="https://api-inference.huggingface.co/models/OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5") استخدمنا هنا واجهة API المجانية (حاليًا) التي توفرها Hugging Face للوصول إلى النماذج اللغوية الكبيرة، لكن يمكنك بالطبع استخدام أي واجهة API أخرى متوفرة لديك وعندها ستستبدل عنوان URL الذي استخدمناه بعنوان URL لنقطة الاتصال endpoint المتوفرة لديك. ملاحظة: تعمل النماذج المجانية لكل من OpenAssistant و StarCoder جيدًا في المهام البسيطة لكن أداءها يتراجع للأسف كلما ازداد تعقيد المهام الموكلة لها، لذا ننصحك باستخدام نماذج OpenAI في المشاريع الكبيرة فبالرغم من كونها غير مفتوحة المصدر لكنها مناسبة. لننتقل إلى الخطوة التالية، ونتعرف عن قرب على واجهتي API المتوفرتين لدينا الآن. التنفيذ الإفرادي باستخدام التابع run يستخدم التنفيذ الإفرادي single execution التابع ()run مع الوكيل agent كما في المثال التالي الذي يطلب من الوكيل توليد صورة تتضمن أنهارًا وبحيرات: agent.run("Draw me a picture of rivers and lakes.") أرجع الوكيل الصورة التالية: سيُحَدِدْ الوكيل agent تلقائيًا الأداة tool أو الأدوات المناسبة للمهمة التي طلبنا تنفيذها، ويعمل على تشغيلها بالطريقة الصحيحة، علمًا أنه يستطيع تنفيذ أكثر من مهمة في آن واحد، لكن لا ننصحك بذلك فكلما ازداد تعقيد الأوامر الموجهة له ازدادت احتمالات الفشل. وهذا مثالٌ آخر لتوليد صورة تتضمن بحرًا ثم إضافة جزيرة عليها: agent.run("Draw me a picture of the sea then transform the picture to add an island") وستكون الصورة التي ستحصل عليها كالتالي: يمكنك تشغيل ()run لمهام مختلفة عدة مرات متتالية، فكل تعليمة ()run مستقلة تمامًا عن غيرها من التعليمات. تُعدّ دقة مطالبات الدخل prompts الموجهة للوكيل مهمة جدًا في الحصول على أفضل النتائج، فالاختلافات الصغيرة فيها تصنع فرقًا فالوكيل agent في نهاية الأمر مجرد نموذج لغوي كبير يستجيب للتوجيهات التي تُعطى له. كما يوفر الوكيل خياراتٍ مفيدة أخرى عبر المتغيرات التي يقبلها، فتستطيع مثلًا تمرير كائنات غير نصية له كتمرير الصور، أو توجيهه لحفظ حالة التنفيذ الأخيرة التي وصل إليها وتحديثها بإضافة عناصر جديدة، لنفترض أننا نريد من الوكيل أخذ صورة الأنهار والبحيرات التي ولدها في مثالنا السابق وإضافة جزيرة عليها، فستكون الأوامر وفق التالي: picture = agent.run("Generate a picture of rivers and lakes.") updated_picture = agent.run("Transform the image in `picture` to add an island to it.", picture=picture) تفيدك هذه الحالة عندما لا يكون النموذج قادرًا على فهم طلبك بوضوح أو عاجزًا عن مزج عدة أدوات معًا، كما في المثال التالي: > agent.run("Draw me the picture of a capybara swimming in the sea") قد يُفسِّر الوكيل هذا الطلب بطريقتين: توليد صورة من النص text-to-image والنص هو: "ارسم لي صورة لحيوان كابيبارا يسبح في الماء". توليد صورة من النص text-to-image والنص هو: "ارسم لي صورة لحيوان كابيبارا"، ثم "استخدام أداة تحويل الصور image-transformation لجعل حيوان الكابيبارا يسبح". يمكنك حسم الموضوع وفرض السيناريو الأول بتمرير موجه prompt صريحة كمتغير للوكيل تتضمن بوضوح ما تريد وجوده في الصورة كما يلي: agent.run("Draw me a picture of the `prompt`", prompt="a capybara swimming in the sea") التنفيذ المستند إلى الدردشة باستخدام التابع chat يعمل الوكيل agent بأسلوب الدردشة النصية chat-based بواسطة التابع ()chat كما في المثال التالي: سنطالبه أولًا بتوليد صورة أنهار وبحيرات: agent.chat("Generate a picture of rivers and lakes") سيولد لنا الصورة التالية: ثم سنطلب منه تحويل الصورة وإضافة عنصر إليها كما يلي: agent.chat("Transform the picture so that there is a rock in there") يساعدك هذا الأسلوب في الاختبارات وتنفيذ التعليمات الفردية التي تحافظ فيها على الحالة الأخيرة للتنفيذ عبر مجموعة من التعليمات، لكنه ليس الأسلوب الأمثل للتعليمات المعقدة، التي يناسبها التنفيذ المعتمد على ()run. يقبل التنفيذ المعتمد على الدردشة تمرير وسيط غير نصي أو موجهات Prompts محددة للتابع ()chat. التنفيذ عن بعد Remote execution أنشأت منصة Hugging Face -باستخدام نقاط الاتصال الاستدلالية inference endpoints- مُنَفِّذْين عن بعد remote executors للعديد من الأدوات الافتراضية التي يستخدمها الوكلاء agents، ستجدها معطلة حاليًا في هذا الإصدار لكننا ذكرناها هنا لتعرف أن الإمكانية متوفرة، وأن باستطاعتك إنشاء أدوات مخصصة لاحتياجات مشروعك وتخزينها في مستودع بعيد ثم استدعائها للتنفيذ عن بعد، اقرأ دليل إنشاء الأدوات المخصصة لتعرف أكثر عن الموضوع. الوكلاء Agents والأدوات Tools بعد هذه المقدمة السريعة سنُعَرِّف الآن الوكلاء Agents والأدوات Tools، لكن اطّلع أولًا على المخطط التوضيحي التالي: الوكلاء Agents الوكيل agent هو نموذج لغوي كبير (LLM) نوجهه بواسطة مُوجّهات prompts ليستخدم مجموعة من الأدوات tools التي نحددها له بغرض تنفيذ المهمة المطلوبة. تُعَدُ النماذج اللغوية الكبيرة (LLMs) مناسبة لتوليد شيفرات برمجية صغيرة، لذا تستفيد الواجهة البرمجية API من هذه الميزة وتطلب من النموذج توليد شيفرة برمجية تتضمن التعليمات اللازمة لتنفيذ مهمة محددة مع استخدام أدوات معينة نَصِفُها له، فيأخذ الوكيل المهمة والوصف المقدم للأدوات، ويكمل المطلوب بإنشاء تعليمات متوافقة مع مدخلات الأدوات ومخرجاتها كما هو موضح في المخطط السابق. الأدوات Tools تتكون الأداة tool من دالة واحدة لها وظيفة محددة؛ وتتميز كل أداة باسم ووصف، نستخدم وصف الأدوات في المُوجِّهات prompt الموجهة للوكيل agent، فيوضح له الوصف كيف يستفيد من كل أداة في تنفيذ المهمة المطلوبة. يستخدم الوكيل agent الأدوات tools بدلًا من خطوط الأنابيب pipelines بالرغم من تشابه المفهومين لأنه يقدم أداءً أفضل في كتابة الشيفرة البرمجية مع الأدوات المحددة والصغيرة، فالأدوات تتخصص بمهمة واحدة بسيطة، بينما تجمع خطوط الأنابيب مهام متعددة في آنٍ واحد. تنفيذ الشيفرة البرمجية بعد توليد الوكيل الشيفرة البرمجية تُنَفَّذْ على المدخلات مباشرةً باستخدام مُفَسِّر أوامر بايثون المحدود والخاص في منصة Hugging Face، قد لا تطمئن لهذه الطريقة أو تظنها غير آمنة فالأوامر الناتجة عن الوكيل تذهب للمُفَسِّر مباشرةً وتُنَفَّذْ دون أن تراها. لكن ما يخفف مخاطرها أن التنفيذ يقتصر على الأدوات التي تستدعيها بنفسك فقط ، ولن تُنفذ أي تعليمات أخرى غيرها، لذا فهو يُعدّ آمنًا نوعًا ما، طالما أنك تلتزم باستخدام الأدوات التي تؤمنها منصة Hugging Face، فالمنصة تعتمد عددًا من الاحتياطات الأمنية فهي تمنع عمليات استخراج السمات من الشيفرات البرمجية أو استيرادها وتحميك من الهجمات الشهيرة. وإذا رغبت بحماية أكبر فيمكنك استخدام أسلوب التنفيذ المعتمد على التابع ()run مع الوسيط return_code=True الذي سيعرض لك الشيفرة البرمجية التي وَلَّدها الوكيل لتتفحصها وتقرر بنفسك فيما إذا ما كنت تود تنفيذها أم لا. أما حالات توقف التنفيذ غير المتوقعة التي قد تصادفك، فهي ترجع عادةً لسببين: إما تنفيذك عملية غير مصرح بها، أو وجود خطأ ما في الشيفرة التي أنتجها الوكيل. الأدوات التي توفرها مكتبة Transformers هذه قائمة بأشهر الأدوات المدمجة في مكتبة المحوّلات Transformers والمستخدمة لتشغيل الوكلاء agents: الإجابة عن أسئلة حول محتوى المستند Document question answering: نمرر للنموذج مستندًا (ملف PDF مثلًا) بصيغة صورة ويستخدم الأداة للإجابة عن أي سؤال تطرحه حول محتوى المستند، ومن أمثلته النموذج (Donut). الإجابة عن أسئلة حول النص Text question answering: تكون المدخلات هنا نص طويل وسؤال، والمخرجات هي الإجابة عن هذا السؤال من داخل النص، تعمل مع النموذج (Flan-T5). وضع تسمية توضيحية للصورة Unconditional image captioning: وضع تسميةً توضيحية للصور المدخلة، مثل النموذج (BLIP). الإجابة عن أسئلة حول الصورة Image question answering: نمرر صورة لتتم الإجابة عن السؤال المطروح عنها، (VILT). تجزئة الصور Image segmentation: المدخلات في هذه الحالة: صورة، وموجه prompt بتجزئة الصورة، ويكون الخرج قناعًا لتجزئة الصورة حسب المعيار المحدد في الموجه prompt، ومن أمثلتها النموذج (CLIPSeg) تحويل الكلام إلى نص Speech to text: نمرر ملفًا صوتيًا لشخص يتكلم، ويجري تحويله إلى نص، يناسبه مثلًا النموذج (Whisper). تحول النص إلى كلام Text to speech: العملية المعاكسة، الدخل هنا هو نص ويُحوّل إلى كلام، تعمل مع النموذج (SpeechT5). تصنيف النصوص بدون تدريب مسبق Zero-shot text classification: نمرر للنموذج نصًا ومجموعة تسميات توضيحية labels لم تكن موجودة ضمن البيانات التي تَدَرَّبَ عليها سابقًا، وينبغي له تحديد التسمية التوضيحية الأكثر توافقًا مع النص، مثل النموذج (BART). تلخيص النصوص Text summarization: تلخيص النص الطويل ببضع جمل فقط، مثل النموذج (BART). الترجمة Translation: ترجمة النص المُعطى إلى اللغة المحددة، مثل النموذج (NLLB). هذه الأدوات مدمجة في مكتبة المحولات Transformers ويمكنك استدعائها واستخدامها يدويًا خارج الإطار السابق كما في المثال التالي: from transformers import load_tool tool = load_tool("text-to-speech") audio = tool("This is a text to speech tool") الأدوات المخصصة بالرغم من توفر العديد من الأدوات الجاهزة في منصة Hugging Face إلّا أن الإمكانية متاحة أمامك لإنشاء أدوات مخصصة لاحتياجات عملك ومشاركتها على المنصة بسرعة وبسهولة. بعد الانتهاء من برمجة الأداة ارفع شيفرتها البرمجية إلى المنصة أو إلى مستودع النموذج الخاص بك، وستتمكن بعدها من استخدامها مع أي وكيل agent، وهذه بعض الأمثلة عن أدوات مخصصة موجودة في قسم huggingface-tools على منصة Hugging Face وهي مستقلة عن مكتبة Transformers: تحميل النصوص Text downloader: تحميل نص من عنوان URL معين. تحويل النص إلى صورة Text to image: توليد صورة بناءً على النص المُدخل في الموجه prompt، وذلك باستخدام نموذج الذكاء الاصطناعي stable diffusion. تحويل الصور Image transformation: تكون المدخلات صورة مبدئية، وموجه prompt بتعديلها، ويجري تعديل الصورة بناءً على الموجه prompt، وذلك باستخدام تعليمات pix2pix stable diffusion. تحويل النص إلى فيديو Text to video: يُنشئ مقطع فيديو صغير بناءً على الموجه prompt المقدم له، وذلك بالاستفادة من damo-vilab. بالمناسبة إن أداة تحويل النص إلى صورة text-to-image التي استخدمناها في أمثلة المقال هي أداة بعيدة مستضافة على منصة Hugging Face على الرابط huggingface-tools/text-to-image، وستجد العديد من الأدوات الأخرى المستضافة هناك. يمكنك الاطلاع على دليل إنشاء الأدوات المخصصة لتتعرف أكثر على طريقة إنشاء الأدوات ومشاركتها، علمًا أن الوكلاء agents يتمتعون تلقائيًا بصلاحية الوصول إلى كافة الأدوات الموجودة على Hugging Face. توليد الشيفرة البرمجية Code generation استخدمنا في أمثلتنا السابقة الوكلاء agents لتنفيذ الإجراءات دون أي تدخل منا، فالوكيل يوّلِد الشيفرة البرمجية ثم تُنَفَّذ هذه الشيفرة باستخدام مُفَسِّر بايثون المحدود، وبالتالي إذا رغبت باستخدام الشيفرة البرمجية الموَّلدة بأي طريقة أخرى، يمكنك ذلك عبر مطالبة الوكيل بإرجاع الشيفرة البرمجية الناتجة جنبًا إلى جنب مع تعريف الأداة المستخدمة وعمليات الاستيراد imports الدقيقة. فالتعليمة المبينة أدناه على سبيل المثال: agent.run("Draw me a picture of rivers and lakes", return_code=True) تُرجع الشيفرة التالية التي تستطيع تعديلها وتنفيذها يدويًا حسب ما تريد: from transformers import load_tool image_generator = load_tool("huggingface-tools/text-to-image") image = image_generator(prompt="rivers and lakes") الخلاصة تعرفنا في هذا المقال على الوكلاء agents والأدوات tools والأساليب المختلفة لاستخدامها في تحويل أوامر اللغة الطبيعية إلى تعليمات برمجية لتوليد الصور والنصوص والفيديوهات أو لترجمتها أو تلخيصها أو تحويلها حالة إلى أخرى، وتعلمنا أيضًا أننا أحرار في طريقة الاستفادة من هذه التعليمات البرمجية الناتجة، فيمكننا تركها لتُنَفَّذْ تلقائيًا أو استعراضها وتنفيذها يدويًا أو حتى استخدامها في أغراضٍ أخرى في برامج أوسع مثلًا أو غير ذلك. وفي الختام ندعوك لمتابعة مقالنا التالي حول توليد النصوص باستخدام النماذج اللغوية الكبيرة LLMs لتعزز معرفتك أكثر بهذا المجال الحيوي. ترجمة -وبتصرف- لقسم Transformers Agents من منصة Hugging Face. اقرأ أيضًا المقال السابق: تدريب المًكيَّفات PEFT Adapters بدل تدريب نماذج الذكاء الاصطناعي بالكامل بناء تطبيق بايثون يجيب على أسئلة ملف PDF باستخدام الذكاء الاصطناعي تطوير تطبيق 'اختبرني' باستخدام ChatGPT ولغة جافاسكربت مع Node.js مصطلحات الذكاء الاصطناعي للمبتدئين
  8. تساهم مشاركة نماذج الذكاء الاصطناعي مع الآخرين في نشر المعرفة، وتوفير الوقت والموارد على الراغبين باستثمارها وبالأخص على المستخدمين الجدد، إذا كنت تتابع معنا هذه السلسلة عن مكتبة المحولات Transformers مفتوحة المصدر من منصة Hugging Face فقد تعلمت كيفية صقل Fine-Tune نموذج ذكاء اصطناعي مُدَرَّبْ مُسبقًا باستخدام كل من PyTorch و Keras وأيضًا كيفية تسريع تدريبه بواسطة التدريب الموزع والمكتبة Accelerate، وستتعلم الآن كيف تشاركه مع المجتمع. سواء كنت قد دَرَّبتَ نموذجك من الصفر أو استخدمت نموذجًا مُسبق التدريب وصقلته fine-tune على بيانات محددة فلديك طريقتين لمشاركته على مستودع نماذج Hugging Face المسمى Model Hub: رفع الملفات إلى المستودع برمجيًا. رفع الملفات إلى المستودع بطريقة السحب والإفلات من واجهة الويب للمستودع. ميزات مستودع النماذج Model Hub يتمتع كل مستودع repository في مستودع النماذج Model Hub بكافة المميزات الخاصة بمستودعات GitHub التقليدية، مثل: توفر نظام التحكم بالإصدارات versioning، وسجل تتبع التعديلات commit history، وإمكانية العرض المرئي للاختلافات بين الإصدارات visualize differences وغيرها. يعتمد نظام التحكم بالإصدار versioning المُضَمَّنْ في مستودع النماذج على كل من git و git-lfs، فتستطيع التعامل مع النموذج على أنه مستودع مستقل، يزيد ذلك من قدرتك على التوسع، ويمنحك تحكمًا أكبر بإمكانية الوصول للنماذج، كما يسمح نظام التحكم بالإصدار بالمراجعات revisions أي تثبيت إصدار محدد من النموذج وتمييزه بعلامةٍ خاصة قد تكون رمزًا commit hash أو وسمًا tag أو فرعًا من المستودع branch. بالنتيجة يمكنك تحديد إصدار النموذج الذي تريده باستخدام المعامل revision: model = AutoModel.from_pretrained( "julien-c/EsperBERTo-small", revision="v2.0.1" # tag name, or branch name, or commit hash ) تُعَدَّل ملفات المستودع بسهولة، ويمكنك مشاهدة التعديلات التي طرأت عليعا والاختلافات التي أحدثتها في النموذج بمرونة تامة، كما في الصورة التالية: إعداد متطلبات العمل تحتاج إلى بيانات الاعتماد الخاصة بك على منصة Hugging Face قبل مشاركة أي نموذج على مستودع النماذج، إذا كنت تملك وصولًا لنافذة الطرفية terminal، فاكتب الأمر التالي ضمن البيئة الافتراضية التي أنشأناها عند تثبيت مكتبة المُحوّلات Transformers وبمجرد تنفيذه ستُخَزَّن بيانات اعتمادك المتمثلة برمز الدخول access token في مجلد الذاكرة المخبئية الخاص بمنصة Hugging Face (وهو المجلد /‎~/.cache افتراضيًا): huggingface-cli login أما إذا كنت تستخدم دفترًا للملاحظات notebook عبر الويب مثل: Jupyter أو Colaboratory فاحرص في البداية على تثبيت المكتبة huggingface_hub التي تسمح لك بالتفاعل البرمجي مع مستودع النماذج: pip install huggingface_hub ثم استخدم notebook_login كما يلي لتسجيل الدخول إلى مستودع النماذج، واتبع بعدها الخطوات الخاصة بتوليد رمز الدخول token لتستخدمه: >>> from huggingface_hub import notebook_login >>> notebook_login() تحويل النموذج ليعمل مع أي إطار عمل ننصحك بإنشاء نقطتي تحقق checkpoints لنموذجك قبل رفعه إلى المستودع واحدة باستخدام إطار العمل PyTorch وأخرى باستخدام TensorFlow، يُسَهِّل هذا الأمر استفادة الآخرين من النموذج بصرف النظر عن إطار العمل الذي يستخدمونه. ونشير هنا إلى المستخدمين سيظلون قادرين على تحميل نموذجك بأي إطار عمل يرغبون به حتى إذا تجاوزت هذه الخطوة ولم تحوّل نموذجك، لكنهم سيعانون عندها من بعض البطء في التحميل، لأن المحوّلات Transformers ستُحَوّل النموذج إلى صيغة تناسب إطار عملهم في أثناء التحميل فيزداد الوقت المستغرق له. أما تحويل نقطة التحقق الخاصة بنموذجك من إطار العمل الذي تعتمده إلى إطار عمل آخر فيُعَدُّ إجراءً سهلًا سنتعلمه معًا، لكن تأكد في البداية من تثبيت إطاري العمل باي تورش PyTorch وتنسرفلو TensorFlow (يمكنك مراجعة مقال تثبيت مكتبة المحوّلات Transformers من هذه السلسلة على أكاديمية حسوب لتتعرف على خطوات التثبيت)، ثم ابحث عن نموذج مهمتك في إطار العمل الآخر الذي ستحول نموذجك إليه لتتأكد أنه متوافق معه. تحويل نقطة التحقق من TensorFlow إلى PyTorch عبر ضبط قيمة المعامل from_tf=True وفق التالي: >>> pt_model = DistilBertForSequenceClassification.from_pretrained("path/to/awesome-name-you-picked", from_tf=True) >>> pt_model.save_pretrained("path/to/awesome-name-you-picked") تحويل نقطة التحقق من PyTorch إلى TensorFlow عبر ضبط قيمة المعامل from_pt=True كما يلي: >>> tf_model = TFDistilBertForSequenceClassification.from_pretrained("path/to/awesome-name-you-picked", from_pt=True) ثم احفظ نموذج TensorFlow الجديد بنقطة تحققه الجديدة: >>> tf_model.save_pretrained("path/to/awesome-name-you-picked") وإذا كان النموذج مدعومًا في Flax يمكنك تحويله من PyTorch إلى Flax وفق التالي: >>> flax_model = FlaxDistilBertForSequenceClassification.from_pretrained( "path/to/awesome-name-you-picked", from_pt=True ) رفع النموذج إلى المستودع في أثناء التدريب يُعدّ رفع النماذج ومشاركتها على المستودع عملًا بسيطًا يماثل إضافة معامل أو رد نداء callback أو غيره من الخيارات المألوفة، فهو في نهاية الأمر أحد معاملات التدريب التي نُحددها ضمن الصنف TrainingArguments كما تعلمنا في مقال صقل Fine-Tune نموذج ذكاء اصطناعي مُدَرَّبْ مُسبقًا فكل ما عليك فعله هو ضبط المعامل Push_to_hub=True في الصنف TrainingArguments كما في الخطوات التالية، وسيُرفَع نموذجك مباشرةً إلى المستودع: >>> training_args = TrainingArguments(output_dir="my-awesome-model", push_to_hub=True) نُمَرِّر هذه الخيارات الآن إلى المُدَرِّب Trainer: trainer = Trainer( model=model, args=training_args, train_dataset=small_train_dataset, eval_dataset=small_eval_dataset, compute_metrics=compute_metrics, ) وبعد الانتهاء من صقل fine-tune النموذج نستدعي الدالة call push_to_hub()‎ بواسطة المُدَرِّب Trainer لرفعه إلى مستودع النماذج، وستُضيف مكتبة المحوّلات Transformers تلقائيًا معلومات النموذج إلى بطاقة الوصف الخاصة به، وهي تتضمن مثلًا: المعاملات الفائقة hyperparameters للنموذج، ونتائج تدريبه، وإصدارات إطار العمل التي يعمل عليها وما إلى ذلك: trainer.push_to_hub() وفي إطار العمل TensorFlow يمكنك مشاركة النماذج على المستودع بواسطة الدالة PushToHubCallback مع إضافة الخيارات التالية: مجلد خرج النموذج. المُرَمِّز tokenizer. مُعَرِّف النموذج على المستودع hub_model_id وهو يتكون من اسم المستخدم مالك النموذج username واسم النموذج. وستكون الأوامر كما يلي: >>> from transformers import PushToHubCallback >>> push_to_hub_callback = PushToHubCallback( output_dir="./your_model_save_path", tokenizer=tokenizer, hub_model_id="your-username/my-awesome-model" ) ثم أضف رد نداء callback للدالة fit وفق التالي وسترفع المحوّلات Transformers نموذجك إلى المستودع: >>> model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3, callbacks=push_to_hub_callback) استخدام الدالة push_to_hub يمكنك بدلًا من استخدام الطريقة السابقة استدعاء الدالة push_to_hub وتمرير اسم النموذج المطلوب رفعه إلى المستودع. حَدِّدْ اسم النموذج ضمن push_to_hub وفق التالي: >>> pt_model.push_to_hub("my-awesome-model") سينشأ الآن مستودعًا repository للنموذج على مستودع النماذج لمنصة Hugging Face يكون تحت اسمك، ويُسمى باسم النموذج وهو في مثالنا my-awesome-model، ويمكن للمستخدمين الآخرين بعد ذلك تحميله بواسطة الدالة from_pretrained كما يلي: >>> from transformers import AutoModel >>> model = AutoModel.from_pretrained("your_username/my-awesome-model") أما إذا كنت تنتمي لمؤسسة لديها حساب على Hugging Face وتريد رفع نموذجك تحت اسم المؤسسة فأضف مُعَرِّف مستودع المؤسسة repo_id مع اسم النموذج وفق التالي: >>> pt_model.push_to_hub("my-awesome-org/my-awesome-model") تساعدك الدالة Push_to_hub على رفع ملفات أخرى إلى مستودع النموذج نحو المُرَمِّز tokenizer مثلًا: >>> tokenizer.push_to_hub("my-awesome-model") أو نسخة TensorFlow من نموذج PyTorch المصقول fine-tuned كما يلي أو غير ذلك: >>> tf_model.push_to_hub("my-awesome-model") الآن عندما تفتح حسابك على منصة Hugging Face سترى المستودع الجديد الذي أنشأته، وبالضغط على تبويب الملفات Files ستستعرض جميع الملفات التي حَمَّلتها إلى المستودع. شرحنا هنا الأساسيات فقط، ولمزيد من المعلومات حول إنشاء الملفات ورفعها على مستودع Hugging Face راجع التوثيقات ذات الصلة على المنصة. تحميل النماذج من واجهة الويب الخاصة بالمستودع إذا كنت تفضل العمل مع الواجهات الرسومية بدلًا من سطر الأوامر فيمكنك استخدام واجهة مستودع Hugging Face الموجودة على الرابط huggingface.co/new لإنشاء المستودع الجديد ورفع النماذج إليه كما في الصورة التالية: بعدها أدخل المعلومات التالية المطلوبة في الصورة أعلاه وهي كالتالي: حَدِّدْ مالك المستودع owner، سواء كنت أنت بصفتك الشخصية أو أي مؤسسة تنتمي إليها. اختر اسمًا مميزًا لنموذجك، والذي سيكون اسمًا للمستودع أيضًا. حَدِّدْ خصوصية مستودعك عامًا أم خاصًا. اختر رخصة استخدام نموذجك. اضغط بعدها على تبويب الملفات Files ثم زر أضف ملف Add file وحَمِّل ملفك الجديد إلى المستودع بطريقة السحب والإفلات، وأخيرًا أضف رسالة التثبيت commit message، ألقِ نظرة على الصورة التوضيحية التالية: إضافة بطاقة وصف للنموذج Model Card تساعد البطاقات مستخدمي النماذج على معرفة مزايا كل نموذج وإمكاناته والاعتبارات الأخلاقية لاستخدامه وغير ذلك من التفاصيل، لذا احرص على إضافة بطاقة خاصة لنموذجك لترشد كل من يود الاستفادة منه أو لتعود إليها عند الحاجة؛ تُعَرَّفْ بطاقة وصف النموذج model card بواسطة الملف README.md ويمكنك إنجاز الأمر بطريقتين: إنشاء الملف README.md وتحميله يدويًا. الضغط على زر تحرير بطاقة النموذج Edit model card من الواجهة الرسومية لمستودعك. ألق نظرة على بطاقة وصف النموذج DistilBert على سبيل المثال، واطَّلِع على المعلومات التي تتضمنها عادةً بطاقات النماذج، كما يفيدك أيضًا استعراض قسم التوثيقات الخاص ببطاقات النماذج على منصة Hugging Face لتعرف المزيد عن الخيارات المرتبطة بالملف README.md مثل البصمة الكربونية للنموذج model’s carbon footprint (التي تقيس استهلاك الطاقة المستخدمة في تشغيل الحواسيب اللازمة لتدريب النموذج، أو اختباره وتشغيله)، وبعض الأمثلة عن الأدوات الملحقة به widget examples. الخلاصة تعلمنا في هذا المقال كيفية مشاركة نماذج الذكاء الاصطناعي على مستودع Hugging Face بعدة طرق برمجيًا وعبر واجهة الويب الرسومية لمستودع النماذج، برمجيًا لدينا طريقتين استخدام الدالة push_to_hub أو إضافة المعامل Push_to_hub=True إلى معاملات التدريب، أما عبر واجهة الويب فيمكنك إنشاء حسابك على المنصة ورفع نموذجك ببضع نقرات بسيطة، والنقطة الأهم أنك تستطيع تحويل النموذج إلى أطر العمل المختلفة قبل مشاركته على المستودع، وذلك بخطوات بسيطة عرضناها في المقال، فتُسهل على الآخرين تحميله بالصيغة التي يفضلونها مثل: PyTorch أو TensorFlow أو Flax، ولا تنسَ إضافة بطاقة وصف دقيقة للنموذج توضح للراغبين بتحميله إمكاناته وخصائصه وشروط استخدامه. ترجمة -وبتصرف- لقسم Share a model من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: تدريب المًكيَّفات PEFT Adapters بدل تدريب نماذج الذكاء الاصطناعي بالكامل. تعرف على أهم مشاريع الذكاء الاصطناعي مكتبات وأطر عمل الذكاء الاصطناعي: القوة الكامنة خلف الأنظمة الذكية المعالجة المُسبقة للبيانات قبل تمريرها لنماذج الذكاء الاصطناعي
  9. نناقش في مقال اليوم طريقة استخدام توابع PEFT أو ما يعرف باسم توابع المعاملات الفعالة لصقل النماذج Parameter-Efficient Fine Tuning methods، وهي نوعٌ خاص من التوابع يُلغي أو يجمًد فعالية المعاملات الأصلية للنماذج المُدَرَّبة مسبقًا أثناء التدريب، ويستبدلها بمجموعة أصغر من المعاملات الخاصة بالمُكيّفات adapters ليجري تدريبها على المهمة المطلوبة بدلًا من تدريب النموذج كاملًا. توفر هذه الطريقة استخدام الذاكرة والموارد الحاسوبية المختلفة بشكل كبير لأن المكيّفات adapters المُدَرَّبة باستعمال توابع PEFT صغيرة الحجم مقارنة بالنماذج الكاملة، وهذا يجعلها أسهل في التحميل والتخزين والمشاركة، وهي تعطي النتائج نفسها التي نحصل عليها بتدريب كامل النموذج. ما هي المكيفات Adapters؟ المكيفات adapters هي بدائل خفيفة الوزن لتحسين نماذج الذكاء الاصطناعي المدربة مسبقًا pre-trained والمصقولة fine-tuned، فبدلاً من ضبط النموذج بالكامل، تُضاف المكيفات adapters بهيئة تعديلات صغيرة بين طبقات النموذج بعد مراحل معينة، وعند التدريب تُجَمَّدْ جميع أوزان النموذج وتُحدَّث أوزان المكيفات فقط وهو ما يؤدي إلى توفير كبير في الموارد الحاسوبية وتسريع التدريب وتحسين الأداء. ألقِ نظرة على الصورة التالية مثلًا فهي مأخوذة من مستودع النماذج، ولاحظ الفرق بين حجم مكيف النموذج OPTForCausalLM وبين حجم النموذج نفسه، إذ يبلغ حجم المكيف adapter حوالي 6 ميجا بايت بينما يصل حجم النموذج الأساسي إلى 700 ميجا. كما سيفيدك الاطلاع على PEFT إذا كنت مهتمًا بمعرفة المزيد من التفاصيل عنها. إعداد بيئة العمل ابدأ بتثبيت المكتبة PEFT من خلال الأمر التالي: pip install peft وإذا رغبت باستثمار مزاياها الحديثة أولًا بأول ثَبِّتها من المصدر الأساسي كما يلي: pip install git+https://github.com/huggingface/peft.git توافق نماذج PEFT مع مكتبة المحوّلات Transformers تدعم مكتبة المحوّلات Transformers عددًا من توابع PEFT تلقائيًا، فيمكنك تحميل أوزانها weights بسهولة سواء كانت مخزنة محليًّا أو في مستودع النماذج، ويمكن تدريبها وتشغيلها ببضع أسطر برمجية فقط، وهذه أبرزها: Low Rank Adapters. IA3. AdaLoRA. أما إذا رغبت باستخدام توابع أخرى مع مكتبة المحولات Transformers مثل: Prompt Learning و Prompt tuning فراجع توثيقات PEFT. تحميل PEFT Adapter يساعدك الصنف AutoModelFor وأصناف أخرى مشابهة على تحميل نماذج PEFT adapter من مكتبة المحوّلات Transformers واستخدامها في مشروعك، لكن تأكد من وجود الملف adapter_config.json وأوزان adapter في مجلدك المحلي أو المستودع البعيد Hub كما هو موضوح في الصورة السابقة. على سبيل المثال يمكنك تحميل نموذج PEFT adapter لمهمة النمذجة اللغوية السببية causal language modeling التي تمكنك من التنبؤ بالكلمة التالية في سلسلة نصية معينة بناءً على الكلمات السابقة باتباع التالي: حدد المُعَرِّف الخاص بنموذج PEFT الذي تريده (أي PEFT model id). مَرِّرْ هذا المُعَرِّف إلى الصنف AutoModelForCausalLM. from transformers import AutoModelForCausalLM, AutoTokenizer peft_model_id = "ybelkada/opt-350m-lora" model = AutoModelForCausalLM.from_pretrained(peft_model_id) يمكنك تحميل PEFT adapter أيضًا باستخدام الصنف AutoModelFor والصنف OPTForCausalLM والصنف LlamaForCausalLM كما يمكنك تحميله أيضًا بواسطة التابع load_adapter كما يلي: from transformers import AutoModelForCausalLM, AutoTokenizer model_id = "facebook/opt-350m" peft_model_id = "ybelkada/opt-350m-lora" model = AutoModelForCausalLM.from_pretrained(model_id) model.load_adapter(peft_model_id) التحميل بصيغة 8 بت أو 4 بت يمكنك الاستفادة من مكتبة bitsandbytes لتقليل استهلاك الذاكرة عن طريق تحميل النماذج باستخدام أنواع بيانات 8 بت و 4 بت، يساعدك هذا على توفير الذاكرة وتسريع تحميل النماذج الكبيرة، حيث يمكنك استخدام المعامل الذي تريده سواء كان load_in_8bit أو load_in_4bit ضمن محددات الدالة from_pretrained()‎ لتختار طبيعة تحميل نموذجك، ويمكنك أيضًا ضبط المعامل device_map="auto"‎ لتوزيع حمل النموذج بكفاءة على الموارد الحاسوبية المتاحة لك، وذلك وفق التالي: from transformers import AutoModelForCausalLM, AutoTokenizer peft_model_id = "ybelkada/opt-350m-lora" model = AutoModelForCausalLM.from_pretrained(peft_model_id, device_map="auto", load_in_8bit=True) تحميل adapter جديد يمكنك تعزيز إمكانيات نموذج الذكاء الاصطناعي من خلال تحميل مُكيَّف adapter إضافي لأي نموذج يحتوي على مُكيَّف adapter سابق لكن يشترط أن يكون من نفس نوع المُكيَّف الحالي الموجود مسبقًا في النموذج، كأن يكونا كلاهما من النوع LoRA مثلًا، وتُنجز ذلك باستخدام ‎~peft.PeftModel.add_adapter كما في المثال التالي: هذه الشيفرة الأصلية لتحميل مُكيَّف LoRA adapter لنموذج الذكاء الاصطناعي: from transformers import AutoModelForCausalLM, OPTForCausalLM, AutoTokenizer from peft import LoraConfig model_id = "facebook/opt-350m" model = AutoModelForCausalLM.from_pretrained(model_id) lora_config = LoraConfig( target_modules=["q_proj", "k_proj"], init_lora_weights=False ) model.add_adapter(lora_config, adapter_name="adapter_1") والآن سنضيف إليها السطر التالي لتحميل مُكيَّف LoRA adapter إضافي: # إضافة adapter جديد بنفس الإعدادات تمامًا model.add_adapter(lora_config, adapter_name="adapter_2") ثم سنستخدم ‎~peft.PeftModel.set_adapter لنُحدد أي adapter هو المعتمد في النموذج: # استخدام adapter_1 model.set_adapter("adapter_1") output = model.generate(**inputs) print(tokenizer.decode(output_disabled[0], skip_special_tokens=True)) # استخدام adapter_2 model.set_adapter("adapter_2") output_enabled = model.generate(**inputs) print(tokenizer.decode(output_enabled[0], skip_special_tokens=True)) طريقة تفعيل adapter معين أو إلغاء تفعيله يبين المثال التالي طريقة تفعيل adapter module: from transformers import AutoModelForCausalLM, OPTForCausalLM, AutoTokenizer from peft import PeftConfig model_id = "facebook/opt-350m" adapter_model_id = "ybelkada/opt-350m-lora" tokenizer = AutoTokenizer.from_pretrained(model_id) text = "Hello" inputs = tokenizer(text, return_tensors="pt") model = AutoModelForCausalLM.from_pretrained(model_id) peft_config = PeftConfig.from_pretrained(adapter_model_id) # تهيئة الأوزان العشوائية peft_config.init_lora_weights = False model.add_adapter(peft_config) model.enable_adapters() output = model.generate(**inputs) وهذه طريقة إلغاء التفعيل: model.disable_adapters() output = model.generate(**inputs) تدريب PEFT adapter يمكنك تدريب PEFT adapters على المهمة التي تريدها باستخدام صنف المُدَرِّب Trainer ببضع أوامر برمجية فقط، ألقِ نظرة على المثال التالي لتدريب LoRA adapter: 1. حدد ضمن إعدادات adapter المهمة التي تود تدريبه عليها، والمعاملات الفائقة hyperparameters الخاصة به وفق التالي، (يمكنك التَعرُّف على المعاملات الفائقة للنوع LoRA adapter واستخداماتها باستعراض تفاصيل ‎~peft.LoraConfig😞 from peft import LoraConfig peft_config = LoraConfig( lora_alpha=16, lora_dropout=0.1, r=64, bias="none", task_type="CAUSAL_LM", ) 2. أضِفْ adapter إلى النموذج: model.add_adapter(peft_config) 3. مَرِّرْ النموذج إلى المُدَرِّب: trainer = Trainer(model=model, ...) trainer.train() وفي النهاية احفظ adapter بعد التدريب وحَمِّله مجددًا كما يلي: model.save_pretrained(save_dir) model = AutoModelForCausalLM.from_pretrained(save_dir) زيادة طبقات إضافية قابلة للتدريب إلى PEFT adapter مَرِّرْ modules_to_save ضمن إعدادات PEFT لصقل fine-tune أي مُكيَّفات تود إضافتها إلى نموذجك الذي يحتوي في الأساس على adapters أخرى، كما في المثال التالي الذي يبين طريقة صقل lm_head فوق نموذج يحتوي في الأساس على LoRA adapter: from transformers import AutoModelForCausalLM, OPTForCausalLM, AutoTokenizer from peft import LoraConfig model_id = "facebook/opt-350m" model = AutoModelForCausalLM.from_pretrained(model_id) lora_config = LoraConfig( target_modules=["q_proj", "k_proj"], modules_to_save=["lm_head"], ) model.add_adapter(lora_config) الخلاصة تعرفنا في هذا المقال على المكيفات adapters وهي وحدات صغيرة تعوض عن تدريب نماذج الذكاء الاصطناعي الكاملة فتُحسِّن الأداء، وتعلمنا كيفية تحميل PEFT Adapters وإضافتها إلى نماذج مكتبة المحولات Transformers وتدريبها، وأيضًا تعرفنا على طريقة إضافة أكثر من مكيف adapter إلى النموذج لتحسين كفاءته بشرط أن تكون جميعها من نوعٍ واحد، مع إمكانية تفعيلها أو إلغاء تفعيلها حسب الحاجة. ترجمة -وبتصرف- لقسم Load adapters with PEFT من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: استخدام التدريب الموزع ومكتبة Accelerate لتسريع تدريب نماذج الذكاء الاصطناعي مكتبات وأطر عمل الذكاء الاصطناعي: القوة الكامنة خلف الأنظمة الذكية خوارزميات الذكاء الاصطناعي تدريب نموذج ذكاء اصطناعي على تلخيص النصوص باستخدام سكربتات Transformers
  10. يُعدّ التدريب الموزع أو التدريب على التوازي استراتيجيةً ناجحة في تدريب نماذج الذكاء الاصطناعي كبيرة الحجم على أجهزة حاسوبية محدودة الموارد، ويزداد الاعتماد عليها يومًا بعد يوم مع ازدياد أحجام النماذج المطروحة، وفي هذا المجال توفر منصة Hugging Face لمستخدميها مكتبةً متخصصة تدعى Accelerate تُسَهِّل عليهم تدريب نماذج مكتبة المحولات Transformers تدريبًا موزعًا بأنواعٍ مختلفة من الإعدادات مثل استخدام عدة وحدات معالجة رسومية (GPU) سواء كانت موجودة على الجهاز نفسه أو موزعة على عدة أجهزة، فكيف نطبق هذا الأسلوب عمليًّا على حلقات تدريب PyTorch الأصلي للاستفادة منه في تدريب نماذج الذكاء الاصطناعي في البيئات الحاسوبية ذات الموارد الموزعة؟ إعداد بيئة العمل ابدأ أولًا بتثبيت المكتبة Accelerate كما يلي: pip install accelerate ثم استورد كائن المُسَرِّع Accelerator وأنشئ واحدًا في مشروعك، وسيكتشف المُسَرِّع نوعية الإعدادات الموزعة المتوفرة لديك ويهيئ لك المكونات الضرورية للتدريب اعتمادًا عليها، ولا حاجة لتخزين النموذج على جهازك: >>> from accelerate import Accelerator >>> accelerator = Accelerator() التحضير لعملية التسريع Accelerate خطوتنا التالية هي تمرير كافة الكائنات المرتبطة بالتدريب إلى تابع التحضير accelerator.prepare والتي تشمل مُحَمِّلات البيانات DataLoaders لكل من مرحلتي التدريب training والتقييم evaluation بالإضافة إلى النموذج model والمُحَسِّن optimizer على النحو التالي: train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare( train_dataloader, eval_dataloader, model, optimizer ) ملاحظة: إن مهمة التابع prepare هنا هي تجهيز جميع مكونات التدريب للعمل في بيئة موزعة، وضمان توافق جميع المكونات مع بعضها البعض. استبدال الدالة Backward وأخيرًا علينا استبدل الدالة loss.backward()‎ المعتادة في حلقة التدريب بدالة Backward الخاصة بمكتبة Accelerate لضمان حساب التدرجات الخلفية (backward pass) بشكل صحيح على الأجهزة الموزعة على النحو التالي: for epoch in range(num_epochs): for batch in train_dataloader: outputs = model(**batch) loss = outputs.loss accelerator.backward(loss) optimizer.step() lr_scheduler.step() optimizer.zero_grad() progress_bar.update(1) إذًا يمكنك تحويل حلقة التدريب العادية إلى حلقة تدريب موزعة بإضافة أربعة أوامر برمجية فقط إلى حلقة التدريب (ميَّزناها هنا بإشارة "+")، وبحذف أمرين فقط (ميَّزناهما بإشارة "-"): + from accelerate import Accelerator from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler + accelerator = Accelerator() model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) optimizer = AdamW(model.parameters(), lr=3e-5) - device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") - model.to(device) + train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare( + train_dataloader, eval_dataloader, model, optimizer + ) num_epochs = 3 num_training_steps = num_epochs * len(train_dataloader) lr_scheduler = get_scheduler( "linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps ) progress_bar = tqdm(range(num_training_steps)) model.train() for epoch in range(num_epochs): for batch in train_dataloader: - batch = {k: v.to(device) for k, v in batch.items()} outputs = model(**batch) loss = outputs.loss - loss.backward() + accelerator.backward(loss) optimizer.step() lr_scheduler.step() optimizer.zero_grad() progress_bar.update(1) التدريب بعد إضافة الأسطر البرمجية السابقة لحلقة التدريب يمكنك البدء بتدريب نموذجك إما بتشغيل السكريبت لديك أو بكتابته في Colaboratory notebook أو أي دفتر ملاحظات مشابه. التدريب باستخدام السكربت إذا كنت تُدَرِّب نموذجك اعتمادًا على سكريبت، فاكتب الأمر التالي لإنشاء ملف الإعدادات وحفظه: accelerate config ثم باشر بالتدريب بكتابة الأمر التالي: accelerate launch train.py التدريب باستخدام دفتر الملاحظات Notebook يمكنك تشغيل مكتبة Accelerate داخل دفتر ملاحظات مثل Colaboratory notebook أو غيره إذا كنت ترغب باستخدام وحدات TPU (أي وحدات معالجة الموتر أو التنسور tensor) الخاصة بخدمة Colaboratory، لكن عليك في هذه الحالة وضع جميع تعليمات التدريب في دالة واحدة وتمريرها إلى notebook_launcher كما يلي: >>> from accelerate import notebook_launcher >>> notebook_launcher(training_function) الخلاصة تعرفنا في مقال اليوم على الخطوات الأساسية لاستخدام المكتبة Accelerate في تسريع تدريب نماذج الذكاء الاصطناعي باستخدام التدريب الموزع وهي طريقة مفيدة لتدريب نماذج الذكاء الاصطناعي الكبيرة على أجهزة محدودة الموارد، ويمكنك التعمق أكثر في خياراتها المختلفة بمطالعة توثيقاتها الرسمية. ترجمة -وبتصرف- لقسم Distributed training with Accelerate من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: تدريب نموذج ذكاء اصطناعي على تلخيص النصوص باستخدام سكربتات Transformers أدوات برمجة نماذج تعلم الآلة مكتبات وأطر عمل الذكاء الاصطناعي: القوة الكامنة خلف الأنظمة الذكية كيفية تهيئة تطبيق المفكرة Jupyter Notebook للعمل مع لغة البرمجة Python
  11. تزخر مكتبة المحوّلات Transformers بالسكربتات التوضيحية والأمثلة التي تشرح تدريب نماذج الذكاء الاصطناعي على مختلف المهام بأطر العمل الشهيرة بايتورش PyTorch وتنسرفلو TensorFlow و JAX/Flax، وترتبط هذه الأمثلة ببعض المشاريع البحثية والمساهمات القديمة لمجتمع Hugging Face، لكن لن تعمل هذه الأمثلة بدقة تامة في مشروعك من دون بعض التعديلات فهي في نهاية الأمر لا تخضع للصيانة والتحديث الدوري ومعظمها لا يتوافق مع الإصدارات الحديثة من مكتبة المحوّلات، لذا ستحتاج لتكييفها مع مشروعك. وبعد سحب الملف من GitHub يمكنك متابعة قراءة هذا المقال لتتعلم كيفية الاستفادة من السكربتات التدريبية الموجود على منصة Hugging Face وتكييفها لمشروعك، اخترنا هنا سكريبت بسيط لمهمة تلخيص النصوص وسنعرض طريقة التعامل معه في كل من إطاري العمل PyTorch و TensorFlow. إعداد بيئة العمل الخطوة الأولى لتشغيل أحدث إصدار من السكربتات التوضيحية بنجاح هي تثبيت مكتبة المحوّلات Transformers من المصدر في بيئة افتراضية جديدة كما يلي: git clone https://github.com/huggingface/transformers cd transformers pip install . وإذا أردت استخدام أمثلة تناسب الإصدارات القديمة من مكتبة المحوّلات Transformers مثل الإصدار v.4.5.1 يمكنك الاطلاع على الرابط وبنفس الطريقة للإصدارات الأخرى. ثم بَدِّل نسحتك من المكتبة إلى الإصدار الذي اخترته حسب المثال وليكن فرضًا الإصدار v3.5.1: git checkout tags/v3.5.1 بعد ضبط الإصدار الصحيح للمكتبة، انتقل إلى مجلد المثال الذي اخترته وثَبِّت متطلباته كما يلي: pip install -r requirements.txt تشغيل السكربت التوضيحي يبدأ السكربت بتحميل مجموعة بيانات dataset من مكتبة مجموعات البيانات Datasets ومعالجتها معالجةً مسبقة، ويستخدم بعدها المُدَرِّب Trainer لضبط مجموعة البيانات على بنية مناسبة لمهمة التلخيص summarization. يبين المثال التالي كيفية صقل النموذج T5-small وتدريبه بدقة fine-tuning على مجموعة البيانات CNN/DailyMail، لاحظ وجود الوسيط source_prefix وهو أحد متطلبات للنموذج T5 ويتيح له معرفة طبيعة المهمة التي سيستخدم لأجلها أي التلخيص في حالتنا، لنعرض السكربت الآن بإطاري العمل: أولًا باستخدام إطار العمل Pytorch: python examples/pytorch/summarization/run_summarization.py \ --model_name_or_path google-t5/t5-small \ --do_train \ --do_eval \ --dataset_name cnn_dailymail \ --dataset_config "3.0.0" \ --source_prefix "summarize: " \ --output_dir /tmp/tst-summarization \ --per_device_train_batch_size=4 \ --per_device_eval_batch_size=4 \ --overwrite_output_dir \ --predict_with_generate ثانيًا باستخدام إطار العمل TensorFlow: python examples/tensorflow/summarization/run_summarization.py \ --model_name_or_path google-t5/t5-small \ --dataset_name cnn_dailymail \ --dataset_config "3.0.0" \ --output_dir /tmp/tst-summarization \ --per_device_train_batch_size 8 \ --per_device_eval_batch_size 16 \ --num_train_epochs 3 \ --do_train \ --do_eval التدريب الموزع والدقة المختلطة يدعم المُدَرِّب ميزة التدريب الموزع distributed training أي توزيع التدريب على أكثر من وحدة معالجة، وميزة الدقة المختلطة mixed precision التي تتيح إمكانية العمل على 32 بت أو 16 بت للتسريع، يمكنك تفعيل الميزتين ضمن السكربت بضبط قيم الوسيطين التاليين: أضف الوسيط fp16 لتفعيل ميزة الدقة المختلطة. حدد عدد وحدات المعالجة الرسومية (GPUs) التي تريد استخدامها ضمن الوسيط nproc_per_node. torchrun \ --nproc_per_node 8 pytorch/summarization/run_summarization.py \ --fp16 \ --model_name_or_path google-t5/t5-small \ --do_train \ --do_eval \ --dataset_name cnn_dailymail \ --dataset_config "3.0.0" \ --source_prefix "summarize: " \ --output_dir /tmp/tst-summarization \ --per_device_train_batch_size=4 \ --per_device_eval_batch_size=4 \ --overwrite_output_dir \ --predict_with_generate أما إطار TensorFlow فيستخدم التدريب الموزع افتراضيًا باستراتيجية خاصة تدعى MirroredStrategy ويوزع العمل على كافة وحدات GPU المتوفرة للتدريب من دون الحاجة لضبط أي وسيط إضافي بهذا الخصوص ضمن السكربت. تشغيل السكربت باستخدام وحدات TPU إن تسريع الأداء هو الهدف الكامن وراء تصميم وحدات معالجة المُوترات أو التنسورات Tensors التي تدعى اختصارًا TPUs، ويساعدك مترجم التعلُّم العميق XLA compiler على استخدامها مع إطار العمل PyTorch (يمكنك معرفة المزيد عنها بمطالعة هذا الرابط). الآن افتح السكربت xla_spawn.py وحدد عدد نوى معالجة المُوترات TPU cors التي تود استخدامها بذكرها ضمن الوسيط num_cores وفق التالي: python xla_spawn.py --num_cores 8 \ summarization/run_summarization.py \ --model_name_or_path google-t5/t5-small \ --do_train \ --do_eval \ --dataset_name cnn_dailymail \ --dataset_config "3.0.0" \ --source_prefix "summarize: " \ --output_dir /tmp/tst-summarization \ --per_device_train_batch_size=4 \ --per_device_eval_batch_size=4 \ --overwrite_output_dir \ --predict_with_generate أما إطار العمل TensorFlow فيستخدم استراتيجيةً اسمها TPUStrategy لتدريب النماذج اعتمادًا على وحدات TPU، ويتعين عليك تحديد اسم المورد الحاسوبي resource الذي ستستخدمه ضمن الوسيط tpu في السكربت كما يلي: python run_summarization.py \ --tpu name_of_tpu_resource \ --model_name_or_path google-t5/t5-small \ --dataset_name cnn_dailymail \ --dataset_config "3.0.0" \ --output_dir /tmp/tst-summarization \ --per_device_train_batch_size 8 \ --per_device_eval_batch_size 16 \ --num_train_epochs 3 \ --do_train \ --do_eval تشغيل السكربت مع المكتبة Accelerate مكتبة Accelerate هي مكتبة خاصة بإطار العمل بايتورش PyTorch فقط، حيث توفر أسلوبًا موحدًا لتدريب نموذج الذكاء الاصطناعي نفسه بإعدادات مختلفة (سواء بالاعتماد على وحدة المعالجة المركزية CPU فقط، أو على أكثر من وحدة معالجة رسومية GPU، أو على وحدات معالجة الموترات TPU) مع الحفاظ على وضوح حلقة التدريب، لكن في البداية ينبغي لنا التأكد من تثبيت المكتبة Accelerate: تنويه: تتطور مكتبة Accelerate باستمرار لذا احرص على تثبيتها من مستودعها على git. pip install git+https://github.com/huggingface/accelerate سنستخدم الآن السكربت run_summarization_no_trainer.py الذي يتضمن الإعدادات الخاصة باستخدام مكتبة Accelerate بدلًا من السكربت السابق run_summarization.py، يمكنك تمييز السكربتات الخاصة بمكتبة Accelerate بوجود الملف Task_no_trainer.py ضمن مجلداتها. ابدأ بتنفيذ الأمر التالي الخاص بإنشاء ملف الإعدادات وحفظه: accelerate config ثم اختبر ملف الإعدادات للتأكد من سلامته: accelerate test أصبحنا جاهزين لبدء التدريب: accelerate launch run_summarization_no_trainer.py \ --model_name_or_path google-t5/t5-small \ --dataset_name cnn_dailymail \ --dataset_config "3.0.0" \ --source_prefix "summarize: " \ --output_dir ~/tmp/tst-summarization استخدام مجموعة بيانات مخصصة مع سكربت التلخيص يمكنك استخدام مجموعة بيانات مخصصة مع سكربت التلخيص التوضيحي الذي اخترناه هنا، بشرط أن تكون بصيغة CSV أو JSON وستحتاج أيضًا لضبط بعض الوسطاء الإضافية لتتناسب مع مجموعة بياناتك وفق التالي: يحدد كل من الملف Train_file وملف validation_file مسار حفظ ملفات التدريب والتحقق على التوالي. يشير text_columnd إلى الدخل أو النص المطلوب تلخيصه. يَدُّل على الخرج ٍSummary_column على الخرج أو النص الهدف بعد التلخيص. وستكون الصيغة النهائية لسكربت التلخيص مع استخدام مجموعة بيانات مخصصة على النحو التالي: python examples/pytorch/summarization/run_summarization.py \ --model_name_or_path google-t5/t5-small \ --do_train \ --do_eval \ --train_file path_to_csv_or_jsonlines_file \ --validation_file path_to_csv_or_jsonlines_file \ --text_column text_column_name \ --summary_column summary_column_name \ --source_prefix "summarize: " \ --output_dir /tmp/tst-summarization \ --overwrite_output_dir \ --per_device_train_batch_size=4 \ --per_device_eval_batch_size=4 \ --predict_with_generate اختبار السكربت على عينة من البيانات يُعدّ اختبار السكربتات على عينة صغيرة من مجموعة البيانات أسلوبًا ناجحًا للتأكد من صحتها وفعاليتها قبل تطبيقها على كامل البيانات، فتجريب السكربت على dataset كاملة يستغرق وقتًا طويلًا ربما ساعات قبل حصولك على النتيجة، ويساعدك الوسطاء الثلاثة الموجودين أدناه على اقتطاع جزء من مجموعة البيانات حسب قيمة كل وسيط ليُنَفَذ السكربت على جزء العينات المقتطع فقط من مجموعة البيانات بدلًا من تنفيذه على كامل المجموعة: max_train_samples. max_eval_samples. max_predict_samples. python examples/pytorch/summarization/run_summarization.py \ --model_name_or_path google-t5/t5-small \ --max_train_samples 50 \ --max_eval_samples 50 \ --max_predict_samples 50 \ --do_train \ --do_eval \ --dataset_name cnn_dailymail \ --dataset_config "3.0.0" \ --source_prefix "summarize: " \ --output_dir /tmp/tst-summarization \ --per_device_train_batch_size=4 \ --per_device_eval_batch_size=4 \ --overwrite_output_dir \ --predict_with_generate ملاحظة: لا تتيح جميع السكربتات التوضيحية الموجودة في مكتبة المحوّلات إمكانية استخدام الوسيط max_predict_samples لذا ننصحك بالتحقق أولًا من توفر هذه الإمكانية في السكربت بإضافة الوسيط h- وفق التالي: examples/pytorch/summarization/run_summarization.py -h استئناف التدريب من نقطة تحقق سابقة قد يتوقف تدريب النموذج لأسباب غير متوقعة؛ هل سبق أن تعرضت لذلك؟ يساعدك خيار استئناف التدريب من نقطة تحقق checkpoint سابقة على متابعة تدريب نموذجك من حيث توقف دون الحاجة لإعادته من البداية، ويوجد طريقتان لإجراء ذلك: سنستخدم في الطريقة الأولى الوسيط output_dir Previous_output_dir لاستئناف التدريب من أحدث نقطة تحقق متوفرة ومخزنة في المجلد output_dir، لكن علينا حذف الأمر overwrite_output_dir من السكربت في هذه الحالة: python examples/pytorch/summarization/run_summarization.py --model_name_or_path google-t5/t5-small \ --do_train \ --do_eval \ --dataset_name cnn_dailymail \ --dataset_config "3.0.0" \ --source_prefix "summarize: " \ --output_dir /tmp/tst-summarization \ --per_device_train_batch_size=4 \ --per_device_eval_batch_size=4 \ --output_dir previous_output_dir \ --predict_with_generate وفي الطريقة الثانية سيُستأنف التدريب انطلاقًا من نقطة التحقق الموجودة في مجلد محدد وذلك باستخدام الوسيط resume_from_checkpoint path_to_specific_checkpoint وفق التالي: python examples/pytorch/summarization/run_summarization.py --model_name_or_path google-t5/t5-small \ --do_train \ --do_eval \ --dataset_name cnn_dailymail \ --dataset_config "3.0.0" \ --source_prefix "summarize: " \ --output_dir /tmp/tst-summarization \ --per_device_train_batch_size=4 \ --per_device_eval_batch_size=4 \ --overwrite_output_dir \ --resume_from_checkpoint path_to_specific_checkpoint \ --predict_with_generate شارك نموذجك يمكنك أن ترفع السكربتات التوضيحية لنموذجك النهائي إلى مستودع النماذج Model Hub على منصة Hugging Face بعد انتهائك من استخدام السكربت، لكن عليك أولًا تسجيل حساب على المنصة وفق التالي: huggingface-cli login ثم إضافة الوسيط Push_to_hub إلى السكربت، يؤدي ذلك إلى إنشاء مستودع خاص بالمستخدم على Hugging Face يُسمى باسم الدخول الخاص به (أي username) مع اسم المجلد المُحدد في put_dir. يمكنك تغيير آلية التسمية واختيار الاسم الذي تريده لمستودعك باستخدام الوسيط Push_to_hub_model_id وسيُدرج تلقائيًا تحت المساحة الاسمية namespace المخصصة لك على المنصة. يبين المثال التالي طريقة تحميل النموذج إلى مستودعٍ محدد: python examples/pytorch/summarization/run_summarization.py --model_name_or_path google-t5/t5-small \ --do_train \ --do_eval \ --dataset_name cnn_dailymail \ --dataset_config "3.0.0" \ --source_prefix "summarize: " \ --push_to_hub \ --push_to_hub_model_id finetuned-t5-cnn_dailymail \ --output_dir /tmp/tst-summarization \ --per_device_train_batch_size=4 \ --per_device_eval_batch_size=4 \ --overwrite_output_dir \ --predict_with_generate الخلاصة شرحنا في مقال اليوم كيفية تدريب نموذج ذكاء اصطناعي على مهمة تلخيص النصوص باستخدام مكتبة المحولات Transformers وشرحنا خطوات إعداد بيئة العمل بداية من تثبيت هذه المكتبة من المصدر، ثم تشغيل سكربت تلخيص نصوص بسيط باستخدام إطاري عمل PyTorch و TensorFlow، كما وضحنا تقنيات تدريب وتسريع وتكييف السكربت ومشاركة النموذج المدرب على منصة Hugging Face. ترجمة -وبتصرف- لقسم Train with a script من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: طريقة الصقل Fine-Tune لنموذج ذكاء اصطناعي مُدَرَّبْ مُسبقًا المعالجة المُسبقة للبيانات قبل تمريرها لنماذج الذكاء الاصطناعي تلخيص النصوص باستخدام الذكاء الاصطناعي أهم مشاريع عملية عن الذكاء الاصطناعي مصطلحات الذكاء الاصطناعي للمبتدئين
  12. لاشك أن استخدام نماذج الذكاء الاصطناعي المُدَرَّبة مُسبقًا pretrained model يقلل الوقت والجهد والتكاليف اللازمة لتدريب هذه النماذج من الصفر، فضلًا عن إتاحة الفرصة أمامك لاستخدام أحدث النماذج المتوفرة على منصات متخصصة مثل تلك التي توفرها مكتبة المُحوّلات Transformers من منصة Hugging Face، لذا يلجأ مهندسو الذكاء الاصطناعي لاستخدام النماذج المُدَرَّبة مُسبقًا في كثير من الحالات ويعمدون إلى صقلها أو معايرتها Fine Tuning بدقة وتدريبها على بيانات محددة تناسب أهدافهم، إذ يعني صقل النماذج fine-tuning أخذ نموذج تعلم آلي مدرب مسبقًا ومواصلة تدريبه على مجموعة بيانات أصغر وأكثر تخصصًا للحفاظ على قدرات النموذج المدرب وتكييفه ليناسب استخدامات محددة ويعطي تنبؤاتٍ دقيقة، كما سنطرح بعض الأمثلة التوضيحية على تدريب النماذج باستخدام كل من التقنيات التالية: مُدَرِّب مكتبة المحوّلات Transformers Trainer. إطار العمل تنسرفلو TensorFlow مع كيراس Keras. إطار العمل بايتورش PyTorch لوحده. تحضير مجموعة بيانات التدريب قبل أن نبدأ بصقل النموذج fine-tune سنُحَمِّل مجموعة بيانات Dataset ونُحَضِّر بياناتها كما تعلمنا في المقال السابق المعالجة المُسبقة للبيانات قبل تمريرها لنماذج الذكاء الاصطناعي. اخترنا في هذا المقال مجموعة البيانات Yelp Reviews: >>> from datasets import load_dataset >>> dataset = load_dataset("yelp_review_full") >>> dataset["train"][100] {'label': 0, 'text': 'My expectations for McDonalds are t rarely high. But for one to still fail so spectacularly...that takes something special!\\nThe cashier took my friends\'s order, then promptly ignored me. I had to force myself in front of a cashier who opened his register to wait on the person BEHIND me. I waited over five minutes for a gigantic order that included precisely one kid\'s meal. After watching two people who ordered after me be handed their food, I asked where mine was. The manager started yelling at the cashiers for \\"serving off their orders\\" when they didn\'t have their food. But neither cashier was anywhere near those controls, and the manager was the one serving food to customers and clearing the boards.\\nThe manager was rude when giving me my order. She didn\'t make sure that I had everything ON MY RECEIPT, and never even had the decency to apologize that I felt I was getting poor service.\\nI\'ve eaten at various McDonalds restaurants for over 30 years. I\'ve worked at more than one location. I expect bad days, bad moods, and the occasional mistake. But I have yet to have a decent experience at this store. It will remain a place I avoid unless someone in my party needs to avoid illness from low blood sugar.'} وبما أن مجموعة بياناتنا نصية لذا سنحتاج مُرَمِّزًا tokenizer مناسبًا للنموذج لمعالجتها كما تعلمنا في مقالات السلسلة، تتضمن هذه المعالجة أساليب الحشو والاقتطاع لتوحيد أطوال السلاسل النصية، وسنستخدم دالةً تدعى map لتسريع المعالجة التحضيرية للبيانات وتطبيقها على كامل مجموعة البيانات dataset وفق التالي: >>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-cased") >>> def tokenize_function(examples): return tokenizer(examples["text"], padding="max_length", truncation=True) >>> tokenized_datasets = dataset.map(tokenize_function, batched=True) للسهولة وتسريع العمل يمكنك أخذ جزء من مجموعة البيانات فقط بدلًا من العمل معها كاملةً كما يلي: >>> small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000)) >>> small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000)) تدريب نموذج ذكاء اصطناعي باستخدام PyTorch Trainer إن المُدَرِّبTrainer هو أحد أصناف مكتبة المحوّلات Transformers حيث يستخدم لتدريب نماذج المكتبة، ويوفر عليك أعباء إنشاء حلقة تدريب خاصة بمشروعك من الصفر، ويتمتع هذا الصنف بواجهة برمجية API متنوعة الخيارات وتؤمن مزايا تدريبية واسعة، مثل: تسجيل الأحداث logging، والتدرج التراكمي gradient accumulation، والدقة المختلطة mixed precision. سنبدأ عملنا بتحميل النموذج وفق الأوامر التالية مع تحديد عدد التسميات التوضيحية labels المتوقعة من البيانات المُدخَلة، وإذا قرأت بطاقة وصف مجموعة البيانات التي حضرناها Yelp Review ستجد أن عدد التسميات labels فيها هو 5: >>> from transformers import AutoModelForSequenceClassification >>> model = AutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-cased", num_labels=5) ملاحة: عندما تُنَفِذ الأوامر السابقة ستواجه تحذيرًا مفاده أن بعض الأوزان المُدَرَّبة مسبقًا في النموذج لن تُسْتَخْدَمْ، وبعضها ستُعاد تهيئته عشوائيًا، يُعدّ هذا التحذير طبيعيًا ولا يستوجب القلق إذ سيُهمَل رأس النموذج BERT المُدَرَّب مسبقًا ويُستَبْدَل برأس تصنيف لا على التعيين، ثم يٌدَرَّب الرأس الجديد على تصنيف السلاسل وتنتقل إليه تلقائيًا كل المعرفة التي اكتسبها النموذج المدرب مسبقًا فيستفيد منها، علمًا أن رأس النموذج model head هو الجزء المسؤول عن معالجة مهمة معينة مثل التصنيف أو الترجمة ويستخدم لتحديد نتائجها. المعاملات الفائقة للنموذج hyperparameters سننشئ صنفًا لوسطاء التدريب TrainingArguments يتضمن كافة المعاملات الفائقة التي يمكننا ضبطها بالإضافة إلى الرايات flags الخاصة بتفعيل خيارات التدريب المختلفة، سنستعمل هنا المعاملات الافتراضية لكن يمكنك استعراض جميع المعاملات الفائقة وتجريبها لتصل إلى الإعدادات الملائمة لحالتك. ملاحظة: المعاملات الفائقة للنموذج هي المعاملات التي نحددها قبل بدء عملية تدريب النموذج وتتحكم في كيفية تعلم النموذج. لا تنسَ أن تحدد مكان حفظ نقاط التحقق checkpoints الناتجة عن التدريب: >>> from transformers import TrainingArguments >>> training_args = TrainingArguments(output_dir="test_trainer") التقييم لا يعطي المُدَرِّب Trainer في الأحوال الطبيعية مؤشراتٍ عن أداء النماذج في أثناء التدريب، فإذا رغبت بالحصول على تقييمٍ لنموذجك، ينبغي أن تمرر دالة خاصة بهذا الأمر تحسب مؤشرات الأداء وترجع لك تقريرًا بتقييم النموذج، وفي هذا المجال توفر مكتبة التقييم Evaluate دالةً بسيطة تدعى accuracy يمكنك تحميلها باستخدام evaluate.load كما في المثال التالي (طالع هذه الجولة السريعة في مكتبة التقييم لمزيدٍ من المعلومات): >>> import numpy as np >>> import evaluate >>> metric = evaluate.load("accuracy") استدعِ الدالة compute مع metric وفق التالي لحساب دقة التنبؤات الناتجة عن نموذجك، ولأن نماذج مكتبة المحوّلات Transformers تضع مخرجاتها في السمة logits (كما تعلمنا سابقًا في مقال جولة سريعة للبدء مع مكتبة المحوّلات Transformers) فينبغي لنا في البداية تحويل logits الناتجة عن النموذج إلى تنبؤات predictions ثم تمريرها لدالة حساب الدقة: >>> def compute_metrics(eval_pred): logits, labels = eval_pred predictions = np.argmax(logits, axis=-1) return metric.compute(predictions=predictions, references=labels) والآن أعطِ القيمة "epoch" للمعامل evaluation_strategy من وسطاء التدريب TrainingArguments لمراقبة أداء نموذجك أثناء التدريب فهذا الخيار سيعطيك تقييمًا في نهاية كل دورة تدريبية epoch للنموذج: >>> from transformers import TrainingArguments, Trainer >>> training_args = TrainingArguments(output_dir="test_trainer", evaluation_strategy="epoch") المُدَرِّب Trainer لننشئ الآن كائن المُدَرِّب Trainer باستخدام جميع الإعدادات السابقة وهي: النموذج الذي اخترناه، ووسطاء التدريب، ومجموعة بيانات التدريب، ودالة التقييم وذلك وفق الأمر التالي: >>> trainer = Trainer( model=model, args=training_args, train_dataset=small_train_dataset, eval_dataset=small_eval_dataset, compute_metrics=compute_metrics, ) ثم دَرِّب نموذجك باستخدامه كما يلي: >>> trainer.train() تدريب نموذج TensorFlow باستخدام Keras نناقش هنا تدريب نماذج من مكتبة Transformers باستخدام إطار العمل تنسرفلو TensorFlow وكيراس Keras API، حيث أن كيراس هو إطار عمل سهل ومفتوح المصدر يسمح بإنشاء شبكات عصبية معقدة بتعليمات قليلة، بدأ مشروعًا مستقلًا ثم اندمج مع TensorFlow (يمكنك معرفة المزيد بمطالعة قسم الذكاء الاصطناعي على أكاديمية حسوب وخاصةً المقال التعريفي مكتبات وأطر عمل الذكاء الاصطناعي). تحويل البيانات إلى صيغة تناسب كيراس Keras يتطلب تدريب نماذج Transformers باستخدام Keras API تحميل مجموعة بيانات بصيغة تتوافق مع كيراس Keras، وإحدى الطرق السهلة لذلك هي تحويل البيانات التدريبية إلى مصفوفات NumPy ثم تمريرها له، تناسب هذه الطريقة مجموعات البيانات صغيرة الحجم وهي ما سنجربه بدايةً قبل الانتقال إلى طرق أكثر تعقيدًا. لنُحمِّل في البداية مجموعة بيانات، وقد اخترنا هنا المجموعة CoLA dataset من GLUE benchmark وهي مجموعة بيانات بسيطة تناسب تصنيف النصوص الثنائية binary text، وسنأخذ منها القسم المخصص للتدريب فقط: from datasets import load_dataset dataset = load_dataset("glue", "cola") dataset = dataset["train"] # أخذنا من مجموعة البيانات القسم الخاص بالتدريب فقط سنُحَمِّل بعد ذلك مُرمِّزًا tokenizer يناسب النموذج ونستخدمه لترميز بيانات الندريب وتحويلها إلى مصفوفات NumPy، ولكن في مثالنا البيانات ثنائية بسيطة وتسمياتها التوضيحية labels هي مجموعة أصفار وواحدات فيمكننا تحويلها إلى مصفوفة NumPy مباشرةً دون ترميز: from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-cased") tokenized_data = tokenizer(dataset["sentence"], return_tensors="np", padding=True) # يرجع المُرَمِّز دفعات مُرَمَّزة من البيانات، حوّلناها هنا إلى قاموس يناسب Keras tokenized_data = dict(tokenized_data) labels = np.array(dataset["label"]) # هذه البيانات في الأساس مصفوفة أصفار وواحدات وفي المرحة الأخيرة سنُحَمِّل النموذج ونخضعه لعملية تصريف compile ثم ملائمة fit، وننوه هنا أن كل نموذج في مكتبة المحوّلات يتضمن دالةً افتراضية لحساب الخسارة loss function تناسب المهمة التي يُستَخدم النموذج لأجلها، فلست بحاجة لضبط أي خيارات بهذا الخصوص: from transformers import TFAutoModelForSequenceClassification from tensorflow.keras.optimizers import Adam # تحميل النموذج وتصريفه model = TFAutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-cased") # غالبًا ما تكون معدلات التَعَلُّم المنخفضة هي الأنسب لصقل نماذج مكتبة المحوّلات المُدَرَّبة مُسبقًا model.compile(optimizer=Adam(3e-5)) # لاحظ عدم وجود أي وسيط يتعلق بدالة حساب الخسارة فهي افتراضية model.fit(tokenized_data, labels) ملاحظة: تختار نماذج Hugging Face تلقائيًا دوال الخسارة المناسبة لبُنيتها ومهامها، لذا لن تضطر لتمرير الوسيط الخاص بحساب الخسارة عند تصريف نموذجك باستخدام compile()‎ لكن الخيار يبقى لك ففي حال لم ترغب باستخدام دالة الخسارة الافتراضية يمكنك حسابها بنفسك. يعمل أسلوب الترميز السابق جيدًا مع مجموعات البيانات صغيرة الحجم لكنه لا يُعدّ عمليًّا أبدًا مع مجموعات البيانات الكبيرة بل وسيؤدي إلى إبطاء عملية التدريب، يعود ذلك لسببين: الأول أن مصفوفتي الرموز والتسميات التوضيحية ستكونان كبيرتي الحجم وتحميلهما بالكامل إلى الذاكرة يُعدّ مشكلة، والسبب الثاني أن مكتبة Numpy لا تستطيع التعامل مع المصفوفات غير منظمة الأطوال المعروفة باسم jagged arrays يعني ذلك أنك ستضطر إلى حشو العناصر القصيرة في المصفوفة بالأصفار لتصبح جميعها بطول موحد يساوي أطول عنصر في المصفوفة، وهذا أيضًا سيُبَطئ التدريب. تحميل مجموعة بيانات بصيغة tf.data.Dataset يمكنك تحميل مجموعة بياناتك بصيغة tf.data.Dataset بدلًا من اتباع الطريقة السابقة والمخاطرة بإبطاء التدريب، سنقترح عليك طريقتين لإنجاز الأمر، وتستطيع إنشاء خط أنابيبك الخاص tf.data يدويًا إذا رغبت بذلك: prepare_tf_dataset()‎: تعتمد هذه الطريقة على طبيعة نموذجك لذا تُعدّ الطريقة الأنسب والموصى بها في معظم الحالات، فهي تفحص مواصفات النموذج وتتعرف تلقائيًا على أعمدة مجموعة البيانات المتوافقة معه أي التي يمكن استخدامها كمدخلات للنموذج، وتتجاهل الأعمدة غير المتوافقة فتُنشئ بذلك مجموعة بيانات أبسط وأفضل أداءً. to_tf_dataset: طريقة منخفضة المستوى low-level فهي تتحكم بالتفاصيل الدقيقة لطريقة إنشاء مجموعة بيانات التدريب، فتُمَكِّنك من تحديد الأعمدة columns وتسمياتها التوضيحية label_cols التي تود تضمينها في مجموعة البيانات. لنبدأ بالطريقة الأولى prepare_tf_dataset()‎، ولكن قبل تطبيقها ينبغي لنا ترميز البيانات وإدخال مُخرجات المُرَمِّز بهيئة أعمدة إلى مجموعة البيانات dataset كما يلي: def tokenize_dataset(data): # سنُدخِل مفاتيح القاموس الناتج هنا إلى مجموعة البيانات بصفتها أعمدة return tokenizer(data["text"]) dataset = dataset.map(tokenize_dataset) تُخَزَّن مجموعات بيانات Hugging Face على القرص الصلب افتراضيًا، فلن تسبب ضغطًا على استخدام الذاكرة على حاسوبك، وبمجرد إضافة الأعمدة السابقة تستطيع الحصول على الدفعات batches من مجموعة البيانات، وإضافة رموز الحشو إلى كل دفعة وهو ما يقلل عدد رموز الحشو المطلوبة في كل مرة مقارنةً بحشو مجموعة البيانات كاملةً. tf_dataset = model.prepare_tf_dataset(dataset["train"], batch_size=16, shuffle=True, tokenizer=tokenizer) مررنا إلى Preparation_tf_dataset في التعليمات السابقة وسيطًا خاصًا هو tokenizer يحدد المُرَمِّز الذي سنستخدمه لحشو الدفعات المُحَمَّلة بطريقة صحيحة، لكن يمكنك الاستغناء عنه إذا كانت العينات في مجموعة بياناتك متساوية الطول ولا تحتاج لأي حشو، أو استبداله بوسيطٍ آخر نحو Collate_fn إذا كنت ترغب بتدريب النموذج على حالات أعقد، مثل نمذجة اللغة المقنعة masked language modelling أي إخفاء بعض الرموز ليتنبأ النموذج بالكلمات من السياق أو غيرها من الحالات، تستطيع تحدد نوعية المعالجة التحضيرية التي تريدها للدفعات قبل تمريرها للنموذج، يساعدك الاطلاع على بعض الأمثلة والملاحظات المتعلقة بالموضوع من منصة Hugging Face لتطبيق ذلك عمليًّا. والآن بعد إنشاء مجموعة بيانات tf.data.Dataset يتبقى لنا الخطوة الأخيرة وهي تصريف النموذج compile وملائمته fit وفق التالي: model.compile(optimizer=Adam(3e-5)) # No loss argument! model.fit(tf_dataset) تدريب نموذج ذكاء اصطناعي باستخدام Native PyTorch يساعدك المُدَرِّب Trainer على تدريب نموذجك وضبطه بتعليمة واحدة فقط ويغنيك عن إنشاء حلقة التدريب من الصفر، لكن بعض المستخدمين يفضلون عدم الاعتماد على المُدَرِّب وإنشاء حلقات تدريبهم الخاصة بأنفسهم لتدريب نماذج مكتبة المحوّلات Transformers، فإذا كنت أحدهم يمكنك إجراء ذلك باستخدام إطار العمل PyTorch لوحده أي native PyTorch وفق الخطوات التالية، لكن في البداية ننصحك بتفريغ الذاكرة المؤقتة على جهازك أو دفتر ملاحظاتك notebook بإعادة تشغيله أو بتنفيذ هذه الأوامر: del model del trainer torch.cuda.empty_cache() تتضمن الخطوات التالية المعالجة التي سنجريها يدويًا على البيانات المُرَمَّزة tokenized_dataset لتحضيرها للتدريب. 1. تخَلَّص من عمود النص text لأن النموذج لا يقبل النصوص الخام مدخلاتٍ له: >>> tokenized_datasets = tokenized_datasets.remove_columns(["text"]) 2. عَدِّل اسم العمود label إلى labels ليتوافق مع اسم الوسيط الذي يقبله النموذج: >>> tokenized_datasets = tokenized_datasets.rename_column("label", "labels") 3. اضبط تنسيق مجموعة البيانات لتُرجِع PyTorch tensors بدلًا من القوائم المعتادة: >>> tokenized_datasets.set_format("torch") 4. ثم أنشئ مجموعة بيانات مُصَغَّرة من مجموعة البيانات الكاملة كما فعلنا في الفقرات السابقة لتسريع عملية صقل النموذج fine-tuning: >>> small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000)) >>> small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000)) مُحَمِّل البيانات DataLoader أنشئ مُحَمِّل بيانات DataLoader لمجموعات بيانات التدريب والاختبار لتٌنَفِّذ العمليات التكرارية على دفعات البيانات: >>> from torch.utils.data import DataLoader >>> train_dataloader = DataLoader(small_train_dataset, shuffle=True, batch_size=8) >>> eval_dataloader = DataLoader(small_eval_dataset, batch_size=8) ثم حَمِّل النموذج وحَدِّد عدد التسميات labels المتوقعة له: >>> from transformers import AutoModelForSequenceClassification >>> model = AutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-cased", num_labels=5) المُحَسِّنْ Optimizer ومُجَدّوِل معدل التعلُّم learning rate scheduler سننشئ مُحَسِّنْ Optimizer ومُجَدّوِل معدل التعلُّم learning rate scheduler لتدريب النموذج وضبطه، اخترنا هنا المُحَسِّنْ AdamW من PyTorch: >>> from torch.optim import AdamW >>> optimizer = AdamW(model.parameters(), lr=5e-5) ثم مُجَدّوِل معدل التعلُّم باستخدام المُجَدّوِل الافتراضي للمُدَّرِب Trainer: >>> from transformers import get_scheduler >>> num_epochs = 3 >>> num_training_steps = num_epochs * len(train_dataloader) >>> lr_scheduler = get_scheduler( name="linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps ) وأخيرًا حَدِّدْ قيمة المعامل device لتكون "cpu" إذا كان لديك وحدة معالجة رسوميات (GPU) ورغبت باستخدامها للتدريب، فمن دونها سيستغرق التدريب مدةً طويلة في حال الاعتماد على وحدة المعالجة المركزية (CPU) لوحدها وقد تصل المدة لساعات بدلًا من بضع دقائق: >>> import torch >>> device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") >>> model.to(device) أصبحنا جاهزين الآن للتدريب. حلقة التدريب Training loop إليك نموذجًا للشيفرة البرمجية الخاصة بحلقة التدريب، ويمكنك استخدام المكتبة tqdm لإضافة شريط خاص bar يعرض لك تقدم مراحل التدريب لتتبع سير العملية: >>> from tqdm.auto import tqdm >>> progress_bar = tqdm(range(num_training_steps)) >>> model.train() for epoch in range(num_epochs): for batch in train_dataloader: batch = {k: v.to(device) for k, v in batch.items()} outputs = model(**batch) loss = outputs.loss loss.backward() optimizer.step() lr_scheduler.step() optimizer.zero_grad() progress_bar.update(1) التقييم Evaluate يختلف أسلوب تقييم أداء النموذج في حلقة التدريب المخصصة عنه في صنف المُدَرِّب Trainer، فبدلًا من حساب مؤشرات الأداء وتصدير التقارير عنها في نهاية كل دورة تدربية epoch سيجري التقييم هنا في نهاية التدريب إذ سنُجَمع كافة الدفعات باستخدم add_batch ونحسب مؤشرات الأداء. >>> import evaluate >>> metric = evaluate.load("accuracy") >>> model.eval() for batch in eval_dataloader: batch = {k: v.to(device) for k, v in batch.items()} with torch.no_grad(): outputs = model(**batch) logits = outputs.logits predictions = torch.argmax(logits, dim=-1) metric.add_batch(predictions=predictions, references=batch["labels"]) >>> metric.compute() الخلاصة تغرفنا في مقال اليوم على تقنية الصقل fine-tuning لتدريب نماذج الذكاء الاصطناعي المُدَرَّبة مسبقًا وتحسين أدائها على مهام معينة باستخدام بيانات محددة، ووضحنا الفوائد الرئيسية لاستخدام نماذج مُدَرَّبة مسبقًا وكيفية تحميل وتحضير البيانات لها وتدريبها وضبطها وتقييم أدائها من خلال استخدام مكتبات وأطر عمل متنوعة تساعدنا في تنفيذ مهام الصقل مثل Transformers و TensorFlow و Keras و PyTorch كي نحسن من كفاءة وأداء هذه النماذج في مشاريعنا الخاصة. ترجمة -وبتصرف- لقسم Fine-tune a pretrained model من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: المعالجة المُسبقة للبيانات قبل تمريرها لنماذج الذكاء الاصطناعي تعرف على إطار عمل باي تورش PyTorch وأهميته لتطبيقات الذكاء الاصطناعي كيفية بناء شبكة عصبية لترجمة لغة الإشارة إلى اللغة الإنجليزية تعرف على أفضل دورات الذكاء الاصطناعي
  13. تحتاج جميع أنواع البيانات مهما كان نوعها سواء كانت نصوصًا أو صورًا أو ملفات صوتية أو غير ذلك إلى معالجة مسبقة أو معالجة تحضيرية قبل تمريرها لنماذج الذكاء الاصطناعي حتى تتدرب عليها، نطلق على هذه العملية اسم "data Preprocessing" إذ تتحول هذه البيانات بعد معالجتها إلى دفعاتٍ من التنسورات tensors التي تمثل بنى ملائمة لتمثيل البيانات تتوافق مع النموذج ويمكنه التعامل معها، وفي هذا المجال توفر مكتبة المحولات Transformers مجموعةً واسعة من أصناف المعالجة تُسّهِل عليك تجهيز بياناتك للنموذج، وهو ما سنتعلمه في مقال اليوم إذ سنُجري معالجة مسبقة لأنواع البيانات التالية: النصوص: سنستخدم المُرَمِّزات Tokenizer لمعالجة النص وتحويله إلى سلسلة رموز tokens، ثم تمثيلها عدديًا وتجميعها على هيئة tensors. الكلام والصوت: سنعتمد على مستخرج الميزات Feature extractor لاستخراج الميزات المتسلسلة من الأمواج الصوتية وتحويلها إلى tensors. الصور: سنتعامل مع معالج الصور ImageProcessor ونُمَرِر له الصور المطلوبة قبل إدخالها للنموذج فيُحولها إلى tensors. الأنماط المتعددة Multimodal: نستخدم في هذه الحالة معالجًا Processor يجمع بين وظيفة المُرَمِّز ووظيفة معالج الصور أو بين وظيفة المُرَمِّز ومستخرج الميزات حسب أنماط البيانات المستخدمة في مشروعك وهل هي تتضمن نصًا وصوتًا، أو نصًا وصورة، أو غير ذلك. ملاحظة: ننصحك باستخدام المعالج التلقائي AutoProcessor فهو يساعدك بصورة كبيرة ويختار لك دومًا دائمًا صنف المعالج المناسب لنموذجك سواء كان مُرَمِّز أو معالج صور أو مستخرج ميزات أو معالج للأنماط المتعددة. قبل البدء بأمثلتنا العملية سنُثَبِّتْ مجموعة البيانات Datasets لنتمكن من تحميل مجموعات بيانات تجريبية لعملنا من خلال كتابة التعليمة التالية: pip install datasets معالجة اللغة الطبيعية المُرَمِّز tokenizer هو الأداة الرئيسية لمعالجة النصوص اللغوية قبل تمريرها للنموذج، إذ يُقَسٍّمُها إلى رموز tokens وفقًا لقواعد خاصة، ثم يحوّل هذه الرموز إلى أعداد ثم إلى تنسورات tensors تمثل المدخلات المقبولة للنموذج، وستُمَرَر أية بيانات إضافية لاحقًا للنموذج له عبر المُرَمِّز. ملاحظة: إذا كنت تخطط لاستخدام أحد النماذج المُدَّربة مسبقًا بدلًا من تدريب نموذجك من الصفر، فاحرص على معالجة بياناتك بالمُرَمِّز نفسه الذي تَدّرَبَ عليه النموذج الجاهز قبل تمريرها له، فهذا يعني أن يُقَسَّم النص الخاص بك بالطريقة نفسها التي قُسِّمَت بها بيانات تدريب النموذج، وأن يُرَمَّز برموزه نفسها (التي يشار إليها بالمفردات vocab). لنبدأ بالتطبيق العملي، حَمِّلْ في البداية مُرَمِّزًا tokenizer يناسب النموذج الذي اخترته، ويتضمن المفردات vocab التي تَدَّرَبَ عليها سابقًا، وذلك بواسطة التابع AutoTokenizer.from_pretrained()‎ وفق التالي: >>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-cased") ثم مَرر النص للمُرَمِّز وستحصل على الخرج التالي: >>> encoded_input = tokenizer("Do not meddle in the affairs of wizards, for they are subtle and quick to anger.") >>> print(encoded_input) {'input_ids': [101, 2079, 2025, 19960, 10362, 1999, 1996, 3821, 1997, 16657, 1010, 2005, 2027, 2024, 11259, 1998, 4248, 2000, 4963, 1012, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]} يعطي المُرَمِّز في خرجه قاموسًا dictionary يتضمن ثلاثة أنواع من العناصر هي: input_ids: الدلالات العددية المقابلة لكل رمز من رموز الجملة أي لكل token. attention_mask: يشير إلى الرموز المهمة التي ينبغي الانتباه لها. token_type_ids: تبين السلسلة التي ينتمي إليها كل رمز، وهي مفيدة عندما تمرر أكثر من سلسلة للمُرَمِّز. يمكنك فك ترميز الخرج السابق لاستعادة النص الأصلي كما يلي: >>> tokenizer.decode(encoded_input["input_ids"]) '[CLS] Do not meddle in the affairs of wizards, for they are subtle and quick to anger. [SEP]' لاحظ أنك استعدت النص مع رمزين إضافيين هما CLS و SEP واحد في مقدمة الجملة، وواحد في نهايتها أضافهما المُرَمِّز، قد لا تتطلب جميع النماذج وجود هذين الرمزين لكنَّ المُرَمِّز يُضيفهما تلقائيًا، علمًا أن الرمز CLS هو اختصار لكلمة المُصَنِّف classifier والرمز SEP اختصار لكلمة الفاصل separator. أما إذا رغبت بمعالجة عدة جمل في آنٍ واحد، فمَرِرها للمُرَمِّز بهيئة قائمة list كما في المثال التالي: >>> batch_sentences = [ "But what about second breakfast?", "Don't think he knows about second breakfast, Pip.", "What about elevensies?", ] >>> encoded_inputs = tokenizer(batch_sentences) >>> print(encoded_inputs) {'input_ids': [[101, 1252, 1184, 1164, 1248, 6462, 136, 102], [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102], [101, 1327, 1164, 5450, 23434, 136, 102]], 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1]]} الحشو Pad يشترط النموذج أن تكون جميع tensors المدخلة إليه بنفس الطول أي بنفس عدد المحارف، وهذا الأمر لا يمكن تحقيقه من دون معالجة النصوص، فالجمل النصية التي نتعامل معها مختلفة الأطوال في معظم الحالات إن لم يكن في جميعها، لذا نلجأ للحشو pad في تطبيقات معالجة اللغة الطبيعية أي إضافة رموز خاصة للجمل القصيرة تسمى رموز الحشو padding token لزيادة طولها حتى تتساوى مع الجمل الطويلة فنحصل على طول موحد للمدخلات. اضبط المعامل padding على القيمة True لتُفَعِّل ميزة الحشو في برنامجك كما في المثال التالي: >>> batch_sentences = [ "But what about second breakfast?", "Don't think he knows about second breakfast, Pip.", "What about elevensies?", ] >>> encoded_input = tokenizer(batch_sentences, padding=True) >>> print(encoded_input) {'input_ids': [[101, 1252, 1184, 1164, 1248, 6462, 136, 102, 0, 0, 0, 0, 0, 0, 0], [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102], [101, 1327, 1164, 5450, 23434, 136, 102, 0, 0, 0, 0, 0, 0, 0, 0]], 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]]} كما تلاحظ فإن الجملة الثانية في المثال السابق هي الأطول، لذا أضفنا عددًا من الأصفار لكل من الجملة الأولى والثالثة حتى تتساوى معها بالطول. الاقتطاع Truncation الاقتطاع Truncation هي الحالة المعاكسة للحشو، فقد تصادف في بعض الأحيان سلاسل طويلة جدًا أكبر من الحد المسموح به في النماذج فلا يستطيع النموذج التعامل معها، نلجأ في الحالة لاقتطاع جزء من السلسلة حتى تصبح أقصر. يمكنك استخدام هذه الخاصية بضبط قيمة المعامل truncation على True ليقطتع المُرَمِّز من طول السلسلة المدخلة حتى تتناسب مع الحد الأقصى للطول الذي يقبله النموذج: >>> batch_sentences = [ "But what about second breakfast?", "Don't think he knows about second breakfast, Pip.", "What about elevensies?", ] >>> encoded_input = tokenizer(batch_sentences, padding=True, truncation=True) >>> print(encoded_input) {'input_ids': [[101, 1252, 1184, 1164, 1248, 6462, 136, 102, 0, 0, 0, 0, 0, 0, 0], [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102], [101, 1327, 1164, 5450, 23434, 136, 102, 0, 0, 0, 0, 0, 0, 0, 0]], 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]]} يمكنك مطالعة دليل الحشو والاقتطاع على منصة Hugging Face لمعرفة المزيد حول وسطاء arguments هاتين العمليتين. بناء الموترات Tensors إن عناصر الموترات أو التنسورات tensors هي المخرجات النهائية التي نريدها من المُرَمِّز ففي نهاية الأمر هي المدخلات الوحيدة التي يقبلها النموذج، يمكنك الحصول عليها بضبط قيمة المعامل return_tensors حسب إطار عمل الذكاء الاصطناعي الذي تعتمده. فإذا كنت تستخدم إطار العمل بايتورش Pytorch، اضبط قيمة المعامل return_tensors على pt وفق التالي: >>> batch_sentences = [ "But what about second breakfast?", "Don't think he knows about second breakfast, Pip.", "What about elevensies?", ] >>> encoded_input = tokenizer(batch_sentences, padding=True, truncation=True, return_tensors="pt") >>> print(encoded_input) {'input_ids': tensor([[101, 1252, 1184, 1164, 1248, 6462, 136, 102, 0, 0, 0, 0, 0, 0, 0], [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102], [101, 1327, 1164, 5450, 23434, 136, 102, 0, 0, 0, 0, 0, 0, 0, 0]]), 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]])} وإذا كنت تستخدم إطار العمل TensorFlowK، اضبط قيمة المعامل return_tensors على tf كما في المثال التالي: >>> batch_sentences = [ "But what about second breakfast?", "Don't think he knows about second breakfast, Pip.", "What about elevensies?", ] >>> encoded_input = tokenizer(batch_sentences, padding=True, truncation=True, return_tensors="tf") >>> print(encoded_input) {'input_ids': <tf.Tensor: shape=(2, 9), dtype=int32, numpy= array([[101, 1252, 1184, 1164, 1248, 6462, 136, 102, 0, 0, 0, 0, 0, 0, 0], [101, 1790, 112, 189, 1341, 1119, 3520, 1164, 1248, 6462, 117, 21902, 1643, 119, 102], [101, 1327, 1164, 5450, 23434, 136, 102, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int32)>, 'token_type_ids': <tf.Tensor: shape=(2, 9), dtype=int32, numpy= array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int32)>, 'attention_mask': <tf.Tensor: shape=(2, 9), dtype=int32, numpy= array([[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int32)>} ملاحظة: تختلف خطوط الأنابيب في قبولها لوسطاء المُرَمِّز عند استدعائها ()__call__، فعلى سبيل المثال يدعم خط الأنابيب text-2-text-generation الوسيط truncation فقط، بينما يسمح خط الأنابيب text-generation بتمرير ثلاثة وسطاء هي text-generation و truncation و add_special_tokens، أما في خط الأنابيب fill-mask فتُمرر وسطاء المُرَمِّز بهيئة قاموس ضمن الوسيط tokenizer_kwargs. معالجة البيانات الصوتية إن أداة المعالجة في المهام الصوتية هي مُستَخرِج الميزات feature extractor حيث تستخدمه لمعالجة البيانات الصوتية الخام وإعدادها قبل إدخالها للنموذج، فيعمل على استخراج الميزات منها ثم تحوّيلها إلى tensors. سنبدأ أولًا بتحميل مجموعة بيانات صوتية مثل MInDS-14 dataset كما يلي: >>> from datasets import load_dataset, Audio >>> dataset = load_dataset("PolyAI/minds14", name="en-US", split="train") اطلب العنصر الأول من العمود audio من مجموعة البيانات لتأخذ لمحة عن تنسيق الدخل الذي نتعامل معه، علمًا أنه بمجرد استدعاء عمود audio سيتحمل الملف الصوتي تلقائيًا ويُعاد أخذ العينات منه: >>> dataset[0]["audio"] {'array': array([ 0. , 0.00024414, -0.00024414, ..., -0.00024414, 0. , 0. ], dtype=float32), 'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~JOINT_ACCOUNT/602ba55abb1e6d0fbce92065.wav', 'sampling_rate': 8000} يتضمن الخرج السابق ثلاثة عناصر: array: المصفوفة هي الإشارة الصوتية المُحَمَّلة للكلام، والتي سيُعاد أخذ العينات منها وتشكيلها بهيئة مصفوفة أحادية البعد path: يُشير إلى مسار تخزين الملف الصوتي sampling_rate: معدل أخذ العينات، وهو عدد العينات المأخوذة من الإشارة الصوتية في الثانية استُخدِمَ النموذج Wav2Vec2 في هذا المقال، وإذا قرأت توصيفه ستجد أن معدل أخذ العينات في البيانات الصوتية التي تَدَّرَب عليها هو 16KHz، وبالتالي لضمان سلامة التطبيق بنبغي أن نستخدم المعدل نفسه في البيانات الصوتية التي سنمررها للنموذج، لذا تفقد دائمًا معدل أخذ العينات في بياناتك الصوتية فإذا كان مختلفًا عن معدل النموذج فينبغي لك إعادة أخذ العينات منها وتسمى هذه العملية resample ليصبح لها نفس معدل النموذج، وهذه هي الخطوة الأولى التي سنطبقها تاليًا: 1. استخدم التابع cast_column الخاص بمجموعات البيانات Datasets لرفع معدل أخذ العينات في مجموعتنا إلى 16KHz: >>> dataset = dataset.cast_column("audio", Audio(sampling_rate=16_000)) 2. استدعِ العمود audio من مجموعة البيانات ليُعاد أخذ العينات منه وفق المعدل الجديد وتشكيل الملف الصوتي: >>> dataset[0]["audio"] {'array': array([ 2.3443763e-05, 2.1729663e-04, 2.2145823e-04, ..., 3.8356509e-05, -7.3497440e-06, -2.1754686e-05], dtype=float32), 'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~JOINT_ACCOUNT/602ba55abb1e6d0fbce92065.wav', 'sampling_rate': 16000} والآن سنُحمّل مستخرج الميزات لتسوية الملف الصوتي normalize، ومعالجته بالحشو أو الاقتطاع وتحضيره قبل إدخاله للنموذج، ففي معالجة النصوص كنا نضيف أصفارًا "0" إلى السلاسل النصية القصيرة لزيادة طولها، وهنا أيضًا سنضيف أصفارًا "0" إلى المصفوفة الصوتية array فهي لا تؤثر على معناها لأنها تفُسَّر بصفتها لحظات صامتة. حمّل إذًا مُستَخرِج الميزات المناسب لنموذجك بواسطة AutoFeatureExtractor.from_pretrained()‎ كما يلي: >>> from transformers import AutoFeatureExtractor >>> feature_extractor = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-base") ثم مَرر المصفوفة الصوتية array إلى مستخرج المميزات مع ضبط قيمة الوسيط sampling_rate على معدل أخذ العينات المرغوب لضمان تصحيح أي أخطاء قد تحدث: >>> audio_input = [dataset[0]["audio"]["array"]] >>> feature_extractor(audio_input, sampling_rate=16000) {'input_values': [array([ 3.8106556e-04, 2.7506407e-03, 2.8015103e-03, ..., 5.6335266e-04, 4.6588284e-06, -1.7142107e-04], dtype=float32)]} يمكنك تطبيق الحشو والاقتطاع هنا للتعامل مع السلاسل المتغيرة كما طبقناه مع المُرَمِّز tokenizer، ألقِ نظرة على طول العينتين الصوتيتين أدناه: >>> dataset[0]["audio"]["array"].shape (173398,) >>> dataset[1]["audio"]["array"].shape (106496,) أنشئ الدالة preprocess_function التالية لمعالجة مجموعة البيانات حتى تصبح جميع العينات الصوتية بطولٍ واحد، كل ما عليك هو تحديد الحد الأقصى لطول العينة، وسيعمل مستخرج الميزات على حشو السلاسل أو اقتطاعها لتصل للطول المطلوب: >>> def preprocess_function(examples): audio_arrays = [x["array"] for x in examples["audio"]] inputs = feature_extractor( audio_arrays, sampling_rate=16000, padding=True, max_length=100000, truncation=True, ) return inputs ثم طبِّق الدالة preprocess_function على أول بضع عينات من مجموعة البيانات: >>> processed_dataset = preprocess_function(dataset[:5]) أصبحت جميع العينات الآن بالطول نفسه الذي يماثل الحد الأقصى لطول العينة، ويمكننا تمريرها للنموذج: >>> processed_dataset["input_values"][0].shape (100000,) >>> processed_dataset["input_values"][1].shape (100000,) الرؤية الحاسوبية يستخدم معالج الصور image processor في مشاريع الرؤية الحاسوبية لتجهيز الصور قبل إدخالها للنموذج؛ وتتكون معالجة الصور من عدة مراحل تتحول الصور في نهايتها إلى مدخلات يقبلها النموذج، ومن المراحل على سبيل المثال: تغيير الحجم resizing، والتسوية normalizing، وتصحيح القناة اللونية color channel correction، وأخيرًا تحويل الصور إلى tensors. إن تحسين الصور أو تعزير الصور image augmentation هو الأسلوب الأكثر استخدامًا في المعالجة المسبقة للصور، وهذه أبرز الفوائد المرجوة من كليهما: تعمل ميزة تعزيز الصور image augmentation على تعديل الصور بطريقة تساعدك على الحد من الفرط في التخصيص أي المبالغة في ملائمة البيانات المدخلة للبيانات التي تدرب عليها النموذج، يزيد ذلك من واقعية النموذج ويُحَسِّن أدائه، يمكنك أن تبدع في تعزيز بياناتك وإنشاء نسخ عنها، اضبط السطوع والألوان مثلًا، أو اقتطع من الصور، أو عدّل تدويرها، أو غيّر حجمها بالتكبير أو التصغير أو غير ذلك، ولكن حافظ دائمًا على معناها. تضمن المعالجة المسبقة للصور image preprocessing مطابقة صورك لتنسيق الدخل الذي يقبله النموذج، فالصور المُمَرَّرة لنموذج الرؤية الحاسوبية ينبغي أن تُعالج بالطريقة نفسها التي عولجت فيها الصور التي تَدَّرَبَ عليها النموذج عند تدريبه وضبطه وتسمى عملية الصقل fine-tune. ملاحظة: احرص على استخدام معالج الصور ImageProcessor المرتبط بالنموذج الذي اخترته، ولجهة تعزيز الصور فيمكنك استخدام أي مكتبة تريدها لإنجاز ذلك. لنتعلم معًا كيف نستخدم معالج الصور على مجموعة بيانات كاملة، حمّل في البداية مجموعة البيانات food101 dataset وفق الأمر التالي، ويمكنك الاطلاع على دليل تحميل مجموعات البيانات من Hugging Face لمزيد من المعلومات عن طريقة تحميلها: ملاحظة: سنستخدم هنا المعامل split لأخذ عينة بسيطة من مجموعة البيانات لأنها كبيرة الحجم. >>> from datasets import load_dataset >>> dataset = load_dataset("food101", split="train[:100]") والآن لنأخذ الصورة الأولى من مجموعة البيانات باستخدام الخاصية image كما يلي: >>> dataset[0]["image"] حمّل بعدها معالج الصور المناسب لنموذجك باستخدام التابع AutoImageProcessor.from_pretrained()‎ كما يلي: >>> from transformers import AutoImageProcessor >>> image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224") يمكننا الآن إضافة بعض الصور باستخدام تعزيز الصور، تستطيع اختيار المكتبة التي تريدها لتطبيق ذلك، مثل Albumentations أو Kornia notebooks، أما في هذا المقال فقد استُخدِمَتْ الوحدة torchvision من مكتبة المحولات transforms وفق الخطوات التالية: سنستخدم اثنين من التحويلات transforms لتعديل الصور في مثالنا، التحويل الأول RandomResizedCrop لتغيير حجم الصور، والثاني ColorJitter لتغيير خصائصها مثل السطوع والتشبع، وسنستخدم الصنف Compose لدمج التحويلين معًا، علمًا أننا نستطيع استخلاص متطلبات الحجم الذي يقبله النموذج من خصائص image_processor إذ تشترط بعض النماذج قياساتٍ محددة للارتفاع والعرض، ويقتصر بعضها الآخر على تحديد أقصر حافة shortest_edge فقط. >>> from torchvision.transforms import RandomResizedCrop, ColorJitter, Compose >>> size = ( image_processor.size["shortest_edge"] if "shortest_edge" in image_processor.size else (image_processor.size["height"], image_processor.size["width"]) ) >>> _transforms = Compose([RandomResizedCrop(size), ColorJitter(brightness=0.5, hue=0.5)]) سننشئ دالةً تجمع بين وظيفتي معالجة الصور وتعزير الصور (التي أجريناها في الخطوة السابقة)، تُطَبَّق هذه الدالة على دفعات الصور التي سنمررها لها وتعطينا في النهاية pixel_values التي تُعدّ مدخلات النموذج، إذ إن المرحلة الثانية من الدالة تتضمن استخدام معالج الصور، وهو يتكفل بتسوية الصور وتحويلها إلى tensors مناسبة للنموذج، ألقِ نظرة على الأوامر التالية لتتضح لك الفكرة: >>> def transforms(examples): images = [_transforms(img.convert("RGB")) for img in examples["image"]] examples["pixel_values"] = image_processor(images, do_resize=False, return_tensors="pt")["pixel_values"] return examples لابُدّ أنك لاحظت أننا ضبطنا المعامل الخاص بتعديل حجم الصور في معالج الصور على القيمة do_resize=False، لأننا لا نحتاجه هنا فقد أنجزنا تعديل حجم الصور بالفعل في مرحلة تعزيز الصور (أي في الخطوة الأولى) مستفيدين من خاصية الحجم في معالج الصور image_processor لمعرفة حدود الحجم المقبولة في النموذج، أما إذا لم تعدل حجم الصور في مرحلة تعزيز الصور، فاترك المعامل do_resize على قيمته الافتراضية وسيُعَدِّل معالج الصور أحجام صورك بما يتناسب مع متطلبات النموذج. وبالمقابل إذا رغبت بإجراء تسوية normalize للصور ضمن مرحلة تعزيز الصور فاستخدم عندها الخاصيتين image_processor.image_mean و image_processor.image_std. استخدم الآن datasets.set_transform لتسريع نشر التحويلات السابقة transforms على مجموعة البيانات: >>> dataset.set_transform(transforms) استدعِ الصورة الأولى من مجموعة البيانات ولاحظ كيف تغيرت فقد أضاف إليها التحويل قيم pixel_values، وبذلك أصبحت مجموعة البيانات dataset جاهزة لإدخالها إلى النموذج: dataset[0].keys() ألقِ نظرة على الصورة بعد التعديل، فقد اقتطع جزءٌ عشوائيٌ منها، وتغيرت خصائصها اللونية. >>> import numpy as np >>> import matplotlib.pyplot as plt >>> img = dataset[0]["pixel_values"] >>> plt.imshow(img.permute(1, 2, 0)) ملاحظة:لا يقتصر عمل معالج الصور ImageProcessor على المعالجة المُسبقة أو التحضيرية للبيانات قبل إدخالها للنموذج، بل يستخدم أيضًا في المعالجة اللاحقة post processing فيعالج المخرجات الأولية لنموذج الذكاء الاصطناعي ويحولها إلى تنبؤات لها معنى مثل المربعات المحيطة bounding boxes وخرائط التقسيم segmentation maps. هذا مفيد في مهام مثل التَعرُّف على الكائنات object detection، والتجزئة الدلالية للصور semantic segmentation أي تقسيم الصورة إلى أجزاء بحيث يعبر كل جزء عن صنف معينة، وتجزئة المثيل instance segmentation وهي تشابه التجزئة الدلالية ولكن بالإضافة إلى تحديد الأصناف، تفصل المثيلات الفردية داخل نفس الصنف، وتجزئة panoptic segmentation الشاملة التي تنتج خرائط تقسيم شاملة تحدد كل جزء من الصورة وتوضح الصنف أو الكائن الذي ينتمي إليه. الحشو Pad تطبقُ بعض النماذج عملية تعزيز الصور في أثناء التدريب، مثل نموذج DETR المخصص للتعرف على الكائنات، وتسبب هذه الحالة اختلافًا في أحجام الصور ضمن الدفعة الواحدة batch، يتعامل DETR مع هذه الحالة باستخدام تابع الحشو image_processor.pad()‎ من الصنف DetrImageProcessor مع وضع قناع "pixel_mask" يظهر أي البيكسلات هي بيكسلات الحشو، بالإضافة إلى تعريف الدالة collate_fn وفق التالي لتجميع الصور: >>> def collate_fn(batch): pixel_values = [item["pixel_values"] for item in batch] encoding = image_processor.pad(pixel_values, return_tensors="pt") labels = [item["labels"] for item in batch] batch = {} batch["pixel_values"] = encoding["pixel_values"] batch["pixel_mask"] = encoding["pixel_mask"] batch["labels"] = labels return batch الأنماط المتعددة يُستَخدم المعالج processor لتحضير البيانات متعددة الأنماط multimodal قبل إدخالها لنماذج الذكاء الاصطناعي، ويجمع المعالج الواحد أكثر من وظيفة معالجة من الوظائف التي تعرفنا عليها، مثل المُرَمِّز ومُستَخرِج الميزات أو غير ذلك حسب مزيج الأنماط الموجود في بياناتك نصوص أو صور أو صوت. حمِّل مثلًا مجموعة البيانات LJ Speech متعددة الأنماط وطبق المثال التالي لتتعلم طريقة التَعَرُّف التلقائي على الكلام (ASR) فيها: >>> from datasets import load_dataset >>> lj_speech = load_dataset("lj_speech", split="train") سنُرَكِز اهتمامنا على الصوت audio والنص text في مهام التَعَرُّف التلقائي على الكلام ASR لذا سنبدأ بإزالة الأعمدة الأخرى من مجموعة البيانات وفق التالي: >>> lj_speech = lj_speech.map(remove_columns=["file", "id", "normalized_text"]) لنستعرض الآن عمودي الصوت والنص: >>> lj_speech[0]["audio"] {'array': array([-7.3242188e-04, -7.6293945e-04, -6.4086914e-04, ..., 7.3242188e-04, 2.1362305e-04, 6.1035156e-05], dtype=float32), 'path': '/root/.cache/huggingface/datasets/downloads/extracted/917ece08c95cf0c4115e45294e3cd0dee724a1165b7fc11798369308a465bd26/LJSpeech-1.1/wavs/LJ001-0001.wav', 'sampling_rate': 22050} >>> lj_speech[0]["text"] 'Printing, in the only sense with which we are at present concerned, differs from most if not from all the arts and crafts represented in the Exhibition' كما تعلمنا في الفقرات السابقة ينبغي أن يتطابق معدل أخذ العينات في بياناتنا الصوتية المدخلة للنموذج مع معدل أخذ العينات في البيانات الصوتية التي تَدَرَّبَ عليها النموذج سابقًا، لذا سنجري عملية إعادة أخذ للعينات resample في بياناتنا وفق التالي: >>> lj_speech = lj_speech.cast_column("audio", Audio(sampling_rate=16_000)) يمكننا الآن تحميل المعالج المناسب لحالتنا باستخدام AutoProcessor.from_pretrained()‎: >>> from transformers import AutoProcessor >>> processor = AutoProcessor.from_pretrained("facebook/wav2vec2-base-960h") يتبقى لنا خطوتان قبل تمرير البيانات للنموذج: إنشاء الدالة prepare_dataset التالية التي ستُعَالِج البيانات الصوتية الموجودة في array (أحد عناصر الخرج لمستخرج الميزات كما تعلمنا في فقرة الصوتيات) وتُحَوّلها إلى input_values، وأيضًا تُرَمِّز tokenize النص text ليتحول إلى labels، وبذلك نكون قد جهزّنا مُدخلات النموذج: >>> def prepare_dataset(example): audio = example["audio"] example.update(processor(audio=audio["array"], text=example["text"], sampling_rate=16000)) return example 2. تطبيق الدالة على مجموعة البيانات dataset، سنُطّبِّقها هنا على عينة منها: >>> prepare_dataset(lj_speech[0]) إذًا فقد جَهَّز المعالج بياناتنا للنموذج والتي تتكون من input_values و labels، وضبط معدل أخذ العينات على 16KHz، وبالتالي يمكننا الآن تمرير البيانات إلى النموذج. الخلاصة المعالجة المسبقة للبيانات قبل تمريرها لنماذج الذكاء الاصطناعي خطوة أساسية لا غنى عنها في أي مشروع، وتختلف أساليب المعالجة حسب نوع بياناتك صوت أو صورة أو نص أو غيرها، لكنها تنتهي دائمًا بتحويل البيانات الخام إلى tensors يقبلها النموذج، ولا تنسَ أن الأصناف التلقائية في مكتبة Transformers مثل: AutoTokenizer و AutoProcessor و AutoImageProcessor و AutoFeatureExtractor تساعدك على اختيار المعالج المسبق المناسب لنموذجك، وهذا مهمٌ جدًا عند استخدامك النماذج المدربة مسبقًا إذ ينبغي تُعالج بيانات مشروعك بالمعايير نفسها التي عولجت بها البيانات التي تَدَرَّبَ عليها النموذج قبلًا فتستخدم المفردات vocab نفسها مثلًا في مهام معالجة النص، ومعدل أخذ العينات نفسه والمهام الصوتية وما إلى ذلك. ترجمة -وبتصرف- لقسم Preprocess من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: تحميل النماذج المُدّربة مسبقًا باستخدام الأصناف التلقائية AutoClasses في مكتبة Transformers استخدام خطوط الأنابيب Pipelines للاستدلال في تطبيقات الذكاء الاصطناعي أفضل دورات الذكاء الاصطناعي مصطلحات الذكاء الاصطناعي للمبتدئين
  14. في ظل التنوع الكبير للبنى الموجودة في مكتبة المحوّلات Transformers قد يصعب عليك إنشاء بنية مناسبة لنقطة التحقق من النموذج checkpoint الخاصة بك وهنا يأتي دور الأصناف التلقائية AutoClasses التي توفرها مكتبة Transformers التي حرص مطوروها على جعلها مكتبةً مرنة وسهلة الاستخدام حيث تستنتج هذه الأصناف التلقائية البنية المناسبة لنقطة تحقق معينة وتُحمّلها لك تلقائيًا. فأنت تستطيع بواسطة الدالة ‎from_pretrained()‎ في مكتبة Transformers تحميل نموذج مُدَّرب مسبقًا لأي بنية تريدها بسرعة وسهولة ومن دون الحاجة لتدريبه من الصفر وهدر الوقت والموارد، ويمكننا القول أن إنتاج هذا النوع من الشيفرات البرمجية المعزول كليًّا عن نقاط التحقق checkpoint-agnostic code والتي يمكن استخدامها مع نماذج مختلفة دون تغيير يساعد المطورين جدًا، فالشيفرة التي تعمل مع نقطة تحقق معينة ستعمل مع أي نقطة تحقق أخرى حتى لو كانت مختلفة بالبنية طالما الشيفرة مُدربة سابقًا على مهمة مماثلة. سنتطرق للنقاط التالية في هذا المقال: تحميل مُرَمِّز مُدَّرب مسبقًا pretrained tokenizer. تحميل معالج صور مُدَّرب مسبقًا pretrained image processor. تحميل مُستخرج ميزات مُدَّرب مسبقًا pretrained feature extractor. تحميل معالج مُدَّرب مسبقًا pretrained processor. تحميل نموذج مُدَّرب مسبقًا pretrained model. تحميل نموذج ليكون backbone. المُرَمِّز التلقائي AutoTokenizer تبدأ معظم مهام معالجة اللغة الطبيعية (NLP) بمُرَمِّز AutoTokenizer يحول المُدخَلات إلى تنسيق مناسب للنموذج حتى يستطيع معالجتها. علينا أولًا تحميل المُرَمِّز المناسب للنموذج باستخدام الدالة ‎AutoTokenizer.from_pretrained()‎: >>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased") ثم تُرَمِّزْ المدخلات باستخدامه كما يلي: >>> sequence = "In a hole in the ground there lived a hobbit." >>> print(tokenizer(sequence)) {'input_ids': [101, 1999, 1037, 4920, 1999, 1996, 2598, 2045, 2973, 1037, 7570, 10322, 4183, 1012, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]} معالج الصور التلقائي AutoImageProcessor يعد معالج الصور AutoImageProcessor أداة مهمة في مكتبة Transformers تسهل عملية تحضير الصور للنماذج المختصة بالرؤية الحاسوبية، مما يجعل استخدام هذه النماذج أكثر سهولة وفعالية. تشبه وظيفة معالج الصور وظيفة المُرَمِّز AutoTokenizer فهو يُحَضِّر البيانات قبل إدخالها للنموذج، لكنه يستخدم في مهام الرؤية الحاسوبية فيكفل معالجة الصور المدخلة بالتنسيق الصحيح الملائم للنموذج، كما في المثال التالي: >>> from transformers import AutoImageProcessor >>> image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224") AutoBackbone AutoBackbone هو أداة قوية تسمح باستخدام نماذج معقدة مثل Swin Transformer بطريقة مرنة، حيث يمكن استخراج ميزات الصور على مستويات مختلفة من التفاصيل حسب متطلبات المهمة التي نقوم بها. ألقِ نظرة على الصورة التالية في البداية التي تبين نموذج Backbone الخاص بمحوّل Swin Transformer متعدد المراحل لاستخراج ميزات الصور: يساعدك AutoBackbone على استخدام النماذج المُدّربة مسبقًا بصفتها بنى أساسية Backbones مكونة من عدة مراحل تعطيك خرائط الميزات feature maps لبياناتك بطريقة تدريجية على عدة مراحل حتى تصل إلى أفضل نتيجة، ويمكنك تحديد المرحلة التي تريد استخراج الخرائط عندها بواسطة معاملات الدالة from_pretrained‎()‎ إذ ينبغي لك تحديد معامل واحد على الأقل من المعاملات التالية: المعامل out_indices: يشير إلى فهرس index الطبقة التي ستستخرج خريطة الميزات منها. المعامل out_features: يدل على اسم الطبقة التي ستستخرج خريطة الميزات منها. وإذا استخدمت المعاملين معًا فاحرص على التوافق بينهما، أما في الحالات التي لا تُمرر فيها أي معامل فستعبر بياناتك جميع مراحل Backbone وتحصل على خريطة الميزة من المرحلة الأخيرة. يبين المثال التالي كيفية الحصول على خريطة الميزات من المرحلة الأولى لنموذج Swin backbone عبر ضبط قيمة المعامل out_indices=(1,)‎، لاحظ الصورة ثم التعليمات البرمجية المرتبطة: >>> from transformers import AutoImageProcessor, AutoBackbone >>> import torch >>> from PIL import Image >>> import requests >>> url = "http://images.cocodataset.org/val2017/000000039769.jpg" >>> image = Image.open(requests.get(url, stream=True).raw) >>> processor = AutoImageProcessor.from_pretrained("microsoft/swin-tiny-patch4-window7-224") >>> model = AutoBackbone.from_pretrained("microsoft/swin-tiny-patch4-window7-224", out_indices=(1,)) >>> inputs = processor(image, return_tensors="pt") >>> outputs = model(**inputs) >>> feature_maps = outputs.feature_maps يمكنك الآن الوصول إلى الكائن feature_maps الخاص بخرائط الميزات وفق التالي: >>> list(feature_maps[0].shape) [1, 96, 56, 56] مُسْتَخْرِج الميزات التلقائي AutoFeatureExtractor يستخدم مُسْتَخْرِج الميزات في معالجة الصوتيات ويمكنك من معالجة الملفات الصوتية بالتنسيق الصحيح قبل إدخالها للنموذج، وفيما يلي طريقة تحميله بواسطة الدالة ‎AutoFeatureExtractor.from_pretrained()‎: >>> from transformers import AutoProcessor >>> processor = AutoProcessor.from_pretrained("microsoft/layoutlmv2-base-uncased") النموذج التلقائي AutoModel تتيح لك أصناف النماذج التلقائية AutoModel تحميل نموذج جاهز مُدَّرب مسبقًا يناسب المهمة التي تعمل عليها، وتختلف هذه الأصناف classes حسب إطار العمل الذي تستخدمه، ففي إطار عمل بايتورشPytorch تكون من نوع AutoModelFor (ويمكنك الاطلاع على كافة المهام التي تدعمها أصناف التلقائية بمراجعة القسم الخاص بها على Hugging Face)، تستطيع مثلًا يمكنك تحميل نموذج ملائم لتصنيف السلاسل sequence classification بواسطة AutoModelForSequenceClassification.from_pretrained()‎ كما يلي: يمكنك استخدام نقطة التحقق نفسها لمهمة مختلفة: >>> from transformers import AutoModelForTokenClassification >>> model = AutoModelForTokenClassification.from_pretrained("distilbert/distilbert-base-uncased") ملاحظة: في نماذج PyTorch تُحَمّل النماذج بواسطة التابع from_pretrained()‎ المعتمدة على torch.load()‎ التي تستخدم بدورها الوحدة pickle من بايثون وهي غير آمنة، لذا ننصحك بعدم تحميل أي نماذج مجهولة المصدر أو غير موثوقة حتى لا تَضُّرْ بمشروعك، واحرص دائمًا على تحميلها من منصات معروفة مثل النماذج العامة الموجودة في مستودع Hugging Face فهي أقل خطرًا إذ تفحصها المنصة عند كل commit لضمان خلوها من البرمجيات الخبيثة، ويمكنك الاطلاع على توثيقات المستودع لمعرفة أفضل الممارسات في هذا المجال مثل استخدام GPG في التحقق من أن عمليات commit في النموذج موقعة من طرف موثوق وغيرها من طرق الحماية. بالمقابل تُعدّ نقاط تحقق checkpoints لكل من إطاري TensorFlow و Flax محمية من هذا الخطر، ويمكنك الاستفادة من ذلك وتجاوز المخاطر السابقة بتحميل هذه النماذج ضمن بنى PyTorch أي بتحويلها إلى نماذج PyTorch باستخدام from_tf و from_flax بالصيغة kwargs مع from_pretrained. توجد أصناف تلقائية مشابهة في إطار العمل TensorFlow وتتيح أيضًا تحميل نماذج مُدَّربة مسبقًا لمهمة محددة تختارها، تسمى أصناف TFAutoModelFor (يمكنك الاطلاع على كافة مهام المعالجة التي تدعمها)، يبين المثال التالي طريقة استخدام TFAutoModelForSequenceClassification.from_pretrained()‎ لتحميل نموذج مناسب لتصنيف السلاسل: >>> from transformers import TFAutoModelForSequenceClassification model = >>> TFAutoModelForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased") تستطيع بسهولة إعادة استخدام نقطة التحقق التي وصلت إليها لتحميل بنية تناسب مهمة أخرى مختلفة كما في المثال التالي: >>> from transformers import TFAutoModelForTokenClassification >>> model = TFAutoModelForTokenClassification.from_pretrained("distilbert/distilbert-base-uncased") ختامًا يوصى باستخدام صنف المُرَمِّز التلقائي AutoTokenizer وأصناف النموذج التلقائي AutoModelFor و TFAutoModelFor (حسب إطار العمل الذي تعتمده) لتحميل مثيلات النماذج المُدَّربة مُسبقًا لمشروعك فهي تضمن استخدامك البنية الصحيحة والمناسبة لمهمتك في كل مرة. تابع معنا مقالات السلسلة واقرأ مقالنا التالي عن المعالجة المسبقة للبيانات قبل تمريرها لنماذج الذكاء الاصطناعي لتتعلم كيف تعالج مجموعات بياناتك وتضبطها بدقة قبل تمريرها إلى النموذج وذلك عبر تقنيات المعالجة المختلفة، مثل المُرَمِّز، ومعالج الصور، ومستخرج الميزات، ومعالج الأنماط المتعددة. ترجمة -وبتصرف- لقسم Load pretrained instances with an AutoClass من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: استخدام خطوط الأنابيب Pipelines للاستدلال في تطبيقات الذكاء الاصطناعي من هو مهندس الذكاء الاصطناعي وما أبرز مهامه مقدمة إلى الذكاء الاصطناعي التوليدي Generative AI مكتبات وأطر عمل الذكاء الاصطناعي: القوة الكامنة خلف الأنظمة الذكية
  15. نشرح في هذا المقال التعامل مع خطوط الأنابيب pipeline()‎ التي توفر طريقة سهلة وموحدة للتعامل مع نماذج الذكاء الاصطناعي الموجودة في مستودع Hugging Face إذ يمكنك استخدامها للاستدلال inference وتوقع معلومات جديدة بناءً على المعلومات المتوفرة بأي أسلوب معالجة، سواء كان يعتمد على فهم اللغة language أو فهم الكلام speech أو الرؤية الحاسوبية computer vision أو الأنماط المتعددة multimodal. فمع خطوط الأنابيب المتاحة في مكتبة transformers لن تحتاج معرفةً قوية بالنماذج المخصصة لنمط معين ولا بطريقة كتابة شيفراتها البرمجية فهي ستسهل عليك المهمة، وهذا ما نعرضه في هذا المقال إذ سنتناول النقاط التالية: كيفية استخدام خطوط الأنابيب للاستدلال. طريقة استخدام مُرَمِّز tokenizer محدد أو نموذج model محدد. آلية استخدام خطوط الأنابيب لمشاريع معالجة الصوتيات والرؤية والأنماط المتعددة multimodal التي تتضمن التعامل مع بيانات متعددة الأنماط مثل الأصوات والصور معًا. استخدام خطوط الأنابيب Pipeline يوجد خط أنابيب pipeline()‎ خاص بكل مهمة، إلّا أن استخدام خط الأنابيب العام general pipeline (وهو تجريد يضم خطوط الأنابيب الخاصة بجميع المهام) يوفر طريقةً أسهل وأكثر مرونة، إذ يُحَمِّل نموذجًا افتراضيًا وصنف معالجة مسبقة للاستدلال مناسبين لطبيعة مشروعك. يبين مثالنا التالي طريقة استخدام خط الأنابيب للتَعَرُّف التلقائي على الكلام (ASR) أي تحويله إلى نص، لتنفيذ هذا التطبيق حاول تطبيق الخطوات في بيئتك التجريبية: أنشئ خط الأنابيب pipeline()‎ وحدد المهمة التي تريدها وهي هنا التعرف التلقائي على الكلام: >>> from transformers import pipeline >>> transcriber = pipeline(task="automatic-speech-recognition") 2. مَرِّر مُدخَلَاتِك input إلى خط الأنابيب، واحصل على النتيجة، في مثالنا المُدخَل هو الملف الصوتي المطلوب التَعَرُّف عليه وتحويله إلى نص: >>> transcriber("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac") {'text': 'I HAVE A DREAM BUT ONE DAY THIS NATION WILL RISE UP LIVE UP THE TRUE MEANING OF ITS TREES'} إذا لم تكن النتيجة مرضية كأن لا يعطيك النص مثلًا المعنى كاملًا، أو يحوي كلمات في غير سياقها أو غير ذلك، فابحث عندها عن نموذج أقوى للتعامل مع المهمة، يمكنك الدخول مستودع Hugging Face مثلًا واستعراض نماذج التَعَرُّف على الكلام الأكثر تحميلًا ضمنه وتجريبها. ومنها على سبيل المثال النموذج Whisper large-v2 من منصة OpenAI فهو أحدث من النموذج الافتراضي Wav2Vec2 المستخدم أعلاه بسنتين، وقد جرى تدريبه على كمية بيانات أكثر بعشر أضعاف فهو بالتأكيد سيتفوق عليه في دقة التَعَرُّف على الكلام وسيعطيك نتائج أدق، هذا فضلًا عن قدرته على التنبؤ بعلامات الترقيم وحالة الحروف صغيرة أم كبيرة، ولا تتوفر هاتان الميزتان في Wav2Vec2. لنُعِدْ التنفيذ باستخدام النموذج Whisper large-v2 ونلاحظ الفرق: >>> transcriber = pipeline(model="openai/whisper-large-v2") >>> transcriber("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac") {'text': ' I have a dream that one day this nation will rise up and live out the true meaning of its creed.'} يبدو النص الآن أدق في إيصال المعنى وصياغته متماسكة أكثر من النص الأول، يمكنك معرفة المزيد عن النماذج المناسبة لمعالجة الملفات الصوتية بالاطلاع على القسم التعليمي الخاص بالصوتيات منصة Hugging Face، ويمكنك تجربة النماذج الموجودة في مستودع المنصة على عينات بسيطة ومقارنة النتائج لاختيار النموذج المناسب لك، وإن لم تجد ما يلائم مشروعك دَرِِّبْ نموذجك الخاص؛ لمزيدٍ من المعلومات طالع مقال [كيفية تدريب نموذج ذكاء اصطناعي مُدَّرب مسبقًا]() من هذه السلسلة على أكاديمية حسوب. أما إذا كان لديك عدة مُدخَلاَت inputs أي عدة ملفات صوتية تحتاج لتحويلها إلى نصوص كما في مثالنا أعلاه فيمكنك تمريرها لخط الأنابيب بهيئة قائمة وفق التالي: transcriber( [ "https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac", "https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/1.flac", ] ) تُعدّ خطوط الأنابيب طريقةً مرنة لتجريب النماذج، فالتبديل من نموذج لآخر إجراء سهل ولن يشكل أي عبءٍ عليك، وفضلًا عن ذلك فهي تستخدم مع مجموعات البيانات الكبيرة dataset وخوادم الويب webserver. معاملات خطوط الأنابيب هناك نوعان من معاملات parameters خطوط الأنابيب pipeline()‎ نوعان عامة وخاصة؛ توجد المعاملات العامة في جميع أنواع خطوط الأنابيب، بينما تختص المعاملات الخاصة بمهمة محددة مثل معالجة اللغة الطبيعية أو الرؤية الحاسوبية أو التعرُّف على الكلام أو غيرها، ويمكنك تعريف المعاملات في أي قسم من برنامجك كما في المثال التالي: transcriber = pipeline(model="openai/whisper-large-v2", my_parameter=1) out = transcriber(...) # يعتمد هذا السطر القيمة 1 للمعامل ‎out = transcriber(..., my_parameter=2) # تعدلت قيمة المعامل هنا وأصبحت 2 out = transcriber(...) # الآن بدون كتابة قيمة جديدة للمعامل سيأخذ من جديد القيمة الابتدائية 1 سنعرض بمزيد من التفصيل ثلاثة من أشهر المعاملات: معامل الجهاز Device يشير المعامل Device إلى الجهاز المستخدم لتشغيل نموذج الذكاء الاصطناعي سواء وحدة المعالجة المركزية (CPU) أو وحدة معالجة الرسومات (GPU).إذا ضبطت قيمة هذا المعامل على device=n فإن خط الأنابيب سيُحَمّل النموذج على الجهاز الذي حددته بالقيمة "n". ألقِ نظرة على الأمر التالي لضبط قيمة المعامل device علمًا أنه ينطبق على إطار عمل PyTorch و Tensorflow: transcriber = pipeline(model="openai/whisper-large-v2", device=0) أما إذا كنت تعتمد نموذجًا كبير الحجم ويحتاج إلى أكثر من وحدة معالجة رسومية (GPU) وكنت تستخدم PyTorch، فيمكنك عندها ضبط قيمة المعامل على device_map="auto"‎ لتجري عملية توزيع أوتوماتيكية لأحمال النموذج على مكونات الجهاز، مع الانتباه لأن استخدام المعامل device_map مشروط بوجود مكتبة التسريع Accelerate: pip install --upgrade accelerate إذًا سيوزع السطر التالي أحمال النموذج على معالجات الجهاز: transcriber = pipeline(model="openai/whisper-large-v2", device_map="auto") وننوه هنا إلى أن تمرير قيمة المتغير device_map="auto"‎ يغنيك عن كتابة device=device فوجودهما معًا في الشيفرة قد يسبب سلوكيات غير متوقعة في برنامجك. معامل حجم الدفعة Batch size لا تقُسِّم خطوط الأنابيب بيانات الاستدلال إلى دفعات batching افتراضيًا، فإذا أردت تقسيمها اضبط الإعدادات اللازمة لذلك، واعلم أن هذه العملية لا تؤدي دائمًا إلى تسريع الأداء فربما تسبب البطء في بعض الحالات، لذا يترك خيار التقسيم من عدمه حسب حالة الاستخدام. يبين المثال التالي طريقة استخدامها: transcriber = pipeline(model="openai/whisper-large-v2", device=0, batch_size=2) audio_filenames = [f"https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/{i}.flac" for i in range(1, 5)] texts = transcriber(audio_filenames) بموجب التعليمات السابقة: سيُطَبَّق خط الأنابيب على الملفات الصوتية الأربعة المقدمة له، لكنه سيُمررها للنموذج على دفعتين ملفين في كل دفعة، (النموذج في مثالنا موجود على وحدة GPU والتقسيم إلى دفعات يُعدّ مفيدًا في هذه الحالة). لا تتطلب عملية التقسيم كتابة أي تعليمات برمجية إضافية فكل ما عليك هو تحديد قيمة المعامل، مع ضرورة التنويه إلى أن الخرج سيكون نفسه في الحالتين سواء قَسَّمْتَ بياناتك المستخدمة للاستدلال أو لم تُقَسِّمْها فالهدف من التقسيم هو تسريع أداء خط الأنابيب فقط دون أي تأثير على التنبؤات. الغاية الأساسية كما ذكرنا تحسين الأداء لكنك قد ستصادف بعض العناصر كبيرة الحجم (الملفات الصوتية الطويلة مثلًا) والتي لا يمكن للنماذج معالجتها دون تقسيمها إلى أجزاء فستضطر عندها لاستخدام التقسيم بصرف النظر عن الأداء، وهنا يأتي دور خطوط الأنابيب إذ تخفف عنك بعض تعقيدات العملية وتقسم هذه العناصر نيابةً عنك. معاملات خاصة بنوع معين من المهمات يتوفر لكل مهمة معاملات خاصة تعطيها المرونة وتساعدك على التحكم بخياراتها الإضافية لصالح مشروعك، فعلى سبيل المثال يتضمن أسلوب المعالجة Transformers.AutomaticSpeechRecognitionPipeline.call()‎ معاملًا خاصًا يدعى return_timestamps يُعدّ معاملًا واعدًا في إضافة النصوص التوضيحية لمقاطع الفيديو subtitling videos: >>> transcriber = pipeline(model="openai/whisper-large-v2", return_timestamps=True) >>> transcriber("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac") {'text': ' I have a dream that one day this nation will rise up and live out the true meaning of its creed.', 'chunks': [{'timestamp': (0.0, 11.88), 'text': ' I have a dream that one day this nation will rise up and live out the true meaning of its'}, {'timestamp': (11.88, 12.38), 'text': ' creed.'}]} إذا دققت في خرج الأمر السابق ستلاحظ أن النموذج قد استنتج النص من الملف الصوتي وأيضًا وقت النطق بكل جملة 'timestamp'. لذا ننصحك بمراجعة توصيف الواجهة البرمجية API لكل مهمة أو أسلوب معالجة حتى تتعرف أكثر على معاملاتها وتتمكن من استثمار مزاياها على أكمل وجه، فعلى سبيل المثال تحتوي المهمة AutomaticSpeechRecognitionPipeline على معامل مفيد للتعامل مع الملفات الصوتية الطويلة يدعى chunk_length_s يفيدك في ترجمة الأفلام أو مقاطع الفيديو التي تصل مدتها إلى ساعة مثلًا والتي لا يستطيع النموذج التعامل معها بخياراته الاعتيادية: >>> transcriber = pipeline(model="openai/whisper-large-v2", chunk_length_s=30, return_timestamps=True) >>> transcriber("https://huggingface.co/datasets/sanchit-gandhi/librispeech_long/resolve/main/audio.wav") {'text': " Chapter 16. I might have told you of the beginning of this liaison in a few lines, but I wanted you to see every step by which we came. I, too, agree to whatever Marguerite wished, Marguerite to be unable to live apart from me. It was the day after the evening... و في سعيها للتطوير تشجع Hugging Face المستخدمين على طلب المعاملات التي يحتاجونها ولا يتمكنون من إيجادها. استخدام خط الأنابيب على مجموعة بيانات يمكنك تشغيل خط الأنابيب pipeline للاستدلال على مجموعة بيانات كبيرة dataset وليس مجرد قائمة بالمدخلات، وأسهل الطرق الموصى بها لإنجاز ذلك هي استخدام مُكَرِّر iterator كما في المثال التالي: def data(): for i in range(1000): yield f"My example {i}" pipe = pipeline(model="openai-community/gpt2", device=0) generated_characters = 0 for out in pipe(data()): generated_characters += len(out[0]["generated_text"]) يعمل المُكَرِّر data()‎ ويُرجِع نتيجة في كل تكرار؛ ويُميّز خط الأنابيب مباشرةً أن المُدخَل الوارد إليه قابل للتكرار iterable أي يمكن الحصول على بياناته بطريقة متكررة أو متتالية، فيبدأ بجلب البيانات بالتزامن مع استمراره في معالجة الموجود في وحدة GPU (ويستخدم في ذلك موازن البيانات DataLoader ضمنًا)، تتميز هذه الطريقة بكونها لا تتطلب حجز ذاكرة لكامل مجموعة البيانات، وتساعدك على تغذية GPU بالبيانات بأسرع ما يمكن. يُعدّ تقسيم البيانات إلى دفعات (بضبط المعامل batch_size) مفيدًا في هذه الحالة ويؤدي إلى تحسين الأداء. ويمكنك تنفيذ التكرار على مجموعة بيانات بتحميل إحدى مجموعات البيانات Datasets الموجودة في مستودعات Hugging Face وتقسيمها ثم استخدام الأداة المساعدة ‎KeyDataset ضمن حلقة التكرار للحصول على الخرج المطلوب: # KeyDataset أداة مساعدة ترجع لك الخرج الذي يهمك من مجموعة البيانات from transformers.pipelines.pt_utils import KeyDataset from datasets import load_dataset pipe = pipeline(model="hf-internal-testing/tiny-random-wav2vec2", device=0) dataset = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation[:10]") for out in pipe(KeyDataset(dataset, "audio")): print(out) ملاحظة: بطريقة مشابهة لاستخدامها مع مجموعات البيانات، يمكنك استخدام خطوط الأنابيب مع خوادم الويب في مشاريع ذات طبيعة خاصة، يمكنك الاطلاع على هذا الدليل من توثيقات Hugging Face لمزيد من المعلومات. استخدام خط الأنابيب مع الرؤية الحاسوبية عمليًا يشبه استخدام خطوط الأنابيب في مشاريع الرؤية الحاسوبية استخدامها في أمثلتنا السابقة. حَدِّد مهمتك ثم مرر الصورة إلى المُصَنِّف classifier، طبعًا يمكنك تمرير الصورة بهيئة رابط link أو مسار محلي path يشير إليها، أو صورة مشفرة بترميز base64. لنفترض مثلًا أن مهمتنا هي اكتشاف السلالة التي تنتمي إليها القطة في الصورة التالية: فستكون الشيفرة البرمجية كما يلي: >>> from transformers import pipeline >>> vision_classifier = pipeline(model="google/vit-base-patch16-224") >>> preds = vision_classifier( images="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg" ) >>> preds = [{"score": round(pred["score"], 4), "label": pred["label"]} for pred in preds] >>> Preds [{'score': 0.4335, 'label': 'lynx, catamount'}, {'score': 0.0348, 'label': 'cougar, puma, catamount, mountain lion, painter, panther, Felis concolor'}, {'score': 0.0324, 'label': 'snow leopard, ounce, Panthera uncia'}, {'score': 0.0239, 'label': 'Egyptian cat'}, {'score': 0.0229, 'label': 'tiger cat'}] استخدام خط الأنابيب مع النصوص يمكنك بآلية مشابهة استخدام خط الأنابيب لمهام معالجة اللغة الطبيعية (NLP) كما في المثال التالي: >>> from transformers import pipeline # النموذج المستخدم من نوع `zero-shot-classification` # يمكنك اختيار التسميات التوضيحية التي تريدها لتصنيف النص >>> classifier = pipeline(model="facebook/bart-large-mnli") >>> classifier( "I have a problem with my iphone that needs to be resolved asap!!", candidate_labels=["urgent", "not urgent", "phone", "tablet", "computer"], ) {'sequence': 'I have a problem with my iphone that needs to be resolved asap!!', 'labels': ['urgent', 'phone', 'computer', 'not urgent', 'tablet'], 'scores': [0.504, 0.479, 0.013, 0.003, 0.002]} استخدام خط الأنابيب مع الأنماط المتعددة يدعم خط الأنابيب التعامل مع أكثر من أسلوب معالجة في المهمة الواحدة، وهو ما يسمى بالمعالجة متعددة الأنماط Multimodal، ومن أمثلتها الإجابة عن الأسئلة المرئية (VQA) فهي تجمع بين معالجة النص والصورة، تمرر في هذه الحالة الصورة المطلوبة بهيئة رابط URL أو مسار تخزين ونص السؤال الذي تود طرحه عنها. ألقِ نظرة على المثال التالي، نسأل هنا عن رقم الفاتورة المكتوب في صورة الفاتورة الموجودة هنا: >>> from transformers import pipeline >>> vqa = pipeline(model="impira/layoutlm-document-qa") >>> vqa( image="https://huggingface.co/spaces/impira/docquery/resolve/2359223c1837a7587402bda0f2643382a6eefeab/invoice.png", question="What is the invoice number?", ) [{'score': 0.42515, 'answer': 'us-001', 'start': 16, 'end': 16}] لتنفيذ المثال السابق تحتاج لتثبيت الأداة pytesseract الخاصة بالتَعَرُّف على المستندات الممسوحة ضوئيًا (OCR) في بايثون طبعًا بالإضافة لمكتبة المحوّلات Transformers، وهذه أوامر تثبيتها: >> sudo apt install -y tesseract-ocr >> pip install pytesseract استخدام خط الأنابيب مع النماذج الكبيرة ومكتبة التسريع تُسهّل مكتبة التسريع accelerate استخدام خطوط الأنابيب مع النماذج الكبيرة large models، ويمكنك تثبيتها بالأمر pip install accelerate. حمّل نموذجك مع ضبط المعامل device_map="auto"‎ ثم اتبع الأوامر التالية، اخترنا في هذا المقال النموذج "facebook/opt-1.3b". # pip install accelerate import torch from transformers import pipeline pipe = pipeline(model="facebook/opt-1.3b", torch_dtype=torch.bfloat16, device_map="auto") output = pipe("This is a cool example!", do_sample=True, top_p=0.95) وإذا أردت تمرير نماذج 8‎-bit‎ فاحرص على تثبيت المكتبة bitsandbytes وتمرير الوسيط load_in_8bit=True كما في المثال التالي: # pip install accelerate bitsandbytes import torch from transformers import pipeline pipe = pipeline(model="facebook/opt-1.3b", device_map="auto", model_kwargs={"load_in_8bit": True}) output = pipe("This is a cool example!", do_sample=True, top_p=0.95) الآن يمكنك أخذ نقطة التحقق checkpoint هذه وتبديلها بأي نموذج يناسب النماذج الكبيرة من منصة Hugging Face مثل النموذج اللغوي متعدد اللغات BLOOM. ترجمة -وبتصرف- لقسم Pipelines for inference من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: تثبيت مكتبة المحوّلات Transformers تعرف على مكتبة المحوّلات Transformers من منصة Hugging Face تعرف على أفضل دورات الذكاء الاصطناعي تعرف على إطار عمل باي تورش PyTorch وأهميته لتطبيقات الذكاء الاصطناعي
  16. تعرفنا في مقال سابق على مكتبة المحوّلات Transformers التي توفرها منصة Hugging Face واستعرضنا أبرز مميزاتها وتوافقها مع أي مكتبة تعلُّم عميق تستخدمها؛ وسنتعلم في هذا المقال كيفية تثبيت هذه المكتبة على حاسوبك المحلي وخطوات ضبط متغيرات الذاكرة المخبئية cache المتعلقة بها، والإعدادات اللازمة للتعامل مع المكتبة دون الحاجةللاتصال بالإنترنت. هذه المكتبة مختبرة على إصدارات مختلفة من لغة بايثون من الإصدار 3.6 وأعلى، وإطار العمل باي تورش PyTorch من الإصدار 1.1.0 وأعلى، والإطار تنسرفلو TensorFlow من الإصدار 2 وأعلى، بالإضافة إلى مكتبة Flax. وسنعرض في مقال اليوم تعليمات تثبيتها مع كل من: إطار العمل PyTorch. إطار العمل TensorFlow 2.0. مكتبة الشبكات العصبية Flax. اتبع التعليمات التي تناسبك من بينها. التثبيت بواسطة مدير الحزم pip سنبدأ عملنا بإنشاء البيئة الافتراضية للمشروع إذ ينبغي أن تثبت المكتبة Transformers ضمن بيئة افتراضية، وتساعدك بيئات بايثون الافتراضية على إدارة مشاريعك البرمجية المختلفة بمرونة وتجنب المشكلات التي قد تحدث بسبب تعارض الاعتماديات الخاصة بكل مشروع. يمكنك معرفة المزيد عن كيفية تثبيت بايثون وإعداد بيئته الافتراضية على أشهر نظم التشغيل بمساعدة هذا الدليل باللغة العربية على أكاديمية حسوب. أنشئ بيئةً افتراضية في مجلد مشروعك وفق التالي: python -m venv .env ثم فعّل البيئة الافتراضية، فإذا كنت تستخدم نظام تشغيل لينكس أو ماك اكتب هذا الأمر: source .env/bin/activate وإذا كنت تستخدم نظام التشغيل ويندوز فيمكنك تفعيلها بكتابة ما يلي: .env/Scripts/activate وبذلك تكون جاهزًا لتثبيت المكتبة من خلال التعليمة التالية: pip install transformers وفي حالة الأجهزة التي تعتمد في معالجتها على وحدة المعالجة المركزية (CPU) فقط فيمكنك تثبيت مكتبة التعلم العميق ومكتبة المحولات transformers في سطرٍ واحد، مثل السطر التالي الذي يبين طريقة تثبيت PyTorch و Transformers: pip install 'transformers[torch]' والآن لتثبيت Transformers و TensorFlow 2.0 نكتب: pip install 'transformers[tf-cpu]' وأخيرًا لتثبيت Transformers مع Flax نكتب الأمر التالي: pip install 'transformers[flax]' يمكنك التأكد من صحة تثبيت المكتبة transformers بتنفيذ السطر التالي الذي ينبغي أن يُحمّل نموذج تعلّم آلي مدرب مسبقًا pretrained model: python -c "from transformers import pipeline; print(pipeline('sentiment-analysis')('we love you'))" ولنعرض بعدها قاموس النموذج الذي حمّلناه والمتضمن مفتاحي التسمية التوضيحية label ومجموع النقاط score: [{'label': 'POSITIVE', 'score': 0.9998704791069031}] دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن تثبيت المكتبة Transformers من المصدر الأساسي يمكنك تثبيت مكتبة المحولات من مصدرها الأساسي (أي من مستودع منصة Hugging Face على github) بكتابة التالي: pip install git+https://github.com/huggingface/transformers بهذه الطريقة ستثبت الإصدار الأساسي من المكتبة main version وليس أحدث إصدار مستقر متوفر stable version، والفرق بينهما أن استخدام الإصدار الأساسي يبقيك على اطلاع بأحدث تطورات المكتبة أولًا بأول حتى إن لم تكن تحديثات مستقرة، فمثلًا إذا ظهر خطأ معين في الإصدار الرسمي للمكتبة فيمكن للجهة المطورة لها أن تصلحه إطلاق الإصدار الجديد وبذلك ستستفيد من الإصلاح قبل طرح الإصدار الجديد المستقر. تأكد الآن من صحة تثبيت المكتبة بتنفيذ الأمر التالي: python -c "from transformers import pipeline; print(pipeline('sentiment-analysis')('I love you'))" تثبيت المكتبة تثبيًا قابلًا للتعديل تحتاج هذا النوع من التثبيت القابل للتعديل Editable install في حالتين هما: عندما تستخدم الإصدار الأساسي main version من الشيفرة المصدرية. إذا أردت المساهمة في مشروع مكتبة المحوّلات واختبار تعديلات الشيفرات البرمجية. لنبدأ أولًا باستنساخ مستودع المكتبة وتثبيتها كما يلي: git clone https://github.com/huggingface/transformers.git cd transformers pip install -e . ستعمل هذه الأوامر على وصل المجلد الذي استنسخت مستودع المكتبة ضمنه مع مسارات مكتبة بايثون التي تستخدمها، أي ستبحث بايثون عند تنفيذ الأوامر في هذا المجلد إضافةً إلى مجلدات المكتبة الاعتيادية التي تبحث فيها عادةً، فعلى سبيل المثال إذا كانت حزم بايثون مثبتة في المجلد /‎~/anaconda3/envs/main/lib/python3.7/site-packages فيجري البحث عن الأوامر ضمنه وضمن المجلد /‎~/transformers الذي استنسخت فيه المستودع. والآن حَدِّث ما استنسخته إلى أحدث إصدار من المكتبة وفق التالي: cd ~/transformers/ git pull ستكتشف البيئة الافتراضية لبايثون الإصدار الأساسي من المكتبة الذي ثبتناه وتبدأ بالتعامل معه بعد إعادة التشغيل. التثبيت باستخدام conda يمكنك تثبيت المكتبة باستخدام conda بدلًا من pip كما يلي: conda install conda-forge::transformers ضبط الذاكرة المخبئية Cache setup يُشير المتغير TRANSFORMERS_CACHE، وهو أحد متغيرات البيئة للصدفة shell، إلى المجلد المحلي الذي ستُخَزَّن فيه النماذج المدربة مسبقًا التي ستُحمِّلها، وفي الوضع الافتراضي يكون هذا المجلد هو ‎~/.cache/huggingface/hub في لينكس، ويكون C:\Users\username\.cache\huggingface\hub في ويندوز، لكن يمكنك تغييره بتعديل قيم متغيرات البيئة للصدفة shell الواردة أدناه مع مراعاة ترتيبها فهي مرتبة حسب الأولوية: المتغير HUGGINGFACE_HUB_CACHE أو TRANSFORMERS_CACHE. المتغير HF_HOME. المتغير XDG_CACHE_HOME + /huggingface. العمل من دون اتصال بالإنترنت Offline Mode يمكنك تشغيل مكتبة المحوّلات في بيئة محمية بجدار ناري أو غير متصلة بالإنترنت بالاعتماد على الملفات المخزنة محليًا على جهازك، وذلك بإعطاء القيمة "1" للمتغير TRANSFORMERS_OFFLINE. تستطيع أيضًا أن توفر لمشروعك مجموعات بيانات Datasets محلية لاستخدامها في التدريب من دون اتصال بالإنترنت عبر ضبط قيمة المتغير HF_DATASETS_OFFLINE=1. كما في المثال التالي: HF_DATASETS_OFFLINE=1 TRANSFORMERS_OFFLINE=1 \ python examples/pytorch/translation/run_translation.py --model_name_or_path google-t5/t5-small --dataset_name wmt16 --dataset_config ro-en ... سيعمل هذا السكربت بلا تأخير أو انتظار لأنه لن يحاول الاتصال بالإنترنت لتحميل النموذج من مستودع Hugging Face بل سيستخدم الملفات المحلية فقط. تستطيع أيضًا إيقاف تحميل النماذج من المستودع وتحميلها من المواقع المحلية فقط عن طريق ضبط قيمة المعامل local_files_only على True في كل مرة تستدعي فيها from_pretrained()‎ وفق التالي: from transformers import T5Model model = T5Model.from_pretrained("./path/to/local/directory", local_files_only=True) جلب النماذج والمُرمِزَّات لاستخدامها في حالة العمل دون اتصال بالإنترنت يُقصد بجلب fetch النماذج والمُرمِزَّات تحميلها مسبقًا من مستودعات المكتبة Transformers، وحفظها على جهازك، ثم استخدامها لاحقًا من دون اتصال بالإنترنت عبر الإشارة إلى مسارها المحلي عند كتابة التعليمات البرمجية، وذلك بثلاث طرق: الطريقة الأولى: حمّل الملفات التي تريدها من واجهة المستخدم لمستودع النماذج بالضغط على أيقونة السهم النازل الموجودة بجوار كل ملف كما في الصورة التالية: الطريقة الثانية: استخدم PreTrainedModel.from_pretrained()‎ و PreTrainedModel.save_pretrained()‎ وفق التسلسل التالي: 1. حمّل مسبقًا الملفات اللازمة لمشروعك بواسطة PreTrainedModel.from_pretrained()‎ كما يلي: >>> from transformers import AutoTokenizer, AutoModelForSeq2SeqLM >>> tokenizer = AutoTokenizer.from_pretrained("bigscience/T0_3B") >>> model = AutoModelForSeq2SeqLM.from_pretrained("bigscience/T0_3B") 2. احفظ ملفاتك في مجلد معين على حاسوبك باستخدام PreTrainedModel.save_pretrained()‎: >>> tokenizer.save_pretrained("./your/path/bigscience_t0") >>> model.save_pretrained("./your/path/bigscience_t0") 3. عندما تكون في وضع العمل من دون اتصال بالإنترنت أعد تحميل الملفات من المجلد الذي حفظته الملفات به بواسطة التعليمة PreTrainedModel.from_pretrained()‎: >>> tokenizer = AutoTokenizer.from_pretrained("./your/path/bigscience_t0") >>> model = AutoModel.from_pretrained("./your/path/bigscience_t0") الطريقة الثالثة: حمّل الملفات برمجيًا باستخدام مكتبة huggingface_hub كما يلي: 1. ثَبّت المكتبة huggingface_hub في بيئتك الافتراضية: python -m pip install huggingface_hub 2. استخدم الدالة hf_hub_download لتحميل الملف الذي تريده إلى المجلد المحلي المحدد، فالأمر التالي على سبيل المثال يُحَمِّل الملف config.json من النموذج "T0" إلى المجلد الذي تحدده: >>> from huggingface_hub import hf_hub_download >>> hf_hub_download(repo_id="bigscience/T0_3B", filename="config.json", cache_dir="./your/path/bigscience_t0") الآن بمجرد الانتهاء من تحميل ملفات النماذج وتخزينها محليًّا يصبح بإمكانك استخدامها عبر كتابة مسار المجلد الذي حفظت فيه ضمن التعليمات البرمجية كما في المثال التالي: >>> from transformers import AutoConfig >>> config = AutoConfig.from_pretrained("./your/path/bigscience_t0/config.json") ننهي عند هذه النقطة خطوات تثبيت المكتبة huggingface_hubوضبط إعداداتها، ولمزيد من التعمق ندعوك لمتابعة السلسلة وقراءة مقالنا التالي الذي سنتعرف فيه على طريقة استخدام خطوط الأنابيب pipeline لتبسيط التعامل مع نماذج الذكاء الاصطناعي التي توفرها Hugging Face. ترجمة -وبتصرف- لقسم Installation من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: جولة سريعة للبدء مع مكتبة المحوّلات Transformers من هو مهندس الذكاء الاصطناعي وما أبرز مهامه لغات برمجة الذكاء الاصطناعي مكتبات وأطر عمل الذكاء الاصطناعي: القوة الكامنة خلف الأنظمة الذكية
  17. إذا كنت مطوّرًا أو مستخدمًا دائمًا للذكاء الاصطناعي فجولتنا في مقال اليوم ستساعدك على الاستفادة من مكتبة المحولات Transformers، وتعرض لك آلية استخدام خطوط الأنابيب ‎‏pipeline()‎‏ في الاستدلال وتوقع معلومات جديدة inference، وكيفية تحميل نموذج مدرب مسبقًا ومعالج مدرب مسبقًا يناسبان مشروعك بواسطة الأصناف التلقائية Auto Classes، بالإضافة إلى طريقة تدريب النموذج بإطار عمل PyTorch أو TensorFlow. تأكد في البداية من تثبيت المكتبات التالية لتتابع معنا خطوات العمل: !pip install transformers datasets وثبت بعدها إطار عمل التعلُّم الآلي الذي تفضله. فإذا اخترت Pytorch اكتب السطر التالي لتثبيته: pip install torch وإذا كنت تفضل TensorFlow ثَبّته بكتابة ما يلي: pip install tensorflow خطوط الأنابيب Pipeline خط الأنابيب ‎‏pipeline()‎‏ هو أسهل وأسرع الطرق المتاحة لاستخدام نموذج تعلّم آلي مدرب مسبقًا في عملية الاستدلال، ويمكنك الاستفادة منه في مجالات متنوعة لتنفيذ مهام تتعلق بمعالجة اللغة الطبيعية Natural Language Processing أو الصوتيات Audio أو الرؤية الحاسوبية Computer Vision أو الأنماط المتعددة Modalities، ويبين الجدول التالي أبرزها: المهمة الوصف أسلوب المعالجة المُعرّف Pipeline identifier تصنيف نص وضع تسمية توضيحية label لجزء محدد من النص معالجة اللغة الطبيعية (NLP) pipeline(task=“sentiment-analysis”) توليد نص توليد نص بناءً على موجه promote معين يُعطى للنموذج معالجة اللغة الطبيعية (NLP) pipeline(task=“text-generation”) التلخيص إنشاء ملخص لجزء من نص أو مستند معالجة اللغة الطبيعية (NLP) pipeline(task=“summarization”) تصنيف الصور وضع تسمية توضيحية لصورة الرؤية الحاسوبية pipeline(task=“image-classification”) تجزئة الصور وضع تسمية توضيحية لكل جزء أو بيكسل من الصورة (يدعم التجزئة الدلالية للصور تجزئة المثيل) الرؤية الحاسوبية pipeline(task=“image-segmentation”) التعرّف على الكائنات التنبؤ بالمربعات المحيطة بالكائنات في صورة معينة وتصنيفها الرؤية الحاسوبية pipeline(task=“object-detection”) تصنيف الصوتيات وضع تسمية توضيحية للبيانات الصوتية صوتيات pipeline(task=“audio-classification”) التعرّف التلقائي على الكلام تحويل الكلام إلى نص مكتوب صوتيات pipeline(task=“automatic-speech-recognition”) الإجابة على الأسئلة مرئيًا الإجابة على سؤال حول الصورة، يُعطى النموذج سؤال وصورة أنماط متعددة Multimodal pipeline(task=“vqa”) الإجابة على الأسئلة المتعلقة بالمستندات الإجابة على سؤال حول المستند، يُعطى النموذج سؤال ومستند أنماط متعددة Multimodal pipeline(task=“document-question-answering”) عَنْوَنْة الصور إعطاء عنوان مناسب للصورة أنماط متعددة Multimodal pipeline(task=“image-to-text”) والآن بعد أن ثبتنا إطار العمل سننشئ مثيلًا instance لخط الأنابيب pipeline()‎ ونحدد المهمة التي نريد استخدامه من أجلها، سنستخدمه في هذا المقال لتحليل المشاعر "sentiment-analysis"، وذلك بكتابة الأوامر التالية: >>> from transformers import pipeline >>> classifier = pipeline("sentiment-analysis") بموجب التعليمات السابقة سيُحَمِّل خط الأنابيب‎ نموذج افتراضي مدرب مسبقًا pretrained model ومُرَمِّزْ tokenizer مناسبين لمهمة تحليل المشاعر، ويمكنك بعدها استخدام المُصَنِّف classifier الذي عرّفناه على النص الذي تود تحليل المشاعر ضمنه لتحصل على النتيجة، وفق التالي: >>> classifier("We are very happy to show you the ? Transformers library.") [{'label': 'POSITIVE', 'score': 0.9998}] إذا كان لديك أكثر من مُدْخَل input أي أكثر من نص، فمَرِرهم لخط الأنابيب pipeline()‎ بهيئة قائمة ليرجع لك قائمة بالقواميس dictionaries كما يلي: >>> results = classifier(["We are very happy to show you the ? Transformers library.", "We hope you don't hate it."]) >>> for result in results: print(f"label: {result['label']}, with score: {round(result['score'], 4)}") label: POSITIVE, with score: 0.9998 label: NEGATIVE, with score: 0.5309 يمكن لخط الأنابيب أيضًا التعامل مع مجموعة بيانات كاملة dataset بدلًا من بضع مدخلات فقط، كما في المثال التالي الذي يبين استخدام pipeline()‎ لمهمة التعرّف على الكلام "automatic-speech-recognition": >>> import torch >>> from transformers import pipeline >>> speech_recognizer = pipeline("automatic-speech-recognition", model="facebook/wav2vec2-base-960h") وسنُحمّل مجموعة بيانات صوتية audio dataset لنُطَبَّق عليها خط الأنابيب، لتكن مثلًا المجموعة MInDS-14 وفق التالي (يمكنك معرفة المزيد عن التعامل مع مجموعات البيانات بمراجعة القسم الخاص بها على منصة Hugging Face): >>> from datasets import load_dataset, Audio >>> dataset = load_dataset("PolyAI/minds14", name="en-US", split="train") عند التعامل مع الصوتيات ينبغي الانتباه لكون معدّل أخذ العينات sampling rate الخاص بمجموعة البيانات الصوتية MInDS-14 التي حملناها يطابق معدّل أخذ العينات الذي تَدرَّب عليه النموذج facebook/wav2vec2-base-960h وفق التالي: >>> dataset = dataset.cast_column("audio", Audio(sampling_rate=speech_recognizer.feature_extractor.sampling_rate)) الآن بمجرد استدعاء العمود "audio" وحسب التعليمات التالية ستُحَمَّلْ الملفات الصوتية من مجموعة البيانات ويُعاد أخذ العينات منها resampled تلقائيًا بما يتناسب مع معدّل أخذ العينات في النموذج، ثم ستُشكل مصفوفات الأشكال الموجية الأولية raw waveform arrays من العينات الأربع الأولى وتُمرر بهيئة قائمة إلى خط الأنابيب: >>> result = speech_recognizer(dataset[:4]["audio"]) >>> print([d["text"] for d in result]) ['I WOULD LIKE TO SET UP A JOINT ACCOUNT WITH MY PARTNER HOW DO I PROCEED WITH DOING THAT', "FONDERING HOW I'D SET UP A JOIN TO HELL T WITH MY WIFE AND WHERE THE AP MIGHT BE", "I I'D LIKE TOY SET UP A JOINT ACCOUNT WITH MY PARTNER I'M NOT SEEING THE OPTION TO DO IT ON THE APSO I CALLED IN TO GET SOME HELP CAN I JUST DO IT OVER THE PHONE WITH YOU AND GIVE YOU THE INFORMATION OR SHOULD I DO IT IN THE AP AN I'M MISSING SOMETHING UQUETTE HAD PREFERRED TO JUST DO IT OVER THE PHONE OF POSSIBLE THINGS", 'HOW DO I FURN A JOINA COUT'] أما عندما تتعامل مع مجموعات البيانات الكبيرة أي مع المدخلات الكبيرة (مثل التعامل بيانات الكلام speech أو الرؤية vision) فستحتاج مولدًا generator بدلًا من القائمة السابقة لتمرير البيانات إلى خطوط الأنابيب حتى تتحمل جميع المدخلات إلى الذاكرة. يمكنك معرفة المزيد عن الموضوع بالاطلاع على واجهة API لخطوط الأنابيب. تطبيق عملي ثاني باستخدام نموذج آخر ومُرَمِّز آخر تتكيف خطوط الأنابيب مع أي نموذج موجود في مستودع Hugging Face، يعطيك هذا مرونةً كبيرة في حالات الاستخدام المختلفة، لنفترض مثلًا أنك ترغب بتحليل المشاعر في نصوص مكتوبة باللغة الفرنسية، فيمكنك عندها استخدام الوسوم وفلاتر التصفية الموجودة في المستودع لتصل إلى النموذج المناسب لاحتياجك، فإذا جربت البحث عن نماذج تدعم اللغة الفرنسية سيكون نموذج BERT model المتعدد اللغات أحد الخيارات واسمه الدقيق هو: >>> model_name = "nlptown/bert-base-multilingual-uncased-sentiment" إذا كنت تعتمد إطار العمل Pytorch، فاستخدم الصنف التلقائي AutoModelForSequenceClassification الذي يناسب تصنيف النصوص، والمُرمِّز التلقائي AutoTokenizer من أجل تحميل النموذج المدرب مسبقًا الذي حددناه والمُرمِّز المرتبط به وفق التالي: >>> from transformers import AutoTokenizer, AutoModelForSequenceClassification >>> model = AutoModelForSequenceClassification.from_pretrained(model_name) >>> tokenizer = AutoTokenizer.from_pretrained(model_name) أما إذا كنت تعتمد الإطار TensorFlow، فإن الصنف التلقائي الخاص بتحميل النموذج عندها سيكون TFAutoModelForSequenceClassification والمُرمِّز المناسب هو AutoTokenizer كما يلي: >>> from transformers import AutoTokenizer, TFAutoModelForSequenceClassification >>> model = TFAutoModelForSequenceClassification.from_pretrained(model_name) >>> tokenizer = AutoTokenizer.from_pretrained(model_name) والآن لنطبق المُصَنِف classifier على النص الذي نود تحليل المشاعر ضمنه بعد كتابة النموذج والمُرمِّز اللذين اخترناهما ضمن محددات خط الأنابيب ()pipeline وفق التالي: >>> classifier = pipeline("sentiment-analysis", model=model, tokenizer=tokenizer) >>> classifier("Nous sommes très heureux de vous présenter la bibliothèque ? Transformers.") [{'label': '5 stars', 'score': 0.7273}] إذا لم تجد نموذجًا جاهزًا يناسب مشروعك في مستودع المنصة فينبغي لك إعادة تدريب أحد النماذج المدربة مسبقًا على بياناتك، يمكنك الاطلاع على مقال [تدريب نموذج مُعدّ مسبقًا على بيانات محددة]() من هذه السلسلة لمساعدتك بالمهمة، وتستطيع بعدها مشاركة النموذج على منصة Hagging Face باتباع الخطوات الواردة في مقال [مشاركة النماذج على منصة Hagging Face](). الصنف التلقائي AutoClass الأصناف التلقائية في حقيقة الأمر هي صاحبة الدور الرئيسي في تشغيل خطوط الأنابيب ()pipeline كما في مثالنا السابق عندما استخدمنا الصنفين التلقائيين AutoModelForSequenceClassification و AutoTokenizer، وإذا أردنا تعريف الصنف التلقائي AutoClass فهو اختصار يُرجع للمستخدم بنية النموذج الذي زوده باسمه أو مساره تلقائيًا، لذا فكل ما عليك فعله هو اختيار الصنف التلقائي AutoClass وصنف المعالج المُسبق preprocessing class المناسبين لمشروعك. لنرجع للمثال السابق ونحاول استخدام Autocalss للحصول على النتائج من خطوط الأنابيب. المُرمِّز التلقائي AutoTokenizer المُرمِّز هو المسؤول عن المعالجة التحضيرية للنص ليتحول إلى مصفوفة من الأعداد تكون بمثابة المدخلات للنموذج. وتخضع عملية الترميز لمجموعة قواعد مثل كيفية تقسيم split الكلمة وعلى أي مستوى تُقسّم الكلمات وغير ذلك (يمكنك معرفة المزيد عن الموضوع بمطالعة ملخص المُرمِّزات)، وتذكر دائمًا أن عليك إنشاء مثيل للمُرمِّز باسم النموذج نفسه للتأكد أنك تستخدم قواعد الترميز نفسها التي تدرب عليها النموذج مسبقًا. يتضمن الأمر التالي طريقة تحميل المُرَمِّز باستخدام AutoTokenizer: >>> from transformers import AutoTokenizer >>> model_name = "nlptown/bert-base-multilingual-uncased-sentiment" >>> tokenizer = AutoTokenizer.from_pretrained(model_name) والآن يمكنك تمرير النص الذي تريد ترميزه للمُرَمِّز وفق التالي: >>> encoding = tokenizer("We are very happy to show you the ? Transformers library.") >>> print(encoding) {'input_ids': [101, 11312, 10320, 12495, 19308, 10114, 11391, 10855, 10103, 100, 58263, 13299, 119, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]} يُرجع المُرَمِّز قاموسًا يتضمن: input_ids: تمثيلات عددية للرموز tokens. attention_mask: تبين أي الرموز تقابل أجزاء النص المهمة التي ينبغي الانتباه لها والأخذ بها وأيُّها لا. يتيح المُرَمِّز أيضًا إمكانية التعامل مع قائمة بالمدخلات inputs بدلًا من مدخل واحد، وإجراء عمليات الحشو والاقتطاع لزيادة أو إنقاص طول السلاسل النصية المدخلة للوصول إلى دفعات batches أو قطع بطول موحد. وذلك وفق التالي في Pytorch: pt_batch = tokenizer( ["We are very happy to show you the ? Transformers library.", "We hope you don't hate it."], padding=True, truncation=True, max_length=512, return_tensors="pt", ) وفي TensorFlow: tf_batch = tokenizer( ["We are very happy to show you the ? Transformers library.", "We hope you don't hate it."], padding=True, truncation=True, max_length=512, return_tensors="tf", ) النموذج التلقائي AutoModel توفر مكتبة المحولات Transformers طريقةً سهلة وموحدة لتحميل مثيلات النماذج المدربة مسبقًا، تشبه طريقة استخدام AutoTokenizer الذي تعاملنا معه سابقًا لكن عليك هنا تحديد AutoModel المناسب للمهمة التي تنفذها، مثل AutoModelForSequenceClassification الملائم لتصنيف النصوص في إطار العمل Pytorch: >>> from transformers import AutoModelForSequenceClassification >>> model_name = "nlptown/bert-base-multilingual-uncased-sentiment" >>> pt_model = AutoModelForSequenceClassification.from_pretrained(model_name) لنمرر الآن قاموس الدفعات أو قطع المدخلات pt_batch التي عالجناها قبل قليل إلى النموذج التلقائي AutoModel لكن بعد فك ضغطه unpack بإضافة رمز النجمتين ** وفق التالي: >>> pt_outputs = pt_model(**pt_batch) يضع النموذج المخرجات النهائية التي تنتج بعد كل التنشيطات activations في السمة logits، ثم نطبق الدالة softmax على السمة logits للحصول على الاحتمالات المتنبأ بها وفق التالي: >>> from torch import nn >>> pt_predictions = nn.functional.softmax(pt_outputs.logits, dim=-1) >>> print(pt_predictions) tensor([[0.0021, 0.0018, 0.0115, 0.2121, 0.7725], [0.2084, 0.1826, 0.1969, 0.1755, 0.2365]], grad_fn=<SoftmaxBackward0>) أما في حالة استخدامك لإطار العمل TensorFlow فإن النموذج التلقائي سيُسمى عندها TFAutoModel ويمكنك استخدامه بالطريقة نفسها التي تُحمّل بها AutoTokenizer، وأيضًا عليك هنا تحديد النموذج التلقائي TFAutoModel المناسب لمشروعك، في مثالنا سنستخدم TFAutoModelForSequenceClassification لأنه مخصص لتصنيف النصوص: >>> from transformers import TFAutoModelForSequenceClassification >>> model_name = "nlptown/bert-base-multilingual-uncased-sentiment" >>> tf_model = TFAutoModelForSequenceClassification.from_pretrained(model_name) مرر الآن مصفوفة tensors التي تتضمن قطع المدخلات التي عالجناها سابقًا إلى النموذج كما هي (أي بدون الرمز ** مثل ما فعلنا في تعليمات Pytorch): >>> tf_outputs = tf_model(tf_batch) ثم نطبق الدالة softmax على مخرجات النموذج النهائية الموجودة في السمة logits وفق التالي: >>> import tensorflow as tf >>> tf_predictions = tf.nn.softmax(tf_outputs.logits, axis=-1) >>> tf_predictions حفظ النموذج يمكنك حفظ النموذج مع المُرَمِّز الخاص به بعد الانتهاء من تدريبه على بيانات مشروعك باستخدام PreTrainedModel.save_pretrained()‎ في إطار العمل Pytorch وفق التالي: >>> pt_save_directory = "./pt_save_pretrained" >>> tokenizer.save_pretrained(pt_save_directory) >>> pt_model.save_pretrained(pt_save_directory) وعندما تحتاجه مجددًا تستطيع تحميله بواسطة PreTrainedModel.from_pretrained()‎ كما يلي: >>> pt_model = AutoModelForSequenceClassification.from_pretrained("./pt_save_pretrained") أما في إطار العمل TensorFlow فيمكنك حفظ النموذج باستخدام TFPreTrainedModel.save_pretrained()‎: >>> tf_save_directory = "./tf_save_pretrained" >>> tokenizer.save_pretrained(tf_save_directory) >>> tf_model.save_pretrained(tf_save_directory) وعندما تريد استخدامه ثانيةً استعمل TFPreTrainedModel.from_pretrained()‎ وفق التالي: >>> tf_model = TFAutoModelForSequenceClassification.from_pretrained("./tf_save_pretrained") تُعدّ ميزة تحويل النماذج من PyTorch إلى TensorFlow وبالعكس واحدة من أبرز مميزات المكتبة Transormers، وذلك باستخدام المعاملين from_pt و from_tf فيمكنك حفظ النموذج ثم تحميله بالصيغة المناسبة لإطار العمل الذي تفضله، وهذا مثال عملي: أولًا إطار العمل PyTorch: >>> from transformers import AutoModel >>> tokenizer = AutoTokenizer.from_pretrained(tf_save_directory) >>> pt_model = AutoModelForSequenceClassification.from_pretrained(tf_save_directory, from_tf=True) ثانيًا إطار العمل TensorFlow: >>> from transformers import TFAutoModel >>> tokenizer = AutoTokenizer.from_pretrained(pt_save_directory) >>> tf_model = TFAutoModelForSequenceClassification.from_pretrained(pt_save_directory, from_pt=True) بناء نموذج تعلّم آلي مخصص يمكنك بناء نموذج مخصص لحالتك بتعديل صنف إعدادات النموذج configuration class وتحديد السمات التي تريدها، مثل: عدد الطبقات المخفية hidden layers ورؤوس الانتباه attention heads، فعندما تبني نموذجك من الصفر استنادًا إلى صنف إعدادات مخصص فإن سمات النموذج ستأخذ في البداية محددات عشوائية ويمكنك ضبطها فيما وتحقيق الاستفادة المتوقعة منه بعد بتدريب النموذج على البيانات المناسبة لمشروعك. لنبدأ بالتطبيق العملي: سنستدعي أولًا الصنف AutoConfig ثم نُحمّل النموذج المُعدّ مسبقًا الذي نريد تخصيصه حسب حالتنا، ونذكر السمة التي نود تعديلها ضمن الدالة AutoConfig.from_pretrained()‎ كما في المثال التالي الذي يبين طريقة تغيير سمة رؤوس الانتباه: >>> from transformers import AutoConfig >>> my_config = AutoConfig.from_pretrained("distilbert/distilbert-base-uncased", n_heads=12) والخطوة التالية هي بناء النموذج انطلاقًا من الإعدادات المخصصة التي ضبطناها أعلاه وباستخدام AutoModel.from_config()‎ في Pytorch، و TFAutoModel.from_config()‎ في TensorFlow. إذا كنت تستخدم إطار العمل Pytorch فيمكنك تنفيذها وفق التالي: >>> from transformers import AutoModel >>> my_model = AutoModel.from_config(my_config) وإذا كنت تعتمد TensorFlow وفق التالي: >>> from transformers import TFAutoModel >>> my_model = TFAutoModel.from_config(my_config) المُدَرِّبْ Trainer- حلقة التدريب المحسنة في PyTorch جميع نماذج مكتبة المحولات Transformers المتوافقة مع PyTorch هي نماذج torch.nn.Module قياسية، يمكنك استخدامها في أي حلقة تدريب training loop نموذجية تريدها؛ يمكنك أيضًا برمجة حلقة تدريبك الخاصة وفق متطلبات عملك، ومع ذلك توفر لك المكتبة صنفًا خاصًا بتدريب حلقات PyTorch يدعى صنف المُدَرِّب Trainer class ويتضمن حلقة التدريب الاعتيادية ووظائف إضافية أخرى مثل: التدريب الموزع distributed training والتدريب مختلط الدقة mixed precision وغيرها. وفي أثناء العمل ستمرر للمُدَرِّب عدة وسطاء حسب احتياجات مشروعك، لنبدأ بالخطوات العملية: 1. حمّل في البداية نموذجًا قياسيًا: >>> from transformers import AutoModelForSequenceClassification >>> model = AutoModelForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased") 2. حَدِّدْ قيم وسطاء التدريب مثل: معدّل التدريب learning rate، والحجم الموحد لقطع المدخلات التي يعالجها النموذج دفعة واحدة batch size، وعدد دورات التدريب number of epochs أي عدد تكرارات مجموعة البيانات التي سيتدرب عليها النموذج، وإن لم تحدد قيمًّا للوسطاء فستُستخدم القيم الافتراضية: >>> from transformers import TrainingArguments >>> training_args = TrainingArguments( output_dir="path/to/save/folder/", learning_rate=2e-5, per_device_train_batch_size=8, per_device_eval_batch_size=8, num_train_epochs=2, ) 3. حَدِّدْ صنف المعالجة المسبقة الذي تحتاجه، مثل: المُرمِّز tokenizer أو معالج الصور mage processor أو مستخرج المميزات feature extractor أو المعالج processor: >>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased") 4. حمّل مجموعة البيانات dataset المناسبة: >>> from datasets import load_dataset >>> dataset = load_dataset("rotten_tomatoes") # doctest: +IGNORE_RESULT 5. أنشئ دالة لترميز مجموعة البيانات: >>> def tokenize_dataset(dataset): return tokenizer(dataset["text"]) ثم طبّقها على كامل مجموعة البيانات باستعمال map وفق التالي: >>> dataset = dataset.map(tokenize_dataset, batched=True) 6. استخدم DataCollatorWithPadding لإنشاء قطع من الأمثلة من مجموعة البيانات: >>> from transformers import DataCollatorWithPadding >>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer) والآن اجمع كل هذه الأصناف في شيفرة المُدَرِّب trainer كما يلي: >>> from transformers import Trainer >>> trainer = Trainer( model=model, args=training_args, train_dataset=dataset["train"], eval_dataset=dataset["test"], tokenizer=tokenizer, data_collator=data_collator, ) # doctest: +SKIP وبعد ذلك يمكنك استدعاء المُدَرِّب train()‎ ليبدأ عملية التدريب وفق التالي: >>> trainer.train() يمكنك التحكم بسلوك حلقة التدريب بطريقتين: أولًا عبر إنشاء أصناف فرعية subclassing لمنهجيات التدريب المضمنة داخل المُدَرِّب Trainer؛ يساعدك ذلك على تخصيص ميزات مثل: دالة الخسارة loss function، والمُحَسِّن optimizer، والمُجَدّوِل scheduler حسب متطلبات عملك، يمكنك الاطلاع على قسم المُدَرِّب من توثيقات Hugging Face لمزيد من المعلومات عن منهجيات التدريب القابلة للتصنيف الفرعي subclassing. وثانيًا باستخدام الاستدعاءات Callbacks لتحقيق التكامل مع المكتبات الأخرى ولتفحص عمل حلقة التدريب ومتابعة تقدمها أو إيقاف التدريب في مرحلة معينة، مع العلم أن الاستدعاءات لا تتيح لك إجراء أي تعديل على بنية الحلقة لتخصيص ميزات مثل دالة الخسارة أو غيره فمثل هذه الأعمال محصورة فقط بالطريقة الأولى أي بإنشاء الأصناف الفرعية. تدريب نموذج في TensorFlow جميع نماذج المكتبة المتوافقة مع TensorFlow هي نماذج tf.keras.Model قياسية، يمكنك تدريبها باستخدام واجهة برمجة التطبيقات Keras API، وتوفر مكتبة المحولات منهجيةً تدعى prepare_tf_dataset()‎ تسهل عليك تحميل مجموعات البيانات التي ستعتمدها بصيغة tf.data.Dataset والشروع بتدريبها باستخدام منهجيات Keras مثل compile و fit، لنبدأ بالتطبيق العملي: 1. حمّل نموذجًا قياسيًا: >>> from transformers import TFAutoModelForSequenceClassification >>> model = TFAutoModelForSequenceClassification.from_pretrained("distilbert/distilbert-base-uncased") 2. اختر صنف المعالجة المسبقة الذي تحتاجه، مثل: المُرمِّز tokenizer أو معالج الصور mage processor أو مستخرج المميزات feature extractor أو المعالج processor: >>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased") 3. أنشئ دالة لترميز مجموعة البيانات: >>> def tokenize_dataset(dataset): return tokenizer(dataset["text"]) # doctest: +SKIP طبّق الترميز على كامل مجموعة البيانات باستعمال map، ثم مرر المُرَمِّز ومجموعة البيانات إلى prepare_tf_dataset()‎ وفق التالي، ويمكنك في هذه المرحلة تغيير حجم الدفعات أو قطع المدخلات batch size أو خلط بيانات مجموعة البيانات إذا رغبت بذلك: >>> dataset = dataset.map(tokenize_dataset) # doctest: +SKIP >>> tf_dataset = model.prepare_tf_dataset( dataset["train"], batch_size=16, shuffle=True, tokenizer=tokenizer ) # doctest: +SKIP استدعِ compile و fit لبدء عملية التدريب، وننوه هنا إلى أن جميع نماذج مكتبة المحولات تتضمن دالة افتراضية لحساب الخسارة تتعلق بطبيعة المهمة التي تعمل عليها، يمكنك الاعتماد عليها افتراضيًا إلّا إذا رغبت بعكس ذلك: >>> from tensorflow.keras.optimizers import Adam >>> model.compile(optimizer=Adam(3e-5)) # No loss argument! >>> model.fit(tf_dataset) # doctest: +SKIP الخلاصة وصلنا إلى ختام جولتنا السريعة في مكتبة Transformers، تابع مقالنا القادم تثبيت مكتبة المحولات Transformers لتتعلم كيفية تثبيتها والتعامل معها باستخدام كل من PyTorch و TensorFlow و Flax. ترجمة -وبتصرف- لقسم Quick tour من توثيقات Hugging Face. اقرأ أيضًا المقال السابق: تعرف على مكتبة المحوّلات Transformers من منصة Hugging Face تعرف على أفضل دورات الذكاء الاصطناعي تعرف على إطار عمل باي تورش PyTorch وأهميته لتطبيقات الذكاء الاصطناعي أساسيات الذكاء الاصطناعي: دليل المبتدئين
  18. سنتعرف في هذه السلسلة من المقالات على منصة Hugging Face وهي منصة تفاعلية سهلة الاستخدام للمهتمين بإنشاء تطبيقات الذكاء الاصطناعي وتعلم الآلة، فهي توفر أكثر من 400 ألف نموذج جاهز للاستخدام وتوفر مجموعات بيانات مخصصة لتدريب نماذج جديدة، كما أنها تتيح لك التواصل مع مجتمع ضخم مع المهتمين بتعلم الآلة من جميع أنحاء العالم ومشاركة تجاربك معهم. سنبدأ السلسلة بالتعرف على أداة برمجية فعالة تعمل على هذه المنصة وهي المكتبة Transformers التي تسهل استخدام نماذج تعلم الآلة الحديثة وتمكنك من أداء عدة مهام متعلقة بالذكاء الاصطناعي، ونتعرف على النماذج المتنوعة التي توفرها هذه المكتبة للتعامل مع النصوص والصور والصوت والوسائط المتعددة كما نستعرض مختلف إطارات العمل البرمجية التي تدعمها وأهم تطبيقاتها. ما هي المكتبة Transformers مكتبة المحوّلات Transformers هي أحدث تقنيات تعلُّم الآلة المستخدمة مع أطر عمل الذكاء الاصطناعي الشهيرة مثل باي تورش PyTorch وتنسرفلو TensorFlow و JAX، وهي تزود المبرمجين بواجهات برمجة تطبيقات APIs وأدوات مساعدة تُسهّل عليهم تحميل أحدث نماذج تعلم الآلة المدربة مسبقًا pretrained models وإعادة تدريبها. وتوفر هذه النماذج المدربة مسبقًا وقتك وجهدك فلن تحتاج لجمع البيانات، وتنظيفها، وتحضيرها، ولا لتشغيل عمليات التدريب والتحسين بل يمكنك استخدام النموذج مباشرة في تطبيقك، كما توفر أيضًا الموارد وعمليات الحوسبة وحتى استهلاك الطاقة الذي تحتاجه لتدريب نماذج جديدة من الصفر، وتخدمك في العديد من مجالات الذكاء الاصطناعي وإليك أهما: مجال معالجة اللغة الطبيعية Natural Language Processing: ومن أهم تطبيقاته تصنيف النصوص text classification، والتعرّف على الكائنات المسماة named entity recognition، والإجابة على الأسئلة question answering، والاختيار من متعدد multiple choice، ونمذجة اللغة language modeling، والتلخيص summarization، والترجمة translation، وتوليد النص text generation. مجال الرؤية الحاسوبية Computer Vision: تستخدم الرؤية الحاسوبية في مشاريع عديدة مثل: تصنيف الصور image classification، والتعرّف على الكائنات object detection، وتجزئة الصور segmentation بناءً على خصائص محددة وغير ذلك. مجال الصوتيات Audio: ومن أهم تطبيقاته التعرّف التلقائي على الكلام automatic speech recognition، وتصنيف المقاطع الصوتية audio classification. مجال الأنماط المتعددة Multimodal: يقصد به التعامل مع أنواع متعددة من المُدخَلات ومن أمثلتها الإجابة على الأسئلة الموجودة ضمن جدول معين table question answering، والتعرّف البصري على الحروف optical character recognition، واستخراج المعلومات من المستندات الممسوحة ضوئيًا، وتصنيف مقاطع الفيديو video classification، والإجابة على الأسئلة مرئيًا visual question answering أي الإجابة على أسئلة حول الصور. وتدعم مكتبة المحولات التشغيل البيني framework interoperability لأطر العمل الثلاثة PyTorch و TensorFlow و JAX أي أن بإمكانك جمعها في مشروع واحد بمرونة تامة، فهي تتيح لك استخدام إطار عمل مختلف في كل مرحلة من مراحل بناء النموذج؛ تستطيع مثلًا تدريب النموذج بإطار عمل معين، ثم استخدام إطار آخر في مرحلة الاستدلال inference وهكذا، يمكنك أيضًا تصدير نماذج الآلي بصيغ مثل: ONNX و TorchScript لنشرها في بيئات الإنتاج. النماذج التي يدعمها كل إطار عمل يبين الجدول التالي نماذج المكتبة التي يدعمها كل إطار عمل من الأطر التالية PyTorch و TensorFlow و JAX حتى تاريخ ترجمة هذا المقال، سواء كانت مميزة بمُرمِز tokenizer بايثون بطيء"slow" أو سريع "fast". النموذج توافقيته مع PyTorch؟ توافقيته مع TensorFlow؟ توافقيته مع JAX؟ ALBERT نعم نعم نعم ALIGN نعم لا لا AltCLIP نعم لا لا Audio Spectrogram Transformer نعم لا لا Autoformer نعم لا لا Bark نعم لا لا BART نعم نعم نعم BARThez نعم نعم نعم BARTpho نعم نعم نعم BEiT نعم لا نعم BERT نعم نعم نعم Bert Generation نعم لا لا BertJapanese نعم نعم نعم BERTweet نعم نعم نعم BigBird نعم لا نعم BigBird-Pegasus نعم لا لا BioGpt نعم لا لا BiT نعم لا لا Blenderbot نعم نعم نعم BlenderbotSmall نعم نعم نعم BLIP نعم نعم لا BLIP-2 نعم لا لا BLOOM نعم لا نعم BORT نعم نعم نعم BridgeTower نعم لا لا BROS نعم لا لا ByT5 نعم نعم نعم CamemBERT نعم نعم لا CANINE نعم لا لا Chinese-CLIP نعم لا لا CLAP نعم لا لا CLIP نعم نعم نعم CLIPSeg نعم لا لا CLVP نعم لا لا CodeGen نعم لا لا CodeLlama نعم لا نعم Conditional DETR نعم لا لا ConvBERT نعم نعم لا ConvNeXT نعم نعم لا ConvNeXTV2 نعم نعم لا CPM نعم نعم نعم CPM-Ant نعم لا لا CTRL نعم نعم لا CvT نعم نعم لا Data2VecAudio نعم لا لا Data2VecText نعم لا لا Data2VecVision نعم نعم لا DeBERTa نعم نعم لا DeBERTa-v2 نعم نعم لا Decision Transformer نعم لا لا Deformable DETR نعم لا لا DeiT نعم نعم لا DePlot نعم لا لا Depth Anything نعم لا لا DETA نعم لا لا DETR نعم لا لا DialoGPT نعم نعم نعم DiNAT نعم لا لا DINOv2 نعم لا لا DistilBERT نعم نعم نعم DiT نعم لا نعم DonutSwin نعم لا لا DPR نعم نعم لا DPT نعم لا لا EfficientFormer نعم نعم لا EfficientNet نعم لا لا ELECTRA نعم نعم نعم EnCodec نعم لا لا Encoder decoder نعم نعم نعم ERNIE نعم لا لا ErnieM نعم لا لا ESM نعم نعم لا FairSeq Machine-Translation نعم لا لا Falcon نعم لا لا FastSpeech2Conformer نعم لا لا FLAN-T5 نعم نعم نعم FLAN-UL2 نعم نعم نعم FlauBERT نعم نعم لا FLAVA نعم لا لا FNet نعم لا لا FocalNet نعم لا لا Funnel Transformer نعم نعم لا Fuyu نعم لا لا Gemma نعم لا نعم GIT نعم لا لا GLPN نعم لا لا GPT Neo نعم لا نعم GPT NeoX نعم لا لا GPT NeoX Japanese نعم لا لا GPT-J نعم نعم نعم GPT-Sw3 نعم نعم نعم GPTBigCode نعم لا لا GPTSAN-japanese نعم لا لا Graphormer نعم لا لا GroupViT نعم نعم لا HerBERT نعم نعم نعم Hubert نعم نعم لا I-BERT نعم لا لا IDEFICS نعم لا لا ImageGPT نعم لا لا Informer نعم لا لا InstructBLIP نعم لا لا Jukebox نعم لا لا KOSMOS-2 نعم لا لا LayoutLM نعم نعم لا LayoutLMv2 نعم لا لا LayoutLMv3 نعم نعم لا LayoutXLM نعم لا لا LED نعم نعم لا LeViT نعم لا لا LiLT نعم لا لا LLaMA نعم لا نعم Llama2 نعم لا نعم LLaVa نعم لا لا Longformer نعم نعم لا LongT5 نعم لا نعم LUKE نعم لا لا LXMERT نعم نعم لا M-CTC-T نعم لا لا M2M100 نعم لا لا MADLAD-400 نعم نعم نعم Marian نعم نعم نعم MarkupLM نعم لا لا Mask2Former نعم لا لا MaskFormer نعم لا لا MatCha نعم لا لا mBART نعم نعم نعم mBART-50 نعم نعم نعم MEGA نعم لا لا Megatron-BERT نعم لا لا Megatron-GPT2 نعم نعم نعم MGP-STR نعم لا لا Mistral نعم لا نعم Mixtral نعم لا لا mLUKE نعم لا لا MMS نعم نعم نعم MobileBERT نعم نعم لا MobileNetV1 نعم لا لا MobileNetV2 نعم لا لا MobileViT نعم نعم لا MobileViTV2 نعم لا لا MPNet نعم نعم لا MPT نعم لا لا MRA نعم لا لا MT5 نعم نعم نعم MusicGen نعم لا لا MVP نعم لا لا NAT نعم لا لا Nezha نعم لا لا NLLB نعم لا لا NLLB-MOE نعم لا لا Nougat نعم نعم نعم Nyströmformer نعم لا لا OneFormer نعم لا لا OpenAI GPT نعم نعم لا OpenAI GPT-2 نعم نعم نعم OpenLlama نعم نعم لا OPT نعم نعم نعم OWL-ViT نعم لا لا OWLv2 نعم لا لا PatchTSMixer نعم لا لا PatchTST نعم لا لا Pegasus نعم نعم نعم PEGASUS-X نعم لا لا Perceiver نعم لا لا Persimmon نعم لا لا Phi نعم لا لا PhoBERT نعم نعم نعم Pix2Struct نعم لا لا PLBart نعم لا لا PoolFormer نعم لا لا Pop2Piano نعم لا لا ProphetNet نعم لا لا PVT نعم لا لا QDQBert نعم لا لا Qwen2 نعم لا لا RAG نعم نعم لا REALM نعم لا لا Reformer نعم لا لا RegNet نعم نعم نعم RemBERT نعم نعم لا ResNet نعم نعم نعم RetriBERT نعم لا لا RoBERTa نعم نعم نعم RoBERTa-PreLayerNorm نعم نعم نعم RoCBert نعم لا لا RoFormer نعم نعم نعم RWKV نعم لا لا SAM نعم نعم لا SeamlessM4T نعم لا لا SeamlessM4Tv2 نعم لا لا SegFormer نعم نعم لا SEW نعم لا لا SEW-D نعم لا لا SigLIP نعم لا لا Speech Encoder decoder نعم لا نعم Speech2Text نعم نعم لا SpeechT5 نعم لا لا Splinter نعم لا لا SqueezeBERT نعم لا لا StableLm نعم لا لا SwiftFormer نعم لا لا Swin Transformer نعم نعم لا Swin Transformer V2 نعم لا لا Swin2SR نعم لا لا SwitchTransformers نعم لا لا T5 نعم نعم نعم T5v1.1 نعم نعم نعم Table Transformer نعم لا لا TAPAS نعم نعم لا TAPEX نعم نعم نعم Time Series Transformer نعم لا لا TimeSformer نعم لا لا Trajectory Transformer نعم لا لا Transformer-XL نعم نعم لا TrOCR نعم لا لا TVLT نعم لا لا TVP نعم لا لا UL2 نعم نعم نعم UMT5 نعم لا لا UniSpeech نعم لا لا UniSpeechSat نعم لا لا UnivNet نعم لا لا UPerNet نعم لا لا VAN نعم لا لا VideoMAE نعم لا لا ViLT نعم لا لا VipLlava نعم لا لا Vision Encoder decoder نعم نعم نعم VisionTextDualEncoder نعم نعم نعم VisualBERT نعم لا لا ViT نعم نعم نعم ViT Hybrid نعم لا لا VitDet نعم لا لا ViTMAE نعم نعم لا ViTMatte نعم لا لا ViTMSN نعم لا لا VITS نعم لا لا ViViT نعم لا لا Wav2Vec2 نعم نعم نعم Wav2Vec2-BERT نعم لا لا Wav2Vec2-Conformer نعم لا لا Wav2Vec2Phoneme نعم نعم نعم WavLM نعم لا لا Whisper نعم نعم نعم X-CLIP نعم لا لا X-MOD نعم لا لا XGLM نعم نعم نعم XLM نعم نعم لا XLM-ProphetNet نعم لا لا XLM-RoBERTa نعم نعم نعم XLM-RoBERTa-XL نعم لا لا XLM-V نعم نعم نعم XLNet نعم نعم لا XLS-R نعم نعم نعم XLSR-Wav2Vec2 نعم نعم نعم YOLOS نعم لا لا YOSO نعم لا لا الخلاصة تعرفنا في مقال اليوم على منصة Hugging Face التفاعلية التي تقدم نماذج مدربة جاهزة ومجموعات بيانات للتدريب تسرع عملية تطوير تطبيقات الذكاء الاصطناعي وتعلم الآلة وتعرفنا على المجالات المختلفة التي يمكن تطبيق الذكاء الاصطناعي فيها باستخدام هذه المكتبة كما استعرضنا أطر العمل المختلفة التي توفرها لبناء النماذج. ترجمة -وبتصرف- لقسم Transformers من توثيقات Hugging Face. اقرأ أيضًا مكتبات وأطر عمل الذكاء الاصطناعي: القوة الكامنة خلف الأنظمة الذكية تلخيص النصوص باستخدام الذكاء الاصطناعي أسئلة شائعة حول الذكاء الاصطناعي استخدام النماذج التوليديّة Generative models لتوليد الصور
×
×
  • أضف...