چیت‌شیت

ساخت یک VLM از صفر

Build a VLM from Scratch

امبدینگ پچ، انکودر ViT، تصویرساز MLP، دیکودر کراس‌اتنشن، پیش‌آموزش InfoNCE به‌همراه LM، معیارهای R@K، EM و BLEU-4.

  • ۱۱ بخش
  • ۶ درس مرتبط
  • کد و دستورها عیناً از دوره‌ی اصلی
فهرست مطالب
  1. استک VLM
  2. اجرای هر درس
  3. ساخت و انکود
  4. هم‌ترازسازی، ادغام و پیش‌آموزش
  5. اتنشن در یک VLM
  6. یک گام پیش‌آموزش
  7. ابعاد و اعداد
  8. ارزیابی مدل
  9. پیش‌فرض‌های پیکربندی
  10. خطاها و راه‌حل‌ها
  11. پرسش‌ها

استک VLM

معماری
197 توکنCLSکلیدها (K) و مقادیر (V) حافظهپرس‌وجوها (queries)image_embلاجیت‌هاتصویر224x224x3PatchEmbedConv2d, 196 tokens + CLSViT12 بلوک، 12 هد، پیش‌نرمال‌سازی لایه‌ای (pre-LN)MLPProjectorخطی، GELU، خطیشناسه‌های کپشنجدول متن میانگین‌گیری‌شده (mean-pooled)دیکودرخوداتنشن علّی + کراس‌اتنشنتوابع زیان (Losses)InfoNCE + LM

اجرای هر درس

دستورها
دستورعملکرد
`python3 code/main.py` (58)توکن‌هایی با ابعاد (1, 197, 768). تطابق Unfold با Conv2d
`python3 code/main.py` (59)انکود به (1, 197, 768). حدود 86 میلیون پارامتر
`python3 code/main.py` (60)200 گام. کاهش تابع زیان از حدود 1.07 به حدود 0.80
`python3 code/main.py` (61)لاجیت‌های (2, 10, text_vocab)، ماسک (10, 10)، بررسی کش
`python3 code/main.py` (62)50 گام. کاهش زیان تطبیقی از 2.77 به 2.4. کاهش LM از 6.24 به 4.7
`python3 code/main.py` (63)معیارها قبل و بعد از 50 گام آموزش
python3 -m unittest code/test_main.pyاجرای تست‌های یک درس

ساخت و انکود

کد
python
cfg = ViTConfig()                         # 224، 16، 768، عمق 12، 12 هد
encoder = VisionEncoder(cfg).eval()       # فرانت‌اند به‌همراه استک ViT
img = synthesize_image(seed=0)            # (1, 3, 224, 224) in [0, 1]
tokens, cls = encoder(img)                # (1, 197, 768) and (1, 768)
pos = sinusoidal_2d(grid_h, grid_w, dim)  # dim بخش‌پذیر بر 4
ref = unfold_then_linear(img, weight, bias, cfg.patch_size)
nn.Conv2d(cfg.in_channels, cfg.hidden,
          kernel_size=cfg.patch_size, stride=cfg.patch_size)
x = x + self.attn(self.ln1(x))            # باقیمانده‌ی پیش‌نرمال‌سازی لایه‌ای (pre-LN residual)
x = x + self.ffn(self.ln2(x))             # GELU MLP، با عرض 4x

هم‌ترازسازی، ادغام و پیش‌آموزش

کد
python
projector = MLPProjector(cfg.vision_hidden, cfg.projection_hidden, cfg.text_hidden)
freeze(encoder)                                     # requires_grad_(False)
loss = cosine_alignment_loss(image_emb, text_emb)   # mean of 1 - cos
mask = causal_mask(10)                              # (10, 10) lower triangle
logits = decoder(text_ids, memory, use_cache=True)  # کش شدن K و V تصویر
contrast, sim = info_nce_loss(image_emb, text_emb, self.log_tau)
lm = lm_loss(logits, targets, padding_id=PAD_ID)    # مقدار PAD_ID برابر 0 است
total = contrast + cfg.lm_weight * lm

اتنشن در یک VLM

مقایسه
عاملخوداتنشن ViTخوداتنشن دیکودرکراس‌اتنشن
Queryتوکن‌های تصویرتوکن‌های متنتوکن‌های متن
Keys و Valuesتوکن‌های تصویرتوکن‌های متنتوکن‌های حافظه تصویر
ماسکبدون ماسکعلّی (Nt, Nt)بدون ماسک
ابعاد خروجی(B, 197, 768)(B, Nt, hidden)(B, Nt, hidden)
دلیلفقط-انکودر و دوطرفهعدم نگاه‌به‌جلو در خودبازگشتقابل مشاهده بودن کل تصویر
کشاستفاده نمی‌شوداستفاده نمی‌شودمحاسبه K و V تصویر یک‌بار به ازای هر تصویر

یک گام پیش‌آموزش

