19. CLIP
Mais sobre PLN
Veja o curso de PLN do Tiago Tavares, que cobre Transformers e outros tópicos avançados: https://tiagoft.github.io/nlp_course/.
Todo modelo generativo dos capítulos anteriores conseguia produzir uma imagem. Nenhum deles conseguia produzir a imagem que você pediu, porque nenhum deles fazia ideia do que uma frase significa. É com o CLIP (Contrastive Language–Image Pre-training, pré-treino contrastivo entre linguagem e imagem) que isso muda e é por isso que este capítulo fica no meio de um módulo sobre geração apesar de não ser, de forma alguma, um modelo generativo.
A ideia2 é de uma simplicidade quase desconcertante. Pegue 400 milhões de pares (imagem, legenda) da internet. Treine um encoder de imagem e um encoder de texto — duas redes separadas, sem pesos compartilhados — juntos, sob uma única instrução: coloque uma imagem e a legenda dela perto uma da outra e todo o resto longe.
Esse é todo o objetivo. O que sai disso é um único espaço vetorial no qual imagens e frases habitam e portanto uma interface: agora dá para fazer perguntas que atravessam a fronteira entre modalidades. "O quão perto esta figura está da frase uma foto de um cachorro?" vira um produto escalar.
Slides
Clique nos slides e use as setas ← → para navegar; F abre em tela cheia e P abre a visão do apresentador, com as notas. Os simuladores e os diagramas desta página rodam dentro dos slides. Abrir os slides numa aba nova
Os componentes
- Encoder de imagem — um ViT ou uma ResNet modificada (o artigo treina os dois; o melhor modelo é um ViT-L/14 a 336 px: L = Large, 24 camadas de largura 1024; /14 = patches de 14 × 14 pixels), produzindo um vetor de tamanho fixo por imagem.
- Encoder de texto — um Transformer sobre no máximo 77 tokens, produzindo um vetor por legenda.
- Uma projeção linear e uma normalização L2 de cada lado. Os dois encoders nem têm a mesma largura; as projeções levam os dois para o mesmo espaço de \(d\) dimensões e a normalização põe todo embedding na esfera unitária, de modo que a similaridade de cosseno é apenas um produto escalar. Toda a arquitetura se resume a esse espaço compartilhado.
- Uma perda contrastiva (InfoNCE simétrica: uma entropia cruzada de softmax que precisa achar o par certo entre os \(N\) pares do lote) sobre um lote: a diagonal da matriz de similaridade imagem×texto está certa, todo o resto está errado.
No openai/clip-vit-base-patch32, o mais barato dos modelos ViT publicados (50 tokens por imagem) e o que o laboratório usa, um lote de \(N\) pares percorre este caminho:
| passo | lado da imagem | lado do texto |
|---|---|---|
| entrada | \(N \times 3 \times 224 \times 224\) | \(N \times 77\) ids de token (no máximo) |
| encoder | ViT-B/32: 49 patches + [CLS], largura 768, 12 camadas | Transformer: largura 512, 12 camadas |
| saída agregada | token [CLS]: \(N \times 768\) | token de fim de texto: \(N \times 512\) |
| projeção | \(768 \to 512\), sem viés | \(512 \to 512\), sem viés |
| normalização L2 | \(I\): \(N \times 512\), linhas unitárias | \(T\): \(N \times 512\), linhas unitárias |
| similaridade | \(S = I\,T^\top\): \(N \times N\) cossenos |
O [CLS] é um token extra aprendido cuja saída resume a imagem (capítulo 13). A torre de texto agrega o token de fim de texto porque é causal (cada token só vê os anteriores): o último é o único que viu a legenda inteira.
São cerca de 87,5 milhões de parâmetros do lado da imagem e 63,2 milhões do lado do texto. As torres não compartilham nenhum peso: elas só se encontram na perda, pelo produto escalar e pela temperatura.
O que a perda de fato pede
Repare no que o CLIP não é solicitado a fazer. Ele nunca reconstrói uma imagem, nunca gera uma legenda, nunca prevê um rótulo. Só lhe pedem que distinga pares que casam de pares que não casam — e o espaço que sai de fazer isso em escala acaba codificando uma quantidade enorme de informação sobre a aparência das coisas e sobre como elas se chamam. O artigo mediu as alternativas: um Transformer que prevê a legenda palavra por palavra aprendeu o ImageNet zero-shot (classificar o ImageNet sem treinar nele, só a partir dos nomes das classes; veja abaixo) 3× mais devagar que um modelo que só prevê quais palavras aparecem; o objetivo contrastivo foi ainda 4× mais rápido. Discriminar é um objetivo muito mais barato que gerar.
A perda e as duas decisões de projeto dentro dela
Com \(I\) e \(T\) as matrizes \(N \times d\) dos embeddings normalizados de imagem e de texto (a linha \(i\) de cada uma vem do mesmo par), \(\tau > 0\) a temperatura (abaixo) e \(\text{CE}(Z, \text{diag})\) a entropia cruzada de softmax de cada linha de \(Z\) cuja classe certa é a da diagonal (linha \(i\) → coluna \(i\)):
A linha \(i\) de \(I T^\top / \tau\) é um problema de classificação com \(N\) classes: qual das \(N\) legendas pertence à imagem \(i\)? A resposta certa é a classe \(i\). O segundo termo faz a mesma pergunta do lado de cada legenda, pelas colunas.
A temperatura \(\tau\) escala as similaridades antes do softmax. Um \(\tau\) pequeno afia a distribuição e a perda se concentra no negativo mais difícil (a legenda errada com a maior similaridade); um \(\tau\) grande trata todos os negativos por igual e a representação para de afiar. O CLIP aprende o \(\tau\) em vez de fixá-lo, de modo que o próprio modelo ajusta a dificuldade ao longo do treino. Ele é guardado em escala logarítmica, começa em \(\tau = 0{,}07\) e é limitado para que \(1/\tau \le 100\); os modelos publicados terminam exatamente nesse limite, \(\tau = 0{,}01\). Por que tão baixo: os cossenos de uma legenda certa e de uma errada diferem por poucos centésimos (0,26 contra 0,20 no laboratório) e só multiplicar por \(1/\tau \approx 100\) transforma essa diferença num softmax confiante. Arraste-o no painel: repare que a acurácia de busca não muda — o \(\tau\) afeta a perda, não o ranking.
O tamanho do lote faz parte do objetivo. Cada uma das outras legendas do lote é um negativo, então um lote de 32.768 dá a cada exemplo 32.767 negativos. Um modelo que chuta às cegas paga \(\log N\) (log natural) por exemplo, então um lote maior é uma tarefa mais difícil, não só mais rápida: quanto mais concorrentes, mais finas as distinções que os encoders precisam aprender. Também significou espalhar a matriz de similaridade por centenas de aceleradores e essa restrição de engenharia moldou o aprendizado contrastivo por anos.
A perda, com números
Três pares, em 3 dimensões, para que todo número possa ser conferido à mão. Os textos de propósito não são vetores unitários, porque as saídas dos encoders também não são:
-
Normalizar. As linhas de \(T_{\text{cru}}\) têm normas \(0{,}906\), \(0{,}812\) e \(0{,}762\). Dividindo cada linha pela sua norma:
\[ T = \begin{bmatrix} 0{,}994 & 0{,}110 & 0 \\ 0{,}123 & 0{,}985 & 0{,}123 \\ 0 & 0{,}394 & 0{,}919 \end{bmatrix} \] -
Similaridades. \(S = I\,T^\top\). A linha \(i\) é a imagem \(i\) contra as três legendas:
\[ S = \begin{bmatrix} 0{,}994 & 0{,}123 & 0 \\ 0{,}110 & 0{,}985 & 0{,}394 \\ 0 & 0{,}123 & 0{,}919 \end{bmatrix} \]A diagonal é a maior em toda linha e em toda coluna: as seis buscas já estão certas.
-
Logits. Divida por \(\tau\):
\[ S/\tau = \begin{bmatrix} 14{,}20 & 1{,}76 & 0 \\ 1{,}58 & 14{,}07 & 5{,}63 \\ 0 & 1{,}76 & 13{,}13 \end{bmatrix} \] -
Imagem → texto: softmax ao longo de cada linha. A linha 2, a que tem um concorrente de verdade: \(p_{2 \to 2}\), a probabilidade que a imagem 2 dá à legenda 2, é $ e^{14{,}07} / (e^{1{,}58} + e^{14{,}07} + e^{5{,}63}) = 0{,}99978$. As três probabilidades da diagonal são \(0{,}999995\), \(0{,}99978\) e \(0{,}999987\), então
\[ \mathcal{L}_{I \to T} = -\tfrac{1}{3}\big(\log 0{,}999995 + \log 0{,}99978 + \log 0{,}999987\big) = 7{,}9 \times 10^{-5} \] -
Texto → imagem: softmax ao longo de cada coluna. Agora a coluna 3 é a difícil: a legenda 3 tem cosseno \(0{,}394\) com a imagem 2, então \(p_{3 \to 3} = e^{13{,}13} / (e^{0} + e^{5{,}63} + e^{13{,}13}) = 0{,}99945\) e \(\mathcal{L}_{T \to I} = 1{,}9 \times 10^{-4}\). As duas direções não dão o mesmo número — é por isso que a perda tira a média delas:
\[ \mathcal{L} = \tfrac{1}{2}\big(7{,}9 \times 10^{-5} + 1{,}9 \times 10^{-4}\big) = 1{,}3 \times 10^{-4} \] -
Os mesmos embeddings, \(\tau = 1\). Os logits agora são o próprio \(S\), o softmax fica quase plano (a linha 2 dá \(0{,}21\); \(0{,}51\); \(0{,}28\)) e \(\mathcal{L} = 0{,}626\) — mais da metade do \(\log 3 = 1{,}10\) que um chute cego paga. O ranking (e portanto a acurácia) é idêntico. A temperatura decide o quanto a perda insiste, não o que o modelo sabe.
O CLIP real faz exatamente isto com \(N = 32.768\) e \(d\) entre 512 e 1024. O gradiente de \(\mathcal{L}\) volta pelas duas projeções até os dois encoders.
A mesma conta, como o laboratório a escreve — perda_clip, linha a linha. Percorra com o exemplo acima (é o caso inicial); depois mude um número, a temperatura ou o caso e veja qual linha se mexe:
SigLIP: o que o substituiu
Troque o objetivo do painel para SigLIP5 e o softmax desaparece. Cada uma das \(N^2\) células vira uma pergunta binária independente — estes dois casam? — sob uma perda sigmoide comum com uma escala \(t\) (faz o papel de \(1/\tau\); é um escalar, não a matriz de texto \(T\)) e um viés \(b\) aprendidos:
O viés começa bem negativo (\(b = -10\)) porque \(N - 1\) de cada \(N\) células são negativos; sem ele, os primeiros passos seriam gastos só afastando tudo de tudo. Nada é normalizado sobre o lote: sem all-gather (juntar os embeddings de todos os aceleradores para que cada um normalize sobre o lote inteiro), sem softmax distribuído. No artigo, a perda sigmoide supera o softmax com folga em lotes pequenos e empata em lotes grandes; nos dois casos os ganhos param por volta de um lote de 32 mil. A maioria dos modelos abertos recentes de visão-linguagem (VLMs: modelos de linguagem que também leem imagens), como o PaliGemma, o Idefics2 e 3 e o Gemma 3, usa um encoder de imagem da família SigLIP, então, se você for escolher uma torre de imagem hoje, comece por ela — não pelo CLIP original.
Classificação zero-shot e o que ela realmente é
Escreva uma frase por classe — "uma foto de um {classe}" — codifique-as, codifique a imagem, pegue a maior similaridade de cosseno. Sem treino, sem exemplos rotulados e com qualquer conjunto de classes que você consiga descrever em palavras. (Na prática, em inglês: "a photo of a {class}.", a língua das legendas em que o CLIP foi treinado.)
Escrito como camada, é um classificador linear cujos pesos foram digitados em vez de aprendidos. Empilhe os \(C\) embeddings normalizados dos prompts numa matriz \(W \in \mathbb{R}^{C \times d}\); então, para o embedding \(x\) de uma imagem,
em que \(w_c\) é a linha de \(W\) da classe \(c\) e \(\langle \cdot, \cdot \rangle\) o produto escalar. Isso é uma camada nn.Linear(d, C, bias=False) com \(W\) como peso.
Para aplicar o CLIP a uma tarefa nova, tudo que precisamos é "dizer" ao encoder de texto do CLIP os nomes dos conceitos visuais da tarefa e ele produz um classificador linear das representações visuais do CLIP. A acurácia desse classificador é frequentemente competitiva com a de modelos totalmente supervisionados.1
O 'zero-shot' dessa frase promete mais do que parece
O CLIP viu 400 milhões de imagens legendadas. Se as suas classes foram descritas em algum lugar daqueles dados — e, para objetos comuns, foram, muitas vezes — isto não é zero-shot em nenhum sentido forte; é busca num conjunto de treino enorme com um índice em linguagem natural. A parte genuinamente surpreendente não é que funcione com cachorros. É que a interface é linguagem, de modo que o conjunto de classes é definido na inferência por quem estiver digitando.
O laboratório mede isso em 1.000 imagens de teste do CIFAR-10 com o ViT-B/32: 89,5 % de acurácia com "a photo of a {}.", contra 87,4 % com o nome da classe sozinho. Uma sonda linear (linear probe: uma regressão logística treinada sobre os embeddings de imagem do CLIP de \(k\) imagens rotuladas de treino do CIFAR-10 por classe) precisa de 8 a 16 por classe para alcançá-lo.
O espaço compartilhado não é dividido por igual: o gap entre modalidades
Todos os embeddings vivem na mesma esfera unitária, mas não na mesma região dela. Os embeddings de imagem se amontoam num cone estreito e os de texto em outro8. No laboratório, duas imagens ao acaso têm cosseno médio 0,755 e dois prompts ao acaso 0,671, enquanto uma imagem e o seu prompt correto chegam só a 0,258. Um classificador linear separa "este vetor é uma imagem ou uma legenda?" com 100 % de acurácia.
Isso não quebra a classificação zero-shot: o argmax só compara uma imagem com vários textos, então um deslocamento comum a todos os textos se cancela. No laboratório, tirar as duas médias move a acurácia só de 89,5 % para 91,3 %: subtrair a média \(\mu_t\) dos textos desloca a nota de todas as classes pelo mesmo \(\langle \mu_t, x \rangle\), que se cancela no argmax; já subtrair a média \(\mu_i\) das imagens desloca a classe \(c\) por \(\langle w_c, \mu_i \rangle\), que muda de classe para classe (assim como a nova normalização). São esses dois efeitos que movem a acurácia em 1,8 ponto. Mas o gap explica duas coisas que você vai ver na prática: as similaridades do CLIP entre uma imagem e um texto são números pequenos (0,2 a 0,35 para um bom par) e uma imagem costuma ficar mais perto de outras imagens que de qualquer legenda, o que importa quando você mistura as duas num mesmo índice de busca.
As limitações honestas
-
Contagem e relações espaciais
"Três gatos" e "um gato" ficam próximos no espaço do CLIP. Assim como "a xícara sobre o livro" e "o livro sobre a xícara". O próprio artigo lista a contagem (CLEVRCounts) entre as tarefas em que o CLIP zero-shot é fraco.
-
Ele se comporta como saco de palavras
Embaralhe as palavras de uma legenda e a busca do CLIP quase não muda7. A estrutura composicional (qual objeto tem qual atributo, quem fez o quê a quem) praticamente não aparece. Esta é a limitação mais profunda conhecida de toda a família.
-
Sensibilidade ao prompt
No ImageNet,
"a photo of a {class}."supera o"{class}"sozinho em 1,3 ponto; tirar a média dos embeddings de 80 templates escritos à mão acrescenta mais 3,5. Isso é um remendo, não uma propriedade. -
Ele aprendeu as associações da internet
Inclusive as que você não gostaria que ele aprendesse. Falhas documentadas em raça e gênero, ocupação e aparência. São herdadas por todo modelo construído sobre ele — incluindo geradores de imagem condicionados a embeddings de texto do CLIP.
Onde o CLIP fica neste curso
Este capítulo está aqui porque geração condicionada a texto precisa de um encoder de texto e foi do CLIP que veio um deles.
| Uso | O que o CLIP fornece |
|---|---|
| Condicionar um modelo de difusão | O Stable Diffusion faz atenção cruzada com embeddings de texto do CLIP (capítulo 20). O SDXL usa dois encoders de texto; SD3 e FLUX acrescentam um encoder T5 (o encoder do Transformer texto-para-texto do Google, bem maior que a torre de texto do CLIP), porque a torre de texto do CLIP é pequena e seu comportamento de saco de palavras limita prompts longos e composicionais. |
| O encoder de imagem de um VLM | A torre de visão que alimenta um modelo de linguagem costuma ser um encoder da família SigLIP (capítulo 13). |
| Busca | Busca texto-para-imagem e imagem-para-imagem, em escala, com um produto escalar por candidato. |
| Avaliação | O CLIPScore — o quanto a imagem gerada casa com o prompt? — é a métrica padrão de aderência ao prompt (capítulo 8.3) e herda todas as limitações acima, inclusive a cegueira à ordem das palavras. |
| Curadoria de dados | Filtrar conjuntos imagem-texto de bilhões de itens por similaridade do CLIP. O LAION (um conjunto aberto de bilhões de pares imagem–texto da web) foi construído assim, o que significa que modelos posteriores herdam o julgamento do CLIP sobre o que é um bom par. |
O resultado que importou mais que a arquitetura
Uma reprodução aberta (o benchmark DataComp, construído sobre o código do OpenCLIP) manteve fixos a arquitetura e o orçamento de treino e variou só os dados6. Um conjunto filtrado até uma fração do tamanho original bateu o conjunto inteiro; o melhor conjunto filtrado do DataComp treinou um ViT-L/14 que superou o da própria OpenAI com o mesmo custo computacional. A lição duradoura do CLIP talvez nem seja o aprendizado contrastivo: é que, nesta escala, construir o conjunto de dados é a arquitetura do modelo.
Laboratório: um espaço, medido
O comportamento do modelo descrito nesta página é medido num notebook no Colab com o modelo público openai/clip-vit-base-patch32 em imagens de teste do CIFAR-10 e do CIFAR-100. Ele roda no navegador; uma GPU T4 (gratuita no Colab) o faz levar poucos minutos e ele também roda em CPU, mais devagar. Não é preciso instalar nada. São nove seções, cada uma terminando num checkpoint com valor de verificação:
- as duas torres: formatos, larguras, parâmetros e onde ficam as projeções;
- a perda contrastiva calculada à mão num lote e conferida contra a do próprio modelo;
- a temperatura: o valor aprendido, o que ela muda e o que não muda;
- o tamanho do lote como parte do objetivo, de 2 a 100 candidatos;
- a classificação zero-shot como uma camada linear cujos pesos são frases;
- templates de prompt, do nome da classe sozinho a uma média de vários;
- busca imagem–texto nas duas direções;
- a geometria do espaço: similaridades de cosseno, o gap entre modalidades, um saco de palavras;
- zero-shot contra uma sonda linear (linear probe) treinada com poucos exemplos — e os seus próprios prompts, numa tabela.
Abrir o laboratório no Colab — salve uma cópia no seu Drive (Arquivo → Salvar uma cópia no Drive) para rodar e editar.
Pontos principais
- O CLIP treina dois encoders para colocar uma imagem e sua legenda no mesmo espaço. Esse espaço compartilhado é uma interface entre visão e linguagem, não um modelo generativo.
- A perda é contrastiva: a diagonal da matriz de similaridade do lote está certa, todo o resto está errado, nas duas direções. Discriminação, não reconstrução.
- A temperatura decide o quanto a perda liga para o negativo mais difícil e o CLIP a aprende; ela muda a perda, não o ranking. O tamanho do lote faz parte do objetivo — cada uma das outras legendas é um negativo.
- O SigLIP o substituiu: uma sigmoide independente por par, sem normalização sobre o lote, melhor em lotes pequenos e tão bom quanto em lotes grandes. Hoje, use um encoder da família SigLIP.
- Classificação zero-shot é um classificador linear cujos pesos são frases codificadas — busca com um índice em linguagem. Impressiona, mas não é mágica; a redação do prompt importa.
- O espaço compartilhado tem um gap entre modalidades: imagens e textos ficam em cones separados e um par imagem–texto correto tem cosseno menor que duas imagens sem relação.
- O CLIP é próximo de um saco de palavras: contagem, relações espaciais e composicionalidade são fracas e isso flui para todo modelo condicionado a ele.
- Neste curso o CLIP é a ponte: é o que permite que do capítulo 20 em diante a geração seja condicionada a uma frase. E a curadoria de dados importou mais que a arquitetura — essa é a lição duradoura.
Adicional
Embeddings L2-normalizados
Um vetor L2-normalizado tem comprimento euclidiano 1. Ele é obtido dividindo cada componente pela norma L2 do vetor3:
Por que o CLIP o usa
- Só a direção é comparada. Depois da normalização o produto escalar é a similaridade de cosseno4, um número em \([-1, 1]\). Um vetor longo não ganha uma comparação só por ser longo.
- Distância e similaridade viram o mesmo ranking. Para vetores unitários, \(\|a - b\|^2 = 2 - 2\cos(a, b)\), então a busca de vizinhos mais próximos por distância e por cosseno devolve os mesmos itens.
- A temperatura ganha uma escala fixa sobre a qual agir. Sem normalização os logits poderiam crescer só com o crescimento das normas; com ela, os logits ficam em \([-1/\tau, 1/\tau]\) e só o \(\tau\) decide o quão afiado é o softmax.
A mesma restrição — embeddings numa hiperesfera — é comum onde quer que a saída seja uma similaridade: reconhecimento facial, busca e recomendação.
-
CLIP: Connecting Text and Images, OpenAI, 2021. ↩
-
Radford, A., Kim, J. W., Hallacy, C., Ramesh, A., Goh, G., Agarwal, S., Sastry, G., Askell, A., Mishkin, P., Clark, J., Krueger, G., & Sutskever, I. (2021). Learning Transferable Visual Models From Natural Language Supervision — ICML. ↩
-
How to Normalize a Vector, Nextbridge. ↩
-
Cosine Similarity, GeeksforGeeks. ↩
-
Zhai, X., Mustafa, B., Kolesnikov, A., & Beyer, L. (2023). Sigmoid Loss for Language Image Pre-Training — ICCV. SigLIP; o artigo que removeu o softmax sobre o lote. ↩
-
Gadre, S. Y., et al. (2023). DataComp: In search of the next generation of multimodal datasets — NeurIPS. Arquitetura fixa, dados variados — e os dados vencem. ↩
-
Yuksekgonul, M., Bianchi, F., Kalluri, P., Jurafsky, D., & Zou, J. (2023). When and why vision-language models behave like bags-of-words, and what to do about it? — ICLR. ↩
-
Liang, W., Zhang, Y., Kwon, Y., Yeung, S., & Zou, J. (2022). Mind the Gap: Understanding the Modality Gap in Multi-modal Contrastive Representation Learning — NeurIPS. ↩