مدلهای سنتی بینایی ماشین با محدودیت دستهبندی بسته (closed-vocabulary) روبهرو هستند؛ اگر مدلی را روی هزار کلاس آموزش داده باشید، اضافه کردن کلاس هزارویکم به جمعآوری داده، برچسبگذاری مجدد و آموزش دوبارهی لایهی خروجی نیاز دارد. مدل CLIP با پیوند دادن زبان طبیعی و تصویر در یک فضای برداری مشترک، این چالش را برای همیشه حل کرد تا بتوانید صرفاً با نوشتن یک جمله، هر مفهوم بصری جدیدی را در زمان اجرا دستهبندی کنید.
امروزه تسکهای مدرن هوش مصنوعی از تشخیص شیء و بخشبندی تصویر گرفته تا بازیابی چندوجهی و مدلهای بینایی-زبان (VLM)، همگی بر پایهی امبدینگهای مشترک سبک CLIP بنا شدهاند. در این درس یاد میگیرید که معماری دوبرجی، تابع زیان تقابلی و ترفندهای مهندسی پرامپت چگونه دستهبندی صفر-شات (zero-shot) را ممکن میکنند و چرا ساختار مدرنتر SigLIP عملکرد بهتری در اندازههای کوچک دسته دادهها ارائه میدهد.
برای اجرای کدهای پایه و پیادهسازی دستهبندی در این درس، نیازی به پردازندههای گرافیکی سنگین نخواهید داشت و محاسبات بهسادگی روی CPU یا تراشههای شخصی قابل انجام است. همچنین بارگیری مدلهای پیشآموزشدیده از طریق کتابخانههای معتبری مثل OpenCLIP و Hugging Face صورت میگیرد که در صورت مواجهه با کندی در بارگیری این وزنها از ایران، استفاده از میرورهای داخلی بستههای پایتون راهکاری کاربردی خواهد بود.
یک انکودر تصویر و یک انکودر متن را همزمان طوری آموزش دهید که جفتهای متناظر (تصویر، کپشن) در فضایی مشترک دقیقاً روی یک نقطه قرار بگیرند. تمام ترفند کار همین است.
اهداف یادگیری
- تشریح معماری دوبرجی (two-tower architecture) در CLIP و تابع هدف آموزش تقابلی (contrastive training) آن
- استفاده از CLIP (یا SigLIP) پیشآموزشدیده برای دستهبندی صفر-شات (zero-shot classification) بدون نیاز به هیچگونه آموزش اختصاصی برای تسک
- پیادهسازی دستهبندی صفر-شات از صفر: انکود پرامپتهای کلاس، محاسبهی شباهت کسینوسی (cosine similarity) و گرفتن argmax
- تشخیص تفاوتهای CLIP، SigLIP، OpenCLIP و مدلهای LLaVA/LLaMA-vision — و کاربرد هرکدام در سال 2026
صورت مسئله
دستهبندهای سنتی دامنهی واژگان بستهای دارند (closed-vocabulary): مدلی که روی 1000 کلاس ImageNet آموزش دیده، فقط میتواند همین 1000 برچسب را پیشبینی کند. هر دستهی جدید به دادههای برچسبخورده و آموزش دوبارهی لایهی خروجی (head) نیاز دارد.
مدل CLIP (ارائهشده توسط Radford و همکاران، OpenAI در سال 2021) نشان داد که با آموزش روی 400 میلیون جفت (تصویر، کپشن) جمعآوریشده از وب، مدلی به دست میآید که در زمان استنتاج، میتواند هر مجموعهای از دستهها را صرفاً با توصیف متنی به زبان طبیعی دستهبندی کند. کافی است با نوشتن یک جمله، کلاس جدیدی به آن معرفی کنید.
همین قابلیت — یعنی انتقال صفر-شات (zero-shot transfer) — دلیل اصلی این است که امروزه تقریباً تمام سیستمهای بینایی ماشین با یک چکپوینت از خانوادهی CLIP کارشان را شروع میکنند. تشخیص شیء (Grounding DINO، OWL-ViT)، بخشبندی تصویر (CLIPSeg، SAM)، بازیابی (retrieval)، مدیریت محتوا، مدلهای چندوجهی زبان و تصویر (VLM) و مدلهای تولید تصویر از متن، همگی بر پایهی امبدینگهای مشترک سبک CLIP بنا شدهاند.
مفاهیم کلیدی
دو برج
هر دو انکودر به یک لایهی تصویر کردن خطی (linear projection) با بُعد امبدینگ یکسان ختم میشوند (512 برای CLIP-B/32 و 1024 برای CLIP-L/14). سپس بردارها نرمالسازی L2 میشوند و شباهت کسینوسی آنها محاسبه میشود.
تابع هدف
با داشتن یک بچ شامل جفت (تصویر، کپشن)، یک ماتریس شباهت میسازیم. هر دو انکودر را طوری آموزش میدهیم که قطر اصلی (جفتهای متناظر) بیشترین شباهت و درایههای غیرقطری (جفتهای نامرتبط) کمترین شباهت را داشته باشند.
sim_matrix = image_embeddings @ text_embeddings.T / tau
loss_i2t = cross_entropy(sim_matrix, targets=arange(N))
loss_t2i = cross_entropy(sim_matrix.T, targets=arange(N))
loss = (loss_i2t + loss_t2i) / 2
این فرمول متقارن است؛ چون بازیابی تصویر-به-متن و متن-به-تصویر باید هر دو بهدرستی کار کنند. پارامتر tau (دما یا temperature) معمولاً یک اسکالر قابلیادگیری با مقدار اولیهی 0.07 است.
مدل SigLIP: تابع زیانی بهتر
مدل SigLIP (توسط Zhai و همکاران، 2023) تابع سافتمکس (softmax) را با یک تابع سیگموئید مجزا به ازای هر جفت جایگزین کرد:
محاسبهی تابع زیان (loss) بهازای هر جفت، نیاز به نرمالسازی در سطح کل بچ را — که CLIP به آن وابسته بود — از بین میبرد. SigLIP با اندازهی بچ کوچکتر بهتر آموزش میبیند و با دادهی یکسان، عملکردی همتراز یا حتی بهتر از CLIP ثبت میکند.
دستهبندی صفر-شات
وقتی یک CLIP آموزشدیده در اختیار دارید:
- برای هر کلاس، یک پرامپت میسازید: "a photo of a {class}".
- همهی پرامپتهای کلاسها را با انکودر متن انکود میکنید -> خروجی
Tبا ابعاد (C, d). - تصویر تست را انکود میکنید -> خروجی
Iبا ابعاد (1, d). - محاسبهی شباهت:
I @ T.Tبا ابعاد (1, C). - گرفتن Argmax -> کلاس پیشبینیشده.
مهندسی پرامپت اهمیت زیادی دارد. OpenAI تعداد 80 قالب پرامپت برای ImageNet منتشر کرده است ("a photo of a {}", "a blurry photo of a {}", "a sketch of a {}", ...). اگر از امبدینگهای همهی این قالبها برای هر کلاس میانگین بگیرید، دقت top-1 بین 1 تا 3 درصد بهتر میشود.
کاربرد مدلهای سبک CLIP در سال 2026
- دستهبندی صفر-شات — استفادهی مستقیم.
- بازیابی تصویر — یک بار انکود کردن تمام تصاویر و محاسبهی امبدینگ پرسمان در زمان استنتاج.
- تشخیص شیء مبتنی بر متن — مدلهایی مثل Grounding DINO و OWL-ViT که یک برج متنی CLIP را به دتکتور متصل میکنند.
- بخشبندی مبتنی بر متن — مدل CLIPSeg؛ مدل SAM نیز پرامپتهای متنی ورودی را از طریق CLIP دریافت میکند.
- مدلهای بینایی-زبان (VLM) — مدلهای LLaVA، Qwen-VL و InternVL که انکودر تصویر خانوادهی CLIP را به یک LLM پیوند میزنند.
- تولید تصویر از متن — مدلهای Stable Diffusion و DALL-E 3 که خروجی خود را بر اساس امبدینگهای متنی CLIP شرطیسازی میکنند.
به محض اینکه یک فضای امبدینگ مشترک داشته باشید، هر تسک بینایی + زبان به یک محاسبهی فاصلهی ساده تبدیل میشود.
پیادهسازی عملی
گام 1: یک مدل دوبرجی بسیار کوچک
مدل واقعی CLIP از ترکیب ViT و ترنسفورمر متنی ساخته شده است. در این درس، برجها را MLPهای کوچکی روی ویژگیهای از پیش استخراجشده در نظر میگیریم تا روند آموزش حتی روی CPU هم ملموس و قابلمشاهده باشد.
import torch
import torch.nn as nn
import torch.nn.functional as F
class TwoTower(nn.Module):
def __init__(self, img_in=128, txt_in=64, emb=64):
super().__init__()
self.image_proj = nn.Sequential(nn.Linear(img_in, 128), nn.ReLU(), nn.Linear(128, emb))
self.text_proj = nn.Sequential(nn.Linear(txt_in, 128), nn.ReLU(), nn.Linear(128, emb))
self.logit_scale = nn.Parameter(torch.ones([]) * 2.6592) # ln(1/0.07)
def forward(self, img_feats, txt_feats):
i = F.normalize(self.image_proj(img_feats), dim=-1)
t = F.normalize(self.text_proj(txt_feats), dim=-1)
return i, t, self.logit_scale.exp()
دو تصویر، خروجی با ابعاد مشترک و دمای قابلیادگیری؛ ساختاری دقیقاً مطابق با API واقعی CLIP.
گام 2: تابع زیان تقابلی
def clip_loss(image_emb, text_emb, logit_scale):
N = image_emb.size(0)
sim = logit_scale * image_emb @ text_emb.T
targets = torch.arange(N, device=sim.device)
l_i = F.cross_entropy(sim, targets)
l_t = F.cross_entropy(sim.T, targets)
return (l_i + l_t) / 2
فرمول متقارن است. مقدار بالاتر logit_scale یعنی سافتمکس تیزتر و در نتیجه پیشبینیهای بااطمینانتر، اما خطر ناپایداری آموزش هم بیشتر میشود.
گام 3: دستهبند صفر-شات
@torch.no_grad()
def zero_shot_classify(model, image_feats, class_text_feats, class_names):
"""
image_feats: (N, img_in)
class_text_feats: (C, txt_in) one averaged embedding per class
"""
i = F.normalize(model.image_proj(image_feats), dim=-1)
t = F.normalize(model.text_proj(class_text_feats), dim=-1)
sim = i @ t.T
pred = sim.argmax(dim=-1)
return [class_names[p] for p in pred.tolist()]
هر مرحله در یک خط. این دقیقاً همان فرایند صفر-شاتی است که در محیطهای پروداکشن با چکپوینتهای CLIP اجرا میشود.
گام 4: بررسی اولیهی صحت عملکرد (Sanity check)
torch.manual_seed(0)
model = TwoTower()
img = torch.randn(8, 128)
txt = torch.randn(8, 64)
i, t, scale = model(img, txt)
loss = clip_loss(i, t, scale)
print(f"batch size: {i.size(0)} loss: {loss.item():.3f}")
مقدار تابع زیان (loss) برای مدلی با وزنهای تصادفی باید نزدیک به log(N) = log(8) = 2.08 باشد؛ یعنی همان مقدار هدف در آنتروپی متقاطع (cross-entropy) متقارن، زمانی که هنوز هیچ ساختاری در دادهها یاد گرفته نشده است.
استفادهی کاربردی
در سال 2026، کتابخانهی OpenCLIP انتخاب اول جامعهی متنباز است:
import open_clip
import torch
from PIL import Image
model, _, preprocess = open_clip.create_model_and_transforms("ViT-B-32", pretrained="laion2b_s34b_b79k")
tokenizer = open_clip.get_tokenizer("ViT-B-32")
image = preprocess(Image.open("dog.jpg")).unsqueeze(0)
text = tokenizer(["a photo of a dog", "a photo of a cat", "a photo of a car"])
with torch.no_grad():
image_features = model.encode_image(image)
text_features = model.encode_text(text)
image_features = image_features / image_features.norm(dim=-1, keepdim=True)
text_features = text_features / text_features.norm(dim=-1, keepdim=True)
probs = (100.0 * image_features @ text_features.T).softmax(dim=-1)
print(probs)
مدل SigLIP جدیدتر است، در مقیاسهای کوچکتر بهتر آموزش میبیند و برای پروژههای تازه گزینهی بهتری به شمار میرود: google/siglip-base-patch16-224. پلتفرم Hugging Face از هر دو پشتیبانی میکند.
تحویل پروژه
در این درس فایلهای زیر را تولید میکنید:
outputs/prompt-zero-shot-class-picker.md— پرامپتی که بر اساس فهرست کلاسها و حوزهی کاری، قالبهای کلاسی مناسب را برای صفر-شات در CLIP طراحی میکند.outputs/skill-image-text-retriever.md— مهارتی که یک نمایهی امبدینگ تصویر با هر چکپوینت دلخواه CLIP میسازد و از جستوجو با متن و تصویر پشتیبانی میکند.
تمرینها
- (ساده) با استفاده از مدل پیشآموزشدیدهی OpenCLIP ViT-B/32 و مجموعهی پرامپتهای 80 قالبی، دستهبندی صفر-شات را روی CIFAR-10 اجرا کنید. دقت top-1 را گزارش دهید؛ این عدد باید حدود 85 تا 90 درصد باشد.
- (متوسط) روی همان مجموعهی CIFAR-10، عملکرد پرامپت تکقالبی ("a photo of a {}") را با میانگین امبدینگهای 80 قالب مقایسه کنید. این اختلاف را بهصورت دقیق اندازه بگیرید و توضیح دهید چرا قالبهای چندگانه باعث بهبود نتایج میشوند.
- (سخت) یک نمایهی بازیابی تصویر صفر-شات بسازید: 1000 تصویر را با CLIP امبد کنید، یک ایندکس FAISS بسازید و با توصیفهای زبان طبیعی آن را جستوجو کنید. نرخ بازخوانی (recall@5) را برای 20 پرسمان دستنویس مجزا گزارش دهید.
اصطلاحات کلیدی
| اصطلاح | در گفتگوها | معنای دقیق فنی |
|---|---|---|
| Two-tower | «انکودر دوگانه» | انکودرهای مجزا برای تصویر و متن که به یک لایهی تصویر کردن (projection head) با ابعاد مشترک ختم میشوند |
| Zero-shot | «بدون آموزش اختصاصی تسک» | دستهبندی روی کلاسهایی که در زمان استنتاج فقط با متن توصیف شدهاند؛ بدون نیاز به تغییر یا مشاهدهی برچسبها |
| Temperature / logit_scale | «پارامتر tau» | اسکالر قابلیادگیری که ماتریس شباهت را قبل از سافتمکس مقیاسبندی میکند |
| Prompt template | «A photo of a {}» | قالبی به زبان طبیعی دور نام کلاسها؛ میانگینگیری از چندین قالب دقت صفر-شات را بالاتر میبرد |
| CLIP | «مدل تصویر+متن» | مدل عرضهشده توسط OpenAI در سال 2021؛ زبان مشترک این حوزه در سال 2026 |
| SigLIP | «مدل Sigmoid CLIP» | جایگزین کردن سافتمکس با تابع سیگموئید بهازای هر جفت؛ آموزش بهتر در بچهای کوچکتر |
| OpenCLIP | «بازتولید متنباز» | مدلهای بازتولیدشدهی CLIP توسط جامعهی متنباز روی مجموعهدادهی LAION؛ گزینهی پیشفرض در پایپلاینهای پروداکشن |
| VLM | «مدل بینایی-زبان» | انکودری از خانوادهی CLIP متصل به یک LLM که برای پاسخ دادن به پرسشها دربارهی تصویر آموزش دیده است |
مطالعهی بیشتر
- CLIP: Learning Transferable Visual Models from Natural Language Supervision (Radford et al., 2021)
- SigLIP: Sigmoid Loss for Language-Image Pre-Training (Zhai et al., 2023)
- OpenCLIP — مخزن کدهای متنباز جامعهی هوش مصنوعی
- Oquab et al. (2023). DINOv2: Learning Robust Visual Features without Supervision — مقالهی پژوهشی همراه با بنچمارک استخراج ویژگی در مقایسه با مدلهای خانوادهی CLIP و MAE