گام‌به‌گام
  1. نمونه‌گیرانتخاب 16 جفت بدون جایگذاری از پیکره متنی 200 جفتی.
  2. انکودربرگرداندن توکن‌های حافظه و امبدینگ تصویر تصویرشده.
  3. بخش متنمیانگین‌گیری از شناسه‌های امبدشده کپشن به text_emb.
  4. InfoNCEنرمال‌سازی L2 هر دو. آنتروپی متقاطع روی سطرها و ستون‌ها، سپس میانگین‌گیری.
  5. دیکودرخواندن text_ids[:, :-1] و پیش‌بینی text_ids[:, 1:].
  6. تابع زیان LMآنتروپی متقاطع که شناسه پدینگ 0 را نادیده می‌گیرد.
  7. Adamاعمال گام بهینه‌سازی روی contrast + lm_weight * lm. چاپ خروجی هر 5 گام یک‌بار.

ابعاد و اعداد

مفهوم‌ها
پچ‌ها
تقسیم 224 بر 16 یک شبکه 14x14 شامل 196 پچ با 768 مقدار می‌دهد.
هزینه اتنشن
196 توکن، 38,416 امتیاز به ازای هر هد در هر لایه تولید می‌کند.
تصویر
590,592 پارامتر برای ViT-Base/16. توکن CLS مقدار 768 پارامتر اضافه می‌کند.
ابعاد هر هد
تقسیم 768 بر 12 هد، 64 می‌دهد.
به ازای هر بلوک
حدود 7.1 میلیون. 12 بلوک حدود 85 میلیون. انکودر حدود 86 میلیون.
تصویرساز
حدود 1.3 میلیون برای یک هد 768 -> 1024 -> 512.
تابع زیان کسینوسی
0 در صورت هم‌راستایی، 2 در جهت مخالف.
معیار R@K تصادفی، N=50
مقدار R@1 برابر 0.02، مقدار R@5 برابر 0.10، مقدار R@10 برابر 0.20.

ارزیابی مدل

کار و کد
وظیفهکد
ساخت مجموعه ارزیابیbuild_eval_suite(seed, n_samples, vocab_size, max_len)
بازخوانی تصویر و متنi2t, t2i = recall_at_k(sim, k)
دقت VQAvqa_exact_match(predictions, references)
امتیاز کپشن‌نویسیbleu4(generated, references, smoothing=True)
هر سه معیارevaluate(model, suite)
آموزش بین ارزیابی‌هاcontrast, lm, _ = model(imgs, ids)

پیش‌فرض‌های پیکربندی

پیش‌فرض‌ها
تنظیمپیش‌فرضنکته
`image_size`, `patch_size`224پچ 16، hidden برابر 768
`depth`, `heads`12mlp_ratio برابر 4.0، اپسیلون LayerNorm برابر 1e-6
Align `steps`20032 جفت، lr برابر 3e-4
projection_hidden1024text_hidden برابر 512
Decoder `hidden`2568 هد، عمق 4، 197 توکن دیداری
Pretrain `batch_size`1650 گام، lr برابر 5e-4
lm_weight1.0وزن تابع زیان LM
init_log_taumath.log(1.0 / 0.07)محدود شدن مقیاس بین 1e-3 و 100.0

خطاها و راه‌حل‌ها

عیب‌یابی
  • patch_size ... must divide image_size

    علت
    شبکه کامل نیست
    راه‌حل
    اندازه پچی انتخاب کنید که تصویر بر آن بخش‌پذیر باشد
  • spatial mismatch از PatchEmbed

    علت
    تفاوت اندازه ورودی با پیکربندی
    راه‌حل
    تغییر اندازه تصویر به image_size
  • sinusoidal_2d dim must be divisible by 4

    علت
    اندازه مخفی مضرب 4 نیست
    راه‌حل
    استفاده از اندازه مخفیِ بخش‌پذیر بر 4
  • hidden ... not divisible by heads

    علت
    ابعاد هد عدد صحیح نیست
    راه‌حل
    انتخاب تعداد هدهایی که اندازه مخفی بر آن بخش‌پذیر باشد
  • could not load lesson 58 main.py

    علت
    پوشه‌های درس جابه‌جا شده‌اند
    راه‌حل
    پوشه‌های هم‌سطح درس را در جای خود نگه‌دارید
  • causal mask shape ... does not match

    علت
    ماسک (Nt, Nt) نیست
    راه‌حل
    ساخت آن با causal_mask(nt)
  • batch_size ... cannot exceed corpus size

    علت
    نمونه‌گیری بدون جایگذاری
    راه‌حل
    کاهش اندازه دسته یا افزودن جفت‌ها
  • k ... not in [1, N]

    علت
    مقدار K بزرگ‌تر از استخر داده‌هاست
    راه‌حل
    نگه‌داشتن k مساوی یا کمتر از N

پرسش‌ها

پرسش و پاسخ
چرا پچ‌ها و نه پیکسل‌ها؟
150,528 توکن پیکسلی، هزینه اتنشن را غیرقابل تحمل می‌کند.
چرا فریز کردن انکودر حین هم‌ترازسازی؟
فقط تصویرساز 1.3 میلیونی نیاز به یادگیری دارد.
چرا ادغام دیرهنگام؟
متن دست‌نخورده می‌ماند. K و V تصویر تنها یک‌بار به ازای هر تصویر محاسبه می‌شوند.
چرا یادگیری دما؟
مقدار خیلی کوچک نویز ایجاد می‌کند؛ مقدار خیلی بزرگ سافت‌مکس را مسطح می‌کند.