Faza 04 · lecția 18

Viziune cu vocabular deschis — CLIP

Scopul lecției: Antrenați împreună un codificator de imagine și un codificator text, astfel încât perechile potrivite (imagine, descriere) să ajungă în același punct dintr-un spațiu comun. Acesta este întregul truc.

Versiunea curentă AlexBred.com: primele 100 de lecții ale programului în limba română.

Curs
AI Engineering from Scratch
Fază
Viziune computerizată
Lectură
12 min.
Verificat
Cuprinsul lecției
  1. Obiective de învățare
  2. Problema
  3. Conceptul
  4. Două turnuri
  5. Obiectivul
  6. SigLIP: o pierdere mai bună
  7. Clasificare zero-shot
  8. Unde sunt utilizate modelele de tip CLIP în 2026
  9. Construiți-l
  10. Pasul 1: un model minuscul cu două turnuri
  11. Pasul 2: pierderea contrastivă
  12. Pasul 3: clasificatorul zero-shot
  13. Pasul 4: verificare de plauzibilitate
  14. Utilizați-l
  15. Livrați-l
  16. Exerciții
  17. Termeni-cheie
  18. Lecturi suplimentare

Antrenați împreună un codificator de imagine și un codificator text, astfel încât perechile potrivite (imagine, descriere) să ajungă în același punct dintr-un spațiu comun. Acesta este întregul truc.

Tip: Construiți + utilizați Limbaje: Python Cerințe prealabile: Faza 4 Lecția 14 (ViT), Faza 4 Lecția 17 (Viziune auto-supervizată) Timp: ~45 de minute

Obiective de învățare

  • Explicați arhitectura cu două turnuri a CLIP și obiectivul său de antrenare contrastivă
  • Utilizați un CLIP (sau SigLIP) preantrenat pentru clasificare zero-shot, fără antrenare specifică sarcinii
  • Implementați de la zero clasificarea zero-shot: codificați prompturi de clasă, calculați similaritatea cosinus, aplicați argmax
  • Deosebiți modelele CLIP, SigLIP, OpenCLIP și LLaVA/LLaMA-vision — rolul fiecăruia în 2026

Problema

Clasificatoarele tradiționale au vocabular închis: un model ImageNet cu 1.000 de clase poate prezice doar 1.000 de etichete. Fiecare categorie nouă necesită date etichetate și un cap de clasificare reantrenat.

CLIP (Radford et al., OpenAI, 2021) a arătat că antrenarea pe 400M de perechi (imagine, descriere) culese de pe internet produce un model care poate clasifica, la inferență, în orice set de categorii descrise exclusiv în limbaj natural. O clasă nouă îi este furnizată printr-o propoziție.

Această capacitate — transferul zero-shot — este motivul pentru care fiecare sistem de viziune modern începe cu un checkpoint din familia CLIP. Detecția (Grounding DINO, OWL-ViT), segmentarea (CLIPSeg, SAM), regăsirea, moderarea conținutului, VLM-urile și generarea text-la-imagine se bazează toate pe reprezentări vectoriale comune de tip CLIP.

Notă tehnică a traducerii: CLIP demonstrează transfer zero-shot pentru multe sarcini, nu faptul că toate sistemele moderne de viziune pornesc de la un checkpoint CLIP. Alegerea unui encoder depinde de sarcină și de date; de exemplu, DINOv2 este un encoder vizual auto-supervizat, nu un model imagine–text de tip CLIP.

Notă tehnică a traducerii: Afirmația despre SAM nu descrie modelul Segment Anything original: acesta primește prompturi de puncte, casete sau măști, nu prompturi text prin CLIP. Integrarea textului necesită modele sau extensii suplimentare și nu trebuie atribuită automat lui SAM.

Conceptul

Două turnuri

Диаграмма к уроку «Viziune cu vocabular deschis — CLIP»

Ambele codificatoare se încheie cu o proiecție liniară către aceeași dimensiune a reprezentării vectoriale (512 pentru CLIP-B/32, 1024 pentru CLIP-L/14). Normalizați L2 și calculați similaritatea cosinus.

Notă tehnică a traducerii: Pentru checkpointurile publice OpenAI, proiecția finală are 512 dimensiuni pentru ViT-B/32 și 768 pentru ViT-L/14. Valoarea 1024 este dimensiunea ascunsă a encoderului vizual ViT-L/14, nu dimensiunea reprezentării comune finale.

Obiectivul

Pentru un lot de N perechi (imagine, descriere), construiți o matrice de similaritate NxN. Antrenați ambele codificatoare astfel încât diagonala (perechile potrivite) să aibă similaritate mare, iar elementele din afara diagonalei (perechile nepotrivite) să aibă similaritate mică.

matrice_sim = reprezentari_imagine @ reprezentari_text.T / tau

pierdere_i2t = entropie_incrucisata(matrice_sim,       tinte=interval(N))
pierdere_t2i = entropie_incrucisata(matrice_sim.T,     tinte=interval(N))
pierdere = (pierdere_i2t + pierdere_t2i) / 2

Este simetric deoarece atât regăsirea imagine-la-text, cât și regăsirea text-la-imagine trebuie să funcționeze. tau (temperatura) este de obicei învățată ca parametru scalar, inițializat la 0,07.

SigLIP: o pierdere mai bună

SigLIP (Zhai et al., 2023) a înlocuit softmax cu o sigmoidă pentru fiecare pereche:

pierdere = media peste perechi a log(1 + exp(-y_ij * sim_ij))
y_ij = +1 dacă perechea se potrivește, -1 în caz contrar

Pierderea pe fiecare pereche elimină normalizarea la nivel de lot necesară pentru CLIP. SigLIP se antrenează mai bine cu loturi mici și egalează sau depășește CLIP pentru aceeași cantitate de date.

Notă tehnică a traducerii: Formula afișată este o simplificare didactică. Obiectivul SigLIP publicat include temperatura și un bias în logit-ul fiecărei perechi; pseudocodul păstrează ideea semnului pozitiv/negativ, dar nu este o implementare completă a pierderii originale.

Clasificare zero-shot

Pentru un CLIP antrenat:

  1. Pentru fiecare clasă, alcătuiți un prompt: „o fotografie a unui {class}”.
  2. Codificați toate prompturile de clasă cu codificatorul text -> T cu forma (C, d).
  3. Codificați imaginea de test -> I cu forma (1, d).
  4. Similaritatea = I @ T.T cu forma (1, C).
  5. Argmax -> clasa prezisă.

Ingineria prompturilor contează. OpenAI a publicat 80 de șabloane de prompt pentru ImageNet (“a photo of a {}”, “a blurry photo of a {}”, “a sketch of a {}”, …). Faceți media reprezentărilor tuturor șabloanelor pentru fiecare clasă pentru a obține încă 1–3% acuratețe top-1.

Unde sunt utilizate modelele de tip CLIP în 2026

  • Clasificare zero-shot — utilizare directă.
  • Regăsire de imagini — codificați o dată toate imaginile, apoi reprezentați vectorial interogarea la inferență.
  • Detecție condiționată de text — Grounding DINO și OWL-ViT înfășoară un detector cu turnul text CLIP.
  • Segmentare condiționată de text — CLIPSeg; SAM utilizează intrări de prompt text prin CLIP.
  • VLM-uri — LLaVA, Qwen-VL și InternVL conectează un codificator vizual din familia CLIP la un LLM.
  • Generare text-la-imagine — Stable Diffusion și DALL-E 3 sunt condiționate de reprezentările textuale CLIP.

Odată ce aveți un spațiu de reprezentări vectoriale comun, orice sarcină viziune+limbaj devine un calcul de distanță.

Notă tehnică a traducerii: Grounding DINO realizează fuziune strânsă limbaj–viziune într-un detector DINO, iar OWL-ViT transferă un model imagine–text către detecția cu vocabular deschis; niciunul nu este descris exact ca simpla învelire a unui detector cu un turn text CLIP. Configurația Stable Diffusion v1 folosește FrozenCLIPEmbedder, însă documentația publică DALL·E 3 nu publică encoderul intern de condiționare; nu se poate concluziona că DALL·E 3 folosește reprezentări CLIP. Un spațiu comun de reprezentări este util pentru clasificare și regăsire, dar sarcini precum detecția, segmentarea și generarea necesită componente și obiective suplimentare.

Construiți-l

Pasul 1: un model minuscul cu două turnuri

CLIP real este ViT + Transformer. Pentru această lecție, turnurile sunt MLP-uri mici aplicate unor caracteristici extrase în prealabil, astfel încât semnalul de antrenare să fie vizibil pe 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()

Două proiecții, ieșire într-o dimensiune comună, temperatură învățată. Aceeași formă ca API-ul CLIP real.

Pasul 2: pierderea contrastivă

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

Simetrică. O valoare logit_scale mai mare produce un softmax mai concentrat, deci mai încrezător, dar cu risc de instabilitate.

Pasul 3: clasificatorul zero-shot

@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()]

O linie pentru fiecare pas. Aceasta este procedura zero-shot exactă utilizată cu un checkpoint CLIP de producție.

