طريقة عمل تضمين للغة العربية Word-Embedding (الجزء الأول)

Arabic Word-Embedding Word2Vec

352

تحظى اللغة العربية باهتمام متزايد من المحبين لها والذين يرغبون في دعمها بأحدث وسائل الذكاء الاصطناعي لتحليل النصوص العربية ومحاولة فهم معناها.

واليوم هنحاول سوا استكشاف تقنية معالجة اللغة NLP من أجل الوصول إلى نموذج Model قادر على فهم لغتنا العربية الجميلة 😍.

بداية هنتكلم عن Word-Embedding ونقول مقدمة سريعة عنها, الفكرة الرئيسية هي تحويل الكلمات إلى Vector رياضي بحيث يمكننا ايجاد التشابه بين كلمتين باستخدام معادلة رياضية.

كلام جميل وكلام معقول مقدرش أقول حاجة عنه, بس إزاي ؟  😆😆😆

قالك إحنا عايزين في النهاية نعمل معادلات بالشكل دا:-

رجل + ملك – امرأة = ملكة
مصر + القاهرة – السعودية = الرياض
مصر + القاهرة – الإمارات = أبو ظبي
راكب + راكبة – واقف = واقفة
يركب + تركب – يقوم = تقوم

معني إنك وصلت إلى هذه المعادلات يبقى إنت فعلا قدرت تفهم الكلمات العربية مش بس كدا, دا إنت قدرت تفهم العلاقة بين الدول وعواصمها, والمذكر والمؤنث كمان 💪.

طيب إيه الطريقة المناسبة عشان نحصل على Vectors دي ؟

أول طريقة وأشهرهم اسمها Word2Vec ودي بتعتمد على الكلمات المجاورة في الجملة وعدد تكرارها.

فيه طريقة تانية اسمها gloVe بتعتمد على Matrix Factorization لكن لن نخوض في تفاصيلها اليوم.

خلينا في الطريقة الأولى ونشوف هتشتغل إزاي 😉

مثال توضيحي:-

ذهب محمد إلى المدرسة في الصباح لكى يتعلم ويكون شخصاً نافعاً في المجتمع

كلمة “الصباح” مثلاً يوجد قبلها كلمتين هما “المدرسة” + “في”

وبعدها كلمتين هما “لكي” + “يتعلم”

المفروض لو قلت لبرنامج الذكاء الاصطناعي كلمة “صباح” يبقى لازم يرد على بالأربع كلمات السابقة

أو لو قلت له الأربع كلمات السابقة المفروض يرد على ويقولي “صباح”

الطريقة الأولي اسمها Skip-Gram أما الثانية اسمها CBOW معلش الأسماء سخيفة شوية لكن حاول تبلعها 😡😡😡

طبعا لو هنستعمل البايثون عشان نصمم Neural Network تعمل الكلام دا باستخدام Tensorflow أو Numpy الوضع هيكون فعلا صعب 😥😥😥

سوف تقضي ساعات مطولة عشان تفهم Backpropagation ماشي إزاي وهتضيع أيام طويلة عشان تفهم كل سطر بيعمل إيه.

طيب الموضوع دا شغل بال الأجانب اللي فاهمين النقطة دي كويس 🤔🤔🤔

لحد لما جاء أخونا Radim Řehůřek وعمل مكتبة شهيرة بالبايثون اسمها Gensim عشان تقوم بهذا الدور ببساطة.

طيب خلينا نفتح البايثون ونكتب سوا الكود اللي ممكن يعمل كدا.

فيه سؤال الأول هنجيب الـ Dataset منين ؟

سؤال وجيه, من إمتى بنسأل أسئلة زي دي !!! 🤣🤣🤣

الويكيبيديا طبعا 😮😮😮

طيب ما هي خطوات الشغل ؟

1- عمل دونلود لمقالات الويكيبيديا العربية من اللينك دا

https://dumps.wikimedia.org/arwiki/latest/

2- هتختار المقالات فقط Articles هيكون اسم الملف بالشكل التالي

arwiki-latest-pages-articles-multistream.xml.bz2

حجمه تقريبا 1 جيجا

3- هنستعمل WikiExtractor عشان نفك ضغط المقالات دي ونحولها إلى json بحيث إن كل مقال يكون في ملف منفصل

https://github.com/attardi/wikiextractor

4- هنكتب الكود دا عشان نعمل Text Wrangling للكلمات العربية والتخلص من التشكيل والرموز العربية الخاصة, طبعا زي ما إنتم شايفين إحنا بنستعمل Regular Expression بعبع الكثيرين 😈👿👹

from nltk.tokenize import TreebankWordTokenizer
from gensim.models import Word2Vec
from gensim.models import FastText
import re
import os
import json

# Arabic Text Cleansing
accents = re.compile(r'[\u064b-\u0652\u0640]') # harakaat and tatweel
puncs = re.compile(r'[\u061b\u061f\u060c\u003A\u003D\u002E\u002F\u007C\u002D]')
arabic = re.compile(r'[\u0621-\u063A\u0641-\u064A]+') # Arabic letters only
nonArabic = re.compile(r'[^\u0621-\u063A\u0641-\u064A]')
def ArTokenizer(text,token_min_len=2, token_max_len=15, lower=False):
    tokens = TreebankWordTokenizer().tokenize(accents.sub('',puncs.sub(' ', text)))
    # keep only Ar words between min/max len and remove other characters if any
    return [nonArabic.sub('',token) for token in tokens if arabic.findall(token) and token_min_len <= len(token) <= token_max_len]

5- هنبتدي نقرا الملفات اللي تم فكها من الملف المضغوط, بعد لما تتفك هيكون فيه مجلدات وكل مجلد فيه 100 ملف json, الهدف هو قراءة هذه الملفات وتحويلها إلى List of Lists of words

6- هنكتب الكود دا عشان الكلمات تكون جاهزة للتدريب.

# Reading from Wikipedia extracted directory
folders = ['AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL']
wikis = []
for ff in folders:
    for i in range(0, 100):
        ext = str(i) if i >= 10 else '0' + str(i)
        if os.path.exists("wikiextractor/text/" + ff + "/wiki_" + ext):
            with open("wikiextractor/text/" + ff + "/wiki_" + ext, encoding="utf-8") as f:
                for line in f.readlines():
                    l = json.loads(line)
                    wikis.append({"title": l["title"], "size": len(l["text"]), "text": l["text"]})

# Calling Arabic Text Wrangling            
sentences = []
for wiki in wikis:
    text = wiki['text'].replace("\\n\\n", "\n\n")
    text = ArTokenizer(text)
    sentences.append(text)

طبعا لما فكيت الملف المضغوط طلع عندي مجلدات تبدأ من “AA” إلى “AL” دا على حسب آخر تعديل من الويكيبيديا, لو كان عدد المجلدات مختلف عندك يبقى لازم تعدلها في الكود بحيث إنها تطابق الواقع وإلا الكود لن يعمل 😥😥😥

غالباً هياخد حوالي 5 دقايق ويكون انتهت عملية التنقيح بنجاح.

7- آخر خطوة وهي عملية التدريب نفسها.

# Start Training the Model using Word2Vec
Word2Vec_model = Word2Vec(sentences, size=300, window=5, min_count=5, workers=8, sg=0)
Word2Vec_model.save('ar_wiki_word2vec')

# Start Training the Model using FastText
FastText_model = FastText(sentences, size=300, window=5, min_count=5, workers=8, sg=0)
FastText_model.save('ar_wiki_FastText')

شوف اللي يريحك هل تحب تستعمل Word2Vec أو FastText, غالبا هياخد حوالي ربع ساعة ويكون التدريب انتهى بنجاح تام, طبعا فيه Hyper Parameter Tuning مثلاً طول الـ Vector هو 300 عشان ويكيبيديا تعتبر Dataset كبيرة فعلاً, لكن لو Dataset بتاعتك صغيرة يبقى 100 أو 50 كفاية, وكذلك الأمر بالنسبة للـ window وهو عدد الكلمات المجاورة اللي هياخدها في الحسبان وخلي بالك لازم تكون عدد فردي 5 أو 7 أو 9, برضه بالنسبة للـ min_count المقصود بيها لو الكلمة اتكررت في Dataset أقل من 5 مرات يبقى الكلمة دي مش هتتاخد في الحسبان, وهي مهمة عشان معالجة الأخطاء اللغوية, وبرضه على حسب Dataset ممكن تخليها 10 أو 7 زي ما تحب.

لو إنت مش عايز تستعمل الويكيبيديا وعايز تستعمل تويتات أو بوستات من السوشيال ميديا برضه مفيش مشكلة هتغير حاجات بسيطة في الكود عشان يقرا Dataset بتاعتك.

في الحلقة القادمة هنتكلم عن تجريب Model ونشوف إزاي نكتب معادلات على الكلمات العربية, ونتفرج على الرسم البياني مدى تشابه الكلمات من بعضها.

انتظرونا 😉

تعليقات