Embedding — وقتی متن تبدیل به عدد می‌شه

قسمت ۳ ۲۰ دقیقه

Embedding — وقتی متن تبدیل به عدد می‌شه

توی اپیزود قبلی دیدیم که RAG سه مرحله داره: بازیابی، تقویت و تولید. ولی یه سؤال مهم جواب نگرفت: توی مرحله بازیابی، سیستم چطور می‌فهمه کدوم قطعه متن به سؤال کاربر مرتبطه؟

جواب یه کلمه‌ست: Embedding.

Embedding فرآیند تبدیل متن به اعداد (بردار) هست، به شکلی که معنای متن حفظ بشه. این یکی از مهم‌ترین مفاهیم توی دنیای NLP و RAG هست. بذار قدم به قدم بریم جلو.

مشکل: کامپیوتر زبان نمی‌فهمه

کامپیوتر فقط با عدد کار می‌کنه. وقتی بهش میگی «سگ»، هیچ درکی از این کلمه نداره. براش فقط یه رشته کاراکتره: س + گ.

اولین تلاش‌ها برای نمایش کلمات ساده بود: به هر کلمه یه عدد بده. مثلاً سگ = ۱، گربه = ۲، ماشین = ۳. ولی این روش یه مشکل بزرگ داره: هیچ اطلاعاتی از معنا و رابطه بین کلمات نمی‌ده.

توی این سیستم، فاصله «سگ» تا «گربه» برابره با فاصله «سگ» تا «ماشین». ولی ما می‌دونیم سگ و گربه خیلی بیشتر به هم مرتبطن تا سگ و ماشین.

تشبیه آدرس توی شهر معنا

بهترین تشبیهی که برای Embedding وجود داره، تشبیه آدرس توی یه شهر هست.

فرض کن یه شهر خیالی داریم به اسم «شهر معنا». توی این شهر:

  • کلمات مرتبط نزدیک هم زندگی می‌کنن
  • کلمات بی‌ربط دور از هم زندگی می‌کنن
  • هر کلمه یه آدرس دقیق داره (مختصات عددی)

مثلاً:

  • «سگ» و «گربه» توی یه محله‌ن (محله حیوانات خانگی)
  • «پاریس» و «لندن» توی محله شهرهای اروپایی‌ن
  • «شاد» و «خوشحال» تقریباً هم‌خانه‌ن
  • «سگ» و «دموکراسی» توی دو سر شهرن

Embedding یعنی پیدا کردن آدرس هر کلمه (یا جمله، یا پاراگراف) توی این شهر معنا. این آدرس یه لیست از اعداده. هر چی دو تا آدرس به هم نزدیک‌تر باشن، معنای اون دو تا متن به هم شبیه‌تره.

البته این شهر خیالی سه‌بعدی نیست. ممکنه ۱۵۳۶ بعدی باشه! ولی ایده‌ش همونه: هر متن یه نقطه توی یه فضای چندبعدی هست و فاصله بین نقاط نشون‌دهنده شباهت معنایی‌شونه.

Embedding در عمل چطوری به نظر میاد؟

بذار یه مثال واقعی ببینیم. وقتی جمله «گربه روی تشک نشسته» رو به یه مدل Embedding بدی، خروجیش یه چیزی شبیه اینه:

# خروجی واقعی یه مدل Embedding (خلاصه‌شده)
embedding = [0.023, -0.041, 0.089, 0.012, -0.067, 0.045, ...]
# در واقعیت ۱۵۳۶ عدد (برای مدل text-embedding-3-small)

هر کدوم از این اعداد یه بعد از معنای متن رو نشون میده. مثلاً یه بعد ممکنه «حیوانی بودن» رو نشون بده، یه بعد دیگه «مکانی بودن» رو، یه بعد دیگه «احساسی بودن» رو. البته تفسیر دقیق هر بعد معمولاً ممکن نیست، ولی مجموع همه ابعاد، معنای کلی متن رو کدگذاری می‌کنه.

