مستوى المقال: مبتدئ. لو سمعت كلمة Embeddings كتير وحسّيت إنها كلمة تخويف، المقال ده هيفكّها لك من الصفر بمثال بسيط وكود تقدر تشغّله بنفسك في دقيقتين.
الـ Embeddings للمبتدئين: كيف يفهم الحاسوب أن "قطة" و"كلب" متقاربتان؟
الحاسوب لا يعرف معنى كلمة "قطة". هو يتعامل مع أرقام فقط. ومع ذلك، لو سألت ChatGPT أو محرك بحث ذكي عن "قطة" فقد يرشّح لك محتوى عن "كلب" أو "حيوان أليف". السر وراء ده حاجة اسمها Embeddings. في نهاية المقال هتعرف بالظبط إيه هي، وهتشغّل كود يقيس التشابه بين كلمتين بنفسك.
المشكلة باختصار
الكمبيوتر يخزّن الكلمات كنصوص أو أرقام تعريفية عشوائية. "قطة" رقم 4021 و"كلب" رقم 88. الرقمان لا يقولان أي شيء عن المعنى. فلو بنيت بحثًا يعتمد على تطابق الحروف فقط، البحث عن "عربية" لن يجد صفحة مكتوب فيها "سيارة" رغم إنهما نفس المعنى. محتاجين طريقة تخلّي الحاسوب يمثّل المعنى نفسه، مش الحروف.
الفكرة بمثال بسيط: مدينة الأحياء
تخيّل مدينة سكانها بيتوزّعوا حسب المهنة. كل الأطباء يسكنون في حي واحد، وكل المهندسين في حي تاني، والفنانين في حي ثالث. لو أعطيتك عنوان بيت شخص لا تعرفه، تقدر تخمّن مهنته من الحي اللي هو فيه. والأقرب في العنوان غالبًا الأقرب في المهنة.
الـ Embeddings بتعمل نفس الحاجة بالظبط مع الكلمات. بتدّي كل كلمة "عنوانًا" (إحداثيات) في فضاء. الكلمات المتقاربة في المعنى بتاخد عناوين متجاورة. "قطة" و"كلب" جيران في حي الحيوانات، و"سيارة" و"شاحنة" جيران في حي بعيد. المسافة بين العنوانين هي مقياس قرب المعنى.
التعريف العلمي بدقة
الـ Embedding هو متجه (قائمة أرقام حقيقية) بيمثّل الكلمة. مثلًا نموذج شائع زي all-MiniLM-L6-v2 بيحوّل أي جملة لمتجه من 384 رقمًا. النموذج بيتدرّب على كميات ضخمة من النصوص بحيث الكلمات اللي بتظهر في سياقات متشابهة تاخد متجهات متقاربة. النتيجة: المعنى بقى موقعًا في مكان، والقرب في المكان = قرب في المعنى.
كيف يقيس الحاسوب "القرب"؟
الطريقة الشائعة اسمها جيب تمام الزاوية (Cosine Similarity). بنقيس الزاوية بين متجهين. زاوية صغيرة تعني اتجاهًا متشابهًا وبالتالي معنى قريبًا، وقيمة قريبة من 1. زاوية كبيرة تعني معنى بعيدًا وقيمة قريبة من 0.
كود شغّال تجرّبه بنفسك
الكود ده يشتغل فورًا بدون أي تحميل، لأننا كتبنا المتجهات بأيدينا للتوضيح:
# مثال قابل للنسخ والتشغيل مباشرة
import numpy as np
embeddings = {
"قطة": np.array([0.90, 0.80, 0.10, 0.00]),
"كلب": np.array([0.85, 0.82, 0.12, 0.00]),
"سيارة": np.array([0.10, 0.05, 0.90, 0.80]),
}
def cosine(a, b):
return a @ b / (np.linalg.norm(a) * np.linalg.norm(b))
print(round(cosine(embeddings["قطة"], embeddings["كلب"]), 2)) # 1.0
print(round(cosine(embeddings["قطة"], embeddings["سيارة"]), 2)) # 0.22