دليل شامل: فهم وتطبيق نموذج Google BERT في معالجة اللغة الطبيعية

دقائق القراءة: 11

دليل شامل: فهم وتطبيق نموذج Google BERT في معالجة اللغة الطبيعية

تُعد تطبيقات التعلم الآلي واسعة ومتنوعة، ومن أبرزها مجال معالجة اللغة الطبيعية (NLP). يتعامل NLP مع مهام حيوية مثل فهم سياق الكلمات، وتوليد الاستجابات النصية، وإجراء المحادثات التفاعلية. إنه الجسر الذي يمكّن أجهزة الكمبيوتر من فهم اللغة البشرية، مما يفتح آفاقًا جديدة للتواصل بين الإنسان والآلة.

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

لقد أصبح NLP جزءًا لا يتجزأ من التعلم الآلي لعدة أسباب رئيسية. فهو يساعد الآلات على اكتشاف المشاعر في ملاحظات العملاء، ويمكنه فرز تذاكر الدعم للمشاريع المختلفة، ولديه القدرة على قراءة النصوص وفهمها باتساق عالٍ. وبما أنه يعمل وفقًا لمجموعة من القواعد اللغوية، فإنه يتجنب التحيزات البشرية المحتملة.

نظرًا لاتساع مجال NLP، تتوفر العديد من الأدوات والأساليب لتحليل البيانات لأغراض محددة. أحد هذه الأساليب هو النهج القائم على القواعد، حيث يتم إعداد العديد من عبارات if-then للتعامل مع تفسير النص. عادةً ما يكون اللغويون مسؤولين عن هذه المهمة، وتكون مخرجاتهم سهلة الفهم للبشر. قد يكون هذا النهج جيدًا للبدء، ولكنه يصبح معقدًا للغاية عند التعامل مع مجموعات بيانات كبيرة.

هناك نهج آخر وهو استخدام التعلم الآلي، حيث لا تحتاج إلى تحديد القواعد يدويًا. هذا النهج مثالي عندما تحاول تحليل كميات كبيرة من البيانات بسرعة ودقة. يعد اختيار الخوارزمية الصحيحة أمرًا بالغ الأهمية لضمان كفاءة ودقة نهج التعلم الآلي. توجد خوارزميات شائعة مثل Naïve Bayes و Support Vector Machines، بالإضافة إلى خوارزميات أكثر تخصصًا مثل Google BERT.

ما هو نموذج Google BERT؟

BERT هي مكتبة مفتوحة المصدر تم تطويرها في عام 2018 بواسطة Google. إنها تقنية جديدة لمعالجة اللغة الطبيعية (NLP) وتتبنى نهجًا مختلفًا تمامًا لتدريب النماذج مقارنة بالتقنيات الأخرى. BERT هو اختصار لـ Bidirectional Encoder Representations from Transformers (تمثيلات المشفّر ثنائي الاتجاه من المحوّلات). وهذا يعني أنه على عكس معظم التقنيات التي تحلل الجمل من اليسار إلى اليمين أو من اليمين إلى اليسار، فإن BERT يعمل في كلا الاتجاهين باستخدام مشفّر Transformer.

الهدف الأساسي لـ BERT هو توليد نموذج لغوي. يمنحه هذا دقة وأداءً لا يصدقان حتى على مجموعات البيانات الأصغر، مما يحل مشكلة كبيرة في معالجة اللغة الطبيعية. فبينما تتوفر كمية هائلة من البيانات النصية، فإن جزءًا صغيرًا جدًا منها فقط تم تصنيفه (labeled) لاستخدامه في تدريب نموذج التعلم الآلي. وبما أن معظم حلول مشاكل NLP تستفيد من التعلم العميق (deep learning)، فإنها تتطلب كميات كبيرة من البيانات للتدريب.