محاسبات برداری — جادوی Embedding

یکی از جالب‌ترین خاصیت‌های Embedding اینه که محاسبات ریاضی روی بردارها، معنادار هستن. معروف‌ترین مثال:

king - man + woman ≈ queen
پادشاه - مرد + زن ≈ ملکه

یعنی اگه بردار کلمه «king» رو بگیری، بردار «man» رو ازش کم کنی و بردار «woman» رو بهش اضافه کنی، بردار نتیجه خیلی نزدیک به بردار «queen» میشه!

چند مثال دیگه:

Paris - France + Italy ≈ Rome
پاریس - فرانسه + ایتالیا ≈ رم

big - small + cold ≈ hot
بزرگ - کوچک + سرد ≈ گرم (رابطه تضاد حفظ میشه)

این نشون میده که Embedding واقعاً معنا رو درک کرده، نه فقط حروف و کلمات رو.

چرا این مهمه برای RAG؟ چون وقتی کاربر بپرسه «چطور اپلیکیشن رو نصب کنم؟» و توی مستنداتت نوشته «راهنمای Installation نرم‌افزار»، سیستم Embedding می‌فهمه که اینا به هم مرتبطن. حتی با وجود اینکه هیچ کلمه مشترکی ندارن.

Cosine Similarity — اندازه‌گیری شباهت

حالا که هر متن یه بردار شد، چطور بفهمیم دو تا متن چقدر به هم شبیهن؟ متداول‌ترین روش Cosine Similarity (شباهت کسینوسی) هست.

ایده‌ش ساده‌ست: زاویه بین دو بردار رو اندازه بگیر.

  • اگه دو بردار هم‌جهت باشن (زاویه ۰ درجه): شباهت = ۱ (کاملاً شبیه)
  • اگه عمود باشن (زاویه ۹۰ درجه): شباهت = ۰ (بی‌ربط)
  • اگه مخالف باشن (زاویه ۱۸۰ درجه): شباهت = -۱ (کاملاً متضاد)
import numpy as np

def cosine_similarity(vec1, vec2):
    """محاسبه شباهت کسینوسی بین دو بردار"""
    dot_product = np.dot(vec1, vec2)
    norm1 = np.linalg.norm(vec1)
    norm2 = np.linalg.norm(vec2)
    return dot_product / (norm1 * norm2)

# مثال
similarity = cosine_similarity(
    embed("گربه روی تشک نشسته"),
    embed("یه بچه گربه روی فرش دراز کشیده")
)
# similarity ≈ 0.92 (خیلی شبیه!)

similarity = cosine_similarity(
    embed("گربه روی تشک نشسته"),
    embed("نرخ تورم در سال ۱۴۰۳")
)
# similarity ≈ 0.11 (بی‌ربط)

توی RAG، وقتی کاربر سؤالی می‌پرسه، سؤال رو تبدیل به بردار می‌کنیم و بعد Cosine Similarity بین بردار سؤال و بردار همه قطعات مستندات رو محاسبه می‌کنیم. قطعاتی که بیشترین شباهت رو دارن، مرتبط‌ترین‌ها هستن.

مدل‌های Embedding مطرح

چندین مدل Embedding وجود داره که هر کدوم مزایا و معایب خودشون رو دارن. بذار مهم‌ترین‌ها رو بررسی کنیم:

۱. OpenAI text-embedding-3-small و text-embedding-3-large

  • ابعاد: ۱۵۳۶ (small) و ۳۰۷۲ (large)
  • کیفیت بالا، خصوصاً برای انگلیسی
  • API-based (نیاز به اینترنت و هزینه)
  • قابلیت کاهش ابعاد (Matryoshka Embedding)