Notă tehnică a traducerii: Fragmentul ilustrează pașii de bază, nu API-ul CLIP exact: aplică MLP-uri unor caracteristici sintetice și nu include scala logit în similitudinea finală. Implementarea CLIP publică expune encode_image și encode_text, normalizează reprezentările și aplică o scală logit învățată pentru logit-uri.

Pasul 4: verificare de plauzibilitate

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}")

Pierderea ar trebui să fie apropiată de log(N) = log(8) = 2.08 pentru un model inițializat aleator — ținta entropiei încrucișate simetrice atunci când încă nu a fost învățată nicio structură.

Notă tehnică a traducerii: log(N) este referința pentru logit-uri egale. În acest exemplu, vectorii aleatori normalizați sunt înmulțiți cu exp(2.6592), astfel încât pierderea observată nu este garantată să fie 2,08; ea depinde de dimensiunea reprezentării, de scala logit și de eșantionul aleator. Folosiți valoarea doar ca verificare orientativă.

Utilizați-l

OpenCLIP este opțiunea implicită a comunității în 2026:

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 este mai nou, se antrenează mai bine la scări mici și este preferat pentru activități noi: google/siglip-base-patch16-224. Hugging Face le oferă pe ambele.

Notă tehnică a traducerii: Lucrarea SigLIP susține avantajul obiectivului sigmoid la loturi mai mici, nu o recomandare universală pentru toate proiectele noi. Alegeți checkpointul prin evaluare pe datele, licența, costul și cerințele concrete ale aplicației.

Livrați-l

Această lecție produce:

  • outputs/prompt-zero-shot-class-picker.md — un prompt care proiectează șabloane de clase pentru CLIP zero-shot, având o listă de clase și un domeniu.
  • outputs/skill-image-text-retriever.md — o competență care construiește un index de reprezentări vectoriale ale imaginilor cu orice checkpoint CLIP și acceptă interogări prin text și prin imagine.

Exerciții

  1. (Ușor) Utilizați un OpenCLIP ViT-B/32 preantrenat și realizați clasificare zero-shot pe CIFAR-10 cu setul de 80 de șabloane de prompt. Raportați acuratețea top-1; aceasta ar trebui să fie în jur de 85–90%.
  2. (Mediu) Comparați un singur șablon (“a photo of a {}”) cu reprezentările mediate ale celor 80 de șabloane, pentru aceeași sarcină CIFAR-10. Cuantificați diferența și explicați de ce ajută șabloanele.
  3. (Dificil) Construiți un index de regăsire zero-shot a imaginilor: reprezentați vectorial 1.000 de imagini cu CLIP, construiți un index FAISS, interogați-l cu o descriere în limbaj natural. Raportați recall@5 pentru 20 de interogări reținute, scrise de dumneavoastră.

Notă tehnică a traducerii: Intervalul CIFAR-10 este o țintă orientativă, nu un rezultat garantat. El depinde, între altele, de checkpointul OpenCLIP exact, de preprocesare, de șabloanele de prompt, de versiunea pachetului și de protocolul de evaluare; raportați aceste detalii împreună cu scorul.

Termeni-cheie

Termen Cum este numit în practică Ce înseamnă de fapt
Două turnuri „Codificator dual” Codificatoare de imagine și de text separate, care se încheie într-un cap de proiecție cu dimensiune comună
Zero-shot „Fără antrenare specifică sarcinii” Clasificare în clase descrise doar prin text la inferență; nu se utilizează etichete
Temperatură / logit_scale „tau” Scalar învățat care scalează matricea de similaritate înainte de softmax
Șablon de prompt „A photo of a {}” Înveliș în limbaj natural în jurul numelor claselor; media multor șabloane crește acuratețea zero-shot
CLIP „Model imagine+text” Modelul OpenAI din 2021; vocabularul domeniului în 2026
SigLIP „CLIP cu sigmoidă” Înlocuiește softmax cu o sigmoidă pentru fiecare pereche; se antrenează mai bine cu loturi mici
OpenCLIP „Reproducere deschisă” Variante CLIP antrenate de comunitate pe LAION; valoare implicită de producție pentru fluxurile open-source
VLM „Model viziune–limbaj” Un codificator din familia CLIP plus un LLM, antrenat să răspundă la întrebări despre imagini

Notă tehnică a traducerii: Arhitecturile VLM diferă: unele folosesc un encoder din familia CLIP, dar această structură nu este o definiție universală a unui VLM.

Lecturi suplimentare

Sursă: Originalul în limba engleză

Navigare: ← Lecția 04.17 — Viziune auto-supervizată — SimCLR, DINO, MAE · Faza 4 — Viziune computerizată · Lecția 04.19 — OCR și înțelegerea documentelor → · Catalog complet