كل شيء ممكن: حل مشاكل البرمجة اللغوية العصبية باستخدام Spacy





أصبحت معالجة اللغة الطبيعية الآن في كل مكان: تتطور الواجهات الصوتية وروبوتات الدردشة بسرعة ، ويتم تطوير النماذج لمعالجة البيانات النصية الكبيرة ، وتستمر الترجمة الآلية في التطور.



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



بادئ ذي بدء ، دعنا نلقي نظرة على كيفية معالجة البيانات في SpaCy. يمر النص الذي تم تحميله للمعالجة بالتسلسل عبر مكونات معالجة مختلفة ويتم حفظه كمثيل لكائن Doc:







Doc هو بنية البيانات المركزية في SpaCy ، حيث يتم تخزين تسلسل الكلمات أو ، كما يطلق عليها أيضًا ، الرموز المميزة. داخل كائن Doc ، يمكن تمييز نوعين آخرين من الكائنات: Token و Span. الرمز المميز هو ارتباط لكلمات فردية من المستند ، وسبان هو ارتباط لسلسلة من عدة كلمات (يمكنك إنشائها بنفسك):







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



يتم توصيل الرموز المميزة للمستند بكائن Vocab من خلال تجزئة ، والتي من خلالها يمكنك الحصول على الأشكال الأولية للكلمات أو السمات المعجمية الأخرى للرموز المميزة:







الآن نحن نعرف كيف يتم ترتيب تخزين البيانات ومعالجتها في مكتبة SpaCy. كيف تستفيد من الفرص التي توفرها؟ دعنا نلقي نظرة على العمليات التي يمكن استخدامها لمعالجة النص بالتسلسل.



1. العمليات الأساسية



قبل أن تبدأ العمل مع النص ، يجب عليك استيراد نموذج اللغة. بالنسبة للغة الروسية ، يوجد نموذج رسمي من SpaCy يدعم الترميز (تقسيم النص إلى رموز منفصلة) وعدد من العمليات الأساسية الأخرى:



from spacy.lang.ru import Russian
      
      





بعد استيراد نموذج اللغة وإنشاء مثيل له ، يمكنك البدء في معالجة النص. للقيام بذلك ، تحتاج فقط إلى تمرير النص إلى المثيل الذي تم إنشاؤه:



nlp = Russian()
doc = nlp("     ,   .")
      
      





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



token = doc[0]
print(token.text)

span = doc[3:6]
print(span.text)


  
      
      





لمزيد من المعلومات حول نوع المعلومات الموجودة في الرمز المميز ، يمكن استخدام السمات التالية:



  1. is_alpha - تحقق مما إذا كان الرمز المميز يحتوي على أحرف أبجدية فقط
  2. is_punct - تحقق مما إذا كان الرمز المميز علامة ترقيم
  3. like_num - تحقق مما إذا كان الرمز المميز عبارة عن رقم


print("is_alpha:    ", [token.is_alpha for token in doc])
print("is_punct:    ", [token.is_punct for token in doc])
print("like_num:    ", [token.like_num for token in doc])

      
      





لنفكر في مثال آخر ، حيث يتم عرض جميع الرموز المميزة التي تسبق النقطة على الشاشة. للحصول على هذه النتيجة ، عند التكرار فوق الرموز المميزة ، تحقق من الرمز المميز التالي باستخدام سمة token.i:



for token in doc:
    if token.i+1 < len(doc):
        next_token = doc[token.i+1]
        if next_token.text == ".":
            print(token.text)


      
      





2. العمليات مع النحو



لمزيد من عمليات معالجة الكلمات المعقدة ، يتم استخدام نماذج أخرى. يتم تدريبهم بشكل خاص على المهام المتعلقة بالنحو واستخراج الكيانات المسماة والعمل مع معاني الكلمات. على سبيل المثال ، بالنسبة للغة الإنجليزية ، هناك 3 نماذج رسمية تختلف في الحجم. بالنسبة للغة الروسية ، في الوقت الحالي ، لم يتم تدريب النموذج الرسمي بعد ، ولكن يوجد بالفعل نموذج ru2 من مصادر خارجية يمكنها العمل مع بناء الجملة.



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



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



python -m spacy download en_core_web_sm
      
      





باستخدام هذا النموذج ، يمكننا الحصول على جزء من الكلام لكل من الرموز المميزة ودورًا في الجملة والرمز الذي يعتمد عليه:



import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("New Apple MacBook set launch tomorrow")

for token in doc:
    token_text = token.text
    token_pos = token.pos_
    token_dep = token.dep_
    token_head = token.head.text
    print(f"{token_text:<12}{token_pos:<10}" \
          f"{token_dep:<10}{token_head:<12}")
      
      





New         PROPN     compound  MacBook     
Apple       PROPN     compound  MacBook     
MacBook     PROPN     nsubj     set         
set         VERB      ROOT      set         
to          PART      aux       launch      
launch      VERB      xcomp     set         
tomorrow    NOUN      npadvmod  launch 
      
      





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



from spacy import displacy
displacy.render(doc, style='dep', jupyter=True)
      
      





نتيجة لتنفيذ الشفرة ، حصلنا على شجرة توجد عليها جميع المعلومات النحوية حول الجملة:







لفك تشفير أسماء العلامات ، يمكنك استخدام وظائف الشرح:



print(spacy.explain("aux"))
print(spacy.explain("PROPN"))
auxiliary
proper noun
      
      





هنا ، يتم عرض الاختصارات على الشاشة ، والتي يمكننا من خلالها معرفة أن aux تعني جسيمًا مساعدًا (مساعد) ، و PROPN تعني اسم علم.



ينفذ SpaCy أيضًا القدرة على معرفة الشكل الأولي للكلمة لأي من الرموز المميزة (يستخدم -PRON- للضمائر):



import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("I saw a movie yesterday")
print(' '.join([token.lemma_ for token in doc]))

'-PRON- see a movie yesterday'
      
      





3. تخصيص الكيانات المسماة



في كثير من الأحيان ، للعمل مع النص ، تحتاج إلى إبراز الكيانات المذكورة في النص. يتم استخدام السمة doc.ents لسرد الكيانات المسماة في المستند ، ويتم استخدام السمة ent.label_ للحصول على تسمية لهذا الكيان:



import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("Apple is looking at buying U.K. startup for 1$ billion")
for ent in doc.ents:
    print(ent.text, ent.label_)


Apple ORG
U.K. GPE
1$ billion MONEY
      
      





يمكنك أيضًا استخدام سمة التفسير هنا لمشاهدة فك تشفير تسميات الكيانات المسماة:



print(spacy.explain("GPE"))

      
      







ستساعدك البلدان والمدن والولايات وستساعدك وظيفة الإزاحة على تصور قوائم الكيانات في النص مباشرة:



من إزاحة استيراد الفضاء.

render (doc ، style = 'ent' ، jupyter = True)







4. إنشاء القوالب الخاصة بك للبحث عن النص



تحتوي وحدة spaCy على أداة مفيدة للغاية تتيح لك إنشاء قوالب بحث نصية خاصة بك. على وجه الخصوص ، يمكنك البحث عن كلمات جزء معين من الكلام ، وجميع أشكال الكلمة حسب شكلها الأولي ، والتحقق من نوع المحتوى في الرمز المميز. فيما يلي قائمة بالمعلمات الرئيسية:







لنحاول إنشاء قالب خاص بنا للتعرف على سلسلة من الرموز المميزة. لنفترض أننا نريد استخراج سطور من النص حول كأس العالم للكريكيت FIFA أو ICC مع ذكر السنة:



import spacy
from spacy.matcher import Matcher

nlp = spacy.load("en_core_web_sm")
matcher = Matcher(nlp.vocab)
pattern = [
    {"IS_DIGIT": True}, 
    {"LOWER": {"REGEX": "(fifa|icc)"}},
    {"LOWER": "cricket", "OP": "?"},
    {"LOWER": "world"},
    {"LOWER": "cup"}
]
matcher.add("fifa_pattern", None, pattern)
doc = nlp("2018 ICC Cricket World Cup: Afghanistan won!")
matches = matcher(doc)
for match_id, start, end in matches:
    matched_span = doc[start:end]
    print(matched_span)
      
      





2018 ICC Cricket World Cup
      
      





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



بعد إنشاء قالب ، تحتاج إلى إضافته إلى المجموعة باستخدام وظيفة الإضافة ، مع تحديد معرف قالب فريد في المعلمات. يتم عرض نتائج البحث في شكل قائمة مجموعات. تتكون كل مجموعة من معرف المطابقة وفهارس البداية والنهاية للشريحة الموجودة في المستند.



5. تحديد القرب الدلالي



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



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



import spacy
      
      





nlp = spacy.load("en_core_web_md")
doc1 = nlp("I like burgers")
doc2 = nlp("I like pizza")
print(doc1.similarity(doc2))
      
      





0.9244169833828932
      
      





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



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



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



6. إنشاء مكونات المعالجة الخاصة بك



تدعم وحدة SpaCy عددًا من المكونات المضمنة (رمز مميز ، تمييز كيان مسمى) ، ولكنها تتيح لك أيضًا تحديد المكونات الخاصة بك. في الواقع ، تسمى المكونات بالتسلسل الوظائف التي تأخذ مستندًا كمدخلات وتعديلها وترسلها مرة أخرى. يمكن إضافة مكونات جديدة باستخدام السمة add_pipe:



import spacy

def length_component(doc):
    doc_length = len(doc)
    print(f"This document is {doc_length} tokens long.")
    return doc

nlp = spacy.load("en_core_web_sm")
nlp.add_pipe(length_component, first=True)
print(nlp.pipe_names)
doc = nlp("This is a sentence.")
      
      





['length_component', 'tagger', 'parser', 'ner']
This document is 5 tokens long.
      
      





في المثال أعلاه ، أنشأنا وأضفنا وظيفتنا الخاصة التي تعرض عدد الرموز المميزة في المستند المعالج. باستخدام السمة nlp.pipe_names ، حصلنا على ترتيب تنفيذ المكونات: كما نرى ، المكون الذي تم إنشاؤه هو الأول في القائمة. يمكنك استخدام الخيارات التالية لتحديد مكان إضافة المكون الجديد:







القدرة على إضافة مكونات مخصصة هي أداة قوية للغاية لتحسين المعالجة لاحتياجاتك.



7. نماذج التدريب والتحديث



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



يمكن إضافة أمثلة تدريب إضافية مباشرة في واجهة SpaCy. يجب أن تتكون الأمثلة نفسها من بيانات نصية وقائمة بالتسميات لهذا المثال الذي سيتدرب عليه النموذج.



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



على سبيل المثال:



("What to expect at Apple's 10 November event", {"entities": [(18,23,"COMPANY")]})
("Is that apple pie I smell?", {"entities": []})
      
      





في المثال الأول ، تم ذكر شركة: للتدريب ، نسلط الضوء على المواقف حيث يبدأ اسمها وينتهي ، ثم نضع علامتنا بأن هذا الكيان هو شركة. في المثال الثاني نتحدث عن فاكهة ، لذلك لا توجد كيانات.



عادةً ما يتم ترميز بيانات تدريب النموذج بواسطة الأشخاص ، ولكن يمكن أتمتة هذا العمل قليلاً باستخدام قوالب البحث الخاصة في SpaCy أو برامج الترميز المتخصصة (على سبيل المثال ، Prodigy ).



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







import spacy
import random
from spacy.lang.en import English

TRAINING_DATA = [
    ("What to expect at Apple's 10 November event", 
    {"entities": [(18,23,"COMPANY")]})
    #  ...
]

nlp = English()

for i in range(10):
    random.shuffle(TRAINING_DATA)
    for batch in spacy.util.minibatch(TRAINING_DATA):
        texts = [text for text, annotation in batch]
        annotations = [annotation for text, annotation in batch]
        nlp.update(texts, annotations)
        
nlp.to_disk("model")
      
      





في المثال أعلاه ، تكونت الحلقة من 10 تدريبات. بعد الانتهاء من التدريب ، تم حفظ النموذج على القرص في مجلد النموذج.



في الحالات التي يكون فيها من الضروري ليس فقط التحديث ، ولكن لإنشاء نموذج جديد ، يتطلب الأمر عددًا من العمليات قبل بدء التدريب.



ضع في اعتبارك عملية إنشاء نموذج جديد لتمييز الكيانات المسماة:



nlp = spacy.blank("en")
ner = nlp.create_pipe("ner")
nlp.add_pipe(ner)
ner.add_label("COMPANY")
nlp.begin_training()
      
      





أولاً ، نقوم بإنشاء نموذج فارغ باستخدام وظيفة spacy.blank ("en"). يحتوي النموذج على بيانات اللغة وقواعد الترميز فقط. ثم نضيف مكونًا ner مسؤولاً عن تمييز الكيانات المسماة ، وباستخدام سمة add_label ، أضف تسميات للكيانات. ثم نستخدم الدالة nlp.begin_training () لتهيئة النموذج للتدريب مع التوزيع العشوائي للأوزان. حسنًا ، سيكفي تدريب النموذج ، كما هو موضح في المثال السابق.



All Articles