۲. Cohere embed-v3

  • ابعاد: ۱۰۲۴
  • پشتیبانی عالی از چندزبانگی (از جمله فارسی)
  • قابلیت تفکیک بین جستجو و ذخیره‌سازی
  • API-based

۳. مدل‌های Open-Source

  • BGE (BAAI General Embedding): یکی از بهترین مدل‌های رایگان، توسط آکادمی علوم چین
  • E5: توسط مایکروسافت، عملکرد عالی
  • Instructor: قابلیت سفارشی‌سازی با دستورالعمل
  • all-MiniLM-L6-v2: سبک و سریع، مناسب برای شروع

نکته مهم درباره فارسی: اکثر مدل‌های Embedding روی متن انگلیسی بهترین عملکرد رو دارن. برای فارسی، مدل‌های multilingual مثل Cohere embed-v3 یا multilingual-e5-large گزینه‌های بهتری هستن. حتماً قبل از استفاده، مدل رو روی داده‌های فارسی تست کن.

چطور Embedding تولید کنیم؟

بذار یه مثال عملی ببینیم با OpenAI:

from openai import OpenAI

client = OpenAI()

def get_embedding(text, model="text-embedding-3-small"):
    """تبدیل متن به بردار با OpenAI"""
    response = client.embeddings.create(
        input=text,
        model=model
    )
    return response.data[0].embedding

# یه متن ساده
embedding = get_embedding("سلام! امروز هوا خیلی خوبه.")
print(f"تعداد ابعاد: {len(embedding)}")  # 1536
print(f"چند عدد اول: {embedding[:5]}")
# [0.023, -0.041, 0.089, 0.012, -0.067]

و با مدل open-source:

from sentence_transformers import SentenceTransformer

# بارگذاری مدل (فقط بار اول دانلود میشه)
model = SentenceTransformer("all-MiniLM-L6-v2")

# تولید Embedding
texts = [
    "هوش مصنوعی داره دنیا رو تغییر میده",
    "AI is transforming the world",
    "قیمت دلار امروز"
]

embeddings = model.encode(texts)
print(f"شکل خروجی: {embeddings.shape}")  # (3, 384)

# محاسبه شباهت
from sklearn.metrics.pairwise import cosine_similarity
similarities = cosine_similarity(embeddings)
print(similarities)
# جمله ۱ و ۲ شباهت بالایی دارن (ترجمه همن)
# جمله ۳ با بقیه شباهت کمی داره

Embedding برای جملات vs کلمات

یه نکته مهم: مدل‌های قدیمی مثل Word2Vec فقط برای کلمات تکی Embedding تولید می‌کردن. ولی مدل‌های جدید می‌تونن برای جملات، پاراگراف‌ها و حتی مستندات کامل هم Embedding تولید کنن.

توی RAG، معمولاً Embedding در سطح قطعه متن (Chunk) تولید میشه. یه قطعه ممکنه یه پاراگراف، چند جمله، یا یه بخش از مستند باشه.

فرق مهم:

  • Word Embedding (مثل Word2Vec): هر کلمه یه بردار ثابت داره. «بانک» همیشه یه بردار داره، چه منظور بانک پول باشه چه بانک رودخانه.
  • Contextual Embedding (مثل BERT, OpenAI): بردار هر کلمه بسته به جمله‌ای که توشه فرق می‌کنه. «بانک» توی «رفتم بانک پول بگیرم» بردار متفاوتی داره از «بانک» توی «کنار بانک رودخانه نشستم».

برای RAG، حتماً از Contextual Embedding استفاده کن.

ابعاد Embedding: بیشتر بهتره؟

مدل‌های مختلف ابعاد مختلفی دارن:

  • all-MiniLM-L6-v2: ۳۸۴ بعد
  • text-embedding-3-small: ۱۵۳۶ بعد
  • text-embedding-3-large: ۳۰۷۲ بعد

