إنشاء تضمينات باستخدام Sentence Transformers

عرض على ai.google.dev التشغيل في Google Colab التشغيل في Kaggle الفتح في Vertex AI عرض المصدر على GitHub

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

الإعداد

قبل البدء في هذا البرنامج التعليمي، أكمِل الخطوات التالية:

  • يمكنك الوصول إلى Gemma من خلال تسجيل الدخول إلى Hugging Face والنقر على أوافق على الترخيص لنموذج Gemma.
  • أنشئ رمز دخول في Hugging Face واستخدِمه لتسجيل الدخول من Colab.

سيتم تشغيل ورقة الملاحظات هذه على وحدة المعالجة المركزية أو وحدة معالجة الرسومات.

تثبيت حِزم Python

ثبِّت المكتبات المطلوبة لتشغيل نموذج EmbeddingGemma وإنشاء عمليات التضمين. ‫Sentence Transformers هو إطار عمل Python لعمليات التضمين في النصوص والصور. لمزيد من المعلومات، يُرجى الاطّلاع على مستندات Sentence Transformers.

pip install -U sentence-transformers git+https://github.com/huggingface/transformers@v4.56.0-Embedding-Gemma-preview

بعد قبول الترخيص، تحتاج إلى رمز مميّز صالح من Hugging Face للوصول إلى النموذج.

# Login into Hugging Face Hub
from huggingface_hub import login
login()

تحميل النموذج

استخدِم مكتبات sentence-transformers لإنشاء مثيل لفئة نموذج باستخدام EmbeddingGemma.

import torch
from sentence_transformers import SentenceTransformer

device = "cuda" if torch.cuda.is_available() else "cpu"

model_id = "google/embeddinggemma-300M"
model = SentenceTransformer(model_id).to(device=device)

print(f"Device: {model.device}")
print(model)
print("Total number of parameters in the model:", sum([p.numel() for _, p in model.named_parameters()]))
Device: cuda:0
SentenceTransformer(
  (0): Transformer({'max_seq_length': 2048, 'do_lower_case': False, 'architecture': 'Gemma3TextModel'})
  (1): Pooling({'word_embedding_dimension': 768, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})
  (2): Dense({'in_features': 768, 'out_features': 3072, 'bias': False, 'activation_function': 'torch.nn.modules.linear.Identity'})
  (3): Dense({'in_features': 3072, 'out_features': 768, 'bias': False, 'activation_function': 'torch.nn.modules.linear.Identity'})
  (4): Normalize()
)
Total number of parameters in the model: 307581696

إنشاء التضمين

التضمين هو تمثيل رقمي للنص، مثل كلمة أو جملة، يوضّح معناه الدلالي. وهي في الأساس قائمة أرقام (متّجه) تتيح لأجهزة الكمبيوتر فهم العلاقات بين الكلمات وسياقها.

لنطّلع على كيفية معالجة EmbeddingGemma لثلاث كلمات مختلفة ["apple", "banana", "car"].

تم تدريب EmbeddingGemma على كميات كبيرة من النصوص، وقد تعلّم العلاقات بين الكلمات والمفاهيم.

words = ["apple", "banana", "car"]

# Calculate embeddings by calling model.encode()
embeddings = model.encode(words)

print(embeddings)
for idx, embedding in enumerate(embeddings):
  print(f"Embedding {idx+1} (shape): {embedding.shape}")
[[-0.18476306  0.00167681  0.03773484 ... -0.07996225 -0.02348064
   0.00976741]
 [-0.21189538 -0.02657359  0.02513712 ... -0.08042689 -0.01999852
   0.00512146]
 [-0.18924113 -0.02551468  0.04486253 ... -0.06377774 -0.03699806
   0.03973572]]
Embedding 1: (768,)
Embedding 2: (768,)
Embedding 3: (768,)

يُخرج النموذج متّجهًا رقميًا لكل جملة. المتّجهات الفعلية طويلة جدًا (768)، ولكن لتبسيط الأمر، يتم عرضها ببضعة أبعاد.