تظهر التحسينات الهائلة في النموذج بشكل واضح عندما يتم تدريبه على ملايين نقاط البيانات. للتغلب على مشكلة نقص البيانات المصنفة، توصل الباحثون إلى طرق لتدريب نماذج تمثيل لغوي للأغراض العامة من خلال التدريب المسبق (pre-training) باستخدام نصوص من الإنترنت. يمكن بعد ذلك ضبط هذه النماذج المدربة مسبقًا (fine-tuned) للعمل على مجموعات بيانات محددة أصغر من تلك المستخدمة عادةً في التعلم العميق. يمكن أن تكون مجموعات البيانات الأصغر هذه لمشاكل مثل تحليل المشاعر أو اكتشاف البريد العشوائي.

هذه هي الطريقة التي يتم بها التعامل مع معظم مشاكل NLP لأنها تعطي نتائج أكثر دقة من البدء بمجموعة بيانات صغيرة. لهذا السبب، يُعد BERT اكتشافًا كبيرًا؛ فهو يوفر طريقة للتدريب المسبق لنماذجك بدقة أكبر وببيانات أقل. النهج ثنائي الاتجاه الذي يستخدمه يعني أنه يحصل على سياق أكبر للكلمة مما لو كان يتدرب في اتجاه واحد فقط. ومع هذا السياق الإضافي، فإنه قادر على الاستفادة من تقنية أخرى تسمى Masked LM.

كيف يختلف BERT عن خوارزميات التعلم الآلي الأخرى؟

تعتمد تقنية Masked LM على إخفاء 15% من الكلمات في الجملة عشوائيًا باستخدام رمز [MASK]، ثم محاولة التنبؤ بها بناءً على الكلمات المحيطة بالكلمة المخفية. هذه هي الطريقة التي يتمكن بها BERT من النظر إلى الكلمات من اليسار إلى اليمين ومن اليمين إلى اليسار في آن واحد. هذا يختلف تمامًا عن أي نموذج لغوي آخر موجود لأنه ينظر إلى الكلمات قبل وبعد الكلمة المخفية في نفس الوقت. يمكن أن يُعزى الكثير من دقة BERT إلى هذه الميزة.

لتشغيل BERT مع مجموعة البيانات الخاصة بك، ستحتاج إلى إضافة بعض البيانات الوصفية (metadata). سيتطلب الأمر وجود token embeddings لتمييز بداية ونهاية الجمل. ستحتاج إلى segment embeddings لتكون قادرًا على التمييز بين الجمل المختلفة. أخيرًا، ستحتاج إلى positional embeddings للإشارة إلى موضع الكلمات في الجملة. سيبدو الأمر مشابهًا لهذا:

[CLS] the [MASK] has blue spots [SEP] it rolls [MASK] the parking lot [SEP]

مع إضافة البيانات الوصفية إلى نقاط البيانات الخاصة بك، تكون تقنية Masked LM جاهزة للعمل. بمجرد الانتهاء من التنبؤ بالكلمات، يستفيد BERT من ميزة التنبؤ بالجملة التالية (next sentence prediction). تنظر هذه الميزة في العلاقة بين جملتين. تقوم بذلك لفهم سياق مجموعة البيانات بأكملها بشكل أفضل عن طريق أخذ زوج من الجمل والتنبؤ بما إذا كانت الجملة الثانية هي الجملة التالية بناءً على النص الأصلي.

لكي تعمل ميزة التنبؤ بالجملة التالية في تقنية BERT، يتم إرسال الجملة الثانية عبر النموذج القائم على Transformer. هناك أربعة إصدارات مختلفة مدربة مسبقًا من BERT، اعتمادًا على حجم البيانات التي تعمل بها. يمكنك معرفة المزيد عنها هنا: https://github.com/google-research/bert#bert