آیا بیشتر بهتره؟ لزوماً نه.

  • ابعاد بیشتر = اطلاعات بیشتر = دقت بالاتر (معمولاً)
  • ولی ابعاد بیشتر = حافظه بیشتر = جستجوی کندتر = هزینه بیشتر

باید یه تعادل پیدا کنی. برای اکثر کاربردها، ۱۵۳۶ بعد کافیه. اگه دیتاست خیلی بزرگه و حافظه مهمه، ۳۸۴ بعد هم می‌تونه خوب کار کنه.

Matryoshka Embedding: مدل‌های جدید OpenAI از تکنیکی به اسم Matryoshka استفاده می‌کنن. مثل عروسک‌های روسی تودرتو، می‌تونی ابعاد رو کم کنی بدون اینکه مدل رو دوباره آموزش بدی. مثلاً بردار ۱۵۳۶ بعدی رو ببری به ۵۱۲ بعد و همچنان کیفیت خوبی داشته باشی.

هزینه Embedding

اگه از API استفاده کنی، هزینه Embedding معمولاً خیلی کمتر از هزینه تولید متنه:

  • OpenAI text-embedding-3-small: حدود $0.02 به ازای هر ۱ میلیون توکن
  • OpenAI text-embedding-3-large: حدود $0.13 به ازای هر ۱ میلیون توکن
  • Cohere embed-v3: حدود $0.10 به ازای هر ۱ میلیون توکن
  • مدل‌های open-source: رایگان (فقط هزینه سرور)

برای یه پروژه با ۱۰ هزار مستند (هر کدوم ۱۰۰۰ کلمه)، هزینه Embedding با OpenAI small حدود $0.30 میشه. خیلی ارزونه.

نکات عملی

چند تا نکته که توی پیاده‌سازی به کارت میاد:

۱. یه مدل رو برای همه چیز استفاده کن: بردار سؤال و بردار مستندات باید با یه مدل تولید بشن. اگه مستندات رو با OpenAI Embed کنی و سؤال رو با Cohere، نتایج بی‌معنی میشه.

۲. Normalize کن: بعضی مدل‌ها بردارهای Normalize نشده برمی‌گردونن. حتماً قبل از محاسبه شباهت، بردارها رو Normalize کن.

۳. Batch processing: اگه هزاران مستند داری، بردارها رو دسته‌ای تولید کن. هم سریع‌تره، هم ارزون‌تره.

۴. Cache کن: بردار هر متن رو فقط یه بار تولید کن و ذخیره کن. دفعه بعد نیازی به تولید دوباره نیست (مگه متن عوض بشه).

۵. تست کن: قبل از انتخاب مدل، چند مدل رو روی داده‌های واقعیت تست کن. نتایج ممکنه شگفت‌انگیز باشه.

# مثال Batch Embedding با OpenAI
texts = ["متن اول", "متن دوم", "متن سوم", ...]

response = client.embeddings.create(
    input=texts,  # تا ۲۰۴۸ متن همزمان
    model="text-embedding-3-small"
)

embeddings = [item.embedding for item in response.data]

جمع‌بندی

توی این اپیزود یاد گرفتی:

  • Embedding یعنی تبدیل متن به بردار عددی با حفظ معنا
  • مثل آدرس دادن به کلمات توی شهر معنا
  • محاسبات ریاضی روی بردارها معنادارن (king – man + woman = queen)
  • Cosine Similarity برای اندازه‌گیری شباهت استفاده میشه
  • مدل‌های مختلفی وجود داره: OpenAI، Cohere، و open-source
  • برای فارسی، مدل‌های multilingual بهتر کار می‌کنن

توی اپیزود بعدی میریم سراغ Vector Database — جایی که این بردارها ذخیره و جستجو میشن. یاد می‌گیری چرا دیتابیس‌های معمولی کافی نیستن و کدوم Vector Database رو انتخاب کنی.

نظرات

هنوز نظری ثبت نشده. اولین نفر باشید!

نظر خود را بنویسید