SimCLR: Aprender por Contraste e Pagar pelos Negativos
por Frank de Alcantara em 28/07/2026
Mostremos à rede duas fotografias do mesmo cão: uma recortada, outra desfocada e com as cores alteradas. Depois mostremos a fotografia de outro cão. Se a representação aproximar as duas primeiras e afastar a terceira, talvez tenha aprendido algo sobre identidade visual. Talvez tenha aprendido apenas nossa escolha de recortes e cores. O SimCLR é interessante justamente porque transforma essa ambiguidade numa tarefa precisa.
Índice da Série: Representações e Modelos de Mundo
- 1. Autoencoders: o Gargalo, a Reconstrução e o Latente
- 2. Difusão Latente: Comprimir Antes de Gerar
- 3. SimCLR: Aprender por Contraste e Pagar pelos Negativos (Você está aqui)
- 4. BYOL: Aprender sem Negativos sem Entregar Tudo ao Colapso
- 5. DINO: Autodestilação e Objetos que Emergem da Atenção
- 6. MAE: Mascarar 75% da Imagem e Reconstruir o que Falta
- 7. Prever, não gerar: o template JEPA e o problema do colapso
O autoencoder organiza um latente para reconstrução. A difusão latente organiza um espaço para geração. O SimCLR abandona ambos os contratos. Em vez de perguntar “consigo refazer a entrada?”, pergunta “duas transformações da mesma imagem chegam ao mesmo lugar, e imagens diferentes permanecem separadas?”. Não há decoder de pixels. Há geometria, temperatura e um lote cheio de adversários involuntários.
1. Duas views definem o positivo
Para cada imagem $x_k$, sorteamos duas transformações $t$ e $t’$ de uma família $\mathcal{T}$:
\[\tilde{x}_{2k}=t(x_k),\qquad \tilde{x}_{2k+1}=t'(x_k).\]Essas duas views formam um par positivo. As views de outras imagens no lote funcionam como negativos. Com $B$ imagens, o modelo processa $2B$ entradas.
O encoder $f$ produz uma representação $h_i=f(\tilde{x}_i)$. Um pequeno projection head $g$ produz
\[z_i=g(h_i).\]A perda atua sobre $z_i$, enquanto tarefas posteriores usam $h_i$. O SimCLR mostrou empiricamente que essa separação melhora a representação utilizada depois. O cabeçalho absorve parte da pressão específica da tarefa contrastiva e é descartado ao final.
2. Aumentos são uma declaração de invariância
Recorte, redimensionamento, distorção de cor e borramento não são decoração. Ao declarar duas transformações como positivas, dizemos que a representação deve aproximá-las.
Se remover cor não muda a classe relevante, a invariância ajuda. Se a cor determina o diagnóstico de uma lâmina médica, a mesma transformação pode apagar o sinal. O artigo do SimCLR encontra uma composição forte de recorte e distorção de cor para imagens naturais; isso é evidência naquele domínio, não uma lei que atravessa EEG, áudio e sensoriamento remoto sem revisão.
Uma tarefa autossupervisionada sempre contém conhecimento humano, ainda que nenhum rótulo de classe apareça. Aqui ele mora em $\mathcal{T}$.
3. NT-Xent, símbolo por símbolo
Normalizamos $z_i$ e medimos similaridade de cosseno:
\[s_{ij}= \frac{z_i^\top z_j}{\lVert z_i\rVert_2\lVert z_j\rVert_2}.\]Para uma âncora $i$ e seu positivo $j$, a perda é
\[\ell_{i,j} =-\log \frac{\exp(s_{ij}/\tau)} {\sum_{k=0}^{2B-1}\mathbf{1}_{[k\ne i]}\exp(s_{ik}/\tau)},\]na qual $\tau>0$ é a temperatura. O denominador contém um positivo e $2B-2$ negativos. A perda final mede as duas direções de cada par.
Essa é a NT-Xent, de normalized temperature-scaled cross entropy (entropia cruzada normalizada e escalada por temperatura), uma forma de InfoNCE. A derivação de InfoNCE aplicada a texto e o laboratório de geometria vivem em Do Cosseno à Borda. Aqui a proprietária é a tarefa visual: aumentos, duas views e custo do lote.
4. Temperatura transforma margem em pressão
Considere similaridade positiva $s_+=0{,}7$, negativos com $s_-=0{,}2$, lote $B=64$ e $\tau=0{,}1$. A razão entre a exponencial positiva e cada negativa é
\[\exp\left(\frac{s_+-s_-}{\tau}\right)=e^5\approx148.\]Parece confortável, mas existem $2B-2=126$ negativos. Sob a simplificação de que todos possuem o mesmo $s_-$, a probabilidade do positivo é
\[p_+=\frac{e^{s_+/\tau}} {e^{s_+/\tau}+126e^{s_-/\tau}} \approx0{,}54,\]e a perda permanece perto de $0{,}62$. Um único negativo é fraco; uma multidão soma.
Temperatura baixa concentra gradiente nos negativos difíceis. Baixá-la demais pode tornar a otimização sensível a pequenas diferenças e falsos negativos.
5. O custo quadrático
As $2B$ representações formam uma matriz de similaridades
\[S=ZZ^\top\in\mathbb{R}^{2B\times2B}.\]Ela contém $4B^2$ entradas. Com $B=4096$, são $8192^2=67\,108\,864$ similaridades. Em FP32, somente essa matriz ocupa cerca de $256$ MiB, antes de gradientes, ativações e comunicação entre dispositivos.
A GEMM custa aproximadamente
\[2(2B)^2D=8B^2D\]FLOPs para representações de dimensão $D$. Distribuir o lote exige reunir negativos entre GPUs ou usar mecanismos alternativos, como fila e momentum encoder no MoCo. O SimCLR simplifica a arquitetura, mas paga em lote e duração de treino.
6. Falsos negativos
O denominador presume que outras imagens são incompatíveis. Duas fotografias de cães diferentes podem compartilhar semântica útil e ainda serem afastadas. Esse é um falso negativo.
O problema não significa que a perda falha sempre. Em lotes grandes e dados diversos, a pressão global ainda pode organizar boas representações. Significa que a supervisão criada pelo lote contém erros estruturais e que aumentar $B$ oferece mais negativos e mais oportunidades de incluir parentes semânticos.
O contraste com negative sampling no SkipGram também merece precisão. Ambos amostram eventos negativos, mas os objetos, distribuições e objetivos são diferentes. No SimCLR, as outras views do lote entram numa classificação contrastiva por âncora.
7. NT-Xent em C++23
O programa calcula a perda de uma âncora. Os vetores já estão normalizados; por isso, o produto interno é o cosseno.
#include <algorithm>
#include <array>
#include <cmath>
#include <cstddef>
#include <iostream>
#include <span>
#include <stdexcept>
#include <vector>
double dot(
const std::span<const double> a,
const std::span<const double> b) {
if (a.size() != b.size()) {
throw std::invalid_argument("dimensões incompatíveis");
}
double result = 0.0;
for (std::size_t d = 0; d < a.size(); ++d) {
result += a[d] * b[d];
}
return result;
}
double ntxent_anchor(
const std::span<const std::array<double, 2>> embeddings,
const std::size_t anchor,
const std::size_t positive,
const double temperature) {
if (embeddings.size() < 2 || anchor >= embeddings.size()
|| positive >= embeddings.size() || anchor == positive
|| temperature <= 0.0) {
throw std::invalid_argument("par contrastivo inválido");
}
std::vector<double> logits(embeddings.size());
for (std::size_t i = 0; i < embeddings.size(); ++i) {
logits[i] = i == anchor
? -1e30
: dot(embeddings[anchor], embeddings[i]) / temperature;
}
const double maximum =
*std::max_element(logits.begin(), logits.end());
double denominator = 0.0;
for (const double logit : logits) {
denominator += std::exp(logit - maximum);
}
return -(logits[positive] - maximum - std::log(denominator));
}
int main() {
const std::array<std::array<double, 2>, 4> z{{
{1.0, 0.0}, {0.8, 0.6}, {-1.0, 0.0}, {-0.8, -0.6}
}};
const double forward = ntxent_anchor(z, 0, 1, 0.1);
const double reverse = ntxent_anchor(z, 1, 0, 0.1);
std::cout << "perda simétrica do primeiro par="
<< 0.5 * (forward + reverse) << '\n';
}
Em produção, normalizamos uma matriz inteira, calculamos $ZZ^\top$ por GEMM e aplicamos uma entropia cruzada com os índices dos positivos. O código escalar serve para verificar o índice excluído e a simetria, dois lugares onde implementações erradas continuam produzindo perdas que diminuem com grande serenidade.
No MSVC 19.51, compilamos com cl /std:c++latest /permissive- /W4 /EHsc /utf-8 /O2 simclr.cpp. A saída é aproximadamente 1.27765e-07. Ela é tão pequena porque o positivo possui cosseno $0{,}8$, enquanto os dois negativos possuem $-1$ e $-0{,}8$; com $\tau=0{,}1$, a separação é enorme. O exemplo verifica a função. A Seção 4, com 126 negativos moderados, mostra por que um lote real raramente oferece esse sossego.
8. Laboratório: a multidão no denominador
Altere lote, temperatura e similaridades. A barra verde é a probabilidade do positivo; a vermelha agrega todos os negativos. Observe que aumentar $B$ pode elevar a perda sem mudar a geometria de nenhum par.
9. O que fica quando retiramos os negativos
SimCLR mostra que uma tarefa de comparação simples, aumentos fortes e um cabeçalho não linear aprendem representações competitivas. Também deixa duas contas: $O(B^2)$ em similaridades e uma dependência forte da transformação que define o positivo.
O próximo artigo retirará os negativos. O BYOL manterá duas views, mas colocará uma rede online diante de um alvo lento e pedirá que um preditor case suas representações. A perda ficará simples; o problema do colapso, não.
Os negativos impedem que todos ocupem o mesmo ponto. Retirá-los exige outra razão para o espaço permanecer aberto.
Acrônimos e Abreviações neste artigo
A seguir está a lista de todos os acrônimos e abreviações identificados no texto, organizados em ordem alfabética com o termo original em inglês e a tradução para o português:
| Acrônimo / Abreviação | Definição em Inglês | Tradução em Português |
|---|---|---|
BLAS |
Basic Linear Algebra Subprograms | Subprogramas Básicos de Álgebra Linear |
CPU / CPUs |
Central Processing Unit | Unidade Central de Processamento |
FLOPs |
Floating Point Operations | Operações de Ponto Flutuante |
FP32 |
32-bit Floating Point | Ponto Flutuante de 32 bits |
GEMM |
General Matrix Multiply | Multiplicação Geral de Matrizes |
GPU |
Graphics Processing Unit | Unidade de Processamento Gráfico |
IA |
Artificial Intelligence | Inteligência Artificial |
I-JEPA |
Image Joint-Embedding Predictive Architecture | Arquitetura Preditiva de Incorporação Conjunta de Imagem |
JEPA |
Joint-Embedding Predictive Architecture | Arquitetura Preditiva de Incorporação Conjunta |
KiB |
Kibibyte | Kibibyte |
MAE |
Masked Autoencoder | Autocodificador Mascarado |
MSE |
Mean Squared Error | Erro Quadrático Médio |
MSVC |
Microsoft Visual C++ | Microsoft Visual C++ |
PCA |
Principal Component Analysis | Análise de Componentes Principais |
SIMD |
Single Instruction, Multiple Data | Instrução Única, Múltiplos Dados |
SimCLR |
Simple Framework for Contrastive Learning of Visual Representations | Estrutura Simples para Aprendizado Contrastivo de Representações Visuais |
Referências
CHEN, T.; KORNBLITH, S.; NOROUZI, M.; HINTON, G. A Simple Framework for Contrastive Learning of Visual Representations. ICML, 2020. Disponível em: https://proceedings.mlr.press/v119/chen20j.html. Acesso em: 28 jul. 2026.
HE, K.; FAN, H.; WU, Y.; XIE, S.; GIRSHICK, R. Momentum Contrast for Unsupervised Visual Representation Learning. CVPR, 2020. Disponível em: https://openaccess.thecvf.com/content_CVPR_2020/html/He_Momentum_Contrast_for_Unsupervised_Visual_Representation_Learning_CVPR_2020_paper.html. Acesso em: 28 jul. 2026.
OORD, A. van den; LI, Y.; VINYALS, O. Representation Learning with Contrastive Predictive Coding. 2018. Disponível em: https://arxiv.org/abs/1807.03748. Acesso em: 28 jul. 2026.
Índice da Série: Representações e Modelos de Mundo
- 1. Autoencoders: o Gargalo, a Reconstrução e o Latente
- 2. Difusão Latente: Comprimir Antes de Gerar
- 3. SimCLR: Aprender por Contraste e Pagar pelos Negativos (Você está aqui)
- 4. BYOL: Aprender sem Negativos sem Entregar Tudo ao Colapso
- 5. DINO: Autodestilação e Objetos que Emergem da Atenção
- 6. MAE: Mascarar 75% da Imagem e Reconstruir o que Falta
- 7. Prever, não gerar: o template JEPA e o problema do colapso
(Updated: )