الجانب السلبي لهذا النهج هو أن دالة الخسارة (loss function) تأخذ في الاعتبار فقط تنبؤات الكلمات المخفية وليس تنبؤات الكلمات الأخرى. وهذا يعني أن تقنية BERT تتقارب بشكل أبطأ من التقنيات الأخرى التي تعمل من اليمين إلى اليسار أو من اليسار إلى اليمين. يمكن تطبيق BERT على أي مشكلة NLP يمكنك التفكير فيها، بما في ذلك التنبؤ بالنية، وتطبيقات الإجابة على الأسئلة، وتصنيف النصوص.

مثال عملي: تطبيق BERT لتصنيف مراجعات Yelp

التحضير الأولي

سنستعرض الآن مثالاً عمليًا لتطبيق BERT. أولاً، ستحتاج إلى استنساخ مستودع BERT:

git clone https://github.com/google-research/bert.git

الآن تحتاج إلى تنزيل ملفات نموذج BERT المدربة مسبقًا من صفحة GitHub الخاصة بـ BERT. خلال بقية هذا الدليل، سأشير إلى دليل هذا المستودع على أنه الدليل الجذر (root directory). توفر هذه الملفات المعاملات الفائقة (hyper-parameters)، والأوزان (weights)، وغيرها من المعلومات التي تعلمها BERT أثناء التدريب المسبق.

سأستخدم نموذج BERT-Base, Uncased، ولكن ستجد العديد من الخيارات الأخرى عبر لغات مختلفة في صفحة GitHub. بعض الأسباب التي قد تدفعك لاختيار نموذج BERT-Base, Uncased هي إذا لم يكن لديك وصول إلى وحدة معالجة Tensor (Google TPU)، وفي هذه الحالة ستختار عادةً نموذج Base. إذا كنت تعتقد أن حالة الأحرف في النص الذي تحاول تحليله حساسة (أي أن حالة الأحرف تعطي معنى سياقيًا حقيقيًا)، فستختار نموذج Cased. إذا كانت حالة الأحرف غير مهمة أو لم تكن متأكدًا بعد، فإن نموذج Uncased سيكون خيارًا صالحًا.

سنعمل مع بعض مراجعات Yelp كمجموعة بيانات لنا. تذكر أن BERT يتوقع البيانات بتنسيق معين باستخدام token embeddings وغيرها. سنحتاج إلى إضافة هذه البيانات إلى ملف .tsv. سيكون هذا الملف مشابهًا لملف .csv، ولكنه سيحتوي على أربعة أعمدة ولا يحتوي على صف رأس (header row). إليك كيف ستبدو الأعمدة الأربعة:

  • العمود 0: معرف الصف (Row id)
  • العمود 1: تصنيف الصف (Row label) (يجب أن يكون عددًا صحيحًا)
  • العمود 2: عمود من نفس الحرف لجميع الصفوف (لا يُستخدم لأي شيء، لكن BERT يتوقعه)
  • العمود 3: النص الذي نريد تصنيفه

ستحتاج إلى إنشاء مجلد يسمى data في الدليل الذي استنسخت فيه BERT وإضافة ثلاثة ملفات هناك: train.tsv و dev.tsv و test.tsv. في ملفي train.tsv و dev.tsv، سيكون لدينا الأعمدة الأربعة التي تحدثنا عنها سابقًا. في ملف test.tsv، سيكون لدينا فقط معرف الصف والنص الذي نريد تصنيفه كأعمدة. ستكون هذه هي ملفات البيانات التي سنستخدمها لتدريب واختبار نموذجنا.

تجهيز البيانات

أولاً، نحتاج إلى الحصول على البيانات التي سنعمل بها. يمكنك تنزيل مراجعات Yelp بنفسك من هنا: https://course.fast.ai/datasets#nlp

ستجدها تحت قسم NLP، وستحتاج إلى إصدار Polarity. السبب في أننا سنعمل مع هذا الإصدار هو أن البيانات تحتوي بالفعل على قطبية (polarity)، مما يعني أنها تحتوي بالفعل على شعور (sentiment) مرتبط بها. احفظ هذا الملف في دليل data. الآن نحن جاهزون لبدء كتابة الكود. أنشئ ملفًا جديدًا في الدليل الجذر يسمى _pre_processing.py وأضف الكود التالي:

import pandas as pd
# this is to extract the data from that .tgz file
import tarfile
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split

# get all of the data out of that .tgz
yelp_reviews = tarfile.open('data/yelp_review_polarity_csv.tgz')
yelp_reviews.extractall('data')
yelp_reviews.close()

# check out what the data looks like before you get started
# look at the training data set
train_df = pd.read_csv('data/yelp_review_polarity_csv/train.csv', header=None)
print(train_df.head())

# look at the test data set
test_df = pd.read_csv('data/yelp_review_polarity_csv/test.csv', header=None)
print(test_df.head())

لقطة شاشة تعرض رؤوس ملفات بيانات Yelp train.csv و test.csv قبل معالجة BERT

في هذا الكود، قمنا باستيراد بعض حزم Python وفك ضغط البيانات لمعرفة كيف تبدو. ستلاحظ أن القيم المرتبطة بالمراجعات هي 1 و 2، حيث 1 يمثل مراجعة سيئة و 2 يمثل مراجعة جيدة. نحتاج إلى تحويل هذه القيم إلى تصنيفات أكثر معيارية، أي 0 و 1. يمكنك القيام بذلك باستخدام الكود التالي:

train_df[0] = (train_df[0] == 2).astype(int)
test_df[0] = (test_df[0] == 2).astype(int)

كلما قمت بتحديث بياناتك، من المهم دائمًا التحقق مما إذا كانت الأمور قد سارت على ما يرام. لذلك سنفعل ذلك باستخدام الأوامر التالية:

print(train_df.head())
print(test_df.head())

لقطة شاشة تعرض رؤوس ملفات بيانات Yelp train.csv و test.csv بعد تحويل قيم القطبية إلى 0 و 1

عندما ترى أن قيم القطبية قد تغيرت لتكون كما توقعت، تكون البيانات الآن تحتوي على 1 و 0. بعد تنظيف البيانات الأولية، حان الوقت لتجهيز الأمور لـ BERT. سيتعين علينا جعل بياناتنا تتناسب مع تنسيقات الأعمدة التي تحدثنا عنها سابقًا. لنبدأ ببيانات التدريب. ستحتوي بيانات التدريب على الأعمدة الأربعة جميعها: معرف الصف، تصنيف الصف، حرف واحد، النص الذي نريد تصنيفه.

يتوقع BERT ملفين للتدريب يسمى train و dev. سنقوم بإنشاء هذه الملفات عن طريق تقسيم ملف التدريب الأولي إلى ملفين بعد تنسيق بياناتنا باستخدام الأوامر التالية:

bert_df = pd.DataFrame({
    'id': range(len(train_df)),
    'label': train_df[0],
    'alpha': ['q']*train_df.shape[0],
    'text': train_df[1].replace(r'\n', ' ', regex=True)
})
train_bert_df, dev_bert_df = train_test_split(bert_df, test_size=0.01)

باستخدام المتغير bert_df، قمنا بتنسيق البيانات لتكون كما يتوقع BERT. يمكنك اختيار أي حرف آخر لقيمة alpha إذا أردت. تتعامل طريقة train_test_split التي استوردناها في البداية مع تقسيم بيانات التدريب إلى الملفين اللذين نحتاجهما. ألقِ نظرة على كيفية تنسيق البيانات باستخدام هذا الأمر:

print(train_bert_df.head())

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

test_bert_df = pd.DataFrame({
    'id': range(len(test_df)),
    'text': test_df[1].replace(r'\n', ' ', regex=True)
})

إنه مشابه لما فعلناه مع بيانات التدريب، فقط بدون عمودين. ألقِ نظرة على بيانات الاختبار المنسقة حديثًا:

test_bert_df.head()

إذا كان كل شيء يبدو جيدًا، يمكنك حفظ هذه المتغيرات كملفات .tsv التي سيعمل معها BERT:

train_bert_df.to_csv('data/train.tsv', sep='\t', index=False, header=False)
dev_bert_df.to_csv('data/dev.tsv', sep='\t', index=False, header=False)
test_bert_df.to_csv('data/test.tsv', sep='\t', index=False, header=False)

تدريب النموذج

ملاحظة سريعة قبل أن نبدأ في تدريب النموذج: يمكن أن يكون BERT مكثفًا جدًا للموارد على أجهزة الكمبيوتر المحمولة. قد يتسبب في أخطاء في الذاكرة بسبب عدم وجود ذاكرة وصول عشوائي (RAM) كافية أو أن بعض الأجهزة الأخرى ليست قوية بما يكفي. يمكنك محاولة جعل حجم دفعة التدريب (training_batch size) أصغر، ولكن ذلك سيجعل تدريب النموذج بطيئًا جدًا.

أضف مجلدًا إلى الدليل الجذر يسمى _model_output. هذا هو المكان الذي سيتم فيه حفظ نموذجنا بعد الانتهاء من التدريب. الآن افتح طرفية (terminal) وانتقل إلى الدليل الجذر لهذا المشروع. بمجرد أن تكون في الدليل الصحيح، قم بتشغيل الأمر التالي وسيبدأ تدريب نموذجك:

python run_classifier.py \
  --task_name=cola \
  --do_train=true \
  --do_eval=true \
  --data_dir=./data/ \
  --vocab_file=./uncased_L-12_H-768_A-12/vocab.txt \
  --bert_config_file=./uncased_L-12_H-768_A-12/bert_config.json \
  --init_checkpoint=./uncased_L-12_H-768_A-12/bert_model.ckpt.index \
  --max_seq_length=128 \
  --train_batch_size=32 \
  --learning_rate=2e-5 \
  --num_train_epochs=3.0 \
  --output_dir=./model_output \
  --do_lower_case=False

يجب أن ترى بعض المخرجات تتدفق عبر الطرفية الخاصة بك. بمجرد الانتهاء من التشغيل، سيكون لديك نموذج مدرب جاهز لإجراء التنبؤات!

إجراء التنبؤات

إذا ألقيت نظرة في دليل _model_output، ستلاحظ وجود مجموعة من ملفات model.ckpt. تحتوي هذه الملفات على أوزان النموذج المدرب في نقاط مختلفة أثناء التدريب، لذا سترغب في العثور على الملف الذي يحتوي على أعلى رقم. سيكون هذا هو النموذج المدرب النهائي الذي سترغب في استخدامه.

الآن سنقوم بتشغيل _run_classifier.py مرة أخرى بخيارات مختلفة قليلاً. على وجه الخصوص، سنقوم بتغيير قيمة _init_checkpoint إلى أعلى نقطة فحص للنموذج وتعيين قيمة جديدة لـ --do_predict إلى true. إليك الأمر الذي تحتاج إلى تشغيله في الطرفية الخاصة بك:

python run_classifier.py \
  --task_name=cola \
  --do_predict=true \
  --data_dir=./data \
  --vocab_file=./uncased_L-12_H-768-A-12/bert_config.json \
  --init_checkpoint=./model_output/model.ckpt-<highest checkpoint number> \
  --max_seq_length=128 \
  --output_dir=./model_output

بمجرد الانتهاء من تشغيل الأمر، يجب أن ترى ملفًا جديدًا يسمى _test_results.tsv. سيحتوي هذا الملف على نتائجك المتوقعة بناءً على النموذج الذي قمت بتدريبه! لقد استخدمت للتو BERT لتحليل بعض البيانات الحقيقية، ونأمل أن يكون كل هذا منطقيًا.

الخلاصة التقنية

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

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *