Redes Neurais Artificiais e Deep Learning · Insper

Redes Neurais Convolucionais

A restrição, com o preço na etiqueta

Comece pela conta

Uma foto 224 × 224 × 3 entra numa camada densa de 1 000 neurônios.
Quantos pesos tem essa camada?

  • entradas 1 000 saídas 150 milhões de pesos — só na primeira camada.
  • E o pior não é o número: o detector de borda do canto e o do centro são pesos diferentes, aprendidos separadamente, com dados que você não tem.

Duas afirmações sobre imagens

  1. O que importa é local. Um pixel conversa com os vizinhos, não com o canto oposto.
  2. Significa a mesma coisa em qualquer lugar. Uma borda no canto é o mesmo evento que uma borda no centro.

Uma camada convolucional é uma camada densa à qual essas duas coisas foram impostas:
localidade e compartilhamento de pesos. Nada é acrescentado — capacidade é retirada, de propósito.

Uma arquitetura é um prior escrito como restrição sobre os pesos.

A mesma camada, três vezes

6 entradas → 4 saídas (1-D, kernel 3). Cada célula é um peso; a cor diz quais são o mesmo número.

densa
24 pesos distintos
0 0 0 0 0 0 0 0 0 0 0 0
+ localidade
12 pesos distintos
w1 w2 w3 0 0 0 0 w1 w2 w3 0 0 0 0 w1 w2 w3 0 0 0 0 w1 w2 w3
+ compartilhamento
3 pesos — uma convolução

Uma posição da saída = um produto escalar

passo 1, sem padding

  • Janela do canto:
  • As quatro janelas:
  • Os mesmos quatro números de foram lidos em todas as posições.

O PyTorch faz correlação cruzada (não gira o kernel). Para a rede não importa: o kernel é aprendido. Para conferir derivadas à mão, importa — volta na passagem reversa.

Simulador · o kernel deslizando

O formato da saída

  • Passo : quanto a janela pula. corta a resolução pela metade — o downsampling mais barato.
  • Padding : zeros inventados na borda. Com ímpar, é o padding "same": a saída mantém o tamanho.
  • O pooling segue a mesma fórmula (em geral , ).

Quase todo bug de CNN é de formato. Quando o PyTorch reclamar no primeiro Linear, imprima o formato camada por camada — não chute o número.

Exercício · siga o tensor

Entrada (1, 1, 28, 28) = (imagens, canais, altura, largura): uma imagem cinza de 28×28. Preencha antes de virar o slide.

camada saída
Conv2d(1, 8, 5) ?
MaxPool2d(2) ?
Conv2d(8, 16, 3, padding=1) ?
MaxPool2d(2) ?
Conv2d(16, 32, 3, stride=2) ?
Flatten() ?

Conv2d(canais que entram, nº de filtros, lado do kernel)

MaxPool2d(2): janela 2×2, passo 2

Lado da saída:

Responda em canais × altura × largura.

Siga o tensor · resposta

1×28×28conv 5×58 filtros8×24×24max pool 28×12×12conv 3×3, p=116 filtros16×12×12max pool 216×6×6conv 3×3, s=232 filtros32×2×2flatten128

camada saída de onde vem
Conv2d(1, 8, 5) 8 × 24 × 24 8 filtros · (28 + 0 − 5)/1 + 1 = 24
MaxPool2d(2) 8 × 12 × 12 mesmos canais · (24 − 2)/2 + 1 = 12
Conv2d(8, 16, 3, padding=1) 16 × 12 × 12 16 filtros · (12 + 2 − 3)/1 + 1 = 12
MaxPool2d(2) 16 × 6 × 6 mesmos canais · (12 − 2)/2 + 1 = 6
Conv2d(16, 32, 3, stride=2) 32 × 2 × 2 32 filtros · ⌊(6 + 0 − 3)/2⌋ + 1 = 2
Flatten() 128 32 · 2 · 2 → o próximo é Linear(128, …)

De um kernel para uma camada: canais

  • A entrada tem canais (3 no RGB, 64 depois de uma camada…).
  • Cada kernel é um bloco : lê todos os canais e soma tudo num número.
  • kernels → mapas de ativação, que viram os canais da próxima camada.

Conv2d(3, 64, 3) numa imagem 32 × 32. Quantos parâmetros?

  • A densa equivalente (): ≈ 201 milhões
  • Não há nem na conta: a mesma camada roda em 32 × 32 ou em 4K.

Equivariância é o que você ganha…

Compartilhar pesos dá uma propriedade exata: desloque a entrada e o mapa se desloca junto.

Isso é equivariância à translação — o certo para um detector.

…invariância é o que você queria

Um classificador quer "bota" onde quer que a bota esteja. Equivariância só vira invariância quando:

mecanismo o que faz
pooling / conv com passo descarta a posição dentro da janela — invariância pequena e local
global average pooling no fim colapsa inteiro — é daqui que a invariância vem
data augmentation compra, com exemplos, invariância ao que a conv não cobre

O que a convolução não dá

O prior cobre translação e mais nada. Rotação, escala, ponto de vista: comprados com augmentation e dados — numa CNN exatamente como num Transformer.

  • Nem a translação é exata: cada passo e cada pooling amostram a grade. Um deslocamento que não é múltiplo do passo total não volta idêntico lá em cima.
  • O Flatten não colapsa nada: mantém cada posição numa coordenada própria do vetor.

No laboratório: MLP, CNN + Flatten e CNN + GAP treinadas no Fashion-MNIST. Desloque o teste 4 px. Qual cai menos? E se girar 90°?

Medido no laboratório

Três épocas de treino no Fashion-MNIST, Adam, lr = 1e-3. Acurácia de teste:

rede parâmetros no lugar deslocado 4 px deslocado 8 px girado 90°
MLP 784 → 256 → 128 → 10 235 146 0,86 0,25 0,18 0,05
CNN + Flatten 20 586 0,90 0,33 0,19 0,06
CNN + GAP 24 170 0,85 0,81 0,65 0,07
CNN + Flatten, augmentation ±4 px 20 586 0,85 0,80 0,26 —
  • O GAP compra invariância — e cobra alguns pontos no lugar de sempre: jogar fora a posição custa informação.
  • A augmentation compra invariância só dentro da faixa que mostrou.
  • Nada compra rotação de graça.

O campo receptivo é o orçamento

Uma unidade funda não vê a imagem: vê o que a alimentou, recursivamente.

  1. Passo 1: cresce linearmente. Cada 3×3 soma 2. Para enxergar 224 px: 112 camadas.
  2. Passo 2: cresce geometricamente. Cada passo dobra o salto de tudo acima — é por isso que CNNs fazem downsampling.
  3. Dilatação: alcance sem pesos e sem perder resolução — segmentação semântica.

Self-attention alcança todas as posições na camada 1, a um custo O(n²). O trade-off CNN × Transformer inteiro está nessa frase.

Simulador · campo receptivo

Duas 3×3 ganham de uma 5×5

Qual enxerga mais? Qual custa menos?

  • As duas alcançam 5 pixels.
  • Duas 3×3: pesos. Uma 5×5: .
  • E o par põe uma não linearidade no meio.
  • Esse foi o artigo do VGG inteiro.
  • É por isso que 3×3 é o padrão quase universal…
  • …e por que as convoluções de entrada 11×11 (AlexNet) sumiram depois de 2014.

A volta: a mesma operação três vezes

gradiente o que é implementação
soma de sobre batch e espaço uma redução
correlação cruzada da entrada com uma convolução
correlação "full" de com o kernel girado 180° (= convolução "full" com o kernel) uma convolução (a "transposta")

Com passo s > 1: insira s − 1 zeros entre as entradas de ∂L/∂Y e aplique a mesma receita.

A volta, com números

Chega para o exemplo de antes ( 3×3, 2×2).

  • Viés: soma tudo →
  • Kernel: →
  • Entrada: convolução "full" →
  • Chegou 2×2, saiu 3×3: cada pixel recebe a soma de todas as janelas em que entrou — o canto em uma, o centro em quatro. Por isso o padding é de cada lado.

Simulador · o código da convolução, linha a linha

X
K
b
dY

Convolução transposta e o xadrez

  • A operação de , usada para frente, é o ConvTranspose2d: o upsampling de decodificadores e GANs.
  • Quando o passo não divide o kernel, algumas posições de saída recebem mais contribuições que outras.
  • Resultado: um xadrez visível na imagem gerada.

A correção que todo mundo usa:
nn.Upsample + Conv2d — nunca uma transposta pura.

Odena, Dumoulin & Olah (2016), Deconvolution and Checkerboard Artifacts, Distill.

Pooling: quem recebe o gradiente

Nenhum peso. Resume cada janela num número — e a escolha do resumo decide quem recebe gradiente.

  • Max é um roteador, não um filtro: o gradiente inteiro vai para quem venceu a janela; o resto recebe zero.
  • Average divide igualmente: cada célula recebe — mais estável, menos seletivo.
  • A rota muda durante o treino: o vencedor depende dos valores, não dos índices.

Entrada 6 × 6, max 2 × 2, passo 2, gradiente 1 em cada saída. Quantas das 36 células recebem algo?

Simulador · pooling, ida e volta

Flatten × global average pooling

Flatten desmancha num vetor e entrega a uma densa.

  • VGG-16: números → Linear(25088, 4096)
  • 102,8 milhões de parâmetros — 74% da rede inteira (138 M) numa camada só.
  • E cada peso amarrado a uma posição.

GAP tira a média de cada canal sobre .

  • números, nenhum parâmetro.
  • A cabeça vira Linear(C, classes).
  • Colapsa o espaço → é daqui que vem a invariância.

Uma CNN inteira, camada por camada

camada saída parâmetros campo receptivo
entrada 1 × 28 × 28 — 1
Conv2d(1, 16, 3, padding=1) + BatchNorm + ReLU 16 × 28 × 28 192 3
MaxPool2d(2) 16 × 14 × 14 0 4
Conv2d(16, 32, 3, padding=1) + BatchNorm + ReLU 32 × 14 × 14 4 704 8
MaxPool2d(2) 32 × 7 × 7 0 10
Conv2d(32, 64, 3, padding=1) + BatchNorm + ReLU 64 × 7 × 7 18 624 18
AdaptiveAvgPool2d(1) + Flatten 64 0 a imagem toda
Linear(64, 10) 10 650 —
total 24 170

Resolução cai, canais sobem · os parâmetros moram no fim · um MLP de acurácia parecida tem 235 146.

Como a arquitetura ganhou o formato que tem

✅ sobreviveu

  • kernels 3×3 empilhados (VGG)
  • blocos residuais (ResNet) — hoje em toda arquitetura
  • normalização depois de cada conv
  • global average pooling no lugar da cabeça densa
  • convoluções separáveis em profundidade e 1×1

❌ não sobreviveu

  • Local Response Normalization (AlexNet)
  • cabeças densas com dezenas de milhões de parâmetros
  • kernels grandes na entrada (11×11 passo 4, 7×7 passo 2)
  • classificadores auxiliares (GoogLeNet)
  • sigmoid e tanh em pilhas de visão
  • a própria corrida de backbones do ImageNet

As convoluções baratas: 1×1 e separável

1×1 — uma camada densa por posição: mistura canais, não olha vizinhos. É como toda arquitetura muda o número de canais barato.

Separável em profundidade = um kernel por canal (depthwise) + uma 1×1 (pointwise).

á

64 → 128, 3×3 parâmetros
Conv2d(64, 128, 3) 73 856
depthwise Conv2d(64, 64, 3, groups=64) 640
pointwise Conv2d(64, 128, 1) 8 320
separável 8 960 (12%)

Previsão: 1/128 + 1/9 ≈ 0,119. Todo modelo que roda num celular (MobileNet, EfficientNet) usa isso.

ConvNeXt: o experimento de controle

2020–2021: "a atenção venceu a convolução". Será?

  • Pegue uma ResNet-50 e mude só o que não é atenção: AdamW, 300 épocas, augmentation pesada, proporções entre estágios, kernel 7×7 depthwise, LayerNorm, GELU.
  • Nenhuma atenção em lugar nenhum.
  • Resultado: empata com o Swin Transformer em todas as escalas.

Boa parte da vantagem reportada dos ViTs era a receita de treino, não a arquitetura. As duas famílias convergiram para o mesmo bloco, vindo de direções opostas.

Onde as convoluções vivem em 2026

ainda convolucional — e não por inércia

  • o VAE de todo modelo de difusão latente (SD, SDXL, SD3, FLUX)
  • segmentação médica (nnU-Net): centenas de volumes, não bilhões de imagens
  • visão em dispositivo e tempo real
  • áudio, espectrogramas, séries temporais (conv 1-D)
  • o patch embedding de um ViT é uma conv com passo

hoje normalmente Transformer

  • classificação e busca em larga escala
  • reconhecimento de vocabulário aberto (CLIP)
  • o backbone de geração texto-imagem (DiT, MMDiT)

A regra que generaliza

Convolução
prior forte, barato e fixo

vence quando os dados são escassos, a latência importa ou a estrutura é genuinamente local

Transformer
prior fraco, caro e aprendível

vence quando você pode pagar por dados suficientes para aprender uma estrutura melhor do que a que teria imposto

Esse trade-off é o eixo ao longo do qual as próximas quatro aulas se movem: atenção, Transformers, ViT e transfer learning.

Laboratório · a restrição, medida

Notebook no Colab, ~2 h, Fashion-MNIST. Cada seção termina num checkpoint com valor de verificação.

  1. a convolução escrita à mão
  2. formatos — e o erro do Linear
  3. o preço em parâmetros
  4. equivariância × invariância, medidas
  5. campo receptivo pelo gradiente
  1. a volta: três convoluções e um roteador
  2. MLP × CNN, com o teste deslocado
  3. o que a primeira camada aprendeu
  4. a sua CNN com orçamento: ≤ 30 000 parâmetros, ≤ 5 épocas

abrir no Colab →

Para levar

  1. Convolução = densa com localidade e compartilhamento. Parâmetros: , sem nem .
  2. Pesos compartilhados dão equivariância. Invariância vem do GAP e da augmentation — rotação e escala, nunca de graça.
  3. O campo receptivo é o orçamento: o passo o faz crescer geometricamente; a dilatação, sem perder resolução.
  4. Duas 3×3 > uma 5×5. A volta são três convoluções; usada para frente, a transposta faz xadrez.
  5. Max pooling é um roteador: um vencedor por janela recebe tudo.
  6. ConvNeXt: boa parte da vantagem dos ViTs era a receita. As famílias convergiram.
  7. As convoluções perderam o ImageNet e ficaram com VAEs latentes, medicina, celulares e o patch stem.

Roteiro: (1) por que restringir uma camada densa; (2) formato e parâmetros; (3) equivariância e campo receptivo; (4) a volta: convolução e pooling; (5) a arquitetura que sobreviveu e onde as convoluções vivem em 2026. Fecha com o laboratório no Colab.

Deixe a turma chutar antes de revelar. O ponto do segundo item é o que importa mais que a contagem: a densa não sabe que uma borda é uma borda em qualquer lugar.

Linha i = saída i, coluna j = entrada j. Densa: tudo ligado a tudo. Localidade: só a faixa diagonal sobra. Compartilhamento: a faixa usa os mesmos três números em toda linha — isso é uma matriz de Toeplitz. Multiplicá-la é exatamente deslizar o kernel.

Aperte play com "borda vertical". Depois mude passo para 2 e padding para same e peça a fórmula antes de olhar a linha de baixo. A razão densa/conv é o argumento da aula.

No laboratório (seção 2) o mesmo exercício aparece com o erro do Linear(256, 10).

As duas CNNs têm BatchNorm: a única diferença entre elas é a cabeça. Notebook, seção 7.

Peça previsões: 5 camadas 3x3 passo 1 → 11. Passo 2 → ? (63). Dilatação 2 → 21.

Caso inicial = os números do slide anterior. Avançar linha a linha; na linha 4 clicar em Y[1,1] (7), na linha 7 no centro de dXp (quatro janelas, 1) e depois num canto (uma janela). Depois: "conte as janelas" (dX = 1 2 1 / 2 4 2 / 1 2 1), padding "same" (o gradiente da saída do canto cai quase todo nos zeros e some na linha 8) e passo 2 (janelas sem sobreposição: dX são cópias de K escaladas por dY).

Resposta da pergunta anterior: 9 recebem, 27 ficam sem nada. Depois arraste o passo para 1 e mostre o acúmulo quando as janelas se sobrepõem.