المفتاح ليس الأرقام الفردية نفسها، بل المسافة بين المتجهات. إذا أردنا رسم هذه المتجهات في مساحة متعددة الأبعاد، ستكون متجهات apple وbanana قريبة جدًا من بعضها البعض. وسيكون المتجه الخاص بـ car بعيدًا عن المتجهَين الآخرَين.

تحديد التشابه

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

  • التشابه الكبير:

    • الجملة (أ): "أعدّ الطاهي وجبة لذيذة للضيوف".
    • الجملة (ب): "أعدّ الشيف عشاءً لذيذًا للضيوف".
    • السبب: يصف كلتا الجملتين الحدث نفسه باستخدام كلمات وبِنى نحوية مختلفة (صيغة المبني للمعلوم مقابل صيغة المبني للمجهول). وهي تنقل المعنى الأساسي نفسه.
  • التشابه المتوسط:

    • الجملة (أ): "إنّها خبيرة في تعلُّم الآلة".
    • الجملة (ب): "لديه اهتمام كبير بالذكاء الاصطناعي".
    • السبب: الجملتان مرتبطتان لأنّ تعلُّم الآلة هو أحد مجالات الذكاء الاصطناعي. ومع ذلك، يتحدثون عن أشخاص مختلفين بمستويات تفاعل مختلفة (خبير مقابل مهتم).
  • التشابه المنخفض:

    • الجملة (أ): "الطقس في طوكيو مشمس اليوم".
    • الجملة (ب): "أحتاج إلى شراء البقالة لهذا الأسبوع".
    • السبب: تتناول الجملتان موضوعَين غير مرتبطَين تمامًا ولا تتشاركان أي تداخل دلالي.
# The sentences to encode
sentence_high = [
    "The chef prepared a delicious meal for the guests.",
    "A tasty dinner was cooked by the chef for the visitors."
]
sentence_medium = [
    "She is an expert in machine learning.",
    "He has a deep interest in artificial intelligence."
]
sentence_low = [
    "The weather in Tokyo is sunny today.",
    "I need to buy groceries for the week."
]

for sentence in [sentence_high, sentence_medium, sentence_low]:
  print("🙋‍♂️")
  print(sentence)
  embeddings = model.encode(sentence)
  similarities = model.similarity(embeddings[0], embeddings[1])
  print("`-> 🤖 score: ", similarities.numpy()[0][0])
🙋‍♂️
['The chef prepared a delicious meal for the guests.', 'A tasty dinner was cooked by the chef for the visitors.']
`-> 🤖 score:  0.8002148
🙋‍♂️
['She is an expert in machine learning.', 'He has a deep interest in artificial intelligence.']
`-> 🤖 score:  0.45417833
🙋‍♂️
['The weather in Tokyo is sunny today.', 'I need to buy groceries for the week.']
`-> 🤖 score:  0.22262995

استخدام الطلبات مع EmbeddingGemma

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

كيفية تطبيق الطلبات

يمكنك تطبيق طلب أثناء الاستنتاج بثلاث طرق.

  1. استخدام وسيطة prompt
    مرِّر سلسلة الطلب الكاملة مباشرةً إلى طريقة encode. يمنحك ذلك تحكّمًا دقيقًا.

    embeddings = model.encode(
        sentence,
        prompt="task: sentence similarity | query: "
    )
    
  2. استخدام الوسيطة prompt_name
    اختَر طلبًا محدّدًا مسبقًا حسب اسمه. يتم تحميل هذه الطلبات من إعدادات النموذج أو أثناء تهيئته.

    embeddings = model.encode(sentence, prompt_name="STS")
    
  3. استخدام الطلب التلقائي
    إذا لم تحدّد prompt أو prompt_name، سيستخدم النظام تلقائيًا الطلب الذي تم ضبطه على default_prompt_name. وإذا لم يتم ضبط أي طلب تلقائي، لن يتم تطبيق أي طلب.

    embeddings = model.encode(sentence)
    
print("Available tasks:")
for name, prefix in model.prompts.items():
  print(f" {name}: \"{prefix}\"")
print("-"*80)

for sentence in [sentence_high, sentence_medium, sentence_low]:
  print("🙋‍♂️")
  print(sentence)
  embeddings = model.encode(sentence, prompt_name="STS")
  similarities = model.similarity(embeddings[0], embeddings[1])
  print("`-> 🤖 score: ", similarities.numpy()[0][0])
Available tasks:
 query: "task: search result | query: "
 document: "title: none | text: "
 BitextMining: "task: search result | query: "
 Clustering: "task: clustering | query: "
 Classification: "task: classification | query: "
 InstructionRetrieval: "task: code retrieval | query: "
 MultilabelClassification: "task: classification | query: "
 PairClassification: "task: sentence similarity | query: "
 Reranking: "task: search result | query: "
 Retrieval: "task: search result | query: "
 Retrieval-query: "task: search result | query: "
 Retrieval-document: "title: none | text: "
 STS: "task: sentence similarity | query: "
 Summarization: "task: summarization | query: "
--------------------------------------------------------------------------------
🙋‍♂️
['The chef prepared a delicious meal for the guests.', 'A tasty dinner was cooked by the chef for the visitors.']
`-> 🤖 score:  0.9363755
🙋‍♂️
['She is an expert in machine learning.', 'He has a deep interest in artificial intelligence.']
`-> 🤖 score:  0.6425841
🙋‍♂️
['The weather in Tokyo is sunny today.', 'I need to buy groceries for the week.']
`-> 🤖 score:  0.38587403

حالة الاستخدام: التوليد المعزّز بالاسترجاع (RAG)

بالنسبة إلى أنظمة الاسترجاع المستند إلى الإنشاء، استخدِم قيم prompt_name التالية لإنشاء عمليات تضمين متخصّصة لطلبات البحث والمستندات:

  • بالنسبة إلى طلبات البحث: استخدِم prompt_name="Retrieval-query".

    query_embedding = model.encode(
        "How do I use prompts with this model?",
        prompt_name="Retrieval-query"
    )
    
  • للمستندات: استخدِم prompt_name="Retrieval-document". لتحسين تضمينات المستندات بشكل أكبر، يمكنك أيضًا تضمين عنوان باستخدام الوسيطة prompt مباشرةً:

    • مع عنوان:
    doc_embedding = model.encode(
        "The document text...",
        prompt="title: Using Prompts in RAG | text: "
    )
    
    • بدون عنوان:
    doc_embedding = model.encode(
        "The document text...",
        prompt="title: none | text: "
    )
    

محتوى إضافي للقراءة

  • للحصول على تفاصيل حول جميع طلبات EmbeddingGemma المتاحة، يُرجى الاطّلاع على بطاقة النموذج.
  • للحصول على معلومات عامة حول نماذج الطلبات، يمكنك الاطّلاع على مستندات Sentence Transformer.
  • للحصول على عرض توضيحي عن RAG، يمكنك الاطّلاع على مثال بسيط على RAG في Gemma Cookbook.

التصنيف

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

من التطبيقات العملية لتصنيف النصوص توجيه تذاكر دعم العملاء. توجّه هذه العملية تلقائيًا استفسارات العملاء إلى القسم المناسب، ما يوفّر الوقت ويقلّل من العمل اليدوي.

labels = ["Billing Issue", "Technical Support", "Sales Inquiry"]

sentence = [
  "Excuse me, the app freezes on the login screen. It won't work even when I try to reset my password.",
  "I would like to inquire about your enterprise plan pricing and features for a team of 50 people.",
]

# Calculate embeddings by calling model.encode()
label_embeddings = model.encode(labels, prompt_name="Classification")
embeddings = model.encode(sentence, prompt_name="Classification")

# Calculate the embedding similarities
similarities = model.similarity(embeddings, label_embeddings)
print(similarities)

idx = similarities.argmax(1)
print(idx)

for example in sentence:
  print("🙋‍♂️", example, "-> 🤖", labels[idx[sentence.index(example)]])
tensor([[0.4673, 0.5145, 0.3604],
        [0.4191, 0.5010, 0.5966]])
tensor([1, 2])
🙋‍♂️ Excuse me, the app freezes on the login screen. It won't work even when I try to reset my password. -> 🤖 Technical Support
🙋‍♂️ I would like to inquire about your enterprise plan pricing and features for a team of 50 people. -> 🤖 Sales Inquiry

Matryoshka Representation Learning (MRL)

تستفيد EmbeddingGemma من MRL لتقديم أحجام تضمين متعددة من نموذج واحد. إنّها طريقة تدريب ذكية تنشئ عملية تضمين واحدة وعالية الجودة يتم فيها تركيز أهم المعلومات في بداية المتّجه.

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

لنستخدم ثلاث كلمات ["apple", "banana", "car"] وننشئ تضمينات مبسطة لمعرفة طريقة عمل MRL.

def check_word_similarities():
  # Calculate the embedding similarities
  print("similarity function: ", model.similarity_fn_name)
  similarities = model.similarity(embeddings[0], embeddings[1:])
  print(similarities)

  for idx, word in enumerate(words[1:]):
    print("🙋‍♂️ apple vs.", word, "-> 🤖 score: ", similarities.numpy()[0][idx])

# Calculate embeddings by calling model.encode()
embeddings = model.encode(words, prompt_name="STS")

check_word_similarities()
similarity function:  cosine
tensor([[0.7510, 0.6685]])
🙋‍♂️ apple vs. banana -> 🤖 score:  0.75102395
🙋‍♂️ apple vs. car -> 🤖 score:  0.6684626

الآن، للحصول على تطبيق أسرع، لست بحاجة إلى نموذج جديد. ما عليك سوى اقتطاع التضمينات الكاملة إلى أول 512 سمة. للحصول على أفضل النتائج، يُنصح أيضًا بضبط normalize_embeddings=True، ما يؤدي إلى تغيير مقياس المتّجهات إلى طول وحدة يبلغ 1.

embeddings = model.encode(words, truncate_dim=512, normalize_embeddings=True)

for idx, embedding in enumerate(embeddings):
  print(f"Embedding {idx+1}: {embedding.shape}")

print("-"*80)
check_word_similarities()
Embedding 1: (512,)
Embedding 2: (512,)
Embedding 3: (512,)
--------------------------------------------------------------------------------
similarity function:  cosine
tensor([[0.7674, 0.7041]])
🙋‍♂️ apple vs. banana -> 🤖 score:  0.767427
🙋‍♂️ apple vs. car -> 🤖 score:  0.7040509

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

model = SentenceTransformer(model_id, truncate_dim=256, similarity_fn_name="dot").to(device=device)
embeddings = model.encode(words, prompt_name="STS", normalize_embeddings=True)

for idx, embedding in enumerate(embeddings):
  print(f"Embedding {idx+1}: {embedding.shape}")

print("-"*80)
check_word_similarities()
Embedding 1: (256,)
Embedding 2: (256,)
Embedding 3: (256,)
--------------------------------------------------------------------------------
similarity function:  dot
tensor([[0.7855, 0.7382]])
🙋‍♂️ apple vs. banana -> 🤖 score:  0.7854644
🙋‍♂️ apple vs. car -> 🤖 score:  0.7382126

الملخّص والخطوات التالية

أنت الآن مجهّز لإنشاء تضمينات نصية عالية الجودة باستخدام EmbeddingGemma ومكتبة Sentence Transformers. يمكنك تطبيق هذه المهارات لإنشاء ميزات فعّالة مثل التشابه الدلالي وتصنيف النصوص وأنظمة التوليد المعزّز بالاسترجاع (RAG)، ومواصلة استكشاف الإمكانات التي توفّرها نماذج Gemma.

يمكنك الاطّلاع على المستندات التالية: